summaryrefslogtreecommitdiff
path: root/txt.c
diff options
context:
space:
mode:
authorWormHeamer2025-12-28 20:30:37 -0500
committerWormHeamer2025-12-28 20:30:37 -0500
commit2fe237e65a13545c053c31b7b413898d5b8734ac (patch)
tree66354165554feeb303010473c22e67b0b48cda87 /txt.c
parent3ed6bbd8eb7214268d6e042736dcd5285cb4f4d7 (diff)
remove most explicit Txt* params, fix some utf-8 problems
Diffstat (limited to 'txt.c')
-rw-r--r--txt.c226
1 files changed, 144 insertions, 82 deletions
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;
}