Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/cli/keyboard-shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ This document lists the available keyboard shortcuts in the Gemini CLI.
| `1-9` | Select an item by its number. |
| (multi-digit) | For items with numbers greater than 9, press the digits in quick succession to select the corresponding item. |

## Tool Use

| Shortcut | Description |
| -------- | ---------------------------------------------------------------------------------------------------- |
| `Ctrl+S` | When confirming an MCP tool call, toggle display of the input arguments to the MCP server (as JSON). |

## IDE Integration

| Shortcut | Description |
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/config/keyBindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export enum Command {
EXIT = 'exit',
SHOW_MORE_LINES = 'showMoreLines',

// Tool calling
TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION = 'toggleToolCallArgumentsExpansion',

// Shell commands
REVERSE_SEARCH = 'reverseSearch',
SUBMIT_REVERSE_SEARCH = 'submitReverseSearch',
Expand Down Expand Up @@ -162,6 +165,9 @@ export const defaultKeyBindings: KeyBindingConfig = {
[Command.EXIT]: [{ key: 'd', ctrl: true }],
[Command.SHOW_MORE_LINES]: [{ key: 's', ctrl: true }],

// Tool calling
[Command.TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION]: [{ key: 's', ctrl: true }],

// Shell commands
[Command.REVERSE_SEARCH]: [{ key: 'r', ctrl: true }],
// Note: original logic ONLY checked ctrl=false, ignored meta/shift/paste
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ describe('ToolConfirmationMessage', () => {
serverName: 'test-server',
toolName: 'test-tool',
toolDisplayName: 'Test Tool',
args: {},
onConfirm: vi.fn(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const ToolConfirmationMessage: React.FC<

const [ideClient, setIdeClient] = useState<IdeClient | null>(null);
const [isDiffingEnabled, setIsDiffingEnabled] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);

useEffect(() => {
let isMounted = true;
Expand Down Expand Up @@ -83,6 +84,8 @@ export const ToolConfirmationMessage: React.FC<
if (!isFocused) return;
if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {
handleConfirm(ToolConfirmationOutcome.Cancel);
} else if (key.ctrl && key.name === 's') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To improve consistency and maintainability, it's better to use the centralized keyMatchers for keybinding checks instead of hardcoding the key combination. This ensures that if the keybinding for TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION is ever changed in keyBindings.ts, it will be automatically reflected here. This also makes the purpose of defining the new Command and its keybinding clearer.

You'll also need to add import { keyMatchers, Command } from '../../keyMatchers.js'; at the top of the file.

Suggested change
} else if (key.ctrl && key.name === 's') {
} else if (keyMatchers[Command.TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION](key)) {

setIsExpanded((prev) => !prev);
}
Comment on lines +87 to 89
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The keypress for toggling argument expansion is hardcoded as key.ctrl && key.name === 's'. This is inconsistent with the rest of the application, which uses a centralized system for managing keybindings (keyBindings.ts) and matching them (keyMatchers.ts). You've already added the TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION command to this system, and it should be used here to maintain consistency and configurability.

You will need to import keyMatchers and Command from ../../keyMatchers.js.

Suggested change
} else if (key.ctrl && key.name === 's') {
setIsExpanded((prev) => !prev);
}
} else if (keyMatchers[Command.TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION](key)) {
setIsExpanded((prev) => !prev);
}

Copy link
Author

@janEbert janEbert Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in line with the if-query in the lines right above the change, which also checks for (key.name === 'escape' || (key.ctrl && key.name === 'c')). Should both occurrences be adapted? If yes, what should the other command(s) be?

},
{ isActive: isFocused },
Expand Down Expand Up @@ -273,6 +276,14 @@ export const ToolConfirmationMessage: React.FC<
<Box flexDirection="column" paddingX={1} marginLeft={1}>
<Text color={theme.text.link}>MCP Server: {mcpProps.serverName}</Text>
<Text color={theme.text.link}>Tool: {mcpProps.toolName}</Text>
{isExpanded && (
<Text color={theme.text.link}>
Arguments: {JSON.stringify(mcpProps.args, null, 2)}
</Text>
)}
<Text color={theme.text.secondary}>
(Press CTRL+s to {isExpanded ? 'collapse' : 'expand'} arguments)
</Text>
</Box>
);

Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/ui/keyMatchers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ describe('keyMatchers', () => {
[Command.QUIT]: (key: Key) => key.ctrl && key.name === 'c',
[Command.EXIT]: (key: Key) => key.ctrl && key.name === 'd',
[Command.SHOW_MORE_LINES]: (key: Key) => key.ctrl && key.name === 's',
[Command.TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION]: (key: Key) =>
key.ctrl && key.name === 's',
[Command.REVERSE_SEARCH]: (key: Key) => key.ctrl && key.name === 'r',
[Command.SUBMIT_REVERSE_SEARCH]: (key: Key) =>
key.name === 'return' && !key.ctrl,
Expand Down Expand Up @@ -241,6 +243,13 @@ describe('keyMatchers', () => {
negative: [createKey('s'), createKey('l', { ctrl: true })],
},

// Tool calling
{
command: Command.TOGGLE_TOOL_CALL_ARGUMENTS_EXPANSION,
positive: [createKey('s', { ctrl: true })],
negative: [createKey('s'), createKey('l', { ctrl: true })],
},

// Shell commands
{
command: Command.REVERSE_SEARCH,
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/ui/utils/textUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ describe('textUtils', () => {
serverName: '\u001b[31mmy-server\u001b[0m',
toolName: '\u001b[32mdeploy\u001b[0m',
toolDisplayName: '\u001b[33mDeploy Service\u001b[0m',
args: { a: '\u001b[35mvalue\u001b[0m' },
onConfirm: async () => {},
};

Expand All @@ -98,6 +99,9 @@ describe('textUtils', () => {
expect(sanitized.toolDisplayName).toBe(
'\\u001b[33mDeploy Service\\u001b[0m',
);
expect((sanitized.args as { a: string }).a).toBe(
'\\u001b[35mvalue\\u001b[0m',
);
}
});

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tools/mcp-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class DiscoveredMCPToolInvocation extends BaseToolInvocation<
serverName: this.serverName,
toolName: this.serverToolName, // Display original tool name in confirmation
toolDisplayName: this.displayName, // Display global registry name exposed to model and user
args: this.params,
onConfirm: async (outcome: ToolConfirmationOutcome) => {
if (outcome === ToolConfirmationOutcome.ProceedAlwaysServer) {
DiscoveredMCPToolInvocation.allowlist.add(serverAllowListKey);
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tools/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ export interface ToolMcpConfirmationDetails {
serverName: string;
toolName: string;
toolDisplayName: string;
args: Record<string, unknown>;
onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void>;
}

Expand Down