summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 00:45:33 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commite563be42a5b3e9243e2c01d34cf8e94d2047b753 (patch)
treed71c8265c353f41cdb49b20f3a7e4d6e8d9baab2 /src/ninep
parent0fe78621cc0db8b835ebcb7c51bbd2d20d6dbcc2 (diff)
downloadpardes-e563be42a5b3e9243e2c01d34cf8e94d2047b753.tar.gz
pardes-e563be42a5b3e9243e2c01d34cf8e94d2047b753.zip
A terminal's body reads as logical lines, the last one ending in a newline
A terminal's body came back as the screen's rows, a long line cut where the terminal wrapped it and the last line with no newline. The body (and a terminal's Save, and the length its ctl reports) now joins wrapped rows by ghostty's wrap flags, as pty/run's output does, and ends the last line with a newline. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/screen.zig22
1 files changed, 18 insertions, 4 deletions
diff --git a/src/ninep/screen.zig b/src/ninep/screen.zig
index 462ea40f..f496da03 100644
--- a/src/ninep/screen.zig
+++ b/src/ninep/screen.zig
@@ -146,7 +146,7 @@ test "terminal body handles keep one history snapshot across fragmented reads" {
try testing.expectEqualStrings("", call(p, .{ .tag = 4, .op = .read, .node = node, .handle = opened.reply.handle, .off = original.len, .size = 3 }).bytes);
_ = call(p, .{ .tag = 5, .op = .release, .node = node, .handle = opened.reply.handle });
const newer = call(p, .{ .tag = 6, .op = .open, .node = node });
- try testing.expectEqualStrings("new output", call(p, .{ .tag = 7, .op = .read, .node = node, .handle = newer.reply.handle, .size = 32 }).bytes);
+ try testing.expectEqualStrings("new output\n", call(p, .{ .tag = 7, .op = .read, .node = node, .handle = newer.reply.handle, .size = 32 }).bytes);
_ = call(p, .{ .tag = 8, .op = .release, .node = node, .handle = newer.reply.handle });
}
@@ -162,7 +162,7 @@ test "an empty terminal body snapshot stays empty while output continues" {
try testing.expectEqualStrings("", call(p, .{ .tag = 3, .op = .read, .node = node, .handle = opened.reply.handle, .size = 32 }).bytes);
_ = call(p, .{ .tag = 4, .op = .release, .node = node, .handle = opened.reply.handle });
const newer = call(p, .{ .tag = 5, .op = .open, .node = node });
- try testing.expectEqualStrings("new output", call(p, .{ .tag = 6, .op = .read, .node = node, .handle = newer.reply.handle, .size = 32 }).bytes);
+ try testing.expectEqualStrings("new output\n", call(p, .{ .tag = 6, .op = .read, .node = node, .handle = newer.reply.handle, .size = 32 }).bytes);
_ = call(p, .{ .tag = 7, .op = .release, .node = node, .handle = newer.reply.handle });
}
@@ -194,13 +194,13 @@ test "terminal body snapshots are lazy bounded and released after the pane close
try testing.expectEqual(E.NOMEM, failed.errno());
try testing.expect(p.fs.opens[handles[0] - 1].what.snapshot == null);
const first = call(p, .{ .tag = 4, .op = .read, .node = node, .handle = handles[0], .size = 32 });
- try testing.expectEqualStrings("latest output", first.bytes);
+ try testing.expectEqualStrings("latest output\n", first.bytes);
const saved = p.fs.opens[handles[0] - 1].what.snapshot.?;
failing = std.testing.FailingAllocator.init(gpa, .{ .fail_index = 0 });
p.gpa = failing.allocator();
const second = call(p, .{ .tag = 5, .op = .read, .node = node, .handle = handles[0], .off = 7, .size = 32 });
p.gpa = gpa;
- try testing.expectEqualStrings("output", second.bytes);
+ try testing.expectEqualStrings("output\n", second.bytes);
try testing.expect(!failing.has_induced_failure);
try testing.expectEqual(saved.ptr, p.fs.opens[handles[0] - 1].what.snapshot.?.ptr);
try testing.expectEqual(E.INVAL, call(p, .{ .tag = 6, .op = .read, .node = screen_node, .handle = handles[0], .size = 32 }).errno());
@@ -328,3 +328,17 @@ test "screen inspection preserves acknowledged presentation and the next real fr
}
}
}
+
+test "a terminal's body is its logical lines: a row the terminal wrapped is joined again" {
+ const p = try th.withTerm(testing.allocator);
+ defer p.deinit();
+ const pane = p.panes[0].?;
+ const long = "w" ** 50 ++ "x" ** 150; // wider than the pane: it wraps
+ try testing.expect(long.len > pane.cols);
+ p.update(.{ .output = .{ .pane = 0, .bytes = long ++ "\r\nnext" } });
+ while (p.nextEffect()) |_| {}
+ const node = Node.of(pane.serial, .body);
+ const body = th.rd(p, node, 0, 4096).bytes;
+ try testing.expectEqualStrings(long ++ "\nnext\n", body);
+ try testing.expectEqual(@as(u64, body.len), th.call(p, .{ .tag = 1, .op = .getattr, .node = node }).reply.attr.size);
+}