diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 18:13:43 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 09ef40318a3a3d1b9494e2a5fa41f71363929676 (patch) | |
| tree | 2f01fa0ff91e1f9341b90f41acd03b72c2604da1 /src/look.zig | |
| parent | 01bf4ed09423b3c7e01598ff3a844cc3c12c3ff2 (diff) | |
| download | pardes-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.zig | 82 |
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) { |
