diff options
| author | Daniel Young Lee <[email protected]> | 2025-05-30 19:36:52 -0700 |
|---|---|---|
| committer | N. Taylor Mullen <[email protected]> | 2025-05-30 20:51:07 -0700 |
| commit | 1468047081d330bd36e98380d6eaa8588653f78e (patch) | |
| tree | 74733230f63d9b0962a97204389cde1f6b671799 /packages/cli/src | |
| parent | 7012c86336effa2f9c4a900edf06e8b4e5cc4cbb (diff) | |
feat: Implement delayed Ctrl+C exit prompt
This change introduces a small delay after the first Ctrl+C press, prompting the user to press Ctrl+C again to exit. This helps prevent accidental termination of the application.
- Added `exitOnCtrlC={false}` to the Ink render options in `gemini.tsx` to enable custom Ctrl+C handling.
- Implemented logic in `App.tsx` to:
- Display "Press Ctrl+C again to exit." for 2 seconds after the first Ctrl+C.
- Exit the application if Ctrl+C is pressed again during this period.
- Revert to normal operation if the second Ctrl+C is not pressed within the timeout.
- Defined a constant `CTRL_C_PROMPT_DURATION_MS` for the timeout duration.
Diffstat (limited to 'packages/cli/src')
| -rw-r--r-- | packages/cli/src/gemini.tsx | 1 | ||||
| -rw-r--r-- | packages/cli/src/ui/App.tsx | 35 |
2 files changed, 35 insertions, 1 deletions
diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index e7ab6baa..0ed27a99 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -78,6 +78,7 @@ async function main() { startupWarnings={startupWarnings} /> </React.StrictMode>, + { exitOnCtrlC: false }, ); return; } diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 90426ccc..e1657984 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -44,6 +44,8 @@ import { useLogger } from './hooks/useLogger.js'; import { StreamingContext } from './contexts/StreamingContext.js'; import { useGitBranchName } from './hooks/useGitBranchName.js'; +const CTRL_C_PROMPT_DURATION_MS = 1000; + interface AppProps { config: Config; settings: LoadedSettings; @@ -77,18 +79,43 @@ export const App = ({ const [corgiMode, setCorgiMode] = useState(false); const [shellModeActive, setShellModeActive] = useState(false); const [showErrorDetails, setShowErrorDetails] = useState<boolean>(false); + const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false); + const ctrlCTimerRef = useRef<NodeJS.Timeout | null>(null); const errorCount = useMemo( () => consoleMessages.filter((msg) => msg.type === 'error').length, [consoleMessages], ); + useInput((input: string, key: InkKeyType) => { if (key.ctrl && input === 'o') { setShowErrorDetails((prev) => !prev); refreshStatic(); + } else if (key.ctrl && (input === 'c' || input === 'C')) { + if (ctrlCPressedOnce) { + if (ctrlCTimerRef.current) { + clearTimeout(ctrlCTimerRef.current); + } + process.exit(0); + } else { + setCtrlCPressedOnce(true); + ctrlCTimerRef.current = setTimeout(() => { + setCtrlCPressedOnce(false); + ctrlCTimerRef.current = null; + }, CTRL_C_PROMPT_DURATION_MS); + } } }); + useEffect( + () => () => { + if (ctrlCTimerRef.current) { + clearTimeout(ctrlCTimerRef.current); + } + }, + [], + ); + useConsolePatcher({ onNewMessage: handleNewMessage, debugMode: config.getDebugMode(), @@ -365,11 +392,17 @@ export const App = ({ {process.env.GEMINI_SYSTEM_MD && ( <Text color={Colors.AccentRed}>|⌐■_■| </Text> )} - {geminiMdFileCount > 0 && ( + {ctrlCPressedOnce ? ( + <Text color={Colors.AccentYellow}> + Press Ctrl+C again to exit. + </Text> + ) : geminiMdFileCount > 0 ? ( <Text color={Colors.SubtleComment}> Using {geminiMdFileCount} GEMINI.md file {geminiMdFileCount > 1 ? 's' : ''} </Text> + ) : ( + <Text> </Text> // Render an empty space to reserve height )} </Box> <Box> |
