richterm

"terminal emulator" with support for text fonts and images for plan9
git clone git://nsmpr.xyz/richterm.git
Log | Files | Refs | README

commit 80e60139ca21b441842b2c645092961fbeac6b09
parent b4033c14386ced8dbbcdbed3b9007b550c62273a
Author: glenda <glenda@9front.local>
Date:   Tue, 25 Jan 2022 20:13:14 +0000

much code, new internal data format, new drawing functions

Diffstat:
MTODO | 2++
Mrichterm.c | 265++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mrichterm.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 303 insertions(+), 14 deletions(-)

diff --git a/TODO b/TODO @@ -5,3 +5,5 @@ Rename Objects to Elements. Rename array to slice. Rethink color palette. + +Rewrite drawing to use absolute coords for page.r and cursor pos diff --git a/richterm.c b/richterm.c @@ -96,11 +96,6 @@ threadmain(int argc, char **argv) Object *ov, *ov2, *obj; Array *av; - ov = nil; - ov2 = nil; - obj = nil; - av = nil; - ARGBEGIN{ case 'D': chatty9p++; @@ -112,6 +107,10 @@ threadmain(int argc, char **argv) usage(); } ARGEND + ov = nil; + ov2 = nil; + obj = nil; + av = nil; mmode = MM_NONE; if (initdraw(0, 0, argv0) < 0) @@ -158,9 +157,12 @@ threadmain(int argc, char **argv) redrawc = chancreate(sizeof(Object *), 8); insertc = chancreate(sizeof(Array *), 8); + generatesampleelems(); + resize(); draw(screen, screen->r, Inormbg, nil, ZP); drawscrollbar(); + drawelems(); flushimage(display, 1); if(rfork(RFENVG) < 0) @@ -168,9 +170,14 @@ threadmain(int argc, char **argv) quotefmtinstall(); atexit(shutdown); + /* pidchan = chancreate(sizeof(int), 0); proccreate(runcmd, argv, 16 * 1024); hostpid = recvul(pidchan); + */ + + threadsetname("main"); + enum {MOUSE, RESIZE, REDRAW, INSERT, KBD, AEND}; Alt alts[AEND + 1] = { @@ -182,8 +189,6 @@ threadmain(int argc, char **argv) {nil, nil, CHANEND}, }; - threadsetname("main"); - for (;;) { switch(alt(alts)) { case MOUSE: @@ -198,8 +203,10 @@ threadmain(int argc, char **argv) case REDRAW: while (nbrecv(redrawc, &ov2) != 0) ov = minobj(ov, ov2); lockdisplay(display); - redraw(ov); + // redraw(ov); + draw(screen, screen->r, Inormbg, nil, ZP); drawscrollbar(); + drawelems(); flushimage(display, 1); unlockdisplay(display); break; @@ -338,6 +345,8 @@ mouse(Mousectl *mc, Mouse mv, int *mmode) } break; case MM_TEXT: + break; + if (mv.buttons == 1) { selstart = getsel(mv.xy); selend = selstart; @@ -368,6 +377,8 @@ mouse(Mousectl *mc, Mouse mv, int *mmode) } break; case MM_SELECT: + break; + if (mv.buttons == (1|2)) { /* cut */ break; @@ -416,7 +427,7 @@ scroll(Point p, Rich *r) if (p.x < 0) p.x = 0; if (p.x > r->page.max.x) p.x = r->page.max.x; if (p.y < 0) p.y = 0; - if (p.y > r->page.max.y) p.y = r->page.max.y; + // if (p.y > r->page.max.y) p.y = r->page.max.y; r->page.scroll = p; @@ -429,7 +440,7 @@ scroll(Point p, Rich *r) } cur = obj->startpt; - lockdisplay(display); +/* lockdisplay(display); draw(screen, rich.page.r, Inormbg, nil, ZP); for (; i < rich.objects->count; i++) { @@ -438,15 +449,15 @@ scroll(Point p, Rich *r) drawobject(obj, &cur); if (objectisvisible(obj) == 0) break; } - +*/ qunlock(rich.l); - +/* drawscrollbar(); flushimage(display, 1); unlockdisplay(display); - - // nbsend(redrawc, nil); +*/ + nbsend(redrawc, nil); } Object * @@ -998,3 +1009,229 @@ minobj(Object *o1, Object *o2) } return nil; } + + +/* **** New Code Beyond This Point **** */ + +Elem * +elemcreate(int type, char *str) +{ + Elem *e; + e = malloc(sizeof(Elem)); + e->type = type; + e->str = str; + if (str != nil) e->count = strlen(str); + e->aux = nil; + e->pos = ZP; + return e; +} + +Array *elems; + +char * +elemparse(Elem *e, char *str, long n) +{ + int type; + int count; + char *sp, *ep; + + type = *str; + sp = str + 1; + if (n <= 1) return nil; + ep = memchr(sp, '\n', n - 1); + if (ep == nil) return nil; + count = ep - sp; + + e->type = type; + e->str = sp; + e->count = count; + + return ep + 1; +} + +void +generatesampleelems(void) +{ + Elem *e, *eold; + char *dp, *link, *fstr; + Font *sfont; + long count; + char *dat = + ".alpha beta\n" + "s\n" + "Lhttp://nsmpr.xyz\n" + ".gamma\n" + "L\n" + "s\n" + "F/lib/font/bit/terminus/unicode.12.font\n" + ".delta\n" + "F\n" + "n\n" + ".Каким-то макаром попали к татарам амбары да бары пропали задаром\n"; + + elems = arraycreate(sizeof(Elem *), 128, nil); + eold = nil; + link = nil; + sfont = font; + dp = dat; + count = strlen(dat); + while (dp != nil) { + e = mallocz(sizeof(Elem), 1); + dp = elemparse(e, dp, dat + count - dp); + + e->prev = eold; + if (eold != nil) eold->next = e; + + switch (e->type) { + case E_LINK: + /* TODO: maybe use char Array instead of blindly reallocing link */ + if (e->count > 0) { + link = realloc(link, e->count + 1); + memcpy(link, e->str, e->count); + link[e->count] = '\0'; + } else link = realloc(link, 0); + break; + case E_FONT: + /* TODO: maybe use char Array instead of blindly reallocing fstr */ + if (e->count > 0) { + fstr = mallocz(e->count + 1, 1); + memcpy(fstr, e->str, e->count); + sfont = getfont(fonts, fstr); + free(fstr); + } else sfont = font; + break; + } + if (link != nil) e->link = strdup(link); + e->font = sfont; + arraygrow(elems, 1, &e); + } + if (link != nil) free(link); +} + +void +drawelems(void) +{ + long i; + Point pos; + Elem *e; + pos = subpt(rich.page.r.min, rich.page.scroll); //ZP; + for (i = 0; i < elems->count; i++) { + if (arrayget(elems, i, &e) == nil) + sysfatal("drawelems: failed to get elem"); + e->pos = pos; + pos = drawelem(e); + } +} + +Point +drawelem(Elem *e) +{ + Point (*drawp)(Elem *); + + static const Point (*dtable[256])(Elem *) = { + [E_NOOP] drawnoop, + [E_TEXT] drawtext, + [E_FONT] drawnoop, + [E_LINK] drawnoop, + [E_IMAGE] drawnoop, + [E_NL] drawnl, + [E_TAB] drawnoop, + [E_SPACE] drawspace, + }; + + if (e == nil) sysfatal("drawelem: e is nil"); + + drawp = dtable[e->type]; + + if (drawp == nil) { + fprint(2, "drawelem: unknown elem type: %uhhx", e->type); + e->type = E_NOOP; + drawp = drawnoop; + } + + return drawp(e); +} + +Point +drawtext(Elem *e) +{ + Point pos; + int i, n, s, nl; + Image *fg; + Rune *R; + char *sp; + + fg = (e->link != nil) ? Ilink : Itext; + + sp = e->str; + n = utfnlen(sp, e->count); + R = malloc(sizeof(Rune) * (n + 1)); + R[n] = 0; + for (i = 0; i < n; i++) { + sp += chartorune(&R[i], sp); + } + pos = e->pos; + s = 0; + nl = 0; + while (s < n) { + for (i = 0; i < n - s; i++) { + /* if (selection start) break; */ + /* if (selection end) break; */ + if (pos.x + runestringnwidth(e->font, &R[s], i) > rich.page.r.max.x) { + i --; + nl = 1; + break; + } + } + /* + * if (selected) Ibg = Isel; + * else Ibg = Inormbg; + */ + pos = runestringn(screen, pos, fg, ZP, e->font, &R[s], i); + if (nl != 0) { + nl = 0; + pos = Pt(rich.page.r.min.x, pos.y + e->font->height); + /* + * TODO: instead of font->height, calculate line width + * from max height of every element on this line + */ + } + s += i; + } + + free(R); + return pos; +} + +Point +drawnl(Elem *e) +{ + /* + * if (selected) Ibg = Isel; + * else Ibg = Inormbg; + * draw(Ibg); + */ + return Pt(rich.page.r.min.x, e->pos.y + e->font->height); +} + +Point +drawspace(Elem *e) +{ + Point pos; + int w; + /* + * if (selected) Ibg = Isel; + * else Ibg = Inormbg; + * draw(Ibg); + */ + pos = e->pos; + w = stringwidth(e->font, " "); + /* TODO: add linewrap handling */ + return Pt(e->pos.x + w, e->pos.y); +} + +Point +drawnoop(Elem *e) +{ + return e->pos; +} diff --git a/richterm.h b/richterm.h @@ -88,3 +88,53 @@ struct Faux { }; Faux * fauxalloc(Object *, Array *, void (*)(Req *), void (*)(Req *), void (*)(Req *), void (*)(Fid *)); + + +/* **** New Code Beyond This Point **** */ + +enum { + E_NOOP = '\0', + E_TEXT = '.', + E_FONT = 'F', + E_LINK = 'L', + E_IMAGE = 'I', + E_NL = 'n', + E_TAB = 't', + E_SPACE = 's' +}; + +typedef struct Token Token; + +struct Token { + int type; + char *str; + long count; +}; + +typedef struct Elem Elem; + +struct Elem { + Token; + + void *aux; + Point pos; + Point nlpos; + + Elem *next; + Elem *prev; + char *link; + Image *image; + Font *font; +}; + +extern Array *elems; + +Elem * elemcreate(int, char *); +void generatesampleelems(void); +void drawelems(void); +Point drawelem(Elem *); +Point drawtext(Elem *); +Point drawnl(Elem *); +Point drawspace(Elem *); +Point drawnoop(Elem *); +char * elemparse(Elem *, char *, long);