From 83df7c5a4bed79c53357fd91c393071de1eb60a2 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Wed, 31 Dec 2025 05:43:46 -0500 Subject: add (hacky and slow) reverse regex search --- main.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 19 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 70a25a6..cee28a8 100644 --- a/main.c +++ b/main.c @@ -54,7 +54,8 @@ typedef struct { EditMode mode; u32 count; Str input_line, input_prompt; - Str last_search; + Str search; + int search_dir; } Editor; Editor e = { 0 }; @@ -522,8 +523,60 @@ search_from_start: return 0; } +int search_prev_regex(TxtLoc start, Str src, TxtLoc *out) { + RegEx re = { 0 }; + ReSearch s = { 0 }; + if (re_comp_ex(&re, src, &e.scratch, &e.scratch, RE_COMP_NO_GROUPS)) { + /* TODO: report parse error */ + return 0; + } + int match_found = 0; + TxtLoc end = txt_end(start.t); + TxtLoc l = start; +search_from_end: + for (;;) { + ReMatch m; + Arena a = e.scratch; + re_search_start(&s, &re, &e.scratch); + TxtLoc t = l; + while (!at_end(t)) { + TxtLoc p = t; + Str chnk = txt_next_chunk(&t); + re_search_chunk(&s, chnk.s, chnk.n); + if (at_end(t)) re_search_last_chunk(&s); + if (re_search_match_at_start(&s, &m) && m.extent.start == 0) { + *out = (TxtLoc) { p.t, p.p, p.i + m.extent.start }; + return 1; + } + if (~s.flags & RE_SEARCH_MID_MATCH) { + if (chnk.n > 0) break; + if (txt_after(t, end)) break; + } + } + e.scratch = a; + if (at_start(l)) break; + l = cprev(l); + } + if (match_found == 0) { + match_found = -1; + l = txt_end(l.t); + end = start; + goto search_from_end; + } + return 0; +} + +int read_search(void) { + Str src = get_input_line(S("Search: ")); + if (!src.n) return 0; + e.search.s = malloc(src.n); + if (!e.search.s) FAIL_WITH_MSG("failed to allocate search"); + memcpy(e.search.s, src.s, src.n); + e.search.n = src.n; + return 1; +} + int motion(TxtLoc *lp, u32 c) { - static Str last_search = { 0 }; TxtLoc l = *lp; TxtLoc last_loc = l; @@ -657,25 +710,33 @@ loop: } } break; - case '/': { - if (last_search.s) free(last_search.s); - last_search = (Str) { 0, 0 }; - Str src = get_input_line(S("Search: ")); - if (!src.n) return 0; - last_search.s = malloc(src.n); - if (!last_search.s) FAIL_WITH_MSG("failed to allocate search"); - memcpy(last_search.s, src.s, src.n); - last_search.n = src.n; - TxtLoc r; - if (search_next_regex(l, src, &r)) { - l = r; + case '/': + if (read_search()) { + TxtLoc r; + if (search_next_regex(l, e.search, &r)) l = r; + e.search_dir = 1; } - } break; + break; - case 'n': { - TxtLoc r; - if (last_search.n > 0 && search_next_regex(cnext(l), last_search, &r)) l = r; - } break; + case '?': + if (read_search()) { + TxtLoc r; + if (search_prev_regex(l, e.search, &r)) l = r; + e.search_dir = -1; + } + break; + + case 'n': + if (!e.search.n) return 0; + if (e.search_dir > 0 && !search_next_regex(cnext(l), e.search, &l)) return 0; + if (e.search_dir < 0 && !search_prev_regex(cprev(l), e.search, &l)) return 0; + break; + + case 'N': + if (!e.search.n) return 0; + if (e.search_dir < 0 && !search_next_regex(cnext(l), e.search, &l)) return 0; + if (e.search_dir > 0 && !search_prev_regex(cprev(l), e.search, &l)) return 0; + break; default: return 0; -- cgit v1.2.3