Skip to content

Commit 4a127de

Browse files
committed
fix(amazonq): move workspace lsp messages off blocking thread calls
we are inappropriately freezing EDT while passing workspace context to the LSP
1 parent 35f05f9 commit 4a127de

File tree

4 files changed

+43
-16
lines changed

4 files changed

+43
-16
lines changed

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,32 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
282282
return runnable(lsp)
283283
}
284284

285+
suspend fun<T> executeIfRunning(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T? {
286+
val lsp = try {
287+
withTimeout(1.seconds) {
288+
val holder = mutex.withLock { instance }.await()
289+
holder.initializeResult.join()
290+
291+
holder.languageServer
292+
}
293+
} catch (_: Exception) {
294+
LOG.debug { "LSP not running" }
295+
null
296+
}
297+
298+
return lsp?.let { runnable(it) }
299+
}
300+
285301
fun<T> executeSync(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T =
286302
runBlocking(cs.coroutineContext) {
287303
execute(runnable)
288304
}
289305

306+
fun<T> syncExecuteIfRunning(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
307+
runBlocking(cs.coroutineContext) {
308+
executeIfRunning(runnable)
309+
}
310+
290311
companion object {
291312
private val LOG = getLogger<AmazonQLspService>()
292313
private const val MAX_RESTARTS = 5
@@ -295,10 +316,10 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
295316

296317
@Deprecated("Easy to accidentally freeze EDT")
297318
fun <T> executeIfRunning(project: Project, runnable: AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
298-
project.serviceIfCreated<AmazonQLspService>()?.executeSync(runnable)
319+
project.serviceIfCreated<AmazonQLspService>()?.syncExecuteIfRunning(runnable)
299320

300-
suspend fun <T> asyncExecuteIfRunning(project: Project, runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
301-
project.serviceIfCreated<AmazonQLspService>()?.execute(runnable)
321+
suspend fun <T> executeAsyncIfRunning(project: Project, runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T? =
322+
project.serviceIfCreated<AmazonQLspService>()?.executeIfRunning(runnable)
302323

303324
fun didChangeConfiguration(project: Project) {
304325
executeIfRunning(project) {
@@ -496,13 +517,13 @@ private class AmazonQServerInstance(private val project: Project, private val cs
496517
DefaultAuthCredentialsService(project, encryptionManager).also {
497518
Disposer.register(this, it)
498519
}
499-
TextDocumentServiceHandler(project).also {
520+
TextDocumentServiceHandler(project, cs).also {
500521
Disposer.register(this, it)
501522
}
502-
WorkspaceServiceHandler(project, lspInitResult).also {
523+
WorkspaceServiceHandler(project, cs, lspInitResult).also {
503524
Disposer.register(this, it)
504525
}
505-
DefaultModuleDependenciesService(project).also {
526+
DefaultModuleDependenciesService(project, cs).also {
506527
Disposer.register(this, it)
507528
}
508529
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import com.intellij.openapi.module.ModuleManager
88
import com.intellij.openapi.project.Project
99
import com.intellij.openapi.roots.ModuleRootEvent
1010
import com.intellij.openapi.roots.ModuleRootListener
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.launch
1113
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
1214
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.ModuleDependencyProvider.Companion.EP_NAME
1315
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.DidChangeDependencyPathsParams
14-
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
1516

1617
class DefaultModuleDependenciesService(
1718
private val project: Project,
19+
private val cs: CoroutineScope,
1820
) : ModuleDependenciesService,
1921
ModuleRootListener,
2022
Disposable {
@@ -35,7 +37,7 @@ class DefaultModuleDependenciesService(
3537

3638
override fun didChangeDependencyPaths(params: DidChangeDependencyPathsParams) {
3739
AmazonQLspService.executeIfRunning(project) { languageServer ->
38-
pluginAwareExecuteOnPooledThread {
40+
cs.launch {
3941
languageServer.didChangeDependencyPaths(params)
4042
}
4143
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import com.intellij.openapi.vfs.VirtualFileManager
1919
import com.intellij.openapi.vfs.newvfs.BulkFileListener
2020
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent
2121
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
22+
import kotlinx.coroutines.CoroutineScope
23+
import kotlinx.coroutines.launch
2224
import org.eclipse.lsp4j.DidChangeTextDocumentParams
2325
import org.eclipse.lsp4j.DidCloseTextDocumentParams
2426
import org.eclipse.lsp4j.DidOpenTextDocumentParams
@@ -29,10 +31,10 @@ import org.eclipse.lsp4j.TextDocumentItem
2931
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier
3032
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3133
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.toUriString
32-
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
3334

3435
class TextDocumentServiceHandler(
3536
private val project: Project,
37+
private val cs: CoroutineScope,
3638
) : FileDocumentManagerListener,
3739
FileEditorManagerListener,
3840
BulkFileListener,
@@ -78,7 +80,7 @@ class TextDocumentServiceHandler(
7880
}
7981
AmazonQLspService.executeIfRunning(project) { languageServer ->
8082
toUriString(file)?.let { uri ->
81-
pluginAwareExecuteOnPooledThread {
83+
cs.launch {
8284
languageServer.textDocumentService.didOpen(
8385
DidOpenTextDocumentParams().apply {
8486
textDocument = TextDocumentItem().apply {
@@ -98,7 +100,7 @@ class TextDocumentServiceHandler(
98100
AmazonQLspService.executeIfRunning(project) { languageServer ->
99101
val file = FileDocumentManager.getInstance().getFile(document) ?: return@executeIfRunning
100102
toUriString(file)?.let { uri ->
101-
pluginAwareExecuteOnPooledThread {
103+
cs.launch {
102104
languageServer.textDocumentService.didSave(
103105
DidSaveTextDocumentParams().apply {
104106
textDocument = TextDocumentIdentifier().apply {
@@ -114,7 +116,7 @@ class TextDocumentServiceHandler(
114116

115117
override fun after(events: MutableList<out VFileEvent>) {
116118
AmazonQLspService.executeIfRunning(project) { languageServer ->
117-
pluginAwareExecuteOnPooledThread {
119+
cs.launch {
118120
events.filterIsInstance<VFileContentChangeEvent>().forEach { event ->
119121
val document = FileDocumentManager.getInstance().getCachedDocument(event.file) ?: return@forEach
120122
toUriString(event.file)?.let { uri ->
@@ -168,8 +170,8 @@ class TextDocumentServiceHandler(
168170

169171
private fun realTimeEdit(event: DocumentEvent) {
170172
AmazonQLspService.executeIfRunning(project) { languageServer ->
171-
pluginAwareExecuteOnPooledThread {
172-
val vFile = FileDocumentManager.getInstance().getFile(event.document) ?: return@pluginAwareExecuteOnPooledThread
173+
cs.launch {
174+
val vFile = FileDocumentManager.getInstance().getFile(event.document) ?: return@launch
173175
toUriString(vFile)?.let { uri ->
174176
languageServer.textDocumentService.didChange(
175177
DidChangeTextDocumentParams().apply {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent
1616
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
1717
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent
1818
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
19+
import kotlinx.coroutines.CoroutineScope
20+
import kotlinx.coroutines.launch
1921
import org.eclipse.lsp4j.CreateFilesParams
2022
import org.eclipse.lsp4j.DeleteFilesParams
2123
import org.eclipse.lsp4j.DidChangeWatchedFilesParams
@@ -37,13 +39,13 @@ import org.eclipse.lsp4j.WorkspaceFoldersChangeEvent
3739
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3840
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.toUriString
3941
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil.createWorkspaceFolders
40-
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
4142
import java.nio.file.FileSystems
4243
import java.nio.file.PathMatcher
4344
import java.nio.file.Paths
4445

4546
class WorkspaceServiceHandler(
4647
private val project: Project,
48+
private val cs: CoroutineScope,
4749
initializeResult: InitializeResult,
4850
) : BulkFileListener,
4951
ModuleRootListener,
@@ -281,7 +283,7 @@ class WorkspaceServiceHandler(
281283

282284
override fun after(events: List<VFileEvent>) {
283285
// since we are using synchronous FileListener
284-
pluginAwareExecuteOnPooledThread {
286+
cs.launch {
285287
didCreateFiles(events.filter { it is VFileCreateEvent || it is VFileMoveEvent || it is VFileCopyEvent })
286288
didDeleteFiles(events.filter { it is VFileMoveEvent || it is VFileDeleteEvent })
287289
didRenameFiles(events.filterIsInstance<VFilePropertyChangeEvent>())

0 commit comments

Comments
 (0)