summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/builtins.zig3
-rw-r--r--src/look.zig10
-rw-r--r--src/ninep/ctl.zig23
3 files changed, 33 insertions, 3 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index 3f4a680c..59fc140d 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -1339,7 +1339,8 @@ pub const Grep = struct {
pub fn run(c: Ctx) void {
const pat = std.mem.trim(u8, c.arg orelse "", " \t\r\n");
if (pat.len > 0) {
- _ = look.runSearch(c.p, c.id, pat, .grep, .top, true) catch |err| c.p.reportError(c.id, "grep", err);
+ const rows = look.runSearch(c.p, c.id, pat, .grep, .top, false) catch |err| return c.p.reportError(c.id, "grep", err);
+ if (rows == 0) c.p.reportFailure(c.id, "grep: no match");
return;
}
c.p.startPrompt(c.pane, &c.pane.body, .{ .search = config.grep_marker });
diff --git a/src/look.zig b/src/look.zig
index 87dcede3..ba022bef 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -612,8 +612,14 @@ pub fn runSearch(p: *Pardes, id: usize, pat_raw: []const u8, kind: Search, start
roots[nroots] = d;
nroots += 1;
}
+ // A pane's directory that is not there (a scratch named into one
+ // not made yet, a peer's) has nothing to grep: passed over, not the
+ // search's failure.
for (roots[0..nroots]) |r|
- out_len += try filesystem.grep(arena, p.gpa, r, dir, pat, out[out_len..]);
+ out_len += filesystem.grep(arena, p.gpa, r, dir, pat, out[out_len..]) catch |err| switch (err) {
+ error.FileNotFound, error.NotDir, error.AccessDenied => continue,
+ else => return err,
+ };
} else if (kind == .find) {
out_len = try filesystem.find(arena, dir, pat, out);
} else if (pane.hasPdf()) {
@@ -655,7 +661,7 @@ pub fn runSearch(p: *Pardes, id: usize, pat_raw: []const u8, kind: Search, start
nrows += 1;
}
}
- if (!open_empty and kind == .text and nrows == 0) return 0;
+ if (!open_empty and (kind == .text or kind == .grep) and nrows == 0) 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 1ef9a2f6..330b9cb7 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1819,6 +1819,29 @@ test "a builtin that needs its argument, written bare to an exec, is EINVAL as t
}
}
+test "Grep with no hit says grep: no match and opens nothing, a missing pane directory passed over" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ var tmp = testing.tmpDir(.{});
+ defer tmp.cleanup();
+ try tmp.dir.writeFile(testing.io, .{ .sub_path = "a.txt", .data = "alpha\n" });
+ var dir_buf: [4096]u8 = undefined;
+ 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 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");
+ var count: usize = 0;
+ for (p.panes) |slot| count += @intFromBool(slot != null);
+ const missed = wr(p, Node.of(serialOf(p), .exec), "Grep zzqqnomatchzz\n");
+ try testing.expectEqual(E.IO, missed.errno());
+ try testing.expectEqualStrings("grep: no match", missed.reply.ename);
+ var after: usize = 0;
+ for (p.panes) |slot| after += @intFromBool(slot != null);
+ try testing.expectEqual(count, after);
+}
+
test "size is monotonic: growing is never refused, and a size once taken is taken again" {
const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 160, .rows = 60 });
defer p.deinit();