diff --git a/.changes/next-release/feature-3155ac52-b98c-47ab-8f9d-83d6bf377076.json b/.changes/next-release/feature-3155ac52-b98c-47ab-8f9d-83d6bf377076.json
new file mode 100644
index 00000000000..f9cfa9177b5
--- /dev/null
+++ b/.changes/next-release/feature-3155ac52-b98c-47ab-8f9d-83d6bf377076.json
@@ -0,0 +1,4 @@
+{
+ "type" : "feature",
+ "description" : "Amazon Q inline: now display completions much more consistently at the user's current caret position"
+}
\ No newline at end of file
diff --git a/.changes/next-release/feature-6a46f2ba-0d74-4385-afbc-896a9f13b90a.json b/.changes/next-release/feature-6a46f2ba-0d74-4385-afbc-896a9f13b90a.json
new file mode 100644
index 00000000000..c704c17f1eb
--- /dev/null
+++ b/.changes/next-release/feature-6a46f2ba-0d74-4385-afbc-896a9f13b90a.json
@@ -0,0 +1,4 @@
+{
+ "type" : "feature",
+ "description" : "Amazon Q inline: now Q completions can co-exist with JetBrains' native IntelliSense completions, when both are showing, press Tab or your customized key shortcuts to accept Q completions and press Enter to accept IntelliSense completions."
+}
\ No newline at end of file
diff --git a/.changes/next-release/feature-81882751-0f01-47db-8cd3-ee7955ef0c96.json b/.changes/next-release/feature-81882751-0f01-47db-8cd3-ee7955ef0c96.json
new file mode 100644
index 00000000000..ce99e68895b
--- /dev/null
+++ b/.changes/next-release/feature-81882751-0f01-47db-8cd3-ee7955ef0c96.json
@@ -0,0 +1,4 @@
+{
+ "type" : "feature",
+ "description" : "Amazon Q inline: now shows in a JetBrains native UX of popup and inlay text style"
+}
\ No newline at end of file
diff --git a/.changes/next-release/feature-b25741c4-9461-417f-979f-6203b3ce761c.json b/.changes/next-release/feature-b25741c4-9461-417f-979f-6203b3ce761c.json
new file mode 100644
index 00000000000..ce0cdc1951b
--- /dev/null
+++ b/.changes/next-release/feature-b25741c4-9461-417f-979f-6203b3ce761c.json
@@ -0,0 +1,4 @@
+{
+ "type" : "feature",
+ "description" : "Amazon Q inline: The new UX allows configurable shortcuts for accepting completions and navigating through completions. *Caveat: for users using the previous versions, if you have configured your custom key shortcuts for the Q inline before, you will have to re-configure them again in Amazon Q settings due to a change in the keymap actions."
+}
\ No newline at end of file
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/auth/AuthController.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/auth/AuthController.kt
index 5a4e03c9336..8b1844b55cb 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/auth/AuthController.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/auth/AuthController.kt
@@ -26,34 +26,24 @@ class AuthController {
*/
fun getAuthNeededStates(project: Project): AuthNeededStates {
val connectionState = checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q)
- val codeWhispererState = checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER)
// CW chat is enabled for Builder and IDC users, same for Amazon Q
return AuthNeededStates(
- chat = getAuthNeededState(connectionState, codeWhispererState),
- amazonQ = getAuthNeededState(connectionState, codeWhispererState)
+ chat = getAuthNeededState(connectionState),
+ amazonQ = getAuthNeededState(connectionState)
)
}
private fun getAuthNeededState(
amazonqConnectionState: ActiveConnection,
- codeWhispererConnectionState: ActiveConnection,
onlyIamIdcConnection: Boolean = false,
): AuthNeededState? =
when (amazonqConnectionState) {
ActiveConnection.NotConnected -> {
- if (codeWhispererConnectionState == ActiveConnection.NotConnected) {
- AuthNeededState(
- message = message("q.connection.disconnected"),
- authType = AuthFollowUpType.FullAuth,
- )
- } else {
- // There is a connection for codewhisperer, but it's not valid for Q
- AuthNeededState(
- message = message("q.connection.need_scopes"),
- authType = AuthFollowUpType.MissingScopes,
- )
- }
+ AuthNeededState(
+ message = message("q.connection.disconnected"),
+ authType = AuthFollowUpType.FullAuth,
+ )
}
is ActiveConnection.ValidBearer -> {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/resources/META-INF/plugin-codewhisperer.xml b/plugins/amazonq/codewhisperer/jetbrains-community/resources/META-INF/plugin-codewhisperer.xml
index 7fdcf371ad4..24de37b55d9 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/resources/META-INF/plugin-codewhisperer.xml
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/resources/META-INF/plugin-codewhisperer.xml
@@ -57,11 +57,10 @@
instance="software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable"
/>
-
-
-
+
+
+
@@ -90,29 +89,6 @@
text="Invoke Amazon Q Inline Suggestions">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src-242/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src-242/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt
new file mode 100644
index 00000000000..345078fe203
--- /dev/null
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src-242/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt
@@ -0,0 +1,21 @@
+// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codewhisperer.popup
+import com.intellij.codeInsight.inline.completion.InlineCompletionEvent
+import com.intellij.openapi.actionSystem.DataContext
+import com.intellij.openapi.editor.Editor
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE
+
+fun InlineCompletionEvent.isManualCall(): Boolean =
+ this is InlineCompletionEvent.DirectCall && this.context?.getData(DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE) == false
+
+fun getManualCallEvent(editor: Editor, isIntelliSenseAccept: Boolean): InlineCompletionEvent {
+ val dataContext = DataContext { dataId ->
+ when (dataId) {
+ DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE.name -> isIntelliSenseAccept
+ else -> null
+ }
+ }
+ return InlineCompletionEvent.DirectCall(editor, editor.caretModel.currentCaret, dataContext)
+}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src-243+/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src-243+/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt
new file mode 100644
index 00000000000..1f6e8dd7c06
--- /dev/null
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src-243+/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QManualCall.kt
@@ -0,0 +1,17 @@
+// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codewhisperer.popup
+import com.intellij.codeInsight.inline.completion.InlineCompletionEvent
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.util.UserDataHolderBase
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.KEY_Q_AUTO_TRIGGER_INTELLISENSE
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.Q_INLINE_PROVIDER_ID
+
+fun InlineCompletionEvent.isManualCall(): Boolean =
+ this is InlineCompletionEvent.ManualCall && this.additionalData.getUserData(KEY_Q_AUTO_TRIGGER_INTELLISENSE) == false
+
+fun getManualCallEvent(editor: Editor, isIntelliSenseAccept: Boolean): InlineCompletionEvent {
+ val data = UserDataHolderBase().apply { this.putUserData(KEY_Q_AUTO_TRIGGER_INTELLISENSE, isIntelliSenseAccept) }
+ return InlineCompletionEvent.ManualCall(editor, Q_INLINE_PROVIDER_ID, data)
+}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/CodeWhispererExplorerActionManager.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/CodeWhispererExplorerActionManager.kt
index e5f07904e64..efb99a7aa8c 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/CodeWhispererExplorerActionManager.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/CodeWhispererExplorerActionManager.kt
@@ -8,12 +8,9 @@ import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
-import org.jetbrains.annotations.ApiStatus
-import software.aws.toolkits.core.utils.getLogger
-import software.aws.toolkits.core.utils.warn
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
@@ -38,7 +35,7 @@ class CodeWhispererExplorerActionManager : PersistentStateComponent()
}
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererAcceptAction.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererAcceptAction.kt
deleted file mode 100644
index c7487cc80cc..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererAcceptAction.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.actions
-
-import com.intellij.openapi.actionSystem.ActionUpdateThread
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.project.DumbAware
-import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispererPopupManager
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
-import software.aws.toolkits.resources.message
-
-open class CodeWhispererAcceptAction(title: String = message("codewhisperer.inline.accept")) : AnAction(title), DumbAware {
- override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabled = e.project != null && e.getData(CommonDataKeys.EDITOR) != null &&
- CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val states = e.project?.getUserData(CodeWhispererPopupManager.KEY_INVOCATION_CONTEXT) ?: return
- if (!CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()) return
- ApplicationManager.getApplication().messageBus.syncPublisher(
- CodeWhispererPopupManager.CODEWHISPERER_USER_ACTION_PERFORMED
- ).beforeAccept(states, CodeWhispererPopupManager.getInstance().sessionContext)
- }
-}
-
-// A same accept action but different key shortcut and different promoter logic
-class CodeWhispererForceAcceptAction(title: String = message("codewhisperer.inline.force.accept")) : CodeWhispererAcceptAction(title)
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererActionPromoter.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererActionPromoter.kt
deleted file mode 100644
index 1e165f67f14..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererActionPromoter.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.actions
-
-import com.intellij.openapi.actionSystem.ActionPromoter
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.DataContext
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatusNew
-
-class CodeWhispererActionPromoter : ActionPromoter {
- override fun promote(actions: MutableList, context: DataContext): MutableList {
- val results = actions.toMutableList()
- if (!CodeWhispererInvocationStatusNew.getInstance().isDisplaySessionActive() &&
- !CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()
- ) {
- return results
- }
-
- results.sortWith { a, b ->
- if (isCodeWhispererForceAction(a)) {
- return@sortWith -1
- } else if (isCodeWhispererForceAction(b)) {
- return@sortWith 1
- }
-
- if (isCodeWhispererAcceptAction(a)) {
- return@sortWith -1
- } else if (isCodeWhispererAcceptAction(b)) {
- return@sortWith 1
- }
-
- 0
- }
-
- results.sortWith { a, b ->
- if (isCodeWhispererNavigateAction(a)) {
- return@sortWith -1
- } else if (isCodeWhispererNavigateAction(b)) {
- return@sortWith 1
- }
-
- 0
- }
- return results
- }
-
- private fun isCodeWhispererAcceptAction(action: AnAction): Boolean = action is CodeWhispererAcceptAction
-
- private fun isCodeWhispererForceAcceptAction(action: AnAction): Boolean =
- action is CodeWhispererForceAcceptAction
-
- private fun isCodeWhispererNavigateAction(action: AnAction): Boolean =
- action is CodeWhispererNavigateNextAction || action is CodeWhispererNavigatePrevAction
-
- private fun isCodeWhispererForceAction(action: AnAction): Boolean =
- isCodeWhispererForceAcceptAction(action) || isCodeWhispererNavigateAction(action)
-}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigateNextAction.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigateNextAction.kt
deleted file mode 100644
index 3a0be77bc9b..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigateNextAction.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.actions
-
-import com.intellij.openapi.actionSystem.ActionUpdateThread
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.project.DumbAware
-import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispererPopupManager
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
-import software.aws.toolkits.resources.message
-
-class CodeWhispererNavigateNextAction : AnAction(message("codewhisperer.inline.navigate.next")), DumbAware {
- override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabled = e.project != null &&
- e.getData(CommonDataKeys.EDITOR) != null &&
- CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val states = e.project?.getUserData(CodeWhispererPopupManager.KEY_INVOCATION_CONTEXT) ?: return
- if (!CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()) return
- ApplicationManager.getApplication().messageBus.syncPublisher(
- CodeWhispererPopupManager.CODEWHISPERER_USER_ACTION_PERFORMED
- ).navigateNext(states)
- }
-}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigatePrevAction.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigatePrevAction.kt
deleted file mode 100644
index 8fc05cdc7a2..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererNavigatePrevAction.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.actions
-
-import com.intellij.openapi.actionSystem.ActionUpdateThread
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.project.DumbAware
-import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispererPopupManager
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
-import software.aws.toolkits.resources.message
-
-class CodeWhispererNavigatePrevAction : AnAction(message("codewhisperer.inline.navigate.previous")), DumbAware {
- override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabled = e.project != null &&
- e.getData(CommonDataKeys.EDITOR) != null &&
- CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val states = e.project?.getUserData(CodeWhispererPopupManager.KEY_INVOCATION_CONTEXT) ?: return
- if (!CodeWhispererInvocationStatus.getInstance().isDisplaySessionActive()) return
- ApplicationManager.getApplication().messageBus.syncPublisher(
- CodeWhispererPopupManager.CODEWHISPERER_USER_ACTION_PERFORMED
- ).navigatePrevious(states)
- }
-}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererRecommendationAction.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererRecommendationAction.kt
index e4755cdabee..6243b1455a4 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererRecommendationAction.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererRecommendationAction.kt
@@ -12,9 +12,7 @@ import com.intellij.openapi.util.Key
import kotlinx.coroutines.Job
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
-import software.aws.toolkits.jetbrains.services.codewhisperer.model.LatencyContext
-import software.aws.toolkits.jetbrains.services.codewhisperer.model.TriggerTypeInfo
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutomatedTriggerType
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererService
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererServiceNew
import software.aws.toolkits.resources.message
@@ -33,8 +31,6 @@ class CodeWhispererRecommendationAction : AnAction(message("codewhisperer.trigge
if (QRegionProfileManager.getInstance().hasValidConnectionButNoActiveProfile(project)) {
return
}
- val latencyContext = LatencyContext()
- latencyContext.codewhispererEndToEndStart = System.nanoTime()
val editor = e.getRequiredData(CommonDataKeys.EDITOR)
if (!(
if (CodeWhispererFeatureConfigService.getInstance().getNewAutoTriggerUX()) {
@@ -47,14 +43,7 @@ class CodeWhispererRecommendationAction : AnAction(message("codewhisperer.trigge
return
}
- val triggerType = TriggerTypeInfo(CodewhispererTriggerType.OnDemand, CodeWhispererAutomatedTriggerType.Unknown())
- val job = if (CodeWhispererFeatureConfigService.getInstance().getNewAutoTriggerUX()) {
- CodeWhispererServiceNew.getInstance().showRecommendationsInPopup(editor, triggerType, latencyContext)
- } else {
- CodeWhispererService.getInstance().showRecommendationsInPopup(editor, triggerType, latencyContext)
- }
-
- e.getData(CommonDataKeys.EDITOR)?.getUserData(ACTION_JOB_KEY)?.set(job)
+ QInlineCompletionProvider.invokeCompletion(editor)
}
companion object {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt
index 674bcdf9500..839c0c3b3e8 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt
@@ -64,7 +64,7 @@ import software.aws.toolkits.jetbrains.core.coroutines.EDT
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineUiContext
import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.listeners.CodeWhispererCodeScanDocumentListener
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.listeners.CodeWhispererCodeScanEditorMouseMotionListener
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.listeners.CodeWhispererCodeScanFileListener
@@ -397,7 +397,7 @@ class CodeWhispererCodeScanManager(val project: Project) {
var codeScanStatus: Result = Result.Failed
val startTime = Instant.now().toEpochMilli()
var codeScanResponseContext = defaultCodeScanResponseContext()
- val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
var language: CodeWhispererProgrammingLanguage = CodeWhispererUnknownLanguage.INSTANCE
var skipTelemetry = false
try {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEnterHandler.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEnterHandler.kt
deleted file mode 100644
index fbaec53e3d3..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEnterHandler.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.editor
-
-import com.intellij.codeInsight.editorActions.EnterHandler
-import com.intellij.openapi.actionSystem.DataContext
-import com.intellij.openapi.editor.Caret
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.editor.actionSystem.EditorActionHandler
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutoTriggerService
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutomatedTriggerType
-import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
-
-class CodeWhispererEnterHandler(private val originalHandler: EditorActionHandler) : EnterHandler(originalHandler) {
- override fun executeWriteAction(editor: Editor, caret: Caret?, dataContext: DataContext?) {
- originalHandler.execute(editor, caret, dataContext)
-
- pluginAwareExecuteOnPooledThread {
- CodeWhispererAutoTriggerService.getInstance().invoke(editor, CodeWhispererAutomatedTriggerType.Enter())
- }
- }
-}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererTypedHandler.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererTypedHandler.kt
deleted file mode 100644
index e585bc5d486..00000000000
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererTypedHandler.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.services.codewhisperer.editor
-
-import com.intellij.codeInsight.editorActions.TypedHandlerDelegate
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiFile
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutoTriggerService
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutomatedTriggerType
-import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
-
-class CodeWhispererTypedHandler : TypedHandlerDelegate() {
- override fun charTyped(c: Char, project: Project, editor: Editor, psiFiles: PsiFile): Result {
- // Special Char
- if (CodeWhispererConstants.SPECIAL_CHARACTERS_LIST.contains(c.toString())) {
- CodeWhispererAutoTriggerService.getInstance().invoke(editor, CodeWhispererAutomatedTriggerType.SpecialChar(c))
- return Result.CONTINUE
- }
-
- CodeWhispererAutoTriggerService.getInstance().invoke(editor, CodeWhispererAutomatedTriggerType.Classifier())
-
- return Result.CONTINUE
- }
-}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/actions/Customize.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/actions/Customize.kt
index d7c27c0137f..1330046dbe1 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/actions/Customize.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/actions/Customize.kt
@@ -8,7 +8,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.DumbAwareAction
import icons.AwsIcons
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator
import software.aws.toolkits.resources.message
@@ -20,7 +20,7 @@ class Customize : DumbAwareAction(
override fun update(e: AnActionEvent) {
val project = e.project ?: return
- val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
val activeCustomization = CodeWhispererModelConfigurator.getInstance().activeCustomization(project)
if (connection != null) {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/importadder/CodeWhispererImportAdder.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/importadder/CodeWhispererImportAdder.kt
index 623395afe49..d4657aa06f1 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/importadder/CodeWhispererImportAdder.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/importadder/CodeWhispererImportAdder.kt
@@ -5,6 +5,7 @@ package software.aws.toolkits.jetbrains.services.codewhisperer.importadder
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -40,9 +41,13 @@ abstract class CodeWhispererImportAdder {
}
}
- private fun insertImportStatement(states: InvocationContext, import: InlineCompletionImports) {
- val project = states.requestContext.project
- val editor = states.requestContext.editor
+ fun insertImportStatements(project: Project, editor: Editor, imports: List?) {
+ imports?.forEach {
+ insertImportStatement(project, editor, it)
+ }
+ }
+
+ private fun insertImportStatement(project: Project, editor: Editor, import: InlineCompletionImports) {
val document = editor.document
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document) ?: return
@@ -72,6 +77,12 @@ abstract class CodeWhispererImportAdder {
LOG.info { "Added import: $added" }
}
+ private fun insertImportStatement(states: InvocationContext, import: InlineCompletionImports) {
+ val project = states.requestContext.project
+ val editor = states.requestContext.editor
+ insertImportStatement(project, editor, import)
+ }
+
private fun insertImportStatement(states: InvocationContextNew, import: InlineCompletionImports) {
val project = states.requestContext.project
val editor = states.requestContext.editor
@@ -154,5 +165,8 @@ abstract class CodeWhispererImportAdder {
fun get(language: CodeWhispererProgrammingLanguage): CodeWhispererImportAdder? =
EP.extensionList.firstOrNull { language in it.supportedLanguages }
?: EP.extensionList.find { it is CodeWhispererFallbackImportAdder }
+
+ fun getFallback(): CodeWhispererImportAdder? =
+ EP.extensionList.find { it is CodeWhispererFallbackImportAdder }
}
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/model/CodeWhispererModel.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/model/CodeWhispererModel.kt
index 61157a2a1d1..3e647d564f0 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/model/CodeWhispererModel.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/model/CodeWhispererModel.kt
@@ -3,6 +3,7 @@
package software.aws.toolkits.jetbrains.services.codewhisperer.model
+import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement
import com.intellij.openapi.Disposable
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.VisualPosition
@@ -10,7 +11,9 @@ import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.popup.JBPopup
import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.UserDataHolderBase
import com.intellij.util.concurrency.annotations.RequiresEdt
+import kotlinx.coroutines.channels.Channel
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionItem
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionListWithReferences
@@ -235,3 +238,21 @@ data class TryExampleRowContext(
val description: String,
val filename: String?,
)
+
+data class InlineCompletionSessionContext(
+ val itemContexts: MutableList = mutableListOf(),
+ var sessionId: String = "",
+ val triggerOffset: Int,
+ var counter: Int = 0,
+)
+
+data class InlineCompletionItemContext(
+ val project: Project,
+ var item: InlineCompletionItem?,
+ val channel: Channel,
+ val data: UserDataHolderBase = UserDataHolderBase(),
+ var hasSeen: Boolean = false,
+ var isAccepted: Boolean = false,
+ var isDiscarded: Boolean = false,
+ var isEmpty: Boolean = false,
+)
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupComponents.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupComponents.kt
index cd6d4bea4d5..d5f391e0897 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupComponents.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupComponents.kt
@@ -44,7 +44,7 @@ import javax.swing.JLabel
import javax.swing.JPanel
class CodeWhispererPopupComponents {
- val prevButton = createNavigationButton(prevButtonText())
+ val prevButton = createNavigationButton("←")
fun prevButtonText() =
message(
"codewhisperer.popup.button.prev",
@@ -53,7 +53,7 @@ class CodeWhispererPopupComponents {
ActionManager.getInstance().getAction("codewhisperer.inline.navigate.previous")
)
)
- val nextButton = createNavigationButton(nextButtonText()).apply { preferredSize = prevButton.preferredSize }
+ val nextButton = createNavigationButton("→").apply { preferredSize = prevButton.preferredSize }
fun nextButtonText() = message(
"codewhisperer.popup.button.next",
POPUP_DIM_HEX,
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionInsertHandler.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionInsertHandler.kt
new file mode 100644
index 00000000000..83f827d1946
--- /dev/null
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionInsertHandler.kt
@@ -0,0 +1,11 @@
+// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codewhisperer.popup
+
+import com.intellij.codeInsight.inline.completion.InlineCompletionInsertHandler
+import com.intellij.openapi.editor.Editor
+
+interface QInlineCompletionInsertHandler : InlineCompletionInsertHandler {
+ fun afterTyped(editor: Editor, startOffset: Int)
+}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt
new file mode 100644
index 00000000000..a092798cb67
--- /dev/null
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt
@@ -0,0 +1,591 @@
+// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codewhisperer.popup
+
+import com.intellij.codeInsight.hint.HintManager
+import com.intellij.codeInsight.inline.completion.InlineCompletion
+import com.intellij.codeInsight.inline.completion.InlineCompletionEvent
+import com.intellij.codeInsight.inline.completion.InlineCompletionEventAdapter
+import com.intellij.codeInsight.inline.completion.InlineCompletionEventType
+import com.intellij.codeInsight.inline.completion.InlineCompletionHandler
+import com.intellij.codeInsight.inline.completion.InlineCompletionInsertEnvironment
+import com.intellij.codeInsight.inline.completion.InlineCompletionProvider
+import com.intellij.codeInsight.inline.completion.InlineCompletionProviderID
+import com.intellij.codeInsight.inline.completion.InlineCompletionProviderPresentation
+import com.intellij.codeInsight.inline.completion.InlineCompletionRequest
+import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement
+import com.intellij.codeInsight.inline.completion.elements.InlineCompletionGrayTextElement
+import com.intellij.codeInsight.inline.completion.logs.InlineCompletionUsageTracker
+import com.intellij.codeInsight.inline.completion.session.InlineCompletionSession
+import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionSuggestion
+import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionSuggestionUpdateManager
+import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionVariant
+import com.intellij.openapi.actionSystem.DataKey
+import com.intellij.openapi.application.runInEdt
+import com.intellij.openapi.application.runReadAction
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.Key
+import com.intellij.ui.dsl.builder.Cell
+import com.intellij.ui.dsl.builder.RightGap
+import com.intellij.ui.dsl.builder.panel
+import com.intellij.ui.dsl.builder.text
+import com.intellij.ui.dsl.gridLayout.UnscaledGaps
+import com.intellij.ui.util.preferredHeight
+import icons.AwsIcons
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.flow.receiveAsFlow
+import kotlinx.coroutines.future.await
+import kotlinx.coroutines.launch
+import migration.software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager
+import org.eclipse.lsp4j.jsonrpc.messages.Either
+import software.aws.toolkits.core.utils.debug
+import software.aws.toolkits.core.utils.getLogger
+import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
+import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
+import software.aws.toolkits.jetbrains.services.codewhisperer.importadder.CodeWhispererImportAdder
+import software.aws.toolkits.jetbrains.services.codewhisperer.model.InlineCompletionItemContext
+import software.aws.toolkits.jetbrains.services.codewhisperer.model.InlineCompletionSessionContext
+import software.aws.toolkits.jetbrains.services.codewhisperer.model.LatencyContext
+import software.aws.toolkits.jetbrains.services.codewhisperer.model.TriggerTypeInfo
+import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutomatedTriggerType
+import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
+import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererService
+import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
+import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
+import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
+import software.aws.toolkits.jetbrains.utils.isQConnected
+import software.aws.toolkits.resources.message
+import software.aws.toolkits.telemetry.CodewhispererTriggerType
+import java.awt.Dimension
+import javax.swing.Icon
+import javax.swing.JComponent
+import javax.swing.JEditorPane
+import javax.swing.JLabel
+
+class QInlineCompletionProvider(private val cs: CoroutineScope) : InlineCompletionProvider {
+ // TODO: good news is that suggestionUpdateManager can be overridden, this means we can define custom behaviors
+ // such as on backspace when variants are showing, future improvements
+ override val suggestionUpdateManager: InlineCompletionSuggestionUpdateManager
+ get() = super.suggestionUpdateManager
+ override val insertHandler: QInlineCompletionInsertHandler
+ get() = object : QInlineCompletionInsertHandler {
+ override fun afterTyped(editor: Editor, startOffset: Int) {
+ insertCodeReferencesAndImports(editor, startOffset)
+ }
+
+ override fun afterInsertion(environment: InlineCompletionInsertEnvironment, elements: List) {
+ insertCodeReferencesAndImports(environment.editor, environment.insertedRange.startOffset)
+ }
+
+ private fun insertCodeReferencesAndImports(editor: Editor, startOffset: Int) {
+ currentAcceptedItemContext?.let {
+ CodeWhispererCodeReferenceManager.getInstance(it.project).insertCodeReference(editor, it.item, startOffset)
+ val importAdder = CodeWhispererImportAdder.getFallback()
+ if (importAdder == null) {
+ logInline(triggerSessionId) {
+ "No import adder found for JB inline"
+ }
+ return
+ }
+ importAdder.insertImportStatements(it.project, editor, it.item?.mostRelevantMissingImports)
+ logInline(triggerSessionId) {
+ "Accepted suggestion has ${it.item?.references?.size ?: 0} references and " +
+ "${it.item?.mostRelevantMissingImports?.size ?: 0} imports"
+ }
+ }
+ }
+ }
+ override val id: InlineCompletionProviderID = Q_INLINE_PROVIDER_ID
+ override val providerPresentation: InlineCompletionProviderPresentation
+ get() = object : InlineCompletionProviderPresentation {
+ override fun getTooltip(project: Project?): JComponent {
+ project ?: return JLabel()
+ val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return JLabel()
+ val session = InlineCompletionSession.getOrNull(editor) ?: return JLabel()
+ return qToolTip(
+ "Amazon Q",
+ AwsIcons.Logos.AWS_Q_GRADIENT_SMALL,
+ session
+ )
+ }
+ }
+ private var cell: Cell? = null
+ private var triggerSessionId = 0
+ private var currentAcceptedItemContext: InlineCompletionItemContext? = null
+
+ // not needed for current implementation, will need this when we support concurrent triggers, so leave it here
+ private val activeTriggerSessions = mutableMapOf()
+
+ fun qToolTip(
+ title: String,
+ icon: Icon,
+ session: InlineCompletionSession,
+ ): JComponent {
+ return panel {
+ row {
+ icon(icon).gap(RightGap.SMALL)
+ comment(title).gap(RightGap.SMALL)
+ cell(navigationButton(session, "←")).gap(RightGap.SMALL)
+ text(indexDisplayText(session)).gap(RightGap.SMALL).applyToComponent {
+ // workaround of text cutoff issue: 21 is the max width of all its possible strings (4/5)
+ this.preferredSize = Dimension(21, this.preferredHeight)
+ }.also {
+ cell = it
+ }
+ cell(navigationButton(session, "→"))
+
+ // if there are imports and references, add them here
+ val item = session.capture()?.activeVariant?.data?.getUserData(KEY_Q_INLINE_ITEM_CONTEXT)?.item ?: return@row
+ val imports = item.mostRelevantMissingImports
+ val references = item.references
+
+ if (!imports.isNullOrEmpty()) {
+ cell(
+ JLabel("${imports.size} imports").apply {
+ toolTipText = "${imports.joinToString("
") { it.statement }}"
+ }
+ )
+ }
+ val components = CodeWhispererPopupManager.getInstance().popupComponents
+ if (!references.isNullOrEmpty()) {
+ cell(JLabel("Reference code under ")).customize(UnscaledGaps.EMPTY)
+ references.forEachIndexed { i, reference ->
+ cell(components.licenseLink(reference.licenseName)).customize(UnscaledGaps.EMPTY)
+ if (i == references.size - 1) return@forEachIndexed
+ cell(JLabel(", ")).customize(UnscaledGaps.EMPTY)
+ }
+ }
+ }
+ }
+ }
+
+ private fun getDisplayVariantIndex(session: InlineCompletionSession, direction: Int) =
+ getCurrentValidVariantIndex(session, direction) + 1
+
+ private fun getCurrentValidVariantIndex(session: InlineCompletionSession, direction: Int): Int {
+ val variants = session.capture()?.variants ?: return -1
+ // the variants snapshots at this point either 1) have elements(normal case) 2) have no elements but have
+ // data (trySend(elements) hasn't finished), so need to check both
+ val validVariants = variants.filter { isValidVariant(it) }
+ if (validVariants.isEmpty()) return 0
+ return (validVariants.indexOfFirst { it.isActive } + direction + validVariants.size) % validVariants.size
+ }
+
+ fun getAllValidVariantsCount(session: InlineCompletionSession) =
+ session.capture()?.variants?.count { isValidVariant(it) } ?: 0
+
+ private fun isValidVariant(variant: InlineCompletionVariant.Snapshot) =
+ (
+ (!variant.isEmpty() && variant.elements.any { it.text.isNotEmpty() }) ||
+ variant.data.getUserData(KEY_Q_INLINE_ITEM_CONTEXT)?.item != null
+ ) &&
+ variant.state != InlineCompletionVariant.Snapshot.State.INVALIDATED
+
+ companion object {
+ private const val MAX_CHANNELS = 5
+ private val LOG = getLogger()
+ val Q_INLINE_PROVIDER_ID = InlineCompletionProviderID("Amazon Q")
+ val KEY_Q_INLINE_ITEM_CONTEXT = Key("amazon.q.inline.completion.item.context")
+
+ val DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE = DataKey.create("amazon.q.auto.trigger.intellisense")
+ val KEY_Q_AUTO_TRIGGER_INTELLISENSE = Key("amazon.q.auto.trigger.intellisense")
+
+ fun invokeCompletion(editor: Editor, isIntelliSenseAccept: Boolean = false) {
+ val event = getManualCallEvent(editor, isIntelliSenseAccept)
+ InlineCompletion.getHandlerOrNull(editor)?.invokeEvent(event)
+ }
+
+ fun logInline(triggerSessionId: Int, e: Throwable? = null, block: () -> String) {
+ LOG.debug(e) { "Q inline: Trigger session $triggerSessionId: ${block()}" }
+ }
+ }
+
+ private fun addQInlineCompletionListener(
+ project: Project,
+ editor: Editor,
+ session: InlineCompletionSession,
+ handler: InlineCompletionHandler,
+ triggerSessionId: Int,
+ latencyContext: LatencyContext,
+ sessionContext: InlineCompletionSessionContext,
+ ) {
+ handler.addEventListener(
+ object : InlineCompletionEventAdapter {
+ // when all computations are done
+ override fun onCompletion(event: InlineCompletionEventType.Completion) {
+ CodeWhispererInvocationStatus.getInstance().setIsInvokingQInline(session, false)
+ updateDisplayIndex(session)
+ logInline(triggerSessionId) {
+ "Session pagination progress is complete, now showing suggestions"
+ }
+ super.onCompletion(event)
+ }
+
+ override fun onComputed(event: InlineCompletionEventType.Computed) {
+ updateDisplayIndex(session)
+ super.onComputed(event)
+ }
+
+ override fun onShow(event: InlineCompletionEventType.Show) {
+ val isFirstTimeShowing = sessionContext.itemContexts.all { !it.hasSeen }
+ setSelectedVariantAsSeen(sessionContext, event.variantIndex)
+ if (isFirstTimeShowing) {
+ CodeWhispererInvocationStatus.getInstance().completionShown()
+ latencyContext.codewhispererEndToEndEnd = System.nanoTime()
+
+ // For JB inline completion UX, no userInput
+ latencyContext.perceivedLatency = latencyContext.getCodeWhispererEndToEndLatency()
+
+ logInline(triggerSessionId) {
+ "Session first time showing, perceived E2E latency: ${latencyContext.perceivedLatency}"
+ }
+ }
+ super.onShow(event)
+ }
+
+ override fun onInvalidated(event: InlineCompletionEventType.Invalidated) {
+ updateDisplayIndex(session)
+ super.onInvalidated(event)
+ }
+
+ override fun onEmpty(event: InlineCompletionEventType.Empty) {
+ setSelectedVariantAsDiscarded(sessionContext, event.variantIndex)
+ setSelectedVariantAsSeen(sessionContext, event.variantIndex, seen = false)
+ super.onEmpty(event)
+ }
+
+ override fun onVariantSwitched(event: InlineCompletionEventType.VariantSwitched) {
+ updateDisplayIndex(session, event.toVariantIndex - event.fromVariantIndex)
+ setSelectedVariantAsSeen(sessionContext, event.toVariantIndex)
+ logInline(triggerSessionId) {
+ "Switching to variant ${event.toVariantIndex}"
+ }
+ super.onVariantSwitched(event)
+ }
+
+ override fun onInsert(event: InlineCompletionEventType.Insert) {
+ currentAcceptedItemContext = session.capture()?.activeVariant?.data?.getUserData(KEY_Q_INLINE_ITEM_CONTEXT)
+ }
+
+ override fun onHide(event: InlineCompletionEventType.Hide) {
+ logInline(triggerSessionId) {
+ "Exiting display session with reason: ${event.finishType}"
+ }
+ super.onHide(event)
+ when (event.finishType) {
+ InlineCompletionUsageTracker.ShownEvents.FinishType.CARET_CHANGED,
+ InlineCompletionUsageTracker.ShownEvents.FinishType.MOUSE_PRESSED,
+ InlineCompletionUsageTracker.ShownEvents.FinishType.EDITOR_REMOVED,
+ InlineCompletionUsageTracker.ShownEvents.FinishType.ESCAPE_PRESSED,
+ InlineCompletionUsageTracker.ShownEvents.FinishType.BACKSPACE_PRESSED,
+ -> {
+ setCurrentVariantAsRejected(session)
+ }
+ InlineCompletionUsageTracker.ShownEvents.FinishType.TYPED -> {
+ // TYPED finished type will not trigger insert hook from JB (to insert imports and references) so have to manually set and invoke here
+ currentAcceptedItemContext = session.capture()?.activeVariant?.data?.getUserData(KEY_Q_INLINE_ITEM_CONTEXT)
+ insertHandler.afterTyped(editor, sessionContext.triggerOffset)
+ setCurrentVariantAsAccepted(session)
+ }
+ InlineCompletionUsageTracker.ShownEvents.FinishType.EMPTY -> {
+ if (session.request.event.isManualCall()) {
+ runInEdt {
+ HintManager.getInstance().showInformationHint(
+ session.editor,
+ message("codewhisperer.popup.no_recommendations"),
+ HintManager.UNDER
+ )
+ }
+ }
+ // language server returns EMPTY_RESULT, no need to send any telemetry.
+ }
+ InlineCompletionUsageTracker.ShownEvents.FinishType.INVALIDATED -> {
+ // TODO: for current version, always send discard event for invalidated sessions, language server
+ // also sends a discarded event on their side. In a future version
+ // we will support concurrent triggers first in language server and then here.
+ // as of now, for INVALIDATED JB can send discard to language server regardless
+ val atLeastOneSeen = sessionContext.itemContexts.any { it.hasSeen }
+ if (!atLeastOneSeen) {
+ repeat(sessionContext.itemContexts.size) { i ->
+ setSelectedVariantAsDiscarded(sessionContext, i)
+ }
+ }
+ }
+ InlineCompletionUsageTracker.ShownEvents.FinishType.SELECTED -> {
+ setCurrentVariantAsAccepted(session)
+ }
+ else -> {
+ logInline(triggerSessionId) {
+ "Closing session for unchecked reason: ${event.finishType}"
+ }
+ }
+ }
+ cs.launch {
+ CodeWhispererTelemetryService.getInstance().sendUserTriggerDecisionEventForTriggerSession(
+ project,
+ latencyContext,
+ sessionContext,
+ triggerSessionId,
+ )
+ activeTriggerSessions.remove(triggerSessionId)
+ }
+ }
+ },
+ session
+ )
+ }
+
+ private fun updateDisplayIndex(session: InlineCompletionSession, steps: Int = 0) {
+ cell?.text(indexDisplayText(session, steps))
+ }
+
+ private fun indexDisplayText(session: InlineCompletionSession, steps: Int = 0) =
+ "${getDisplayVariantIndex(session, steps)}/${getAllValidVariantsCount(session)}"
+
+ private fun setCurrentVariantAsAccepted(session: InlineCompletionSession, isAccepted: Boolean = true) {
+ session.capture()?.activeVariant?.data?.getUserData(KEY_Q_INLINE_ITEM_CONTEXT)?.isAccepted = isAccepted
+ }
+
+ private fun setCurrentVariantAsRejected(session: InlineCompletionSession) {
+ setCurrentVariantAsAccepted(session, false)
+ }
+
+ private fun setSelectedVariantAsSeen(sessionContext: InlineCompletionSessionContext, index: Int, seen: Boolean = true) {
+ sessionContext.itemContexts[index].hasSeen = seen
+ }
+
+ private fun setSelectedVariantAsDiscarded(sessionContext: InlineCompletionSessionContext, index: Int) {
+ sessionContext.itemContexts[index].isDiscarded = true
+ }
+
+ private fun getTriggerTypeInfo(request: InlineCompletionRequest): TriggerTypeInfo {
+ val event = request.event
+ val triggerType = if (event.isManualCall()) CodewhispererTriggerType.OnDemand else CodewhispererTriggerType.AutoTrigger
+ val automatedTriggerType = when (triggerType) {
+ CodewhispererTriggerType.AutoTrigger -> {
+ val triggerString = request.document.charsSequence.substring(request.startOffset, request.endOffset)
+ if (triggerString.startsWith(System.lineSeparator())) {
+ CodeWhispererAutomatedTriggerType.Enter()
+ } else if (CodeWhispererConstants.SPECIAL_CHARACTERS_LIST.contains(triggerString)) {
+ CodeWhispererAutomatedTriggerType.SpecialChar(triggerString.single())
+ } else if (event.isManualCall()) {
+ CodeWhispererAutomatedTriggerType.IntelliSense()
+ } else {
+ CodeWhispererAutomatedTriggerType.Classifier()
+ }
+ }
+ CodewhispererTriggerType.OnDemand,
+ CodewhispererTriggerType.Unknown,
+ -> {
+ CodeWhispererAutomatedTriggerType.Unknown()
+ }
+ }
+ return TriggerTypeInfo(triggerType, automatedTriggerType)
+ }
+
+ override suspend fun getSuggestion(request: InlineCompletionRequest): InlineCompletionSuggestion {
+ val editor = request.editor
+ val document = editor.document
+ val project = editor.project ?: return InlineCompletionSuggestion.Empty
+ val handler = InlineCompletion.getHandlerOrNull(editor) ?: return InlineCompletionSuggestion.Empty
+ val session = InlineCompletionSession.getOrNull(editor) ?: return InlineCompletionSuggestion.Empty
+ val triggerSessionId = triggerSessionId++
+ val latencyContext = LatencyContext(codewhispererEndToEndStart = System.nanoTime())
+ val triggerTypeInfo = getTriggerTypeInfo(request)
+
+ CodeWhispererInvocationStatus.getInstance().setIsInvokingQInline(session, true)
+ Disposer.register(session) {
+ CodeWhispererInvocationStatus.getInstance().setIsInvokingQInline(session, false)
+ }
+
+ val sessionContext = InlineCompletionSessionContext(triggerOffset = request.endOffset)
+
+ // Pagination workaround: Always return exactly 5 variants
+ // Create channel placeholder for upcoming pagination results
+ // this is the only known way paginated items can show later
+ repeat(MAX_CHANNELS) {
+ sessionContext.itemContexts.add(InlineCompletionItemContext(project, null, Channel(Channel.UNLIMITED)))
+ }
+
+ activeTriggerSessions[triggerSessionId] = sessionContext
+
+ addQInlineCompletionListener(project, editor, session, handler, triggerSessionId, latencyContext, sessionContext)
+
+ runReadAction {
+ logInline(triggerSessionId) {
+ "Initializing trigger session, " +
+ "event type: ${request.event.javaClass.simpleName}, " +
+ "startOffset: ${request.startOffset}, " +
+ "endOffset: ${request.endOffset}, " +
+ "trigger text: ${document.charsSequence.subSequence(request.startOffset, request.endOffset)}, " +
+ "triggerTypeInfo: $triggerTypeInfo, " +
+ "left context of the current line: ${
+ document.charsSequence.subSequence(
+ document.getLineStartOffset(document.getLineNumber(editor.caretModel.offset)),
+ editor.caretModel.offset
+ )
+ }"
+ }
+ }
+
+ try {
+ // Launch coroutine for background pagination progress
+ cs.launch {
+ var nextToken: Either? = null
+ do {
+ nextToken = startPaginationInBackground(
+ project,
+ editor,
+ triggerTypeInfo,
+ triggerSessionId,
+ nextToken,
+ sessionContext,
+ )
+ } while (nextToken != null && !nextToken.left.isNullOrEmpty())
+
+ // closing all channels since pagination for this session has finished
+ logInline(triggerSessionId) {
+ "Pagination finished, closing all channels"
+ }
+ sessionContext.itemContexts.forEach {
+ it.channel.close()
+ }
+ if (session.context.isDisposed) {
+ logInline(triggerSessionId) {
+ "Current display session already disposed by a new trigger before pagination finishes, exiting"
+ }
+ }
+ }
+
+ return object : InlineCompletionSuggestion {
+ override suspend fun getVariants(): List =
+ sessionContext.itemContexts.map { itemContext ->
+ itemContext.data.putUserData(KEY_Q_INLINE_ITEM_CONTEXT, itemContext)
+ InlineCompletionVariant.build(data = itemContext.data, elements = itemContext.channel.receiveAsFlow())
+ }
+ }
+ } catch (e: Exception) {
+ logInline(triggerSessionId, e) {
+ "Error getting inline completion suggestion: ${e.message}"
+ }
+ if (e is CancellationException) {
+ throw e
+ }
+ return InlineCompletionSuggestion.Empty
+ }
+ }
+
+ private suspend fun startPaginationInBackground(
+ project: Project,
+ editor: Editor,
+ triggerTypeInfo: TriggerTypeInfo,
+ triggerSessionId: Int,
+ nextToken: Either?,
+ sessionContext: InlineCompletionSessionContext,
+ ): Either? {
+ try {
+ logInline(triggerSessionId) {
+ "Fetching next paginated results with token: ${nextToken?.left}"
+ }
+
+ val nextPageResult = AmazonQLspService.executeAsyncIfRunning(project) { server ->
+ val params = createInlineCompletionParams(editor, triggerTypeInfo, nextToken)
+ server.inlineCompletionWithReferences(params)
+ }?.await() ?: run {
+ logInline(triggerSessionId) {
+ "Received null completion response from LSP, stop pagination for the current session"
+ }
+ return null
+ }
+
+ logInline(triggerSessionId) {
+ "Received ${nextPageResult.items.size} items from pagination with token: ${nextToken?.left}"
+ }
+
+ // Update channels in order with new items from pagination
+ if (nextPageResult.sessionId.isEmpty()) {
+ activeTriggerSessions.remove(triggerSessionId)
+ logInline(triggerSessionId) {
+ "Ending pagination progress since LSP returned EMPTY_RESULT"
+ }
+ return null
+ }
+
+ sessionContext.sessionId = nextPageResult.sessionId
+ nextPageResult.items.forEachIndexed { itemIndex, newItem ->
+ // Calculate which channel this item should go to, continue from where we left off
+ val channelIndex = sessionContext.counter % MAX_CHANNELS
+ if (channelIndex >= sessionContext.itemContexts.size) {
+ // service returned more than 5 suggestions, we don't have enough channel placeholders
+ return@forEachIndexed
+ }
+ sessionContext.itemContexts[channelIndex].item = newItem
+ val existingChannel = sessionContext.itemContexts[channelIndex].channel
+
+ // try displaying the suggestions in the current session, if it's still valid
+ var discarded = false
+ val displayText =
+ runReadAction {
+ if (editor.caretModel.offset < sessionContext.triggerOffset) {
+ discarded = true
+ ""
+ } else {
+ val userInput = editor.document.charsSequence.subSequence(sessionContext.triggerOffset, editor.caretModel.offset)
+ if (newItem.insertText.startsWith(userInput)) {
+ newItem.insertText.substring(userInput.length)
+ } else {
+ discarded = true
+ ""
+ }
+ }
+ }
+
+ if (newItem.insertText.isEmpty()) {
+ logInline(triggerSessionId) {
+ "Received variant ${channelIndex + 1} as an empty string"
+ }
+ }
+
+ sessionContext.itemContexts[channelIndex].isDiscarded = discarded
+ val success = existingChannel.trySend(InlineCompletionGrayTextElement(displayText))
+ logInline(triggerSessionId) {
+ "Adding paginated item '${newItem.itemId}' to channel $channelIndex, success: ${success.isSuccess}, discarded: $discarded"
+ }
+ sessionContext.counter++
+ }
+ return nextPageResult.partialResultToken
+ } catch (e: Exception) {
+ logInline(triggerSessionId, e) {
+ "Error during pagination"
+ }
+ return null
+ }
+ }
+
+ private fun createInlineCompletionParams(
+ editor: Editor,
+ triggerTypeInfo: TriggerTypeInfo,
+ nextToken: Either?,
+ ) = CodeWhispererService.getInstance().createInlineCompletionParams(
+ editor,
+ triggerTypeInfo,
+ nextToken
+ )
+
+ override fun isEnabled(event: InlineCompletionEvent): Boolean {
+ val request = event.toRequest() ?: return false
+ val editor = request.editor
+ val project = editor.project ?: return false
+
+ if (!isQConnected(project)) return false
+ if (!CodeWhispererExplorerActionManager.getInstance().isAutoEnabled() && event.isManualCall()) return false
+ if (QRegionProfileManager.getInstance().hasValidConnectionButNoActiveProfile(project)) return false
+ return true
+ }
+}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionUtils.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionUtils.kt
new file mode 100644
index 00000000000..59bd95663a5
--- /dev/null
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionUtils.kt
@@ -0,0 +1,35 @@
+// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codewhisperer.popup
+
+import com.intellij.codeInsight.inline.completion.session.InlineCompletionSession
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.actionSystem.ActionPlaces
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.Presentation
+import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.actionSystem.impl.ActionButton
+import com.intellij.openapi.project.DumbAware
+import com.intellij.util.ui.JBUI
+
+fun navigationButton(session: InlineCompletionSession, direction: String): ActionButton {
+ val icon = if (direction == "←") AllIcons.Chooser.Left else AllIcons.Chooser.Right
+ val navigate = if (direction == "←") session::usePrevVariant else session::useNextVariant
+ return object : ActionButton(
+ object : AnAction(direction, null, icon), DumbAware {
+ override fun actionPerformed(e: AnActionEvent) {
+ navigate()
+ }
+ },
+ Presentation().apply {
+ this.icon = icon
+ putClientProperty(ActionUtil.HIDE_DROPDOWN_ICON, true)
+ },
+ ActionPlaces.EDITOR_POPUP,
+ JBUI.emptySize()
+ ) {
+ override fun isFocusable() = false
+ }
+}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutoTriggerService.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutoTriggerService.kt
index 39644c1fd4f..3ba9003a51a 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutoTriggerService.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutoTriggerService.kt
@@ -11,12 +11,8 @@ import com.intellij.openapi.editor.Editor
import com.intellij.util.Alarm
import com.intellij.util.AlarmFactory
import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
import org.apache.commons.collections4.queue.CircularFifoQueue
-import software.aws.toolkits.jetbrains.core.coroutines.EDT
-import software.aws.toolkits.jetbrains.core.coroutines.applicationCoroutineScope
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
-import software.aws.toolkits.jetbrains.services.codewhisperer.model.LatencyContext
import software.aws.toolkits.telemetry.CodewhispererPreviousSuggestionState
import software.aws.toolkits.telemetry.CodewhispererTriggerType
import java.time.Duration
@@ -37,7 +33,7 @@ class CodeWhispererAutoTriggerService : CodeWhispererAutoTriggerHandler, Disposa
}
// real auto trigger logic
- fun invoke(editor: Editor, triggerType: CodeWhispererAutomatedTriggerType): Job? {
+ fun invoke(editor: Editor): Job? {
timeAtLastCharTyped = System.nanoTime()
if (!(
if (CodeWhispererFeatureConfigService.getInstance().getNewAutoTriggerUX()) {
@@ -53,15 +49,7 @@ class CodeWhispererAutoTriggerService : CodeWhispererAutoTriggerHandler, Disposa
lastInvocationTime = Instant.now()
lastInvocationLineNum = runReadAction { editor.caretModel.visualPosition.line }
- val latencyContext = LatencyContext().apply {
- codewhispererEndToEndStart = System.nanoTime()
- }
-
- val coroutineScope = applicationCoroutineScope()
-
- return coroutineScope.launch(EDT) {
- performAutomatedTriggerAction(editor, triggerType, latencyContext)
- }
+ return null
}
private fun scheduleReset() {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutomatedTriggerType.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutomatedTriggerType.kt
index fbb006ca402..b4b4e556b9e 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutomatedTriggerType.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererAutomatedTriggerType.kt
@@ -20,4 +20,12 @@ sealed class CodeWhispererAutomatedTriggerType(
class IdleTime : CodeWhispererAutomatedTriggerType(CodewhispererAutomatedTriggerType.IdleTime)
class Unknown : CodeWhispererAutomatedTriggerType(CodewhispererAutomatedTriggerType.Unknown)
+
+ override fun toString(): String {
+ val toString = when (this) {
+ is SpecialChar -> "SpecialChar($specialChar)"
+ else -> telemetryType.toString()
+ }
+ return toString
+ }
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererInvocationStatus.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererInvocationStatus.kt
index c58c4b4a466..69408ea4c5f 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererInvocationStatus.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererInvocationStatus.kt
@@ -3,6 +3,7 @@
package software.aws.toolkits.jetbrains.services.codewhisperer.service
+import com.intellij.codeInsight.inline.completion.session.InlineCompletionSession
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
@@ -15,7 +16,7 @@ import java.util.concurrent.atomic.AtomicBoolean
@Service
class CodeWhispererInvocationStatus {
- private val isInvokingCodeWhisperer: AtomicBoolean = AtomicBoolean(false)
+ private val isInvokingQInline: AtomicBoolean = AtomicBoolean(false)
private var invokingSessionId: String? = null
private var timeAtLastInvocationComplete: Instant? = null
var timeAtLastDocumentChanged: Instant = Instant.now()
@@ -24,9 +25,18 @@ class CodeWhispererInvocationStatus {
private var timeAtLastInvocationStart: Instant? = null
var completionShownTime: Instant? = null
private set
+ private var currentSession: InlineCompletionSession? = null
+
+ fun setIsInvokingQInline(session: InlineCompletionSession, value: Boolean) {
+ if (!value && currentSession != session) return
+ currentSession = session
+ isInvokingQInline.set(value)
+ // TODO: set true or false? prob doesn't matter
+ ApplicationManager.getApplication().messageBus.syncPublisher(CODEWHISPERER_INVOCATION_STATE_CHANGED).invocationStateChanged(true)
+ }
fun checkExistingInvocationAndSet(): Boolean =
- if (isInvokingCodeWhisperer.getAndSet(true)) {
+ if (isInvokingQInline.getAndSet(true)) {
LOG.debug { "Have existing CodeWhisperer invocation, sessionId: $invokingSessionId" }
true
} else {
@@ -35,10 +45,10 @@ class CodeWhispererInvocationStatus {
false
}
- fun hasExistingServiceInvocation(): Boolean = isInvokingCodeWhisperer.get()
+ fun hasExistingServiceInvocation(): Boolean = isInvokingQInline.get()
fun finishInvocation() {
- if (isInvokingCodeWhisperer.compareAndSet(true, false)) {
+ if (isInvokingQInline.compareAndSet(true, false)) {
ApplicationManager.getApplication().messageBus.syncPublisher(CODEWHISPERER_INVOCATION_STATE_CHANGED).invocationStateChanged(false)
LOG.debug { "Ending CodeWhisperer invocation" }
invokingSessionId = null
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt
index 9a62fcff440..44e19c9cf7f 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt
@@ -38,7 +38,7 @@ import software.aws.toolkits.jetbrains.core.coroutines.EDT
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.GetConfigurationFromServerParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LspServerConfigurations
@@ -446,7 +446,7 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
val caretPosition = runReadAction { getCaretPosition(editor) }
// 4. connection
- val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
// 5. customization
val customizationArn = CodeWhispererModelConfigurator.getInstance().activeCustomization(project)?.arn
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererServiceNew.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererServiceNew.kt
index 42c557b8b2a..81713e2ce47 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererServiceNew.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererServiceNew.kt
@@ -40,7 +40,7 @@ import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionContext
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionListWithReferences
@@ -532,7 +532,7 @@ class CodeWhispererServiceNew(private val cs: CoroutineScope) : Disposable {
val caretPosition = runReadAction { getCaretPosition(editor) }
// 4. connection
- val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
return RequestContextNew(project, editor, triggerTypeInfo, caretPosition, fileContext, connection)
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt
index dd10d1747b2..70ac9c104b2 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt
@@ -326,6 +326,6 @@ class CodeWhispererConfigurable(private val project: Project) :
}
companion object {
- private const val Q_INLINE_KEYBINDING_SEARCH_TEXT = "Amazon Q"
+ private const val Q_INLINE_KEYBINDING_SEARCH_TEXT = "Inline Proposal"
}
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererIntelliSenseAutoTriggerListener.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererIntelliSenseAutoTriggerListener.kt
index 4609e14cdcf..798187d703a 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererIntelliSenseAutoTriggerListener.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererIntelliSenseAutoTriggerListener.kt
@@ -11,8 +11,7 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.observable.util.addMouseHoverListener
import com.intellij.ui.hover.HoverListener
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutoTriggerService
-import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererAutomatedTriggerType
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererServiceNew
import java.awt.Component
@@ -29,7 +28,7 @@ object CodeWhispererIntelliSenseAutoTriggerListener : LookupManagerListener {
}
// Classifier
- CodeWhispererAutoTriggerService.getInstance().invoke(editor, CodeWhispererAutomatedTriggerType.IntelliSense())
+ QInlineCompletionProvider.invokeCompletion(editor, isIntelliSenseAccept = true)
cleanup()
}
override fun lookupCanceled(event: LookupEvent) {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererProjectStartupSettingsListener.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererProjectStartupSettingsListener.kt
index 80aa16950ac..2cd3197ebbc 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererProjectStartupSettingsListener.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererProjectStartupSettingsListener.kt
@@ -13,7 +13,7 @@ import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerListener
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProviderListener
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanManager
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator
@@ -58,7 +58,7 @@ class CodeWhispererProjectStartupSettingsListener(private val project: Project)
CodeWhispererCodeScanManager.getInstance(project).removeCodeScanUI()
}
- ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())?.let {
+ ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let {
// re-check the allowlist status
CodeWhispererModelConfigurator.getInstance().shouldDisplayCustomNode(project, forceUpdate = true)
}
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/telemetry/CodeWhispererTelemetryService.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/telemetry/CodeWhispererTelemetryService.kt
index f2bccb3beef..06ce031c52b 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/telemetry/CodeWhispererTelemetryService.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/telemetry/CodeWhispererTelemetryService.kt
@@ -16,8 +16,10 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LogInlineC
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanIssue
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.model.CodeScanTelemetryEvent
+import software.aws.toolkits.jetbrains.services.codewhisperer.model.InlineCompletionSessionContext
import software.aws.toolkits.jetbrains.services.codewhisperer.model.LatencyContext
import software.aws.toolkits.jetbrains.services.codewhisperer.model.RecommendationContext
+import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.getCodeWhispererStartUrl
@@ -68,6 +70,53 @@ class CodeWhispererTelemetryService(private val cs: CoroutineScope) {
}
}
+ suspend fun sendUserTriggerDecisionEventForTriggerSession(
+ project: Project,
+ latencyContext: LatencyContext,
+ sessionContext: InlineCompletionSessionContext,
+ triggerSessionId: Int,
+ ) {
+ if (sessionContext.sessionId.isEmpty()) {
+ QInlineCompletionProvider.logInline(triggerSessionId) {
+ "Did not receive a valid sessionId from language server, skipping telemetry"
+ }
+ return
+ }
+ QInlineCompletionProvider.logInline(triggerSessionId) {
+ "Sending UserTriggerDecision for ${sessionContext.sessionId}:"
+ }
+ sessionContext.itemContexts.forEachIndexed { i, itemContext ->
+ QInlineCompletionProvider.logInline(triggerSessionId) {
+ "Index: $i, item: ${itemContext.item?.itemId}, seen: ${itemContext.hasSeen}, " +
+ "accepted: ${itemContext.isAccepted}, discarded: ${itemContext.isDiscarded}"
+ }
+ }
+ QInlineCompletionProvider.logInline(triggerSessionId) {
+ "Perceived latency: ${latencyContext.perceivedLatency}, " +
+ "total session display time: ${CodeWhispererInvocationStatus.getInstance().completionShownTime?.let { Duration.between(it, Instant.now()) }
+ ?.toMillis()?.toDouble()}"
+ }
+ val params = LogInlineCompletionSessionResultsParams(
+ sessionId = sessionContext.sessionId,
+ completionSessionResult = sessionContext.itemContexts.filter { it.item != null }.associate {
+ it.item?.itemId.orEmpty() to InlineCompletionStates(
+ seen = it.hasSeen,
+ accepted = it.isAccepted,
+ discarded = it.isDiscarded
+ )
+ },
+ firstCompletionDisplayLatency = latencyContext.perceivedLatency,
+ totalSessionDisplayTime = CodeWhispererInvocationStatus.getInstance().completionShownTime?.let { Duration.between(it, Instant.now()) }
+ ?.toMillis()?.toDouble(),
+ // no userInput in JB inline completion API, every new char input will discard the previous trigger so
+ // user input is always 0
+ typeaheadLength = 0
+ )
+ AmazonQLspService.executeAsyncIfRunning(project) { server ->
+ server.logInlineCompletionSessionResults(params)
+ }
+ }
+
private fun mapToTelemetryScope(codeAnalysisScope: CodeWhispererConstants.CodeAnalysisScope, initiatedByChat: Boolean): CodewhispererCodeScanScope =
when (codeAnalysisScope) {
CodeWhispererConstants.CodeAnalysisScope.FILE -> {
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/toolwindow/CodeWhispererCodeReferenceManager.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/toolwindow/CodeWhispererCodeReferenceManager.kt
index 7981197416b..cd984ee7d61 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/toolwindow/CodeWhispererCodeReferenceManager.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/toolwindow/CodeWhispererCodeReferenceManager.kt
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.ui.awt.RelativePoint
+import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionItem
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionReference
import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil.getPopupPositionAboveText
import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil.getRelativePathToContentRoot
@@ -68,6 +69,10 @@ class CodeWhispererCodeReferenceManager(private val project: Project) {
fun insertCodeReference(originalCode: String, references: List?, editor: Editor, caretPosition: CaretPosition) {
val startOffset = caretPosition.offset
+ insertCodeReference(originalCode, references, editor, startOffset)
+ }
+
+ fun insertCodeReference(originalCode: String, references: List?, editor: Editor, startOffset: Int) {
val relativePath = getRelativePathToContentRoot(editor)
references?.forEachIndexed { i, reference ->
// TODO YUX: validate this
@@ -122,6 +127,10 @@ class CodeWhispererCodeReferenceManager(private val project: Project) {
)
}
+ fun insertCodeReference(editor: Editor, item: InlineCompletionItem?, offset: Int) {
+ insertCodeReference(item?.insertText.orEmpty(), item?.references, editor, offset)
+ }
+
fun getReferenceLineNums(editor: Editor, start: Int, end: Int): String {
val startLine = editor.document.getLineNumber(start)
val endLine = editor.document.getLineNumber(end)
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererUtil.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererUtil.kt
index 20682bfbe96..d6fe3ba7019 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererUtil.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererUtil.kt
@@ -30,7 +30,7 @@ import software.aws.toolkits.jetbrains.core.credentials.ReauthSource
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.maybeReauthProviderIfNeeded
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.reauthConnectionIfNeeded
import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
@@ -62,7 +62,7 @@ import java.nio.file.Paths
// 1. It will be sent for Builder ID users, only if they have optin telemetry sharing.
// 2. It will be sent for IdC users, regardless of telemetry optout status.
fun runIfIdcConnectionOrTelemetryEnabled(project: Project, callback: (connection: ToolkitConnection) -> Unit) =
- ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())?.let {
+ ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let {
runIfIdcConnectionOrTelemetryEnabled(it, callback)
}
@@ -279,14 +279,14 @@ object CodeWhispererUtil {
fun getCodeWhispererStartUrl(project: Project): String? {
val connection = ToolkitConnectionManager.getInstance(
project
- ).activeConnectionForFeature(CodeWhispererConnection.getInstance()) as? AwsBearerTokenConnection?
+ ).activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection?
return connection?.startUrl
}
private fun tokenConnection(project: Project) = (
ToolkitConnectionManager
.getInstance(project)
- .activeConnectionForFeature(CodeWhispererConnection.getInstance()) as? AwsBearerTokenConnection
+ .activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection
)
private fun tokenProvider(project: Project) =
@@ -296,7 +296,7 @@ object CodeWhispererUtil {
?.delegate as? BearerTokenProvider
fun reconnectCodeWhisperer(project: Project) {
- val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
if (connection !is ManagedBearerSsoConnection) return
pluginAwareExecuteOnPooledThread {
reauthConnectionIfNeeded(project, connection, isReAuth = true, reauthSource = ReauthSource.CODEWHISPERER)
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererAcceptTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererAcceptTest.kt
index eecab3fc0a6..14b5f330b03 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererAcceptTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererAcceptTest.kt
@@ -3,13 +3,12 @@
package software.aws.toolkits.jetbrains.services.codewhisperer
-import com.intellij.ide.DataManager
import com.intellij.openapi.actionSystem.ActionManager
-import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionItem
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.textDocument.InlineCompletionListWithReferences
@@ -17,13 +16,9 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestU
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.javaResponse
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.javaTestContext
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.testNextToken
-import software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererActionPromoter
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineAcceptActionId
-import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineForceAcceptActionId
-import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineNavigateNextActionId
-import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineNavigatePrevActionId
-import kotlin.test.fail
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererAcceptTest : CodeWhispererTestBase() {
@Before
@@ -110,33 +105,6 @@ class CodeWhispererAcceptTest : CodeWhispererTestBase() {
testAcceptRecommendationWithTypingAndMatchingBracketsOnTheRight("", "({test")
}
- @Test
- fun `test CodeWhisperer keyboard shortcuts should be prioritized to be executed`() {
- testCodeWhispererKeyboardShortcutShouldBePrioritized(qInlineAcceptActionId)
- testCodeWhispererKeyboardShortcutShouldBePrioritized(qInlineNavigateNextActionId)
- testCodeWhispererKeyboardShortcutShouldBePrioritized(qInlineNavigatePrevActionId)
- testCodeWhispererKeyboardShortcutShouldBePrioritized(qInlineForceAcceptActionId)
- }
-
- private fun testCodeWhispererKeyboardShortcutShouldBePrioritized(actionId: String) {
- projectRule.fixture.configureByText(javaFileName, javaTestContext)
- val wrongAction = object : AnAction() {
- override fun actionPerformed(e: AnActionEvent) {
- fail("the other action should not get executed first")
- }
- }
- withCodeWhispererServiceInvokedAndWait {
- val codeWhispererAction = ActionManager.getInstance().getAction(actionId)
- val actions = listOf(wrongAction, codeWhispererAction)
- val newActions = CodeWhispererActionPromoter().promote(
- actions.toMutableList(),
- DataManager.getInstance().getDataContext(projectRule.fixture.editor.contentComponent)
- )
- assertThat(newActions[0]).isEqualTo(codeWhispererAction)
- popupManagerSpy.popupComponents.acceptButton.doClick()
- }
- }
-
private fun testAcceptRecommendationWithTypingAndMatchingBracketsOnTheRight(
typing: String,
brackets: String,
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererExplorerActionManagerTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererExplorerActionManagerTest.kt
index e73f8191a40..8330cd75c1d 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererExplorerActionManagerTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererExplorerActionManagerTest.kt
@@ -22,8 +22,8 @@ import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.core.credentials.LegacyManagedBearerSsoConnection
import software.aws.toolkits.jetbrains.core.credentials.MockToolkitAuthManagerRule
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.ConnectionPinningManager
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sono.Q_SCOPES
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL
import software.aws.toolkits.jetbrains.core.credentials.sso.DeviceAuthorizationGrantToken
@@ -114,7 +114,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = true,
expectedIsCwExpired = false
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
assertConnectionState(
startUrl = SONO_URL,
@@ -125,7 +125,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = true,
expectedIsCwExpired = true
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
assertConnectionState(
startUrl = SONO_URL,
@@ -136,7 +136,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = false,
expectedIsCwExpired = false
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
assertConnectionState(
startUrl = aString(),
@@ -147,7 +147,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = true,
expectedIsCwExpired = false
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
assertConnectionState(
startUrl = aString(),
@@ -158,7 +158,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = true,
expectedIsCwExpired = true
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
assertConnectionState(
startUrl = aString(),
@@ -169,7 +169,7 @@ class CodeWhispererExplorerActionManagerTest {
expectedIsCwEnabled = false,
expectedIsCwExpired = false
)
- assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(CodeWhispererConnection.getInstance())).isFalse
+ assertThat(ConnectionPinningManager.getInstance().isFeaturePinned(QConnection.getInstance())).isFalse
}
@SuppressWarnings("UnusedParameter")
@@ -205,10 +205,10 @@ class CodeWhispererExplorerActionManagerTest {
)
ToolkitConnectionManager.getInstance(project).switchConnection(myConnection)
- val activeCwConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
+ val activateQConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
val myTokenProvider = myConnection.getConnectionSettings().tokenProvider.delegate as InteractiveBearerTokenProvider
- assertThat(activeCwConn).isEqualTo(myConnection)
+ assertThat(activateQConn).isEqualTo(myConnection)
assertThat(myTokenProvider.state()).isEqualTo(expectedState)
assertThat(CodeWhispererExplorerActionManager.getInstance().checkActiveCodeWhispererConnectionType(project)).isEqualTo(expectedLoginType)
assertThat(isCodeWhispererEnabled(project)).isEqualTo(expectedIsCwEnabled)
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt
index de3c11d6616..bb79a6608e1 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt
@@ -35,7 +35,7 @@ import software.aws.toolkits.jetbrains.core.credentials.LegacyManagedBearerSsoCo
import software.aws.toolkits.jetbrains.core.credentials.MockCredentialManagerRule
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerState
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sono.Q_SCOPES
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_REGION
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL
@@ -416,7 +416,7 @@ class CodeWhispererModelConfiguratorTest {
val builderIdConn = LegacyManagedBearerSsoConnection(region = SONO_REGION, startUrl = SONO_URL, scopes = Q_SCOPES)
connectionManager.switchConnection(builderIdConn)
- assertThat(connectionManager.activeConnectionForFeature(CodeWhispererConnection.getInstance()).isSono()).isTrue
+ assertThat(connectionManager.activeConnectionForFeature(QConnection.getInstance()).isSono()).isTrue
val actual = sut.listCustomizations(projectRule.project)
assertThat(actual).isNull()
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererNavigationTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererNavigationTest.kt
index a470ff97e6c..df99209aef3 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererNavigationTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererNavigationTest.kt
@@ -6,12 +6,14 @@ package software.aws.toolkits.jetbrains.services.codewhisperer
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnActionEvent
import org.assertj.core.api.Assertions.assertThat
+import org.junit.Ignore
import org.junit.Test
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonResponse
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineNavigateNextActionId
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.QInlineActionId.qInlineNavigatePrevActionId
import javax.swing.JButton
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererNavigationTest : CodeWhispererTestBase() {
@Test
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererStateTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererStateTest.kt
index 3588cc4f707..ded8e057e46 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererStateTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererStateTest.kt
@@ -5,6 +5,7 @@ package software.aws.toolkits.jetbrains.services.codewhisperer
import com.intellij.openapi.util.TextRange
import org.assertj.core.api.Assertions.assertThat
+import org.junit.Ignore
import org.junit.Test
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonFileName
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonResponse
@@ -12,6 +13,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispe
import software.aws.toolkits.telemetry.CodewhispererLanguage
import software.aws.toolkits.telemetry.CodewhispererTriggerType
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererStateTest : CodeWhispererTestBase() {
@Test
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererTypeaheadTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererTypeaheadTest.kt
index ae2cb710687..d2f3e7585cd 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererTypeaheadTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererTypeaheadTest.kt
@@ -5,10 +5,12 @@ package software.aws.toolkits.jetbrains.services.codewhisperer
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
+import org.junit.Ignore
import org.junit.Test
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonFileName
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonTestLeftContext
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererTypeaheadTest : CodeWhispererTestBase() {
@Test
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserActionsTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserActionsTest.kt
index abb05f74778..0f0f0a0913e 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserActionsTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserActionsTest.kt
@@ -18,6 +18,7 @@ import com.intellij.openapi.ui.popup.JBPopup
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.mockito.Mockito.times
import org.mockito.kotlin.any
@@ -33,6 +34,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.Co
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
import java.awt.Rectangle
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererUserActionsTest : CodeWhispererTestBase() {
@Before
diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserInputTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserInputTest.kt
index b2e086dc4ef..e0a62cf6761 100644
--- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserInputTest.kt
+++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererUserInputTest.kt
@@ -4,9 +4,11 @@
package software.aws.toolkits.jetbrains.services.codewhisperer
import org.assertj.core.api.Assertions.assertThat
+import org.junit.Ignore
import org.junit.Test
import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonResponse
+@Ignore("This test suite needs a rewrite for JB inline completion API")
class CodeWhispererUserInputTest : CodeWhispererTestBase() {
@Test
diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QUtils.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QUtils.kt
index 55b6c46d7ef..516047bf209 100644
--- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QUtils.kt
+++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QUtils.kt
@@ -12,12 +12,12 @@ import software.amazon.awssdk.services.codewhispererruntime.model.OperatingSyste
import software.amazon.awssdk.services.codewhispererruntime.model.UserContext
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
+import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
import software.aws.toolkits.jetbrains.services.telemetry.ClientMetadata
fun calculateIfIamIdentityCenterConnection(project: Project, calculationTask: (connection: ToolkitConnection) -> T): T? =
- ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())?.let {
+ ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let {
calculateIfIamIdentityCenterConnection(it, calculationTask)
}
@@ -29,7 +29,7 @@ fun calculateIfIamIdentityCenterConnection(connection: ToolkitConnection, ca
}
fun calculateIfBIDConnection(project: Project, calculationTask: (connection: ToolkitConnection) -> T): T? =
- ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())?.let {
+ ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let {
if (it.isSono()) {
calculationTask(it)
} else {
diff --git a/plugins/core/jetbrains-community/resources/META-INF/module-core.xml b/plugins/core/jetbrains-community/resources/META-INF/module-core.xml
index 72b1c4f84da..e03f58657d8 100644
--- a/plugins/core/jetbrains-community/resources/META-INF/module-core.xml
+++ b/plugins/core/jetbrains-community/resources/META-INF/module-core.xml
@@ -9,7 +9,6 @@
-
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/pinning/CodeWhispererConnection.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/pinning/CodeWhispererConnection.kt
deleted file mode 100644
index 9bb50dcb454..00000000000
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/credentials/pinning/CodeWhispererConnection.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-package software.aws.toolkits.jetbrains.core.credentials.pinning
-
-import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
-import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
-import software.aws.toolkits.jetbrains.core.credentials.sono.CODEWHISPERER_SCOPES
-
-@Deprecated("pending removal, merge into QConnection & QSCOPES")
-class CodeWhispererConnection : FeatureWithPinnedConnection {
- override val featureId = "aws.codewhisperer"
- override val featureName = "CodeWhisperer"
-
- override fun supportsConnectionType(connection: ToolkitConnection): Boolean {
- if (connection is AwsBearerTokenConnection) {
- return CODEWHISPERER_SCOPES.all { it in connection.scopes }
- }
-
- return false
- }
-
- companion object {
- fun getInstance() = FeatureWithPinnedConnection.EP_NAME.findExtensionOrFail(CodeWhispererConnection::class.java)
- }
-}
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/GettingStartedAuthUtils.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/GettingStartedAuthUtils.kt
index 52ba8eb02cb..cc62bf04203 100644
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/GettingStartedAuthUtils.kt
+++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/GettingStartedAuthUtils.kt
@@ -11,7 +11,6 @@ import software.aws.toolkits.jetbrains.core.credentials.ProfileSsoManagedBearerS
import software.aws.toolkits.jetbrains.core.credentials.ReauthSource
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.loginSso
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.reauthConnectionIfNeeded
import software.aws.toolkits.jetbrains.core.credentials.sono.Q_SCOPES
@@ -131,9 +130,9 @@ fun requestCredentialsForQ(
isReauth: Boolean,
): Boolean {
// try to scope upgrade if we have a codewhisperer connection
- val codeWhispererConnection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
- if (codeWhispererConnection is LegacyManagedBearerSsoConnection) {
- codeWhispererConnection.let {
+ val qConnection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
+ if (qConnection is LegacyManagedBearerSsoConnection) {
+ qConnection.let {
return tryOrNull {
loginSso(project, it.startUrl, it.region, Q_SCOPES)
} != null
@@ -141,7 +140,7 @@ fun requestCredentialsForQ(
}
val dialogState = SetupAuthenticationDialogState().apply {
- (codeWhispererConnection as? ProfileSsoManagedBearerSsoConnection)?.let { connection ->
+ (qConnection as? ProfileSsoManagedBearerSsoConnection)?.let { connection ->
idcTabState.apply {
profileName = connection.configSessionName
startUrl = connection.startUrl
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanelUtils.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanelUtils.kt
index 34d545f7971..e1905109032 100644
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanelUtils.kt
+++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanelUtils.kt
@@ -15,7 +15,6 @@ import software.aws.toolkits.jetbrains.core.credentials.ToolkitAuthManager
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.lazyIsUnauthedBearerConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeCatalystConnection
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.profiles.SsoSessionConstants
import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL
@@ -30,7 +29,6 @@ enum class ActiveConnectionType {
}
enum class BearerTokenFeatureSet {
- CODEWHISPERER,
CODECATALYST,
Q,
}
@@ -86,9 +84,6 @@ fun checkBearerConnectionValidity(project: Project, source: BearerTokenFeatureSe
if (connections.isEmpty()) return ActiveConnection.NotConnected
val activeConnection = when (source) {
- BearerTokenFeatureSet.CODEWHISPERER -> ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(
- CodeWhispererConnection.getInstance()
- )
BearerTokenFeatureSet.CODECATALYST -> ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(
CodeCatalystConnection.getInstance()
)
@@ -141,7 +136,6 @@ fun checkConnectionValidity(project: Project): ActiveConnection {
val tokenFeatureSets = listOf(
BearerTokenFeatureSet.CODECATALYST,
BearerTokenFeatureSet.Q,
- BearerTokenFeatureSet.CODEWHISPERER
)
var result = checkIamConnectionValidity(project)
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedTelemetryUtils.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedTelemetryUtils.kt
index 99ea1207ee9..03ae0e55e6d 100644
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedTelemetryUtils.kt
+++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedTelemetryUtils.kt
@@ -39,13 +39,6 @@ fun getEnabledConnectionsForTelemetry(project: Project?): Set {
AuthFormId.BUILDERID_CODECATALYST
)
- addConnectionInfoToSet(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER),
- enabledConnections,
- AuthFormId.IDENTITYCENTER_CODEWHISPERER,
- AuthFormId.BUILDERID_CODEWHISPERER
- )
-
addConnectionInfoToSet(
checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q),
enabledConnections,
@@ -137,8 +130,6 @@ enum class AuthFormId {
IDENTITYCENTER_EXPLORER,
BUILDERID_CODECATALYST,
IDENTITYCENTER_CODECATALYST,
- BUILDERID_CODEWHISPERER,
- IDENTITYCENTER_CODEWHISPERER,
BUILDERID_Q,
IDENTITYCENTER_Q,
UNKNOWN,
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/services/telemetry/OpenTelemetryAction.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/services/telemetry/OpenTelemetryAction.kt
index b0abe63c5ed..ef0eeae1d9d 100644
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/services/telemetry/OpenTelemetryAction.kt
+++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/services/telemetry/OpenTelemetryAction.kt
@@ -14,12 +14,18 @@ import com.intellij.openapi.project.DefaultProjectFactory
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.ui.FrameWrapper
import com.intellij.openapi.util.Disposer
+import com.intellij.ui.DocumentAdapter
import com.intellij.ui.JBColor
+import com.intellij.ui.components.JBLabel
+import com.intellij.ui.components.JBTextField
import com.intellij.util.ui.components.BorderLayoutPanel
import software.aws.toolkits.core.telemetry.MetricEvent
import software.aws.toolkits.jetbrains.isDeveloperMode
+import java.awt.BorderLayout
import javax.swing.BorderFactory
import javax.swing.JComponent
+import javax.swing.JPanel
+import javax.swing.event.DocumentEvent
class OpenTelemetryAction : DumbAwareAction() {
override fun actionPerformed(event: AnActionEvent) {
@@ -38,6 +44,8 @@ class OpenTelemetryAction : DumbAwareAction() {
setViewer(true)
}.console
}
+ private val telemetryEvents = mutableListOf()
+ private var currentFilter = ""
init {
title = "Telemetry Viewer"
@@ -48,11 +56,20 @@ class OpenTelemetryAction : DumbAwareAction() {
val panel = BorderLayoutPanel()
val consoleComponent = consoleView.component
+ // Add search/filter bar at the top
+ val filterPanel = JPanel(BorderLayout())
+ val filterField = JBTextField().apply {
+ emptyText.text = "Filter telemetry events..."
+ }
+ filterPanel.add(JBLabel("Filter: "), BorderLayout.WEST)
+ filterPanel.add(filterField, BorderLayout.CENTER)
+
val actionGroup = DefaultActionGroup(*consoleView.createConsoleActions())
val toolbar = ActionManager.getInstance().createActionToolbar("AWS.TelemetryViewer", actionGroup, false)
toolbar.setTargetComponent(consoleComponent)
+ panel.addToTop(filterPanel)
panel.addToLeft(toolbar.component)
panel.addToCenter(consoleComponent)
@@ -64,11 +81,32 @@ class OpenTelemetryAction : DumbAwareAction() {
Disposer.register(this) { telemetryService.removeListener(this) }
Disposer.register(this, consoleView)
+ // Implement filtering logic
+ filterField.document.addDocumentListener(object : DocumentAdapter() {
+ override fun textChanged(e: DocumentEvent) {
+ // Filter console content based on filterField.text
+ applyFilter(filterField.text)
+ }
+ })
+
return panel
}
+ private fun applyFilter(filterText: String) {
+ currentFilter = filterText
+ consoleView.clear()
+ telemetryEvents.filter {
+ it.toString().contains(filterText, ignoreCase = true)
+ }.forEach { event ->
+ consoleView.print(event.toString() + "\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ }
+
override fun onTelemetryEvent(event: MetricEvent) {
- consoleView.print(event.toString() + "\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ telemetryEvents.add(event)
+ if (event.toString().contains(currentFilter, ignoreCase = true)) {
+ consoleView.print(event.toString() + "\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
}
}
}
diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/FunctionUtils.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/FunctionUtils.kt
index 0ba09a91f9f..5eb148010b7 100644
--- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/FunctionUtils.kt
+++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/utils/FunctionUtils.kt
@@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory
import software.aws.toolkits.core.utils.debug
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
@@ -42,21 +41,19 @@ suspend fun pollFor(func: () -> T): T? {
fun isQConnected(project: Project): Boolean {
val manager = ToolkitConnectionManager.getInstance(project)
val qState = manager.connectionStateForFeature(QConnection.getInstance())
- val cwState = manager.connectionStateForFeature(CodeWhispererConnection.getInstance())
LOG.debug {
- "qConnectionState: $qState; cwConnectionState: $cwState"
+ "qConnectionState: $qState"
}
- return qState != BearerTokenAuthState.NOT_AUTHENTICATED && cwState != BearerTokenAuthState.NOT_AUTHENTICATED
+ return qState != BearerTokenAuthState.NOT_AUTHENTICATED
}
fun isQExpired(project: Project): Boolean {
val manager = ToolkitConnectionManager.getInstance(project)
val qState = manager.connectionStateForFeature(QConnection.getInstance())
- val cwState = manager.connectionStateForFeature(CodeWhispererConnection.getInstance())
LOG.debug {
- "qConnectionState: $qState; cwConnectionState: $cwState"
+ "qConnectionState: $qState"
}
- return qState == BearerTokenAuthState.NEEDS_REFRESH || cwState == BearerTokenAuthState.NEEDS_REFRESH
+ return qState == BearerTokenAuthState.NEEDS_REFRESH
}
fun AwsBearerTokenConnection.state(): BearerTokenAuthState =
diff --git a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanel.kt b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanel.kt
index 7d1c55e021f..414614db6b5 100644
--- a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanel.kt
+++ b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/gettingstarted/editor/GettingStartedPanel.kt
@@ -843,7 +843,7 @@ class GettingStartedPanel(
)
}
}
- }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER) is ActiveConnection.NotConnected)
+ }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q) is ActiveConnection.NotConnected)
panelConnectionInProgress = panel {
row {
@@ -879,16 +879,16 @@ class GettingStartedPanel(
row {
label(message("gettingstarted.auth.connected.builderid")).applyToComponent { this.icon = PanelConstants.CHECKMARK_ICON }
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.BUILDER_ID
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.BUILDER_ID
)
row {
label(message("gettingstarted.auth.connected.idc")).applyToComponent { this.icon = PanelConstants.CHECKMARK_ICON }
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.IAM_IDC
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.IAM_IDC
)
row {
link(message("toolkit.login.aws_builder_id.already_connected.reconnect")) {
- val validConnection = checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER)
+ val validConnection = checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q)
val connection = validConnection.activeConnectionBearer
if (connection is ProfileSsoManagedBearerSsoConnection) {
@@ -924,7 +924,7 @@ class GettingStartedPanel(
)
}
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.BUILDER_ID
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.BUILDER_ID
)
row {
text("${message("codewhisperer.gettingstarted.panel.login_button")}") {
@@ -942,9 +942,9 @@ class GettingStartedPanel(
)
}
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.IAM_IDC
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.IAM_IDC
)
- }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER) is ActiveConnection.ValidBearer)
+ }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q) is ActiveConnection.ValidBearer)
panelReauthenticationRequired = panel {
row {
@@ -971,16 +971,16 @@ class GettingStartedPanel(
row {
label(message("gettingstarted.auth.builderid.expired")).applyToComponent { this.icon = PanelConstants.X_ICON }
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.BUILDER_ID
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.BUILDER_ID
)
row {
label(message("gettingstarted.auth.idc.expired")).applyToComponent { this.icon = PanelConstants.X_ICON }
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.IAM_IDC
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.IAM_IDC
)
row {
link(message("toolkit.login.aws_builder_id.already_connected.reconnect")) {
- val validConnection = checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER)
+ val validConnection = checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q)
val connection = validConnection.activeConnectionBearer
if (connection is ProfileSsoManagedBearerSsoConnection) {
if (validConnection.connectionType == ActiveConnectionType.IAM_IDC) {
@@ -1009,7 +1009,7 @@ class GettingStartedPanel(
)
}
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.BUILDER_ID
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.BUILDER_ID
)
row {
text("${message("codewhisperer.gettingstarted.panel.login_button")}") {
@@ -1027,9 +1027,9 @@ class GettingStartedPanel(
)
}
}.visible(
- checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER).connectionType == ActiveConnectionType.IAM_IDC
+ checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q).connectionType == ActiveConnectionType.IAM_IDC
)
- }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER) is ActiveConnection.ExpiredBearer)
+ }.visible(checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q) is ActiveConnection.ExpiredBearer)
}
}.apply {
isOpaque = false
diff --git a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/startup/QMigrationActivity.kt b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/startup/QMigrationActivity.kt
index c0031a00e2f..d0b12a79236 100644
--- a/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/startup/QMigrationActivity.kt
+++ b/plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/core/startup/QMigrationActivity.kt
@@ -21,7 +21,6 @@ import software.aws.toolkits.core.utils.debug
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.jetbrains.AwsToolkit
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
-import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.services.amazonq.QConstants
import software.aws.toolkits.jetbrains.settings.AwsSettings
@@ -50,9 +49,8 @@ class QMigrationActivity : StartupActivity.DumbAware {
private fun displayQMigrationInfo(project: Project) {
if (AwsSettings.getInstance().isQMigrationNotificationShownOnce) return
- val hasUsedCodeWhisperer = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance()) != null
val hasUsedQ = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) != null
- if (hasUsedCodeWhisperer || hasUsedQ) {
+ if (hasUsedQ) {
// do auto-install
installQPlugin(project, autoInstall = true)
} else if (!PluginManager.isPluginInstalled(PluginId.getId(AwsToolkit.Q_PLUGIN_ID))) {