summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 10:03:10 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commitdf6106af80e13cc4f0121b7f2caf5315a4453a9d (patch)
treebeb1176f4b6cf13bb65732ccbf0d9f6e1049f605
parentae71c2e2845be4a5595e7fae117c0ef22c16c0c0 (diff)
downloadpardes-df6106af80e13cc4f0121b7f2caf5315a4453a9d.tar.gz
pardes-df6106af80e13cc4f0121b7f2caf5315a4453a9d.zip
Find and Grep share one +Search a directory, each run replacing the last
Each Grep with a new pattern opened another +Search, until the column refused panes. Find and Grep now reuse their directory's one, as acme reuses +Errors, and the exec reads back the pane it filled; a plain word's LookWord list search keeps a pane a pattern as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--docs/fs.md5
-rw-r--r--src/Output.zig17
-rw-r--r--src/fs.zig3
-rw-r--r--src/ninep/ctl.zig9
-rw-r--r--test/snapshots/find.golden16
-rw-r--r--test/snapshots/stepgrain.golden32
6 files changed, 59 insertions, 23 deletions
diff --git a/docs/fs.md b/docs/fs.md
index 9b5b9d64..a0b3dcf7 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -736,7 +736,10 @@ whose directory is gone says `look: <dir>: no such directory` -- and for a
Find or Grep that finds nothing, `grep: no match, not found`; Grep walks
every pane's directory on this host, passing over panes of the served
tree (`/virtual/`, a peer's `/n/<name>/`) and directories not there,
-so none of them spoils the rest, ENOSPC for no room or
+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
+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 <serial|->
<file>: <why>`, with no `msg` for it. A builtin a click runs (Save, get's
`Modified`, Tty with no room, Edit) is no exception. What is not a
diff --git a/src/Output.zig b/src/Output.zig
index b32a40a2..37d25168 100644
--- a/src/Output.zig
+++ b/src/Output.zig
@@ -406,6 +406,16 @@ pub fn open(p: *Pardes, id: usize, dir: []const u8, from: Origin, arg: []const u
return pane;
}
+/// 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.
+fn fileSearch(from: Origin) bool {
+ return switch (from) {
+ .cmd => |c| c == .Find or c == .Grep,
+ else => false,
+ };
+}
+
pub fn fillResults(p: *Pardes, id: usize, dir: []const u8, from: Origin, arg: []const u8, content: []u8, initial_anchor: ?usize) !void {
var result_content = content;
errdefer p.gpa.free(result_content);
@@ -448,9 +458,12 @@ pub fn fillResults(p: *Pardes, id: usize, dir: []const u8, from: Origin, arg: []
const rp = slot orelse continue;
const rf = if (rp.file) |*f| f else continue;
const o = if (rf.output) |*x| x else continue;
- if (!std.meta.eql(o.from, from)) continue;
- if (by_arg and !std.mem.eql(u8, o.arg(), arg)) continue;
+ const shared = fileSearch(from) and fileSearch(o.from);
+ if (!shared and !std.meta.eql(o.from, from)) continue;
+ if (!shared and by_arg and !std.mem.eql(u8, o.arg(), arg)) continue;
if (!std.mem.eql(u8, std.fs.path.dirname(rf.path) orelse "", dir)) continue;
+ o.from = from;
+ p.fs.refilled = rp.serial;
try setArg(o, arg);
if (std.mem.eql(u8, rf.content, result_content)) {
p.gpa.free(result_content);
diff --git a/src/fs.zig b/src/fs.zig
index de02e8e8..6feaa972 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -1316,6 +1316,9 @@ pub const Namespace = struct {
/// The serial of the pane the root's exec or look last ran a line at
/// (the keyboard's), 0 before one: its err record names that pane.
ran_at: u32 = 0,
+ /// The output pane a search just filled again rather than made
+ /// (Output.fillResults): what an exec reads back.
+ refilled: ?u32 = null,
/// Every failure said (Messages.reportFailure), counted: a builtin
/// that said one while it ran failed.
failures: u32 = 0,
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index a474c781..fbda6113 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -73,6 +73,7 @@ pub fn run(p: *Pardes, id: usize, exec: bool, text: []const u8, in_tag: bool) vo
// An exec answers the pane it went to: a command pane it reused, or
// the terminal it typed into.
p.look_missed = false;
+ p.fs.refilled = null;
const went: ?usize = if (exec) pardes.exec.execute(p, id, text) else blk: {
look.lookAt(p, id, text);
break :blk null;
@@ -88,6 +89,9 @@ pub fn run(p: *Pardes, id: usize, exec: bool, text: []const u8, in_tag: bool) vo
created = true;
};
if (created) return;
+ // A +Search it filled again (Find and Grep reuse one): that is what it
+ // touched.
+ if (p.fs.refilled) |serial| if (p.paneBySerial(serial) != null) return noteResult(p, serial);
if (went) |dst| if (p.panes[dst]) |pane| return noteResult(p, pane.serial);
noteResult(p, if (exec) context else (p.panes[p.active] orelse return).serial);
}
@@ -1841,7 +1845,8 @@ test "Grep with no hit says grep: no match and opens nothing, a missing pane dir
const dir = dir_buf[0..try tmp.dir.realPath(testing.io, &dir_buf)];
var line: [4200]u8 = undefined;
_ = wr(p, Node.of(serialOf(p), .name), try std.fmt.bufPrint(&line, "{s}/a.txt\n", .{dir}));
- // A hit opens its +Search, a row a line: exec reads it back.
+ // A hit opens its +Search, a row a line: exec reads it back. Find and
+ // Grep share it, a directory's one +Search, each run replacing it.
try testing.expectEqual(Status.ok, wr(p, Node.of(serialOf(p), .exec), "Grep bravo\n").reply.status);
const grepped = p.panes[p.paneBySerial(try std.fmt.parseInt(u32, std.mem.trimEnd(u8, rd(p, root_exec, 0, 64).bytes, "\n"), 10)).?].?;
try testing.expectEqual(@as(usize, 2), std.mem.count(u8, grepped.file.?.content, "other.txt:"));
@@ -1850,6 +1855,8 @@ test "Grep with no hit says grep: no match and opens nothing, a missing pane dir
try testing.expectEqual(Status.ok, wr(p, Node.of(serialOf(p), .exec), "Find other\n").reply.status);
const found = p.panes[p.paneBySerial(try std.fmt.parseInt(u32, std.mem.trimEnd(u8, rd(p, root_exec, 0, 64).bytes, "\n"), 10)).?].?;
try testing.expect(std.mem.indexOf(u8, found.file.?.content, "other.txt") != null);
+ try testing.expectEqual(grepped.serial, found.serial);
+ try testing.expect(std.mem.indexOf(u8, found.file.?.content, "bravo here") == null);
// A second pane in a directory that is not there.
const other = try th.newPane(p);
_ = wr(p, Node.of(other, .name), "/tmp/pardes-no-such-dir-zz/b.txt\n");
diff --git a/test/snapshots/find.golden b/test/snapshots/find.golden
index dec8ed1d..a6eae9cf 100644
--- a/test/snapshots/find.golden
+++ b/test/snapshots/find.golden
@@ -75,13 +75,17 @@
|3: 1 Find Find /
|4:
|13: 1 gamma body Last
-== snap nomatch grid=120x41 cursor=7,8
+== snap nomatch grid=120x41 cursor=7,3
|3: 1 Find
+|6: 1
+|7:
+|8:
|13: 1 gamma body
-|18: /tmp/pardes-snap/find/cwd/+Search Save Tty Collapse Del
-|19: 1
== snap refit grid=120x41 cursor=7,3
+|6: 1 sub/ZQMARK-beta.txt
+|7: 2 sub/nest/zqmark-gamma.txt
+|8: 3 zqmark-alpha.txt
== snap topbar grid=120x41 cursor=12,16
-|21: /tmp/pardes-snap/find/cwd/+Search Save Tty Collapse Del
-|22: 1 zqmark-alpha.txt
-|23: 2
+|6: 1 zqmark-alpha.txt
+|7: 2
+|8:
diff --git a/test/snapshots/stepgrain.golden b/test/snapshots/stepgrain.golden
index ef3cc49b..7f18d246 100644
--- a/test/snapshots/stepgrain.golden
+++ b/test/snapshots/stepgrain.golden
@@ -51,17 +51,23 @@
|8: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #f5f7ee,#3c614a, 20-149 d,#0d1410,
== snap step-row3 grid=150x31 cursor=7,10
== snap step-wrap grid=150x31 cursor=7,6
-== snap blank-in-path grid=150x31 cursor=7,13
-|12: /tmp/pardes-snap/stepgrain/cwd/+Search Save Tty Collapse Del
-|13: 1 two words.txt
-|14: 2
+== snap blank-in-path grid=150x31 cursor=7,6
+|5: /tmp/pardes-snap/stepgrain/cwd/+Search Save Tty Collapse Del
+|6: 1 two words.txt
+|7: 2
+|8:
+|9:
+|10:
+|11:
+|12:
== style blank-in-path grid=150x31
-|5: 0-1 #ffffff,#496656, 2-2 d,#1d2824, 3-33 #b2c3b8,#1d2824, 34-40 #d3b0d9,#1d2824, 41-78 #b2c3b8,#1d2824, 79-149 d,#1d2824,
-|6: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #f5f7ee,#3c614a, 19-149 d,#0d1410,
-|8: 0-0 d,#608269, 1-1 d,#0d1410, 2-19 #59675c,#0d1410, 20-149 d,#0d1410,
-|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #f7e4a5,#5e4923, 13-23 #e5eee5,#0d1410, 24-149 d,#0d1410,
-|12: 0-1 #000000,#add38a, 2-2 d,#314738, 3-33 #becfc4,#314738, 34-40 #dfbce5,#314738, 41-62 #becfc4,#314738, 63-149 d,#314738,
-|13: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #f5f7ee,#3c614a, 20-149 d,#0d1410,
-== snap blank-opened grid=150x31 cursor=7,16
-|15: /tmp/pardes-snap/stepgrain/cwd/two words.txt Save Tty Collapse Del
-|16: 1
+|5: 0-1 #000000,#add38a, 2-2 d,#314738, 3-33 #becfc4,#314738, 34-40 #dfbce5,#314738, 41-62 #becfc4,#314738, 63-149 d,#314738,
+|6: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #f5f7ee,#3c614a, 20-149 d,#0d1410,
+|7: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|8: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|9: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|10: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|11: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+== snap blank-opened grid=150x31 cursor=7,9
+|8: /tmp/pardes-snap/stepgrain/cwd/two words.txt Save Tty Collapse Del
+|9: 1