fix: prevent escape character from being inserted into input

Strip escape characters in PasteAwareTextInput handleChange to prevent
them from being inserted by ink-text-input. This was causing the
'Press Esc again to clear' hint to flicker and disappear immediately
because the value change triggered the useEffect that resets escapePressed.

Also extracted the double-escape window duration to a constant (2.5s).

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>
This commit is contained in:
cpacker
2025-12-15 18:10:23 -08:00
parent cbfc7d4eee
commit 693ae8b4e0
2 changed files with 20 additions and 2 deletions

View File

@@ -20,6 +20,8 @@ const appVersion = getVersion();
// Only show token count when it exceeds this threshold
const COUNTER_VISIBLE_THRESHOLD = 1000;
// Window for double-escape to clear input
const ESC_CLEAR_WINDOW_MS = 2500;
export function Input({
visible = true,
@@ -164,12 +166,12 @@ export function Input({
setEscapePressed(false);
if (escapeTimerRef.current) clearTimeout(escapeTimerRef.current);
} else {
// First escape - start 1-second timer
// First escape - start timer to allow double-escape to clear
setEscapePressed(true);
if (escapeTimerRef.current) clearTimeout(escapeTimerRef.current);
escapeTimerRef.current = setTimeout(() => {
setEscapePressed(false);
}, 1000);
}, ESC_CLEAR_WINDOW_MS);
}
}
}

View File

@@ -333,6 +333,22 @@ export function PasteAwareTextInput({
}, [internal_eventEmitter]);
const handleChange = (newValue: string) => {
// Drop lone escape characters that Ink's text input would otherwise insert;
// they are used as control keys for double-escape handling and should not
// mutate the input value.
const sanitizedValue = newValue.replaceAll("\u001b", "");
if (sanitizedValue !== newValue) {
// Keep caret in bounds after stripping control chars
const nextCaret = Math.min(caretOffsetRef.current, sanitizedValue.length);
setNudgeCursorOffset(nextCaret);
caretOffsetRef.current = nextCaret;
newValue = sanitizedValue;
// If nothing actually changed after stripping, bail out early
if (sanitizedValue === displayValue) {
return;
}
}
// Heuristic: detect large additions that look like pastes
const addedLen = newValue.length - displayValue.length;
const lineDelta = countLines(newValue) - countLines(displayValue);