- commit
- a061876
- parent
- 543b45c
- author
- Eric Bower
- date
- 2025-12-29 15:28:18 -0500 EST
fix: prevent terminal state corruption on detach When zmx sessions are nested through SSH (host zmx -> ssh -> remote zmx), the detach restore sequence was corrupting the outer session's terminal state tracking in ghostty-vt. The issue: when the remote zmx client detached, it sent clear screen and home cursor sequences (\x1b[2J\x1b[H) which flowed through SSH to the host's PTY. This caused the host's ghostty-vt to update its cursor position, and since nothing followed to correct it, subsequent reattaches to the host session would restore with incorrect cursor positioning. The fix: remove clear screen and home cursor from the detach sequence. We still reset terminal modes (mouse tracking, bracketed paste, alt screen, etc.) to ensure the terminal is left in a sane state. Trade-offs: - On detach, users now see the session content instead of a cleared screen. This is arguably useful feedback showing what was happening. - Nested zmx through SSH may still have cursor positioning issues since the restore's CUP sequence also flows through to the outer session. This is accepted as an edge case we cannot fully solve without breaking normal operation. - The attach clear is kept because it provides a clean slate and any corruption it causes is immediately overwritten by the session restore. Design principle: be conservative about terminal escape sequences sent on detach since they persist and affect the outer terminal's state. The session restore handles reconstruction, so we don't need to "clean up" on the way out. References: https://github.com/neurosnap/zmx/issues/31
1 files changed,
+6,
-3
+6,
-3
1@@ -695,10 +695,12 @@ fn attach(daemon: *Daemon) !void {
2 // Reset terminal modes on detach:
3 // - Mouse: 1000=basic, 1002=button-event, 1003=any-event, 1006=SGR extended
4 // - 2004=bracketed paste, 1004=focus events, 1049=alt screen
5- // - 25h=show cursor, 2J=clear screen, H=cursor home
6+ // - 25h=show cursor
7+ // NOTE: We intentionally do NOT clear screen or home cursor here because we dont
8+ // want to corrupt any programs that rely on it including ghostty's session restore.
9 const restore_seq = "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l" ++
10 "\x1b[?2004l\x1b[?1004l\x1b[?1049l" ++
11- "\x1b[?25h\x1b[2J\x1b[H";
12+ "\x1b[?25h";
13 _ = posix.write(posix.STDOUT_FILENO, restore_seq) catch {};
14 }
15
16@@ -718,7 +720,8 @@ fn attach(daemon: *Daemon) !void {
17
18 _ = c.tcsetattr(posix.STDIN_FILENO, c.TCSANOW, &raw_termios);
19
20- // Clear screen and move cursor to home before attaching
21+ // Clear screen before attaching. This provides a clean slate before
22+ // the session restore.
23 const clear_seq = "\x1b[2J\x1b[H";
24 _ = try posix.write(posix.STDOUT_FILENO, clear_seq);
25