diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 13:48:53 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 0fb5881520884691c395ef1ce4b9d1d902434bd6 (patch) | |
| tree | 4ec25459314b0b2f3249380d4c122611098661dd /src | |
| parent | 65a4c17767f175ce16cbbce5520a86926d61692d (diff) | |
| download | pardes-0fb5881520884691c395ef1ce4b9d1d902434bd6.tar.gz pardes-0fb5881520884691c395ef1ce4b9d1d902434bd6.zip | |
A run whose output a redraw moved above its start answers cut, never an empty whole
pty/run reads a command's output between its C and D marks. When the
end landed at or before the start, it answered `exit 0` with no output,
as if nothing was printed. That happens when the shell redraws its prompt
over the output, as it can in a window two rows high (winsize 10 2). Now
only equal marks mean nothing was printed. An end at the top-left cell
or above the start says `cut`, since how much was printed is not known.
bash, fish, long lines and 3000-line outputs at winsize 10 2 all came
back whole on this build, so the dogfood's loss could not be reproduced
directly. The test drives the marks into the inverted case the loss
needs.
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 | 9 |
2 files changed, 14 insertions, 2 deletions
diff --git a/src/ninep/pty.zig b/src/ninep/pty.zig index 0f5202cc..390ae58d 100644 --- a/src/ninep/pty.zig +++ b/src/ninep/pty.zig @@ -960,6 +960,7 @@ test "a run's answer says cut when its output's start is gone, and reads a bound var got = sh.answered(p, node, h, into); try testing.expect(std.mem.startsWith(u8, got, "exit 0 cut\n")); + // A resize between its start and end reflows the pins with the text. h = sh.send(p, node); sh.put(p, c ++ "one\r\ntwo\r\n"); @@ -1022,6 +1023,12 @@ test "a run's answer says cut when its output's start is gone, and reads a bound sh.put(p, d ++ prompt); p.gpa = gpa; try testing.expectEqualStrings("error out of memory\n", sh.answered(p, node, h, into)); + // An end drawn above the start (the prompt redrawn over what was + // printed, as in a window two rows high): cut, never an empty whole. + h = sh.send(p, node); + sh.put(p, c ++ "printed\r\nmore\r\n\x1b[4A" ++ d ++ prompt); + got = sh.answered(p, node, h, into); + try testing.expect(std.mem.startsWith(u8, got, "exit 0 cut\n")); } test "a terminal's ctl counts its body, and a new directory is a rename in the log" { diff --git a/src/terminal.zig b/src/terminal.zig index 1a3b6a21..4cac6f1d 100644 --- a/src/terminal.zig +++ b/src/terminal.zig @@ -1044,9 +1044,14 @@ pub fn commandOutput(pane: *Pane, gpa: std.mem.Allocator, max_rows: usize) !Comm const screen = state.vt.screens.get(.primary) orelse break :printed false; if (end.garbage) break :printed false; var whole = !marks.lost and !start.garbage; + // Nothing printed: the whole of it. + if (start.eql(end.*)) break :printed whole; // D is where the next prompt begins: the output ends a cell before. - const last = end.leftWrap(1) orelse break :printed whole; - if (start.eql(end.*) or last.before(start.*)) break :printed whole; + // An end at the very top, or before the start, is output a redraw + // moved (a prompt drawn over it in a window two rows high): how + // much is not known, so it is not called whole. + const last = end.leftWrap(1) orelse break :printed false; + if (last.before(start.*)) break :printed false; var from = start.*; if (last.up(max_rows)) |floor| if (from.before(floor)) { from = floor; |
