From 42c26d1e1b274ff88aa340a2330bc8f4decfa6ba Mon Sep 17 00:00:00 2001 From: Tommaso Sciortino Date: Wed, 14 Jan 2026 16:30:07 -0800 Subject: [PATCH] cleanup: Improve keybindings (#16672) --- docs/cli/keyboard-shortcuts.md | 2 ++ packages/cli/src/config/keyBindings.ts | 8 ++++++ .../src/ui/components/shared/text-buffer.ts | 26 ++++--------------- .../src/ui/contexts/KeypressContext.test.tsx | 2 +- .../cli/src/ui/contexts/KeypressContext.tsx | 2 +- 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/docs/cli/keyboard-shortcuts.md b/docs/cli/keyboard-shortcuts.md index 8cb87a1048..16a4083584 100644 --- a/docs/cli/keyboard-shortcuts.md +++ b/docs/cli/keyboard-shortcuts.md @@ -19,6 +19,8 @@ available combinations. | ------------------------------------------- | ------------------------------------------------------------ | | Move the cursor to the start of the line. | `Ctrl + A`
`Home` | | Move the cursor to the end of the line. | `Ctrl + E`
`End` | +| Move the cursor up one line. | `Up Arrow (no Ctrl, no Cmd)` | +| Move the cursor down one line. | `Down Arrow (no Ctrl, no Cmd)` | | Move the cursor one character to the left. | `Left Arrow (no Ctrl, no Cmd)`
`Ctrl + B` | | Move the cursor one character to the right. | `Right Arrow (no Ctrl, no Cmd)`
`Ctrl + F` | | Move the cursor one word to the left. | `Ctrl + Left Arrow`
`Cmd + Left Arrow`
`Cmd + B` | diff --git a/packages/cli/src/config/keyBindings.ts b/packages/cli/src/config/keyBindings.ts index b420ab0ef2..b101ae489e 100644 --- a/packages/cli/src/config/keyBindings.ts +++ b/packages/cli/src/config/keyBindings.ts @@ -66,6 +66,8 @@ export enum Command { TOGGLE_AUTO_EDIT = 'toggleAutoEdit', UNDO = 'undo', REDO = 'redo', + MOVE_UP = 'moveUp', + MOVE_DOWN = 'moveDown', MOVE_LEFT = 'moveLeft', MOVE_RIGHT = 'moveRight', MOVE_WORD_LEFT = 'moveWordLeft', @@ -141,6 +143,8 @@ export const defaultKeyBindings: KeyBindingConfig = { { key: 'right', ctrl: false, command: false }, { key: 'f', ctrl: true }, ], + [Command.MOVE_UP]: [{ key: 'up', ctrl: false, command: false }], + [Command.MOVE_DOWN]: [{ key: 'down', ctrl: false, command: false }], [Command.MOVE_WORD_LEFT]: [ { key: 'left', ctrl: true }, { key: 'left', command: true }, @@ -269,6 +273,8 @@ export const commandCategories: readonly CommandCategory[] = [ commands: [ Command.HOME, Command.END, + Command.MOVE_UP, + Command.MOVE_DOWN, Command.MOVE_LEFT, Command.MOVE_RIGHT, Command.MOVE_WORD_LEFT, @@ -372,6 +378,8 @@ export const commandDescriptions: Readonly> = { [Command.END]: 'Move the cursor to the end of the line.', [Command.MOVE_LEFT]: 'Move the cursor one character to the left.', [Command.MOVE_RIGHT]: 'Move the cursor one character to the right.', + [Command.MOVE_UP]: 'Move the cursor up one line.', + [Command.MOVE_DOWN]: 'Move the cursor down one line.', [Command.MOVE_WORD_LEFT]: 'Move the cursor one word to the left.', [Command.MOVE_WORD_RIGHT]: 'Move the cursor one word to the right.', [Command.KILL_LINE_RIGHT]: 'Delete from the cursor to the end of the line.', diff --git a/packages/cli/src/ui/components/shared/text-buffer.ts b/packages/cli/src/ui/components/shared/text-buffer.ts index 9ef6fdec83..a80d088bf2 100644 --- a/packages/cli/src/ui/components/shared/text-buffer.ts +++ b/packages/cli/src/ui/components/shared/text-buffer.ts @@ -2223,25 +2223,12 @@ export function useTextBuffer({ (key: Key): void => { const { sequence: input } = key; - if (key.name === 'paste') { - // Do not do any other processing on pastes so ensure we handle them - // before all other cases. - insert(input, { paste: true }); - return; - } - - if ( - !singleLine && - (key.name === 'return' || - input === '\r' || - input === '\n' || - input === '\\r') // VSCode terminal represents shift + enter this way - ) - newline(); + if (key.name === 'paste') insert(input, { paste: true }); + else if (keyMatchers[Command.RETURN](key)) newline(); else if (keyMatchers[Command.MOVE_LEFT](key)) move('left'); else if (keyMatchers[Command.MOVE_RIGHT](key)) move('right'); - else if (key.name === 'up') move('up'); - else if (key.name === 'down') move('down'); + else if (keyMatchers[Command.MOVE_UP](key)) move('up'); + else if (keyMatchers[Command.MOVE_DOWN](key)) move('down'); else if (keyMatchers[Command.MOVE_WORD_LEFT](key)) move('wordLeft'); else if (keyMatchers[Command.MOVE_WORD_RIGHT](key)) move('wordRight'); else if (keyMatchers[Command.HOME](key)) move('home'); @@ -2252,9 +2239,7 @@ export function useTextBuffer({ else if (keyMatchers[Command.DELETE_CHAR_RIGHT](key)) del(); else if (keyMatchers[Command.UNDO](key)) undo(); else if (keyMatchers[Command.REDO](key)) redo(); - else if (key.insertable) { - insert(input, { paste: false }); - } + else if (key.insertable) insert(input, { paste: false }); }, [ newline, @@ -2266,7 +2251,6 @@ export function useTextBuffer({ insert, undo, redo, - singleLine, ], ); diff --git a/packages/cli/src/ui/contexts/KeypressContext.test.tsx b/packages/cli/src/ui/contexts/KeypressContext.test.tsx index 24cadfa85c..af707fff69 100644 --- a/packages/cli/src/ui/contexts/KeypressContext.test.tsx +++ b/packages/cli/src/ui/contexts/KeypressContext.test.tsx @@ -179,7 +179,7 @@ describe('KeypressContext', () => { expect(keyHandler).toHaveBeenLastCalledWith( expect.objectContaining({ - name: '', + name: 'return', sequence: '\r', insertable: true, }), diff --git a/packages/cli/src/ui/contexts/KeypressContext.tsx b/packages/cli/src/ui/contexts/KeypressContext.tsx index df59356990..4fc774a00b 100644 --- a/packages/cli/src/ui/contexts/KeypressContext.tsx +++ b/packages/cli/src/ui/contexts/KeypressContext.tsx @@ -157,7 +157,7 @@ function bufferFastReturn(keypressHandler: KeypressHandler): KeypressHandler { if (key.name === 'return' && now - lastKeyTime <= FAST_RETURN_TIMEOUT) { keypressHandler({ ...key, - name: '', + name: 'return', sequence: '\r', insertable: true, });