diff options
Diffstat (limited to 'src/ninep/addr.zig')
| -rw-r--r-- | src/ninep/addr.zig | 87 |
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; |
