Merge pull request #115 from IronRookieCoder/fix-exit-terminal-state
Fix exit terminal state
This commit is contained in:
commit
d042115b6a
|
|
@ -68,6 +68,7 @@ import {
|
||||||
import { SYNC_OUTPUT_SUPPORTED, supportsExtendedKeys, type Terminal, writeDiffToTerminal } from './terminal.js';
|
import { SYNC_OUTPUT_SUPPORTED, supportsExtendedKeys, type Terminal, writeDiffToTerminal } from './terminal.js';
|
||||||
import {
|
import {
|
||||||
CURSOR_HOME,
|
CURSOR_HOME,
|
||||||
|
CURSOR_LEFT,
|
||||||
cursorMove,
|
cursorMove,
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
DISABLE_KITTY_KEYBOARD,
|
DISABLE_KITTY_KEYBOARD,
|
||||||
|
|
@ -75,6 +76,7 @@ import {
|
||||||
ENABLE_KITTY_KEYBOARD,
|
ENABLE_KITTY_KEYBOARD,
|
||||||
ENABLE_MODIFY_OTHER_KEYS,
|
ENABLE_MODIFY_OTHER_KEYS,
|
||||||
ERASE_SCREEN,
|
ERASE_SCREEN,
|
||||||
|
ERASE_TO_END_SCREEN,
|
||||||
} from './termio/csi.js';
|
} from './termio/csi.js';
|
||||||
import {
|
import {
|
||||||
DBP,
|
DBP,
|
||||||
|
|
@ -1054,6 +1056,20 @@ export default class Ink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the visible main-screen region currently owned by Ink.
|
||||||
|
* Used by graceful shutdown for interactive REPL exits, where transient UI
|
||||||
|
* should not remain underneath the shell prompt.
|
||||||
|
*/
|
||||||
|
clearMainScreenForShutdown(): void {
|
||||||
|
if (!this.options.stdout.isTTY || this.altScreenActive) return;
|
||||||
|
|
||||||
|
const cursor = this.displayCursor ?? this.frontFrame.cursor;
|
||||||
|
const topOffset = Math.min(Math.max(cursor.y, 0), Math.max(this.frontFrame.viewport.height - 1, 0));
|
||||||
|
const clearFromTop = cursorMove(0, -topOffset) + CURSOR_LEFT + ERASE_TO_END_SCREEN;
|
||||||
|
writeSync(1, clearFromTop);
|
||||||
|
}
|
||||||
|
|
||||||
/** @see drainStdin */
|
/** @see drainStdin */
|
||||||
drainStdin(): void {
|
drainStdin(): void {
|
||||||
drainStdin(this.options.stdin);
|
drainStdin(this.options.stdin);
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,9 @@ export function eraseToEndOfScreen(): string {
|
||||||
return csi('J')
|
return csi('J')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Erase from cursor to end of screen - constant form */
|
||||||
|
export const ERASE_TO_END_SCREEN = csi('J')
|
||||||
|
|
||||||
/** Erase from cursor to start of screen (CSI 1 J) */
|
/** Erase from cursor to start of screen (CSI 1 J) */
|
||||||
export function eraseToStartOfScreen(): string {
|
export function eraseToStartOfScreen(): string {
|
||||||
return csi(1, 'J')
|
return csi(1, 'J')
|
||||||
|
|
|
||||||
|
|
@ -65,23 +65,23 @@ function cleanupTerminalModes(): void {
|
||||||
// we're busy unmounting. Otherwise events arrive during cooked-mode
|
// we're busy unmounting. Otherwise events arrive during cooked-mode
|
||||||
// cleanup and either echo to the screen or leak to the shell.
|
// cleanup and either echo to the screen or leak to the shell.
|
||||||
writeSync(1, DISABLE_MOUSE_TRACKING)
|
writeSync(1, DISABLE_MOUSE_TRACKING)
|
||||||
// Exit alt screen FIRST so printResumeHint() (and all sequences below)
|
|
||||||
// land on the main buffer.
|
|
||||||
//
|
|
||||||
// Unmount Ink directly rather than writing EXIT_ALT_SCREEN ourselves.
|
|
||||||
// Ink registered its unmount with signal-exit, so it will otherwise run
|
|
||||||
// AGAIN inside forceExit() → process.exit(). Two problems with letting
|
|
||||||
// that happen:
|
|
||||||
// 1. If we write 1049l here and unmount writes it again later, the
|
|
||||||
// second one triggers another DECRC — the cursor jumps back over
|
|
||||||
// the resume hint and the shell prompt lands on the wrong line.
|
|
||||||
// 2. unmount()'s onRender() must run with altScreenActive=true (alt-
|
|
||||||
// screen cursor math) AND on the alt buffer. Exiting alt-screen
|
|
||||||
// here first makes onRender() scribble a REPL frame onto main.
|
|
||||||
// Calling unmount() now does the final render on the alt buffer,
|
|
||||||
// unsubscribes from signal-exit, and writes 1049l exactly once.
|
|
||||||
const inst = instances.get(process.stdout)
|
const inst = instances.get(process.stdout)
|
||||||
if (inst?.isAltScreenActive) {
|
if (inst?.isAltScreenActive) {
|
||||||
|
// Exit alt screen FIRST so printResumeHint() (and all sequences below)
|
||||||
|
// land on the main buffer.
|
||||||
|
//
|
||||||
|
// Unmount Ink directly rather than writing EXIT_ALT_SCREEN ourselves.
|
||||||
|
// Ink registered its unmount with signal-exit, so it will otherwise run
|
||||||
|
// AGAIN inside forceExit() -> process.exit(). Two problems with letting
|
||||||
|
// that happen:
|
||||||
|
// 1. If we write 1049l here and unmount writes it again later, the
|
||||||
|
// second one triggers another DECRC — the cursor jumps back over
|
||||||
|
// the resume hint and the shell prompt lands on the wrong line.
|
||||||
|
// 2. unmount()'s onRender() must run with altScreenActive=true (alt-
|
||||||
|
// screen cursor math) AND on the alt buffer. Exiting alt-screen
|
||||||
|
// here first makes onRender() scribble a REPL frame onto main.
|
||||||
|
// Calling unmount() now does the final render on the alt buffer,
|
||||||
|
// unsubscribes from signal-exit, and writes 1049l exactly once.
|
||||||
try {
|
try {
|
||||||
inst.unmount()
|
inst.unmount()
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -89,6 +89,8 @@ function cleanupTerminalModes(): void {
|
||||||
// so printResumeHint still hits the main buffer.
|
// so printResumeHint still hits the main buffer.
|
||||||
writeSync(1, EXIT_ALT_SCREEN)
|
writeSync(1, EXIT_ALT_SCREEN)
|
||||||
}
|
}
|
||||||
|
} else if (inst) {
|
||||||
|
inst.clearMainScreenForShutdown()
|
||||||
}
|
}
|
||||||
// Catches events that arrived during the unmount tree-walk.
|
// Catches events that arrived during the unmount tree-walk.
|
||||||
// detachForShutdown() below also drains.
|
// detachForShutdown() below also drains.
|
||||||
|
|
@ -169,9 +171,7 @@ function printResumeHint(): void {
|
||||||
|
|
||||||
writeSync(
|
writeSync(
|
||||||
1,
|
1,
|
||||||
chalk.dim(
|
chalk.dim(`\nResume this session with:\ncsc --resume ${resumeArg}\n`),
|
||||||
`\nResume this session with:\ncsc --resume ${resumeArg}\n`,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
resumeHintPrinted = true
|
resumeHintPrinted = true
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user