mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 20:20:57 +00:00
Merge pull request #1824 from QwenLM/mingholy/fix/esc-interrupt
refactor(cli): unify Escape key handling in AppContainer
This commit is contained in:
commit
ffa2d89ecd
3 changed files with 74 additions and 51 deletions
|
|
@ -692,7 +692,6 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
terminalWidth,
|
||||
terminalHeight,
|
||||
handleVisionSwitchRequired, // onVisionSwitchRequired
|
||||
embeddedShellFocused,
|
||||
);
|
||||
|
||||
// Track whether suggestions are visible for Tab key handling
|
||||
|
|
@ -900,6 +899,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
const ctrlCTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
|
||||
const ctrlDTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [escapePressedOnce, setEscapePressedOnce] = useState(false);
|
||||
const escapeTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [constrainHeight, setConstrainHeight] = useState<boolean>(true);
|
||||
const [ideContextState, setIdeContextState] = useState<
|
||||
IdeContext | undefined
|
||||
|
|
@ -1176,6 +1177,47 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
}
|
||||
handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef);
|
||||
return;
|
||||
} else if (keyMatchers[Command.ESCAPE](key)) {
|
||||
// Escape key handling
|
||||
// Skip if shell is focused (to allow shell's own escape handling)
|
||||
if (embeddedShellFocused) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If input has content, use double-press to clear
|
||||
if (buffer.text.length > 0) {
|
||||
if (escapePressedOnce) {
|
||||
// Second press: clear input, keep the flag to allow immediate cancel
|
||||
buffer.setText('');
|
||||
return;
|
||||
}
|
||||
// First press: set flag and show prompt
|
||||
setEscapePressedOnce(true);
|
||||
escapeTimerRef.current = setTimeout(() => {
|
||||
setEscapePressedOnce(false);
|
||||
escapeTimerRef.current = null;
|
||||
}, CTRL_EXIT_PROMPT_DURATION_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Input is empty, cancel request immediately (no double-press needed)
|
||||
if (streamingState === StreamingState.Responding) {
|
||||
if (escapeTimerRef.current) {
|
||||
clearTimeout(escapeTimerRef.current);
|
||||
escapeTimerRef.current = null;
|
||||
}
|
||||
cancelOngoingRequest?.();
|
||||
setEscapePressedOnce(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// No action available, reset the flag
|
||||
if (escapeTimerRef.current) {
|
||||
clearTimeout(escapeTimerRef.current);
|
||||
escapeTimerRef.current = null;
|
||||
}
|
||||
setEscapePressedOnce(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let enteringConstrainHeightMode = false;
|
||||
|
|
@ -1220,10 +1262,15 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
ctrlCPressedOnce,
|
||||
setCtrlCPressedOnce,
|
||||
ctrlCTimerRef,
|
||||
buffer.text.length,
|
||||
ctrlDPressedOnce,
|
||||
setCtrlDPressedOnce,
|
||||
ctrlDTimerRef,
|
||||
escapePressedOnce,
|
||||
setEscapePressedOnce,
|
||||
escapeTimerRef,
|
||||
streamingState,
|
||||
cancelOngoingRequest,
|
||||
buffer,
|
||||
handleSlashCommand,
|
||||
activePtyId,
|
||||
embeddedShellFocused,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue