Skip to content

Commit c73ed14

Browse files
authored
fix(amazonq): suppress IDE error when editor does not actually contain text (#5908)
1 parent 8a74642 commit c73ed14

File tree

3 files changed

+95
-69
lines changed

3 files changed

+95
-69
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Suppress IDE error when current editor context is not valid for Amazon Q"
4+
}

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

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ import org.eclipse.lsp4j.TextDocumentContentChangeEvent
3333
import org.eclipse.lsp4j.TextDocumentIdentifier
3434
import org.eclipse.lsp4j.TextDocumentItem
3535
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier
36+
import software.aws.toolkits.core.utils.getLogger
3637
import software.aws.toolkits.core.utils.tryOrNull
38+
import software.aws.toolkits.core.utils.warn
39+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
3740
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3841
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION
3942
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.getCursorState
@@ -98,40 +101,36 @@ class TextDocumentServiceHandler(
98101
}
99102
}
100103

101-
cs.launch {
102-
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
103-
toUriString(file)?.let { uri ->
104-
languageServer.textDocumentService.didOpen(
105-
DidOpenTextDocumentParams().apply {
106-
textDocument = TextDocumentItem().apply {
107-
this.uri = uri
108-
text = file.inputStream.readAllBytes().decodeToString()
109-
languageId = file.fileType.name.lowercase()
110-
version = file.modificationStamp.toInt()
111-
}
104+
trySendIfValid { languageServer ->
105+
toUriString(file)?.let { uri ->
106+
languageServer.textDocumentService.didOpen(
107+
DidOpenTextDocumentParams().apply {
108+
textDocument = TextDocumentItem().apply {
109+
this.uri = uri
110+
text = file.inputStream.readAllBytes().decodeToString()
111+
languageId = file.fileType.name.lowercase()
112+
version = file.modificationStamp.toInt()
112113
}
113-
)
114-
}
114+
}
115+
)
115116
}
116117
}
117118
}
118119
}
119120

120121
override fun beforeDocumentSaving(document: Document) {
121-
cs.launch {
122-
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
123-
val file = FileDocumentManager.getInstance().getFile(document) ?: return@executeAsyncIfRunning
124-
toUriString(file)?.let { uri ->
125-
languageServer.textDocumentService.didSave(
126-
DidSaveTextDocumentParams().apply {
127-
textDocument = TextDocumentIdentifier().apply {
128-
this.uri = uri
129-
}
130-
// TODO: should respect `textDocumentSync.save.includeText` server capability config
131-
text = document.text
122+
trySendIfValid { languageServer ->
123+
val file = FileDocumentManager.getInstance().getFile(document) ?: return@trySendIfValid
124+
toUriString(file)?.let { uri ->
125+
languageServer.textDocumentService.didSave(
126+
DidSaveTextDocumentParams().apply {
127+
textDocument = TextDocumentIdentifier().apply {
128+
this.uri = uri
132129
}
133-
)
134-
}
130+
// TODO: should respect `textDocumentSync.save.includeText` server capability config
131+
text = document.text
132+
}
133+
)
135134
}
136135
}
137136
}
@@ -141,23 +140,21 @@ class TextDocumentServiceHandler(
141140
val document = FileDocumentManager.getInstance().getCachedDocument(event.file) ?: return@forEach
142141

143142
handleFileOpened(event.file)
144-
cs.launch {
145-
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
146-
toUriString(event.file)?.let { uri ->
147-
languageServer.textDocumentService.didChange(
148-
DidChangeTextDocumentParams().apply {
149-
textDocument = VersionedTextDocumentIdentifier().apply {
150-
this.uri = uri
151-
version = document.modificationStamp.toInt()
152-
}
153-
contentChanges = listOf(
154-
TextDocumentContentChangeEvent().apply {
155-
text = document.text
156-
}
157-
)
143+
trySendIfValid { languageServer ->
144+
toUriString(event.file)?.let { uri ->
145+
languageServer.textDocumentService.didChange(
146+
DidChangeTextDocumentParams().apply {
147+
textDocument = VersionedTextDocumentIdentifier().apply {
148+
this.uri = uri
149+
version = document.modificationStamp.toInt()
158150
}
159-
)
160-
}
151+
contentChanges = listOf(
152+
TextDocumentContentChangeEvent().apply {
153+
text = document.text
154+
}
155+
)
156+
}
157+
)
161158
}
162159
}
163160
}
@@ -179,17 +176,15 @@ class TextDocumentServiceHandler(
179176
tryOrNull { FileDocumentManager.getInstance().getDocument(file)?.removeDocumentListener(listener) }
180177
file.putUserData(KEY_REAL_TIME_EDIT_LISTENER, null)
181178

182-
cs.launch {
183-
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
184-
toUriString(file)?.let { uri ->
185-
languageServer.textDocumentService.didClose(
186-
DidCloseTextDocumentParams().apply {
187-
textDocument = TextDocumentIdentifier().apply {
188-
this.uri = uri
189-
}
179+
trySendIfValid { languageServer ->
180+
toUriString(file)?.let { uri ->
181+
languageServer.textDocumentService.didClose(
182+
DidCloseTextDocumentParams().apply {
183+
textDocument = TextDocumentIdentifier().apply {
184+
this.uri = uri
190185
}
191-
)
192-
}
186+
}
187+
)
193188
}
194189
}
195190
}
@@ -221,24 +216,22 @@ class TextDocumentServiceHandler(
221216
}
222217

223218
private fun realTimeEdit(event: DocumentEvent) {
224-
cs.launch {
225-
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
226-
val vFile = FileDocumentManager.getInstance().getFile(event.document) ?: return@executeAsyncIfRunning
227-
toUriString(vFile)?.let { uri ->
228-
languageServer.textDocumentService.didChange(
229-
DidChangeTextDocumentParams().apply {
230-
textDocument = VersionedTextDocumentIdentifier().apply {
231-
this.uri = uri
232-
version = event.document.modificationStamp.toInt()
233-
}
234-
contentChanges = listOf(
235-
TextDocumentContentChangeEvent().apply {
236-
text = event.document.text
237-
}
238-
)
219+
trySendIfValid { languageServer ->
220+
val vFile = FileDocumentManager.getInstance().getFile(event.document) ?: return@trySendIfValid
221+
toUriString(vFile)?.let { uri ->
222+
languageServer.textDocumentService.didChange(
223+
DidChangeTextDocumentParams().apply {
224+
textDocument = VersionedTextDocumentIdentifier().apply {
225+
this.uri = uri
226+
version = event.document.modificationStamp.toInt()
239227
}
240-
)
241-
}
228+
contentChanges = listOf(
229+
TextDocumentContentChangeEvent().apply {
230+
text = event.document.text
231+
}
232+
)
233+
}
234+
)
242235
}
243236
}
244237
// Process document changes here
@@ -247,7 +240,20 @@ class TextDocumentServiceHandler(
247240
override fun dispose() {
248241
}
249242

243+
private fun trySendIfValid(runnable: (AmazonQLanguageServer) -> Unit) {
244+
cs.launch {
245+
AmazonQLspService.executeAsyncIfRunning(project) { languageServer ->
246+
try {
247+
runnable(languageServer)
248+
} catch (e: Exception) {
249+
LOG.warn { "Invalid document: $e" }
250+
}
251+
}
252+
}
253+
}
254+
250255
companion object {
251256
private val KEY_REAL_TIME_EDIT_LISTENER = Key.create<DocumentListener>("amazonq.textdocument.realtimeedit.listener")
257+
private val LOG = getLogger<TextDocumentServiceHandler>()
252258
}
253259
}

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandlerTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ class TextDocumentServiceHandlerTest {
188188
}
189189
}
190190

191+
@Test
192+
fun `fileOpened suppreses document read failure`() = runTest {
193+
sut = TextDocumentServiceHandler(projectRule.project, this)
194+
advanceUntilIdle()
195+
196+
val file = mockk<VirtualFile> {
197+
every { inputStream } throws RuntimeException("read failure")
198+
every { getUserData<Any>(any()) } returns null
199+
every { putUserData<Any>(any(), any()) } returns Unit
200+
every { isValid } returns false
201+
}
202+
sut.fileOpened(mockk(), file)
203+
204+
verify(exactly = 0) { mockTextDocumentService.didOpen(any()) }
205+
}
206+
191207
@Test
192208
fun `didClose runs on fileClosed`() = runTest {
193209
sut = TextDocumentServiceHandler(projectRule.project, this)

0 commit comments

Comments
 (0)