mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
remove wildcard behavior on keybindings (#21315)
This commit is contained in:
committed by
GitHub
parent
e8bc7bea44
commit
19c9508fd1
@@ -19,12 +19,12 @@ available combinations.
|
||||
|
||||
| Action | Keys |
|
||||
| ------------------------------------------- | ------------------------------------------------------------ |
|
||||
| Move the cursor to the start of the line. | `Ctrl + A`<br />`Home (no Shift, Ctrl)` |
|
||||
| Move the cursor to the end of the line. | `Ctrl + E`<br />`End (no Shift, Ctrl)` |
|
||||
| Move the cursor up one line. | `Up Arrow (no Shift, Alt, Ctrl, Cmd)` |
|
||||
| Move the cursor down one line. | `Down Arrow (no Shift, Alt, Ctrl, Cmd)` |
|
||||
| Move the cursor one character to the left. | `Left Arrow (no Shift, Alt, Ctrl, Cmd)` |
|
||||
| Move the cursor one character to the right. | `Right Arrow (no Shift, Alt, Ctrl, Cmd)`<br />`Ctrl + F` |
|
||||
| Move the cursor to the start of the line. | `Ctrl + A`<br />`Home` |
|
||||
| Move the cursor to the end of the line. | `Ctrl + E`<br />`End` |
|
||||
| Move the cursor up one line. | `Up Arrow` |
|
||||
| Move the cursor down one line. | `Down Arrow` |
|
||||
| Move the cursor one character to the left. | `Left Arrow` |
|
||||
| Move the cursor one character to the right. | `Right Arrow`<br />`Ctrl + F` |
|
||||
| Move the cursor one word to the left. | `Ctrl + Left Arrow`<br />`Alt + Left Arrow`<br />`Alt + B` |
|
||||
| Move the cursor one word to the right. | `Ctrl + Right Arrow`<br />`Alt + Right Arrow`<br />`Alt + F` |
|
||||
|
||||
@@ -39,7 +39,7 @@ available combinations.
|
||||
| Delete the next word. | `Ctrl + Delete`<br />`Alt + Delete`<br />`Alt + D` |
|
||||
| Delete the character to the left. | `Backspace`<br />`Ctrl + H` |
|
||||
| Delete the character to the right. | `Delete`<br />`Ctrl + D` |
|
||||
| Undo the most recent text edit. | `Cmd + Z (no Shift)`<br />`Alt + Z (no Shift)` |
|
||||
| Undo the most recent text edit. | `Cmd + Z`<br />`Alt + Z` |
|
||||
| Redo the most recent undone text edit. | `Shift + Ctrl + Z`<br />`Shift + Cmd + Z`<br />`Shift + Alt + Z` |
|
||||
|
||||
#### Scrolling
|
||||
@@ -55,72 +55,72 @@ available combinations.
|
||||
|
||||
#### History & Search
|
||||
|
||||
| Action | Keys |
|
||||
| -------------------------------------------- | --------------------- |
|
||||
| Show the previous entry in history. | `Ctrl + P (no Shift)` |
|
||||
| Show the next entry in history. | `Ctrl + N (no Shift)` |
|
||||
| Start reverse search through history. | `Ctrl + R` |
|
||||
| Submit the selected reverse-search match. | `Enter (no Ctrl)` |
|
||||
| Accept a suggestion while reverse searching. | `Tab (no Shift)` |
|
||||
| Browse and rewind previous interactions. | `Double Esc` |
|
||||
| Action | Keys |
|
||||
| -------------------------------------------- | ------------ |
|
||||
| Show the previous entry in history. | `Ctrl + P` |
|
||||
| Show the next entry in history. | `Ctrl + N` |
|
||||
| Start reverse search through history. | `Ctrl + R` |
|
||||
| Submit the selected reverse-search match. | `Enter` |
|
||||
| Accept a suggestion while reverse searching. | `Tab` |
|
||||
| Browse and rewind previous interactions. | `Double Esc` |
|
||||
|
||||
#### Navigation
|
||||
|
||||
| Action | Keys |
|
||||
| -------------------------------------------------- | ------------------------------------------- |
|
||||
| Move selection up in lists. | `Up Arrow (no Shift)` |
|
||||
| Move selection down in lists. | `Down Arrow (no Shift)` |
|
||||
| Move up within dialog options. | `Up Arrow (no Shift)`<br />`K (no Shift)` |
|
||||
| Move down within dialog options. | `Down Arrow (no Shift)`<br />`J (no Shift)` |
|
||||
| Move to the next item or question in a dialog. | `Tab (no Shift)` |
|
||||
| Move to the previous item or question in a dialog. | `Shift + Tab` |
|
||||
| Action | Keys |
|
||||
| -------------------------------------------------- | --------------------- |
|
||||
| Move selection up in lists. | `Up Arrow` |
|
||||
| Move selection down in lists. | `Down Arrow` |
|
||||
| Move up within dialog options. | `Up Arrow`<br />`K` |
|
||||
| Move down within dialog options. | `Down Arrow`<br />`J` |
|
||||
| Move to the next item or question in a dialog. | `Tab` |
|
||||
| Move to the previous item or question in a dialog. | `Shift + Tab` |
|
||||
|
||||
#### Suggestions & Completions
|
||||
|
||||
| Action | Keys |
|
||||
| --------------------------------------- | -------------------------------------------------- |
|
||||
| Accept the inline suggestion. | `Tab (no Shift)`<br />`Enter (no Ctrl)` |
|
||||
| Move to the previous completion option. | `Up Arrow (no Shift)`<br />`Ctrl + P (no Shift)` |
|
||||
| Move to the next completion option. | `Down Arrow (no Shift)`<br />`Ctrl + N (no Shift)` |
|
||||
| Expand an inline suggestion. | `Right Arrow` |
|
||||
| Collapse an inline suggestion. | `Left Arrow` |
|
||||
| Action | Keys |
|
||||
| --------------------------------------- | ---------------------------- |
|
||||
| Accept the inline suggestion. | `Tab`<br />`Enter` |
|
||||
| Move to the previous completion option. | `Up Arrow`<br />`Ctrl + P` |
|
||||
| Move to the next completion option. | `Down Arrow`<br />`Ctrl + N` |
|
||||
| Expand an inline suggestion. | `Right Arrow` |
|
||||
| Collapse an inline suggestion. | `Left Arrow` |
|
||||
|
||||
#### Text Input
|
||||
|
||||
| Action | Keys |
|
||||
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Submit the current prompt. | `Enter (no Shift, Alt, Ctrl, Cmd)` |
|
||||
| Submit the current prompt. | `Enter` |
|
||||
| Insert a newline without submitting. | `Ctrl + Enter`<br />`Cmd + Enter`<br />`Alt + Enter`<br />`Shift + Enter`<br />`Ctrl + J` |
|
||||
| Open the current prompt or the plan in an external editor. | `Ctrl + X` |
|
||||
| Paste from the clipboard. | `Ctrl + V`<br />`Cmd + V`<br />`Alt + V` |
|
||||
|
||||
#### App Controls
|
||||
|
||||
| Action | Keys |
|
||||
| -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
|
||||
| Toggle detailed error information. | `F12` |
|
||||
| Toggle the full TODO list. | `Ctrl + T` |
|
||||
| Show IDE context details. | `Ctrl + G` |
|
||||
| Toggle Markdown rendering. | `Alt + M` |
|
||||
| Toggle copy mode when in alternate buffer mode. | `Ctrl + S` |
|
||||
| Toggle YOLO (auto-approval) mode for tool calls. | `Ctrl + Y` |
|
||||
| Cycle through approval modes: default (prompt), auto_edit (auto-approve edits), and plan (read-only). Plan mode is skipped when the agent is busy. | `Shift + Tab` |
|
||||
| Expand and collapse blocks of content when not in alternate buffer mode. | `Ctrl + O` |
|
||||
| Expand or collapse a paste placeholder when cursor is over placeholder. | `Ctrl + O` |
|
||||
| Toggle current background shell visibility. | `Ctrl + B` |
|
||||
| Toggle background shell list. | `Ctrl + L` |
|
||||
| Kill the active background shell. | `Ctrl + K` |
|
||||
| Confirm selection in background shell list. | `Enter` |
|
||||
| Dismiss background shell list. | `Esc` |
|
||||
| Move focus from background shell to Gemini. | `Shift + Tab` |
|
||||
| Move focus from background shell list to Gemini. | `Tab (no Shift)` |
|
||||
| Show warning when trying to move focus away from background shell. | `Tab (no Shift)` |
|
||||
| Show warning when trying to move focus away from shell input. | `Tab (no Shift)` |
|
||||
| Move focus from Gemini to the active shell. | `Tab (no Shift)` |
|
||||
| Move focus from the shell back to Gemini. | `Shift + Tab` |
|
||||
| Clear the terminal screen and redraw the UI. | `Ctrl + L` |
|
||||
| Restart the application. | `R` |
|
||||
| Suspend the CLI and move it to the background. | `Ctrl + Z` |
|
||||
| Action | Keys |
|
||||
| -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
|
||||
| Toggle detailed error information. | `F12` |
|
||||
| Toggle the full TODO list. | `Ctrl + T` |
|
||||
| Show IDE context details. | `Ctrl + G` |
|
||||
| Toggle Markdown rendering. | `Alt + M` |
|
||||
| Toggle copy mode when in alternate buffer mode. | `Ctrl + S` |
|
||||
| Toggle YOLO (auto-approval) mode for tool calls. | `Ctrl + Y` |
|
||||
| Cycle through approval modes: default (prompt), auto_edit (auto-approve edits), and plan (read-only). Plan mode is skipped when the agent is busy. | `Shift + Tab` |
|
||||
| Expand and collapse blocks of content when not in alternate buffer mode. | `Ctrl + O` |
|
||||
| Expand or collapse a paste placeholder when cursor is over placeholder. | `Ctrl + O` |
|
||||
| Toggle current background shell visibility. | `Ctrl + B` |
|
||||
| Toggle background shell list. | `Ctrl + L` |
|
||||
| Kill the active background shell. | `Ctrl + K` |
|
||||
| Confirm selection in background shell list. | `Enter` |
|
||||
| Dismiss background shell list. | `Esc` |
|
||||
| Move focus from background shell to Gemini. | `Shift + Tab` |
|
||||
| Move focus from background shell list to Gemini. | `Tab` |
|
||||
| Show warning when trying to move focus away from background shell. | `Tab` |
|
||||
| Show warning when trying to move focus away from shell input. | `Tab` |
|
||||
| Move focus from Gemini to the active shell. | `Tab` |
|
||||
| Move focus from the shell back to Gemini. | `Shift + Tab` |
|
||||
| Clear the terminal screen and redraw the UI. | `Ctrl + L` |
|
||||
| Restart the application. | `R`<br />`Shift + R` |
|
||||
| Suspend the CLI and move it to the background. | `Ctrl + Z` |
|
||||
|
||||
<!-- KEYBINDINGS-AUTOGEN:END -->
|
||||
|
||||
@@ -156,7 +156,7 @@ available combinations.
|
||||
## Limitations
|
||||
|
||||
- On [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal):
|
||||
- `shift+enter` is not supported.
|
||||
- `shift+enter` is only supported in version 1.25 and higher.
|
||||
- `shift+tab`
|
||||
[is not supported](https://github.com/google-gemini/gemini-cli/issues/20314)
|
||||
on Node 20 and earlier versions of Node 22.
|
||||
|
||||
@@ -58,46 +58,6 @@ describe('keyBindings config', () => {
|
||||
const config: KeyBindingConfig = defaultKeyBindings;
|
||||
expect(config[Command.HOME]).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have correct specific bindings', () => {
|
||||
// Verify navigation ignores shift
|
||||
const navUp = defaultKeyBindings[Command.NAVIGATION_UP];
|
||||
expect(navUp).toContainEqual({ key: 'up', shift: false });
|
||||
|
||||
const navDown = defaultKeyBindings[Command.NAVIGATION_DOWN];
|
||||
expect(navDown).toContainEqual({ key: 'down', shift: false });
|
||||
|
||||
// Verify dialog navigation
|
||||
const dialogNavUp = defaultKeyBindings[Command.DIALOG_NAVIGATION_UP];
|
||||
expect(dialogNavUp).toContainEqual({ key: 'up', shift: false });
|
||||
expect(dialogNavUp).toContainEqual({ key: 'k', shift: false });
|
||||
|
||||
const dialogNavDown = defaultKeyBindings[Command.DIALOG_NAVIGATION_DOWN];
|
||||
expect(dialogNavDown).toContainEqual({ key: 'down', shift: false });
|
||||
expect(dialogNavDown).toContainEqual({ key: 'j', shift: false });
|
||||
|
||||
// Verify physical home/end keys for cursor movement
|
||||
expect(defaultKeyBindings[Command.HOME]).toContainEqual({
|
||||
key: 'home',
|
||||
ctrl: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(defaultKeyBindings[Command.END]).toContainEqual({
|
||||
key: 'end',
|
||||
ctrl: false,
|
||||
shift: false,
|
||||
});
|
||||
|
||||
// Verify physical home/end keys for scrolling
|
||||
expect(defaultKeyBindings[Command.SCROLL_HOME]).toContainEqual({
|
||||
key: 'home',
|
||||
ctrl: true,
|
||||
});
|
||||
expect(defaultKeyBindings[Command.SCROLL_END]).toContainEqual({
|
||||
key: 'end',
|
||||
ctrl: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('command metadata', () => {
|
||||
|
||||
@@ -134,27 +134,12 @@ export const defaultKeyBindings: KeyBindingConfig = {
|
||||
[Command.EXIT]: [{ key: 'd', ctrl: true }],
|
||||
|
||||
// Cursor Movement
|
||||
[Command.HOME]: [
|
||||
{ key: 'a', ctrl: true },
|
||||
{ key: 'home', shift: false, ctrl: false },
|
||||
],
|
||||
[Command.END]: [
|
||||
{ key: 'e', ctrl: true },
|
||||
{ key: 'end', shift: false, ctrl: false },
|
||||
],
|
||||
[Command.MOVE_UP]: [
|
||||
{ key: 'up', shift: false, alt: false, ctrl: false, cmd: false },
|
||||
],
|
||||
[Command.MOVE_DOWN]: [
|
||||
{ key: 'down', shift: false, alt: false, ctrl: false, cmd: false },
|
||||
],
|
||||
[Command.MOVE_LEFT]: [
|
||||
{ key: 'left', shift: false, alt: false, ctrl: false, cmd: false },
|
||||
],
|
||||
[Command.MOVE_RIGHT]: [
|
||||
{ key: 'right', shift: false, alt: false, ctrl: false, cmd: false },
|
||||
{ key: 'f', ctrl: true },
|
||||
],
|
||||
[Command.HOME]: [{ key: 'a', ctrl: true }, { key: 'home' }],
|
||||
[Command.END]: [{ key: 'e', ctrl: true }, { key: 'end' }],
|
||||
[Command.MOVE_UP]: [{ key: 'up' }],
|
||||
[Command.MOVE_DOWN]: [{ key: 'down' }],
|
||||
[Command.MOVE_LEFT]: [{ key: 'left' }],
|
||||
[Command.MOVE_RIGHT]: [{ key: 'right' }, { key: 'f', ctrl: true }],
|
||||
[Command.MOVE_WORD_LEFT]: [
|
||||
{ key: 'left', ctrl: true },
|
||||
{ key: 'left', alt: true },
|
||||
@@ -183,8 +168,8 @@ export const defaultKeyBindings: KeyBindingConfig = {
|
||||
[Command.DELETE_CHAR_LEFT]: [{ key: 'backspace' }, { key: 'h', ctrl: true }],
|
||||
[Command.DELETE_CHAR_RIGHT]: [{ key: 'delete' }, { key: 'd', ctrl: true }],
|
||||
[Command.UNDO]: [
|
||||
{ key: 'z', cmd: true, shift: false },
|
||||
{ key: 'z', alt: true, shift: false },
|
||||
{ key: 'z', cmd: true },
|
||||
{ key: 'z', alt: true },
|
||||
],
|
||||
[Command.REDO]: [
|
||||
{ key: 'z', ctrl: true, shift: true },
|
||||
@@ -207,56 +192,33 @@ export const defaultKeyBindings: KeyBindingConfig = {
|
||||
[Command.PAGE_DOWN]: [{ key: 'pagedown' }],
|
||||
|
||||
// History & Search
|
||||
[Command.HISTORY_UP]: [{ key: 'p', shift: false, ctrl: true }],
|
||||
[Command.HISTORY_DOWN]: [{ key: 'n', shift: false, ctrl: true }],
|
||||
[Command.HISTORY_UP]: [{ key: 'p', ctrl: true }],
|
||||
[Command.HISTORY_DOWN]: [{ key: 'n', ctrl: true }],
|
||||
[Command.REVERSE_SEARCH]: [{ key: 'r', ctrl: true }],
|
||||
[Command.REWIND]: [{ key: 'double escape' }],
|
||||
[Command.SUBMIT_REVERSE_SEARCH]: [{ key: 'return', ctrl: false }],
|
||||
[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH]: [{ key: 'tab', shift: false }],
|
||||
[Command.REWIND]: [{ key: 'double escape' }], // for documentation only
|
||||
[Command.SUBMIT_REVERSE_SEARCH]: [{ key: 'return' }],
|
||||
[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH]: [{ key: 'tab' }],
|
||||
|
||||
// Navigation
|
||||
[Command.NAVIGATION_UP]: [{ key: 'up', shift: false }],
|
||||
[Command.NAVIGATION_DOWN]: [{ key: 'down', shift: false }],
|
||||
[Command.NAVIGATION_UP]: [{ key: 'up' }],
|
||||
[Command.NAVIGATION_DOWN]: [{ key: 'down' }],
|
||||
// Navigation shortcuts appropriate for dialogs where we do not need to accept
|
||||
// text input.
|
||||
[Command.DIALOG_NAVIGATION_UP]: [
|
||||
{ key: 'up', shift: false },
|
||||
{ key: 'k', shift: false },
|
||||
],
|
||||
[Command.DIALOG_NAVIGATION_DOWN]: [
|
||||
{ key: 'down', shift: false },
|
||||
{ key: 'j', shift: false },
|
||||
],
|
||||
[Command.DIALOG_NEXT]: [{ key: 'tab', shift: false }],
|
||||
[Command.DIALOG_NAVIGATION_UP]: [{ key: 'up' }, { key: 'k' }],
|
||||
[Command.DIALOG_NAVIGATION_DOWN]: [{ key: 'down' }, { key: 'j' }],
|
||||
[Command.DIALOG_NEXT]: [{ key: 'tab' }],
|
||||
[Command.DIALOG_PREV]: [{ key: 'tab', shift: true }],
|
||||
|
||||
// Suggestions & Completions
|
||||
[Command.ACCEPT_SUGGESTION]: [
|
||||
{ key: 'tab', shift: false },
|
||||
{ key: 'return', ctrl: false },
|
||||
],
|
||||
[Command.COMPLETION_UP]: [
|
||||
{ key: 'up', shift: false },
|
||||
{ key: 'p', shift: false, ctrl: true },
|
||||
],
|
||||
[Command.COMPLETION_DOWN]: [
|
||||
{ key: 'down', shift: false },
|
||||
{ key: 'n', shift: false, ctrl: true },
|
||||
],
|
||||
[Command.ACCEPT_SUGGESTION]: [{ key: 'tab' }, { key: 'return' }],
|
||||
[Command.COMPLETION_UP]: [{ key: 'up' }, { key: 'p', ctrl: true }],
|
||||
[Command.COMPLETION_DOWN]: [{ key: 'down' }, { key: 'n', ctrl: true }],
|
||||
[Command.EXPAND_SUGGESTION]: [{ key: 'right' }],
|
||||
[Command.COLLAPSE_SUGGESTION]: [{ key: 'left' }],
|
||||
|
||||
// Text Input
|
||||
// Must also exclude shift to allow shift+enter for newline
|
||||
[Command.SUBMIT]: [
|
||||
{
|
||||
key: 'return',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
},
|
||||
],
|
||||
[Command.SUBMIT]: [{ key: 'return' }],
|
||||
[Command.NEWLINE]: [
|
||||
{ key: 'return', ctrl: true },
|
||||
{ key: 'return', cmd: true },
|
||||
@@ -283,19 +245,17 @@ export const defaultKeyBindings: KeyBindingConfig = {
|
||||
[Command.TOGGLE_BACKGROUND_SHELL_LIST]: [{ key: 'l', ctrl: true }],
|
||||
[Command.KILL_BACKGROUND_SHELL]: [{ key: 'k', ctrl: true }],
|
||||
[Command.UNFOCUS_BACKGROUND_SHELL]: [{ key: 'tab', shift: true }],
|
||||
[Command.UNFOCUS_BACKGROUND_SHELL_LIST]: [{ key: 'tab', shift: false }],
|
||||
[Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING]: [
|
||||
{ key: 'tab', shift: false },
|
||||
],
|
||||
[Command.SHOW_SHELL_INPUT_UNFOCUS_WARNING]: [{ key: 'tab', shift: false }],
|
||||
[Command.UNFOCUS_BACKGROUND_SHELL_LIST]: [{ key: 'tab' }],
|
||||
[Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING]: [{ key: 'tab' }],
|
||||
[Command.SHOW_SHELL_INPUT_UNFOCUS_WARNING]: [{ key: 'tab' }],
|
||||
[Command.BACKGROUND_SHELL_SELECT]: [{ key: 'return' }],
|
||||
[Command.BACKGROUND_SHELL_ESCAPE]: [{ key: 'escape' }],
|
||||
[Command.SHOW_MORE_LINES]: [{ key: 'o', ctrl: true }],
|
||||
[Command.EXPAND_PASTE]: [{ key: 'o', ctrl: true }],
|
||||
[Command.FOCUS_SHELL_INPUT]: [{ key: 'tab', shift: false }],
|
||||
[Command.FOCUS_SHELL_INPUT]: [{ key: 'tab' }],
|
||||
[Command.UNFOCUS_SHELL_INPUT]: [{ key: 'tab', shift: true }],
|
||||
[Command.CLEAR_SCREEN]: [{ key: 'l', ctrl: true }],
|
||||
[Command.RESTART_APP]: [{ key: 'r' }],
|
||||
[Command.RESTART_APP]: [{ key: 'r' }, { key: 'r', shift: true }],
|
||||
[Command.SUSPEND_APP]: [{ key: 'z', ctrl: true }],
|
||||
};
|
||||
|
||||
|
||||
@@ -11,17 +11,6 @@ Enter to submit · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Choice question placeholder > uses default placeholder when not provided 2`] = `
|
||||
"Select your preferred language:
|
||||
|
||||
1. TypeScript
|
||||
2. JavaScript
|
||||
● 3. Enter a custom value
|
||||
|
||||
Enter to submit · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Choice question placeholder > uses placeholder for "Other" option when provided 1`] = `
|
||||
"Select your preferred language:
|
||||
|
||||
@@ -33,17 +22,6 @@ Enter to submit · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Choice question placeholder > uses placeholder for "Other" option when provided 2`] = `
|
||||
"Select your preferred language:
|
||||
|
||||
1. TypeScript
|
||||
2. JavaScript
|
||||
● 3. Type another language...
|
||||
|
||||
Enter to submit · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Scroll Arrows (useAlternateBuffer: false) > shows scroll arrows correctly when useAlternateBuffer is false 1`] = `
|
||||
"Choose an option
|
||||
|
||||
@@ -58,20 +36,6 @@ Enter to select · ↑/↓ to navigate · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Scroll Arrows (useAlternateBuffer: false) > shows scroll arrows correctly when useAlternateBuffer is false 2`] = `
|
||||
"Choose an option
|
||||
|
||||
▲
|
||||
● 1. Option 1
|
||||
Description 1
|
||||
2. Option 2
|
||||
Description 2
|
||||
▼
|
||||
|
||||
Enter to select · ↑/↓ to navigate · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Scroll Arrows (useAlternateBuffer: true) > shows scroll arrows correctly when useAlternateBuffer is true 1`] = `
|
||||
"Choose an option
|
||||
|
||||
@@ -111,45 +75,6 @@ Enter to select · ↑/↓ to navigate · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Scroll Arrows (useAlternateBuffer: true) > shows scroll arrows correctly when useAlternateBuffer is true 2`] = `
|
||||
"Choose an option
|
||||
|
||||
● 1. Option 1
|
||||
Description 1
|
||||
2. Option 2
|
||||
Description 2
|
||||
3. Option 3
|
||||
Description 3
|
||||
4. Option 4
|
||||
Description 4
|
||||
5. Option 5
|
||||
Description 5
|
||||
6. Option 6
|
||||
Description 6
|
||||
7. Option 7
|
||||
Description 7
|
||||
8. Option 8
|
||||
Description 8
|
||||
9. Option 9
|
||||
Description 9
|
||||
10. Option 10
|
||||
Description 10
|
||||
11. Option 11
|
||||
Description 11
|
||||
12. Option 12
|
||||
Description 12
|
||||
13. Option 13
|
||||
Description 13
|
||||
14. Option 14
|
||||
Description 14
|
||||
15. Option 15
|
||||
Description 15
|
||||
16. Enter a custom value
|
||||
|
||||
Enter to select · ↑/↓ to navigate · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Text type questions > renders text input for type: "text" 1`] = `
|
||||
"What should we name this component?
|
||||
|
||||
|
||||
@@ -27,33 +27,6 @@ Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: false > bubbles up Ctrl+C when feedback is empty while editing 2`] = `
|
||||
"Overview
|
||||
|
||||
Add user authentication to the CLI application.
|
||||
|
||||
Implementation Steps
|
||||
|
||||
1. Create src/auth/AuthService.ts with login/logout methods
|
||||
2. Add session storage in src/storage/SessionStore.ts
|
||||
3. Update src/commands/index.ts to check auth status
|
||||
4. Add tests in src/auth/__tests__/
|
||||
|
||||
Files to Modify
|
||||
|
||||
- src/index.ts - Add auth middleware
|
||||
- src/config.ts - Add auth configuration options
|
||||
|
||||
1. Yes, automatically accept edits
|
||||
Approves plan and allows tools to run automatically
|
||||
2. Yes, manually accept edits
|
||||
Approves plan but requires confirmation for each tool
|
||||
● 3. Type your feedback...
|
||||
|
||||
Enter to submit · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: false > calls onFeedback when feedback is typed and submitted 1`] = `
|
||||
"Overview
|
||||
|
||||
@@ -81,33 +54,6 @@ Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: false > calls onFeedback when feedback is typed and submitted 2`] = `
|
||||
"Overview
|
||||
|
||||
Add user authentication to the CLI application.
|
||||
|
||||
Implementation Steps
|
||||
|
||||
1. Create src/auth/AuthService.ts with login/logout methods
|
||||
2. Add session storage in src/storage/SessionStore.ts
|
||||
3. Update src/commands/index.ts to check auth status
|
||||
4. Add tests in src/auth/__tests__/
|
||||
|
||||
Files to Modify
|
||||
|
||||
- src/index.ts - Add auth middleware
|
||||
- src/config.ts - Add auth configuration options
|
||||
|
||||
1. Yes, automatically accept edits
|
||||
Approves plan and allows tools to run automatically
|
||||
2. Yes, manually accept edits
|
||||
Approves plan but requires confirmation for each tool
|
||||
● 3. Add tests
|
||||
|
||||
Enter to submit · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: false > displays error state when file read fails 1`] = `
|
||||
" Error reading plan: File not found
|
||||
"
|
||||
@@ -194,33 +140,6 @@ Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: true > bubbles up Ctrl+C when feedback is empty while editing 2`] = `
|
||||
"Overview
|
||||
|
||||
Add user authentication to the CLI application.
|
||||
|
||||
Implementation Steps
|
||||
|
||||
1. Create src/auth/AuthService.ts with login/logout methods
|
||||
2. Add session storage in src/storage/SessionStore.ts
|
||||
3. Update src/commands/index.ts to check auth status
|
||||
4. Add tests in src/auth/__tests__/
|
||||
|
||||
Files to Modify
|
||||
|
||||
- src/index.ts - Add auth middleware
|
||||
- src/config.ts - Add auth configuration options
|
||||
|
||||
1. Yes, automatically accept edits
|
||||
Approves plan and allows tools to run automatically
|
||||
2. Yes, manually accept edits
|
||||
Approves plan but requires confirmation for each tool
|
||||
● 3. Type your feedback...
|
||||
|
||||
Enter to submit · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: true > calls onFeedback when feedback is typed and submitted 1`] = `
|
||||
"Overview
|
||||
|
||||
@@ -248,33 +167,6 @@ Enter to select · ↑/↓ to navigate · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: true > calls onFeedback when feedback is typed and submitted 2`] = `
|
||||
"Overview
|
||||
|
||||
Add user authentication to the CLI application.
|
||||
|
||||
Implementation Steps
|
||||
|
||||
1. Create src/auth/AuthService.ts with login/logout methods
|
||||
2. Add session storage in src/storage/SessionStore.ts
|
||||
3. Update src/commands/index.ts to check auth status
|
||||
4. Add tests in src/auth/__tests__/
|
||||
|
||||
Files to Modify
|
||||
|
||||
- src/index.ts - Add auth middleware
|
||||
- src/config.ts - Add auth configuration options
|
||||
|
||||
1. Yes, automatically accept edits
|
||||
Approves plan and allows tools to run automatically
|
||||
2. Yes, manually accept edits
|
||||
Approves plan but requires confirmation for each tool
|
||||
● 3. Add tests
|
||||
|
||||
Enter to submit · Ctrl+X to edit plan · Esc to cancel
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ExitPlanModeDialog > useAlternateBuffer: true > displays error state when file read fails 1`] = `
|
||||
" Error reading plan: File not found
|
||||
"
|
||||
|
||||
@@ -78,27 +78,6 @@ exports[`InputPrompt > mouse interaction > should toggle paste expansion on doub
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > mouse interaction > should toggle paste expansion on double-click 4`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> [Pasted Text: 10 lines]
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > mouse interaction > should toggle paste expansion on double-click 5`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> [Pasted Text: 10 lines]
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > mouse interaction > should toggle paste expansion on double-click 6`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> [Pasted Text: 10 lines]
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > snapshots > should not show inverted cursor when shell is focused 1`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> Type your message or @path/to/file
|
||||
|
||||
@@ -288,7 +288,7 @@ describe('KeypressContext', () => {
|
||||
expect.objectContaining({
|
||||
name: 'escape',
|
||||
shift: false,
|
||||
alt: true,
|
||||
alt: false,
|
||||
cmd: false,
|
||||
}),
|
||||
);
|
||||
@@ -297,7 +297,7 @@ describe('KeypressContext', () => {
|
||||
expect.objectContaining({
|
||||
name: 'escape',
|
||||
shift: false,
|
||||
alt: true,
|
||||
alt: false,
|
||||
cmd: false,
|
||||
}),
|
||||
);
|
||||
@@ -326,7 +326,7 @@ describe('KeypressContext', () => {
|
||||
expect.objectContaining({
|
||||
name: 'escape',
|
||||
shift: false,
|
||||
alt: true,
|
||||
alt: false,
|
||||
cmd: false,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -178,8 +178,7 @@ function nonKeyboardEventFilter(
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts return keys pressed quickly after other keys into plain
|
||||
* insertable return characters.
|
||||
* Converts return keys pressed quickly after insertable keys into a shift+return
|
||||
*
|
||||
* This is to accommodate older terminals that paste text without bracketing.
|
||||
*/
|
||||
@@ -201,7 +200,7 @@ function bufferFastReturn(keypressHandler: KeypressHandler): KeypressHandler {
|
||||
} else {
|
||||
keypressHandler(key);
|
||||
}
|
||||
lastKeyTime = now;
|
||||
lastKeyTime = key.insertable ? now : 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -630,7 +629,7 @@ function* emitKeys(
|
||||
} else if (sequence === `${ESC}${ESC}`) {
|
||||
// Double escape
|
||||
name = 'escape';
|
||||
alt = true;
|
||||
alt = false;
|
||||
|
||||
// Emit first escape key here, then continue processing
|
||||
keypressHandler({
|
||||
@@ -645,7 +644,7 @@ function* emitKeys(
|
||||
} else if (escaped) {
|
||||
// Escape sequence timeout
|
||||
name = ch.length ? undefined : 'escape';
|
||||
alt = true;
|
||||
alt = ch.length > 0;
|
||||
} else {
|
||||
// Any other character is considered printable.
|
||||
insertable = true;
|
||||
|
||||
@@ -32,8 +32,12 @@ describe('keyMatchers', () => {
|
||||
},
|
||||
{
|
||||
command: Command.ESCAPE,
|
||||
positive: [createKey('escape'), createKey('escape', { ctrl: true })],
|
||||
negative: [createKey('e'), createKey('esc')],
|
||||
positive: [createKey('escape')],
|
||||
negative: [
|
||||
createKey('e'),
|
||||
createKey('esc'),
|
||||
createKey('escape', { ctrl: true }),
|
||||
],
|
||||
},
|
||||
|
||||
// Cursor movement
|
||||
@@ -192,13 +196,21 @@ describe('keyMatchers', () => {
|
||||
},
|
||||
{
|
||||
command: Command.PAGE_UP,
|
||||
positive: [createKey('pageup'), createKey('pageup', { shift: true })],
|
||||
negative: [createKey('pagedown'), createKey('up')],
|
||||
positive: [createKey('pageup')],
|
||||
negative: [
|
||||
createKey('pagedown'),
|
||||
createKey('up'),
|
||||
createKey('pageup', { shift: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
command: Command.PAGE_DOWN,
|
||||
positive: [createKey('pagedown'), createKey('pagedown', { ctrl: true })],
|
||||
negative: [createKey('pageup'), createKey('down')],
|
||||
positive: [createKey('pagedown')],
|
||||
negative: [
|
||||
createKey('pageup'),
|
||||
createKey('down'),
|
||||
createKey('pagedown', { ctrl: true }),
|
||||
],
|
||||
},
|
||||
|
||||
// History navigation
|
||||
@@ -214,13 +226,21 @@ describe('keyMatchers', () => {
|
||||
},
|
||||
{
|
||||
command: Command.NAVIGATION_UP,
|
||||
positive: [createKey('up'), createKey('up', { ctrl: true })],
|
||||
negative: [createKey('p'), createKey('u')],
|
||||
positive: [createKey('up')],
|
||||
negative: [
|
||||
createKey('p'),
|
||||
createKey('u'),
|
||||
createKey('up', { ctrl: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
command: Command.NAVIGATION_DOWN,
|
||||
positive: [createKey('down'), createKey('down', { ctrl: true })],
|
||||
negative: [createKey('n'), createKey('d')],
|
||||
positive: [createKey('down')],
|
||||
negative: [
|
||||
createKey('n'),
|
||||
createKey('d'),
|
||||
createKey('down', { ctrl: true }),
|
||||
],
|
||||
},
|
||||
|
||||
// Dialog navigation
|
||||
@@ -333,14 +353,12 @@ describe('keyMatchers', () => {
|
||||
},
|
||||
{
|
||||
command: Command.SUSPEND_APP,
|
||||
positive: [
|
||||
createKey('z', { ctrl: true }),
|
||||
createKey('z', { ctrl: true, shift: true }),
|
||||
],
|
||||
positive: [createKey('z', { ctrl: true })],
|
||||
negative: [
|
||||
createKey('z'),
|
||||
createKey('y', { ctrl: true }),
|
||||
createKey('z', { alt: true }),
|
||||
createKey('z', { ctrl: true, shift: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -365,8 +383,12 @@ describe('keyMatchers', () => {
|
||||
},
|
||||
{
|
||||
command: Command.ACCEPT_SUGGESTION_REVERSE_SEARCH,
|
||||
positive: [createKey('tab'), createKey('tab', { ctrl: true })],
|
||||
negative: [createKey('return'), createKey('space')],
|
||||
positive: [createKey('tab')],
|
||||
negative: [
|
||||
createKey('return'),
|
||||
createKey('space'),
|
||||
createKey('tab', { ctrl: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
command: Command.FOCUS_SHELL_INPUT,
|
||||
@@ -413,22 +435,6 @@ describe('keyMatchers', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly handle ACCEPT_SUGGESTION_REVERSE_SEARCH cases', () => {
|
||||
expect(
|
||||
keyMatchers[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH](
|
||||
createKey('return', { ctrl: true }),
|
||||
),
|
||||
).toBe(false); // ctrl must be false
|
||||
expect(
|
||||
keyMatchers[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH](createKey('tab')),
|
||||
).toBe(true);
|
||||
expect(
|
||||
keyMatchers[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH](
|
||||
createKey('tab', { ctrl: true }),
|
||||
),
|
||||
).toBe(true); // modifiers ignored
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom key bindings', () => {
|
||||
|
||||
@@ -13,16 +13,15 @@ import { Command, defaultKeyBindings } from '../config/keyBindings.js';
|
||||
* Pure data-driven matching logic
|
||||
*/
|
||||
function matchKeyBinding(keyBinding: KeyBinding, key: Key): boolean {
|
||||
// Check modifiers - follow original logic:
|
||||
// undefined = ignore this modifier (original behavior)
|
||||
// Check modifiers:
|
||||
// true = modifier must be pressed
|
||||
// false = modifier must NOT be pressed
|
||||
// false or undefined = modifier must NOT be pressed
|
||||
return (
|
||||
keyBinding.key === key.name &&
|
||||
(keyBinding.shift === undefined || key.shift === keyBinding.shift) &&
|
||||
(keyBinding.alt === undefined || key.alt === keyBinding.alt) &&
|
||||
(keyBinding.ctrl === undefined || key.ctrl === keyBinding.ctrl) &&
|
||||
(keyBinding.cmd === undefined || key.cmd === keyBinding.cmd)
|
||||
!!key.shift === !!keyBinding.shift &&
|
||||
!!key.alt === !!keyBinding.alt &&
|
||||
!!key.ctrl === !!keyBinding.ctrl &&
|
||||
!!key.cmd === !!keyBinding.cmd
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user