summaryrefslogtreecommitdiff
path: root/src/tty
diff options
context:
space:
mode:
Diffstat (limited to 'src/tty')
-rw-r--r--src/tty/tty.zig36
1 files changed, 36 insertions, 0 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig
index ef7f2761..1d7ff415 100644
--- a/src/tty/tty.zig
+++ b/src/tty/tty.zig
@@ -1083,6 +1083,8 @@ pub fn run(init: std.process.Init, opts: pardes.Options, attach: ?[]const u8) !v
defer vx.exitAltScreen(tty.writer()) catch {};
try vx.setMouseMode(tty.writer(), true);
try vx.setBracketedPaste(tty.writer(), true);
+ Killed.arm(tty.fd.handle, tty.termios);
+ defer Killed.disarm();
if (attach != null) {
attach_end = attachSession(init, attach_name, &tty, &vx);
@@ -1119,6 +1121,40 @@ pub fn run(init: std.process.Init, opts: pardes.Options, attach: ?[]const u8) !v
}
}
+/// SIGTERM or SIGHUP: the terminal put back as a clean exit leaves it --
+/// the main screen, no mouse, paste or keyboard modes, the cursor shown,
+/// cooked termios -- and then the signal's own death. A nested editor
+/// killed in a pane must not leave that pane's terminal wedged.
+/// Async-signal-safe: write, tcsetattr, sigaction, raise.
+const Killed = struct {
+ var fd: posix.fd_t = -1;
+ var cooked: posix.termios = undefined;
+ const reset = "\x1b[<u\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1004l\x1b[?2004l\x1b[0m\x1b[?25h\x1b[?1049l";
+ const signals = [_]posix.SIG{ .TERM, .HUP };
+
+ fn arm(tty_fd: posix.fd_t, termios: posix.termios) void {
+ cooked = termios;
+ fd = tty_fd;
+ const on: posix.Sigaction = .{ .handler = .{ .handler = handle }, .mask = posix.sigemptyset(), .flags = posix.SA.RESETHAND };
+ for (signals) |sig| posix.sigaction(sig, &on, null);
+ }
+
+ fn disarm() void {
+ fd = -1;
+ const default: posix.Sigaction = .{ .handler = .{ .handler = posix.SIG.DFL }, .mask = posix.sigemptyset(), .flags = 0 };
+ for (signals) |sig| posix.sigaction(sig, &default, null);
+ }
+
+ fn handle(sig: posix.SIG) callconv(.c) void {
+ if (fd >= 0) {
+ _ = std.c.write(fd, reset, reset.len);
+ _ = std.c.tcsetattr(fd, .FLUSH, &cooked);
+ }
+ // SA_RESETHAND put the default back: the same signal, now fatal.
+ _ = std.c.raise(sig);
+ }
+};
+
fn localSession(
init: std.process.Init,
opts: pardes.Options,