summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig61
1 files changed, 56 insertions, 5 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index f08cf01b..fbc19b8a 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -4574,7 +4574,7 @@ pub const Pardes = struct {
const path = opts.file.?;
const opened = initial_doc: {
if (comptime pdf_enabled) if (look.isPdfPath(path))
- break :initial_doc panes.Pdf.openPane(p, 0, path, opts.file_line);
+ break :initial_doc panes.Pdf.openPane(p, 0, path, opts.file_line, .last);
if (look.isImagePath(path))
break :initial_doc panes.Image.create(p, 0, path, &.{});
break :initial_doc panes.File.open(p, 0, path, opts.file_line);
@@ -4709,13 +4709,25 @@ pub const Pardes = struct {
return exec.isFile(local);
}
- /// A file pane closing: its place noted in Recent, when Recent keeps it.
+ /// A file, PDF or image pane closing: its place noted in Recent, when
+ /// Recent keeps it.
fn noteClosed(p: *Pardes, pane: *const Pane) void {
- const d = recentDot(pane) orelse return;
+ const d = recentPlace(pane) orelse return;
if (p.recent.get(d.path) == null and !recentKeeps(d.path)) return;
p.recent.closedSel(p.recentGpa(), d.path, d.line, d.col, d.aline, d.acol);
}
+ pub const RecentPlace = struct { path: []const u8, line: u32, col: u32, aline: u32 = 0, acol: u32 = 0 };
+
+ /// Where a pane is, as Recent keeps it: a file's dot, a PDF's page
+ /// (`:page:1`), an image's path alone (line 0). Null for any other.
+ pub fn recentPlace(pane: *const Pane) ?RecentPlace {
+ if (recentDot(pane)) |d| return .{ .path = d.path, .line = d.line, .col = d.col, .aline = d.aline, .acol = d.acol };
+ if (pane.pdfPath()) |path| return .{ .path = path, .line = @intCast(pane.pdfPage().? + 1), .col = 1 };
+ if (pane.image) |iv| return .{ .path = iv.path, .line = 0, .col = 0 };
+ return null;
+ }
+
fn recentDot(pane: *const Pane) ?struct { path: []const u8, line: u32, col: u32, aline: u32 = 0, acol: u32 = 0 } {
const f = pane.file orelse return null;
if (f.output != null) return null;
@@ -6656,7 +6668,7 @@ pub const Pardes = struct {
// fall through: a multi-file rename previews as rows
} else if (w.kind == .format and rows.len > 0) {
// fall through: "cannot format" and friends are prose
- } else return;
+ } else if (w.kind == .format) return; // a rename of nothing says so, below
}
if (rows.len == 0) {
if (w.kind == .completion and pane.body.mode == .insert and pane.body.nsel == 0 and
@@ -6664,7 +6676,8 @@ pub const Pardes = struct {
// Nothing found fails, but for a file with no diagnostics,
// which is no failure, and a completion's Tab.
const none: ?[]const u8 = switch (w.kind) {
- .completion, .format, .rename => null,
+ .completion, .format => null,
+ .rename => "nothing here to rename",
.diagnostics, .workspace_diagnostics => return p.setMessage(w.pane, std.fmt.bufPrint(&said, "{s}: none", .{lspWord(w.kind)}) catch "none"),
.incoming_calls => "callers not found",
.outgoing_calls => "callees not found",
@@ -6889,6 +6902,12 @@ pub const Pardes = struct {
break;
};
}
+ // Two in a row the same (a closed one reopened beside its own,
+ // or the entry between them gone): one entry, one step.
+ if (w > 0 and std.meta.eql(p.jumps[w - 1], kept)) {
+ if (i == p.jcur) cur = w - 1;
+ continue;
+ }
p.jumps[w] = kept;
w += 1;
}
@@ -8034,6 +8053,38 @@ test "raw tty Ctrl-B switches to editor mode without sending child input" {
try std.testing.expectEqualStrings("", drainWrites(p, &buf));
}
+test "the jump list never holds two entries in a row the same, when the one between them goes" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 60, .rows = 40 });
+ defer p.deinit();
+ const pane = try p.setTestFile("a\n" ** 200);
+ const at: Loc = .{ .pane = 0, .serial = pane.serial, .line = 1, .col = 1 };
+ // A, a pane long closed with no file to keep it, A again, then far on.
+ p.jumps[0] = at;
+ p.jumps[1] = .{ .pane = 5, .serial = 999, .line = 1, .col = 1 };
+ p.jumps[2] = at;
+ p.jumps[3] = .{ .pane = 0, .serial = pane.serial, .line = 150, .col = 1 };
+ p.njumps = 4;
+ p.jcur = 3;
+ pane.body.cur_row = 80; // where you are now: far from both
+ p.trackJump();
+ for (1..p.njumps) |i| try std.testing.expect(!std.meta.eql(p.jumps[i - 1], p.jumps[i]));
+ try std.testing.expectEqual(@as(usize, 3), p.njumps);
+ try std.testing.expectEqual(@as(u32, 1), p.jumps[0].line);
+ try std.testing.expectEqual(@as(u32, 150), p.jumps[1].line);
+}
+
+test "a Rename the language server finds nothing for says so, and changes nothing" {
+ if (!lsp.supports.contains(.rename)) return;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("const value=1;\n");
+ p.lspRequest(p.active, .rename, "renamed");
+ const wait = p.lsp_wait.?;
+ p.update(.{ .lsp_resp = .{ .id = wait.id, .rows = "" } });
+ try std.testing.expectEqualStrings("Rename: nothing here to rename", pane.msg[0..pane.msg_len]);
+ try std.testing.expectEqualStrings("const value=1;\n", pane.file.?.content);
+}
+
test "hopping between two panes does not grow the jump stack" {
if (platform == .web) return;
const gpa = std.testing.allocator;