From 425ef692da7e74112f88f0b368f3286dba84f846 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Thu, 18 Jun 2020 19:45:40 -0700 Subject: feat: working parser for rc shell language --- sys/libterm/term.c | 256 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 175 insertions(+), 81 deletions(-) (limited to 'sys/libterm/term.c') diff --git a/sys/libterm/term.c b/sys/libterm/term.c index cda2bbe..11591fc 100644 --- a/sys/libterm/term.c +++ b/sys/libterm/term.c @@ -1,5 +1,8 @@ #include "term.h" +#include +#include + struct ExtraInfo { char *enteralt; @@ -19,6 +22,8 @@ struct ExtraInfo vt200 = .exitmouse = "\e[?1002l\e[?1006l", }; +static Term *sigwinchhead; + // ----------------------------------------------------------------------- // database lookup @@ -78,26 +83,9 @@ guessextrastr(Term *t, char *name, char *guess) return guess; } -static -int -tryextrabool(Term *t, char *name) -{ - const char *nm; - size_t max = unibi_count_ext_bool(t->info); - for (size_t i = 0; i < max; i++) { - nm = unibi_get_ext_bool_name(t->info, i); - if (nm && !strcmp(nm, name)) { - return (int)i; - } - } - return -1; -} - /* formats escape strings and writes to output */ static void tfmt(Term *t, char *esc, int n, ...); - -// ----------------------------------------------------------------------- -// exported pen methods +static void tclear(Term *t); // ----------------------------------------------------------------------- // exported term methods @@ -113,14 +101,25 @@ ttmpbuf(Term *t, int len) return (t->tmp.b = realloc(t->tmp.b, len)); } -void -tinit(Term *t) +void twrite(Term *t, long len, char *s); +void tlistensigwinch(Term *t); + +Term* +tmake(void) { + Term *t; + + t = calloc(1, sizeof(*t)); + + /* meta data */ t->name = getenv("TERM"); t->info = unibi_from_term(t->name); if (!t->info) panicf("could not identify terminal"); + t->fd = 1; // stdout + tlistensigwinch(t); + t->mode.mouse = 0; t->mode.cursorvis = 1; t->mode.altscreen = 0; @@ -128,13 +127,23 @@ tinit(Term *t) t->cap.colors = unibi_get_num(t->info, unibi_max_colors); t->cap.bce = unibi_get_bool(t->info, unibi_back_color_erase); - /* TODO */ - t->input = nil; - t->root = nil; - t->pen = (Pen){0}; + /* initialize root window (get current size)*/ + struct winsize ws = { 0 }; + if (ioctl(t->fd, TIOCGWINSZ, &ws) == 1) + goto bad; - /* fill in buffers */ - t->buf.c = t->buf.b; + t->root = wmake(nil, 0, 0, ws.ws_col, ws.ws_row, 0); + + t->root->curvis = 1; + t->root->blink = 0; + + t->pen = (Pen){ + .state = PenNormal, + .col = {.fg = -1, .bg = -1}, + }; + + /* fill in output buffers */ + t->buf.c = t->buf.b; t->tmp.b = nil; t->tmp.len = 0; @@ -174,22 +183,16 @@ tinit(Term *t) t->esc.ext.rgbf = guessextrastr(t, "setrgbf", "\x1b[38;2;%p1%d;%p2%d;%p3%dm"); t->esc.ext.rgbb = guessextrastr(t, "setrgbb", "\x1b[48;2;%p1%d;%p2%d;%p3%dm"); - /* acs characters */ - t->acs.vline = tryinfostr(t, unibi_acs_vline); - t->acs.hline = tryinfostr(t, unibi_acs_hline); - t->acs.plus = tryinfostr(t, unibi_acs_plus); - t->acs.ltee = tryinfostr(t, unibi_acs_ltee); - t->acs.rtee = tryinfostr(t, unibi_acs_rtee); - t->acs.ttee = tryinfostr(t, unibi_acs_ttee); - t->acs.btee = tryinfostr(t, unibi_acs_btee); - t->acs.ulcorner = tryinfostr(t, unibi_acs_ulcorner); - t->acs.urcorner = tryinfostr(t, unibi_acs_urcorner); - t->acs.llcorner = tryinfostr(t, unibi_acs_llcorner); - t->acs.lrcorner = tryinfostr(t, unibi_acs_lrcorner); + return t; + +bad: + panicf("failed to initialize terminal instance"); + free(t); + return nil; } void -tfini(Term *t) +tfree(Term *t) { if (t->mode.mouse) twrite(t, 0, vt200.exitmouse); @@ -199,6 +202,56 @@ tfini(Term *t) twrite(t, 0, vt200.exitalt); tfmt(t, t->esc.sgr0, 0); + tclear(t); + free(t); +} + +/* handle resize events */ +void +tresize(Term *t) +{ + if (t->fd == -1) + return; + + struct winsize ws = { 0 }; + if (ioctl(t->fd, TIOCGWINSZ, &ws) == 1) + return; + + printf("[%d,%d]\n", ws.ws_col, ws.ws_row); + if (t->root->w != ws.ws_col || t->root->h != ws.ws_row) + wresize(t->root, ws.ws_col, ws.ws_row); +} + +static +void +sigwinch(int num) +{ + Term *it; + for (it = sigwinchhead; it; it = it->link) + tresize(it); +} + +void +tlistensigwinch(Term *t) +{ + sigset_t new, old; + Term *it; + + sigemptyset(&new); + sigaddset(&new, SIGWINCH); + sigprocmask(SIG_BLOCK, &new, &old); + + if (!sigwinchhead) { + sigaction(SIGWINCH, &(struct sigaction){ .sa_handler = sigwinch }, nil); + sigwinchhead = t; + } else { + it = sigwinchhead; + while (it->link) + it = it->link; + it->link = t; + } + + sigprocmask(SIG_SETMASK, &old, nil); } void @@ -217,12 +270,14 @@ twrite(Term *t, long len, char *s) if (!len) len = strlen(s); - while (len > 0) { - n = MIN(len, arrend(t->buf.b) - t->buf.c); - memcpy(t->buf.c, s, n); - t->buf.c += n; - len -= n; +loop: + n = MIN(len, arrend(t->buf.b) - t->buf.c); + memcpy(t->buf.c, s, n); + t->buf.c += n; + len -= n; + if (len) { tflush(t); + goto loop; } } @@ -256,8 +311,8 @@ tsetpen(Term *t, Pen new) /* fg/bg color */ /* TODO: add a check for if the terminal supports true color */ - /* TODO: add a check for negative indices */ - if (new.state & PenTrueClr) { + /* TODO: deal w/ negative indices properly */ + if (new.state & PenRGB) { tfmt(t, t->esc.ext.rgbf, 3, new.rgb.fg.r, new.rgb.fg.g, new.rgb.fg.b); tfmt(t, t->esc.ext.rgbb, 3, new.rgb.bg.r, new.rgb.bg.g, new.rgb.bg.b); } else { @@ -282,12 +337,13 @@ tfmt(Term *t, char *esc, int n, ...) panicf("no terminfo escape string given"); va_start(args, n); - for (i = 0; i < arrlen(param) && i < n; i++) + for (i = 0; i < arrlen(param) && i < n; i++) { param[i] = unibi_var_from_num(va_arg(args, int)); + } va_end(args); len = unibi_run(esc, param, c, sizeof(buf)); - if (len < arrlen(buf)) { + if (len >= arrlen(buf)) { c = ttmpbuf(t, len); unibi_run(esc, param, c, len); } @@ -296,6 +352,7 @@ tfmt(Term *t, char *esc, int n, ...) } /* absolute move */ +static int tgoto(Term *t, int row, int col) { @@ -324,6 +381,7 @@ tgoto(Term *t, int row, int col) } /* relative move */ +static void tjump(Term *t, int down, int right) { @@ -346,50 +404,86 @@ tjump(Term *t, int down, int right) tfmt(t, t->esc.cub, 1, -right); } +static void -tdel(Term *t, int num) +tclear(Term *t) { - char *c, buf[64]; - if (num < 1) - return; - - /* TODO: allow for not moving */ - if (t->cap.bce) { - tfmt(t, t->esc.ech, 1, num); - tjump(t, 0, num); - } else { - c = buf; - memset(c, ' ', arrlen(buf)); - while(num > 64) { - twrite(t, arrlen(buf), c); - num -= arrlen(buf); - } - twrite(t, num, c); - } + tfmt(t, t->esc.ed2, 0); } void -tclear(Term *t) +tblit(Term *t, Window *win) { - tfmt(t, t->esc.ed2, 0); + int r, c, n, j; + Row *row; + char u[UTFmax+1] = {0}; + + j = 0; + tgoto(t, win->top, win->left); + for (r = 0; r < win->h; r++) { + row = win->row + r; + if (!row->dirty) { + j++; + continue; + } + + if (j) { + tjump(t, j, 0); + j = 0; + } + + for (c = 0; c < win->w; c++) { + tsetpen(t, row->cells[c].pen); + n = utf8·runetobyte(u, &row->cells[c].txt); + twrite(t, n, u); + } + + row->dirty = 0; + } + + tflush(t); } // ----------------------------------------------------------------------- -// testing entry +// testing int main() { - Term t; - tinit(&t); - - printf("%s: %s\n", unibi_short_name_str(unibi_set_a_foreground), t.esc.sgr_fg); - printf("%s: %s\n", unibi_short_name_str(unibi_set_a_background), t.esc.sgr_bg); - tfmt(&t, t.esc.ext.rgbf, 3, 10, 10, 100); - tfmt(&t, t.esc.ext.rgbb, 3, 100, 0, 100); - twrite(&t, 0, "hello world\n"); - twrite(&t, 0, "hello world\n"); - twrite(&t, 0, t.acs.hline); - - tfini(&t); + int i; + Term *t; + Window *win; + + t = tmake(); + win = t->root; + tclear(t); + + win->pen = (Pen){ + .state = PenNormal, + .col = {.fg=-1, .bg=-1}, + }; + for (i = 0; i < 2000; i++) + wputrune(win, 'a'); + + tblit(t, win); + + win->cur.row = 10; + win->cur.col = 0; + + win->pen = (Pen){ + .state=PenNormal|PenRGB, + .rgb={.fg={200, 100, 100}, .bg={0, 0, 0} }, + }; + + for (i = 0; i < 500; i++) + wputrune(win, 'b'); + + tblit(t, win); + + sleep(5); + wscroll(win, 10); + tblit(t, win); + sleep(5); + + tfree(t); } -- cgit v1.2.1