summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorWormHeamer2025-12-31 05:01:16 -0500
committerWormHeamer2025-12-31 05:01:16 -0500
commitd723f8a5d54f098f0cf378e5dcf3a7d4ec049822 (patch)
tree0fe9aa493307d04df9d431536b7b3e90d6eb0814 /main.c
parent026da321ebf2f09d17e3978aacf10b513d46460c (diff)
add regex search (only forwards for now)
Diffstat (limited to 'main.c')
-rw-r--r--main.c133
1 files changed, 118 insertions, 15 deletions
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;
}