From bb9a5f19cf0ea6944fd8c67503e09aa5a2da4355 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Thu, 1 Oct 2026 06:32:21 -0300 Subject: `:N:H` looked at on a PDF pane turns to page N, as `book.pdf:N:H` does from anywhere, not a refusal that a PDF has no text A PDF's own pane took only `:N`; `:5:3` was refused as no text to address while `book.pdf:5:3` turned to page 5 (its search hit 3). lookPdfPage now reads the page before a colon and the hit after it. Co-Authored-By: Claude Opus 5.5 --- src/look.zig | 16 +++++++++++----- test/pdf.zig | 6 ++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/look.zig b/src/look.zig index 21148b37..3ae0578c 100644 --- a/src/look.zig +++ b/src/look.zig @@ -1481,17 +1481,23 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void { } /// A PDF's address is its page: `:N` turns to page N, one past its last a -/// miss. It has no text to hold a byte offset (`#N`) or a pattern: any -/// other address is refused with what it takes. +/// miss, and `:N:H` to page N's search hit H, as `book.pdf:N:H` (a PDF +/// search's row) does. It has no text to hold a byte offset (`#N`) or a +/// pattern: any other address is refused with what it takes. fn lookPdfPage(p: *Pardes, id: usize, target: usize, pv: anytype, expr: []const u8) void { var cut: [miss_path_cap + "…".len]u8 = undefined; - const page = std.fmt.parseInt(usize, std.mem.trim(u8, expr, " \t"), 10) catch - return missed(p, id, "{s}: a PDF has no text to address; its address is a page, :N", .{missText(pv.path, &cut)}); + const trimmed = std.mem.trim(u8, expr, " \t"); + const colon = std.mem.indexOfScalar(u8, trimmed, ':') orelse trimmed.len; + const no_text = "{s}: a PDF has no text to address; its address is a page, :N"; + const page = std.fmt.parseInt(usize, trimmed[0..colon], 10) catch + return missed(p, id, no_text, .{missText(pv.path, &cut)}); + const hit = if (colon < trimmed.len) std.fmt.parseInt(usize, trimmed[colon + 1 ..], 10) catch + return missed(p, id, no_text, .{missText(pv.path, &cut)}) else 0; if (page == 0) return missedPage(p, id, pv.path, 0); if (page > pv.page_count) return missedPage(p, id, pv.path, page); const pane = p.panes[target].?; clearNavigationSelection(p, pane); - if (pv.focusLocation(p.pdf_gpa, page, 0)) panes.Pdf.resetPageChrome(pane); + if (pv.focusLocation(p.pdf_gpa, page, hit)) panes.Pdf.resetPageChrome(pane); p.active = target; } diff --git a/test/pdf.zig b/test/pdf.zig index 727a1515..a1be4075 100644 --- a/test/pdf.zig +++ b/test/pdf.zig @@ -492,6 +492,12 @@ test "`:N` on a PDF turns to page N, from the pane and from the root's look, and try std.testing.expect(std.mem.indexOf(u8, record, "\nerr ") == null); _ = p.serveFs(.{ .tag = 4, .op = .release, .node = log, .handle = h }); while (p.nextEffect()) |_| {} + // `:N:H` on the pane is its page N, as `file.pdf:N:H` is. + p.look_missed = false; + pardes.look.lookAt(p, 0, ":1"); + pardes.look.lookAt(p, 0, ":2:3"); + try std.testing.expect(!p.look_missed); + try std.testing.expectEqual(@as(usize, 1), doc.pdf.?.page); // Page 0 is no page: the has-no-page miss. p.look_missed = false; pardes.look.lookAt(p, 0, ":0"); -- cgit v1.3