summaryrefslogtreecommitdiff
path: root/src/look.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 18:13:43 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commit09ef40318a3a3d1b9494e2a5fa41f71363929676 (patch)
tree2f01fa0ff91e1f9341b90f41acd03b72c2604da1 /src/look.zig
parent01bf4ed09423b3c7e01598ff3a844cc3c12c3ff2 (diff)
downloadpardes-09ef40318a3a3d1b9494e2a5fa41f71363929676.tar.gz
pardes-09ef40318a3a3d1b9494e2a5fa41f71363929676.zip
One look logs one err: a file:addr whose file is not there is one miss quoting what was written, and a refused placement is the look's only failure
A look at utf8txt:#3 from a terminal searched for utf8txt, missed, then found the terminal no text to address: two errs for one write. It is now looked for whole, as zzq:2 already was, so every form's miss reads no match for "<as written>". A look whose new pane was refused a place went on to settle its line in the pane it stayed on and logged has no line N after the placement failure; it now stops there. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/look.zig')
-rw-r--r--src/look.zig82
1 files changed, 49 insertions, 33 deletions
diff --git a/src/look.zig b/src/look.zig
index a29b27b5..fe5a3ac1 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -1302,6 +1302,41 @@ fn addressed(tok: []const u8) ?struct { path: []const u8, expr: []const u8 } {
return .{ .path = tok[0..colon], .expr = expr };
}
+/// A look at text that names nothing to open: a `./` name is a missing
+/// file, anything else a search for the text as written.
+fn lookUnresolved(p: *Pardes, id: usize, pane: *Pane, trimmed: []const u8) void {
+ // A `./` or `../` name opened nothing: said, ENOENT, not searched
+ // for as a word. What is missing is the pane's directory when
+ // that is gone, else the file named.
+ if (filesystem.dotRelative(trimmed)) {
+ const dir = Pardes.paneDir(pane);
+ var said: [4200]u8 = undefined;
+ const gone = if (comptime pardes.hosted) if (filesystem.localPath(dir)) |local| !exec.isDirectory(local) else false else true;
+ if (gone) return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such directory", .{dir[0..@min(dir.len, 4096)]}) catch "look: no such directory");
+ var cut: [miss_path_cap + "…".len]u8 = undefined;
+ return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such file", .{missText(trimmed, &cut)}) catch "look: no such file");
+ }
+ // 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;
+ if (p.settings.look_word == .search and pane.file != null) return lookWord(p, id, pane, trimmed);
+ const rows = runSearch(p, id, trimmed, .text, .cursor, false) catch |err| {
+ p.reportError(id, "search", err);
+ return;
+ };
+ if (rows == 0) {
+ var cut: [miss_path_cap + "…".len]u8 = undefined;
+ return missed(p, id, "no match for \"{s}\"", .{missText(trimmed, &cut)});
+ }
+ clearNavigationSelection(p, pane);
+ const at = pane.search_row;
+ _ = searchStep(p, id, 1);
+ if (at != null and pane.search_row == at) {
+ pane.search_row = null;
+ _ = searchStep(p, id, 1);
+ }
+}
+
/// Opens (or finds) `path` as Look would, `id`'s own pane when it is empty,
/// and selects what `expr` addresses there from its dot. An address that
/// does not evaluate moves nothing and says why (acme: no jump).
@@ -1321,9 +1356,18 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void {
const by_serial = std.mem.startsWith(u8, path, config.pane_addr);
if (by_serial and open == null) return missed(p, id, "no pane {s}", .{path[0..@min(path.len, 32)]});
if (open) |o| target = o else if (path.len > 0) {
+ // A path that names nothing to open: the whole of what was written
+ // is looked for, as `zzq:2` is, and a miss quotes it as written.
+ if (!by_serial and resolveLookTarget(p, id, path, &realbuf) == .none)
+ return lookUnresolved(p, id, p.panes[id] orelse return, path.ptr[0 .. path.len + 1 + expr.len]);
const before = p.active;
+ const failures = p.fs.failures;
+ const was_missed = p.look_missed;
lookAt(p, id, path);
target = p.active;
+ // Look said why it opened nothing (its placement refused, say):
+ // that one failure is the look's, no miss of the address after it.
+ if (p.fs.failures != failures or (p.look_missed and !was_missed)) return;
// The path opened nothing (a search, or no such file): Look said so.
if (target == before and target != id) return;
}
@@ -1484,39 +1528,7 @@ pub fn lookAt(p: *Pardes, id: usize, operand: []const u8) void {
pane.sel = @splat(.{});
}
switch (found) {
- .none => {
- // A `./` or `../` name opened nothing: said, ENOENT, not searched
- // for as a word. What is missing is the pane's directory when
- // that is gone, else the file named.
- if (filesystem.dotRelative(trimmed)) {
- const dir = Pardes.paneDir(pane);
- var said: [4200]u8 = undefined;
- const gone = if (comptime pardes.hosted) if (filesystem.localPath(dir)) |local| !exec.isDirectory(local) else false else true;
- if (gone) return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such directory", .{dir[0..@min(dir.len, 4096)]}) catch "look: no such directory");
- var cut: [miss_path_cap + "…".len]u8 = undefined;
- return p.reportFailure(id, std.fmt.bufPrint(&said, "look: {s}: no such file", .{missText(trimmed, &cut)}) catch "look: no such file");
- }
- // 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;
- if (p.settings.look_word == .search and pane.file != null) return lookWord(p, id, pane, trimmed);
- const rows = runSearch(p, id, trimmed, .text, .cursor, false) catch |err| {
- p.reportError(id, "search", err);
- return;
- };
- if (rows == 0) {
- var cut: [miss_path_cap + "…".len]u8 = undefined;
- return missed(p, id, "no match for \"{s}\"", .{missText(trimmed, &cut)});
- }
- clearNavigationSelection(p, pane);
- const at = pane.search_row;
- _ = searchStep(p, id, 1);
- if (at != null and pane.search_row == at) {
- pane.search_row = null;
- _ = searchStep(p, id, 1);
- }
-
- },
+ .none => lookUnresolved(p, id, pane, trimmed),
.pane => |t| {
// `@p<serial>` names no open pane: a miss, said.
if (t.id >= MAX_PANES or p.panes[t.id] == null) return missed(p, id, "no pane {s}", .{pl.path[0..@min(pl.path.len, 32)]});
@@ -1573,7 +1585,11 @@ pub fn lookAt(p: *Pardes, id: usize, operand: []const u8) void {
const nt = panes.File.open(p, free, target.path, target.at.line) catch |err|
return p.reportError(id, if (@import("Messages.zig").dialReason(err) != null) target.path else "look", err);
if (target.at.col > 0) nt.body.cur_col = @intCast(target.at.col - 1);
+ const failures = p.fs.failures;
exec.placeNew(p, id, id, free, .doc);
+ // Refused a place: that is the look's one failure, not a
+ // miss of its line too.
+ if (p.fs.failures != failures) return;
layout.compute(p);
nt.file.?.scroll -|= @max(1, p.rects[free].h -| BOX_H) / 2;
if (target.at.end_line != 0) {