summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c99
-rw-r--r--regex.c25
-rw-r--r--regex.h1
-rw-r--r--txt.c11
4 files changed, 110 insertions, 26 deletions
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;
diff --git a/regex.c b/regex.c
index 710593f..6a362e4 100644
--- a/regex.c
+++ b/regex.c
@@ -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) {
diff --git a/regex.h b/regex.h
index 38089d3..b6ee9c7 100644
--- a/regex.h
+++ b/regex.h
@@ -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);
diff --git a/txt.c b/txt.c
index fd51bc4..a982cd2 100644
--- a/txt.c
+++ b/txt.c
@@ -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)) {