diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 02:47:36 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 02:47:36 -0300 |
| commit | bc4987d2294c9b9cf641b0f9686392611682cc0e (patch) | |
| tree | f22e62fda916d30e0478930387461b6b8b83f1e6 /src | |
| parent | 43b75a3c79e204b758df8d361c213364dc4fe064 (diff) | |
| download | pardes-bc4987d2294c9b9cf641b0f9686392611682cc0e.tar.gz pardes-bc4987d2294c9b9cf641b0f9686392611682cc0e.zip | |
pty/run after a clear answers what the command printed from the clear on, whole; cut only when its start really scrolled away
A clear (ED 2, ED 3, a reset) under a running command marked its output
lost, so `clear; ls` answered only "exit 0 cut". The output's start is
now pinned again at the screen's top after the erase: what the command
prints from there is its answer, whole, and a cut is said only when
that start leaves the scrollback.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ninep/pty.zig | 7 | ||||
| -rw-r--r-- | src/terminal.zig | 28 |
2 files changed, 29 insertions, 6 deletions
diff --git a/src/ninep/pty.zig b/src/ninep/pty.zig index 2245255b..fc8eb570 100644 --- a/src/ninep/pty.zig +++ b/src/ninep/pty.zig @@ -971,13 +971,12 @@ test "a run's answer says cut when its output's start is gone, and reads a bound defer gpa.free(into); sh.put(p, prompt); - // `clear` while it runs erases what it printed before, and the pins then - // span rows that no longer hold it (ED 3 even moves one to the next page - // without calling it garbage), so only the erase itself tells. + // `clear` while it runs: what it printed after is its output, whole; + // what the clear erased was meant to go. var h = sh.send(p, node); sh.put(p, c ++ "before\r\n\x1b[H\x1b[2J\x1b[3Jafter\r\n" ++ d ++ prompt); var got = sh.answered(p, node, h, into); - try testing.expect(std.mem.startsWith(u8, got, "exit 0 cut\n")); + try testing.expectEqualStrings("exit 0\nafter\n", got); // A resize between its start and end reflows the pins with the text. diff --git a/src/terminal.zig b/src/terminal.zig index 0850267e..a0337ce7 100644 --- a/src/terminal.zig +++ b/src/terminal.zig @@ -106,12 +106,36 @@ pub const MarkedHandler = if (enabled) struct { else => {}, } } - if (comptime action == .erase_display_complete or action == .erase_display_scrollback or action == .full_reset) { - if (self.phase == .running) self.lost = true; + if (comptime action == .erase_display_complete or action == .erase_display_scrollback or + action == .erase_display_scroll_complete or action == .full_reset) + { + self.inner.vt(action, value); + // A `clear` under a running command: its output is what it + // prints from here, the screen's top, not lost. Only what the + // scrollback later loses is (the pin goes `garbage`). + if (self.phase == .running) self.pinTop(&self.out_start); + return; } self.inner.vt(action, value); } + /// Pins `slot` to the primary screen's top-left; lost when it cannot be. + fn pinTop(self: *@This(), slot: *?*ghostty_vt.Pin) void { + const screen = self.inner.terminal.screens.get(.primary) orelse return; + if (slot.*) |old| screen.pages.untrackPin(old); + slot.* = null; + if (self.inner.terminal.screens.active_key != .primary) { + self.lost = true; + return; + } + const top = screen.pages.pin(.{ .active = .{} }) orelse { + self.lost = true; + return; + }; + slot.* = screen.pages.trackPin(top) catch null; + if (slot.* == null) self.lost = true; + } + pub fn deinit(self: *@This()) void { self.inner.deinit(); } |
