From 2fe237e65a13545c053c31b7b413898d5b8734ac Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Sun, 28 Dec 2025 20:30:37 -0500 Subject: remove most explicit Txt* params, fix some utf-8 problems --- main.c | 183 ++++++++++++++++++++-------------------------------- txt.c | 226 +++++++++++++++++++++++++++++++++++++++++------------------------ txt.h | 47 ++++++++++---- 3 files changed, 246 insertions(+), 210 deletions(-) diff --git a/main.c b/main.c index 0fe9513..91ef1dc 100644 --- a/main.c +++ b/main.c @@ -27,37 +27,37 @@ int is_space(u32 c) { u32 move_word_back(Txt *t, u32 cur) { TxtLoc l = txt_at(t, cur); - while (!txt_at_start(t,l)) { - TxtLoc n = txt_prev(t, l); - if (!is_space(txt_chr(t, n))) break; + while (!at_start(l)) { + TxtLoc n = bprev(l); + if (!is_space(txt_chr(n))) break; l = n; } - while (!txt_at_start(t,l)) { - TxtLoc n = txt_prev(t, l); - if (is_space(txt_chr(t, n))) break; + while (!at_start(l)) { + TxtLoc n = bprev(l); + if (is_space(txt_chr(n))) break; l = n; } - return txt_ofs(t, l); + return txt_ofs(l); } u32 move_word_fwd(Txt *t, u32 cur) { TxtLoc l = txt_at(t, cur); - while (!txt_at_end(t,l) && is_space(txt_chr(t, l))) l = txt_next(t, l); - while (!txt_at_end(t,l) && !is_space(txt_chr(t, l))) l = txt_next(t, l); - return txt_ofs(t, l); + while (!at_end(l) && is_space(txt_chr(l))) l = cnext(l); + while (!at_end(l) && !is_space(txt_chr(l))) l = cnext(l); + return txt_ofs(l); } u32 move_char_back(Txt *t, u32 cur) { while (cur > 0) { cur--; - u8 c = txt_byte(t, txt_at(t, cur)); + u8 c = txt_byte(txt_at(t, cur)); if ((c & 0xc0) != 0x80) break; } return cur; } u32 move_char_fwd(Txt *t, u32 cur) { - u8 b = txt_byte(t, txt_at(t, cur)); + u8 b = txt_byte(txt_at(t, cur)); u32 n = stdc_leading_ones(b); if (cur + n >= t->len) return t->len; return cur + n + !n; @@ -66,91 +66,40 @@ u32 move_char_fwd(Txt *t, u32 cur) { u32 del_between(Txt *t, u32 a, u32 b) { if (b < a) { u32 t = a; a = b; b = t; } //if (b - a > 10) TRAP(); - return txt_delete(t, b, b - a); -} - -TxtLoc next_newline(Txt *t, TxtLoc l) { - do l = txt_next(t, l); - while (!txt_at_end(t, l) && txt_byte(t, l) != '\n'); - return l; -} - -TxtLoc prev_newline(Txt *t, TxtLoc l) { - do l = txt_prev(t, l); - while (!txt_at_start(t, l) && txt_byte(t, l) != '\n'); - return l; -} - -TxtLoc start_of_line(Txt *t, TxtLoc l) { - l = prev_newline(t, l); - if (!txt_at_start(t,l) && txt_byte(t, l) == '\n') l = txt_next(t, l); - return l; -} - -TxtLoc end_of_line(Txt *t, TxtLoc l) { - TxtLoc start = start_of_line(t, l); - return txt_byte(t, start) == '\n' ? start : next_newline(t, start); -} - -u32 get_col(Txt *t, TxtLoc l) { - u32 n = 0; - for (TxtLoc tmp = start_of_line(t, l); txt_before(tmp, l); txt_chr_next(t, &tmp)) n++; - return n; -} - -TxtLoc at_col(Txt *t, TxtLoc l, u32 col) { - l = start_of_line(t, l); - while (col--) { - if (txt_chr_next(t, &l) == '\n') { - l = txt_prev(t, l); - break; - } - } - return l; -} - -TxtLoc prev_line(Txt *t, TxtLoc l) { - TxtLoc start = start_of_line(t, l); - return at_col(t, txt_prev(t, start), get_col(t, l)); -} - -TxtLoc next_line(Txt *t, TxtLoc l) { - TxtLoc end = end_of_line(t, l); - if (txt_at_end(t, end)) return end; - return at_col(t, txt_next(t, end), get_col(t, l)); + return txt_ofs(txt_delete(txt_at(t, b), b - a)); } u32 move_line_up(Txt *t, u32 cur) { - return txt_ofs(t, prev_line(t, txt_at(t, cur))); + return txt_ofs(prev_line(txt_at(t, cur))); } u32 move_line_down(Txt *t, u32 cur) { - return txt_ofs(t, next_line(t, txt_at(t, cur))); + return txt_ofs(next_line(txt_at(t, cur))); } -int empty_line(Txt *t, TxtLoc l) { - u8 b = txt_byte(t, start_of_line(t, l)); +int empty_line(TxtLoc l) { + u8 b = txt_byte(start_of_line(l)); return b == '\n' || b == 0 /* last line of buffer */; } -TxtLoc next_par(Txt *t, TxtLoc l) { - while (!txt_at_end(t, l) && empty_line(t, l)) l = next_line(t, l); - while (!txt_at_end(t, l) && !empty_line(t, l)) l = next_line(t, l); +TxtLoc next_par(TxtLoc l) { + while (!at_end(l) && empty_line(l)) l = next_line(l); + while (!at_end(l) && !empty_line(l)) l = next_line(l); return l; } -TxtLoc prev_par(Txt *t, TxtLoc l) { - while (!txt_at_start(t, l) && empty_line(t, l)) l = prev_line(t, l); - while (!txt_at_start(t, l) && !empty_line(t, l)) l = prev_line(t, l); +TxtLoc prev_par(TxtLoc l) { + while (!at_start(l) && empty_line(l)) l = prev_line(l); + while (!at_start(l) && !empty_line(l)) l = prev_line(l); return l; } u32 move_par_up(Txt *t, u32 cur) { - return txt_ofs(t, prev_par(t, txt_at(t, cur))); + return txt_ofs(prev_par(txt_at(t, cur))); } u32 move_par_down(Txt *t, u32 cur) { - return txt_ofs(t, next_par(t, txt_at(t, cur))); + return txt_ofs(next_par(txt_at(t, cur))); } /* main */ @@ -162,12 +111,12 @@ void find_view_window(Txt *t, u32 curs, TxtLoc *start, TxtLoc *end) { TxtLoc l = txt_at(t, curs); u32 u = LINES / 2; TxtLoc a = l; - for (u32 i = 0; i < u; i++) a = prev_newline(t, a); + for (u32 i = 0; i < u; i++) a = prev_newline(a); u32 n = 0; TxtLoc b = a; - while (!txt_at_end(t, b) && n++ < LINES) b = next_newline(t, b); - while (!txt_at_start(t, a) && n++ < LINES) a = prev_newline(t, a); - if (!txt_at_start(t,a) && txt_byte(t,a) == '\n') a = txt_next(t, a); + while (!at_end(b) && n++ < LINES) b = next_newline(b); + while (!at_start(a) && n++ < LINES) a = prev_newline(a); + if (!at_start(a) && txt_byte(a) == '\n') a = bnext(a); *start = a; *end = b; } @@ -193,7 +142,7 @@ void draw(void *ctx) { cur_found = 1; vui_curs_pos(x, y); } - u32 c = txt_chr_next(&txt, &start); + u32 c = txt_chr_next(&start); if (c == '\n') { x = 0; y++; @@ -206,7 +155,7 @@ void draw(void *ctx) { } ASSERT(start.i <= txt.ptbl.v[start.p].n); if (!cur_found) vui_curs_pos(x, y); - u32 c = txt_chr(&txt, l); + 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); @@ -259,11 +208,11 @@ loop: case KEY_HOME: case '^': case '0': - cur = txt_ofs(&txt, start_of_line(&txt, txt_at(&txt, cur))); + cur = txt_ofs(start_of_line(txt_at(&txt, cur))); break; case KEY_END: case '$': - cur = txt_ofs(&txt, next_newline(&txt, txt_at(&txt, cur))); + cur = txt_ofs(next_newline(txt_at(&txt, cur))); break; case KEY_HOME | KEY_CTRL_BIT: case 'g': @@ -275,12 +224,12 @@ loop: break; case 'f': { u32 n = vui_key(); - TxtLoc l = txt_next(&txt, txt_at(&txt, cur)); + TxtLoc l = cnext(txt_at(&txt, cur)); for (TxtLoc t = l;;) { - u32 c = txt_chr_next(&txt, &t); + u32 c = txt_chr_next(&t); if (c == '\n') break; if (c == n) { - cur = txt_ofs(&txt, l); + cur = txt_ofs(l); break; } l = t; @@ -288,15 +237,15 @@ loop: } break; case 'F': { u32 n = vui_key(); - TxtLoc l = txt_prev(&txt, txt_at(&txt, cur)); + TxtLoc l = bprev(txt_at(&txt, cur)); for (;;) { - u32 c = txt_chr(&txt, l); + u32 c = txt_chr(l); if (c == '\n') break; if (c == n) { - cur = txt_ofs(&txt, l); + cur = txt_ofs(l); break; } - l = txt_prev(&txt, l); + l = bprev(l); } } break; default: @@ -343,25 +292,25 @@ int main(int argc, const char **argv) { case 'a': { mode = 1; TxtLoc l = txt_at(&txt, cur); - TxtLoc e = end_of_line(&txt, l); - l = txt_before(l, e) ? txt_next(&txt, l) : e; - cur = txt_ofs(&txt, l); + TxtLoc e = end_of_line(l); + l = txt_before(l, e) ? cnext(l) : e; + cur = txt_ofs(l); } break; case 'I': mode = 1; - cur = txt_ofs(&txt, start_of_line(&txt, txt_at(&txt, cur))); + cur = txt_ofs(start_of_line(txt_at(&txt, cur))); break; case 'A': mode = 1; - cur = txt_ofs(&txt, end_of_line(&txt, txt_at(&txt, cur))); + cur = txt_ofs(end_of_line(txt_at(&txt, cur))); break; case 'o': mode = 1; - cur = txt_ofs(&txt, end_of_line(&txt, txt_at(&txt, cur))); + cur = txt_ofs(end_of_line(txt_at(&txt, cur))); goto ins_newline; case 'O': mode = 1; - cur = txt_ofs(&txt, txt_prev(&txt, start_of_line(&txt, txt_at(&txt, cur)))); + cur = txt_ofs(bprev(start_of_line(txt_at(&txt, cur)))); goto ins_newline; case 'd': { u32 before = cur; @@ -371,19 +320,19 @@ int main(int argc, const char **argv) { } } break; case 'D': { - u32 end = txt_ofs(&txt, end_of_line(&txt, txt_at(&txt, cur))); + u32 end = txt_ofs(end_of_line(txt_at(&txt, cur))); del_between(&txt, cur, end); } break; case 'C': { - u32 end = txt_ofs(&txt, end_of_line(&txt, txt_at(&txt, cur))); + u32 end = txt_ofs(end_of_line(txt_at(&txt, cur))); del_between(&txt, cur, end); mode = 1; } break; case 'S': { - TxtLoc l = start_of_line(&txt, txt_at(&txt, cur)); - u32 end = txt_ofs(&txt, end_of_line(&txt, l)); - del_between(&txt, txt_ofs(&txt, l), end); - cur = txt_ofs(&txt, l); + 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); mode = 1; } break; case 'c': { @@ -396,10 +345,10 @@ int main(int argc, const char **argv) { break; } case 'x': - txt_delete_c(&txt, txt_ofs(&txt, txt_next(&txt, txt_at(&txt, cur)))); + cur = txt_ofs(txt_delete_c(cnext(txt_at(&txt, cur)))); break; case 's': - txt_delete_c(&txt, txt_ofs(&txt, txt_next(&txt, txt_at(&txt, cur)))); + cur = txt_ofs(txt_delete_c(cnext(txt_at(&txt, cur)))); mode = 1; break; case '1': case '2': case '3': case '4': @@ -420,11 +369,13 @@ add_to_count: case 1: switch (c) { case KEY_ESC: - if (txt_after(txt_at(&txt, cur), start_of_line(&txt, txt_at(&txt, cur)))) cur--; + if (txt_after(txt_at(&txt, cur), start_of_line(txt_at(&txt, cur)))) { + cur = txt_ofs(cprev(txt_at(&txt, cur))); + } mode = 0; break; case KEY_BKSP: - cur = txt_delete_c(&txt, cur); + cur = txt_ofs(txt_delete_c(txt_at(&txt, cur))); break; case 0x17 /* ^W */: cur = del_between(&txt, move_word_back(&txt, cur), cur); @@ -434,19 +385,21 @@ add_to_count: break; case '\r': { ins_newline:; + /* u32 tabs = 0; - TxtLoc start = start_of_line(&txt, txt_at(&txt, cur)); - for (TxtLoc l = start; txt_byte(&txt, l) == '\t'; l = txt_next(&txt, l)) + TxtLoc start = start_of_line(txt_at(&txt, cur)); + for (TxtLoc l = start; txt_byte(l) == '\t'; l = bnext(l)) tabs++; - while (txt_byte(&txt, txt_at(&txt, cur - 1)) == '\t') { - cur = txt_delete(&txt, cur, 1); + while (txt_byte(txt_at(&txt, cur - 1)) == '\t') { + cur = txt_ofs(txt_delete(txt_at(&txt, cur), 1)); } - cur = txt_insert_c(&txt, cur, '\n'); - while (tabs--) cur = txt_insert_c(&txt, cur, '\t'); + */ + cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), '\n')); + //while (tabs--) cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), '\t')); } break; default: - if ((c == '\t' || c >= ' ') && c <= KEY_UTF8_MAX) cur = txt_insert_c(&txt, cur, c); + if ((c == '\t' || c >= ' ') && c <= KEY_UTF8_MAX) cur = txt_ofs(txt_insert_c(txt_at(&txt, cur), c)); break; } break; diff --git a/txt.c b/txt.c index 38f34c4..b2dc2d8 100644 --- a/txt.c +++ b/txt.c @@ -56,7 +56,7 @@ static void txt_buf_append(Txt *b, TxtBufIdx bi, const char *s, u32 n) { buf->n += n; } -u32 txt_add_piece(Txt *b, TxtLoc l) { +TxtLoc txt_add_piece(Txt *b, TxtLoc l) { if (l.p > 0 && !l.i) { l.p--; l.i = b->ptbl.v[l.p].n; @@ -76,24 +76,24 @@ insert: txt_insert_piece(b, l.p, TXT_ADD, b->buf[TXT_ADD].n, 0); } } - return l.p; + return l; } -u32 txt_insert(Txt *b, u32 cur, const char *s, u32 n) { - TxtLoc l = txt_at(b, cur); - l.p = txt_add_piece(b, l); - TxtPiece *p = &b->ptbl.v[l.p]; - txt_buf_append(b, p->buf, s, n); +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]; + txt_buf_append(l.t, p->buf, s, n); p->n += n; - b->len += n; - return cur + n; + l.t->len += n; + l.i = p->n; + return l; } -u32 txt_insert_c(Txt *b, u32 cur, u32 ch) { +TxtLoc txt_insert_c(TxtLoc l, u32 ch) { char buf[6]; u32 n = utf8_encode_len(&ch, 1); utf8_encode(buf, &ch, 1); - return txt_insert(b, cur, buf, n); + return txt_insert(l, buf, n); } static int txt_are_pieces_adjacent(Txt *t, u32 a, u32 b) { @@ -102,46 +102,46 @@ static int txt_are_pieces_adjacent(Txt *t, u32 a, u32 b) { return pa->buf == pb->buf && pa->ofs + pa->n == pb->ofs; } -static void txt_join_or_kill(Txt *b, u32 pi) { - if (b->ptbl.v[pi].n == 0 && !(pi == 0 && b->ptbl.n == 1)) { - txt_remove_piece(b, pi); +static TxtLoc txt_join_or_kill(TxtLoc l) { + Txt *b = l.t; + if (l.t->ptbl.v[l.p].n == 0 && !(l.p == 0 && b->ptbl.n == 1)) { + txt_remove_piece(b, l.p); } - if (pi + 1 < b->ptbl.n && txt_are_pieces_adjacent(b, pi, pi + 1)) { - b->ptbl.v[pi].n += b->ptbl.v[pi+1].n; - txt_remove_piece(b, pi + 1); + if (l.p + 1 < b->ptbl.n && txt_are_pieces_adjacent(b, l.p, l.p + 1)) { + b->ptbl.v[l.p].n += b->ptbl.v[l.p+1].n; + txt_remove_piece(b, l.p + 1); } + return l; } -u32 txt_delete(Txt *b, u32 cur, u32 n) { - TxtLoc l = txt_at(b, cur); - u32 pi = txt_split_piece(b, l.p, l.i); +TxtLoc txt_delete(TxtLoc l, u32 n) { + u32 pi = txt_split_piece(l.t, l.p, l.i); if (pi > 0) pi--; - if (n > cur) n = cur; - cur -= n; - b->len -= n; + l.p = pi; + l.i = l.t->ptbl.v[l.p].n; for (;;) { - TxtPiece *p = &b->ptbl.v[pi]; - if (n >= p->n) { - n -= p->n; - p->n = 0; - if (pi > 0 || b->ptbl.n > 1) txt_remove_piece(b, pi); - } else { - p->n -= n; - n = 0; + ASSERT(l.i == l.t->ptbl.v[l.p].n); + if (l.i >= n) { + l.i -= n; + l.t->ptbl.v[l.p].n -= n; break; + } else { + l.t->ptbl.v[l.p].n -= l.i; + n -= l.i; + l.i = 0; + if (l.p == 0) break; + l.p = l.p - 1; + l.i = l.t->ptbl.v[l.p].n; } - if (pi == 0) break; - pi--; } - txt_join_or_kill(b, pi); - return cur; + return txt_join_or_kill(l); } -u32 txt_delete_c(Txt *b, u32 cur) { - while (cur > 0 && (txt_byte(b, txt_at(b, cur-1)) & 0xc0) == 0x80) - cur = txt_delete(b, cur, 1); - cur = txt_delete(b, cur, 1); - return cur; +TxtLoc txt_delete_c(TxtLoc l) { + while (!at_start(l) && (txt_byte(l) & 0xc0) == 0x80) + l = txt_delete(l, 1); + l = txt_delete(l, 1); + return l; } int txt_load(Txt *b, const char *path) { @@ -195,44 +195,37 @@ void txt_free(Txt *t) { free(t->ptbl.v); } -/* reading individual chars */ +/* navigation */ -u8 txt_byte(Txt *t, TxtLoc l) { - TxtPiece *p = &t->ptbl.v[l.p]; - TxtBuf *b = &t->buf[p->buf]; - if (l.i >= p->n) return 0; - return b->s[p->ofs + l.i]; -} - -u32 txt_chr(Txt *t, TxtLoc l) { - TxtPiece *p = &t->ptbl.v[l.p]; - TxtBuf *b = &t->buf[p->buf]; - return utf8_decode_at(b->s, p->ofs + l.i, p->ofs + p->n); -} - -/* cursor manipulation */ - -TxtLoc txt_at(Txt *b, u32 cur) { +TxtLoc txt_at(Txt *b, u32 ofs) { for (u32 i = 0; i < b->ptbl.n; i++) { - if (cur < b->ptbl.v[i].n) { - return (TxtLoc) { b, i, cur }; + if (ofs < b->ptbl.v[i].n) { + return (TxtLoc) { b, i, ofs }; } - cur -= b->ptbl.v[i].n; + ofs -= b->ptbl.v[i].n; } return (TxtLoc) { b, b->ptbl.n - 1, b->ptbl.v[b->ptbl.n - 1].n }; } -u32 txt_ofs(Txt *b, TxtLoc l) { +u32 txt_ofs(TxtLoc l) { u32 r = 0; for (u32 i = 0; i < l.p; i++) { - r += b->ptbl.v[i].n; + r += l.t->ptbl.v[i].n; } return r + l.i; } -TxtLoc txt_next(Txt *b, TxtLoc l) { - TxtPiece *p = &b->ptbl.v[l.p]; - if (l.p + 1 < b->ptbl.n) { +int txt_before(TxtLoc a, TxtLoc b) { + return a.p < b.p || (a.p == b.p && a.i < b.i); +} + +int txt_after(TxtLoc a, TxtLoc b) { + return a.p > b.p || (a.p == b.p && a.i > b.i); +} + +TxtLoc bnext(TxtLoc l) { + TxtPiece *p = &l.t->ptbl.v[l.p]; + if (l.p + 1 < l.t->ptbl.n) { if (l.i + 1 < p->n) l.i++; else l.p++, l.i = 0; } else { @@ -242,37 +235,106 @@ TxtLoc txt_next(Txt *b, TxtLoc l) { return l; } -TxtLoc txt_prev(Txt *b, TxtLoc l) { +TxtLoc bprev(TxtLoc l) { if (l.i > 0) { - return (TxtLoc) { b, l.p, l.i - 1 }; - } else if (l.p > 0) { - return (TxtLoc) { b, l.p - 1, b->ptbl.v[l.p - 1].n - 1 }; + return (TxtLoc) { l.t, l.p, l.i - 1 }; + } else if (l.p > 0 && l.t->ptbl.v[l.p - 1].n > 0) { + return (TxtLoc) { l.t, l.p - 1, l.t->ptbl.v[l.p - 1].n - 1 }; } else { - return (TxtLoc) { b, 0, 0 }; + return (TxtLoc) { l.t, 0, 0 }; } } -int txt_at_start(Txt *b, TxtLoc l) { - (void)b; +TxtLoc cnext(TxtLoc l) { + l = bnext(l); + while ((txt_byte(l) & 0xc0) == 0x80) l = bnext(l); + return l; +} + +TxtLoc cprev(TxtLoc l) { + l = bprev(l); + while ((txt_byte(l) & 0xc0) == 0x80) l = bprev(l); + return l; +} + +int at_start(TxtLoc l) { return l.p == 0 && l.i == 0; } -int txt_at_end(Txt *b, TxtLoc l) { - return l.p + 1 == b->ptbl.n && l.i == b->ptbl.v[l.p].n; +int at_end(TxtLoc l) { + return l.p + 1 == l.t->ptbl.n && l.i == l.t->ptbl.v[l.p].n; } -int txt_before(TxtLoc a, TxtLoc b) { - return a.p < b.p || (a.p == b.p && a.i < b.i); +TxtLoc next_newline(TxtLoc l) { + do l = cnext(l); + while (!at_end(l) && txt_byte(l) != '\n'); + return l; } -int txt_after(TxtLoc a, TxtLoc b) { - return a.p > b.p || (a.p == b.p && a.i > b.i); +TxtLoc prev_newline(TxtLoc l) { + do l = cprev(l); + while (!at_start(l) && txt_byte(l) != '\n'); + return l; +} + +TxtLoc start_of_line(TxtLoc l) { + l = prev_newline(l); + if (!at_start(l) && txt_byte(l) == '\n') l = cnext(l); + return l; +} + +TxtLoc end_of_line(TxtLoc l) { + TxtLoc start = start_of_line(l); + return txt_byte(start) == '\n' ? start : next_newline(start); +} + +u32 get_col(TxtLoc l) { + u32 n = 0; + for (TxtLoc tmp = start_of_line(l); txt_before(tmp, l); txt_chr_next(&tmp)) n++; + return n; +} + +TxtLoc at_col(TxtLoc l, u32 col) { + l = start_of_line(l); + while (col--) { + if (txt_chr_next(&l) == '\n') { + l = bprev(l); + break; + } + } + return l; +} + +TxtLoc prev_line(TxtLoc l) { + TxtLoc start = start_of_line(l); + return at_col(cprev(start), get_col(l)); +} + +TxtLoc next_line(TxtLoc l) { + TxtLoc end = end_of_line(l); + if (at_end(end)) return end; + return at_col(cnext(end), get_col(l)); +} + +/* reading chars */ + +u32 txt_chr(TxtLoc l) { + TxtPiece *p = &l.t->ptbl.v[l.p]; + TxtBuf *b = &l.t->buf[p->buf]; + return utf8_decode_at(b->s, p->ofs + l.i, p->ofs + p->n); +} + +u8 txt_byte(TxtLoc l) { + TxtPiece *p = &l.t->ptbl.v[l.p]; + TxtBuf *b = &l.t->buf[p->buf]; + if (l.i >= p->n) return 0; + return b->s[p->ofs + l.i]; } -u32 txt_chr_next(Txt *t, TxtLoc *l) { - if (txt_at_end(t, *l)) return 0; - u32 c = txt_chr(t, *l); +u32 txt_chr_next(TxtLoc *l) { + if (at_end(*l)) return 0; + u32 c = txt_chr(*l); u32 n = UTF8_CP_LEN(c); - for (u32 i = 0; i < n; i++) *l = txt_next(t, *l); + for (u32 i = 0; i < n; i++) *l = bnext(*l); return c; } diff --git a/txt.h b/txt.h index 3af9970..b33599b 100644 --- a/txt.h +++ b/txt.h @@ -29,29 +29,50 @@ typedef struct { u32 p, i; } TxtLoc; +/* text buffer manipulation */ + u32 txt_split_piece(Txt *b, u32 pi, u32 i); void txt_remove_piece(Txt *b, u32 pi); void txt_insert_piece(Txt *b, u32 pi, TxtBufIdx buf, u32 ofs, u32 n); -u32 txt_insert(Txt *b, u32 cur, const char *s, u32 n); -u32 txt_delete(Txt *b, u32 cur, u32 n); -u32 txt_insert_c(Txt *b, u32 cur, u32 ch); -u32 txt_delete_c(Txt *b, u32 cur); int txt_load(Txt *b, const char *path); int txt_save(Txt *b, const char *path); void txt_free(Txt *b); -TxtLoc txt_at(Txt *b, u32 cur); -u32 txt_ofs(Txt *b, TxtLoc l); -TxtLoc txt_next(Txt *b, TxtLoc l); -TxtLoc txt_prev(Txt *b, TxtLoc l); -int txt_at_start(Txt *b, TxtLoc l); -int txt_at_end(Txt *b, TxtLoc l); +/* insertion & deletion */ + +TxtLoc txt_insert(TxtLoc l, const char *s, u32 n); +TxtLoc txt_delete(TxtLoc l, u32 n); +TxtLoc txt_insert_c(TxtLoc l, u32 ch); +TxtLoc txt_delete_c(TxtLoc l); + +/* navigation */ + +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); -u32 txt_chr(Txt *b, TxtLoc l); -u8 txt_byte(Txt *b, TxtLoc l); -u32 txt_chr_next(Txt *b, TxtLoc *l); +TxtLoc bnext(TxtLoc l); +TxtLoc bprev(TxtLoc l); +TxtLoc cnext(TxtLoc l); +TxtLoc cprev(TxtLoc l); +int at_start(TxtLoc l); +int at_end(TxtLoc l); + +TxtLoc next_newline(TxtLoc l); +TxtLoc prev_newline(TxtLoc l); +TxtLoc start_of_line(TxtLoc l); +TxtLoc end_of_line(TxtLoc l); +TxtLoc prev_line(TxtLoc l); +TxtLoc next_line(TxtLoc l); +TxtLoc at_col(TxtLoc l, u32 col); +u32 get_col(TxtLoc l); + +/* reading */ + +u32 txt_chr(TxtLoc l); +u8 txt_byte(TxtLoc l); +u32 txt_chr_next(TxtLoc *l); #endif -- cgit v1.2.3