diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 15:26:17 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | 830e936da4aca7ea802a6a862fa40c0086defd2f (patch) | |
| tree | 8f2b76129f35fc27263dc975cfb61ac8b4024ea2 /src/pardes.zig | |
| parent | d0b4e65eeaf71c8215cda347e7546f3abc07b25b (diff) | |
| download | pardes-830e936da4aca7ea802a6a862fa40c0086defd2f.tar.gz pardes-830e936da4aca7ea802a6a862fa40c0086defd2f.zip | |
A command of several lines keeps its pane's tag to one row, and the tag never panics on a longer prefix
A two-line exec made a command pane whose tag prefix held the line's newline,
so the tag ran to a second row and tagTintRange sliced its first row past its
end: panic. acme runs a multi-line selection as one command, and so does
pardes; the tag now shows the line's first row, cut at a character's start,
and '...', tagTintRange stays inside the row it is given, and the '% line'
echo turns the line's newlines into the terminal's, so it does not
staircase.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index 9821839f..80a20a0d 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -1361,6 +1361,33 @@ test "Exec in a terminal whose tty is taken runs as a command pane instead of ty try std.testing.expect(spawned); } +test "a command of several lines keeps its tag one row, and its echo does not staircase" { + const gpa = std.testing.allocator; + const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 100, .rows = 30 }); + defer p.deinit(); + while (p.nextEffect()) |_| {} + const doc = try p.newDocPane(1); + doc.image = .{ .path = try gpa.dupe(u8, "/tmp/pic.ppm") }; + const two = "def greet(name):\n return name\n\nprint(greet(\"x\"))\n"; + const dst = exec.execute(p, 1, two) orelse return error.NoCommandPane; + while (p.nextEffect()) |_| {} + const pane = p.panes[dst].?; + const prefix = try tagline.tagPrefix(p, pane); + try std.testing.expect(std.mem.indexOfScalar(u8, prefix, '\n') == null); + try std.testing.expect(std.mem.indexOf(u8, prefix, "(def greet(name):...) running") != null); + // Rendered without a panic, however the tag wraps. + var frame = std.heap.ArenaAllocator.init(gpa); + defer frame.deinit(); + _ = try p.render(frame.allocator()); + p.update(.{ .exited = .{ .pane = @intCast(dst), .status = 0 } }); + _ = exec.execute(p, 1, two); + while (p.nextEffect()) |_| {} + _ = try p.render(frame.allocator()); + const body = try panes.Terminal.screenTextAlloc(pane, gpa); + defer gpa.free(body); + try std.testing.expect(std.mem.indexOf(u8, body, "% def greet(name):\n return name") != null); +} + test "a spawn is for the pane it was made for, not whatever took the slot since" { const gpa = std.testing.allocator; const p = try Pardes.init(gpa, .{ .tty_only = true }); |
