summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 06:07:10 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commitb88e6ddf653b6031b906493807b475395c4ae3c4 (patch)
tree3692c1ca35c205ddae9f908a769f999b251f3024
parent98ed98178b667e551ff2bcaeb981e70d1f6ccb1f (diff)
downloadpardes-b88e6ddf653b6031b906493807b475395c4ae3c4.tar.gz
pardes-b88e6ddf653b6031b906493807b475395c4ae3c4.zip
@p<serial>:<address> takes any sam address, as file:<address> does
@p<serial> took a line spot but an address after it (/re/, #n, $, 0/re/, a range) was dropped, the name failing the file check, and an unknown serial fell through to a search. The pane is now addressed like a file; a miss and a serial no pane has each log an err, and look reads back empty. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--docs/fs.md5
-rw-r--r--src/look.zig7
-rw-r--r--src/ninep/ctl.zig27
3 files changed, 36 insertions, 3 deletions
diff --git a/docs/fs.md b/docs/fs.md
index 07b380aa..45a64e44 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -442,7 +442,10 @@ whose `{` or `a`/`c`/`i` text never ended fails and changes nothing
unfinished was cut short. A fragment never runs on its
own. A line or Edit block held past 1 MiB is refused (EINVAL).
-A look takes acme's addresses after a colon (editors/acme/look.c:450): a
+`@p<serial>:<address>` addresses the pane with that serial as `file:<address>`
+does a file, with any sam address (`/re/`, `#n`, `$`, `0/re/`, a range); a
+miss, and a serial no pane has, each log an `err`, and look reads back
+empty. A look takes acme's addresses after a colon (editors/acme/look.c:450): a
line written to `look` as `file:/re/`, `file:#n`, `file:$` or any address
opens (or finds) the file and selects what the address names. **The
address is evaluated from the file's dot**, as acme's is: `file:/re/`
diff --git a/src/look.zig b/src/look.zig
index 8318973b..6a4fe1d1 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -1289,6 +1289,9 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void {
.pane => |t| if (t.id < MAX_PANES and p.panes[t.id] != null) t.id else null,
else => null,
};
+ // `@p<serial>:<address>`: that pane, or, not open, a miss said as one.
+ 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) {
const before = p.active;
lookAt(p, id, path);
@@ -1297,8 +1300,8 @@ fn lookAddress(p: *Pardes, id: usize, path: []const u8, expr: []const u8) void {
if (target == before and target != id) return;
}
const pane = p.panes[target] orelse return;
- const f = pane.file orelse return;
- if (path.len > 0 and (f.output != null or !std.mem.endsWith(u8, f.path, std.fs.path.basename(path)))) return;
+ const f = pane.file orelse return missed(p, id, "{s} is no text to address", .{path[0..@min(path.len, 64)]});
+ 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 };
const r = a.address(ninep_pane.dotOf(pane)) orelse {
return missed(p, id, "{s}", .{a.err});
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index d623296b..bed53473 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1890,3 +1890,30 @@ test "a word written to a raw terminal's look is listed as in normal mode" {
const made = p.panes[p.paneBySerial(try std.fmt.parseInt(u32, said, 10)).?].?;
try testing.expect(made.file.?.output.?.from == .search);
}
+
+test "@p<serial>:<address> takes any sam address; a miss and an unknown serial are errs" {
+ const p = try withFile(testing.allocator, "foo x foo y\nbar\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const root = @intFromEnum(tree.TopFile.look);
+ const dot = Node.of(serial, .dot);
+ const Case = struct { addr: []const u8, want: []const u8 };
+ for ([_]Case{
+ .{ .addr = "0/foo/", .want = " 0 3 " },
+ .{ .addr = "/foo/", .want = " 6 9 " },
+ .{ .addr = "#12,#15", .want = " 12 15 " },
+ .{ .addr = "$", .want = " 16 16 " },
+ .{ .addr = "1,2", .want = " 0 16 " },
+ }) |c| {
+ var line: [64]u8 = undefined;
+ try testing.expectEqual(Status.ok, wr(p, root, try std.fmt.bufPrint(&line, "@p{d}:{s}\n", .{ serial, c.addr })).reply.status);
+ try testing.expectEqualStrings(c.want, rd(p, dot, 0, 64).bytes);
+ }
+ var line: [64]u8 = undefined;
+ _ = wr(p, root, try std.fmt.bufPrint(&line, "@p{d}:/zzqq/\n", .{serial}));
+ try testing.expect(th.logHas(p, "look: no match for regexp"));
+ try testing.expectEqualStrings("", rd(p, root, 0, 64).bytes);
+ _ = wr(p, root, "@p999:/foo/\n");
+ try testing.expect(th.logHas(p, "look: no pane @p999"));
+ try testing.expectEqualStrings("", rd(p, root, 0, 64).bytes);
+}