diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 13:14:20 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 41fb292f314844d1f47e608fbdd4a34cfc8d5618 (patch) | |
| tree | 5f0b6f9bd6feddb88881623a6d990bcab454021e /src | |
| parent | 84fca2d6e5f498f2d4384712d49d727a25441d68 (diff) | |
| download | pardes-41fb292f314844d1f47e608fbdd4a34cfc8d5618.tar.gz pardes-41fb292f314844d1f47e608fbdd4a34cfc8d5618.zip | |
An address searches back after a minus, and a range ending before its start is refused
-/re/ searched forward, since only ?re? set the direction, where acme's
address() takes the direction a minus set (addr.c). And #100,#50 was taken,
leaving data to act on an empty range at 100; sam refuses it as 'addresses out
of order', which acme leaves out, and so does pardes now. The rest of the
dogfood report on addresses already held and is now tested: an expression is
evaluated from the current address, as acme evaluates it from w->addr
(xfid.c:446), so a search starts where the last address or data write left
it and . is that address. Taking . as the selection instead, as the report
asked, would part from acme, which has dot only in its ctl messages; the docs
say which is which.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ninep/addr.zig | 31 | ||||
| -rw-r--r-- | src/ninep/pane.zig | 10 |
2 files changed, 38 insertions, 3 deletions
diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig index cc7ca632..6656c786 100644 --- a/src/ninep/addr.zig +++ b/src/ninep/addr.zig @@ -16,6 +16,7 @@ pub const e_range = "address out of range"; pub const e_regexp = "bad regular expression"; pub const e_slow = "regular expression search took too long"; pub const e_syntax = "bad address syntax"; +pub const e_order = "addresses out of order"; pub const Addr = struct { text: []const u8, @@ -93,7 +94,9 @@ pub const Addr = struct { size = .line; }, '/', '?' => { - const back = c == '?'; + // `-/re/` searches back as `?re?` does (acme's address() + // takes the direction a `-` set, addr.c). + const back = c == '?' or dir == '-'; r = a.regexp(r, a.pattern(c), back) orelse return null; dir = 0; size = .line; @@ -243,6 +246,32 @@ const Node = tree.Node; const E = tree.E; const Status = tree.Status; +test "an address is evaluated from the current one, as acme's are" { + const p = try th.withFile(testing.allocator, "a foo b foo c foo\n"); + defer p.deinit(); + const addr = Node.of(th.serialOf(p), .addr); + const Step = struct { expr: []const u8, q0: u32, q1: u32 }; + _ = th.wr(p, addr, "#0"); + for ([_]Step{ + // each search starts where the last address ended + .{ .expr = "/foo/", .q0 = 2, .q1 = 5 }, + .{ .expr = "/foo/", .q0 = 8, .q1 = 11 }, + // `.` is that address, and `-` before a pattern searches back + .{ .expr = ".", .q0 = 8, .q1 = 11 }, + .{ .expr = "-/foo/", .q0 = 2, .q1 = 5 }, + .{ .expr = "./foo/", .q0 = 8, .q1 = 11 }, + .{ .expr = "+/foo/", .q0 = 14, .q1 = 17 }, + // a number then a pattern: the search starts at the number + .{ .expr = "#9/foo/", .q0 = 14, .q1 = 17 }, + }) |c| { + try testing.expectEqual(Status.ok, th.wr(p, addr, c.expr).reply.status); + try testing.expectEqual(c.q0, p.panes[0].?.fs.addr.q0); + try testing.expectEqual(c.q1, p.panes[0].?.fs.addr.q1); + } + // A range whose end comes before its start is sam's error. + try testing.expectEqualStrings(e_order, th.wr(p, addr, "#10,#5").reply.ename); +} + test "regular expressions search lines as sam's do, and a search wraps" { const p = try th.withFile(testing.allocator, "alpha beta\nbeta gamma\ngamma\n"); defer p.deinit(); diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index 0a511118..6b6d5728 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -453,16 +453,22 @@ pub const e_addr_failed = "no address: the last one written to addr failed"; /// A range file takes an address expression, or that pair of offsets. One /// that does not evaluate says why: `bad address syntax`, `no match for -/// regexp`, `address out of range`, `bad regular expression`. +/// regexp`, `address out of range`, `bad regular expression`, `addresses +/// out of order`. fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply { const pf = &pane.fs; const text = bodyOf(pane); clampAddr(pf, text.len); const expr = std.mem.trimEnd(u8, req.data, "\n"); var a: addressing.Addr = .{ .text = text, .lim = pf.limit, .expr = expr }; - const r = if (pairOf(expr)) |pair| + var r = if (pairOf(expr)) |pair| State.Range{ .q0 = @min(pair.q0, clip(text.len)), .q1 = @min(pair.q1, clip(text.len)) } else if (a.address(pf.addr)) |found| (if (a.i < expr.len) null else found) else null; + // sam's check, which acme leaves out: `#100,#50` names no range. + if (r) |found| if (found.q0 > found.q1) { + a.err = addressing.e_order; + r = null; + }; const range = r orelse { if (file == .addr) pf.addr_failed = true; return tree.failText(req.tag, E.INVAL, a.err); |
