Skip to content

Commit 83e1a52

Browse files
authored
feat(amazonq): inline completion JB API migration (#5851)
* feat: migrate CodeWhisperer to native JetBrains inline completion API Refactor CodeWhisperer inline completion implementation to use JetBrains' native inline completion provider instead of custom popup-based system. Key changes: - Replace custom action handlers with QInlineCompletionProvider - Remove deprecated popup navigation and acceptance actions - Consolidate authentication logic for Amazon Q connections - Migrate from CodeWhispererConnection to QConnection - Remove custom action promoter for inline completion - Streamline auto-trigger handling and invocation status This change improves IDE integration and provides a more native completion experience for users. * ignore bunch of tests that need a rewrite for now * add filter in telemetry viewer and detektMain * api compatiblity fix * fix codereferences to be inserted after the code is inserted * add feature user-facing message * use executeAsyncIfRunning
1 parent a6f98ce commit 83e1a52

File tree

53 files changed

+932
-445
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+932
-445
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Amazon Q inline: now display completions much more consistently at the user's current caret position"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"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."
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Amazon Q inline: now shows in a JetBrains native UX of popup and inlay text style"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"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."
4+
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/auth/AuthController.kt

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,24 @@ class AuthController {
2626
*/
2727
fun getAuthNeededStates(project: Project): AuthNeededStates {
2828
val connectionState = checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q)
29-
val codeWhispererState = checkBearerConnectionValidity(project, BearerTokenFeatureSet.CODEWHISPERER)
3029

3130
// CW chat is enabled for Builder and IDC users, same for Amazon Q
3231
return AuthNeededStates(
33-
chat = getAuthNeededState(connectionState, codeWhispererState),
34-
amazonQ = getAuthNeededState(connectionState, codeWhispererState)
32+
chat = getAuthNeededState(connectionState),
33+
amazonQ = getAuthNeededState(connectionState)
3534
)
3635
}
3736

3837
private fun getAuthNeededState(
3938
amazonqConnectionState: ActiveConnection,
40-
codeWhispererConnectionState: ActiveConnection,
4139
onlyIamIdcConnection: Boolean = false,
4240
): AuthNeededState? =
4341
when (amazonqConnectionState) {
4442
ActiveConnection.NotConnected -> {
45-
if (codeWhispererConnectionState == ActiveConnection.NotConnected) {
46-
AuthNeededState(
47-
message = message("q.connection.disconnected"),
48-
authType = AuthFollowUpType.FullAuth,
49-
)
50-
} else {
51-
// There is a connection for codewhisperer, but it's not valid for Q
52-
AuthNeededState(
53-
message = message("q.connection.need_scopes"),
54-
authType = AuthFollowUpType.MissingScopes,
55-
)
56-
}
43+
AuthNeededState(
44+
message = message("q.connection.disconnected"),
45+
authType = AuthFollowUpType.FullAuth,
46+
)
5747
}
5848

5949
is ActiveConnection.ValidBearer -> {

plugins/amazonq/codewhisperer/jetbrains-community/resources/META-INF/plugin-codewhisperer.xml

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@
5757
instance="software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable"
5858
/>
5959

60-
<typedHandler implementation="software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererTypedHandler"/>
61-
<editorActionHandler action="EditorEnter" implementationClass="software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEnterHandler"
62-
order="first, before editorEnter"/>
63-
<actionPromoter order="last" implementation="software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererActionPromoter"/>
6460
<fileEditorProvider implementation="software.aws.toolkits.jetbrains.services.codewhisperer.learn.LearnCodeWhispererEditorProvider"/>
61+
62+
<!-- Inline Completion Provider -->
63+
<inline.completion.provider id="amazon.q" implementation="software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider"/>
6564
</extensions>
6665

6766
<extensions defaultExtensionNs="aws.toolkit.core">
@@ -90,29 +89,6 @@
9089
text="Invoke Amazon Q Inline Suggestions">
9190
<keyboard-shortcut keymap="$default" first-keystroke="alt C"/>
9291
</action>
93-
<action id="codewhisperer.inline.navigate.previous"
94-
class="software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererNavigatePrevAction"
95-
text="Navigate to Previous Inline Suggestion" description="Navigate to previous inline suggestion">
96-
<keyboard-shortcut keymap="$default" first-keystroke="alt OPEN_BRACKET"/>
97-
</action>
98-
<action id="codewhisperer.inline.navigate.next"
99-
class="software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererNavigateNextAction"
100-
text="Navigate to Next Inline Suggestion" description="Navigate to next inline suggestion">
101-
<keyboard-shortcut keymap="$default" first-keystroke="alt CLOSE_BRACKET"/>
102-
</action>
103-
<action id="codewhisperer.inline.accept"
104-
class="software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererAcceptAction"
105-
text="Accept the Current Inline Suggestion" description="Accept the current inline suggestions">
106-
<keyboard-shortcut keymap="$default" first-keystroke="TAB"/>
107-
</action>
108-
<action id="codewhisperer.inline.force.accept"
109-
class="software.aws.toolkits.jetbrains.services.codewhisperer.actions.CodeWhispererForceAcceptAction"
110-
text="Force Accept the Current Amazon Q Suggestion" description="Force accept the current Amazon Q suggestion">
111-
<keyboard-shortcut keymap="Mac OS X" first-keystroke="alt TAB"/>
112-
<keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="alt TAB"/>
113-
<keyboard-shortcut keymap="$default" first-keystroke="alt ENTER"/>
114-
</action>
115-
11692

11793
<group id="aws.toolkit.codewhisperer.toolbar.security">
11894
<group id="codewhisperer.toolbar.security.group" icon="AllIcons.Actions.GroupBy" text="Group" popup="true">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.codewhisperer.popup
5+
import com.intellij.codeInsight.inline.completion.InlineCompletionEvent
6+
import com.intellij.openapi.actionSystem.DataContext
7+
import com.intellij.openapi.editor.Editor
8+
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE
9+
10+
fun InlineCompletionEvent.isManualCall(): Boolean =
11+
this is InlineCompletionEvent.DirectCall && this.context?.getData(DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE) == false
12+
13+
fun getManualCallEvent(editor: Editor, isIntelliSenseAccept: Boolean): InlineCompletionEvent {
14+
val dataContext = DataContext { dataId ->
15+
when (dataId) {
16+
DATA_KEY_Q_AUTO_TRIGGER_INTELLISENSE.name -> isIntelliSenseAccept
17+
else -> null
18+
}
19+
}
20+
return InlineCompletionEvent.DirectCall(editor, editor.caretModel.currentCaret, dataContext)
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.codewhisperer.popup
5+
import com.intellij.codeInsight.inline.completion.InlineCompletionEvent
6+
import com.intellij.openapi.editor.Editor
7+
import com.intellij.openapi.util.UserDataHolderBase
8+
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.KEY_Q_AUTO_TRIGGER_INTELLISENSE
9+
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.QInlineCompletionProvider.Companion.Q_INLINE_PROVIDER_ID
10+
11+
fun InlineCompletionEvent.isManualCall(): Boolean =
12+
this is InlineCompletionEvent.ManualCall && this.additionalData.getUserData(KEY_Q_AUTO_TRIGGER_INTELLISENSE) == false
13+
14+
fun getManualCallEvent(editor: Editor, isIntelliSenseAccept: Boolean): InlineCompletionEvent {
15+
val data = UserDataHolderBase().apply { this.putUserData(KEY_Q_AUTO_TRIGGER_INTELLISENSE, isIntelliSenseAccept) }
16+
return InlineCompletionEvent.ManualCall(editor, Q_INLINE_PROVIDER_ID, data)
17+
}

plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/explorer/CodeWhispererExplorerActionManager.kt

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ import com.intellij.openapi.components.State
88
import com.intellij.openapi.components.Storage
99
import com.intellij.openapi.components.service
1010
import com.intellij.openapi.project.Project
11-
import org.jetbrains.annotations.ApiStatus
12-
import software.aws.toolkits.core.utils.getLogger
13-
import software.aws.toolkits.core.utils.warn
1411
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
1512
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
16-
import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererConnection
13+
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
1714
import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
1815
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
1916
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
@@ -38,7 +35,7 @@ class CodeWhispererExplorerActionManager : PersistentStateComponent<CodeWhispere
3835
}
3936

4037
private fun getCodeWhispererConnectionStartUrl(project: Project): String {
41-
val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance())
38+
val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
4239
return getConnectionStartUrl(connection) ?: CodeWhispererConstants.ACCOUNTLESS_START_URL
4340
}
4441

@@ -95,22 +92,8 @@ class CodeWhispererExplorerActionManager : PersistentStateComponent<CodeWhispere
9592
actionState.value[CodeWhispererExploreStateType.IsFirstRestartAfterQInstall] = isFirstRestartAfterQInstall
9693
}
9794

98-
@Deprecated("Accountless credential will be removed soon")
99-
@ApiStatus.ScheduledForRemoval
100-
// Will keep it for existing accountless users
101-
/**
102-
* Will be called from CodeWhispererService.showRecommendationInPopup()
103-
* Caller (e.x. CodeWhispererService) should take care if null value returned, popup a notification/hint window or dialog etc.
104-
*/
105-
fun resolveAccessToken(): String? {
106-
if (actionState.token == null) {
107-
LOG.warn { "Logical Error: Try to get access token before token initialization" }
108-
}
109-
return actionState.token
110-
}
111-
11295
fun checkActiveCodeWhispererConnectionType(project: Project): CodeWhispererLoginType {
113-
val conn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(CodeWhispererConnection.getInstance()) as? AwsBearerTokenConnection
96+
val conn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection
11497
return conn?.let {
11598
val provider = (it.getConnectionSettings().tokenProvider.delegate as? BearerTokenProvider) ?: return@let CodeWhispererLoginType.Logout
11699

@@ -148,7 +131,5 @@ class CodeWhispererExplorerActionManager : PersistentStateComponent<CodeWhispere
148131
companion object {
149132
@JvmStatic
150133
fun getInstance(): CodeWhispererExplorerActionManager = service()
151-
152-
private val LOG = getLogger<CodeWhispererExplorerActionManager>()
153134
}
154135
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/actions/CodeWhispererAcceptAction.kt

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)