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.zig44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig
index 9498df19..09ef2b66 100644
--- a/src/ninep/addr.zig
+++ b/src/ninep/addr.zig
@@ -110,6 +110,35 @@ pub const Addr = struct {
}
const q = clip(modal.runeOffsetAt(a.text, .{ .row = @intCast(n - 1), .col = @intCast(col - 1) }));
r = .{ .q0 = q, .q1 = q };
+ // The rows' range, `L:C-L2:C2` or `L:C-C2` (Recent,
+ // +Search, Jumplist): through its last character,
+ // inclusive, as the rows mean it -- so a row pastes in.
+ if (a.i + 1 < a.expr.len and a.expr[a.i] == '-' and a.expr[a.i + 1] >= '1' and a.expr[a.i + 1] <= '9') {
+ a.i += 1;
+ var n2: u64 = 0;
+ while (a.i < a.expr.len and a.expr[a.i] >= '0' and a.expr[a.i] <= '9') : (a.i += 1)
+ n2 = @min(n2 * 10 + (a.expr[a.i] - '0'), std.math.maxInt(u32));
+ var end_line = n;
+ var end_col = n2;
+ if (a.i + 1 < a.expr.len and a.expr[a.i] == ':' and a.expr[a.i + 1] >= '0' and a.expr[a.i + 1] <= '9') {
+ a.i += 1;
+ end_line = n2;
+ end_col = 0;
+ while (a.i < a.expr.len and a.expr[a.i] >= '0' and a.expr[a.i] <= '9') : (a.i += 1)
+ end_col = @min(end_col * 10 + (a.expr[a.i] - '0'), std.math.maxInt(u32));
+ }
+ if (end_line == 0 or end_line > lines or end_col == 0) {
+ a.err = if (end_col == 0) e_col_zero else e_range;
+ return null;
+ }
+ const last = modal.runeOffsetAt(a.text, .{ .row = @intCast(end_line - 1), .col = @intCast(end_col - 1) });
+ const e = clip(@min(a.text.len, last + (std.unicode.utf8ByteSequenceLength(if (last < a.text.len) a.text[last] else 'x') catch 1)));
+ if (e < q) {
+ a.err = e_order;
+ return null;
+ }
+ r.q1 = e;
+ }
continue;
}
r = a.number(r, @intCast(n), dir, size) orelse return null;
@@ -348,6 +377,21 @@ test "an address is evaluated from the current one, as acme's are" {
try testing.expectEqualStrings(e_order, th.wr(q, qaddr, "/a/,/b/").reply.ename);
}
+test "a row's range, L:C-L2:C2 or L:C-C2, is an address through its last character" {
+ const p = try th.withFile(testing.allocator, "one\ntwo three\nfour\n");
+ defer p.deinit();
+ const addr = Node.of(th.serialOf(p), .addr);
+ const data = Node.of(th.serialOf(p), .xdata);
+ try testing.expectEqual(Status.ok, th.wr(p, addr, "2:5-2:9").reply.status);
+ try testing.expectEqualStrings("three", th.rd(p, data, 0, 64).bytes);
+ try testing.expectEqual(Status.ok, th.wr(p, addr, "2:1-3").reply.status);
+ try testing.expectEqualStrings("two", th.rd(p, data, 0, 64).bytes);
+ try testing.expectEqual(Status.ok, th.wr(p, addr, "1:2-3:2").reply.status);
+ try testing.expectEqualStrings("ne\ntwo three\nfo", th.rd(p, data, 0, 64).bytes);
+ try testing.expectEqualStrings(e_order, th.wr(p, addr, "2:5-1:1").reply.ename);
+ try testing.expectEqualStrings(e_range, th.wr(p, addr, "2:1-9:1").reply.ename);
+}
+
test "an empty match at the search's start is passed over, as sam's nextmatch does" {
const p = try th.withFile(testing.allocator, "ab\ncd\nef\n");
defer p.deinit();