feat(cli): switch to ctrl+g from ctrl-x (#24861)

This commit is contained in:
Jacob Richman
2026-04-07 23:22:45 -07:00
committed by GitHub
parent 7e1938c1bc
commit cbacdc67d0
13 changed files with 71 additions and 36 deletions
+9 -8
View File
@@ -86,13 +86,14 @@ available combinations.
#### Text Input #### Text Input
| Command | Action | Keys | | Command | Action | Keys |
| -------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | ------------------------------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `input.submit` | Submit the current prompt. | `Enter` | | `input.submit` | Submit the current prompt. | `Enter` |
| `input.queueMessage` | Queue the current prompt to be processed after the current task finishes. | `Tab` | | `input.queueMessage` | Queue the current prompt to be processed after the current task finishes. | `Tab` |
| `input.newline` | Insert a newline without submitting. | `Ctrl+Enter`<br />`Cmd/Win+Enter`<br />`Alt+Enter`<br />`Shift+Enter`<br />`Ctrl+J` | | `input.newline` | Insert a newline without submitting. | `Ctrl+Enter`<br />`Cmd/Win+Enter`<br />`Alt+Enter`<br />`Shift+Enter`<br />`Ctrl+J` |
| `input.openExternalEditor` | Open the current prompt or the plan in an external editor. | `Ctrl+X` | | `input.openExternalEditor` | Open the current prompt or the plan in an external editor. | `Ctrl+G` |
| `input.paste` | Paste from the clipboard. | `Ctrl+V`<br />`Cmd/Win+V`<br />`Alt+V` | | `input.deprecatedOpenExternalEditor` | Deprecated command to open external editor. | `Ctrl+X` |
| `input.paste` | Paste from the clipboard. | `Ctrl+V`<br />`Cmd/Win+V`<br />`Alt+V` |
#### App Controls #### App Controls
@@ -100,7 +101,7 @@ available combinations.
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `app.showErrorDetails` | Toggle detailed error information. | `F12` | | `app.showErrorDetails` | Toggle detailed error information. | `F12` |
| `app.showFullTodos` | Toggle the full TODO list. | `Ctrl+T` | | `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.toggleMarkdown` | Toggle Markdown rendering. | `Alt+M` |
| `app.toggleCopyMode` | Toggle copy mode when in alternate buffer mode. | `F9` | | `app.toggleCopyMode` | Toggle copy mode when in alternate buffer mode. | `F9` |
| `app.toggleMouseMode` | Toggle mouse mode (scrolling and clicking). | `Ctrl+S` | | `app.toggleMouseMode` | Toggle mouse mode (scrolling and clicking). | `Ctrl+S` |
@@ -8,6 +8,8 @@ import type React from 'react';
import { Box, Text } from 'ink'; import { Box, Text } from 'ink';
import { theme } from '../semantic-colors.js'; import { theme } from '../semantic-colors.js';
import { type IdeContext, type MCPServerConfig } from '@google/gemini-cli-core'; import { type IdeContext, type MCPServerConfig } from '@google/gemini-cli-core';
import { Command } from '../key/keyMatchers.js';
import { formatCommand } from '../key/keybindingUtils.js';
interface ContextSummaryDisplayProps { interface ContextSummaryDisplayProps {
geminiMdFileCount: number; geminiMdFileCount: number;
@@ -49,7 +51,7 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
} }
return `${openFileCount} open file${ return `${openFileCount} open file${
openFileCount > 1 ? 's' : '' openFileCount > 1 ? 's' : ''
} (ctrl+g to view)`; } (${formatCommand(Command.SHOW_IDE_CONTEXT_DETAIL)} to view)`;
})(); })();
const geminiMdText = (() => { const geminiMdText = (() => {
@@ -587,7 +587,7 @@ Implement a comprehensive authentication system with multiple providers.
expect(onFeedback).not.toHaveBeenCalled(); 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 () => const { stdin, lastFrame } = await act(async () =>
renderDialog({ useAlternateBuffer }), renderDialog({ useAlternateBuffer }),
); );
@@ -600,9 +600,9 @@ Implement a comprehensive authentication system with multiple providers.
expect(lastFrame()).toContain('Add user authentication'); expect(lastFrame()).toContain('Add user authentication');
}); });
// Press Ctrl+X // Press Ctrl+G
await act(async () => { await act(async () => {
writeKey(stdin, '\x18'); // Ctrl+X writeKey(stdin, '\x07'); // Ctrl+G
}); });
await waitFor(() => { await waitFor(() => {
@@ -25,6 +25,11 @@ import { useKeypress } from '../hooks/useKeypress.js';
import { Command } from '../key/keyMatchers.js'; import { Command } from '../key/keyMatchers.js';
import { formatCommand } from '../key/keybindingUtils.js'; import { formatCommand } from '../key/keybindingUtils.js';
import { useKeyMatchers } from '../hooks/useKeyMatchers.js'; import { useKeyMatchers } from '../hooks/useKeyMatchers.js';
import {
appEvents,
AppEvent,
TransientMessageType,
} from '../../utils/events.js';
export interface ExitPlanModeDialogProps { export interface ExitPlanModeDialogProps {
planPath: string; planPath: string;
@@ -173,6 +178,14 @@ export const ExitPlanModeDialog: React.FC<ExitPlanModeDialogProps> = ({
void handleOpenEditor(); void handleOpenEditor();
return true; 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; return false;
}, },
{ isActive: true, priority: true }, { isActive: true, priority: true },
@@ -5065,8 +5065,8 @@ describe('InputPrompt', () => {
input: '\x12', input: '\x12',
}, },
{ {
name: 'Ctrl+X hotkey is pressed', name: 'Ctrl+G hotkey is pressed',
input: '\x18', input: '\x07',
}, },
{ {
name: 'F12 hotkey is pressed', name: 'F12 hotkey is pressed',
@@ -1272,6 +1272,15 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
return true; 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 // Ctrl+V for clipboard paste
if (keyMatchers[Command.PASTE_CLIPBOARD](key)) { if (keyMatchers[Command.PASTE_CLIPBOARD](key)) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -1,16 +1,16 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<ContextSummaryDisplay /> > should not render empty parts 1`] = ` exports[`<ContextSummaryDisplay /> > should not render empty parts 1`] = `
" 1 open file (ctrl+g to view) " 1 open file (F4 to view)
" "
`; `;
exports[`<ContextSummaryDisplay /> > should render on a single line on a wide screen 1`] = ` exports[`<ContextSummaryDisplay /> > 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[`<ContextSummaryDisplay /> > should render on multiple lines on a narrow screen 1`] = ` exports[`<ContextSummaryDisplay /> > 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
" "
`; `;
@@ -23,7 +23,7 @@ Files to Modify
Approves plan but requires confirmation for each tool Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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 Approves plan but requires confirmation for each tool
3. Type your feedback... 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
" "
`; `;
@@ -12,7 +12,7 @@ exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'linux' 1`] = `
Ctrl+V paste images Ctrl+V paste images
Alt+M raw markdown mode Alt+M raw markdown mode
Ctrl+R reverse-search history 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 Ctrl+V paste images
Option+M raw markdown mode Option+M raw markdown mode
Ctrl+R reverse-search history 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 Shortcuts See /help for more
! shell mode Shift+Tab cycle mode Ctrl+V paste images ! shell mode Shift+Tab cycle mode Ctrl+V paste images
@ select file or folder Ctrl+Y YOLO mode Alt+M raw markdown mode @ 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 Tab focus UI
" "
`; `;
@@ -47,7 +47,7 @@ exports[`ShortcutsHelp > renders correctly in 'wide' mode on 'mac' 1`] = `
Shortcuts See /help for more Shortcuts See /help for more
! shell mode Shift+Tab cycle mode Ctrl+V paste images ! shell mode Shift+Tab cycle mode Ctrl+V paste images
@ select file or folder Ctrl+Y YOLO mode Option+M raw markdown mode @ 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 Tab focus UI
" "
`; `;
@@ -191,7 +191,7 @@ exports[`ToolConfirmationQueue > renders ExitPlanMode tool confirmation with Suc
│ Approves plan but requires confirmation for each tool │ │ Approves plan but requires confirmation for each tool │
│ 3. Type your feedback... │ │ 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 │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
" "
`; `;
+2 -2
View File
@@ -111,10 +111,10 @@ export const INFORMATIVE_TIPS = [
'Paste from your clipboard with Ctrl+V', 'Paste from your clipboard with Ctrl+V',
'Undo text edits in the input with Alt+Z or Cmd+Z', 'Undo text edits in the input with Alt+Z or Cmd+Z',
'Redo undone text edits with Shift+Alt+Z or Shift+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, move up/down with k/j or the arrow keys',
'In menus, select an item by typing its number', '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 background shells with Ctrl+B or /shells',
'Toggle the background shell process list with Ctrl+L', 'Toggle the background shell process list with Ctrl+L',
// Keyboard shortcut tips end here // Keyboard shortcut tips end here
+7 -2
View File
@@ -77,6 +77,7 @@ export enum Command {
QUEUE_MESSAGE = 'input.queueMessage', QUEUE_MESSAGE = 'input.queueMessage',
NEWLINE = 'input.newline', NEWLINE = 'input.newline',
OPEN_EXTERNAL_EDITOR = 'input.openExternalEditor', OPEN_EXTERNAL_EDITOR = 'input.openExternalEditor',
DEPRECATED_OPEN_EXTERNAL_EDITOR = 'input.deprecatedOpenExternalEditor',
PASTE_CLIPBOARD = 'input.paste', PASTE_CLIPBOARD = 'input.paste',
// App Controls // App Controls
@@ -375,7 +376,8 @@ export const defaultKeyBindingConfig: KeyBindingConfig = new Map([
new KeyBinding('ctrl+j'), 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, Command.PASTE_CLIPBOARD,
[ [
@@ -388,7 +390,7 @@ export const defaultKeyBindingConfig: KeyBindingConfig = new Map([
// App Controls // App Controls
[Command.SHOW_ERROR_DETAILS, [new KeyBinding('f12')]], [Command.SHOW_ERROR_DETAILS, [new KeyBinding('f12')]],
[Command.SHOW_FULL_TODOS, [new KeyBinding('ctrl+t')]], [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_MARKDOWN, [new KeyBinding('alt+m')]],
[Command.TOGGLE_COPY_MODE, [new KeyBinding('f9')]], [Command.TOGGLE_COPY_MODE, [new KeyBinding('f9')]],
[Command.TOGGLE_MOUSE_MODE, [new KeyBinding('ctrl+s')]], [Command.TOGGLE_MOUSE_MODE, [new KeyBinding('ctrl+s')]],
@@ -510,6 +512,7 @@ export const commandCategories: readonly CommandCategory[] = [
Command.QUEUE_MESSAGE, Command.QUEUE_MESSAGE,
Command.NEWLINE, Command.NEWLINE,
Command.OPEN_EXTERNAL_EDITOR, Command.OPEN_EXTERNAL_EDITOR,
Command.DEPRECATED_OPEN_EXTERNAL_EDITOR,
Command.PASTE_CLIPBOARD, Command.PASTE_CLIPBOARD,
], ],
}, },
@@ -626,6 +629,8 @@ export const commandDescriptions: Readonly<Record<Command, string>> = {
[Command.NEWLINE]: 'Insert a newline without submitting.', [Command.NEWLINE]: 'Insert a newline without submitting.',
[Command.OPEN_EXTERNAL_EDITOR]: [Command.OPEN_EXTERNAL_EDITOR]:
'Open the current prompt or the plan in an 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.', [Command.PASTE_CLIPBOARD]: 'Paste from the clipboard.',
// App Controls // App Controls
+7 -2
View File
@@ -311,6 +311,11 @@ describe('keyMatchers', () => {
// External tools // External tools
{ {
command: Command.OPEN_EXTERNAL_EDITOR, 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 })], positive: [createKey('x', { ctrl: true })],
negative: [createKey('x'), createKey('c', { ctrl: true })], negative: [createKey('x'), createKey('c', { ctrl: true })],
}, },
@@ -336,8 +341,8 @@ describe('keyMatchers', () => {
}, },
{ {
command: Command.SHOW_IDE_CONTEXT_DETAIL, command: Command.SHOW_IDE_CONTEXT_DETAIL,
positive: [createKey('g', { ctrl: true })], positive: [createKey('f4')],
negative: [createKey('g'), createKey('t', { ctrl: true })], negative: [createKey('f5'), createKey('t', { ctrl: true })],
}, },
{ {
command: Command.TOGGLE_MARKDOWN, command: Command.TOGGLE_MARKDOWN,