summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/addr.zig87
1 files changed, 11 insertions, 76 deletions
diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig
index 95e699e3..347a2d11 100644
--- a/src/ninep/addr.zig
+++ b/src/ninep/addr.zig
@@ -1,7 +1,7 @@
//! The address language of a pane's `addr` file, acme's (editors/acme/
-//! addr.c), its regular expressions run by mvzr the way sam's run.
+//! addr.c), its regular expressions searched as sam searches (regexp.zig).
const std = @import("std");
-const mvzr = @import("mvzr");
+const regexp_ = @import("../regexp.zig");
const modal = @import("../modal.zig");
const pane_files = @import("pane.zig");
@@ -196,92 +196,27 @@ pub const Addr = struct {
a.err = "no previous regular expression";
return null;
}
- // sam searches the text as lines: `^` and `$` at any line's start
- // and end, and `.` never a newline. mvzr has no such mode (its `^`
- // and `$` are the haystack's ends, its `.` any byte), so each line
- // is its own haystack, and a pattern that names a newline (`\n`)
- // runs over the whole text with its `.`s made `[^\n]`.
- // ponytail: mvzr takes the first alternative that matches, not
- // sam's longest (`/gam|gamma/` finds `gam`); a search from the middle
- // of a line lets `^` match there unless the pattern starts with it;
- // across lines, `^`, `$` and `[^...]` keep mvzr's meaning. A regex
- // engine of sam's own would lift these; the user chose not to.
- const spans = std.mem.indexOf(u8, pat, "\\n") != null;
- var buf: [256]u8 = undefined;
- var len: usize = 0;
- var i: usize = 0;
- var in_class = false;
- while (i < pat.len) : (i += 1) {
- const c = pat[i];
- const piece: []const u8 = if (c == '\\') piece: {
- if (i + 1 >= pat.len) break :piece "";
- i += 1;
- break :piece pat[i - 1 .. i + 1];
- } else if (c == '.' and spans and !in_class) "[^\\n]" else pat[i .. i + 1];
- if (piece.len == 0 or len + piece.len > buf.len) {
- a.err = e_regexp;
- return null;
- }
- if (c == '[') in_class = true;
- if (c == ']') in_class = false;
- @memcpy(buf[len..][0..piece.len], piece);
- len += piece.len;
- }
- const re = mvzr.compile(buf[0..len]) orelse {
+ const rx = regexp_.Regex.compile(pat) orelse {
a.err = e_regexp;
return null;
};
- const anchored = pat[0] == '^';
- const Search = struct {
- /// The first match starting in `from..=last` that ends by `hi`.
- fn first(rx: *const mvzr.Regex, text: []const u8, from: usize, last: usize, hi: usize, whole: bool, bol: bool) ?Range {
- if (whole) {
- const m = rx.matchPos(from, text[0..hi]) orelse return null;
- return if (m.start <= last) .{ .q0 = clip(m.start), .q1 = clip(m.end) } else null;
- }
- var start = if (std.mem.lastIndexOfScalar(u8, text[0..from], '\n')) |nl| nl + 1 else 0;
- var at = from - start;
- // `^` cannot match in the middle of a line.
- if (bol and at > 0) {
- start = (std.mem.indexOfScalarPos(u8, text[0..hi], from, '\n') orelse return null) + 1;
- at = 0;
- }
- while (start <= hi and start <= last) {
- const end = std.mem.indexOfScalarPos(u8, text[0..hi], start, '\n') orelse hi;
- const line = text[start..end];
- // matchPos finds nothing at a line's very end, where
- // `$` or an empty pattern still match.
- const hit: ?[2]usize = if (at < line.len)
- (if (rx.matchPos(at, line)) |m| .{ m.start, m.end } else null)
- else if (at == line.len and rx.isMatch(line[at..])) .{ at, at } else null;
- if (hit) |h| {
- if (start + h[0] > last) return null;
- return .{ .q0 = clip(start + h[0]), .q1 = clip(start + h[1]) };
- }
- if (end == hi) return null;
- start = end + 1;
- at = 0;
- }
- return null;
- }
- };
- const found: ?Range = if (back) found: {
+ const found = if (back) found: {
var last: ?Range = null;
var before: ?Range = null;
var at: usize = 0;
while (at <= a.text.len) {
- const m = Search.first(&re, a.text, at, a.text.len, a.text.len, spans, anchored) orelse break;
- if (m.q1 <= r.q0) before = m;
- last = m;
- at = if (m.q1 > m.q0) m.q1 else m.q1 + 1;
+ const m = rx.find(a.text, at, a.text.len, a.text.len) orelse break;
+ const found_range: Range = .{ .q0 = clip(m.start), .q1 = clip(m.end) };
+ if (found_range.q1 <= r.q0) before = found_range;
+ last = found_range;
+ at = if (m.end > m.start) m.end else m.end + 1;
}
break :found before orelse last;
} else found: {
const hi = if (a.lim) |l| @min(@as(usize, l.q1), a.text.len) else a.text.len;
const from = @min(@as(usize, r.q1), hi);
- if (Search.first(&re, a.text, from, hi, hi, spans, anchored)) |m| break :found m;
- if (a.lim != null or from == 0) break :found null;
- break :found Search.first(&re, a.text, 0, from - 1, hi, spans, anchored);
+ const m = rx.find(a.text, from, hi, hi) orelse (if (a.lim != null or from == 0) null else rx.find(a.text, 0, from - 1, hi)) orelse break :found null;
+ break :found Range{ .q0 = clip(m.start), .q1 = clip(m.end) };
};
return found orelse {
a.err = e_no_match;