diff options
| author | Lee Won Jun <[email protected]> | 2025-08-09 16:03:17 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-09 07:03:17 +0000 |
| commit | b8084ba8158b89facd49fd78a51abb80b1db54da (patch) | |
| tree | 5fd41e255b5118d53798c29d9fad95478a1ed582 /packages/cli/src/ui/App.tsx | |
| parent | 6487cc16895976ef6c983f8beca08a64addb6688 (diff) | |
Centralize Key Binding Logic and Refactor (Reopen) (#5356)
Co-authored-by: Lee-WonJun <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/App.tsx')
| -rw-r--r-- | packages/cli/src/ui/App.tsx | 107 |
1 files changed, 64 insertions, 43 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index e3c77ad0..7ee9405f 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -13,8 +13,6 @@ import { Text, useStdin, useStdout, - useInput, - type Key as InkKeyType, } from 'ink'; import { StreamingState, type HistoryItem, MessageType } from './types.js'; import { useTerminalSize } from './hooks/useTerminalSize.js'; @@ -81,6 +79,8 @@ import { useBracketedPaste } from './hooks/useBracketedPaste.js'; import { useTextBuffer } from './components/shared/text-buffer.js'; import { useVimMode, VimModeProvider } from './contexts/VimModeContext.js'; import { useVim } from './hooks/vim.js'; +import { useKeypress, Key } from './hooks/useKeypress.js'; +import { keyMatchers, Command } from './keyMatchers.js'; import * as fs from 'fs'; import { UpdateNotification } from './components/UpdateNotification.js'; import { @@ -613,50 +613,71 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => { [handleSlashCommand], ); - useInput((input: string, key: InkKeyType) => { - let enteringConstrainHeightMode = false; - if (!constrainHeight) { - // Automatically re-enter constrain height mode if the user types - // anything. When constrainHeight==false, the user will experience - // significant flickering so it is best to disable it immediately when - // the user starts interacting with the app. - enteringConstrainHeightMode = true; - setConstrainHeight(true); - } + const handleGlobalKeypress = useCallback( + (key: Key) => { + let enteringConstrainHeightMode = false; + if (!constrainHeight) { + enteringConstrainHeightMode = true; + setConstrainHeight(true); + } - if (key.ctrl && input === 'o') { - setShowErrorDetails((prev) => !prev); - } else if (key.ctrl && input === 't') { - const newValue = !showToolDescriptions; - setShowToolDescriptions(newValue); + if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) { + setShowErrorDetails((prev) => !prev); + } else if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) { + const newValue = !showToolDescriptions; + setShowToolDescriptions(newValue); - const mcpServers = config.getMcpServers(); - if (Object.keys(mcpServers || {}).length > 0) { - handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc'); - } - } else if ( - key.ctrl && - input === 'e' && - config.getIdeMode() && - ideContextState - ) { - handleSlashCommand('/ide status'); - } else if (key.ctrl && (input === 'c' || input === 'C')) { - if (isAuthenticating) { - // Let AuthInProgress component handle the input. - return; - } - handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef); - } else if (key.ctrl && (input === 'd' || input === 'D')) { - if (buffer.text.length > 0) { - // Do nothing if there is text in the input. - return; + const mcpServers = config.getMcpServers(); + if (Object.keys(mcpServers || {}).length > 0) { + handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc'); + } + } else if ( + keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) && + config.getIdeMode() && + ideContextState + ) { + // Show IDE status when in IDE mode and context is available. + handleSlashCommand('/ide status'); + } else if (keyMatchers[Command.QUIT](key)) { + // When authenticating, let AuthInProgress component handle Ctrl+C. + if (isAuthenticating) { + return; + } + handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef); + } else if (keyMatchers[Command.EXIT](key)) { + if (buffer.text.length > 0) { + return; + } + handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef); + } else if ( + keyMatchers[Command.SHOW_MORE_LINES](key) && + !enteringConstrainHeightMode + ) { + setConstrainHeight(false); } - handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef); - } else if (key.ctrl && input === 's' && !enteringConstrainHeightMode) { - setConstrainHeight(false); - } - }); + }, + [ + constrainHeight, + setConstrainHeight, + setShowErrorDetails, + showToolDescriptions, + setShowToolDescriptions, + config, + ideContextState, + handleExit, + ctrlCPressedOnce, + setCtrlCPressedOnce, + ctrlCTimerRef, + buffer.text.length, + ctrlDPressedOnce, + setCtrlDPressedOnce, + ctrlDTimerRef, + handleSlashCommand, + isAuthenticating, + ], + ); + + useKeypress(handleGlobalKeypress, { isActive: true }); useEffect(() => { if (config) { |
