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 {
|
||||
CURSOR_HOME,
|
||||
CURSOR_LEFT,
|
||||
cursorMove,
|
||||
cursorPosition,
|
||||
DISABLE_KITTY_KEYBOARD,
|
||||
|
|
@ -75,6 +76,7 @@ import {
|
|||
ENABLE_KITTY_KEYBOARD,
|
||||
ENABLE_MODIFY_OTHER_KEYS,
|
||||
ERASE_SCREEN,
|
||||
ERASE_TO_END_SCREEN,
|
||||
} from './termio/csi.js';
|
||||
import {
|
||||
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 */
|
||||
drainStdin(): void {
|
||||
drainStdin(this.options.stdin);
|
||||
|
|
|
|||
|
|
@ -216,6 +216,9 @@ export function eraseToEndOfScreen(): string {
|
|||
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) */
|
||||
export function eraseToStartOfScreen(): string {
|
||||
return csi(1, 'J')
|
||||
|
|
|
|||
|
|
@ -65,23 +65,23 @@ function cleanupTerminalModes(): void {
|
|||
// we're busy unmounting. Otherwise events arrive during cooked-mode
|
||||
// cleanup and either echo to the screen or leak to the shell.
|
||||
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)
|
||||
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 {
|
||||
inst.unmount()
|
||||
} catch {
|
||||
|
|
@ -89,6 +89,8 @@ function cleanupTerminalModes(): void {
|
|||
// so printResumeHint still hits the main buffer.
|
||||
writeSync(1, EXIT_ALT_SCREEN)
|
||||
}
|
||||
} else if (inst) {
|
||||
inst.clearMainScreenForShutdown()
|
||||
}
|
||||
// Catches events that arrived during the unmount tree-walk.
|
||||
// detachForShutdown() below also drains.
|
||||
|
|
@ -169,9 +171,7 @@ function printResumeHint(): void {
|
|||
|
||||
writeSync(
|
||||
1,
|
||||
chalk.dim(
|
||||
`\nResume this session with:\ncsc --resume ${resumeArg}\n`,
|
||||
),
|
||||
chalk.dim(`\nResume this session with:\ncsc --resume ${resumeArg}\n`),
|
||||
)
|
||||
resumeHintPrinted = true
|
||||
} catch {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user