commit 72d7d4897d2f50c80daa55551156b483b69661d7
parent bb5fd5b9fcff1364b2bea20ebaaa8ae3436a32f7
Author: Renev Pavel <an2qzavok@gmail.com>
Date: Sun, 27 Nov 2022 22:24:44 +0000
tabul: more code
Diffstat:
M | src/tabul/tabul.c | | | 233 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
1 file changed, 193 insertions(+), 40 deletions(-)
diff --git a/src/tabul/tabul.c b/src/tabul/tabul.c
@@ -1,14 +1,14 @@
/*
- Simple graphical editor for tsv files
+ Primitive editor for tsv files
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
-// #include <String.h>
+#include <String.h>
#include <thread.h>
#include <draw.h>
-// #include <keyboard.h>
+#include <keyboard.h>
#include <mouse.h>
typedef struct Ed Ed;
@@ -21,13 +21,24 @@ struct Ed {
};
Ed *head;
-
Image *bord, *text, *bg, *curbg;
-Rectangle cell, cells, edit;
+Rectangle cell, cells;
Point cur;
Mousectl *mctl;
+Keyboardctl *kctl;
Mouse mv;
int rv[2];
+Rune kv;
+char *file;
+
+struct {
+ Rectangle r;
+ struct {
+ int s;
+ int e;
+ } sel;
+ String *str;
+} edit;
Ed *
ed(Ed *parent, int x, int y, char *s)
@@ -37,30 +48,41 @@ ed(Ed *parent, int x, int y, char *s)
return e;
}
-/*
+
void
freeed(Ed *e)
{
- if (e != nil) {
- free(e->s);
- free(e);
- }
+ if (e != nil) free(e->s), free(e);
+}
+
+
+Ed *
+getcell(Point p)
+{
+ Ed *ep = head;
+ while ((ep != nil) && ((ep->x != p.x) || (ep->y != p.y)))
+ ep = ep->prev;
+ return ep;
}
-*/
void
-loadfile(char *file)
+loadfile(char *newfile)
{
char *s, *args[64];
int n, x, y = 0;
- Biobuf *b = Bopen(file, OREAD);
- if (b == nil) sysfatal("loadfile: %r");
-
+ Biobuf *b = Bopen(newfile, OREAD);
+ if (b == nil) {
+ 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++) {
- head = ed(head, x, y, args[x]);
+ head = ed(head, x, y, strdup(args[x]));
};
+ free(s);
y++;
}
Bterm(b);
@@ -76,6 +98,22 @@ savefile(char *)
}
void
+flushedit(void)
+{
+ Ed *ep = getcell(cur);
+ if (strcmp(s_to_c(edit.str), ep->s) != 0)
+ head = ed(head, cur.x, cur.y, strdup(s_to_c(edit.str)));
+}
+
+void
+setedit(void)
+{
+ Ed *ep = getcell(cur);
+ s_reset(edit.str);
+ if (ep != nil) s_append(edit.str, ep->s);
+}
+
+void
drawcell(int x, int y)
{
Ed *ep;
@@ -84,28 +122,48 @@ drawcell(int x, int y)
Rectangle r = rectaddpt(cell, addpt(Pt(x * cell.max.x, y * cell.max.y), cells.min));
draw(screen, r, bord, nil, ZP);
draw(screen, insetrect(r, 1), cellbg, nil, ZP);
- for (ep = head; ep != nil; ep = ep->prev) {
- if ((ep->x == x) && (ep->y == y)) {
- stringn(screen, addpt(r.min, Pt(3, 3)), text, ZP, font, ep->s, 8);
- break;
- }
+ ep = getcell(Pt(x, y));
+ if (ep != nil) stringn(screen, addpt(r.min, Pt(3, 3)), text, ZP, font, ep->s, 8);
+}
+
+void
+drawedit(void)
+{
+ char buf[256];
+ snprint(buf, 16, "[%d %d] ", cur.x, cur.y);
+ draw(screen, edit.r, curbg, nil, ZP);
+ Point p = edit.r.min;
+ if (edit.str != nil) {
+ strncat(buf, s_to_c(edit.str), 256 - strlen(buf));
}
+ string(screen, p, text, ZP, font, buf);
}
void
resize(void)
{
- edit = Rpt(
+ edit.r = Rpt(
screen->r.min,
- Pt(screen->r.max.x, screen->r.min.y + font->height + 2)
+ Pt(screen->r.max.x, screen->r.min.y + font->height)
);
cells = Rpt(
- addpt(screen->r.min, Pt(0, Dy(edit))),
+ addpt(screen->r.min, Pt(0, Dy(edit.r))),
screen->r.max
);
}
void
+redraw(void)
+{
+ int x, y, maxx, maxy;
+ maxx = Dx(cells) / cell.max.x;
+ maxy = Dy(cells) / cell.max.y;
+ drawedit();
+ for (x = 0; x <= maxx; x++) for (y = 0; y <= maxy; y++)
+ drawcell(x, y);
+}
+
+void
colors(void)
{
bord = display->black;
@@ -115,44 +173,139 @@ colors(void)
}
void
+mouse(Mouse m)
+{
+ if (m.buttons == 1) {
+ if (ptinrect(m.xy, cells) != 0) {
+ Point mr = subpt(m.xy, cells.min);
+ Point newcur = Pt(mr.x / cell.max.x, mr.y / cell.max.y);
+ if ((cur.x != newcur.x) || (cur.y != newcur.y)) {
+ Point oldcur = cur;
+ cur = newcur;
+ drawcell(oldcur.x, oldcur.y);
+ drawcell(newcur.x, newcur.y);
+ setedit();
+ drawedit();
+ flushimage(display, 1);
+ }
+ }
+ } else if (m.buttons == 4) {
+ static char *items[] = {"load", "save", 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:
+ if (enter("load", buf, 1024, mctl, kctl, nil) > 0) {
+ while (head != nil) {
+ Ed *prev = head->prev;
+ freeed(head);
+ head = prev;
+ }
+ loadfile(strdup(buf));
+ redraw();
+ flushimage(display, 1);
+ }
+ break;
+ case 1:
+ if (enter("save", buf, 1024, mctl, kctl, nil) > 0) {
+ savefile(strdup(buf));
+ }
+ break;
+ }
+ }
+}
+
+void
+kbd(Rune r)
+{
+ switch (r) {
+ case 0x7f: /* del */
+ threadexitsall(nil);
+ case 0x0a: /* newline */
+ flushedit();
+ drawcell(cur.x, cur.y);
+ flushimage(display, 1);
+ break;
+ case 0x09: /* tab */
+ flushedit();
+ cur.x++;
+ setedit();
+ drawedit();
+ drawcell(cur.x, cur.y);
+ drawcell(cur.x-1, cur.y);
+ flushimage(display, 1);
+ break;
+ case 0x08: /* backspace */
+ // TODO: make utf8-complaint, make thread safe?
+ if (edit.str->ptr > edit.str->base) edit.str->ptr--;
+ s_terminate(edit.str);
+ drawedit();
+ flushimage(display, 1);
+ break;
+ default:
+ s_putc(edit.str, r);
+ s_terminate(edit.str);
+ drawedit();
+ flushimage(display, 1);
+ }
+}
+
+void
+init(void)
+{
+ if (initdraw(nil, nil, "tabul") == 0) sysfatal("%r");
+ colors();
+ mctl = initmouse(nil, screen);
+ kctl = initkeyboard(nil);
+ cell = Rect(0, 0, stringwidth(font, "0") * 8 + 4, font->height + 4);
+ edit.str = s_new();
+ cur = ZP;
+ setedit();
+ resize();
+ redraw();
+ flushimage(display, 1);
+}
+
+void
usage(void)
{
- fprint(2, "usage: %s [tsv file]\n", argv0);
+ fprint(2, "usage: %s [tsv_file]\n", argv0);
+ threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
- int x, y;
ARGBEGIN {
default: usage();
} ARGEND;
- if (argc == 1) loadfile(argv[0]);
- if (initdraw(nil, nil, "tabul") == 0) sysfatal("%r");
- colors();
- mctl = initmouse(0, screen);
- cell = Rect(0, 0, stringwidth(font, "0") * 8 + 6, font->height + 6);
- resize();
- draw(screen, edit, curbg, nil, ZP);
- for (x = 0; x < 10; x++) for (y = 0; y < 24; y++)
- drawcell(x, y);
- flushimage(display, 1);
+ if (argc == 1) loadfile(strdup(argv[0]));
+ init();
Alt alts[] = {
{mctl->c, &mv, CHANRCV},
{mctl->resizec, rv, CHANRCV},
+ {kctl->c, &kv, CHANRCV},
{0, 0, CHANEND},
};
for(;;){
switch(alt(alts)) {
case 0: /* mouse */
+ mouse(mv);
break;
case 1: /* resize */
if (getwindow(display, Refnone) < 0) sysfatal("%r");
resize();
- draw(screen, edit, curbg, nil, ZP);
- for (x = 0; x < 10; x++) for (y = 0; y < 24; y++)
- drawcell(x, y);
- flushimage(display, 1);
+ redraw();
+ flushimage(display, 1);
+ break;
+ case 2: /* keyboard */
+ kbd(kv);
break;
}
}