diff options
| -rw-r--r-- | main.c | 99 | ||||
| -rw-r--r-- | regex.c | 25 | ||||
| -rw-r--r-- | regex.h | 1 | ||||
| -rw-r--r-- | txt.c | 11 |
4 files changed, 110 insertions, 26 deletions
@@ -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; @@ -846,18 +846,13 @@ void re_search_last_chunk(ReSearch *s) { * check s->flags to find if the match is done yet */ -int re_search_match(ReSearch *s, ReMatch *m) { +int re_search_match_at_start(ReSearch *s, ReMatch *m) { size_t i = s->buf_idx; size_t n = s->buf_len; while (i < n) { - if (s->re->first_byte && (~s->flags & RE_SEARCH_MID_MATCH)) { - const char *p = memchr(s->buf + i, s->re->first_byte, n - i); - if (!p) break; - i = p - s->buf; - } isize r = re_search_try_match(s, i, n); if (r < 0) { - i++; + return 0; } else { if (i == (usize)r) r++; if (s->flags & RE_SEARCH_MID_MATCH) { @@ -877,6 +872,22 @@ int re_search_match(ReSearch *s, ReMatch *m) { return 0; } +int re_search_match(ReSearch *s, ReMatch *m) { + u32 i = s->buf_idx; + u32 n = s->buf_len; + while (i < n) { + if (s->re->first_byte && (~s->flags & RE_SEARCH_MID_MATCH)) { + const char *p = memchr(s->buf + i, s->re->first_byte, n - i); + if (!p) break; + i = p - s->buf; + } + s->buf_idx = i++; + if (re_search_match_at_start(s, m)) return 1; + } + s->buf_idx = n; + return 0; +} + /* convenience wrappers */ ReMatchList re_match_all(RegEx *re, Str s, Arena *a) { @@ -118,6 +118,7 @@ void re_search_start(ReSearch *s, RegEx *re, Arena *a); void re_search_chunk(ReSearch *s, const char *buf, size_t n); void re_search_last_chunk(ReSearch *s); int re_search_match(ReSearch *s, ReMatch *m); +int re_search_match_at_start(ReSearch *s, ReMatch *m); ReMatchList re_match_all(RegEx *re, Str s, Arena *a); int re_match_full(RegEx *re, Str s, Arena *a); @@ -314,6 +314,17 @@ Str txt_next_chunk(TxtLoc *l) { return s; } +Str txt_prev_chunk(TxtLoc *l) { + while (!l->i && l->p > 0) { + l->p--; + l->i = l->t->ptbl.v[l->p].n; + } + TxtPiece *p = &l->t->ptbl.v[l->p]; + Str s = { l->t->buf[p->buf].s + p->ofs, l->i }; + l->i = 0; + return s; +} + int txt_range_equal(TxtLoc lo, TxtLoc hi, Str cmp) { u32 i = 0; while (txt_before(lo, hi)) { |
