summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-08 03:53:22 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commitb13152f89b478466b860aecb2bada8d96f0e9e36 (patch)
tree6d40c79a58afee11d93b11220568eafb165822e4 /src/pardes.zig
parentacb5be9e71f0faf3781c7d57cdb0ba829ab3e5c4 (diff)
downloadpardes-b13152f89b478466b860aecb2bada8d96f0e9e36.tar.gz
pardes-b13152f89b478466b860aecb2bada8d96f0e9e36.zip
look focuses an already-loaded pane before any filesystem resolve: the looked word (and its cwd-join) is matched against loaded file/image pane paths first, honoring :NN recentering — so the fs-less web build can focus dump-loaded panes on look, and native dedup no longer needs the file on disk. New lookloaded.snap: look at a path after rm'ing it still focuses/recenters the loaded pane.
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig75
1 files changed, 50 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;