diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 12:24:58 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | f6ccac42abf0f08159a78c9ca58ff9137ac18434 (patch) | |
| tree | 272948f5f544d2f9f6cf4a6b8469972902b825a2 /src | |
| parent | 276a060dee5c753b513a75cca0b2c942dfe540fd (diff) | |
| download | pardes-f6ccac42abf0f08159a78c9ca58ff9137ac18434.tar.gz pardes-f6ccac42abf0f08159a78c9ca58ff9137ac18434.zip | |
Back or Forward over a closed file deleted since skips it and goes on, saying so
A jumplist entry for a closed file no longer on disk tried to reopen it, failed as a look, and left the step stuck there. Its entries now go, the message row says <path>: deleted, skipped, and the same step is taken over what is left.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ninep/ctl.zig | 28 | ||||
| -rw-r--r-- | src/pardes.zig | 22 |
2 files changed, 50 insertions, 0 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index d815632d..db058ff2 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -2408,6 +2408,34 @@ test "/recent shows a name as /index does, a newline in it escaped" { try testing.expect(std.mem.indexOf(u8, text, "closed /tmp/a\\nb\\\\c\n") != null); } +test "Back over a closed file deleted since skips it, says so, and goes on to the place before" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + var tmp = testing.tmpDir(.{}); + defer tmp.cleanup(); + for ([_][]const u8{ "a.txt", "gone.txt", "c.txt" }) |name| try tmp.dir.writeFile(testing.io, .{ .sub_path = name, .data = "text\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}/a.txt\n", .{dir})); + p.sync(); + const a_serial = p.panes[p.active].?.serial; + _ = wr(p, root_look, try std.fmt.bufPrint(&line, "{s}/gone.txt\n", .{dir})); + p.sync(); + const gone = p.active; + _ = wr(p, root_look, try std.fmt.bufPrint(&line, "{s}/c.txt\n", .{dir})); + p.sync(); + const c_id = p.active; + _ = wr(p, Node.of(p.panes[gone].?.serial, .ctl), "Del\n"); + p.sync(); + try tmp.dir.deleteFile(testing.io, "gone.txt"); + p.active = c_id; + p.jumpBy(-1); + p.sync(); + try testing.expectEqual(a_serial, p.panes[p.active].?.serial); + try testing.expect(std.mem.indexOf(u8, p.panes[c_id].?.msg[0..p.panes[c_id].?.msg_len], "gone.txt: deleted, skipped") != null); +} + 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(); diff --git a/src/pardes.zig b/src/pardes.zig index 135823e4..4147032b 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -6817,6 +6817,28 @@ pub const Pardes = struct { // places it, and the entry is that pane from here on. if (j.serial == 0) { const e = p.recentByHash(j.path_hash) orelse return; + // Deleted since: its entries go, it is said, and the step goes + // on to the next place, never stuck on one that cannot open. + if (!recentKeeps(e.path)) { + var said: [recent_path_cap + 32]u8 = undefined; + p.setMessage(p.active, std.fmt.bufPrint(&said, "{s}: deleted, skipped", .{e.path}) catch "deleted, skipped"); + const hash = j.path_hash; + var w: usize = 0; + var cur = p.jcur; + for (p.jumps[0..p.njumps], 0..) |k, i| { + if (k.serial == 0 and k.path_hash == hash) { + if (i < p.jcur) cur -= 1; + continue; + } + p.jumps[w] = k; + w += 1; + } + p.njumps = w; + p.jcur = @min(cur, w -| 1); + // The same step again, over the list without them: each + // round takes one file's entries away, so it ends. + return p.jumpBy(delta); + } const from = p.active; look.reopenAt(p, from, e.path, .{ .line = @max(1, j.line), .col = @max(1, j.col) }); const opened = p.panes[p.active] orelse return; |
