From 157df8cb547ba4cf900b1f9eb75df15384985708 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 09:45:38 -0300 Subject: A served-tree pane spoils no Grep, and `look .` from a gone directory is ENOENT A pane named `/virtual` gave Grep the root `/`, which swallowed every other pane's directory and ran out of walk before any file: every Grep missed. Grep passes over panes of the served tree. And `.` from a pane whose directory was gone resolved to the served tree's root (/virtual/), or through the jump list to another pane's directory: a dot path is the looking pane's own, and gone it fails, `look: : no such directory`. Co-Authored-By: Claude Opus 5.5 --- src/look.zig | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src/look.zig') diff --git a/src/look.zig b/src/look.zig index fa86aee4..9a81a5c9 100644 --- a/src/look.zig +++ b/src/look.zig @@ -593,7 +593,11 @@ pub fn runSearch(p: *Pardes, id: usize, pat_raw: []const u8, kind: Search, start var nroots: usize = 0; for (p.panes) |slot| { const pp = slot orelse continue; - const d = Pardes.paneDir(pp); + // A pane of the served tree (/virtual/, /n//) has no + // directory on this host to walk, and one that named `/` would + // swallow every other root: passed over. + const d = filesystem.localPath(Pardes.paneDir(pp)) orelse continue; + if (filesystem.isVirtual(if (pp.file) |f| f.path else d)) continue; var covered = false; var k: usize = 0; while (k < nroots) { @@ -1107,7 +1111,8 @@ fn resolveLookTarget(p: *Pardes, id: usize, txt: []const u8, realbuf: *[4096]u8) if (openPaneTarget(p, j, pl.at)) |target| return target; } found = resolve(p, txt, dir, realbuf); - if (found != .none or pl.path.len == 0 or pl.path[0] == '/') break; + // `.`, `..`, `./x` are this pane's directory's, not another's. + if (found != .none or pl.path.len == 0 or pl.path[0] == '/' or filesystem.dotRelative(pl.path)) break; } return found; } @@ -1407,6 +1412,13 @@ pub fn lookAt(p: *Pardes, id: usize, operand: []const u8) void { } switch (found) { .none => { + // `.` or `..` from a pane whose directory is gone: said, ENOENT, + // not searched for as a word. + if (filesystem.dotRelative(trimmed)) { + const dir = Pardes.paneDir(pane); + var said: [4200]u8 = undefined; + return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such directory", .{dir[0..@min(dir.len, 4096)]}) catch "look: no such directory"); + } // A raw terminal's clicks are its program's; a look written over // 9P is no keyboard input, and searches whatever the key mode. if (pane.image != null or (pane.body.mode == .tty and !p.fs.serving)) return; @@ -1439,6 +1451,12 @@ pub fn lookAt(p: *Pardes, id: usize, operand: []const u8) void { }, .url => |u| if (u.len <= 256) p.emit(.{ .open_link = .from(u) }), .dir => |dir| { + // A directory that is not there (the pane's own, gone): said, + // ENOENT, no terminal made in it. + if (comptime pardes.hosted) if (filesystem.localPath(dir)) |local| if (!exec.isDirectory(local)) { + var said: [4200]u8 = undefined; + return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such directory", .{dir[0..@min(dir.len, 4096)]}) catch "look: no such directory"); + }; for (p.panes, 0..) |slot, i| { if (slot) |tt| if (std.mem.eql(u8, tt.cwdSlice(), dir) and exec.takesCommandLine(p, i)) { clearNavigationSelection(p, tt); -- cgit v1.3