stew

a monorepo of some sort
Log | Files | Refs

commit f9999dc4de71128e720cc6033402cf925f6245dd
parent 34b341144e9e63e1ad92d5937c32cd45669d9471
Author: rpa <rpa@laika>
Date:   Sun, 18 Dec 2022 15:13:06 +0000

tabul: rework internal data structure

Diffstat:
Msrc/tabul/tabul.c | 296+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 175 insertions(+), 121 deletions(-)

diff --git a/src/tabul/tabul.c b/src/tabul/tabul.c @@ -2,9 +2,6 @@ Primitive TSV spreadsheet editor TODO: - - clear trailing whitespace and newlines when writing tables - - switch to another internal data format: - instead of rectangle array, store lines (and line lengths) separately - get some kind of refcount system for cell data instead of strdup`ing - look at optimizing drawing routines */ @@ -18,23 +15,29 @@ #include <keyboard.h> #include <mouse.h> -typedef struct Table Table; -struct Table{ - Rectangle r; - char **s; +typedef struct Array Array; +struct Array { + long n; + void **p; + void (*freep)(void *); + void *aux; }; -Table *view; - -Table * alloctable(Rectangle); -void freetable(Table *); -Table * readtable(int); -int writetable(Table *, int); -void resizetable(Table *, Rectangle); -char ** tfetch(Table *, Point); -void tstore(Table *, Point, char *); -void cleartable(Table *, Rectangle); -Table * duptable(Table *, Rectangle); -void pastetable(Table *, Table *, Point); + +Array * createarray(void (*freep)(void *)); +void freearray(void *); +void astore(Array *, int, void *); +void * afetch(Array *, int); +void atrim(Array *ar); + +Array *view; + +Array * readtable(int); +int writetable(Array *, int); +char * tfetch(Array *, Point); +void tstore(Array *, Point, char *); +void cleartable(Array *, Rectangle); +Array * duptable(Array *, Rectangle); +void pastetable(Array *, Array *, Point); Image *bord, *text, *bg, *curbg; Rectangle cell, blank; @@ -78,10 +81,10 @@ loadfile(char *file) fprint(2, "loadfile: %r\n"); return; } - Table *t = readtable(fd); + Array *t = readtable(fd); close(fd); if (t != nil) { - freetable(view); + freearray(view); view = t; } } @@ -106,9 +109,9 @@ snarfsel(void) fprint(2, "snarfsel: %r"); return; } - Table *t = duptable(view, cells.sel); + Array *t = duptable(view, cells.sel); writetable(t, fd); - freetable(t); + freearray(t); close(fd); } @@ -120,7 +123,7 @@ pastesel(void) fprint(2, "pastesel: %r"); return; } - Table *t = readtable(fd); + Array *t = readtable(fd); pastetable(view, t, cells.cur); close(fd); } @@ -132,7 +135,7 @@ _cell(Image *screen, Rectangle r, Image *brd, Image *bg, Image *fg, int t, Font draw(screen, r, brd, nil, ZP); draw(screen, r2, bg, nil, ZP); if (text != nil) { - int n = strlen(text); + int n = 16;//strlen(text); while (stringnwidth(font, text, n) > Dx(r2)) n--; stringn(screen, addpt(r2.min, Pt(1,(Dy(r2) - font->height)/2)), fg, ZP, font, text, n); } @@ -150,8 +153,8 @@ drawcell(Point xy) (xy.x - cells.scroll.x) * cell.max.x, (xy.y - cells.scroll.y) * cell.max.y), cells.r.min)); if (ptinrect(r.min, cells.r) == 1) { - char **v = tfetch(view, xy); - if ((v != nil) && (*v != nil)) s = *v; + char *v = tfetch(view, xy); + if (v != nil) s = v; _cell(screen, r, bord, cellbg, text, t, font, s); } } @@ -225,10 +228,15 @@ redraw(void) void colors(void) { - bord = display->black; - text = display->black; - bg = display->white; - curbg = allocimage(display, Rect(0,0,1,1), XRGB32, 1, 0xddddddff); + Image *black, *white, *gray; + black = display->black; + white = display->white; + gray = allocimage(display, Rect(0,0,1,1), XRGB32, 1, 0xddddddff); + + bord = black; + text = black; + bg = white; + curbg = gray; } void @@ -355,12 +363,16 @@ kbd(Rune r) // TODO: make utf8-complaint, make thread safe? if (edit.str->ptr > edit.str->base) edit.str->ptr--; s_terminate(edit.str); + flushedit(); + drawcell(cells.cur); drawedit(); flushimage(display, 1); break; default: s_putc(edit.str, r); s_terminate(edit.str); + flushedit(); + drawcell(cells.cur); drawedit(); flushimage(display, 1); } @@ -400,7 +412,7 @@ threadmain(int argc, char **argv) if (argc == 1) { loadfile(argv[0]); strncat(file, argv[0], 256); - } else view = alloctable(Rect(0, 0, 1, 1)); + } else view = createarray(freearray); init(); Alt alts[] = { {mctl->c, &mv, CHANRCV}, @@ -430,15 +442,15 @@ void flushedit(void) { if (strlen(s_to_c(edit.str)) == 0) tstore(view, cells.cur, nil); - else tstore(view, cells.cur, strdup(s_to_c(edit.str))); + else tstore(view, cells.cur, s_to_c(edit.str)); } void setedit(void) { - char **v = tfetch(view, cells.cur); + char *v = tfetch(view, cells.cur); s_reset(edit.str); - if ((v != nil) && (*v != nil)) s_append(edit.str, *v); + if (v != nil) s_append(edit.str, v); } void @@ -452,112 +464,79 @@ drawedit(void) _cell(screen, edit.r, bord, curbg, text, 1, font, buf); } -Table * -alloctable(Rectangle r) -{ - Table *t; - t = malloc(sizeof(Table)); - *t = (Table) {r, mallocz(sizeof(char *) * Dx(r) * Dy(r), 1)}; - return t; -} - -void -freetable(Table *t) -{ - int x, y; - if (t == nil) return; - for (x = t->r.min.x; x < t->r.max.x; x++) - for (y = t->r.min.y; y < t->r.max.y; y++) { - free(t->s[x - t->r.min.x + (y - t->r.min.y) * Dx(t->r)]); - }; - free(t->s); - free(t); -} - -void -resizetable(Table *t, Rectangle r) -{ - char **s = mallocz(sizeof(char *) * Dx(r) * Dy(r), 1); - int x, y; - for (x = r.min.x; x < r.max.x; x++) - for (y = r.min.x; y < r.max.y; y++) { - int i = x - r.min.x + y * Dx(r); - char **v = tfetch(t, Pt(x, y)); - if ((v != nil) && (*v != nil)) s[i] = strdup(*v); - } - for (x = t->r.min.x; x < t->r.max.x; x++) - for (y = t->r.min.y; y < t->r.max.y; y++) { - free(t->s[x - t->r.min.x + (y - t->r.min.y) * Dx(t->r)]); - }; - free(t->s); - *t = (Table){r, s}; -} - -Table * -duptable(Table *t, Rectangle r) +Array * +duptable(Array *t, Rectangle r) { - Table *n = alloctable(r); + assert(t != nil); + Array *n = createarray(freearray); int x, y; - for (x = r.min.x; x < r.max.x; x++) - for (y = r.min.x; y < r.max.y; y++) { - char **v = tfetch(t, Pt(x, y)); - if ((v != nil) && (*v != nil)) n->s[x - r.min.x + (y - r.min.y) * Dx(r)] = strdup(*v); + for (x = r.min.x; x < r.max.x; x++) + for (y = r.min.y; y < r.max.y; y++) { + char *s = tfetch(t, Pt(x, y)); + tstore(n, subpt(Pt(x, y), r.min), s); } return n; } void -cleartable(Table *t, Rectangle r) +cleartable(Array *t, Rectangle r) { + assert(t != nil); int x, y; - for (x = r.min.x; x < r.max.x; x++) - for (y = r.min.x; y < r.max.y; y++) { + for (x = r.min.x; x < r.max.x; x++) + for (y = r.min.y; y < r.max.y; y++) { tstore(t, Pt(x, y), nil); } } void -pastetable(Table *to, Table *fr, Point sp) +pastetable(Array *to, Array *fr, Point sp) { + assert(to != nil); + assert(fr != nil); + Rectangle r; int x, y; - for (x = fr->r.min.x; x <= fr->r.max.x; x++) - for (y = fr->r.min.x; y <= fr->r.max.y; y++) { - char **v = tfetch(fr, Pt(x, y)); - if ((v != nil) && (*v != nil)) tstore(to, addpt(sp, Pt(x, y)), strdup(*v)); - else tstore(to, addpt(sp, Pt(x, y)), nil); + r.min = ZP; + r.max.x = 0; + r.max.y = fr->n; + for (y = 0; y < fr->n; y++) { + Array *row = afetch(fr, y); + if ((row != nil) && (row->n > r.max.x)) { + r.max.x = row->n; + } + } + r = rectaddpt(r, sp); + for (x = r.min.x; x < r.max.x; x++) + for (y = r.min.y; y < r.max.y; y++) { + char *s = tfetch(fr, subpt(Pt(x, y), r.min)); + tstore(to, Pt(x, y), s); } } -char ** -tfetch(Table *t, Point xy) +char * +tfetch(Array *t, Point xy) { - if ((t->s == nil) || (ptinrect(xy, t->r) == 0)) return nil; - return &(t->s[xy.x - t->r.min.x + (xy.y - t->r.min.y) * Dx(t->r)]); + Array *row = afetch(t, xy.y); + if (row == nil) return nil; + return afetch(row, xy.x); } void -tstore(Table *t, Point xy, char *s) -{ - char **v = tfetch(t, xy); - if ((s == nil) && ((v == nil) || (*v == nil))) return; - Rectangle new = { - (xy.x < t->r.min.x) ? xy.x : t->r.min.x, - (xy.y < t->r.min.y) ? xy.y : t->r.min.y, - (xy.x >= t->r.max.x) ? xy.x + 1 : t->r.max.x, - (xy.y >= t->r.max.y) ? xy.y + 1 : t->r.max.y, - }; - if (eqrect(new, t->r) == 0) { - resizetable(t, new); - } - v = tfetch(t, xy); - free(*v); - *v = s; +tstore(Array *t, Point xy, char *s) +{ + Array *row = afetch(t, xy.y); + if (row == nil) row = createarray(free); + char *col = afetch(row, xy.x); + free(col); + if (s != nil) s = strdup(s); + astore(row, xy.x, s); + astore(t, xy.y, row); } -Table * +Array * readtable(int fd) { - Table *t = mallocz(sizeof(Table), 1); + Array *t = mallocz(sizeof(Array), 1); char *s, *args[64]; int n, x, y = 0; fd = dup(fd, -1); @@ -569,7 +548,7 @@ readtable(int fd) while( (s = Brdstr(b, '\n', 1)) != nil) { n = getfields(s, args, 64, 0, "\t"); for (x = 0; x < n; x++) { - if (strlen(args[x]) != 0) tstore(t, Pt(x, y), strdup(args[x])); + if (strlen(args[x]) != 0) tstore(t, Pt(x, y), args[x]); }; free(s); y++; @@ -579,19 +558,94 @@ readtable(int fd) } int -writetable(Table *t, int fd) +writetable(Array *t, int fd) { fd = dup(fd, -1); Biobuf *b = Bfdopen(fd, OWRITE); int x, y; - for (y = t->r.min.y; y < t->r.max.y; y++) { - for (x = t->r.min.x; x < t->r.max.x; x++) { - char **v = tfetch(t, Pt(x, y)); - if (x != t->r.min.x) Bprint(b, "\t"); - if ((v != nil) && (*v != nil)) Bprint(b, "%s", *v); + for (y = 0; y < t->n; y++) { + Array *row = afetch(t, y); + if (row != nil) { + atrim(row); + if (row->n == 0) { + freearray(row); + astore(t, y, nil); + } + } + } + atrim(t); + + for (y = 0; y < t->n; y++) { + Array *row = afetch(t, y); + if (row == nil) continue; + for (x = 0; x < row->n; x++) { + char *s = afetch(row, x); + if (x != 0) Bprint(b, "\t"); + if (s != nil) Bprint(b, "%s", s); } Bprint(b, "\n"); } Bterm(b); return 0; } + +Array * +createarray(void (*freep)(void *)) +{ + Array *new = mallocz(sizeof(Array), 1); + new->freep = freep; + return new; +} + +void +freearray(void *v) +{ + if (v == nil) return; + Array *ar = v; + if (ar->freep != nil) { + int i; + for (i = 0; i < ar->n; i++) ar->freep(ar->p[i]); + } + free(ar); +} + +void +astore(Array *ar, int n, void *p) +{ + assert(ar != nil); + assert(n >= 0); + if (n >= ar->n) { + ar->p = realloc(ar->p, sizeof(void *) * (n + 1)); + int i; + for (i = ar->n; i < n; i++) ar->p[i] = nil; + ar->n = n + 1; + } + ar->p[n] = p; +} + +void * +afetch(Array *ar, int n) +{ + assert(ar != nil); + assert(n >= 0); + if (n < ar->n) { + return ar->p[n]; + } + else return nil; +} + +void +atrim(Array *ar) +{ + assert(ar != nil); + int n; + for (n = ar->n - 1; n >= 0; n--) { + if (ar->p[n] != nil) { + ar->n = n + 1; + return; + } + } + ar->n = 0; + free(ar->p); + ar->p = nil; +}