summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWormHeamer2025-12-29 02:29:53 -0500
committerWormHeamer2025-12-29 02:29:53 -0500
commit4c5442ccd9428c4bb4e73939d3eff50911b574c0 (patch)
tree0b632c7786507178a48d62d0dcd090ae34d88c63
parente40c14f15bc8607717bd1955dc8df5180f36c90b (diff)
various asserts
-rw-r--r--main.c185
-rw-r--r--txt.c65
-rw-r--r--txt.h6
-rw-r--r--vui.c5
4 files changed, 162 insertions, 99 deletions
diff --git a/main.c b/main.c
index b0ba567..df92cb3 100644
--- a/main.c
+++ b/main.c
@@ -21,7 +21,7 @@
Arena scratch = { 0 };
Txt txt = { 0 };
-u32 cur = 0;
+TxtLoc cur = { 0 };
int mode = 0;
u32 count = 0;
@@ -137,6 +137,8 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
end = t;
}
+ u32 cur_ofs = txt_range_len(cur, end);
+
int in, out;
int p = popen2(cmd, &in, &out);
if (p < 0) return -1;
@@ -151,24 +153,27 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
}
l = bnext(l);
}
+ txt_write_range(in, start, end);
close(in);
- txt_delete_range(start, end);
+ start = txt_delete_range(start, end);
DYNARR(char) buf = { 0 };
- DA_AFIT(&buf, &scratch, 1024);
+ DA_AFIT(&buf, &scratch, 8192);
for (;;) {
- isize sz = read(out, &buf.v[buf.n], 1024);
+ isize sz = read(out, &buf.v[buf.n], 8192);
if (sz < 0) {
close(out);
return -1;
}
if (!sz) break;
buf.n += sz;
- DA_AFIT(&buf, &scratch, buf.n + 1024);
+ DA_AFIT(&buf, &scratch, buf.n + (-buf.n & 8191) + 8192);
}
-
- start = txt_insert(start, buf.v, buf.n);
close(out);
+
+ end = txt_insert(start, buf.v, buf.n);
+ cur = end;
+ while (cur_ofs--) cur = cprev(cur);
return 0;
}
@@ -177,8 +182,7 @@ int shell_replace(TxtLoc start, TxtLoc end, const char *cmd) {
#define ODD_ATTR (FG_CYAN | BG_BLACK)
#define EVEN_ATTR (FG_WHITE | BG_BLACK)
-void find_view_window(Txt *t, u32 curs, TxtLoc *start, TxtLoc *end) {
- TxtLoc l = txt_at(t, curs);
+void find_view_window(TxtLoc l, TxtLoc *start, TxtLoc *end) {
u32 u = LINES / 2;
TxtLoc a = l;
for (u32 i = 0; i < u; i++) a = prev_newline(a);
@@ -197,7 +201,7 @@ void draw(void *ctx) {
int lmarg = 0;
int x = lmarg, y = 0;
TxtLoc start, end;
- find_view_window(&txt, cur, &start, &end);
+ find_view_window(cur, &start, &end);
vui_aprintf(-1, 0, ODD_ATTR, "%u piece(s)", txt.ptbl.n);
for (u32 i = 0; i < txt.ptbl.n; i++) {
@@ -206,7 +210,7 @@ void draw(void *ctx) {
vui_aprintf(-1, i+1, a, "%u, %u (%s)", p->ofs, p->n, p->buf == TXT_ADD ? "add" : "src");
}
- TxtLoc l = txt_at(&txt, cur);
+ TxtLoc l = cur;
int cur_found = 0;
while (txt_before(start, end)) {
if (l.p == start.p && l.i == start.i) {
@@ -229,104 +233,106 @@ void draw(void *ctx) {
u32 c = txt_chr(l);
vui_printf(-1, -4, "%u", count);
vui_aprintf(-1, -3, mode ? FG_BCYAN : FG_CYAN, "%s", mode ? "INSERT" : "NORMAL");
- vui_printf(-1, -1, "%u - %u.%u - %02x (%c)", cur, l.p, l.i, c, (c < 0x20 || c > 0x7e) ? ' ' : c);
+ vui_printf(-1, -1, "%u - %u.%u - %02x (%c)", txt_ofs(cur), l.p, l.i, c, (c < 0x20 || c > 0x7e) ? ' ' : c);
u32 used = scratch.beg - scratch.start, max = scratch.end - scratch.start;
vui_printf(-1, -2, "scratch %.02f/%.02fk", used/1024.0, max/1024.0);
}
-int motion(u32 c) {
- u32 last_cur = cur;
+int motion(TxtLoc *lp, u32 c) {
+ TxtLoc l = *lp;
+ TxtLoc last_loc = l;
loop:
switch (c) {
case KEY_LEFT:
case 'h':
- cur = move_char_back(&txt, cur);
- break;
- case KEY_LEFT | KEY_CTRL_BIT:
- case 'b':
- cur = move_word_back(&txt, cur);
+ l = cprev(l);
break;
case KEY_RIGHT:
case 'l':
- cur = move_char_fwd(&txt, cur);
+ l = cnext(l);
+ break;
+ case KEY_LEFT | KEY_CTRL_BIT:
+ case 'b':
+ l = prev_word(l);
break;
case KEY_RIGHT | KEY_CTRL_BIT:
case 'w':
- cur = move_word_fwd(&txt, cur);
+ l = next_word(l);
break;
case KEY_UP:
case 'k':
- cur = move_line_up(&txt, cur);
+ l = prev_line(l);
break;
case KEY_DOWN:
case 'j':
- cur = move_line_down(&txt, cur);
+ l = next_line(l);
break;
case KEY_UP | KEY_CTRL_BIT:
case '{':
- cur = move_par_up(&txt, cur);
+ l = prev_par(l);
break;
case KEY_DOWN | KEY_CTRL_BIT:
case '}':
- cur = move_par_down(&txt, cur);
+ l = next_par(l);
break;
case KEY_PGUP:
- for (u32 i = 0; i < LINES; i += 3) cur = move_line_up(&txt, cur);
+ for (u32 i = 0; i < LINES; i += 3) l = prev_line(l);
break;
case KEY_PGDN:
- for (u32 i = 0; i < LINES; i += 3) cur = move_line_down(&txt, cur);
+ for (u32 i = 0; i < LINES; i += 3) l = next_line(l);
break;
case KEY_HOME:
case '^':
case '0':
- cur = txt_ofs(start_of_line(txt_at(&txt, cur)));
+ l = start_of_line(l);
break;
case KEY_END:
case '$':
- cur = txt_ofs(next_newline(txt_at(&txt, cur)));
+ l = end_of_line(l);
break;
case KEY_HOME | KEY_CTRL_BIT:
case 'g':
- cur = 0;
+ l = txt_start(&txt);
break;
case KEY_END | KEY_CTRL_BIT:
case 'G':
- cur = txt.len;
+ l = txt_end(&txt);
break;
case 'f': {
- u32 n = vui_key();
- TxtLoc l = cnext(txt_at(&txt, cur));
- for (TxtLoc t = l;;) {
- u32 c = txt_chr_next(&t);
- if (c == '\n' || c == 0) break;
- if (c == n) {
- cur = txt_ofs(l);
+ u32 k = vui_key();
+ TxtLoc t = cnext(l);
+ for (TxtLoc n = l;;) {
+ u32 x = txt_chr_next(&n);
+ if (x == '\n' || x == 0) break;
+ if (x == k) {
+ l = t;
break;
}
- l = t;
+ t = n;
}
} break;
case 'F': {
- u32 n = vui_key();
- TxtLoc l = bprev(txt_at(&txt, cur));
+ u32 k = vui_key();
+ TxtLoc t = cprev(l);
for (;;) {
- u32 c = txt_chr(l);
- if (c == '\n') break;
- if (c == n) {
- cur = txt_ofs(l);
+ u32 x = txt_chr(l);
+ if (x == '\n') break;
+ if (x == k) {
+ l = t;
break;
}
- l = bprev(l);
+ t = bprev(t);
}
} break;
default:
return 0;
}
- if (count > 1 && last_cur != cur) {
+ if (count > 1 && (txt_before(l, last_loc) || txt_after(l, last_loc))) {
count--;
goto loop;
}
count = 0;
+ *lp = l;
return 1;
}
@@ -338,7 +344,7 @@ int main(int argc, const char **argv) {
const char *path = "test.txt";
if (argc > 1) path = argv[1];
if (txt_load(&txt, path)) err(1, "couldn't open file");
- cur = txt.len;
+ cur = txt_end(&txt);
for (;;) {
scratch.beg = scratch.start;
draw(NULL);
@@ -362,69 +368,64 @@ int main(int argc, const char **argv) {
break;
case 'a': {
mode = 1;
- TxtLoc l = txt_at(&txt, cur);
+ TxtLoc l = cur;
TxtLoc e = end_of_line(l);
l = txt_before(l, e) ? cnext(l) : e;
- cur = txt_ofs(l);
+ cur = l;
} break;
case 'I':
mode = 1;
- cur = txt_ofs(start_of_line(txt_at(&txt, cur)));
+ cur = start_of_line(cur);
break;
case 'A':
mode = 1;
- cur = txt_ofs(end_of_line(txt_at(&txt, cur)));
+ cur = end_of_line(cur);
break;
case 'o':
mode = 1;
- cur = txt_ofs(end_of_line(txt_at(&txt, cur)));
+ cur = end_of_line(cur);
goto ins_newline;
case 'O':
mode = 1;
- cur = txt_ofs(bprev(start_of_line(txt_at(&txt, cur))));
+ cur = bprev(start_of_line(cur));
goto ins_newline;
case 'd': {
- u32 before = cur;
- if (motion(vui_key())) {
- del_between(&txt, before, cur);
- if (before < cur) cur = before;
+ TxtLoc before = cur;
+ if (motion(&cur, vui_key())) {
+ cur = txt_delete_range(before, cur);
}
} break;
- case 'D': {
- u32 end = txt_ofs(end_of_line(txt_at(&txt, cur)));
- del_between(&txt, cur, end);
- } break;
- case 'C': {
- u32 end = txt_ofs(end_of_line(txt_at(&txt, cur)));
- del_between(&txt, cur, end);
+ case 'D':
+ cur = txt_delete_range(cur, end_of_line(cur));
+ break;
+ case 'C':
+ cur = txt_delete_range(cur, end_of_line(cur));
mode = 1;
- } break;
+ break;
case 'S': {
- TxtLoc l = start_of_line(txt_at(&txt, cur));
- u32 end = txt_ofs(end_of_line(l));
- del_between(&txt, txt_ofs(l), end);
- cur = txt_ofs(l);
+ TxtLoc start = start_of_line(cur);
+ TxtLoc end = end_of_line(cur);
+ cur = txt_delete_range(start, end);
mode = 1;
} break;
case 'c': {
- u32 before = cur;
- if (motion(vui_key())) {
- del_between(&txt, before, cur);
- if (before < cur) cur = before;
+ TxtLoc before = cur;
+ if (motion(&cur, vui_key())) {
+ cur = txt_delete_range(before, cur);
+ mode = 1;
}
- mode = 1;
break;
}
case 'x':
- cur = txt_ofs(txt_delete_c(cnext(txt_at(&txt, cur))));
+ cur = txt_delete_c(cnext(cur));
break;
case 's':
- cur = txt_ofs(txt_delete_c(cnext(txt_at(&txt, cur))));
+ cur = txt_delete_c(cnext(cur));
mode = 1;
break;
case '0':
if (!count) {
- motion(c);
+ motion(&cur, c);
break;
}
/* fallthrough */
@@ -433,57 +434,57 @@ int main(int argc, const char **argv) {
count = (count % 100000000) * 10 + c - '0';
break;
case 'M': {
- TxtLoc start = prev_par(txt_at(&txt, cur));
- TxtLoc end = next_par(txt_at(&txt, cur));
+ TxtLoc start = prev_par(cur);
+ TxtLoc end = next_par(cur);
if (shell_replace(start, end, "fmt -w80 -u")) {
err(1, "shell_replace");
}
- if (cur > txt.len) cur = txt.len;
};
default:
- motion(c);
+ motion(&cur, c);
break;
}
break;
case 1:
switch (c) {
case KEY_ESC:
- if (txt_after(txt_at(&txt, cur), start_of_line(txt_at(&txt, cur)))) {
- cur = txt_ofs(cprev(txt_at(&txt, cur)));
+ if (txt_after(cur, start_of_line(cur))) {
+ cur = cprev(cur);
}
mode = 0;
break;
case KEY_BKSP:
- cur = txt_ofs(txt_delete_c(txt_at(&txt, cur)));
+ cur = txt_delete_c(cur);
break;
case 0x17 /* ^W */:
- cur = del_between(&txt, move_word_back(&txt, cur), cur);
+ cur = txt_delete_range(prev_word(cur), cur);
break;
case 0x05 /* ^E */:
- cur = del_between(&txt, cur, move_word_fwd(&txt, cur));
+ cur = txt_delete_range(cur, next_word(cur));
break;
case '\r': {
ins_newline:;
/*
u32 tabs = 0;
- TxtLoc start = start_of_line(txt_at(&txt, cur));
+ TxtLoc start = start_of_line(cur);
for (TxtLoc l = start; txt_byte(l) == '\t'; l = bnext(l))
tabs++;
while (txt_byte(txt_at(&txt, cur - 1)) == '\t') {
- cur = txt_ofs(txt_delete(txt_at(&txt, cur), 1));
+ cur = txt_ofs(txt_delete(cur, 1));
}
*/
- cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), '\n'));
- //while (tabs--) cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), '\t'));
+ cur = txt_insert_c(cur, '\n');
+ //while (tabs--) cur = txt_ofs(txt_insert_c(cur, '\t'));
} break;
default:
- if ((c == '\t' || c >= ' ') && c <= KEY_UTF8_MAX) cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), c));
+ if ((c == '\t' || c >= ' ') && c <= KEY_UTF8_MAX) cur = txt_insert_c(cur, c);
break;
}
break;
}
if (mode == 1) count = 0;
+ ASSERT(txt_valid_loc(cur));
}
brk:
vui_fini();
diff --git a/txt.c b/txt.c
index 7092964..36af521 100644
--- a/txt.c
+++ b/txt.c
@@ -58,7 +58,7 @@ static void txt_buf_append(Txt *b, TxtBufIdx bi, const char *s, u32 n) {
static isize txt_buf_dedup(Txt *b, TxtBufIdx bi, const char *s, u32 n) {
TxtBuf *buf = &b->buf[bi];
- if (buf->n >= n && !memcmp(buf->s + (buf->n - n), s, n)) {
+ if (buf->n >= n && buf->s && !memcmp(buf->s + (buf->n - n), s, n)) {
return buf->n - n;
} else {
return -1;
@@ -128,6 +128,14 @@ static TxtLoc txt_join_or_kill(TxtLoc l) {
return l;
}
+static inline TxtLoc resolve_loc(TxtLoc l) {
+ if (l.p + 1 < l.t->ptbl.n && l.i == l.t->ptbl.v[l.p].n) {
+ l.p++;
+ l.i = 0;
+ }
+ return l;
+}
+
TxtLoc txt_insert(TxtLoc l, const char *s, u32 n) {
l = txt_add_piece(l.t, l);
TxtPiece *p = &l.t->ptbl.v[l.p];
@@ -142,7 +150,7 @@ TxtLoc txt_insert(TxtLoc l, const char *s, u32 n) {
l.i = p->n;
l = txt_join_or_kill(l);
l.i = l.t->ptbl.v[l.p].n;
- return l;
+ return resolve_loc(l);
}
TxtLoc txt_insert_c(TxtLoc l, u32 ch) {
@@ -173,15 +181,28 @@ TxtLoc txt_delete(TxtLoc l, u32 n) {
}
l = txt_join_or_kill(l);
}
- return txt_join_or_kill(l);
+ return resolve_loc(txt_join_or_kill(l));
+}
+
+u32 txt_range_len(TxtLoc lo, TxtLoc hi) {
+ u32 n = 0;
+ while (lo.p < hi.p) {
+ n += lo.t->ptbl.v[lo.p].n - lo.i;
+ lo.p++;
+ lo.i = 0;
+ }
+ n += hi.i - lo.i;
+ return n;
}
TxtLoc txt_delete_range(TxtLoc lo, TxtLoc hi) {
/* TODO: figure out nr. of chars, then delete all at once */
- while (txt_before(lo, hi)) {
- hi = txt_delete(hi, 1);
+ if (txt_before(hi, lo)) {
+ TxtLoc t = lo;
+ lo = hi;
+ hi = t;
}
- return lo;
+ return txt_delete(hi, txt_range_len(lo, hi));
}
TxtLoc txt_delete_c(TxtLoc l) {
@@ -242,8 +263,28 @@ void txt_free(Txt *t) {
free(t->ptbl.v);
}
+void txt_write_range(int fd, TxtLoc lo, TxtLoc hi) {
+ while (lo.p < hi.p) {
+ TxtPiece *p = &lo.t->ptbl.v[lo.p];
+ write(fd, lo.t->buf[p->buf].s + p->ofs + lo.i, p->n - lo.i);
+ lo.p++;
+ lo.i = 0;
+ }
+ if (hi.i > lo.i) {
+ TxtPiece *p = &lo.t->ptbl.v[lo.p];
+ write(fd, lo.t->buf[p->buf].s + p->ofs + lo.i, hi.i - lo.i);
+ }
+}
+
/* navigation */
+int txt_valid_loc(TxtLoc l) {
+ return l.p < l.t->ptbl.n
+ && (l.i < l.t->ptbl.v[l.p].n
+ || (l.p + 1 == l.t->ptbl.n
+ && l.i <= l.t->ptbl.v[l.p].n));
+}
+
TxtLoc txt_at(Txt *b, u32 ofs) {
for (u32 i = 0; i < b->ptbl.n; i++) {
if (ofs < b->ptbl.v[i].n) {
@@ -263,13 +304,25 @@ u32 txt_ofs(TxtLoc l) {
}
int txt_before(TxtLoc a, TxtLoc b) {
+ ASSERT(txt_valid_loc(a));
+ ASSERT(txt_valid_loc(b));
return a.p < b.p || (a.p == b.p && a.i < b.i);
}
int txt_after(TxtLoc a, TxtLoc b) {
+ ASSERT(txt_valid_loc(a));
+ ASSERT(txt_valid_loc(b));
return a.p > b.p || (a.p == b.p && a.i > b.i);
}
+TxtLoc txt_start(Txt *t) {
+ return (TxtLoc) { t, 0, 0 };
+}
+
+TxtLoc txt_end(Txt *t) {
+ return (TxtLoc) { t, t->ptbl.n-1, t->ptbl.v[t->ptbl.n-1].n };
+}
+
TxtLoc bnext(TxtLoc l) {
TxtPiece *p = &l.t->ptbl.v[l.p];
if (l.p + 1 < l.t->ptbl.n) {
diff --git a/txt.h b/txt.h
index f1cf538..a7dd908 100644
--- a/txt.h
+++ b/txt.h
@@ -39,6 +39,8 @@ int txt_load(Txt *b, const char *path);
int txt_save(Txt *b, const char *path);
void txt_free(Txt *b);
+void txt_write_range(int fd, TxtLoc lo, TxtLoc hi);
+
/* insertion & deletion */
TxtLoc txt_insert(TxtLoc l, const char *s, u32 n);
@@ -46,13 +48,17 @@ TxtLoc txt_delete(TxtLoc l, u32 n);
TxtLoc txt_delete_range(TxtLoc lo, TxtLoc hi);
TxtLoc txt_insert_c(TxtLoc l, u32 ch);
TxtLoc txt_delete_c(TxtLoc l);
+u32 txt_range_len(TxtLoc lo, TxtLoc hi);
/* navigation */
+int txt_valid_loc(TxtLoc l);
TxtLoc txt_at(Txt *b, u32 ofs);
u32 txt_ofs(TxtLoc l);
int txt_before(TxtLoc a, TxtLoc b);
int txt_after(TxtLoc a, TxtLoc b);
+TxtLoc txt_start(Txt *t);
+TxtLoc txt_end(Txt *t);
TxtLoc bnext(TxtLoc l);
TxtLoc bprev(TxtLoc l);
diff --git a/vui.c b/vui.c
index 8c4a58a..379fdb9 100644
--- a/vui.c
+++ b/vui.c
@@ -584,6 +584,7 @@ end:
}
void vui_chra(int x, int y, VuiChar c, VuiAttr a) {
+ ASSERT(c > 0 && c <= KEY_UTF8_MAX);
if (x >= 0 && x < (int)COLS && y >= 0 && y < (int)LINES) {
CHR(x, y) = c;
ATTR(x, y) = a;
@@ -617,7 +618,9 @@ void vui_putsna(int x, int y, const char *s, unsigned srcn, VuiAttr a) {
u32 n = utf8_decode_len(s, srcn);
truncate_span(&x, &n);
if (n < 1 || y < 0 || y >= (int)LINES) return;
- utf8_decode(&CHR(x, y), s, n);
+ VuiChar *dest = &CHR(x, y);
+ utf8_decode(dest, s, n);
+ for (u32 i = 0; i < n; i++) ASSERT(dest[i] > 0 && dest[i] <= KEY_UTF8_MAX);
for (uint16_t *pa = &ATTR(x, y); n--;) *pa++ = a;
}