From d723f8a5d54f098f0cf378e5dcf3a7d4ec049822 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Wed, 31 Dec 2025 05:01:16 -0500 Subject: add regex search (only forwards for now) --- main.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 118 insertions(+), 15 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index db6d641..70a25a6 100644 --- a/main.c +++ b/main.c @@ -22,6 +22,7 @@ #include "utf8.h" #include "str.h" #include "freelist.h" +#include "regex.h" #define ED_BUF_MAX 1024 @@ -52,6 +53,8 @@ typedef struct { Txt *txt_free; EditMode mode; u32 count; + Str input_line, input_prompt; + Str last_search; } Editor; Editor e = { 0 }; @@ -433,13 +436,16 @@ void draw(void *ctx) { ASSERT(start.i <= eb->txt->ptbl.v[start.p].n); if (!cur_found) vui_curs_pos(x, y); - /* - u32 c = txt_chr(l); - vui_printf(-1, -4, "%u", e.count); - vui_aprintf(-1, -3, e.mode ? FG_BCYAN : FG_CYAN, "%s", e.mode ? "INSERT" : "NORMAL"); - vui_printf(-1, -1, "%u - %u.%u - %02x (%c)", txt_ofs(eb->cur), l.p, l.i, c, (c < 0x20 || c > 0x7e) ? ' ' : c); - u32 used = e.scratch.beg - e.scratch.start, max = e.scratch.end - e.scratch.start; - vui_printf(-1, -2, "e.scratch %.02f/%.02fk", used/1024.0, max/1024.0);*/ + + if (e.input_line.n > 0 || e.input_prompt.n > 0) { + u32 x = 0; + x += vui_putsn(0, 0, e.input_prompt.s, e.input_prompt.n); + x += vui_putsn(x, 0, e.input_line.s, e.input_line.n); + vui_curs_pos(x, 0); + vui_curs_shape(VUI_CURS_BAR); + u32 c = COLS; + while (x < c) vui_chr(x++, 0, ' '); + } } TxtLoc logical_line_start(TxtLoc l) { @@ -448,7 +454,77 @@ TxtLoc logical_line_start(TxtLoc l) { return l; } +Str get_input_line(Str prompt) { + e.input_prompt = prompt; + DYNARR(char) s = { 0 }; + for (;;) { + draw(NULL); + vui_blit(); + u32 c = vui_key(); + switch (c) { + case '\r': + goto done; + case KEY_ESC: + e.input_line = (Str) { 0, 0 }; + e.input_prompt = (Str) { 0, 0 }; + return (Str) { 0, 0 }; + case KEY_BKSP: + if (s.n > 0) s.n--; + break; + case 0x17 /* ^W */: + while (s.n > 0 && is_space(s.v[s.n-1])) s.n--; + while (s.n > 0 && !is_space(s.v[s.n-1])) s.n--; + break; + default: + if (c > 0 && c <= KEY_UTF8_MAX && c >= ' ') { + u32 n = utf8_encode_len(&c, 1); + DA_AFIT(&s, &e.scratch, s.n + n); + utf8_encode(&s.v[s.n], &c, n); + s.n += n; + } + break; + } + e.input_line = (Str) { s.v, s.n }; + } +done:; + e.input_line = (Str) { 0, 0 }; + e.input_prompt = (Str) { 0, 0 }; + return (Str) { s.v, s.n }; +} + +int search_next_regex(TxtLoc l, 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; + } + TxtLoc t = l; + int match_found = 0; +search_from_start: + re_search_start(&s, &re, &e.scratch); + 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); + ReMatch m; + if (re_search_match(&s, &m)) { + *out = (TxtLoc) { p.t, p.p, p.i + m.extent.start }; + return 1; + } + } + if (match_found == 0) { + match_found = -1; + t = txt_start(t.t); + goto search_from_start; + } + return 0; +} + int motion(TxtLoc *lp, u32 c) { + static Str last_search = { 0 }; + TxtLoc l = *lp; TxtLoc last_loc = l; for (;;) { @@ -472,6 +548,7 @@ int motion(TxtLoc *lp, u32 c) { loop: switch (c) { + case KEY_LEFT: case 'h': l = cprev(l); @@ -480,6 +557,15 @@ loop: case 'l': l = cnext(l); break; + case KEY_DOWN: + case 'j': + l = next_line(l); + break; + case KEY_UP: + case 'k': + l = prev_line(l); + break; + case KEY_LEFT | KEY_CTRL_BIT: case 'b': l = prev_word(l); @@ -488,14 +574,7 @@ loop: case 'w': l = next_word(l); break; - case KEY_UP: - case 'k': - l = prev_line(l); - break; - case KEY_DOWN: - case 'j': - l = next_line(l); - break; + case KEY_UP | KEY_CTRL_BIT: case '{': l = prev_par(l); @@ -513,6 +592,7 @@ loop: case '%': if (!match_bracket(l, &l)) return 0; break; + case KEY_PGUP: for (u32 i = 0; i < LINES; i += 3) l = prev_line(l); break; @@ -530,6 +610,7 @@ loop: case '$': l = end_of_line(l); break; + case KEY_HOME | KEY_CTRL_BIT: case 'g': if (e.count) { @@ -548,6 +629,7 @@ loop: l = txt_end(l.t); } break; + case 'f': { u32 k = vui_key(); TxtLoc t = cnext(l); @@ -574,6 +656,27 @@ loop: t = bprev(t); } } 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; + } + } break; + + case 'n': { + TxtLoc r; + if (last_search.n > 0 && search_next_regex(cnext(l), last_search, &r)) l = r; + } break; + default: return 0; } -- cgit v1.2.3