fix(tui): make Esc clear line and cancel hidden prompts in minimal mode

This commit is contained in:
William Valentin
2026-02-16 11:38:22 -08:00
parent a5e8d6c216
commit b7a9fc1d35
+69 -3
View File
@@ -163,8 +163,18 @@ export class MinimalTui {
// Listen for line changes to show hints
this.keypressHandler = (char: string, key: readline.Key) => {
if (this.activePromptCancel && this.isEscapeKey(char, key)) {
this.activePromptCancel();
if (this.isEscapeKey(char, key)) {
if (this.activePromptCancel) {
this.activePromptCancel();
return;
}
if (this.rl) {
try {
this.rl.write(null, { ctrl: true, name: 'u' });
} catch {
// ignore
}
}
return;
}
@@ -520,6 +530,30 @@ export class MinimalTui {
stdoutMuted?: boolean;
_writeToOutput?: (s: string) => void;
};
const stdin = process.stdin as NodeJS.ReadStream & {
isRaw?: boolean;
setRawMode?: (mode: boolean) => void;
};
const wasRaw = Boolean(stdin.isRaw);
let enabledRawForPrompt = false;
let dataListener: ((chunk: Buffer) => void) | null = null;
let settled = false;
if (stdin.isTTY && stdin.setRawMode && !wasRaw) {
stdin.setRawMode(true);
enabledRawForPrompt = true;
}
const cleanup = () => {
if (dataListener) {
stdin.removeListener('data', dataListener);
dataListener = null;
}
if (enabledRawForPrompt && stdin.setRawMode) {
stdin.setRawMode(false);
}
};
rlAny.stdoutMuted = true;
rlAny._writeToOutput = (s: string) => {
if (!rlAny.stdoutMuted) {
@@ -532,8 +566,40 @@ export class MinimalTui {
process.stdout.write('*');
}
};
const answer = await new Promise<string>((resolve) => rl.question(question, resolve));
const answer = await new Promise<string>((resolve) => {
dataListener = (chunk: Buffer) => {
if (settled) {
return;
}
if (chunk.length === 1 && chunk[0] === 0x1b) {
settled = true;
rl.close();
resolve('');
}
};
stdin.on('data', dataListener);
const onClose = () => {
if (settled) {
return;
}
settled = true;
resolve('');
};
if (typeof rl.once === 'function') {
rl.once('close', onClose);
}
rl.question(question, (value) => {
if (settled) {
return;
}
settled = true;
resolve(value);
});
});
rlAny.stdoutMuted = false;
cleanup();
rl.close();
process.stdout.write('\n');
return answer.trim();