180 lines
5.7 KiB
TypeScript
180 lines
5.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* Command enum for all available keyboard shortcuts
|
|
*/
|
|
export enum Command {
|
|
// Basic bindings
|
|
RETURN = 'return',
|
|
ESCAPE = 'escape',
|
|
|
|
// Cursor movement
|
|
HOME = 'home',
|
|
END = 'end',
|
|
|
|
// Text deletion
|
|
KILL_LINE_RIGHT = 'killLineRight',
|
|
KILL_LINE_LEFT = 'killLineLeft',
|
|
CLEAR_INPUT = 'clearInput',
|
|
|
|
// Screen control
|
|
CLEAR_SCREEN = 'clearScreen',
|
|
|
|
// History navigation
|
|
HISTORY_UP = 'historyUp',
|
|
HISTORY_DOWN = 'historyDown',
|
|
NAVIGATION_UP = 'navigationUp',
|
|
NAVIGATION_DOWN = 'navigationDown',
|
|
|
|
// Auto-completion
|
|
ACCEPT_SUGGESTION = 'acceptSuggestion',
|
|
COMPLETION_UP = 'completionUp',
|
|
COMPLETION_DOWN = 'completionDown',
|
|
|
|
// Text input
|
|
SUBMIT = 'submit',
|
|
NEWLINE = 'newline',
|
|
|
|
// External tools
|
|
OPEN_EXTERNAL_EDITOR = 'openExternalEditor',
|
|
PASTE_CLIPBOARD_IMAGE = 'pasteClipboardImage',
|
|
|
|
// App level bindings
|
|
SHOW_ERROR_DETAILS = 'showErrorDetails',
|
|
TOGGLE_TOOL_DESCRIPTIONS = 'toggleToolDescriptions',
|
|
TOGGLE_IDE_CONTEXT_DETAIL = 'toggleIDEContextDetail',
|
|
QUIT = 'quit',
|
|
EXIT = 'exit',
|
|
SHOW_MORE_LINES = 'showMoreLines',
|
|
|
|
// Shell commands
|
|
REVERSE_SEARCH = 'reverseSearch',
|
|
SUBMIT_REVERSE_SEARCH = 'submitReverseSearch',
|
|
ACCEPT_SUGGESTION_REVERSE_SEARCH = 'acceptSuggestionReverseSearch',
|
|
}
|
|
|
|
/**
|
|
* Data-driven key binding structure for user configuration
|
|
*/
|
|
export interface KeyBinding {
|
|
/** The key name (e.g., 'a', 'return', 'tab', 'escape') */
|
|
key?: string;
|
|
/** The key sequence (e.g., '\x18' for Ctrl+X) - alternative to key name */
|
|
sequence?: string;
|
|
/** Control key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */
|
|
ctrl?: boolean;
|
|
/** Shift key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */
|
|
shift?: boolean;
|
|
/** Command/meta key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */
|
|
command?: boolean;
|
|
/** Paste operation requirement: true=must be paste, false=must not be paste, undefined=ignore */
|
|
paste?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Configuration type mapping commands to their key bindings
|
|
*/
|
|
export type KeyBindingConfig = {
|
|
readonly [C in Command]: readonly KeyBinding[];
|
|
};
|
|
|
|
/**
|
|
* Default key binding configuration
|
|
* Matches the original hard-coded logic exactly
|
|
*/
|
|
export const defaultKeyBindings: KeyBindingConfig = {
|
|
// Basic bindings
|
|
[Command.RETURN]: [{ key: 'return' }],
|
|
// Original: key.name === 'escape'
|
|
[Command.ESCAPE]: [{ key: 'escape' }],
|
|
|
|
// Cursor movement
|
|
// Original: key.ctrl && key.name === 'a'
|
|
[Command.HOME]: [{ key: 'a', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 'e'
|
|
[Command.END]: [{ key: 'e', ctrl: true }],
|
|
|
|
// Text deletion
|
|
// Original: key.ctrl && key.name === 'k'
|
|
[Command.KILL_LINE_RIGHT]: [{ key: 'k', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 'u'
|
|
[Command.KILL_LINE_LEFT]: [{ key: 'u', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 'c'
|
|
[Command.CLEAR_INPUT]: [{ key: 'c', ctrl: true }],
|
|
|
|
// Screen control
|
|
// Original: key.ctrl && key.name === 'l'
|
|
[Command.CLEAR_SCREEN]: [{ key: 'l', ctrl: true }],
|
|
|
|
// History navigation
|
|
// Original: key.ctrl && key.name === 'p'
|
|
[Command.HISTORY_UP]: [{ key: 'p', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 'n'
|
|
[Command.HISTORY_DOWN]: [{ key: 'n', ctrl: true }],
|
|
// Original: key.name === 'up'
|
|
[Command.NAVIGATION_UP]: [{ key: 'up' }],
|
|
// Original: key.name === 'down'
|
|
[Command.NAVIGATION_DOWN]: [{ key: 'down' }],
|
|
|
|
// 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
|
|
[Command.SUBMIT]: [
|
|
{
|
|
key: 'return',
|
|
ctrl: false,
|
|
command: false,
|
|
paste: false,
|
|
},
|
|
],
|
|
// Original: key.name === 'return' && (key.ctrl || key.meta || key.paste)
|
|
// Split into multiple data-driven bindings
|
|
[Command.NEWLINE]: [
|
|
{ key: 'return', ctrl: true },
|
|
{ key: 'return', command: true },
|
|
{ key: 'return', paste: true },
|
|
],
|
|
|
|
// External tools
|
|
// Original: key.ctrl && (key.name === 'x' || key.sequence === '\x18')
|
|
[Command.OPEN_EXTERNAL_EDITOR]: [
|
|
{ key: 'x', ctrl: true },
|
|
{ sequence: '\x18', ctrl: true },
|
|
],
|
|
// Original: key.ctrl && key.name === 'v'
|
|
[Command.PASTE_CLIPBOARD_IMAGE]: [{ key: 'v', ctrl: true }],
|
|
|
|
// App level bindings
|
|
// Original: key.ctrl && key.name === 'o'
|
|
[Command.SHOW_ERROR_DETAILS]: [{ key: 'o', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 't'
|
|
[Command.TOGGLE_TOOL_DESCRIPTIONS]: [{ key: 't', ctrl: true }],
|
|
// 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 }],
|
|
// Original: key.ctrl && (key.name === 'd' || key.name === 'D')
|
|
[Command.EXIT]: [{ key: 'd', ctrl: true }],
|
|
// Original: key.ctrl && key.name === 's'
|
|
[Command.SHOW_MORE_LINES]: [{ key: 's', ctrl: true }],
|
|
|
|
// Shell commands
|
|
// Original: key.ctrl && key.name === 'r'
|
|
[Command.REVERSE_SEARCH]: [{ key: 'r', ctrl: true }],
|
|
// Original: key.name === 'return' && !key.ctrl
|
|
// Note: original logic ONLY checked ctrl=false, ignored meta/shift/paste
|
|
[Command.SUBMIT_REVERSE_SEARCH]: [{ key: 'return', ctrl: false }],
|
|
// Original: key.name === 'tab'
|
|
[Command.ACCEPT_SUGGESTION_REVERSE_SEARCH]: [{ key: 'tab' }],
|
|
};
|