#ifndef TXT_H #define TXT_H #include "dynarr.h" #include "arena.h" #include "str.h" #define TXT_HIST_MAX 32 typedef enum : u8 { TXT_SRC, TXT_ADD } TxtBufIdx; typedef struct TxtPiece { TxtBufIdx buf; u32 ofs, n; } TxtPiece; typedef struct { char *s; u32 n, c; } TxtBuf; typedef struct { DYNARR(TxtPiece); int dirty; } TxtPieceTbl; typedef struct { struct Txt *t; u32 p, i; } TxtLoc; typedef struct { TxtPieceTbl v[TXT_HIST_MAX]; TxtLoc cur[TXT_HIST_MAX]; u32 i, n; } TxtHist; typedef struct Txt { TxtPieceTbl ptbl; TxtHist hist; TxtBuf buf[2]; u32 len; int readonly; } Txt; /* text buffer manipulation */ TxtLoc txt_split_piece(TxtLoc l); void txt_remove_piece(Txt *b, u32 pi); void txt_insert_piece(Txt *b, u32 pi, TxtBufIdx buf, u32 ofs, u32 n); void txt_load_empty(Txt *b); int txt_load(Txt *b, const char *path); int txt_save(Txt *b, const char *path); void txt_free(Txt *b); void txt_hist_push(Txt *t, TxtLoc cur); int txt_hist_fwd(Txt *t, TxtLoc *cur); int txt_hist_back(Txt *t, TxtLoc *cur); Str txt_collect_range(TxtLoc lo, TxtLoc hi, Arena *a); u32 txt_read_chunk(TxtLoc *lo, TxtLoc hi, char *buf, u32 sz); Str txt_next_chunk(TxtLoc *l); int txt_range_equal(TxtLoc lo, TxtLoc hi, Str s); /* insertion & deletion */ TxtLoc txt_insert(TxtLoc l, const char *s, u32 n); 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 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 prev_line_start(TxtLoc l); TxtLoc next_line_start(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); /* inline funcs */ static inline int at_start(TxtLoc l) { return l.p == 0 && l.i == 0; } static inline int at_end(TxtLoc l) { return l.p + 1 == l.t->ptbl.n && l.i == l.t->ptbl.v[l.p].n; } static inline 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 { l.i++; if (l.i > p->n) l.i = p->n; } return l; } static inline TxtLoc bprev(TxtLoc l) { if (l.i > 0) { 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) { l.t, 0, 0 }; } } static inline TxtLoc cnext(TxtLoc l) { l = bnext(l); while ((txt_byte(l) & 0xc0) == 0x80) l = bnext(l); return l; } static inline TxtLoc cprev(TxtLoc l) { l = bprev(l); while ((txt_byte(l) & 0xc0) == 0x80) l = bprev(l); return l; } #endif