summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 11:09:17 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit5db9e71ba32dd6f0a0292eaa341d1d8ba805483c (patch)
treefeaf11471f49fdba5122922a960889ea4cb4f549 /src/ninep/ctl.zig
parent6b46d0797003585a99f8e5b99b3e8cff635ebebc (diff)
downloadpardes-5db9e71ba32dd6f0a0292eaa341d1d8ba805483c.tar.gz
pardes-5db9e71ba32dd6f0a0292eaa341d1d8ba805483c.zip
A remembered place is clamped to the file as it is now, its selection's two ends kept
A Recent row or a jumplist entry for a line the file no longer has failed the look; now it opens at the last line. The selection's anchor is remembered too, so a reopen restores both ends where they fit, and Recent and Jumplist share the (closed) marker. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig40
1 files changed, 38 insertions, 2 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 477a91fe..889ee7be 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -2141,8 +2141,8 @@ test "a closed file is found again: Recent and /recent list it closed, a look at
const rows = p.panes[p.paneBySerial(try std.fmt.parseInt(u32, std.mem.trimEnd(u8, rd(p, root_exec, 0, 64).bytes, "\n"), 10)).?].?;
const at = std.mem.indexOf(u8, rows.file.?.content, try std.fmt.bufPrint(&want, "{s}:3:", .{a})).?;
const row = rows.file.?.content[at .. std.mem.indexOfScalarPos(u8, rows.file.?.content, at, '\n').?];
- try testing.expect(std.mem.endsWith(u8, row, " closed"));
- try testing.expectEqual(Status.ok, wr(p, Node.of(rows.serial, .look), try std.fmt.bufPrint(&line, "{s}\n", .{row[0 .. row.len - " closed".len]})).reply.status);
+ try testing.expect(std.mem.endsWith(u8, row, " (closed)"));
+ try testing.expectEqual(Status.ok, wr(p, Node.of(rows.serial, .look), try std.fmt.bufPrint(&line, "{s}\n", .{row[0 .. row.len - " (closed)".len]})).reply.status);
p.sync();
const back = p.panes[p.active].?;
try testing.expectEqualStrings(a, back.file.?.path);
@@ -2163,6 +2163,42 @@ test "a closed file is found again: Recent and /recent list it closed, a look at
try testing.expectEqualStrings(a, p.panes[p.active].?.file.?.path);
}
+test "a remembered place is clamped to the file as it is now, its selection's two ends kept where they fit" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ var tmp = testing.tmpDir(.{});
+ defer tmp.cleanup();
+ try tmp.dir.writeFile(testing.io, .{ .sub_path = "c.txt", .data = "one\ntwo\nthree\nfour\nfive\n" });
+ var dir_buf: [4096]u8 = undefined;
+ const dir = dir_buf[0..try tmp.dir.realPath(testing.io, &dir_buf)];
+ var line: [4200]u8 = undefined;
+ _ = wr(p, root_look, try std.fmt.bufPrint(&line, "{s}/c.txt:2\n", .{dir}));
+ p.sync();
+ const c = p.panes[p.active].?;
+ // A selection over lines 2 to 4, then closed.
+ @import("pane.zig").setDot(c, .{ .q0 = 4, .q1 = 19 });
+ try testing.expect(c.body.vsel.active);
+ _ = wr(p, Node.of(c.serial, .ctl), "Del\n");
+ p.sync();
+ // The file shrinks to two lines while it is closed.
+ try tmp.dir.writeFile(testing.io, .{ .sub_path = "c.txt", .data = "one\ntwo\n" });
+ _ = wr(p, root_exec, "Recent\n");
+ const rows = p.panes[p.paneBySerial(try std.fmt.parseInt(u32, std.mem.trimEnd(u8, rd(p, root_exec, 0, 64).bytes, "\n"), 10)).?].?;
+ const at = std.mem.indexOf(u8, rows.file.?.content, "c.txt:").?;
+ const row = rows.file.?.content[at .. std.mem.indexOfScalarPos(u8, rows.file.?.content, at, '\n').?];
+ // Both ends are in the row, a range.
+ try testing.expect(std.mem.indexOfScalar(u8, row, '-') != null);
+ var full: [4400]u8 = undefined;
+ const loc = try std.fmt.bufPrint(&full, "{s}/{s}\n", .{ dir, row[0 .. std.mem.indexOfScalar(u8, row, ' ').?] });
+ // A look at it opens the file, never a miss, clamped to its last line.
+ try testing.expectEqual(Status.ok, wr(p, Node.of(rows.serial, .look), loc).reply.status);
+ p.sync();
+ const back = p.panes[p.active].?;
+ try testing.expect(std.mem.endsWith(u8, back.file.?.path, "/c.txt"));
+ try testing.expect(back.body.cur_row <= 1);
+ try testing.expect(back.body.vsel.active);
+}
+
test "size is monotonic: growing is never refused, and a size once taken is taken again" {
const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 160, .rows = 60 });
defer p.deinit();