summaryrefslogtreecommitdiff
path: root/src/look.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/look.zig')
-rw-r--r--src/look.zig47
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);