From f3ef8a98ea84acc5cfce93f412514635c1a3d2e0 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Fri, 20 Jun 2025 11:57:40 -0400 Subject: [PATCH 1/9] feat(amazonq): enable pinned context and rules management --- ...-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json | 4 + .../amazonq/webview/BrowserConnector.kt | 32 ++++++++ plugins/amazonq/mynah-ui/package-lock.json | 9 +- plugins/amazonq/mynah-ui/package.json | 2 +- .../src/mynah-ui/ui/quickActions/handler.ts | 2 +- .../services/amazonq/lsp/AmazonQChatServer.kt | 32 ++++++++ .../amazonq/lsp/AmazonQLanguageClient.kt | 12 +++ .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 58 +++++++++++++ .../services/amazonq/lsp/AmazonQLspService.kt | 14 ++++ .../lsp/editor/ActiveEditorChangeListener.kt | 82 +++++++++++++++++++ .../lsp/model/ExtendedClientMetadata.kt | 4 +- .../lsp/model/aws/chat/CreatePromptParams.kt | 1 + .../lsp/model/aws/chat/FlareChatCommands.kt | 6 ++ .../aws/editor/ActiveEditorChangedParams.kt | 12 +++ 14 files changed, 262 insertions(+), 8 deletions(-) create mode 100644 .changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json create mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt create mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt diff --git a/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json b/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json new file mode 100644 index 00000000000..cf4ba893c91 --- /dev/null +++ b/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "Amazon Q Chat: Pin context items in chat and manage workspace rules" +} \ No newline at end of file diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index f030d69aa3d..89b02987bae 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -60,6 +60,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LIST_CONVERSATIONS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PROMPT_OPTION_ACKNOWLEDGED import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_QUICK_ACTION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY @@ -73,6 +75,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Encry import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResponse import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_MCP_SERVERS_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_RULES_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY @@ -83,6 +86,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResultSuccess import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.QuickChatActionRequest +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.RULE_CLICK_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.STOP_CHAT_RESPONSE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest @@ -485,6 +489,34 @@ class BrowserConnector( ) } } + LIST_RULES_REQUEST_METHOD -> { + handleChat(AmazonQChatServer.listRules, node) + .whenComplete { response, _ -> + browser.postChat( + FlareUiMessage( + command = LIST_RULES_REQUEST_METHOD, + params = response + ) + ) + } + } + RULE_CLICK_REQUEST_METHOD -> { + handleChat(AmazonQChatServer.ruleClick, node) + .whenComplete { response, _ -> + browser.postChat( + FlareUiMessage( + command = RULE_CLICK_REQUEST_METHOD, + params = response + ) + ) + } + } + CHAT_PINNED_CONTEXT_ADD -> { + handleChat(AmazonQChatServer.pinnedContextAdd, node) + } + CHAT_PINNED_CONTEXT_REMOVE -> { + handleChat(AmazonQChatServer.pinnedContextRemove, node) + } } } diff --git a/plugins/amazonq/mynah-ui/package-lock.json b/plugins/amazonq/mynah-ui/package-lock.json index a16f304d31b..b6a2ccb2b00 100644 --- a/plugins/amazonq/mynah-ui/package-lock.json +++ b/plugins/amazonq/mynah-ui/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.30.3", + "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.35.5", "@types/node": "^14.18.5", "fs-extra": "^10.0.1", "sanitize-html": "^2.12.1", @@ -115,11 +115,10 @@ }, "node_modules/@aws/mynah-ui-chat": { "name": "@aws/mynah-ui", - "version": "4.30.3", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.30.3.tgz", - "integrity": "sha512-Xy22dzCaFUqpdSHMpLa8Dsq98DiAUq49dm7Iu8Yj2YZXSCyfKQiYMJOfwU8IoqeNcEney5JRMJpf+/RysWugbA==", + "version": "4.35.5", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.35.5.tgz", + "integrity": "sha512-HFzNiVexMLPt4GUBcCBgObr2WKjmLg0EKH7/nPPaThEvQAVZYOapMYKoxaS/IrEa6BqWsE36V4++F3Bh7Vf7uw==", "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", diff --git a/plugins/amazonq/mynah-ui/package.json b/plugins/amazonq/mynah-ui/package.json index 953b82bc434..a24d458648e 100644 --- a/plugins/amazonq/mynah-ui/package.json +++ b/plugins/amazonq/mynah-ui/package.json @@ -12,7 +12,7 @@ "lintfix": "eslint -c .eslintrc.js --fix --ext .ts ." }, "dependencies": { - "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.30.3", + "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.35.5", "@types/node": "^14.18.5", "fs-extra": "^10.0.1", "sanitize-html": "^2.12.1", diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts index 4734b37d7b9..b700b38ff6d 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts @@ -395,7 +395,7 @@ private handleDocCommand(chatPrompt: ChatPrompt, tabID: string, taskName: string cancelButtonWhenLoading: false, }) } else { - this.mynahUI?.updateStore(affectedTabId, { promptInputOptions: [] }) + this.mynahUI?.updateStore(affectedTabId, { promptInputOptions: [], promptTopBarTitle: '' }) } if (affectedTabId && this.isHybridChatEnabled) { diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt index 7c644894bb4..21c8f1b1d42 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt @@ -18,8 +18,11 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_INSERT_TO_CURSOR_NOTIFICATION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LIST_CONVERSATIONS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_QUICK_ACTION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SOURCE_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_ADD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_BAR_ACTIONS @@ -39,11 +42,13 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSe import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InfoLinkClickParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InsertToCursorPositionParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_MCP_SERVERS_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_RULES_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ListConversationsParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeParams +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.RULE_CLICK_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TELEMETRY_EVENT @@ -189,6 +194,18 @@ object AmazonQChatServer : JsonRpcMethodProvider { LSPAny::class.java ) + val listRules = JsonRpcRequest( + LIST_RULES_REQUEST_METHOD, + LSPAny::class.java, + LSPAny::class.java + ) + + val ruleClick = JsonRpcRequest( + RULE_CLICK_REQUEST_METHOD, + LSPAny::class.java, + LSPAny::class.java + ) + val conversationClick = JsonRpcRequest( CHAT_CONVERSATION_CLICK, ConversationClickParams::class.java, @@ -218,6 +235,21 @@ object AmazonQChatServer : JsonRpcMethodProvider { CreatePromptParams::class.java ) + val sendPinnedContext = JsonRpcNotification( + CHAT_SEND_PINNED_CONTEXT, + LSPAny::class.java + ) + + val pinnedContextAdd = JsonRpcNotification( + CHAT_PINNED_CONTEXT_ADD, + LSPAny::class.java + ) + + val pinnedContextRemove = JsonRpcNotification( + CHAT_PINNED_CONTEXT_REMOVE, + LSPAny::class.java + ) + val telemetryEvent = JsonRpcNotification( TELEMETRY_EVENT, Any::class.java diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt index c5141c4446b..dce7e7301ad 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt @@ -9,7 +9,10 @@ import org.eclipse.lsp4j.services.LanguageClient import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPTIONS_UPDATE_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyFileParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.DID_APPEND_FILE @@ -54,6 +57,15 @@ interface AmazonQLanguageClient : LanguageClient { @JsonNotification(CHAT_SEND_CONTEXT_COMMANDS) fun sendContextCommands(params: LSPAny): CompletableFuture + @JsonNotification(CHAT_SEND_PINNED_CONTEXT) + fun sendPinnedContext(params: LSPAny): CompletableFuture + + @JsonNotification(CHAT_PINNED_CONTEXT_ADD) + fun pinnedContextAdd(params: LSPAny): CompletableFuture + + @JsonNotification(CHAT_PINNED_CONTEXT_REMOVE) + fun pinnedContextRemove(params: LSPAny): CompletableFuture + @JsonNotification(DID_COPY_FILE) fun copyFile(params: CopyFileParams) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 6eab2f54841..5e76282f918 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -27,6 +27,7 @@ import org.eclipse.lsp4j.PublishDiagnosticsParams import org.eclipse.lsp4j.ShowDocumentParams import org.eclipse.lsp4j.ShowDocumentResult import org.eclipse.lsp4j.ShowMessageRequestParams +import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.jsonrpc.ResponseErrorException import org.eclipse.lsp4j.jsonrpc.messages.ResponseError import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode @@ -44,7 +45,10 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMes import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPTIONS_UPDATE_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyFileParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FileParams @@ -425,6 +429,60 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC return CompletableFuture.completedFuture(Unit) } + override fun sendPinnedContext(params: LSPAny): CompletableFuture { + val chatManager = ChatCommunicationManager.getInstance(project) + + // Get the active text editor and create text document identifier + val editor = FileEditorManager.getInstance(project).selectedTextEditor + val textDocument = editor?.let { + TextDocumentIdentifier(it.virtualFile.path) + } + + // Create updated params with text document information + // Since params is LSPAny, we need to handle it as a generic object + val updatedParams = when (params) { + is Map<*, *> -> { + val mutableParams = params.toMutableMap() + mutableParams["textDocument"] = textDocument + mutableParams + } + else -> mapOf( + "params" to params, + "textDocument" to textDocument + ) + } + + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_SEND_PINNED_CONTEXT, + params = updatedParams, + ) + ) + return CompletableFuture.completedFuture(Unit) + } + + override fun pinnedContextAdd(params: LSPAny): CompletableFuture { + val chatManager = ChatCommunicationManager.getInstance(project) + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_PINNED_CONTEXT_ADD, + params = params, + ) + ) + return CompletableFuture.completedFuture(Unit) + } + + override fun pinnedContextRemove(params: LSPAny): CompletableFuture { + val chatManager = ChatCommunicationManager.getInstance(project) + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_PINNED_CONTEXT_REMOVE, + params = params, + ) + ) + return CompletableFuture.completedFuture(Unit) + } + override fun appendFile(params: FileParams) = refreshVfs(params.path) override fun createDirectory(params: FileParams) = refreshVfs(params.path) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt index 5b3b4dd107b..95458fac29e 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt @@ -553,6 +553,20 @@ private class AmazonQServerInstance(private val project: Project, private val cs DefaultModuleDependenciesService(project).also { Disposer.register(this, it) } + + // Register active editor change listener + val executor = java.util.concurrent.Executors.newSingleThreadScheduledExecutor { r -> + val thread = Thread(r, "AmazonQ-EditorChangeListener") + thread.isDaemon = true + thread + } + + // Register active editor change listener + software.aws.toolkits.jetbrains.services.amazonq.lsp.editor.ActiveEditorChangeListener.register( + project, + executor + ) + LOG.info { "Registered active editor change listener" } } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt new file mode 100644 index 00000000000..7ab003f5a73 --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt @@ -0,0 +1,82 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.lsp.editor + +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerEvent +import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.vfs.VirtualFile +import org.eclipse.lsp4j.TextDocumentIdentifier +import software.aws.toolkits.core.utils.getLogger +import software.aws.toolkits.core.utils.warn +import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.editor.ActiveEditorChangedParams +import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit + +class ActiveEditorChangeListener( + private val project: Project, + private val executor: ScheduledExecutorService, +) : Disposable { + private var debounceTask: ScheduledFuture<*>? = null + private val DEBOUNCE_DELAY_MS = 100L + + init { + val connection = project.messageBus.connect(this) + connection.subscribe( + FileEditorManagerListener.FILE_EDITOR_MANAGER, + object : FileEditorManagerListener { + override fun selectionChanged(event: FileEditorManagerEvent) { + handleActiveEditorChange(event.newFile, event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) + } + } + ) + } + + private fun handleActiveEditorChange(file: VirtualFile?, editor: Editor?) { + // Cancel any pending notification + debounceTask?.cancel(false) + + // Schedule a new notification after the debounce period + debounceTask = executor.schedule({ + try { + val textDocument = file?.let { LspEditorUtil.toUriString(it) }?.let { TextDocumentIdentifier(it) } + val cursorState = editor?.let { LspEditorUtil.getCursorState(it) } + + val params = ActiveEditorChangedParams(textDocument, cursorState) + + // Send notification to the language server + ApplicationManager.getApplication().invokeLater { + AmazonQLspService.executeIfRunning(project) { _ -> + rawEndpoint.notify(ACTIVE_EDITOR_CHANGED_NOTIFICATION, params) + } + } + } catch (e: Exception) { + LOG.warn(e) { "Failed to send active editor changed notification" } + } + }, DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS) + } + + override fun dispose() { + debounceTask?.cancel(true) + } + + companion object { + private val LOG = getLogger() + + fun register(project: Project, executor: ScheduledExecutorService): ActiveEditorChangeListener { + val listener = ActiveEditorChangeListener(project, executor) + Disposer.register(project, listener) + return listener + } + } +} diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt index db49b158c41..b304a3cff88 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt @@ -24,6 +24,7 @@ data class AwsClientCapabilities( data class DeveloperProfiles( val developerProfiles: Boolean, val mcp: Boolean, + val pinnedContextEnabled: Boolean, ) data class WindowSettings( @@ -62,7 +63,8 @@ fun createExtendedClientMetadata(project: Project): ExtendedClientMetadata { awsClientCapabilities = AwsClientCapabilities( q = DeveloperProfiles( developerProfiles = true, - mcp = true + mcp = true, + pinnedContextEnabled = true, ), window = WindowSettings( showSaveFileDialog = true diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt index 8c089dabde6..cb95ca7106b 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt @@ -5,6 +5,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat data class CreatePromptParams( val promptName: String, + val isRule: Boolean? = null, ) data class CreatePromptNotification( diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt index e53835701a2..4de4c4501c2 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat +const val ACTIVE_EDITOR_CHANGED_NOTIFICATION = "aws/chat/activeEditorChanged" const val AUTH_FOLLOW_UP_CLICKED = "authFollowUpClicked" const val CHAT_BUTTON_CLICK = "aws/chat/buttonClick" const val CHAT_CONVERSATION_CLICK = "aws/chat/conversationClick" @@ -25,7 +26,10 @@ const val CHAT_PROMPT_OPTION_ACKNOWLEDGED = "chatPromptOptionAcknowledged" const val CHAT_QUICK_ACTION = "aws/chat/sendChatQuickAction" const val CHAT_READY = "aws/chat/ready" const val CHAT_SEND_CONTEXT_COMMANDS = "aws/chat/sendContextCommands" +const val CHAT_SEND_PINNED_CONTEXT = "aws/chat/sendPinnedContext" const val CHAT_SEND_UPDATE = "aws/chat/sendChatUpdate" +const val CHAT_PINNED_CONTEXT_ADD = "aws/chat/pinnedContextAdd" +const val CHAT_PINNED_CONTEXT_REMOVE = "aws/chat/pinnedContextRemove" const val CHAT_SOURCE_LINK_CLICK = "aws/chat/sourceLinkClick" const val CHAT_TAB_ADD = "aws/chat/tabAdd" const val CHAT_TAB_BAR_ACTIONS = "aws/chat/tabBarAction" @@ -55,3 +59,5 @@ const val TELEMETRY_EVENT = "telemetry/event" // https://github.com/aws/language-server-runtimes/blob/112feba70219a98a12f13727d67c540205fa9c9f/types/chat.ts#L32 const val LIST_MCP_SERVERS_REQUEST_METHOD = "aws/chat/listMcpServers" const val MCP_SERVER_CLICK_REQUEST_METHOD = "aws/chat/mcpServerClick" +const val LIST_RULES_REQUEST_METHOD = "aws/chat/listRules" +const val RULE_CLICK_REQUEST_METHOD = "aws/chat/ruleClick" diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt new file mode 100644 index 00000000000..f9a3eca8ace --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt @@ -0,0 +1,12 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.editor + +import org.eclipse.lsp4j.TextDocumentIdentifier +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CursorState + +data class ActiveEditorChangedParams( + val textDocument: TextDocumentIdentifier?, + val cursorState: CursorState?, +) From 8bfd8b6a32360f024f9d40049bcdc2b5bfa56724 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Fri, 20 Jun 2025 13:02:43 -0400 Subject: [PATCH 2/9] deps(amazonq): update @aws/chat-client --- plugins/amazonq/mynah-ui/package-lock.json | 44 ++++++++++------------ plugins/amazonq/mynah-ui/package.json | 2 +- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/plugins/amazonq/mynah-ui/package-lock.json b/plugins/amazonq/mynah-ui/package-lock.json index b6a2ccb2b00..b78f76b4250 100644 --- a/plugins/amazonq/mynah-ui/package-lock.json +++ b/plugins/amazonq/mynah-ui/package-lock.json @@ -18,7 +18,7 @@ "web-tree-sitter": "^0.20.7" }, "devDependencies": { - "@aws/chat-client": "^0.1.4", + "@aws/chat-client": "^0.1.18", "@aws/fully-qualified-names": "^2.1.1", "@types/sanitize-html": "^2.8.0", "@typescript-eslint/eslint-plugin": "^5.38.0", @@ -48,25 +48,23 @@ } }, "node_modules/@aws/chat-client": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@aws/chat-client/-/chat-client-0.1.4.tgz", - "integrity": "sha512-5iqo9f/FjipyWxVPByVcI4yF9NPDOFInuS2ak4bK+j4d6ca1n20CnQrEQcMOdGjl5mde51s7X4Jqvlu3smgHGA==", + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@aws/chat-client/-/chat-client-0.1.18.tgz", + "integrity": "sha512-fyeBvYmw7ppvJ7y+k5s5fVNF7DBKaoEO5PUCwlkm+QPnTkm8qfGpMNDsMXsDQJoIYqHcgmwzdRmcZZ6NVcqgNA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws/chat-client-ui-types": "^0.1.12", - "@aws/language-server-runtimes-types": "^0.1.10", - "@aws/mynah-ui": "^4.28.0" + "@aws/chat-client-ui-types": "^0.1.40", + "@aws/language-server-runtimes-types": "^0.1.39", + "@aws/mynah-ui": "^4.35.4" } }, "node_modules/@aws/chat-client-ui-types": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.32.tgz", - "integrity": "sha512-axJymxFQhXh8AOnhek61VL5va917TjIvfHF5sHpyQay+znILAs65osdIMeqHs6VTjZCKtzIEp5iCd6uZbvYRVw==", + "version": "0.1.46", + "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.46.tgz", + "integrity": "sha512-IG/fyMqBfaTPy2swgEVAJ8PgwL3x0rWFYFbj9VxKCIsn6LgYisF8KuKtTg8p0d62H0rGV9SCsziH1nNRufTpKA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.26" + "@aws/language-server-runtimes-types": "^0.1.40" } }, "node_modules/@aws/fully-qualified-names": { @@ -79,23 +77,21 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.26.tgz", - "integrity": "sha512-c63rpUbcrtLqaC33t6elRApQqLbQvFgKzIQ2z/VCavE5F7HSLBfzhHkhgUFd775fBpsF4MHrIzwNitYLhDGobw==", + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.40.tgz", + "integrity": "sha512-GWZaoWwQQkBj21zB+1QXws7W6kP+V0jRGn6Lmwq3apfCrGGRRYpEYjEE7l3Qk/emAjgLs2rhZ7Z0nj/pbFrSAQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5" } }, "node_modules/@aws/mynah-ui": { - "version": "4.30.3", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.30.3.tgz", - "integrity": "sha512-Xy22dzCaFUqpdSHMpLa8Dsq98DiAUq49dm7Iu8Yj2YZXSCyfKQiYMJOfwU8IoqeNcEney5JRMJpf+/RysWugbA==", + "version": "4.35.5", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.35.5.tgz", + "integrity": "sha512-HFzNiVexMLPt4GUBcCBgObr2WKjmLg0EKH7/nPPaThEvQAVZYOapMYKoxaS/IrEa6BqWsE36V4++F3Bh7Vf7uw==", "dev": true, "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -3576,15 +3572,13 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/watchpack": { "version": "2.4.2", diff --git a/plugins/amazonq/mynah-ui/package.json b/plugins/amazonq/mynah-ui/package.json index a24d458648e..59013b87ffd 100644 --- a/plugins/amazonq/mynah-ui/package.json +++ b/plugins/amazonq/mynah-ui/package.json @@ -21,8 +21,8 @@ "web-tree-sitter": "^0.20.7" }, "devDependencies": { + "@aws/chat-client": "^0.1.18", "@aws/fully-qualified-names": "^2.1.1", - "@aws/chat-client": "^0.1.4", "@types/sanitize-html": "^2.8.0", "@typescript-eslint/eslint-plugin": "^5.38.0", "@typescript-eslint/parser": "^5.38.0", From f4fbd173b83a130b44fb1b5a4e3e7ce594fd6e9d Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Fri, 20 Jun 2025 13:34:02 -0400 Subject: [PATCH 3/9] fix: address code scanning comments --- .../jetbrains/services/amazonq/lsp/AmazonQChatServer.kt | 5 ----- .../jetbrains/services/amazonq/lsp/AmazonQLspService.kt | 8 +++++--- .../amazonq/lsp/editor/ActiveEditorChangeListener.kt | 5 ++--- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt index 21c8f1b1d42..cce0af16070 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt @@ -235,11 +235,6 @@ object AmazonQChatServer : JsonRpcMethodProvider { CreatePromptParams::class.java ) - val sendPinnedContext = JsonRpcNotification( - CHAT_SEND_PINNED_CONTEXT, - LSPAny::class.java - ) - val pinnedContextAdd = JsonRpcNotification( CHAT_PINNED_CONTEXT_ADD, LSPAny::class.java diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt index 95458fac29e..a0ea27830d9 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt @@ -71,6 +71,7 @@ import software.aws.toolkits.jetbrains.isDeveloperMode import software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts.ArtifactManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.auth.DefaultAuthCredentialsService import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.DefaultModuleDependenciesService +import software.aws.toolkits.jetbrains.services.amazonq.lsp.editor.ActiveEditorChangeListener import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AmazonQLspTypeAdapterFactory import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsExtendedInitializeResult @@ -561,11 +562,12 @@ private class AmazonQServerInstance(private val project: Project, private val cs thread } - // Register active editor change listener - software.aws.toolkits.jetbrains.services.amazonq.lsp.editor.ActiveEditorChangeListener.register( + ActiveEditorChangeListener.register( project, executor - ) + ).also { + Disposer.register(this, it) + } LOG.info { "Registered active editor change listener" } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt index 7ab003f5a73..080f76b1e21 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt @@ -28,7 +28,7 @@ class ActiveEditorChangeListener( private val executor: ScheduledExecutorService, ) : Disposable { private var debounceTask: ScheduledFuture<*>? = null - private val DEBOUNCE_DELAY_MS = 100L + private val debounceDelayMs = 100L init { val connection = project.messageBus.connect(this) @@ -63,7 +63,7 @@ class ActiveEditorChangeListener( } catch (e: Exception) { LOG.warn(e) { "Failed to send active editor changed notification" } } - }, DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS) + }, debounceDelayMs, TimeUnit.MILLISECONDS) } override fun dispose() { @@ -75,7 +75,6 @@ class ActiveEditorChangeListener( fun register(project: Project, executor: ScheduledExecutorService): ActiveEditorChangeListener { val listener = ActiveEditorChangeListener(project, executor) - Disposer.register(project, listener) return listener } } From d278cd692027c2ea1445c10f199c16d35612e283 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Fri, 20 Jun 2025 13:51:50 -0400 Subject: [PATCH 4/9] fix: remove unused imports --- .../toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt | 1 - .../services/amazonq/lsp/editor/ActiveEditorChangeListener.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt index cce0af16070..b2c8854cf6d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt @@ -22,7 +22,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_QUICK_ACTION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SOURCE_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_ADD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_BAR_ACTIONS diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt index 080f76b1e21..9ab8dacdf71 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt @@ -10,7 +10,6 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.VirtualFile import org.eclipse.lsp4j.TextDocumentIdentifier import software.aws.toolkits.core.utils.getLogger From 31bc9ad6b2a4ea805f0aa72e6963f87fcc6fc110 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Fri, 20 Jun 2025 17:01:56 -0400 Subject: [PATCH 5/9] fix: remove ActiveEditorChangeListener --- .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 7 +- .../services/amazonq/lsp/AmazonQLspService.kt | 16 ---- .../lsp/editor/ActiveEditorChangeListener.kt | 80 ------------------- .../aws/editor/ActiveEditorChangedParams.kt | 12 --- .../TextDocumentServiceHandler.kt | 23 ++++++ 5 files changed, 28 insertions(+), 110 deletions(-) delete mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt delete mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 5e76282f918..b41c1f115e0 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFileManager import migration.software.aws.toolkits.jetbrains.settings.AwsSettings import org.eclipse.lsp4j.ConfigurationParams @@ -432,10 +433,12 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun sendPinnedContext(params: LSPAny): CompletableFuture { val chatManager = ChatCommunicationManager.getInstance(project) - // Get the active text editor and create text document identifier + // Send the active text file path with pinned context val editor = FileEditorManager.getInstance(project).selectedTextEditor val textDocument = editor?.let { - TextDocumentIdentifier(it.virtualFile.path) + val relativePath = VfsUtilCore.getRelativePath(it.virtualFile, project.baseDir) + ?: it.virtualFile.path // Use absolute path if not in project + TextDocumentIdentifier(relativePath) } // Create updated params with text document information diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt index a0ea27830d9..5b3b4dd107b 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt @@ -71,7 +71,6 @@ import software.aws.toolkits.jetbrains.isDeveloperMode import software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts.ArtifactManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.auth.DefaultAuthCredentialsService import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.DefaultModuleDependenciesService -import software.aws.toolkits.jetbrains.services.amazonq.lsp.editor.ActiveEditorChangeListener import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AmazonQLspTypeAdapterFactory import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsExtendedInitializeResult @@ -554,21 +553,6 @@ private class AmazonQServerInstance(private val project: Project, private val cs DefaultModuleDependenciesService(project).also { Disposer.register(this, it) } - - // Register active editor change listener - val executor = java.util.concurrent.Executors.newSingleThreadScheduledExecutor { r -> - val thread = Thread(r, "AmazonQ-EditorChangeListener") - thread.isDaemon = true - thread - } - - ActiveEditorChangeListener.register( - project, - executor - ).also { - Disposer.register(this, it) - } - LOG.info { "Registered active editor change listener" } } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt deleted file mode 100644 index 9ab8dacdf71..00000000000 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/editor/ActiveEditorChangeListener.kt +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package software.aws.toolkits.jetbrains.services.amazonq.lsp.editor - -import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.FileEditorManagerEvent -import com.intellij.openapi.fileEditor.FileEditorManagerListener -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile -import org.eclipse.lsp4j.TextDocumentIdentifier -import software.aws.toolkits.core.utils.getLogger -import software.aws.toolkits.core.utils.warn -import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.editor.ActiveEditorChangedParams -import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil -import java.util.concurrent.ScheduledExecutorService -import java.util.concurrent.ScheduledFuture -import java.util.concurrent.TimeUnit - -class ActiveEditorChangeListener( - private val project: Project, - private val executor: ScheduledExecutorService, -) : Disposable { - private var debounceTask: ScheduledFuture<*>? = null - private val debounceDelayMs = 100L - - init { - val connection = project.messageBus.connect(this) - connection.subscribe( - FileEditorManagerListener.FILE_EDITOR_MANAGER, - object : FileEditorManagerListener { - override fun selectionChanged(event: FileEditorManagerEvent) { - handleActiveEditorChange(event.newFile, event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) - } - } - ) - } - - private fun handleActiveEditorChange(file: VirtualFile?, editor: Editor?) { - // Cancel any pending notification - debounceTask?.cancel(false) - - // Schedule a new notification after the debounce period - debounceTask = executor.schedule({ - try { - val textDocument = file?.let { LspEditorUtil.toUriString(it) }?.let { TextDocumentIdentifier(it) } - val cursorState = editor?.let { LspEditorUtil.getCursorState(it) } - - val params = ActiveEditorChangedParams(textDocument, cursorState) - - // Send notification to the language server - ApplicationManager.getApplication().invokeLater { - AmazonQLspService.executeIfRunning(project) { _ -> - rawEndpoint.notify(ACTIVE_EDITOR_CHANGED_NOTIFICATION, params) - } - } - } catch (e: Exception) { - LOG.warn(e) { "Failed to send active editor changed notification" } - } - }, debounceDelayMs, TimeUnit.MILLISECONDS) - } - - override fun dispose() { - debounceTask?.cancel(true) - } - - companion object { - private val LOG = getLogger() - - fun register(project: Project, executor: ScheduledExecutorService): ActiveEditorChangeListener { - val listener = ActiveEditorChangeListener(project, executor) - return listener - } - } -} diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt deleted file mode 100644 index f9a3eca8ace..00000000000 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/editor/ActiveEditorChangedParams.kt +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.editor - -import org.eclipse.lsp4j.TextDocumentIdentifier -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CursorState - -data class ActiveEditorChangedParams( - val textDocument: TextDocumentIdentifier?, - val cursorState: CursorState?, -) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt index 500626d1440..fab6e213f40 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.editor.event.DocumentListener import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManagerListener import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key @@ -28,6 +29,8 @@ import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.TextDocumentItem import org.eclipse.lsp4j.VersionedTextDocumentIdentifier import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.toUriString import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread @@ -166,6 +169,26 @@ class TextDocumentServiceHandler( } } + override fun selectionChanged(event: FileEditorManagerEvent) { + handleActiveEditorChange(event.newFile, event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) + } + + private fun handleActiveEditorChange(file: VirtualFile?, editor: com.intellij.openapi.editor.Editor?) { + val editor = FileEditorManager.getInstance(project).selectedTextEditor + val textDocumentIdentifier = editor?.let { TextDocumentIdentifier(toUriString(it.virtualFile)) } + val cursorState = editor?.let { LspEditorUtil.getCursorState(it) } + + val params = mapOf( + "textDocument" to textDocumentIdentifier, + "cursorState" to cursorState + ) + + // Send notification to the language server + AmazonQLspService.executeIfRunning(project) { _ -> + rawEndpoint.notify(ACTIVE_EDITOR_CHANGED_NOTIFICATION, params) + } + } + private fun realTimeEdit(event: DocumentEvent) { AmazonQLspService.executeIfRunning(project) { languageServer -> pluginAwareExecuteOnPooledThread { From 33e4c6c07b23e0e2d05b8e0f49b84f0ebe87d3f6 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Sun, 22 Jun 2025 12:41:21 -0400 Subject: [PATCH 6/9] fix: failing detekt test --- .../lsp/textdocument/TextDocumentServiceHandler.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt index fab6e213f40..da5073bbfc3 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt @@ -30,7 +30,7 @@ import org.eclipse.lsp4j.TextDocumentItem import org.eclipse.lsp4j.VersionedTextDocumentIdentifier import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION -import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil +import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.getCursorState import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.toUriString import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread @@ -170,13 +170,13 @@ class TextDocumentServiceHandler( } override fun selectionChanged(event: FileEditorManagerEvent) { - handleActiveEditorChange(event.newFile, event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) + handleActiveEditorChange(event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) } - private fun handleActiveEditorChange(file: VirtualFile?, editor: com.intellij.openapi.editor.Editor?) { + private fun handleActiveEditorChange(editor: com.intellij.openapi.editor.Editor?) { val editor = FileEditorManager.getInstance(project).selectedTextEditor val textDocumentIdentifier = editor?.let { TextDocumentIdentifier(toUriString(it.virtualFile)) } - val cursorState = editor?.let { LspEditorUtil.getCursorState(it) } + val cursorState = editor?.let { getCursorState(it) } val params = mapOf( "textDocument" to textDocumentIdentifier, From 69bbdce719d386d1f476289a77f833b46d3d7a85 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Sun, 22 Jun 2025 12:54:31 -0400 Subject: [PATCH 7/9] fix: reuse ChatCommunicationManager instance --- .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index b41c1f115e0..918520d356d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -79,6 +79,7 @@ import java.util.concurrent.TimeUnit * Concrete implementation of [AmazonQLanguageClient] to handle messages sent from server */ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageClient { + private val chatManager = ChatCommunicationManager.getInstance(project) private fun handleTelemetryMap(telemetryMap: Map<*, *>) { try { @@ -206,7 +207,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun openTab(params: LSPAny): CompletableFuture { val requestId = UUID.randomUUID().toString() val result = CompletableFuture() - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.addTabOpenRequest(requestId, result) chatManager.notifyUi( @@ -257,7 +257,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun getSerializedChat(params: LSPAny): CompletableFuture { val requestId = UUID.randomUUID().toString() val result = CompletableFuture() - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.addSerializedChatRequest(requestId, result) chatManager.notifyUi( @@ -322,9 +321,8 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun notifyProgress(params: ProgressParams?) { if (params == null) return - val chatCommunicationManager = ChatCommunicationManager.getInstance(project) try { - chatCommunicationManager.handlePartialResultProgressNotification(project, params) + chatManager.handlePartialResultProgressNotification(project, params) } catch (e: Exception) { LOG.error(e) { "Cannot handle partial chat" } } @@ -420,7 +418,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC ) override fun sendContextCommands(params: LSPAny): CompletableFuture { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_SEND_CONTEXT_COMMANDS, @@ -431,8 +428,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC } override fun sendPinnedContext(params: LSPAny): CompletableFuture { - val chatManager = ChatCommunicationManager.getInstance(project) - // Send the active text file path with pinned context val editor = FileEditorManager.getInstance(project).selectedTextEditor val textDocument = editor?.let { @@ -465,7 +460,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC } override fun pinnedContextAdd(params: LSPAny): CompletableFuture { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_PINNED_CONTEXT_ADD, @@ -476,7 +470,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC } override fun pinnedContextRemove(params: LSPAny): CompletableFuture { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_PINNED_CONTEXT_REMOVE, @@ -500,7 +493,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC } override fun sendChatOptionsUpdate(params: LSPAny) { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_OPTIONS_UPDATE_NOTIFICATION, From 2c5762af501ccad868197ce8068d88a3b712fa8f Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Sun, 22 Jun 2025 14:20:17 -0400 Subject: [PATCH 8/9] fix: failing unit test and detekt failure --- .../lsp/textdocument/TextDocumentServiceHandler.kt | 9 ++++++--- .../amazonq/lsp/AmazonQLanguageClientImplTest.kt | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt index da5073bbfc3..387ee603557 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt @@ -10,9 +10,11 @@ import com.intellij.openapi.editor.event.DocumentEvent import com.intellij.openapi.editor.event.DocumentListener import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManagerListener +import com.intellij.openapi.fileEditor.FileEditor import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.fileEditor.TextEditor import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.vfs.VirtualFile @@ -170,11 +172,12 @@ class TextDocumentServiceHandler( } override fun selectionChanged(event: FileEditorManagerEvent) { - handleActiveEditorChange(event.newEditor?.let { FileEditorManager.getInstance(project).selectedTextEditor }) + handleActiveEditorChange(event.newEditor) } - private fun handleActiveEditorChange(editor: com.intellij.openapi.editor.Editor?) { - val editor = FileEditorManager.getInstance(project).selectedTextEditor + private fun handleActiveEditorChange(fileEditor: FileEditor?) { + // Extract text editor if it's a TextEditor, otherwise null + val editor = (fileEditor as? TextEditor)?.editor val textDocumentIdentifier = editor?.let { TextDocumentIdentifier(toUriString(it.virtualFile)) } val cursorState = editor?.let { getCursorState(it) } diff --git a/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt b/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt index 09c804abbf7..b1b11778b3e 100644 --- a/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt +++ b/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt @@ -33,6 +33,7 @@ import software.aws.toolkits.core.utils.test.aString import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection +import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.SsoProfileData import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization @@ -47,7 +48,14 @@ import kotlin.random.nextInt @ExtendWith(ApplicationExtension::class) class AmazonQLanguageClientImplTest { private val project: Project = mockk(relaxed = true) - private val sut = AmazonQLanguageClientImpl(project) + private val mockChatManager = mockk(relaxed = true) + private val sut: AmazonQLanguageClientImpl + + init { + // Mock the ChatCommunicationManager service + every { project.service() } returns mockChatManager + sut = AmazonQLanguageClientImpl(project) + } @Test fun `telemetryEvent handles basic event with name and data`() { From 7eb55a422154447ba02888ee36f301fd06243422 Mon Sep 17 00:00:00 2001 From: Avi Alpert Date: Mon, 23 Jun 2025 19:45:06 -0400 Subject: [PATCH 9/9] fix: respond to PR comments --- .../services/amazonq/lsp/AmazonQLanguageClient.kt | 6 +++--- .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 13 +++++-------- .../amazonq/lsp/AmazonQLanguageClientImplTest.kt | 10 +--------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt index dce7e7301ad..4eeafc4cea2 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt @@ -58,13 +58,13 @@ interface AmazonQLanguageClient : LanguageClient { fun sendContextCommands(params: LSPAny): CompletableFuture @JsonNotification(CHAT_SEND_PINNED_CONTEXT) - fun sendPinnedContext(params: LSPAny): CompletableFuture + fun sendPinnedContext(params: LSPAny) @JsonNotification(CHAT_PINNED_CONTEXT_ADD) - fun pinnedContextAdd(params: LSPAny): CompletableFuture + fun pinnedContextAdd(params: LSPAny) @JsonNotification(CHAT_PINNED_CONTEXT_REMOVE) - fun pinnedContextRemove(params: LSPAny): CompletableFuture + fun pinnedContextRemove(params: LSPAny) @JsonNotification(DID_COPY_FILE) fun copyFile(params: CopyFileParams) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 918520d356d..07b985c96ca 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -79,8 +79,8 @@ import java.util.concurrent.TimeUnit * Concrete implementation of [AmazonQLanguageClient] to handle messages sent from server */ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageClient { - private val chatManager = ChatCommunicationManager.getInstance(project) - + private val chatManager + get() = ChatCommunicationManager.getInstance(project) private fun handleTelemetryMap(telemetryMap: Map<*, *>) { try { val name = telemetryMap["name"] as? String ?: return @@ -427,7 +427,7 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC return CompletableFuture.completedFuture(Unit) } - override fun sendPinnedContext(params: LSPAny): CompletableFuture { + override fun sendPinnedContext(params: LSPAny) { // Send the active text file path with pinned context val editor = FileEditorManager.getInstance(project).selectedTextEditor val textDocument = editor?.let { @@ -456,27 +456,24 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC params = updatedParams, ) ) - return CompletableFuture.completedFuture(Unit) } - override fun pinnedContextAdd(params: LSPAny): CompletableFuture { + override fun pinnedContextAdd(params: LSPAny) { chatManager.notifyUi( FlareUiMessage( command = CHAT_PINNED_CONTEXT_ADD, params = params, ) ) - return CompletableFuture.completedFuture(Unit) } - override fun pinnedContextRemove(params: LSPAny): CompletableFuture { + override fun pinnedContextRemove(params: LSPAny) { chatManager.notifyUi( FlareUiMessage( command = CHAT_PINNED_CONTEXT_REMOVE, params = params, ) ) - return CompletableFuture.completedFuture(Unit) } override fun appendFile(params: FileParams) = refreshVfs(params.path) diff --git a/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt b/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt index b1b11778b3e..09c804abbf7 100644 --- a/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt +++ b/plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImplTest.kt @@ -33,7 +33,6 @@ import software.aws.toolkits.core.utils.test.aString import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection -import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.SsoProfileData import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization @@ -48,14 +47,7 @@ import kotlin.random.nextInt @ExtendWith(ApplicationExtension::class) class AmazonQLanguageClientImplTest { private val project: Project = mockk(relaxed = true) - private val mockChatManager = mockk(relaxed = true) - private val sut: AmazonQLanguageClientImpl - - init { - // Mock the ChatCommunicationManager service - every { project.service() } returns mockChatManager - sut = AmazonQLanguageClientImpl(project) - } + private val sut = AmazonQLanguageClientImpl(project) @Test fun `telemetryEvent handles basic event with name and data`() {