From bca5d6a52500e72ec4de69c38f6fb2324df4b503 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 6 Jul 2026 12:45:47 -0300 Subject: tty shell: leave the terminal clean on every exit path. Root causes: vaxis.Tty.init makes the tty raw but run() never called tty.deinit (termios stayed raw -> no echo, staircased output in the spawner shell); the pty reader tasks were never joined (Kill-quit hung the exit in the runtime thread-join with readers blocked in read(2), and finished readers dumped DebugAllocator leak traces onto the tty). Fix: defer tty.deinit() (runs last, after vx.deinit flushes its resets); cancel each pty reader at teardown (cancel interrupts the blocked read) then close masters and drain the loop queue (queued pty_read/paste bytes are gpa-owned); await the reader on pty_eof before closing; readPty posts its eof via tryPostEvent so a post-cancel full queue can't re-block; root panic handler wraps vaxis.recover() so a panic restores cooked mode/main screen/mouse before the trace prints (vaxis.Panic itself is stale: references std.debug.FormattedPanic which 0.16 dropped). Verified with a scripted pty harness (bash spawner, DSR replies): both quit paths (exit-EOF of last pane, middle-click Kill) end with rmcup+cursor+sgr+mouse-off and identical stty -a before/after, no leak spew, prompt back in 0.5s; snap suite 18/18. --- src/main.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index ff151323..9a8cd6da 100644 --- a/src/main.zig +++ b/src/main.zig @@ -18,6 +18,16 @@ pub const std_options_debug_io: std.Io = if (is_emscripten) else std_options_debug_threaded_io.?.io(); +// A panic must restore the terminal (cooked mode, main screen, mouse off) +// before the trace prints, or it lands garbled in a raw alt screen. recover() +// no-ops unless the vaxis tty is live, so gui/tty share the handler. +pub const panic = if (is_emscripten) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.FullPanic(struct { + fn call(msg: []const u8, ret_addr: ?usize) noreturn { + @import("vaxis").recover(); + std.debug.defaultPanic(msg, ret_addr); + } +}.call); + const help_text = \\Usage: pardes [options] \\ -- cgit v1.3