stew

a monorepo of some sort
Log | Files | Refs

commit 6ae6525074eb4c0a703c6e560bf013e9cf429773
parent f6511f4cd7bab5cda46c1bf4808b7d0265d056d2
Author: rpa <rpa@laika>
Date:   Sun, 11 Dec 2022 23:13:13 +0000

tabul: snarf/paste

Diffstat:
Msrc/tabul/tabul.c | 297++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 211 insertions(+), 86 deletions(-)

diff --git a/src/tabul/tabul.c b/src/tabul/tabul.c @@ -1,5 +1,12 @@ /* - Primitive editor for tsv files + 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 */ #include <u.h> @@ -16,6 +23,18 @@ struct Table{ Rectangle r; char **s; }; +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); Image *bord, *text, *bg, *curbg; Rectangle cell, blank; @@ -24,7 +43,8 @@ Keyboardctl *kctl; Mouse mv; int rv[2]; Rune kv; -char *file; +char file[256]; +char *snarf = "/tmp/tabsnarf"; struct { Rectangle r; @@ -46,60 +66,63 @@ struct { Point cur; } cells; -Table view; - -void resizeview(Rectangle r); -void clearview(void); -void setview(Point xy, char *s); -char ** getview(Point xy); -void _cell(Image *screen, Rectangle r, Image *brd, Image *bg, Image *fg, int t, Font *font, char *text); +void _cell(Image *, Rectangle, Image *, Image *, Image *, int, Font *, char *); +void snarfsel(void); +void pastesel(void); void -loadfile(char *newfile) +loadfile(char *file) { - char *s, *args[64]; - int n, x, y = 0; - Biobuf *b = Bopen(newfile, OREAD); - if (b == nil) { + int fd = open(file, OREAD); + if (fd < 0) { fprint(2, "loadfile: %r\n"); return; } - free(file); - file = newfile; - 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) setview(Pt(x, y), strdup(args[x])); - }; - free(s); - y++; + Table *t = readtable(fd); + close(fd); + if (t != nil) { + freetable(view); + view = t; } - Bterm(b); } void -savefile(char *newfile) +savefile(char *file) { - // TODO clean up trainling whitespace (tabs and newlines) - // TODO switch over to bio - int fd = create(newfile, OWRITE, 0666); + int fd = create(file, OWRITE, 0666); if (fd < 0) { fprint(2, "savefile: %r\n"); return; } - Biobuf *b = Bfdopen(fd, OWRITE); - free(file); - file = newfile; - int x, y; - for (y = view.r.min.y; y < view.r.max.y; y++) { - for (x = view.r.min.x; x < view.r.max.x; x++) { - char **v = getview(Pt(x, y)); - if (x != view.r.min.x) Bprint(b, "\t"); - if ((v != nil) && (*v != nil)) Bprint(b, "%s", *v); - } - Bprint(b, "\n"); + writetable(view, fd); + close(fd); +} + +void +snarfsel(void) +{ + int fd = create(snarf, OWRITE, 0666); + if (fd < 0) { + fprint(2, "snarfsel: %r"); + return; } - Bterm(b); + Table *t = duptable(view, cells.sel); + writetable(t, fd); + freetable(t); + close(fd); +} + +void +pastesel(void) +{ + int fd = open(snarf, OREAD); + if (fd < 0) { + fprint(2, "pastesel: %r"); + return; + } + Table *t = readtable(fd); + pastetable(view, t, cells.cur); + close(fd); } void @@ -127,7 +150,7 @@ 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 = getview(xy); + char **v = tfetch(view, xy); if ((v != nil) && (*v != nil)) s = *v; _cell(screen, r, bord, cellbg, text, t, font, s); } @@ -257,30 +280,42 @@ mouse(Mouse m) flushimage(display, 1); } } else if (m.buttons == 4) { - static char *items[] = {"load", "save", "exit", nil}; + static char *items[] = {"cut", "paste", "snarf", "load", "save", "exit", nil}; static Menu menu = { items, nil, 0, }; - char buf[1024]; - buf[0] = '\0'; - if (file != nil) strncat(buf, file, 1024); switch (menuhit(3, mctl, &menu, nil)) { - case 0: /* load */ - if (enter("load", buf, 1024, mctl, kctl, nil) > 0) { - clearview(); - loadfile(strdup(buf)); + case 0: /* cut */ + snarfsel(); + cleartable(view, cells.sel); + setedit(); + redraw(); + flushimage(display, 1); + break; + case 1: /* paste */ + pastesel(); + setedit(); + redraw(); + flushimage(display, 1); + break; + case 2: /* snarf */ + snarfsel(); + break; + case 3: /* load */ + if (enter("load", file, 1024, mctl, kctl, nil) > 0) { + loadfile(file); redraw(); flushimage(display, 1); } break; - case 1: /* save */ - if (enter("save", buf, 1024, mctl, kctl, nil) > 0) { - savefile(strdup(buf)); + case 4: /* save */ + if (enter("save", file, 1024, mctl, kctl, nil) > 0) { + savefile(file); } break; - case 2: /* exit */ + case 5: /* exit */ threadexitsall(nil); break; } @@ -362,7 +397,10 @@ threadmain(int argc, char **argv) ARGBEGIN { default: usage(); } ARGEND; - if (argc == 1) loadfile(strdup(argv[0])); + if (argc == 1) { + loadfile(argv[0]); + strncat(file, argv[0], 256); + } else view = alloctable(Rect(0, 0, 1, 1)); init(); Alt alts[] = { {mctl->c, &mv, CHANRCV}, @@ -391,17 +429,14 @@ threadmain(int argc, char **argv) void flushedit(void) { - char **v = getview(cells.cur); - if ((v == nil) || (*v == nil) || (strcmp(s_to_c(edit.str), *v) != 0)) { - if (strlen(s_to_c(edit.str)) != 0) setview(cells.cur, strdup(s_to_c(edit.str))); - else setview(cells.cur, nil); - } + if (strlen(s_to_c(edit.str)) == 0) tstore(view, cells.cur, nil); + else tstore(view, cells.cur, strdup(s_to_c(edit.str))); } void setedit(void) { - char **v = getview(cells.cur); + char **v = tfetch(view, cells.cur); s_reset(edit.str); if ((v != nil) && (*v != nil)) s_append(edit.str, *v); } @@ -417,54 +452,144 @@ 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 -resizeview(Rectangle r) +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 = getview(Pt(x, y)); - s[i] = (v == nil) ? nil : *v; + 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) +{ + Table *n = alloctable(r); + 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); } - free(view.s); - view.r = r; - view.s = s; + return n; } void -clearview(void) +cleartable(Table *t, Rectangle r) { - int i; - if ((view.s == nil) || (Dx(view.r) * Dy(view.r) == 0)) return; - for (i = 0; i < Dx(view.r) * Dy(view.r); i++) { - free(view.s[i]); - view.s[i] = nil; + int x, y; + for (x = r.min.x; x < r.max.x; x++) + for (y = r.min.x; y < r.max.y; y++) { + tstore(t, Pt(x, y), nil); } } void -setview(Point xy, char *s) +pastetable(Table *to, Table *fr, Point sp) +{ + 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); + } +} + +char ** +tfetch(Table *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)]); +} + +void +tstore(Table *t, Point xy, char *s) { Rectangle new = { - 0, - 0, - (xy.x >= view.r.max.x) ? xy.x + 1 : view.r.max.x, - (xy.y >= view.r.max.y) ? xy.y + 1 : view.r.max.y, + (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, view.r) == 0) { - resizeview(new); + if (eqrect(new, t->r) == 0) { + resizetable(t, new); } - char **v = getview(xy); + char **v = tfetch(t, xy); free(*v); *v = s; } -char ** -getview(Point xy) +Table * +readtable(int fd) { - if ((view.s == nil) || (ptinrect(xy, view.r) == 0)) return nil; - int i = xy.x + xy.y * Dx(view.r); - return &view.s[i]; + Table *t = mallocz(sizeof(Table), 1); + char *s, *args[64]; + int n, x, y = 0; + fd = dup(fd, -1); + Biobuf *b = Bfdopen(fd, OREAD); + if (b == nil) { + fprint(2, "readtable: %r\n"); + return nil; + } + 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])); + }; + free(s); + y++; + } + Bterm(b); + return t; +} + +int +writetable(Table *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); + } + Bprint(b, "\n"); + } + Bterm(b); + return 0; }