aboutsummaryrefslogtreecommitdiff
path: root/sys/libterm/term.c
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-18 19:45:40 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-18 19:45:40 -0700
commit425ef692da7e74112f88f0b368f3286dba84f846 (patch)
treed45729e90010e8d8c539031c3b72165f6884575d /sys/libterm/term.c
parent0522b4bf4e125b7ceb67f7177db692aed3a0ebf9 (diff)
feat: working parser for rc shell language
Diffstat (limited to 'sys/libterm/term.c')
-rw-r--r--sys/libterm/term.c256
1 files changed, 175 insertions, 81 deletions
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 <signal.h>
+#include <sys/ioctl.h>
+
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);
}