summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pardes.zig75
-rw-r--r--test/snapshots/lookloaded.golden93
-rw-r--r--test/snapshots/lookloaded.snap39
3 files changed, 182 insertions, 25 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index 9397f445..4750fa0b 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -4107,6 +4107,37 @@ pub const Pardes = struct {
// ---- the ONE dispatcher: look (right/Enter) and execute (middle/Tab) ----
+ /// focus the pane already loaded on `path` (exact match), if any: file
+ /// panes recenter on a :NN line like the look dedup always has, image
+ /// panes just focus. Returns false when no pane holds that path.
+ fn focusPaneByPath(p: *Pardes, path: []const u8, line: usize) bool {
+ for (p.panes, 0..) |slot, i| {
+ const tt = slot orelse continue;
+ if (tt.image) |iv| if (std.mem.eql(u8, iv.path, path)) {
+ p.active = i;
+ return true;
+ };
+ const ff = if (tt.file) |*f| f else continue;
+ if (!std.mem.eql(u8, ff.path, path)) continue;
+ p.active = i;
+ if (line > 0 and line <= fileLineCount(ff.content)) {
+ const next = (line - 1) -| tt.rows / 2; // center, clamp at top
+ if (next != ff.scroll) {
+ ff.scroll = next;
+ ff.syntax_dirty = true;
+ }
+ // land the modal cursor on the target line (and keep
+ // ensureCursorVisible agreeing with the recenter —
+ // a stale cursor would yank the view right back)
+ tt.cur_row = @intCast(line - 1);
+ tt.cur_col = 0;
+ tt.cur_pinned = true;
+ }
+ return true;
+ }
+ return false;
+ }
+
fn actOnSelection(p: *Pardes, button: Mouse.Button, id: usize, txt: []const u8, arg: ?[]const u8) void {
const pane = p.panes[id] orelse return;
// image tagline toggles (execute), before the builtin/run dispatch
@@ -4135,6 +4166,23 @@ pub const Pardes = struct {
@memcpy(cwdbuf[0..c.len], c);
break :blk cwdbuf[0..c.len];
};
+ // an already-loaded pane wins BEFORE any filesystem resolve: the
+ // web build has no fs (a look would otherwise be inert even for
+ // panes sitting in the session), and native gets the same dedup
+ // it always did, just without touching disk. Pane paths are
+ // canonical (realpath'd or dump-given), so match the word as-is
+ // and cwd-joined; anything fancier falls through to resolve.
+ {
+ const pl = look.parsePathLine(std.mem.trim(u8, txt, " \t\r\n"));
+ if (pl.path.len > 0) {
+ if (p.focusPaneByPath(pl.path, pl.line)) return;
+ if (pl.path[0] != '/') {
+ var joinbuf: [2048]u8 = undefined;
+ if (std.fmt.bufPrint(&joinbuf, "{s}/{s}", .{ cwd, pl.path }) catch null) |j|
+ if (p.focusPaneByPath(j, pl.line)) return;
+ }
+ }
+ }
switch (look.resolve(txt, cwd, &realbuf)) {
.none => {},
.url => |u| if (u.len <= 256) p.emit(.{ .open_link = .from(u) }),
@@ -4157,25 +4205,7 @@ pub const Pardes = struct {
},
.file => |target| {
// focus an existing pane on this path (rescrolled), else open
- for (p.panes, 0..) |slot, i| {
- if (slot) |tt| if (tt.file) |*ff| if (std.mem.eql(u8, ff.path, target.path)) {
- p.active = i;
- if (target.line > 0 and target.line <= fileLineCount(ff.content)) {
- const next = (target.line - 1) -| tt.rows / 2; // center, clamp at top
- if (next != ff.scroll) {
- ff.scroll = next;
- ff.syntax_dirty = true;
- }
- // land the modal cursor on the target line (and keep
- // ensureCursorVisible agreeing with the recenter —
- // a stale cursor would yank the view right back)
- tt.cur_row = @intCast(target.line - 1);
- tt.cur_col = 0;
- tt.cur_pinned = true;
- }
- return;
- };
- }
+ if (p.focusPaneByPath(target.path, target.line)) return;
const free = p.freeSlot() orelse return;
const nt = p.openFileView(free, target.path, target.line) catch return;
p.placeDoc(id, free, nt);
@@ -4186,12 +4216,7 @@ pub const Pardes = struct {
nt.file.?.scroll -|= @max(1, p.rects[free].h -| BOX_H) / 2;
},
.image => |target| {
- for (p.panes, 0..) |slot, i| {
- if (slot) |tt| if (tt.image) |iv| if (std.mem.eql(u8, iv.path, target.path)) {
- p.active = i;
- return;
- };
- }
+ if (p.focusPaneByPath(target.path, 0)) return;
const free = p.freeSlot() orelse return;
// petscii by default when the host has no kitty graphics
const nt = p.openImageView(free, target.path, !p.kitty_ok) catch return;
diff --git a/test/snapshots/lookloaded.golden b/test/snapshots/lookloaded.golden
new file mode 100644
index 00000000..af90b0ef
--- /dev/null
+++ b/test/snapshots/lookloaded.golden
@@ -0,0 +1,93 @@
+== snap file-open grid=100x30 cursor=7,5
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/lookloaded/cwd/big.txt Save NOR /tmp/pardes-snap/lookloaded/cwd Del
+| 37 line 37
+| 38 line 38 big.txt
+| 39 line 39
+| 40 line 40
+| 41 line 41
+|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+|
+|
+| big.txt:40 big.txt:10
+|
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+== snap removed grid=100x30 cursor=4,10
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/lookloaded/cwd/big.txt Save NOR /tmp/pardes-snap/lookloaded/cwd Del
+| 37 line 37
+| 38 line 38 big.txt
+| 39 line 39
+| 40 line 40
+| 41 line 41
+| 42 line 42
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+| GONE
+|
+| big.txt:40 big.txt:10
+|
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+== snap look-noFS grid=100x30 cursor=7,5
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| NOR /tmp/pardes-snap/lookloaded/cwd/big.txt Save NOR /tmp/pardes-snap/lookloaded/cwd Del
+| 7 line 7
+| 8 line 8 big.txt
+| 9 line 9
+| 10 line 10
+| 11 line 11
+| 12 line 12
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+| GONE
+|
+| big.txt:40 big.txt:10
+|
+| NOR /tmp/pardes-snap/lookloaded/cwd Del
+|
+| big.txt
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
diff --git a/test/snapshots/lookloaded.snap b/test/snapshots/lookloaded.snap
new file mode 100644
index 00000000..03874925
--- /dev/null
+++ b/test/snapshots/lookloaded.snap
@@ -0,0 +1,39 @@
+# a look matches an already-LOADED pane before touching the filesystem: open
+# big.txt:40 from a look, rm the file on disk, then look big.txt:10 — the
+# loaded pane focuses and recenters even though realpath now fails. (This
+# fs-last ordering is what lets the fs-less web build focus dump panes.)
+lines big.txt 60
+start 30 100 -n 3
+wait 8000 big.txt
+stable 700 20000
+press left 5 8
+release left 5 8
+stable 400 5000
+key i
+text big.txt:40 big.txt:10
+key esc
+settle 700
+stable 400 5000
+press right 7 8
+release right 7 8
+stable 700 15000
+snap file-open
+# back to the shell: rm the file from disk in tty mode
+press left 5 11
+release left 5 11
+stable 400 5000
+key c-b
+stable 600 8000
+text rm big.txt; echo GO''NE
+key enter
+wait 8000 GONE
+stable 700 15000
+key c-b
+stable 600 8000
+snap removed
+# look big.txt:10: nothing on disk, but the pane is loaded — it focuses and
+# recenters on line 10 (before this change: realpath fails, look no-ops)
+press right 18 15
+release right 18 15
+stable 700 15000
+snap look-noFS