summaryrefslogtreecommitdiff
path: root/src/look.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/look.zig')
-rw-r--r--src/look.zig44
1 files changed, 38 insertions, 6 deletions
diff --git a/src/look.zig b/src/look.zig
index 39f7420e..ca9aa80a 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/<peer>/) 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) {
@@ -612,10 +616,18 @@ 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,
+ };
+ nrows = std.mem.count(u8, out[0..out_len], "\n");
} else if (kind == .find) {
out_len = try filesystem.find(arena, dir, pat, out);
+ nrows = std.mem.count(u8, out[0..out_len], "\n");
} else if (pane.hasPdf()) {
if (comptime pdf_enabled) {
const found = try panes.Pdf.searchRows(
@@ -655,7 +667,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 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
@@ -1110,7 +1122,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;
}
@@ -1390,8 +1403,14 @@ pub fn lookAt(p: *Pardes, id: usize, operand: []const u8) void {
const found = resolveLookTarget(p, id, txt, &realbuf);
// A line past the end of an open pane is a miss (the target's line is
// already clamped, so the one written is asked).
- if (found == .pane and found.pane.id < MAX_PANES) if (p.panes[found.pane.id]) |shown| if (shown.file) |*f| if (pl.at.line > panes.File.nlines(p.gpa, f))
- return missedLine(p, id, trimmed, pl.at.line);
+ if (found == .pane and found.pane.id < MAX_PANES) if (p.panes[found.pane.id]) |shown| {
+ // A terminal's lines are its logical lines, as a +Search lists them.
+ const n = if (shown.file) |*f| panes.File.nlines(p.gpa, f) else if (shown.isTerminal())
+ if (edit.paneCursorLines(p, &shown.body)) |ls| ls.len else |_| std.math.maxInt(usize)
+ else
+ std.math.maxInt(usize);
+ if (pl.at.line > n) return missedLine(p, id, trimmed, pl.at.line);
+ };
// A miss changes nothing, the selection included; a look that stays in
// this pane starts from a clean one. One that goes to another pane
// leaves this one's dot alone, as acme's does: only the click's own
@@ -1404,6 +1423,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;
@@ -1436,6 +1462,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);