diff options
Diffstat (limited to 'src/look.zig')
| -rw-r--r-- | src/look.zig | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/src/look.zig b/src/look.zig index afb5b760..36b91545 100644 --- a/src/look.zig +++ b/src/look.zig @@ -1218,17 +1218,29 @@ pub fn followPdfLink(p: *Pardes, id: usize, probe: *const panes.Pdf.WordProbe) v /// A look that found nothing: said on the message row, logged as an `err` /// record, and marked so that /look reads back nothing (ninep/ctl.zig run). -/// The most of a looked-at path or text a miss repeats; past it, cut on a -/// character boundary and ended with `…`. +/// The most of a looked-at path or text a miss repeats; past it, its +/// middle gives up to `…` (the Rerror cutter's rule), so the file's name at +/// the end stays. const miss_path_cap = 256; fn missText(text: []const u8, buf: *[miss_path_cap + "…".len]u8) []const u8 { - if (text.len <= miss_path_cap) return text; - var n: usize = miss_path_cap; - while (n > 0 and text[n] & 0xC0 == 0x80) n -= 1; - @memcpy(buf[0..n], text[0..n]); - @memcpy(buf[n..][0.."…".len], "…"); - return buf[0 .. n + "…".len]; + return pardes.ctlfs.fitErr(text, buf[0..miss_path_cap]); +} + +test "a miss names a long path by its start and its end, its middle given up to …" { + var cut: [miss_path_cap + "…".len]u8 = undefined; + const long = "/home/someone/" ++ "deep/" ** 80 ++ "the-file.zig"; + const said = missText(long, &cut); + try std.testing.expect(said.len <= miss_path_cap); + try std.testing.expect(std.mem.startsWith(u8, said, "/home/someone/")); + try std.testing.expect(std.mem.endsWith(u8, said, "/the-file.zig")); + try std.testing.expect(std.mem.indexOf(u8, said, "…") != null); + try std.testing.expectEqualStrings("short/path.txt", missText("short/path.txt", &cut)); +} + +fn missedPage(p: *Pardes, id: usize, path: []const u8, page: usize) void { + var cut: [miss_path_cap + "…".len]u8 = undefined; + missed(p, id, "{s} has no page {d}", .{ missText(path, &cut), page }); } fn missedLine(p: *Pardes, id: usize, path: []const u8, line: anytype) void { @@ -1402,7 +1414,8 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void { const pane = p.panes[target] orelse return; const f = pane.file orelse { if (by_serial and pane.isTerminal()) return lookTerminalAddress(p, id, target, expr); - return missed(p, id, "{s} is no text to address", .{path[0..@min(path.len, 64)]}); + var cut: [miss_path_cap + "…".len]u8 = undefined; + return missed(p, id, "{s} is no text to address", .{missText(path, &cut)}); }; if (!by_serial and path.len > 0 and (f.output != null or !std.mem.endsWith(u8, f.path, std.fs.path.basename(path)))) return; var a: Addr = .{ .text = f.content, .lim = null, .expr = expr }; @@ -1468,6 +1481,11 @@ pub fn reopenAt(p: *Pardes, from: usize, path: []const u8, at: Spot) void { lookAt(p, from, path); const id = p.active; const pane = p.panes[id] orelse return; + // A PDF's place is its page, the last if it has fewer now. + if (comptime pdf_enabled) if (pane.pdf) |*pv| if (std.mem.eql(u8, pv.path, path)) { + if (at.line > 0 and pv.focusLocation(p.pdf_gpa, @min(at.line, pv.page_count), 0)) panes.Pdf.resetPageChrome(pane); + return; + }; const f = if (pane.file) |*file| file else return; if (!std.mem.eql(u8, f.path, path)) return; // The empty "line" after a final newline is no line to land on. @@ -1680,6 +1698,11 @@ pub fn lookAt(p: *Pardes, id: usize, operand_raw: []const u8) void { // `@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)]}); const target = p.panes[t.id].?; + // A PDF's page past its last is a miss, as a line past a file's + // end is: never the last page in its place (opening one, the + // same: Pdf.openPane's .refuse). + if (comptime pdf_enabled) if (target.pdf) |pv| if (t.at.line > pv.page_count) + return missedPage(p, id, pv.path, t.at.line); const before = p.active; clearNavigationSelection(p, target); focusPaneLine(p, t.id, t.at, .center); @@ -1710,8 +1733,10 @@ pub fn lookAt(p: *Pardes, id: usize, operand_raw: []const u8) void { if (comptime pdf_enabled) if (target.kind == .pdf) { if (focusPaneByPath(p, target.path, target.at)) return; const free = p.freeSlot() orelse return p.reportError(id, "look", error.NoPaneSlots); - // Said with its path and why, as an image that cannot be read is. - _ = panes.Pdf.openPane(p, free, target.path, target.at.line) catch |err| { + // Said with its path and why, as an image that cannot be read + // is; a page past its last is a miss, as for an open one. + _ = panes.Pdf.openPane(p, free, target.path, target.at.line, .refuse) catch |err| { + if (err == error.NoSuchPage) return missedPage(p, id, target.path, target.at.line); var said: [miss_path_cap + 64]u8 = undefined; var cut: [miss_path_cap + "…".len]u8 = undefined; return p.reportError(id, std.fmt.bufPrint(&said, "look: {s}: not a PDF pardes can read", .{missText(target.path, &cut)}) catch "look: not a PDF pardes can read", err); |
