Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(amazonq): expose lsp server capabilities to consumers of AmazonQLspService #5417

Open
wants to merge 2 commits into
base: feature/q-lsp
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@
import com.intellij.util.io.await
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
Expand All @@ -33,6 +31,7 @@
import org.eclipse.lsp4j.ClientInfo
import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities
import org.eclipse.lsp4j.InitializeParams
import org.eclipse.lsp4j.InitializeResult
import org.eclipse.lsp4j.InitializedParams
import org.eclipse.lsp4j.SynchronizationCapabilities
import org.eclipse.lsp4j.TextDocumentClientCapabilities
Expand Down Expand Up @@ -95,6 +94,8 @@
@Service(Service.Level.PROJECT)
class AmazonQLspService(private val project: Project, private val cs: CoroutineScope) : Disposable {
private var instance: Deferred<AmazonQServerInstance>
val capabilities

Check notice on line 97 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Function or property has platform type

Declaration has type inferred from a platform call, which can lead to unchecked nullability issues. Specify type explicitly as nullable or non-nullable.

Check warning on line 97 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Property "capabilities" is never used

Check notice

Code scanning / QDJVMC

Function or property has platform type Note

Declaration has type inferred from a platform call, which can lead to unchecked nullability issues. Specify type explicitly as nullable or non-nullable.

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "capabilities" is never used
get() = instance.getCompleted().initializeResult.getCompleted().capabilities

// dont allow lsp commands if server is restarting
private val mutex = Mutex(false)
Expand All @@ -110,7 +111,7 @@
Disposer.register(this@AmazonQLspService, it)
}
// wait for handshake to complete
instance.initializer.join()
instance.initializeResult.join()

instance
}
Expand Down Expand Up @@ -140,7 +141,7 @@

try {
val i = it.await()
if (i.initializer.isActive) {
if (i.initializeResult.isActive) {
// not initialized
return
}
Expand All @@ -154,17 +155,17 @@
instance = start()
}

suspend fun<T> execute(runnable: suspend (AmazonQLanguageServer) -> T): T {
suspend fun<T> execute(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T {
val lsp = withTimeout(10.seconds) {
val holder = mutex.withLock { instance }.await()
holder.initializer.join()
holder.initializeResult.join()

holder.languageServer
}
return runnable(lsp)
}

fun<T> executeSync(runnable: suspend (AmazonQLanguageServer) -> T): T =
fun<T> executeSync(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T =
runBlocking(cs.coroutineContext) {
execute(runnable)
}
Expand All @@ -173,7 +174,7 @@
private val LOG = getLogger<AmazonQLspService>()
fun getInstance(project: Project) = project.service<AmazonQLspService>()

fun <T> executeIfRunning(project: Project, runnable: (AmazonQLanguageServer) -> T): T? =
fun <T> executeIfRunning(project: Project, runnable: AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
project.serviceIfCreated<AmazonQLspService>()?.executeSync(runnable)
}
}
Expand All @@ -189,7 +190,7 @@
@Suppress("ForbiddenVoid")
private val launcherFuture: Future<Void>
private val launcherHandler: KillableProcessHandler
val initializer: Job
val initializeResult: Deferred<InitializeResult>

private fun createClientCapabilities(): ClientCapabilities =
ClientCapabilities().apply {
Expand Down Expand Up @@ -281,7 +282,7 @@

launcherFuture = launcher.startListening()

initializer = cs.launch {
initializeResult = cs.async {
// encryption info must be sent within 5s or Flare process will exit
encryptionManager.writeInitializationPayload(launcherHandler.process.outputStream)

Expand All @@ -300,8 +301,11 @@
// then if this succeeds then we can allow the client to send requests
if (initializeResult == null) {
launcherHandler.destroyProcess()
error("LSP initialization failed")
}
languageServer.initialized(InitializedParams())

initializeResult
}
}

Expand Down
Loading