diff --git a/docs/reference/keyboard-shortcuts.md b/docs/reference/keyboard-shortcuts.md index 68b3d884fe..4ef61ac003 100644 --- a/docs/reference/keyboard-shortcuts.md +++ b/docs/reference/keyboard-shortcuts.md @@ -86,13 +86,14 @@ available combinations. #### Text Input -| Command | Action | Keys | -| -------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | -| `input.submit` | Submit the current prompt. | `Enter` | -| `input.queueMessage` | Queue the current prompt to be processed after the current task finishes. | `Tab` | -| `input.newline` | Insert a newline without submitting. | `Ctrl+Enter`
`Cmd/Win+Enter`
`Alt+Enter`
`Shift+Enter`
`Ctrl+J` | -| `input.openExternalEditor` | Open the current prompt or the plan in an external editor. | `Ctrl+X` | -| `input.paste` | Paste from the clipboard. | `Ctrl+V`
`Cmd/Win+V`
`Alt+V` | +| Command | Action | Keys | +| ------------------------------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| `input.submit` | Submit the current prompt. | `Enter` | +| `input.queueMessage` | Queue the current prompt to be processed after the current task finishes. | `Tab` | +| `input.newline` | Insert a newline without submitting. | `Ctrl+Enter`
`Cmd/Win+Enter`
`Alt+Enter`
`Shift+Enter`
`Ctrl+J` | +| `input.openExternalEditor` | Open the current prompt or the plan in an external editor. | `Ctrl+G` | +| `input.deprecatedOpenExternalEditor` | Deprecated command to open external editor. | `Ctrl+X` | +| `input.paste` | Paste from the clipboard. | `Ctrl+V`
`Cmd/Win+V`
`Alt+V` | #### App Controls @@ -100,7 +101,7 @@ available combinations. | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | | `app.showErrorDetails` | Toggle detailed error information. | `F12` | | `app.showFullTodos` | Toggle the full TODO list. | `Ctrl+T` | -| `app.showIdeContextDetail` | Show IDE context details. | `Ctrl+G` | +| `app.showIdeContextDetail` | Show IDE context details. | `F4` | | `app.toggleMarkdown` | Toggle Markdown rendering. | `Alt+M` | | `app.toggleCopyMode` | Toggle copy mode when in alternate buffer mode. | `F9` | | `app.toggleMouseMode` | Toggle mouse mode (scrolling and clicking). | `Ctrl+S` | diff --git a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx index 696793bc06..171e29e905 100644 --- a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx +++ b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx @@ -8,6 +8,8 @@ import type React from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { type IdeContext, type MCPServerConfig } from '@google/gemini-cli-core'; +import { Command } from '../key/keyMatchers.js'; +import { formatCommand } from '../key/keybindingUtils.js'; interface ContextSummaryDisplayProps { geminiMdFileCount: number; @@ -49,7 +51,7 @@ export const ContextSummaryDisplay: React.FC = ({ } return `${openFileCount} open file${ openFileCount > 1 ? 's' : '' - } (ctrl+g to view)`; + } (${formatCommand(Command.SHOW_IDE_CONTEXT_DETAIL)} to view)`; })(); const geminiMdText = (() => { diff --git a/packages/cli/src/ui/components/ExitPlanModeDialog.test.tsx b/packages/cli/src/ui/components/ExitPlanModeDialog.test.tsx index 18f2f02224..6925c749d7 100644 --- a/packages/cli/src/ui/components/ExitPlanModeDialog.test.tsx +++ b/packages/cli/src/ui/components/ExitPlanModeDialog.test.tsx @@ -587,7 +587,7 @@ Implement a comprehensive authentication system with multiple providers. expect(onFeedback).not.toHaveBeenCalled(); }); - it('automatically submits feedback when Ctrl+X is used to edit the plan', async () => { + it('automatically submits feedback when Ctrl+G is used to edit the plan', async () => { const { stdin, lastFrame } = await act(async () => renderDialog({ useAlternateBuffer }), ); @@ -600,9 +600,9 @@ Implement a comprehensive authentication system with multiple providers. expect(lastFrame()).toContain('Add user authentication'); }); - // Press Ctrl+X + // Press Ctrl+G await act(async () => { - writeKey(stdin, '\x18'); // Ctrl+X + writeKey(stdin, '\x07'); // Ctrl+G }); await waitFor(() => { diff --git a/packages/cli/src/ui/components/ExitPlanModeDialog.tsx b/packages/cli/src/ui/components/ExitPlanModeDialog.tsx index b2c28abaeb..11adf8e82b 100644 --- a/packages/cli/src/ui/components/ExitPlanModeDialog.tsx +++ b/packages/cli/src/ui/components/ExitPlanModeDialog.tsx @@ -25,6 +25,11 @@ import { useKeypress } from '../hooks/useKeypress.js'; import { Command } from '../key/keyMatchers.js'; import { formatCommand } from '../key/keybindingUtils.js'; import { useKeyMatchers } from '../hooks/useKeyMatchers.js'; +import { + appEvents, + AppEvent, + TransientMessageType, +} from '../../utils/events.js'; export interface ExitPlanModeDialogProps { planPath: string; @@ -173,6 +178,14 @@ export const ExitPlanModeDialog: React.FC = ({ void handleOpenEditor(); return true; } + if (keyMatchers[Command.DEPRECATED_OPEN_EXTERNAL_EDITOR](key)) { + const cmdKey = formatCommand(Command.OPEN_EXTERNAL_EDITOR); + appEvents.emit(AppEvent.TransientMessage, { + message: `Use ${cmdKey} to open the external editor.`, + type: TransientMessageType.Hint, + }); + return true; + } return false; }, { isActive: true, priority: true }, diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index 3fdaa479cc..7a241691e8 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -5065,8 +5065,8 @@ describe('InputPrompt', () => { input: '\x12', }, { - name: 'Ctrl+X hotkey is pressed', - input: '\x18', + name: 'Ctrl+G hotkey is pressed', + input: '\x07', }, { name: 'F12 hotkey is pressed', diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 7e59ab4d14..b36de8ebb0 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -1272,6 +1272,15 @@ export const InputPrompt: React.FC = ({ return true; } + if (keyMatchers[Command.DEPRECATED_OPEN_EXTERNAL_EDITOR](key)) { + const cmdKey = formatCommand(Command.OPEN_EXTERNAL_EDITOR); + appEvents.emit(AppEvent.TransientMessage, { + message: `Use ${cmdKey} to open the external editor.`, + type: TransientMessageType.Hint, + }); + return true; + } + // Ctrl+V for clipboard paste if (keyMatchers[Command.PASTE_CLIPBOARD](key)) { // eslint-disable-next-line @typescript-eslint/no-floating-promises diff --git a/packages/cli/src/ui/components/__snapshots__/ContextSummaryDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/ContextSummaryDisplay.test.tsx.snap index 876524bdb8..7330b89e4d 100644 --- a/packages/cli/src/ui/components/__snapshots__/ContextSummaryDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/ContextSummaryDisplay.test.tsx.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[` > should not render empty parts 1`] = ` -" 1 open file (ctrl+g to view) +" 1 open file (F4 to view) " `; exports[` > should render on a single line on a wide screen 1`] = ` -" 1 open file (ctrl+g to view) · 1 GEMINI.md file · 1 MCP server · 1 skill +" 1 open file (F4 to view) · 1 GEMINI.md file · 1 MCP server · 1 skill " `; exports[` > should render on multiple lines on a narrow screen 1`] = ` -" 1 open file (ctrl+g to view) · 1 GEMINI.md file · 1 MCP server · 1 skill +" 1 open file (F4 to view) · 1 GEMINI.md file · 1 MCP server · 1 skill " `; diff --git a/packages/cli/src/ui/components/__snapshots__/ExitPlanModeDialog.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/ExitPlanModeDialog.test.tsx.snap index 073c106ceb..71acb9388c 100644 --- a/packages/cli/src/ui/components/__snapshots__/ExitPlanModeDialog.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/ExitPlanModeDialog.test.tsx.snap @@ -23,7 +23,7 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -50,7 +50,7 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -82,7 +82,7 @@ Implementation Steps Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -109,7 +109,7 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -136,7 +136,7 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -163,7 +163,7 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -216,7 +216,7 @@ Testing Strategy Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; @@ -243,6 +243,6 @@ Files to Modify Approves plan but requires confirmation for each tool 3. Type your feedback... -Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel +Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel " `; diff --git a/packages/cli/src/ui/components/__snapshots__/ShortcutsHelp.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/ShortcutsHelp.test.tsx.snap index 9e65c72f69..f51dca0860 100644 --- a/packages/cli/src/ui/components/__snapshots__/ShortcutsHelp.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/ShortcutsHelp.test.tsx.snap @@ -12,7 +12,7 @@ exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'linux' 1`] = ` Ctrl+V paste images Alt+M raw markdown mode Ctrl+R reverse-search history - Ctrl+X open external editor + Ctrl+G open external editor " `; @@ -28,7 +28,7 @@ exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'mac' 1`] = ` Ctrl+V paste images Option+M raw markdown mode Ctrl+R reverse-search history - Ctrl+X open external editor + Ctrl+G open external editor " `; @@ -37,7 +37,7 @@ exports[`ShortcutsHelp > renders correctly in 'wide' mode on 'linux' 1`] = ` Shortcuts See /help for more ! shell mode Shift+Tab cycle mode Ctrl+V paste images @ select file or folder Ctrl+Y YOLO mode Alt+M raw markdown mode - Double Esc clear & rewind Ctrl+R reverse-search history Ctrl+X open external editor + Double Esc clear & rewind Ctrl+R reverse-search history Ctrl+G open external editor Tab focus UI " `; @@ -47,7 +47,7 @@ exports[`ShortcutsHelp > renders correctly in 'wide' mode on 'mac' 1`] = ` Shortcuts See /help for more ! shell mode Shift+Tab cycle mode Ctrl+V paste images @ select file or folder Ctrl+Y YOLO mode Option+M raw markdown mode - Double Esc clear & rewind Ctrl+R reverse-search history Ctrl+X open external editor + Double Esc clear & rewind Ctrl+R reverse-search history Ctrl+G open external editor Tab focus UI " `; diff --git a/packages/cli/src/ui/components/__snapshots__/ToolConfirmationQueue.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/ToolConfirmationQueue.test.tsx.snap index 8d8667b51d..9214e58713 100644 --- a/packages/cli/src/ui/components/__snapshots__/ToolConfirmationQueue.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/ToolConfirmationQueue.test.tsx.snap @@ -191,7 +191,7 @@ exports[`ToolConfirmationQueue > renders ExitPlanMode tool confirmation with Suc │ Approves plan but requires confirmation for each tool │ │ 3. Type your feedback... │ │ │ -│ Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel │ +│ Enter to select · ↑/↓ to navigate · Ctrl+G to edit plan · Esc to cancel │ ╰──────────────────────────────────────────────────────────────────────────────╯ " `; diff --git a/packages/cli/src/ui/constants/tips.ts b/packages/cli/src/ui/constants/tips.ts index 922465347a..78bc16f039 100644 --- a/packages/cli/src/ui/constants/tips.ts +++ b/packages/cli/src/ui/constants/tips.ts @@ -111,10 +111,10 @@ export const INFORMATIVE_TIPS = [ 'Paste from your clipboard with Ctrl+V', 'Undo text edits in the input with Alt+Z or Cmd+Z', 'Redo undone text edits with Shift+Alt+Z or Shift+Cmd+Z', - 'Open the current prompt in an external editor with Ctrl+X', + 'Open the current prompt in an external editor with Ctrl+G', 'In menus, move up/down with k/j or the arrow keys', 'In menus, select an item by typing its number', - "If you're using an IDE, see the context with Ctrl+G", + "If you're using an IDE, see the context with F4", 'Toggle background shells with Ctrl+B or /shells', 'Toggle the background shell process list with Ctrl+L', // Keyboard shortcut tips end here diff --git a/packages/cli/src/ui/key/keyBindings.ts b/packages/cli/src/ui/key/keyBindings.ts index c23596dc0f..0079d743d5 100644 --- a/packages/cli/src/ui/key/keyBindings.ts +++ b/packages/cli/src/ui/key/keyBindings.ts @@ -77,6 +77,7 @@ export enum Command { QUEUE_MESSAGE = 'input.queueMessage', NEWLINE = 'input.newline', OPEN_EXTERNAL_EDITOR = 'input.openExternalEditor', + DEPRECATED_OPEN_EXTERNAL_EDITOR = 'input.deprecatedOpenExternalEditor', PASTE_CLIPBOARD = 'input.paste', // App Controls @@ -375,7 +376,8 @@ export const defaultKeyBindingConfig: KeyBindingConfig = new Map([ new KeyBinding('ctrl+j'), ], ], - [Command.OPEN_EXTERNAL_EDITOR, [new KeyBinding('ctrl+x')]], + [Command.OPEN_EXTERNAL_EDITOR, [new KeyBinding('ctrl+g')]], + [Command.DEPRECATED_OPEN_EXTERNAL_EDITOR, [new KeyBinding('ctrl+x')]], [ Command.PASTE_CLIPBOARD, [ @@ -388,7 +390,7 @@ export const defaultKeyBindingConfig: KeyBindingConfig = new Map([ // App Controls [Command.SHOW_ERROR_DETAILS, [new KeyBinding('f12')]], [Command.SHOW_FULL_TODOS, [new KeyBinding('ctrl+t')]], - [Command.SHOW_IDE_CONTEXT_DETAIL, [new KeyBinding('ctrl+g')]], + [Command.SHOW_IDE_CONTEXT_DETAIL, [new KeyBinding('f4')]], [Command.TOGGLE_MARKDOWN, [new KeyBinding('alt+m')]], [Command.TOGGLE_COPY_MODE, [new KeyBinding('f9')]], [Command.TOGGLE_MOUSE_MODE, [new KeyBinding('ctrl+s')]], @@ -510,6 +512,7 @@ export const commandCategories: readonly CommandCategory[] = [ Command.QUEUE_MESSAGE, Command.NEWLINE, Command.OPEN_EXTERNAL_EDITOR, + Command.DEPRECATED_OPEN_EXTERNAL_EDITOR, Command.PASTE_CLIPBOARD, ], }, @@ -626,6 +629,8 @@ export const commandDescriptions: Readonly> = { [Command.NEWLINE]: 'Insert a newline without submitting.', [Command.OPEN_EXTERNAL_EDITOR]: 'Open the current prompt or the plan in an external editor.', + [Command.DEPRECATED_OPEN_EXTERNAL_EDITOR]: + 'Deprecated command to open external editor.', [Command.PASTE_CLIPBOARD]: 'Paste from the clipboard.', // App Controls diff --git a/packages/cli/src/ui/key/keyMatchers.test.ts b/packages/cli/src/ui/key/keyMatchers.test.ts index 2a3709350f..0fc2f00ac7 100644 --- a/packages/cli/src/ui/key/keyMatchers.test.ts +++ b/packages/cli/src/ui/key/keyMatchers.test.ts @@ -311,6 +311,11 @@ describe('keyMatchers', () => { // External tools { command: Command.OPEN_EXTERNAL_EDITOR, + positive: [createKey('g', { ctrl: true })], + negative: [createKey('g'), createKey('c', { ctrl: true })], + }, + { + command: Command.DEPRECATED_OPEN_EXTERNAL_EDITOR, positive: [createKey('x', { ctrl: true })], negative: [createKey('x'), createKey('c', { ctrl: true })], }, @@ -336,8 +341,8 @@ describe('keyMatchers', () => { }, { command: Command.SHOW_IDE_CONTEXT_DETAIL, - positive: [createKey('g', { ctrl: true })], - negative: [createKey('g'), createKey('t', { ctrl: true })], + positive: [createKey('f4')], + negative: [createKey('f5'), createKey('t', { ctrl: true })], }, { command: Command.TOGGLE_MARKDOWN,