From 53fcf030b175fc035e62d1d471c01c2e0caefc9e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 11:18:33 -0300 Subject: A Find or Grep that finds nothing empties its directory's +Search It failed with no match but left the last search's rows in the +Search, where they read as this one's. Co-Authored-By: Claude Opus 5.5 --- docs/fs.md | 3 ++- src/Output.zig | 10 ++++++++++ src/look.zig | 5 ++++- src/ninep/ctl.zig | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/fs.md b/docs/fs.md index 1baa9b2c..6fa612f5 100644 --- a/docs/fs.md +++ b/docs/fs.md @@ -748,7 +748,8 @@ every pane's directory on this host, passing over panes of the served tree (`/virtual/`, a peer's `/n//`) and directories not there, so none of them spoils the rest; Find and Grep share one `+Search` a directory, each run replacing what the last showed, as acme reuses a -directory's `+Errors` (the exec reads that pane back), while a plain +directory's `+Errors` (the exec reads that pane back; one that finds +nothing empties it rather than leave the last rows), while a plain word's `LookWord list` search keeps a pane a pattern, ENOSPC for no room or slot, EBUSY for a held lock) -- and logs its reason exactly once, as `err : `, with no `msg` for it. A builtin a click runs (Save, get's diff --git a/src/Output.zig b/src/Output.zig index 99246b4a..eb9e8db4 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -418,6 +418,16 @@ pub fn open(p: *Pardes, id: usize, dir: []const u8, from: Origin, arg: []const u /// Find and Grep share one +Search a directory, each run replacing what /// the last showed, as acme reuses a directory's +Errors; a pane's own /// search (LookWord list) keeps a pane a pattern. +/// Whether `dir` has its Find/Grep +Search open. +pub fn hasFileSearch(p: *Pardes, dir: []const u8) bool { + for (p.panes) |slot| { + const f = (slot orelse continue).file orelse continue; + const o = f.output orelse continue; + if (fileSearch(o.from) and std.mem.eql(u8, std.fs.path.dirname(f.path) orelse "", dir)) return true; + } + return false; +} + fn fileSearch(from: Origin) bool { return switch (from) { .cmd => |c| c == .Find or c == .Grep, diff --git a/src/look.zig b/src/look.zig index 0baa9afc..f45fe583 100644 --- a/src/look.zig +++ b/src/look.zig @@ -667,7 +667,10 @@ pub fn runSearch(p: *Pardes, id: usize, pat_raw: []const u8, kind: Search, start nrows += 1; } } - if (!open_empty and nrows == 0) return 0; + // A Find or Grep that finds nothing empties its directory's +Search, if + // there is one, rather than leave the last search's rows looking like + // this one's. + if (!open_empty and nrows == 0 and (kind == .text or !panes.Output.hasFileSearch(p, dir))) return 0; const content = try p.gpa.dupe(u8, out[0..out_len]); // the buffer records WHICH search filled it, pattern and all: Find and // Grep are builtins (words you can execute), the bare `/` is a key diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 2dc3a51b..a78a9fcd 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -1886,6 +1886,8 @@ test "Grep with no hit says grep: no match and opens nothing, a missing pane dir var after: usize = 0; for (p.panes) |slot| after += @intFromBool(slot != null); try testing.expectEqual(count, after); + // The +Search the miss would have filled is emptied, not left stale. + try testing.expectEqualStrings("", found.file.?.content); } test "Unmount of a name not mounted says no such mount, which a mount reads as ENOENT" { -- cgit v1.3