summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-27 10:20:19 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commitc79612b523c1526202335302e1e49c078ca317cf (patch)
treeb76d7b0e15f3b0e43ba65f9ea9eb57ee4a8ed6e1 /src
parentf0e498832a1a4f92d5fdbc3fc643a3dba1dd9df9 (diff)
downloadpardes-c79612b523c1526202335302e1e49c078ca317cf.tar.gz
pardes-c79612b523c1526202335302e1e49c078ca317cf.zip
look resolves against every open pane's directory: clicked pane first, then most-recently-focused, search only when all fail
Diffstat (limited to 'src')
-rw-r--r--src/pardes.zig67
-rw-r--r--src/tutor.txt7
2 files changed, 45 insertions, 29 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index 017892aa..d3376273 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -2551,20 +2551,17 @@ pub const Pardes = struct {
return true;
}
- /// n/N on a terminal pane (normal mode): select the next/previous output
- /// row whose leading file-ish word looks somewhere — resolves to a
- /// file/dir/path:NNN exactly as a right click would — and look it. The
- /// scan only resolves (realpath, no pane opens, no scrolls); the one
- /// chosen row gets the real look. The modal cursor is the position, so
- /// the walk continues from wherever j/k left it. The look may focus what
- /// it opened; focus comes back here so the next n keeps stepping.
/// n/N on a terminal pane: a MOTION over lookable tokens. Select the
/// next/prev whitespace-separated token that look.resolve can turn into a
/// file/dir (several per line: an ls row hops big.txt -> plain.txt), park
/// the cursor at its start, open NOTHING — Enter's normal-mode handler
/// looks the selection. Wraps around when nothing lies in the direction
/// (fresh out of tty mode the cursor sits below the output, so the first
- /// n lands on the first token).
+ /// n lands on the first token). Deliberately only THIS pane's directory,
+ /// where the look itself walks every pane's: the motion resolves every
+ /// token it steps over, so the other directories would cost tokens ×
+ /// panes realpaths on a single keystroke — and a token the motion skips
+ /// is still openable by looking it, which is all n/N is a shortcut for.
fn lookStep(p: *Pardes, pane: *Pane, pl: PaneLines, delta: i32) void {
_ = p; // a pure motion now: Enter's normal-mode handler does the look
pane.pinCursor(); // fresh out of tty mode the cursor still tracks the shell
@@ -4638,32 +4635,48 @@ pub const Pardes = struct {
const pane = p.panes[id] orelse return;
if (button == .right) {
var realbuf: [4096]u8 = undefined;
- var cwdbuf: [1024]u8 = undefined;
- const cwd: []const u8 = if (pane.file) |f|
- (std.fs.path.dirname(f.path) orelse "/")
- else blk: {
- const c = pane.cwdSlice();
- @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, pl.col)) 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, pl.col)) return;
- }
+ // here and joined onto each directory below.
+ const pl = look.parsePathLine(std.mem.trim(u8, txt, " \t\r\n"));
+ if (pl.path.len > 0 and p.focusPaneByPath(pl.path, pl.line, pl.col)) return;
+ // The word is resolved against the pane DIRECTORIES in access
+ // order: the pane the click came from FIRST — its answer is the
+ // one taken, so nothing that resolves today moves — then every
+ // other live pane, most recently focused first (focus_hist runs
+ // least-recent -> active, so it is that array backwards; the
+ // clicked pane is not always `active`, a right click does not
+ // focus). Only when ALL of them fail does the word fall through to
+ // the search below: a name you can read in one window is openable
+ // from any of them. Each attempt is a realpath + an open and
+ // shells share cwds constantly, so a seen-list holds every
+ // directory to one try; an absolute word — and `@pN`, which reads
+ // no directory at all — answers the same everywhere and stops
+ // after the first pass.
+ var hit: look.Target = .none;
+ var seen: [MAX_PANES][]const u8 = undefined;
+ var nseen: usize = 0;
+ var n: usize = 0;
+ cand: while (n <= p.nfocus) : (n += 1) {
+ const k = if (n == 0) id else p.focus_hist[p.nfocus - n];
+ if (n > 0 and k == id) continue; // tried first, skip the rerun
+ const op = p.panes[k] orelse continue;
+ const dir = if (op.file) |f| (std.fs.path.dirname(f.path) orelse "/") else op.cwdSlice();
+ for (seen[0..nseen]) |s| if (std.mem.eql(u8, s, dir)) continue :cand;
+ seen[nseen] = dir;
+ nseen += 1;
+ if (pl.path.len > 0 and pl.path[0] != '/') {
+ var joinbuf: [2048]u8 = undefined;
+ if (std.fmt.bufPrint(&joinbuf, "{s}/{s}", .{ dir, pl.path }) catch null) |j|
+ if (p.focusPaneByPath(j, pl.line, pl.col)) return;
}
+ hit = look.resolve(txt, dir, &realbuf);
+ if (hit != .none or pl.path.len == 0 or pl.path[0] == '/') break;
}
- switch (look.resolve(txt, cwd, &realbuf)) {
+ switch (hit) {
// acme button-3: a word that names no file/dir is a search of
// the pane it was clicked in — exactly what `/` runs (n/N then
// walk the results). Paths (src/a/b.rs:100) still resolve above
diff --git a/src/tutor.txt b/src/tutor.txt
index 80a67c57..195173c6 100644
--- a/src/tutor.txt
+++ b/src/tutor.txt
@@ -65,6 +65,9 @@
R look open the word under the cursor as a path: a directory
opens/focuses a terminal there and ls's it; a file opens
a file pane (scrolled to a ":line" suffix if present).
+ A bare name is tried in THIS pane's directory first, then
+ in every other open pane's, most recently used first — a
+ name none of them holds is what becomes a search.
WEB TOUCH (one finger): a tap is LOOK, the same action as R; a drag
past a small movement threshold is natural scrolling.
@@ -137,8 +140,8 @@
That is an OUTPUT BUFFER: a file pane with no file behind it, so it has
no Save, but everything else about it is an ordinary buffer you can read,
edit, select and look in. `n`/`N` step the rows and look each one, so the
- view follows along. Right-clicking a word that names no file searches for
- it the same way — acme's button 3 — everywhere except a shell in tty mode,
+ view follows along. Right-clicking a word that names no file in ANY open
+ pane's directory searches for it — acme's button 3 — except in tty mode,
where the click belongs to the program on the other end. On a shell with no
search armed, n/N instead step the lookable tokens in its output.
A hit in a file reads `path:LINE:COL`, the ordinary look target. A hit in