summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/look.zig11
-rw-r--r--src/ninep/ctl.zig19
-rw-r--r--test/pdf.zig6
3 files changed, 32 insertions, 4 deletions
diff --git a/src/look.zig b/src/look.zig
index 922504c0..105b7717 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -1357,9 +1357,11 @@ fn addressed(tok: []const u8) ?struct { path: []const u8, expr: []const u8 } {
if (std.mem.indexOfAny(u8, tok[0..colon], " \t") != null) return null;
if (std.mem.indexOfAny(u8, expr, " \t") != null and std.mem.indexOfAny(u8, expr, "/?") == null) return null;
if (expr.len == 0 or std.mem.indexOfScalar(u8, "0123456789+-/?$.#,;", expr[0]) == null) return null;
+ // `file:12` is a path's line, looked at as a path; a bare `:12` (`:12:5`)
+ // has no path, and is this pane's line, an address like any other.
if (std.ascii.isDigit(expr[0])) {
const pl = parsePathLine(tok);
- if (pl.at.line != 0 and pl.end == tok.len) return null;
+ if (pl.at.line != 0 and pl.end == tok.len and pl.path.len > 0) return null;
}
return .{ .path = tok[0..colon], .expr = expr };
}
@@ -1441,7 +1443,7 @@ 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 (comptime pdf_enabled) if (pane.pdf) |*pv| return lookPdfPage(p, id, target, pv, expr);
- if (by_serial and pane.isTerminal()) return lookTerminalAddress(p, id, target, expr);
+ if ((by_serial or path.len == 0) and pane.isTerminal()) return lookTerminalAddress(p, id, target, expr);
// Named as the pane is, the bare `:addr` (path empty) included.
var serial_name: [32]u8 = undefined;
const subject = if (pane.image) |iv| iv.path else if (path.len > 0) path else std.fmt.bufPrint(&serial_name, config.pane_addr ++ "{d}", .{pane.serial}) catch "the pane";
@@ -1469,8 +1471,9 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void {
/// 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 0;
- if (page == 0) return missed(p, id, "{s}: a PDF has no text to address; its address is a page, :N", .{missText(pv.path, &cut)});
+ 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)});
+ 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);
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index cdb6092a..fd3418a1 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1823,6 +1823,25 @@ test "Pager is a setting of the root ctl: pardes by default, off taken, anything
try testing.expectEqualStrings("bad value in control message; takes pardes, off \"Pager\"", wr(p, root_ctl, "Pager less\n").reply.ename);
}
+test "a bare :N or :N:M look addresses the pane itself, from its look, the root's and event write-back" {
+ const p = try withFile(testing.allocator, "alpha\nbeta\ngamma\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const pane = p.panes[p.paneBySerial(serial).?].?;
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .look), ":2\n").reply.status);
+ try testing.expectEqual(pane_files.State.Range{ .q0 = 6, .q1 = 11 }, pane_files.dotOf(pane));
+ try testing.expectEqual(Status.ok, wr(p, root_look, ":3\n").reply.status);
+ try testing.expectEqual(pane_files.State.Range{ .q0 = 11, .q1 = 17 }, pane_files.dotOf(pane));
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .look), ":3:2\n").reply.status);
+ try testing.expectEqual(@as(u32, 12), pane_files.dotOf(pane).q0);
+ // Written back by an event reader, the same.
+ const event = Node.of(serial, .event);
+ const h = call(p, .{ .tag = 1, .op = .open, .node = event }).reply.handle;
+ defer _ = call(p, .{ .tag = 9, .op = .release, .node = event, .handle = h });
+ try testing.expectEqual(Status.ok, wr(p, event, "ML0 0 0 2 :1\n").reply.status);
+ try testing.expectEqual(pane_files.State.Range{ .q0 = 0, .q1 = 6 }, pane_files.dotOf(pane));
+}
+
test "a refused Del written back through event fails that write, EIO, with its err" {
const gpa = testing.allocator;
const p = try withFile(gpa, "text\n");
diff --git a/test/pdf.zig b/test/pdf.zig
index 6864f247..d1dd5bb0 100644
--- a/test/pdf.zig
+++ b/test/pdf.zig
@@ -442,6 +442,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()) |_| {}
+ // Page 0 is no page: the has-no-page miss.
+ p.look_missed = false;
+ pardes.look.lookAt(p, 0, ":0");
+ try std.testing.expect(p.look_missed);
+ try std.testing.expect(std.mem.indexOf(u8, doc.msg[0..doc.msg_len], "has no page 0") != null);
+ p.look_missed = false;
// A byte offset or a pattern is no PDF address: refused with words.
pardes.look.lookAt(p, 0, ":#3");
try std.testing.expect(p.look_missed);