diff options
Diffstat (limited to 'txt.c')
| -rw-r--r-- | txt.c | 226 |
1 files changed, 144 insertions, 82 deletions
@@ -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; } |
