summaryrefslogtreecommitdiff
path: root/src/ninep/addr.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/addr.zig')
-rw-r--r--src/ninep/addr.zig47
1 files changed, 45 insertions, 2 deletions
diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig
index cc7ca632..0537c17a 100644
--- a/src/ninep/addr.zig
+++ b/src/ninep/addr.zig
@@ -14,8 +14,11 @@ fn clip(n: usize) u32 {
pub const e_no_match = "no match for regexp";
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";
+/// Not "took too long": 9ns reads errors by their words, and that would be
+/// ENAMETOOLONG.
+pub const e_slow = "regular expression search gave up, backtracking past its step budget";
pub const e_syntax = "bad address syntax";
+pub const e_order = "addresses out of order";
pub const Addr = struct {
text: []const u8,
@@ -93,7 +96,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 +248,44 @@ 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);
+
+ // `;` evaluates its right side from its left (acme's addr.c:170-171,
+ // `ar = r`), `,` from the address the whole started at.
+ const q = try th.withFile(testing.allocator, "b a b\n");
+ defer q.deinit();
+ const qaddr = Node.of(th.serialOf(q), .addr);
+ _ = th.wr(q, qaddr, "#0");
+ try testing.expectEqual(Status.ok, th.wr(q, qaddr, "/a/;/b/").reply.status);
+ try testing.expectEqual(@as(u32, 2), q.panes[0].?.fs.addr.q0);
+ try testing.expectEqual(@as(u32, 5), q.panes[0].?.fs.addr.q1);
+ _ = th.wr(q, qaddr, "#0");
+ try testing.expectEqualStrings(e_order, th.wr(q, qaddr, "/a/,/b/").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();