richterm

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

commit 2741d8f7776d78de9fe9ffc08d26bba855e09886
parent 61ec78051d6f8ef2171219ee1033708d0fc5cf0c
Author: Pavel Renev <an2qzavok@gmail.com>
Date:   Wed, 18 Aug 2021 21:55:01 +0000

Views removed, single text buffer implemented, more or less

Diffstat:
MTODO | 3---
Marray.c | 24+++++++++++++++++++-----
Marray.h | 8+++++---
Mdevfs.c | 27++++++++++++++++++++++++---
Mfs.c | 51++++++++++++++++++++++++++++++++++++++-------------
Mrichterm.c | 439+++++++------------------------------------------------------------------------
Mrichterm.h | 24+++---------------------
7 files changed, 124 insertions(+), 452 deletions(-)

diff --git a/TODO b/TODO @@ -1,5 +1,2 @@ Use single buffer array for text. Only store pointer offset in objects, so that offset of next obj is treated as end of current obj. - -Remove Views and draw Objects directly, maybe even letter by letter. -Keep track of object's positional info, such as start point, end poit and next line offset. diff --git a/array.c b/array.c @@ -4,7 +4,7 @@ #include "array.h" Array * -arraycreate(usize size, long n, void (*free)(void *)) +arraycreate(long size, long n, void (*free)(void *)) { Array *ap; ap = mallocz(sizeof(Array), 1); @@ -22,7 +22,7 @@ arraycreate(usize size, long n, void (*free)(void *)) void arrayfree(Array *ap) { - int i; + long i; qlock(ap->l); if (ap->free != nil) { for (i = 0; i < ap->count; i ++) { @@ -38,14 +38,16 @@ arrayfree(Array *ap) void * arraygrow(Array *ap, long n) { + void *v; if (n < 0) return nil; + v = arrayend(ap); qlock(ap->l); ap->count += n; if (ap->count > ap->n) { ap->n += ap->n; ap->p = realloc(ap->p, ap->size * ap->n); } - memset(arrayget(ap, ap->count - n), 0, ap->size * n); + memset(v, 0, ap->size * n); qunlock(ap->l); return (void *)(ap->p + ap->size * (ap->count - n)); } @@ -54,7 +56,7 @@ void arraydel(Array *ap, long n) { char *v; - if ((n < 0) || (n > ap->count)) return; + if ((n < 0) || (n >= ap->count)) return; qlock(ap->l); v = ap->p + ap->size * n; if (ap->free != nil) ap->free(v); @@ -66,6 +68,17 @@ arraydel(Array *ap, long n) void * arrayget(Array *ap, long n) { - if ((n < 0) || (n > ap->count)) return nil; + assert(n >= 0); + assert(n < ap->count); + if ((n < 0) || (n >= ap->count)) { + // fprint(2, "arrayget: n out of bonds\n"); + return nil; + } return (void *)(ap->p + ap->size * n); } + +void * +arrayend(Array *ap) +{ + return (void *)(ap->p + ap->size * ap->count); +} +\ No newline at end of file diff --git a/array.h b/array.h @@ -2,15 +2,16 @@ typedef struct Array Array; struct Array { QLock *l; - usize size; - usize n; + long size; + long n; long count; char *p; void (*free)(void *); }; -Array * arraycreate(usize, long, void (*free)(void *)); +Array * arraycreate(long, long, void (*free)(void *)); void arrayfree(Array *); void * arraygrow(Array *, long); void arraydel(Array *, long); void * arrayget(Array *, long); +void * arrayend(Array *); +\ No newline at end of file diff --git a/devfs.c b/devfs.c @@ -20,7 +20,6 @@ devfs_read(Req *r) dctl = f->aux; if (f == cons) { recv(dctl->rc, &dv); - //print("got: %s", dv->p); r->ofcall.count = dv->count; memcpy(r->ofcall.data, dv->p, dv->count); arrayfree(dv); @@ -37,11 +36,33 @@ void devfs_write(Req *r) { File *f; + Array *buf; + buf = nil; f = r->fid->file; if (f == cons){ - mkobjectftree(newobject(&rich, r->ifcall.data, r->ifcall.count), fsctl->tree->root); - redraw(1); r->ofcall.count = r->ifcall.count; + + if (rich.text->count - olast->offset > 0) { + buf = arraycreate(sizeof(char), + rich.text->count - olast->offset, nil); + + memcpy(buf->p, arrayget(rich.text, olast->offset), + rich.text->count - olast->offset); + } + + rich.objects->count--; + + mkobjectftree( + newobject(&rich, r->ifcall.data, r->ifcall.count), + fsctl->tree->root); + + /* TODO: free olast */ + if (buf != nil) { + olast = newobject(&rich, buf->p, buf->count); + arrayfree(buf); + } else olast = newobject(&rich, nil, 0); + + redraw(1); respond(r, nil); } else if (f == consctl) { respond(r, "not implemented"); diff --git a/fs.c b/fs.c @@ -106,7 +106,7 @@ fs_write(Req *r) } else if (f == new) { respond(r, "not allowed"); } else if (aux != nil) { - aux->read(r, aux->data); + aux->write(r, aux->data); respond(r, nil); redraw(1); } else respond(r, "fs_write: f->aux is nil"); @@ -166,14 +166,10 @@ textread(Req *r, void *) obj = aux->obj; oe = obj->next; - if (oe == nil) - n = rich.text->count; - + if (oe == nil) n = rich.text->count; else n = oe->offset; s = arrayget(rich.text, obj->offset); - - print("tr: %ulld %ulld\n", n, obj->offset); qlock(rich.text->l); @@ -194,33 +190,62 @@ textwrite(Req *r, void *) Object *obj; long n, m, dn; - print("textwrite\n"); - qlock(rich.objects->l); aux = r->fid->file->aux; obj = aux->obj; - p = arrayget(rich.text, obj->offset); - pe = arrayget(rich.text, rich.text->count); + p = rich.text->p + obj->offset; + pe = rich.text->p + rich.text->count; if (obj->next == nil) n = rich.text->count; else n = obj->next->offset - obj->offset; m = r->ifcall.count + r->ifcall.offset; dn = m - n; - - qlock(rich.text->l); if (dn > 0) arraygrow(rich.text, dn); else rich.text->count += dn; + + qlock(rich.text->l); + memcpy(p + m, p + n, pe - p); memcpy(p + r->ifcall.offset, r->ifcall.data, r->ifcall.count); qunlock(rich.text->l); - for (; obj != nil; obj = obj->next) { + for (obj = obj->next; obj != nil; obj = obj->next) { obj->offset += dn; } qunlock(rich.objects->l); +} + +void +fontread(Req *r, void *) +{ + Faux *aux; + qlock(rich.l); + aux = r->fid->file->aux; + readstr(r, aux->obj->font->name); + qunlock(rich.l); +} + +void +fontwrite(Req *r, void *) +{ + char buf[4096], *bp; + Faux *aux; + qlock(rich.l); + aux = r->fid->file->aux; + memcpy(buf, r->ifcall.data, r->ifcall.count); + buf[r->ifcall.count] = '\0'; + + for(bp = buf+ r->ifcall.count - 1; bp >= buf; bp--) + if ((*bp==' ')||(*bp=='\t')||(*bp=='\n')) *bp = '\0'; + + for(bp = buf; bp < buf + r->ifcall.count - 1; bp++) + if ((*bp!=' ')&&(*bp!='\t')&&(*bp!='\n')) break; + + aux->obj->font = getfont(fonts, bp); + qunlock(rich.l); } \ No newline at end of file diff --git a/richterm.c b/richterm.c @@ -17,8 +17,6 @@ void send_interrupt(void); void runcmd(void *); void scroll(Point, Rich *); void mouse(Mousectl *, Mouse, int *); -usize getsel(Point p); -View * getview(Point p); void mpaste(Rich *); void msnarf(Rich *); @@ -109,7 +107,6 @@ threadmain(int argc, char **argv) qlock(rich.l); rich.objects = arraycreate(sizeof(Object *), 8, nil); - rich.views = arraycreate(sizeof(View), 8, nil); rich.text = arraycreate(sizeof(char), 4096, nil); rich.page.scroll = ZP; @@ -180,7 +177,8 @@ threadmain(int argc, char **argv) break; } if (kv == 0x08) { /* backspace */ - if (olast->dtext->count > 0) olast->dtext->count--; + /*TODO: should stop at last offset, not 0 */ + if (rich.text->count > 0) rich.text->count--; redraw(1); break; } @@ -191,8 +189,7 @@ threadmain(int argc, char **argv) qlock(rich.l); - p = arraygrow(olast->dtext, n); - + p = arraygrow(rich.text, n); runetochar(p, &kv); qunlock(rich.l); @@ -202,17 +199,18 @@ threadmain(int argc, char **argv) if (kv == '\n') { qlock(rich.l); - dv = arraycreate(sizeof(char), olast->dtext->n, nil); - arraygrow(dv, olast->dtext->count); - memcpy(dv->p, olast->dtext->p, dv->count); + dv = arraycreate(sizeof(char), + rich.text->count - olast->offset, nil); + arraygrow(dv, rich.text->count - olast->offset); + memcpy(dv->p, + arrayget(rich.text, olast->offset), + rich.text->count - olast->offset); qunlock(rich.l); - mkobjectftree( - newobject(&rich, olast->dtext->p, olast->dtext->count), - fsctl->tree->root); - - olast->dtext->count = 0; + + mkobjectftree(olast, fsctl->tree->root); + olast = newobject(&rich, nil, 0); nbsend(dctl->rc, &dv); @@ -229,8 +227,6 @@ threadmain(int argc, char **argv) void mouse(Mousectl *mc, Mouse mv, int *mmode) { - View *v; - if (mv.buttons == 0) { *mmode = MM_NONE; return; @@ -279,10 +275,6 @@ mouse(Mousectl *mc, Mouse mv, int *mmode) break; case MM_TEXT: if (mv.buttons == 1) { - rich.sel.n[0] = getsel(mv.xy); - rich.sel.v[0] = getview(mv.xy); - rich.sel.n[1] = rich.sel.n[0]; - rich.sel.v[1] = rich.sel.v[0]; redraw(0); *mmode = MM_SELECT; } @@ -293,20 +285,6 @@ mouse(Mousectl *mc, Mouse mv, int *mmode) *mmode = MM_NONE; } if (mv.buttons == 4) { - Object *obj; - Array *dlink; - v = getview(mv.xy); - obj = nil; - dlink = nil; - if (v != nil) obj = v->obj; - if (obj != nil) dlink = obj->dlink; - if ((dlink != nil) && (dlink->n > 0)) { - Array dv; - dv.n = dlink->n; - dv.p = malloc(dlink->n); - memcpy(dv.p, dlink->p, dv.n); - nbsend(dctl->rc, &dv); - } break; } case MM_SELECT: @@ -318,264 +296,10 @@ mouse(Mousectl *mc, Mouse mv, int *mmode) /* paste */ break; } - rich.sel.n[1] = getsel(mv.xy); - rich.sel.v[1] = getview(mv.xy); redraw(0); } } -usize -getsel(Point p) -{ - View *v; - long i; - - v = getview(p); - - p = addpt(subpt(p, rich.page.r.min), rich.page.scroll); - - if (v == nil) return 0; - if (v->length == 0) return 0; - - for (i = 0; i < v->length; i++) { - if (stringnwidth(v->obj->font, v->dp, i) >= - p.x - v->r.min.x) - break; - } - return i - 1; -} - -View * -getview(Point p) -{ - int i; - View *vp; - - - if (p.x < rich.page.r.min.x) p.x = rich.page.r.min.x; - if (p.x > rich.page.r.max.x) p.x = rich.page.r.max.x; - - p = addpt(subpt(p, rich.page.r.min), rich.page.scroll); - - for (i = 0; i < rich.views->count; i++) { - - vp = arrayget(rich.views, i); - - if (ptinrect(p, vp->r) != 0) - return vp; - } - return nil; -} - -void -drawpage(Image *dst, Rich *rich) -{ - View *vp; - int i; - - qlock(rich->l); - for (i = 0; i < rich->views->count; i++) { - vp = arrayget(rich->views, i); - drawview(dst, vp); - } - qunlock(rich->l); -} - -void -drawview(Image *dst, View *v) -{ - Image *bg1, *bg2, *bg3; - Rectangle r, r1, r2, r3; - View *vmin, *vmax; - long nmin, nmax; - - if (rich.sel.v[0] < rich.sel.v[1]) { - vmin = rich.sel.v[0]; - vmax = rich.sel.v[1]; - nmin = rich.sel.n[0]; - nmax = rich.sel.n[1]; - } else { - vmin = rich.sel.v[1]; - vmax = rich.sel.v[0]; - nmin = rich.sel.n[1]; - nmax = rich.sel.n[0]; - } - - if (vmin == vmax) { - if (rich.sel.n[0] < rich.sel.n[1]) { - nmin = rich.sel.n[0]; - nmax = rich.sel.n[1]; - } else { - nmin = rich.sel.n[1]; - nmax = rich.sel.n[0]; - } - } - - r = rectaddpt(rectsubpt(v->r, rich.page.scroll), - rich.page.r.min); - - r1 = r; - r1.max.x = r.min.x; - r2 = r; - r3 = r; - r3.min.x = r.max.x; - - bg1 = Inormbg; - bg2 = Inormbg; - bg3 = Inormbg; - - if ((v > vmin) && (v < vmax)) { - bg1 = Iselbg; - bg2 = Iselbg; - bg3 = Iselbg; - } - - if (v == vmin) { - r1.max.x = r.min.x + stringnwidth(v->obj->font, v->dp, nmin); - r2.min.x = r1.max.x; - bg1 = Inormbg;//Iselbg; - bg2 = Iselbg;//Iselbg; - bg3 = Iselbg;//Iselbg; - } - if (v == vmax) { - r2.max.x = r.min.x + stringnwidth(v->obj->font, v->dp, nmax); - r3.min.x = r2.max.x; - bg1 = Iselbg;//Iselbg; - bg2 = Iselbg;//Iselbg; - bg3 = Inormbg;//Iselbg; - } - if (vmin == vmax) { - bg1 = Inormbg; - bg3 = Inormbg;//Iselbg; - } - - draw(dst, r1, bg1, nil, ZP); - draw(dst, r2, bg2, nil, ZP); - draw(dst, r3, bg3, nil, ZP); - - if (v->obj->image != nil) { - draw(dst, r, v->obj->image, nil, ZP); - return; - } - - stringn(dst, r.min, v->color, ZP, - v->obj->font, v->dp, v->length); -} - -View * -viewadd(Array *views, Object *obj, - char *dp, long len, Rectangle rprev) -{ - View *vp; - Rectangle r; - Point p; - - p = Pt(rprev.max.x, rprev.min.y); - - r = Rpt(p, - addpt(p, Pt( - stringnwidth(obj->font, dp, len), - (Dy(rprev) > obj->font->height) ? - Dy(rprev) : obj->font->height))); - - vp = arraygrow(views, 1); - - *vp = (View) { - obj, - dp, - len, - display->black, - r, - }; - - return vp; -} - -View * -generateviews(Rich *rich, Object *obj, View *v) -{ - Array *views; - Rectangle rprev; - char *sp, *p, *end; - long n; - - enum { - FL_NEW = 1, - FL_TAB = 2, - FL_EL = 4, - FL_NL = 8, - }; - - views = rich->views; - rprev = (v != nil) ? v->r : Rect(0, 0, 0, 0); - end = obj->dtext->p + obj->dtext->count; - sp = obj->dtext->p; - - for (p = sp, n = 0; p < end; p++, n++) { - int fl; - fl = 0; - if (*p == '\t') fl = FL_NEW | FL_TAB; - if (*p == '\n') fl = FL_NEW | FL_EL; - if (rprev.max.x + stringnwidth(obj->font, p, n) > - Dx(rich->page.r)) { - fl = FL_NEW | FL_NL; - } - - /* TODO: - * if object has an image ... */ - - if (fl & FL_NEW) { - v = viewadd(views, obj, sp, n, rprev); - rprev = v->r; - sp = p + 1; - n = -1; - } - if (fl & FL_TAB) { - int tl; - v = viewadd(views, obj, sp, 0, rprev); - tl = stringwidth(font, "0") * 4; - v->r.max.x = ((v->r.max.x / tl) + 1) * tl; - rprev = v->r; - } - if (fl & FL_EL) { - v = viewadd(views, obj, sp, 0, rprev); - v->r.max.x = rich->page.r.max.x; - rprev = v->r; - } - if (((v != nil) && (v->r.max.x >= rich->page.r.max.x)) || - (fl & FL_NL)) { - rprev = Rect(0, rprev.max.y, 0, rprev.max.y); - } - } - v = viewadd(views, obj, sp, n, rprev); - - return v; -} - -void -generatepage(Rich *rich, long n) -{ - Object **op; - View *v; - Array *views; - long i; - - qlock(rich->l); - - views = rich->views; - if (n < views->count) views->count = n; - - v = (views->count > 0) ? - arrayget(views, views->count -1) : nil; - for (i = n; i < rich->objects->count; i++) { - op = arrayget(rich->objects, i); - v = generateviews(rich, *op, v); - } - rich->page.max = Pt(0, v->r.max.y); - - qunlock(rich->l); -} - Font * getfont(Array *fonts, char *name) { @@ -623,51 +347,32 @@ newobject(Rich *rich, char *p, long n) Object *obj, **op, **old; qlock(rich->l); - old = arrayget(rich->objects, rich->objects->count - 1); + old = (rich->objects->count > 0) ? + arrayget(rich->objects, rich->objects->count - 1) : nil; op = arraygrow(rich->objects, 1); - if (rich->objects->count > 1) { - Object **o1; - o1 = arrayget(rich->objects, rich->objects->count - 2); - - *op = *o1; - op = o1; - } - - if (rich->objects->count > 2) { - (*(op - 2))->next = *op; - } - obj = mallocz(sizeof(Object), 1); *op = obj; - obj->offset = rich->text->count; + if (old != nil) (*old)->next = obj; - print("offset %ulld\n", obj->offset); + obj->offset = rich->text->count; - obj->id = smprint("%ulld", rich->idcount++); obj->font = font; obj->text = rich->text; - obj->dtext = arraycreate(sizeof(char), 4096, nil); - obj->dfont = arraycreate(sizeof(char), 4096, nil); obj->dlink = arraycreate(sizeof(char), 4096, nil); obj->dimage = arraycreate(sizeof(char), 4096, nil); if (p != nil) { char *pp; - pp = arraygrow(obj->dtext, n); - memcpy(pp, p, n); pp = arraygrow(rich->text, n); memcpy(pp, p, n); }; - arraygrow(obj->dfont, strlen(font->name)); - memcpy(obj->dfont->p, font->name, strlen(font->name)); - qunlock(rich->l); return obj; } @@ -679,16 +384,21 @@ mkobjectftree(Object *obj, File *root) qlock(rich.l); + obj->id = smprint("%ulld", ++rich.idcount); + obj->dir = createfile(root, obj->id, "richterm", DMDIR|0555, nil); - auxtext = fauxalloc(obj, obj->dtext, FT_TEXT); - auxfont = fauxalloc(obj, obj->dfont, FT_FONT); + auxtext = fauxalloc(obj, nil, FT_TEXT); + auxfont = fauxalloc(obj, nil, FT_FONT); auxlink = fauxalloc(obj, obj->dlink, FT_LINK); auximage = fauxalloc(obj, obj->dimage, FT_IMAGE); auxtext->read = textread; auxtext->write = textwrite; + auxfont->read = fontread; + auxfont->write = fontwrite; + obj->ftext = createfile(obj->dir, "text", "richterm", 0666, auxtext); obj->ffont = createfile(obj->dir, "font", "richterm", 0666, auxfont); obj->flink = createfile(obj->dir, "link", "richterm", 0666, auxlink); @@ -700,15 +410,13 @@ mkobjectftree(Object *obj, File *root) void -redraw(int regen) +redraw(int) { draw(screen, screen->r, Inormbg, nil, ZP); - if ((rich.objects->count != 0) && (regen != 0)) { - generatepage(&rich, 0); - } - drawpage(screen, &rich); drawscrollbar(); + newdraw(); + flushimage(display, 1); } @@ -812,99 +520,14 @@ objectfree(void *v) free(op); } -Array * -getseltext(Rich *rich) -{ - long n, nmin, nmax; - View *vmin, *vmax; - Object **o, **om, *omin, *omax; - Array *d; - - d = malloc(sizeof(Array)); - - vmin = rich->sel.v[0]; - vmax = rich->sel.v[1]; - nmin = rich->sel.n[0]; - nmax = rich->sel.n[1]; - if (vmin > vmax) { - vmin = rich->sel.v[1]; - vmax = rich->sel.v[0]; - nmin = rich->sel.n[1]; - nmax = rich->sel.n[0]; - } - - if (vmin == nil) vmin = arrayget(rich->views, 0); - if (vmax == nil) vmax = arrayget(rich->views, 0); - - if (vmin == vmax) { - if (nmin > nmax) { - n = nmin; - nmin = nmax; - nmax = n; - } - d->n = nmax - nmin; - d->p = malloc(d->n + 1); - d->p[d->n] = '\0'; - memcpy(d->p, vmin->dp + nmin, d->n); - return d; - } - - omin = vmin->obj; - omax = vmax->obj; - - for (om = arrayget(rich->objects, 0); *om != omin; om++); - - for (o = om, n = nmax - nmin; o[1] != omax; o++) - n += (*o)->dtext->count; - - d->n = n; - d->p = malloc(n + 1); - d->p[n] = '\0'; - - if ((*om)->dtext->p != nil) - memcpy(d->p, (*om)->dtext->p + nmin, - (*om)->dtext->count - nmin); - - for (o = om + 1; o[1] != omax; o++) { - if ((*o)->dtext->p != nil) - memcpy(d->p + n, (*o)->dtext->p, (*o)->dtext->count); - n += (*o)->dtext->count; - } - - o++; - - if ((*o)->dtext->p != nil) - memcpy(d->p + n, (*o)->dtext->p, nmax); - - return d; -} - void mpaste(Rich *) { } void -msnarf(Rich *rich) +msnarf(Rich *) { - Array *d; - int snarf; - long n; - n = 0; - d = getseltext(rich); - - if (d->n > 0) { - snarf = open("/dev/snarf", OTRUNC|OWRITE); - if (snarf >= 0) { - n = write(snarf, d->p, d->n); - close(snarf); - } - } - if (n != d->n) - fprint(2, "%s: msnarf: %r\n", argv0); - - free(d->p); - free(d); } void @@ -953,6 +576,10 @@ void drawobject(Object *obj, Point *cur) { long i, n; + if ((obj->offset > rich.text->count) || (obj->offset < 0)) { + fprint(2, "drawobject: object out of bonds: %ld %ld\n", obj->offset, rich.text->count); + return; + } if (obj->next == nil) n = rich.text->count; else n = obj->next->offset; for (i = obj->offset; i < n; i++) { @@ -969,8 +596,12 @@ newdraw(void) cur = ZP; nextlinept = cur; + qlock(rich.l); + qlock(rich.text->l); for (i = 0; i < rich.objects->count; i++) { op = arrayget(rich.objects, i); drawobject(*op, &cur); } + qunlock(rich.text->l); + qunlock(rich.l); } \ No newline at end of file diff --git a/richterm.h b/richterm.h @@ -10,15 +10,13 @@ struct Object { File *flink; File *fimage; char *id; - Array *dtext; - Array *dfont; Array *dlink; Array *dimage; Font *font; Image *image; Array *text; - usize offset; + long offset; Object *next; Point startpt; Point endpt; @@ -35,18 +33,8 @@ extern Array *fonts; Font* getfont(Array *, char *); -typedef struct View View; - typedef struct Page Page; -struct View { - Object *obj; - char *dp; - long length; - Image *color; - Rectangle r; -}; - struct Page { Point scroll; Point max; @@ -54,22 +42,14 @@ struct Page { Rectangle rs; }; -void drawview(Image *, View *); -Point viewsize(View *); - typedef struct Rich Rich; struct Rich { QLock *l; Array *objects; - Array *views; Array *text; u64int idcount; Page page; - struct { - View *v[2]; - long n[2]; - } sel; }; extern Rich rich; @@ -121,3 +101,5 @@ void textread(Req *, void *); void textwrite(Req *, void *); void arrayread(Req *, void *); void arraywrite(Req *, void *); +void fontread(Req *, void *); +void fontwrite(Req *, void *);