Skip to content

Commit 41019e6

Browse files
authored
feat(amazonq): add keyboard shortcut for stop/reject/run commands (#7703)
## Problem Currently, users need to manually click buttons or use the command palette to execute common shell commands (reject/run/stop) in the IDE. This creates friction in the developer workflow, especially for power users who prefer keyboard shortcuts. ## Solution Reopen [Na's PR](#7178) that added keyboard shortcuts for reject/run/stop shell commands Update to align with new requirements. Add VS Code feature flag (shortcut) Only available if Q is focused ## Screenshots https://github.com/user-attachments/assets/84df262e-2b92-456d-a8ae-bc2f1fd6318c --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent d0082e6 commit 41019e6

File tree

6 files changed

+66
-2
lines changed

6 files changed

+66
-2
lines changed

packages/amazonq/package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,21 @@
560560
]
561561
},
562562
"commands": [
563+
{
564+
"command": "aws.amazonq.stopCmdExecution",
565+
"title": "Stop Amazon Q Command Execution",
566+
"category": "%AWS.amazonq.title%"
567+
},
568+
{
569+
"command": "aws.amazonq.runCmdExecution",
570+
"title": "Run Amazon Q Command Execution",
571+
"category": "%AWS.amazonq.title%"
572+
},
573+
{
574+
"command": "aws.amazonq.rejectCmdExecution",
575+
"title": "Reject Amazon Q Command Execution",
576+
"category": "%AWS.amazonq.title%"
577+
},
563578
{
564579
"command": "_aws.amazonq.notifications.dismiss",
565580
"title": "%AWS.generic.dismiss%",
@@ -850,6 +865,24 @@
850865
}
851866
],
852867
"keybindings": [
868+
{
869+
"command": "aws.amazonq.stopCmdExecution",
870+
"key": "ctrl+shift+backspace",
871+
"mac": "cmd+shift+backspace",
872+
"when": "aws.amazonq.amazonqChatLSP.isFocus"
873+
},
874+
{
875+
"command": "aws.amazonq.runCmdExecution",
876+
"key": "ctrl+shift+enter",
877+
"mac": "cmd+shift+enter",
878+
"when": "aws.amazonq.amazonqChatLSP.isFocus"
879+
},
880+
{
881+
"command": "aws.amazonq.rejectCmdExecution",
882+
"key": "ctrl+shift+r",
883+
"mac": "cmd+shift+r",
884+
"when": "aws.amazonq.amazonqChatLSP.isFocus"
885+
},
853886
{
854887
"command": "_aws.amazonq.focusChat.keybinding",
855888
"win": "win+alt+i",

packages/amazonq/src/lsp/chat/commands.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ export function registerCommands(provider: AmazonQChatViewProvider) {
5959
params: {},
6060
})
6161
})
62-
})
62+
}),
63+
registerShellCommandShortCut('aws.amazonq.runCmdExecution', 'run-shell-command', provider),
64+
registerShellCommandShortCut('aws.amazonq.rejectCmdExecution', 'reject-shell-command', provider),
65+
registerShellCommandShortCut('aws.amazonq.stopCmdExecution', 'stop-shell-command', provider)
6366
)
6467
}
6568

@@ -156,3 +159,14 @@ export async function focusAmazonQPanel() {
156159
await Commands.tryExecute('aws.amazonq.AmazonQChatView.focus')
157160
await Commands.tryExecute('aws.amazonq.AmazonCommonAuth.focus')
158161
}
162+
163+
function registerShellCommandShortCut(commandName: string, buttonId: string, provider: AmazonQChatViewProvider) {
164+
return Commands.register(commandName, async () => {
165+
void focusAmazonQPanel().then(() => {
166+
void provider.webview?.postMessage({
167+
command: 'aws/chat/executeShellCommandShortCut',
168+
params: { id: buttonId },
169+
})
170+
})
171+
})
172+
}

packages/amazonq/src/lsp/chat/messages.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ import {
8888
openUrl,
8989
isTextEditor,
9090
globals,
91+
setContext,
9192
} from 'aws-core-vscode/shared'
9293
import {
9394
DefaultAmazonQAppInitContext,
@@ -490,6 +491,11 @@ export function registerMessageListeners(
490491
}
491492
default:
492493
if (isServerEvent(message.command)) {
494+
if (enterFocus(message.params)) {
495+
await setContext('aws.amazonq.amazonqChatLSP.isFocus', true)
496+
} else if (exitFocus(message.params)) {
497+
await setContext('aws.amazonq.amazonqChatLSP.isFocus', false)
498+
}
493499
languageClient.sendNotification(message.command, message.params)
494500
}
495501
break
@@ -699,6 +705,14 @@ function isServerEvent(command: string) {
699705
return command.startsWith('aws/chat/') || command === 'telemetry/event'
700706
}
701707

708+
function enterFocus(params: any) {
709+
return params.name === 'enterFocus'
710+
}
711+
712+
function exitFocus(params: any) {
713+
return params.name === 'exitFocus'
714+
}
715+
702716
/**
703717
* Decodes partial chat responses from the language server before sending them to mynah UI
704718
*/

packages/amazonq/src/lsp/chat/webviewProvider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Webview,
1414
} from 'vscode'
1515
import * as path from 'path'
16+
import * as os from 'os'
1617
import {
1718
globals,
1819
isSageMaker,
@@ -149,7 +150,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
149150
const vscodeApi = acquireVsCodeApi()
150151
const hybridChatConnector = new HybridChatAdapter(${(await AuthUtil.instance.getChatAuthState()).amazonQ === 'connected'},${featureConfigData},${welcomeCount},${disclaimerAcknowledged},${regionProfileString},${disabledCommands},${isSMUS},${isSM},vscodeApi.postMessage)
151152
const commands = [hybridChatConnector.initialQuickActions[0]]
152-
qChat = amazonQChat.createChat(vscodeApi, {disclaimerAcknowledged: ${disclaimerAcknowledged}, pairProgrammingAcknowledged: ${pairProgrammingAcknowledged}, agenticMode: true, quickActionCommands: commands, modelSelectionEnabled: ${modelSelectionEnabled}}, hybridChatConnector, ${JSON.stringify(featureConfigData)});
153+
qChat = amazonQChat.createChat(vscodeApi, {os: "${os.platform()}", disclaimerAcknowledged: ${disclaimerAcknowledged}, pairProgrammingAcknowledged: ${pairProgrammingAcknowledged}, agenticMode: true, quickActionCommands: commands, modelSelectionEnabled: ${modelSelectionEnabled}}, hybridChatConnector, ${JSON.stringify(featureConfigData)});
153154
}
154155
window.addEventListener('message', (event) => {
155156
/**

packages/amazonq/src/lsp/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ export async function startLanguageServer(
165165
pinnedContextEnabled: true,
166166
imageContextEnabled: true,
167167
mcp: true,
168+
shortcut: true,
168169
reroute: true,
169170
modelSelection: true,
170171
workspaceFilePath: vscode.workspace.workspaceFile?.fsPath,

packages/core/src/shared/vscode/setContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type contextKey =
4040
| 'gumby.wasQCodeTransformationUsed'
4141
| 'amazonq.inline.codelensShortcutEnabled'
4242
| 'aws.toolkit.lambda.walkthroughSelected'
43+
| 'aws.amazonq.amazonqChatLSP.isFocus'
4344

4445
const contextMap: Partial<Record<contextKey, any>> = {}
4546

0 commit comments

Comments
 (0)