Skip to content

Commit 7fca93f

Browse files
rlileigaol
authored andcommitted
feat(amazonq): expose lsp server capabilities to consumers of AmazonQLspService (aws#5417)
For certain capabilities, the client implementation needs to be aware of what resources the server is interested in. In the case of `WorkspaceEdit`, we need to expose the filters returned by the server in the initialization handshake. ```json "fileOperations": { "didCreate": { "filters": [ { "pattern": { "glob": "**/*.{ts,js,py,java}", "matches": "file" } }, { "pattern": { "glob": "**/*", "matches": "folder" } } ] }, "didRename": { "filters": [ { "pattern": { "glob": "**/*.{ts,js,py,java}", "matches": "file" } }, { "pattern": { "glob": "**/*", "matches": "folder" } } ] }, "didDelete": { "filters": [ { "pattern": { "glob": "**/*.{ts,js,py,java}", "matches": "file" } }, { "pattern": { "glob": "**/*", "matches": "folder" } } ] } } ```
1 parent c70aae0 commit 7fca93f

File tree

3 files changed

+18
-14
lines changed

3 files changed

+18
-14
lines changed

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ import com.intellij.openapi.util.Key
2121
import com.intellij.util.io.await
2222
import kotlinx.coroutines.CoroutineScope
2323
import kotlinx.coroutines.Deferred
24-
import kotlinx.coroutines.Job
2524
import kotlinx.coroutines.TimeoutCancellationException
2625
import kotlinx.coroutines.async
27-
import kotlinx.coroutines.launch
2826
import kotlinx.coroutines.runBlocking
2927
import kotlinx.coroutines.sync.Mutex
3028
import kotlinx.coroutines.sync.withLock
@@ -33,6 +31,7 @@ import org.eclipse.lsp4j.ClientCapabilities
3331
import org.eclipse.lsp4j.ClientInfo
3432
import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities
3533
import org.eclipse.lsp4j.InitializeParams
34+
import org.eclipse.lsp4j.InitializeResult
3635
import org.eclipse.lsp4j.InitializedParams
3736
import org.eclipse.lsp4j.SynchronizationCapabilities
3837
import org.eclipse.lsp4j.TextDocumentClientCapabilities
@@ -96,6 +95,8 @@ internal class LSPProcessListener : ProcessListener {
9695
@Service(Service.Level.PROJECT)
9796
class AmazonQLspService(private val project: Project, private val cs: CoroutineScope) : Disposable {
9897
private var instance: Deferred<AmazonQServerInstance>
98+
val capabilities
99+
get() = instance.getCompleted().initializeResult.getCompleted().capabilities
99100

100101
// dont allow lsp commands if server is restarting
101102
private val mutex = Mutex(false)
@@ -111,7 +112,7 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
111112
Disposer.register(this@AmazonQLspService, it)
112113
}
113114
// wait for handshake to complete
114-
instance.initializer.join()
115+
instance.initializeResult.join()
115116

116117
instance
117118
}
@@ -141,7 +142,7 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
141142

142143
try {
143144
val i = it.await()
144-
if (i.initializer.isActive) {
145+
if (i.initializeResult.isActive) {
145146
// not initialized
146147
return
147148
}
@@ -155,17 +156,17 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
155156
instance = start()
156157
}
157158

158-
suspend fun<T> execute(runnable: suspend (AmazonQLanguageServer) -> T): T {
159+
suspend fun<T> execute(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T {
159160
val lsp = withTimeout(10.seconds) {
160161
val holder = mutex.withLock { instance }.await()
161-
holder.initializer.join()
162+
holder.initializeResult.join()
162163

163164
holder.languageServer
164165
}
165166
return runnable(lsp)
166167
}
167168

168-
fun<T> executeSync(runnable: suspend (AmazonQLanguageServer) -> T): T =
169+
fun<T> executeSync(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T =
169170
runBlocking(cs.coroutineContext) {
170171
execute(runnable)
171172
}
@@ -174,7 +175,7 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
174175
private val LOG = getLogger<AmazonQLspService>()
175176
fun getInstance(project: Project) = project.service<AmazonQLspService>()
176177

177-
fun <T> executeIfRunning(project: Project, runnable: (AmazonQLanguageServer) -> T): T? =
178+
fun <T> executeIfRunning(project: Project, runnable: AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
178179
project.serviceIfCreated<AmazonQLspService>()?.executeSync(runnable)
179180
}
180181
}
@@ -190,7 +191,7 @@ private class AmazonQServerInstance(private val project: Project, private val cs
190191
@Suppress("ForbiddenVoid")
191192
private val launcherFuture: Future<Void>
192193
private val launcherHandler: KillableProcessHandler
193-
val initializer: Job
194+
val initializeResult: Deferred<InitializeResult>
194195

195196
private fun createClientCapabilities(): ClientCapabilities =
196197
ClientCapabilities().apply {
@@ -272,7 +273,7 @@ private class AmazonQServerInstance(private val project: Project, private val cs
272273

273274
launcherFuture = launcher.startListening()
274275

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

@@ -291,8 +292,11 @@ private class AmazonQServerInstance(private val project: Project, private val cs
291292
// then if this succeeds then we can allow the client to send requests
292293
if (initializeResult == null) {
293294
launcherHandler.destroyProcess()
295+
error("LSP initialization failed")
294296
}
295297
languageServer.initialized(InitializedParams())
298+
299+
initializeResult
296300
}
297301

298302
DefaultAuthCredentialsService(project, encryptionManager, this)

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/auth/DefaultAuthCredentialsServiceTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ class DefaultAuthCredentialsServiceTest {
4343
every {
4444
mockLspService.executeSync<CompletableFuture<ResponseMessage>>(any())
4545
} coAnswers {
46-
val func = firstArg<suspend (AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
47-
func.invoke(mockLanguageServer)
46+
val func = firstArg<suspend AmazonQLspService.(AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
47+
func.invoke(mockLspService, mockLanguageServer)
4848
}
4949

5050
// Mock message bus

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/workspace/WorkspaceServiceHandlerTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ class WorkspaceServiceHandlerTest {
7575
every {
7676
mockLspService.executeSync<CompletableFuture<ResponseMessage>>(any())
7777
} coAnswers {
78-
val func = firstArg<suspend (AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
79-
func.invoke(mockLanguageServer)
78+
val func = firstArg<suspend AmazonQLspService.(AmazonQLanguageServer) -> CompletableFuture<ResponseMessage>>()
79+
func.invoke(mockLspService, mockLanguageServer)
8080
}
8181

8282
// Mock workspace service

0 commit comments

Comments
 (0)