diff --git a/packages/cli/src/config/keyBindings.ts b/packages/cli/src/config/keyBindings.ts index f6ba52e2..6f4a21a2 100644 --- a/packages/cli/src/config/keyBindings.ts +++ b/packages/cli/src/config/keyBindings.ts @@ -32,6 +32,8 @@ export enum Command { // Auto-completion ACCEPT_SUGGESTION = 'acceptSuggestion', + COMPLETION_UP = 'completionUp', + COMPLETION_DOWN = 'completionDown', // Text input SUBMIT = 'submit', @@ -121,6 +123,9 @@ export const defaultKeyBindings: KeyBindingConfig = { // Auto-completion // Original: key.name === 'tab' || (key.name === 'return' && !key.ctrl) [Command.ACCEPT_SUGGESTION]: [{ key: 'tab' }, { key: 'return', ctrl: false }], + // Completion navigation (arrow or Ctrl+P/N) + [Command.COMPLETION_UP]: [{ key: 'up' }, { key: 'p', ctrl: true }], + [Command.COMPLETION_DOWN]: [{ key: 'down' }, { key: 'n', ctrl: true }], // Text input // Original: key.name === 'return' && !key.ctrl && !key.meta && !key.paste @@ -157,15 +162,9 @@ export const defaultKeyBindings: KeyBindingConfig = { // Original: key.ctrl && key.name === 'e' [Command.TOGGLE_IDE_CONTEXT_DETAIL]: [{ key: 'e', ctrl: true }], // Original: key.ctrl && (key.name === 'c' || key.name === 'C') - [Command.QUIT]: [ - { key: 'c', ctrl: true }, - { key: 'C', ctrl: true }, - ], + [Command.QUIT]: [{ key: 'c', ctrl: true }], // Original: key.ctrl && (key.name === 'd' || key.name === 'D') - [Command.EXIT]: [ - { key: 'd', ctrl: true }, - { key: 'D', ctrl: true }, - ], + [Command.EXIT]: [{ key: 'd', ctrl: true }], // Original: key.ctrl && key.name === 's' [Command.SHOW_MORE_LINES]: [{ key: 's', ctrl: true }], diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 7eb1905d..f53d255f 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -373,17 +373,11 @@ export const InputPrompt: React.FC = ({ if (completion.showSuggestions) { if (completion.suggestions.length > 1) { - if ( - keyMatchers[Command.NAVIGATION_UP](key) || - keyMatchers[Command.HISTORY_UP](key) - ) { + if (keyMatchers[Command.COMPLETION_UP](key)) { completion.navigateUp(); return; } - if ( - keyMatchers[Command.NAVIGATION_DOWN](key) || - keyMatchers[Command.HISTORY_DOWN](key) - ) { + if (keyMatchers[Command.COMPLETION_DOWN](key)) { completion.navigateDown(); return; } diff --git a/packages/cli/src/ui/keyMatchers.test.ts b/packages/cli/src/ui/keyMatchers.test.ts index 16951e79..9c72f2dd 100644 --- a/packages/cli/src/ui/keyMatchers.test.ts +++ b/packages/cli/src/ui/keyMatchers.test.ts @@ -21,7 +21,8 @@ describe('keyMatchers', () => { }); // Original hard-coded logic (for comparison) - const originalMatchers = { + const originalMatchers: Record boolean> = { + [Command.RETURN]: (key: Key) => key.name === 'return', [Command.HOME]: (key: Key) => key.ctrl && key.name === 'a', [Command.END]: (key: Key) => key.ctrl && key.name === 'e', [Command.KILL_LINE_RIGHT]: (key: Key) => key.ctrl && key.name === 'k', @@ -34,6 +35,10 @@ describe('keyMatchers', () => { [Command.NAVIGATION_DOWN]: (key: Key) => key.name === 'down', [Command.ACCEPT_SUGGESTION]: (key: Key) => key.name === 'tab' || (key.name === 'return' && !key.ctrl), + [Command.COMPLETION_UP]: (key: Key) => + key.name === 'up' || (key.ctrl && key.name === 'p'), + [Command.COMPLETION_DOWN]: (key: Key) => + key.name === 'down' || (key.ctrl && key.name === 'n'), [Command.ESCAPE]: (key: Key) => key.name === 'escape', [Command.SUBMIT]: (key: Key) => key.name === 'return' && !key.ctrl && !key.meta && !key.paste, @@ -47,10 +52,8 @@ describe('keyMatchers', () => { key.ctrl && key.name === 't', [Command.TOGGLE_IDE_CONTEXT_DETAIL]: (key: Key) => key.ctrl && key.name === 'e', - [Command.QUIT]: (key: Key) => - key.ctrl && (key.name === 'c' || key.name === 'C'), - [Command.EXIT]: (key: Key) => - key.ctrl && (key.name === 'd' || key.name === 'D'), + [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.REVERSE_SEARCH]: (key: Key) => key.ctrl && key.name === 'r', [Command.SUBMIT_REVERSE_SEARCH]: (key: Key) => @@ -62,6 +65,11 @@ describe('keyMatchers', () => { // Test data for each command with positive and negative test cases const testCases = [ // Basic bindings + { + command: Command.RETURN, + positive: [createKey('return')], + negative: [createKey('r')], + }, { command: Command.ESCAPE, positive: [createKey('escape'), createKey('escape', { ctrl: true })], @@ -140,6 +148,16 @@ describe('keyMatchers', () => { positive: [createKey('tab'), createKey('return')], negative: [createKey('return', { ctrl: true }), createKey('space')], }, + { + command: Command.COMPLETION_UP, + positive: [createKey('up'), createKey('p', { ctrl: true })], + negative: [createKey('p'), createKey('down')], + }, + { + command: Command.COMPLETION_DOWN, + positive: [createKey('down'), createKey('n', { ctrl: true })], + negative: [createKey('n'), createKey('up')], + }, // Text input { @@ -194,18 +212,12 @@ describe('keyMatchers', () => { }, { command: Command.QUIT, - positive: [ - createKey('c', { ctrl: true }), - createKey('C', { ctrl: true }), - ], + positive: [createKey('c', { ctrl: true })], negative: [createKey('c'), createKey('d', { ctrl: true })], }, { command: Command.EXIT, - positive: [ - createKey('d', { ctrl: true }), - createKey('D', { ctrl: true }), - ], + positive: [createKey('d', { ctrl: true })], negative: [createKey('d'), createKey('c', { ctrl: true })], }, { @@ -321,18 +333,5 @@ describe('keyMatchers', () => { false, ); }); - - it('should handle case sensitivity', () => { - const config: KeyBindingConfig = { - ...defaultKeyBindings, - [Command.QUIT]: [{ key: 'Q', ctrl: true }], - }; - - const matchers = createKeyMatchers(config); - expect(matchers[Command.QUIT](createKey('Q', { ctrl: true }))).toBe(true); - expect(matchers[Command.QUIT](createKey('q', { ctrl: true }))).toBe( - false, - ); - }); }); });