Skip to content

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

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

Merged
merged 7 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
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 @@ -96,6 +95,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 98 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 98 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

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L99

Added line #L99 was not covered by tests

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

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L115

Added line #L115 was not covered by tests

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

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

suspend fun<T> execute(runnable: suspend (AmazonQLanguageServer) -> T): T {
suspend fun<T> execute(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T {

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L159

Added line #L159 was not covered by tests
val lsp = withTimeout(10.seconds) {
val holder = mutex.withLock { instance }.await()
holder.initializer.join()
holder.initializeResult.join()

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L162

Added line #L162 was not covered by tests

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 @@ -174,7 +175,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 @@ -190,7 +191,7 @@
@Suppress("ForbiddenVoid")
private val launcherFuture: Future<Void>
private val launcherHandler: KillableProcessHandler
val initializer: Job
val initializeResult: Deferred<InitializeResult>

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L194

Added line #L194 was not covered by tests

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

launcherFuture = launcher.startListening()

initializer = cs.launch {
initializeResult = cs.async {

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L276

Added line #L276 was not covered by tests
// encryption info must be sent within 5s or Flare process will exit
encryptionManager.writeInitializationPayload(launcherHandler.process.outputStream)

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

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L295

Added line #L295 was not covered by tests
}
languageServer.initialized(InitializedParams())

initializeResult

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

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt#L299

Added line #L299 was not covered by tests
}

DefaultAuthCredentialsService(project, encryptionManager, this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class DefaultAuthCredentialsServiceTest {
every {
mockLspService.executeSync<CompletableFuture<ResponseMessage>>(any())
} coAnswers {
val func = firstArg<suspend (AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
func.invoke(mockLanguageServer)
val func = firstArg<suspend AmazonQLspService.(AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
func.invoke(mockLspService, mockLanguageServer)
}

// Mock message bus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ class WorkspaceServiceHandlerTest {
every {
mockLspService.executeSync<CompletableFuture<ResponseMessage>>(any())
} coAnswers {
val func = firstArg<suspend (AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
func.invoke(mockLanguageServer)
val func = firstArg<suspend AmazonQLspService.(AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
func.invoke(mockLspService, mockLanguageServer)
}

// Mock workspace service
Expand Down
Loading