From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- sys/libterm/term.c | 489 --------------------------------------------------- sys/libterm/term.h | 270 ---------------------------- sys/libterm/window.c | 408 ------------------------------------------ 3 files changed, 1167 deletions(-) delete mode 100644 sys/libterm/term.c delete mode 100644 sys/libterm/term.h delete mode 100644 sys/libterm/window.c (limited to 'sys/libterm') diff --git a/sys/libterm/term.c b/sys/libterm/term.c deleted file mode 100644 index 11591fc..0000000 --- a/sys/libterm/term.c +++ /dev/null @@ -1,489 +0,0 @@ -#include "term.h" - -#include -#include - -struct ExtraInfo -{ - char *enteralt; - char *exitalt; - - char *entermouse; - char *exitmouse; -}; - -static -struct ExtraInfo vt200 = -{ - .enteralt = "\e[?1049h", - .exitalt = "\e[?1049l", - - .entermouse = "\e[?1049h\e[?1006l", - .exitmouse = "\e[?1002l\e[?1006l", -}; - -static Term *sigwinchhead; - -// ----------------------------------------------------------------------- -// database lookup - -static -char* -tryinfostr(Term *t, enum unibi_string s) -{ - char *val = (char*)unibi_get_str(t->info, s); - /* TODO: provide fallbacks */ - return val; -} - -static -char* -guessinfostr(Term *t, enum unibi_string s, char *guess) -{ - char *val = (char*)unibi_get_str(t->info, s); - if (!val) - return guess; - return val; -} - -static -char* -getinfostr(Term *t, enum unibi_string s) -{ - char *val = tryinfostr(t, s); - if (!val) - panicf("required term info string '%s' missing", unibi_name_str(s)); - - return val; -} - -static -char * -tryextrastr(Term *t, char *name) -{ - const char *nm; - size_t max = unibi_count_ext_str(t->info); - for (size_t i = 0; i < max; i++) { - nm = unibi_get_ext_str_name(t->info, i); - if (nm && !strcmp(nm, name)) { - return (char *)nm; - } - } - return nil; -} - -static -char * -guessextrastr(Term *t, char *name, char *guess) -{ - char *s; - if ((s = tryextrastr(t, name))) - return s; - - return guess; -} - -/* formats escape strings and writes to output */ -static void tfmt(Term *t, char *esc, int n, ...); -static void tclear(Term *t); - -// ----------------------------------------------------------------------- -// exported term methods - -static -char * -ttmpbuf(Term *t, int len) -{ - if (t->tmp.len >= len) - return t->tmp.b; - - /* TODO: error handling */ - return (t->tmp.b = realloc(t->tmp.b, len)); -} - -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; - - t->cap.colors = unibi_get_num(t->info, unibi_max_colors); - t->cap.bce = unibi_get_bool(t->info, unibi_back_color_erase); - - /* initialize root window (get current size)*/ - struct winsize ws = { 0 }; - if (ioctl(t->fd, TIOCGWINSZ, &ws) == 1) - goto bad; - - 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; - - /* get all term info format strings */ - t->esc.cup = getinfostr(t, unibi_cursor_address); - t->esc.vpa = tryinfostr(t, unibi_row_address); - t->esc.hpa = tryinfostr(t, unibi_column_address); - t->esc.cuu = getinfostr(t, unibi_parm_up_cursor); - t->esc.cuu1 = tryinfostr(t, unibi_cursor_up); - t->esc.cud = getinfostr(t, unibi_parm_down_cursor); - t->esc.cud1 = tryinfostr(t, unibi_cursor_down); - t->esc.cuf = getinfostr(t, unibi_parm_right_cursor); - t->esc.cuf1 = tryinfostr(t, unibi_cursor_right); - t->esc.cub = getinfostr(t, unibi_parm_left_cursor); - t->esc.cub1 = tryinfostr(t, unibi_cursor_left); - t->esc.ich = getinfostr(t, unibi_parm_ich); - t->esc.ich1 = tryinfostr(t, unibi_insert_character); - t->esc.dch = getinfostr(t, unibi_parm_dch); - t->esc.dch1 = tryinfostr(t, unibi_delete_character); - t->esc.il = getinfostr(t, unibi_parm_insert_line); - t->esc.il1 = tryinfostr(t, unibi_insert_line); - t->esc.dl = getinfostr(t, unibi_parm_delete_line); - t->esc.dl1 = tryinfostr(t, unibi_delete_line); - t->esc.ech = getinfostr(t, unibi_erase_chars); - t->esc.ed2 = getinfostr(t, unibi_clear_screen); - t->esc.stbm = getinfostr(t, unibi_change_scroll_region); - t->esc.sgr = getinfostr(t, unibi_set_attributes); - t->esc.sgr0 = getinfostr(t, unibi_exit_attribute_mode); - t->esc.sgr_i0 = tryinfostr(t, unibi_exit_italics_mode); - t->esc.sgr_i1 = tryinfostr(t, unibi_enter_italics_mode); - t->esc.sgr_fg = getinfostr(t, unibi_set_a_foreground); - t->esc.sgr_bg = getinfostr(t, unibi_set_a_background); - t->esc.sm_csr = getinfostr(t, unibi_cursor_normal); - t->esc.rm_csr = getinfostr(t, unibi_cursor_invisible); - - /* extensions to terminfo */ - 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"); - - return t; - -bad: - panicf("failed to initialize terminal instance"); - free(t); - return nil; -} - -void -tfree(Term *t) -{ - if (t->mode.mouse) - twrite(t, 0, vt200.exitmouse); - if (!t->mode.cursorvis) - tfmt(t, t->esc.rm_csr, 0); - if (t->mode.altscreen) - 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 -tflush(Term *t) -{ - if (t->fd != -1) - write(t->fd, t->buf.b, t->buf.c - t->buf.b); - - t->buf.c = t->buf.b; -} - -void -twrite(Term *t, long len, char *s) -{ - int n; - if (!len) - len = strlen(s); - -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; - } -} - -void -tsetpen(Term *t, Pen new) -{ - int c; - ushort ic, in; - Pen cur = t->pen; - if (!memcmp(&new, &cur, sizeof(new))) - return; - - /* attributes */ - tfmt(t, t->esc.sgr, 9, - 0, /* standout */ - new.state & PenUnderline, - new.state & PenReverse, - new.state & PenBlink, - new.state & PenDim, - new.state & PenBold, - new.state & PenInvis, - 0, /* protect */ - 0); /* alt */ - - ic = cur.state & PenItalic; - in = new.state & PenItalic; - if (ic & ~in) - tfmt(t, t->esc.sgr_i0, 0); - else if (~ic & in) - tfmt(t, t->esc.sgr_i1, 0); - - /* fg/bg color */ - /* TODO: add a check for if the terminal supports true color */ - /* 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 { - tfmt(t, t->esc.sgr_fg, 1, new.col.fg); - tfmt(t, t->esc.sgr_bg, 1, new.col.bg); - } - - t->pen = new; -} - -static -void -tfmt(Term *t, char *esc, int n, ...) -{ - int i; - long len; - va_list args; - unibi_var_t param[9]; - char buf[64], *c = buf; - - if (!esc) - panicf("no terminfo escape string given"); - - va_start(args, n); - 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)) { - c = ttmpbuf(t, len); - unibi_run(esc, param, c, len); - } - - twrite(t, len, c); -} - -/* absolute move */ -static -int -tgoto(Term *t, int row, int col) -{ - if (row != -1 && col != -1) - tfmt(t, t->esc.cup, 2, row, col); - else if (row != -1) { - if (!t->esc.vpa) - return 0; - tfmt(t, t->esc.vpa, 1, row); - } else if (col != -1) { - if (col == 0) { - twrite(t, 1, "\r"); - return 1; - } - if (t->esc.hpa) - tfmt(t, t->esc.hpa, 1, col); - else if (t->esc.cuf) { - twrite(t, 1, "\r"); - tfmt(t, t->esc.cuf, 1, col); - } else - return 0; - } else - return 0; /* unreachable */ - - return 1; -} - -/* relative move */ -static -void -tjump(Term *t, int down, int right) -{ - if (down == 1 && t->esc.cud1) - tfmt(t, t->esc.cud1, 0); - else if (down == -1 && t->esc.cuu1) - tfmt(t, t->esc.cuu1, 0); - else if (down > 0) - tfmt(t, t->esc.cud, 1, down); - else if (down < 0) - tfmt(t, t->esc.cuu, 1, -down); - - if (right == 1 && t->esc.cuf1) - tfmt(t, t->esc.cuf1, 0); - else if (right == -1 && t->esc.cub1) - tfmt (t, t->esc.cub1, 0); - else if (right > 0) - tfmt(t, t->esc.cuf, 1, right); - else if( right < 0) - tfmt(t, t->esc.cub, 1, -right); -} - -static -void -tclear(Term *t) -{ - tfmt(t, t->esc.ed2, 0); -} - -void -tblit(Term *t, Window *win) -{ - 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 - -int -main() -{ - 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); -} diff --git a/sys/libterm/term.h b/sys/libterm/term.h deleted file mode 100644 index 6bd2f6b..0000000 --- a/sys/libterm/term.h +++ /dev/null @@ -1,270 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#define iota(x) 1 << (x) - -typedef struct RGB8 RGB8; -typedef struct Pen Pen; - -typedef struct Dot Dot; -typedef struct Cell Cell; -typedef struct Row Row; -typedef struct Buffer Buffer; -typedef struct Window Window; - -typedef struct Node Node; -typedef struct Key Key; -typedef struct Input Input; - -typedef struct Term Term; - -struct RGB8 -{ - uint8 r, g, b; -}; - -enum -{ - PenNormal = 0, - PenBold = iota(0), - PenDim = iota(1), - PenInvis = iota(2), - PenItalic = iota(3), - PenReverse = iota(4), - PenStrike = iota(5), - PenUnderline = iota(6), - PenBlink = iota(7), - /* ... */ - PenRGB = iota(15), -}; - -struct Pen -{ - ushort state; - union { - /* 256 color (legacy) */ - struct { - sshort fg : 8, bg : 8; /* 0 - 255 or COLOUR_DEFAULT */ - } col; - /* true color (modern) */ - struct { - RGB8 fg, bg; - } rgb; - }; -}; - -/* outputs */ -struct Cell -{ - rune txt; - Pen pen; -}; - -struct Row -{ - Cell *cells; - uint dirty : 1; -}; - -struct Dot -{ - int row, col; -}; - -/* - * scroll.top & scroll.bot are pointers into the viewport. - * - * scroll back buffer - * - * scroll.buf->+----------------+-----+ - * | | | ^ \ - * | before | | | | - * current terminal content | viewport | | | | - * | | | | - * +----------------+-----+\ | | | s > scroll.above - * ^ | | i | \ | | i | c | - * | | | n | \ | | n | r | - * | | v | \ | | v | o | - * | | i | \ | | i | l / - * | buffer | s | >|<- scroll.index | s | l \ - * h | | i | / | | i | | - * | | b | / | after | b | s > scroll.below - * | | l | / | viewport | l | i | - * v | | e | / | | e | z / - * +----------------+-----+/ | unused | | e - * <- maxw -> | scroll back | | - * <- w -> | buffer | | | - * | | | | - * | | | v - * scroll.buf + scroll.size->+----------------+-----+ - * <- maxw -> - * <- w -> - */ - -struct Buffer -{ - int w, h; /* dimension of buffer */ - Pen pen; /* default attributes */ - int maxw; /* allocated cells (maximal cols over time) */ - Row *row; /* array of row pointers of size 'h' */ - struct { - Row *buf; - Row *top; - Row *bot; - int size; - int index; - int above; - int below; - } scroll; - Dot cur, save; /* cursor position within buffer */ -}; - -struct Window -{ - struct Buffer; - int top, left; - uchar curvis : 1; - uchar blink : 2; - - Window *parent, *child, *link; -}; - -/* input */ -struct Key -{ - int type; - int mods; - uchar utf8[UTFmax+1]; - union { - rune pt; - int num; - int sym; - char mouse[4]; - } code; -}; - -struct KeyInfo -{ - int type; - int sym; - int modmask; - int modset; -}; - -struct Input -{ - int fd; - int flags; - int wait; /* in ms */ - - /* modifiers */ - uchar closed : 1; - uchar started : 1; - uchar hasold : 1; - - struct termios oldterm; - - /* buffer */ - struct { - long off; - uchar *b, *c, *e, bytes[256]; - } rbuf; - struct { - uchar *s, bytes[256]; - } ebuf; - - /* key data */ - Node *keys; - struct KeyInfo c0[32]; -}; - - -struct Term -{ - /* meta data */ - char *name; - unibi_term *info; - struct { - uchar altscreen : 1; - uchar cursorvis : 1; - uchar mouse : 1; - } mode; - struct { - uchar bce : 1; - int colors; - } cap; - - /* input capture */ - Input input; - - /* output display */ - Window *root; - Pen pen; - - /* raw text to pty */ - int fd; - struct { - char *c, b[512]; - } buf; - - struct { - int len; - char *b; - } tmp; - - /* info */ - struct { - /* Positioning */ - char *cup; // cursor_address - char *vpa; // row_address == vertical position absolute - char *hpa; // column_address = horizontal position absolute - - /* Moving */ - char *cuu; char *cuu1; // Cursor Up - char *cud; char *cud1; // Cursor Down - char *cuf; char *cuf1; // Cursor Forward == Right - char *cub; char *cub1; // Cursor Backward == Left - - /* Editing */ - char *ich; char *ich1; // Insert Character - char *dch; char *dch1; // Delete Character - char *il; char *il1; // Insert Line - char *dl; char *dl1; // Delete Line - char *ech; // Erase Character - char *ed2; // Erase Data 2 == Clear screen - char *stbm; // Set Top/Bottom Margins - - /* formatting */ - char *sgr; // Select Graphic Rendition - char *sgr0; // Exit Attribute Mode - char *sgr_i0, *sgr_i1; // SGR italic off/on - char *sgr_fg; // SGR foreground colour - char *sgr_bg; // SGR background colour - - /* Mode setting/clearing */ - char *sm_csr; char *rm_csr; // Set/reset mode: Cursor visible - - /* augmentations to terminfo */ - struct { - char *rgbf; // rgb foreground - char *rgbb; // rgb background - char *smxx; // strikethrough - char *smulx; // curly underline - } ext; - } esc; - - Term *link; -}; - -/* functions */ -void tresize(Term *t); - -Window *wmake(Window *root, int top, int left, int w, int h, int scroll); -void wresize(Window *root, int w, int h); -void wputrune(Window *win, rune r); -void wscroll(Window *win, int s); diff --git a/sys/libterm/window.c b/sys/libterm/window.c deleted file mode 100644 index 5d36c8b..0000000 --- a/sys/libterm/window.c +++ /dev/null @@ -1,408 +0,0 @@ -#include "term.h" - -// ----------------------------------------------------------------------- -// buffers - -static -void -zero(Row *row, int start, int len) -{ - int i; - Cell cell = { - .txt = L' ', - .pen = { - .state = PenNormal, - .col.fg = -1, - .col.bg = -1, - }, - }; - - for (i = start; i < len + start; i++) - row->cells[i] = cell; - row->dirty = 1; -} - -static -void -roll(Row *start, Row *end, int count) -{ - int n = end - start; - - /* enforce circularity */ - count %= n; - if (count < 0) - count += n; - - if (count) { - char buf[count * sizeof(Row)]; /* XXX: remove VLA */ - memcpy(buf, start, count * sizeof(Row)); - memmove(start, start + count, (n - count) * sizeof(Row)); - memcpy(end - count, buf, count * sizeof(Row)); - - for (Row *row = start; row < end; row++) - row->dirty = 1; - } -} - -/* buffer operations */ -static -void -bclear(Buffer *b) -{ - int i; - Cell cell = { - .txt = L' ', - .pen = { - .state = PenNormal, - .col.fg = -1, - .col.bg = -1, - }, - }; - - for (i = 0; i < b->h; i++) { - Row *row = b->row + i; - for (int j = 0; j < b->w; j++) { - row->cells[j] = cell; - row->dirty = 1; - } - } -} - -static -void -bfini(Buffer *b) -{ - int i; - - for (i = 0; i < b->h; i++) - free(b->row[i].cells); - - free(b->row); - - if (b->scroll.size) { - for (i = 0; i < b->scroll.size; i++) - free(b->scroll.buf[i].cells); - - free(b->scroll.buf); - } -} - -static -void -bscroll(Buffer *b, int s) -{ - Row tmp; - int i, ssz = b->scroll.bot - b->scroll.top; - - /* work in quanta of screen size */ - if (s > ssz) { - bscroll(b, ssz); - bscroll(b, s - ssz); - return; - } - if (s < -ssz) { - bscroll(b, -ssz); - bscroll(b, s + ssz); - return; - } - - b->scroll.above += s; - b->scroll.above = CLAMP(b->scroll.above, 0, b->scroll.size); - - if (s > 0) { - if (b->scroll.size) { - for (i = 0; i < s; i++) { - tmp = b->scroll.top[i]; - b->scroll.top[i] = b->scroll.buf[b->scroll.index]; - b->scroll.buf[b->scroll.index] = tmp; - - b->scroll.index++; - if (b->scroll.index == b->scroll.size) - b->scroll.index = 0; - } - } else - for (i = 0; i < s; i++) - zero(b->scroll.top+i, 0, b->maxw); - } - - roll(b->scroll.top, b->scroll.bot, s); - - if (s < 0) { - if (b->scroll.size) { - for (i = (-s) - 1; i >= 0; i--) { - b->scroll.index--; - if (b->scroll.index == -1) - b->scroll.index = b->scroll.size - 1; - - tmp = b->scroll.top[i]; - - b->scroll.top[i] = b->scroll.buf[b->scroll.index]; - b->scroll.buf[b->scroll.index] = tmp; - b->scroll.top[i].dirty = 1; - } - } else - for (i = (-s) - 1; i >= 0; i--) - zero(b->scroll.top+i, 0, b->maxw); - } -} - -static -void -bresize(Buffer *b, int nrow, int ncol) -{ - int r, d; - Row *row = b->row; - Row *cur = row + b->cur.row; - - if (b->h != nrow) { - /* scroll if we can */ - if (cur >= row + nrow) - bscroll(b, b->cur.row - nrow + 1); - while (b->h > nrow) { - free(row[b->h - 1].cells); - b->h--; - } - - row = realloc(row, sizeof(Row) * nrow); - } - - if (b->maxw < ncol) { - /* expand each row */ - for (r = 0; r < b->h; r++) { - row[r].cells = realloc(row[r].cells, sizeof(Cell) * ncol); - if (b->h < ncol) - zero(row + r, b->w, ncol - b->w); - row[r].dirty = 1; - } - /* expand the scroll buffer */ - Row *sbuf = b->scroll.buf; - for (r = 0; r < b->scroll.size; r++) { - sbuf[r].cells = realloc(sbuf[r].cells, sizeof(Cell) * ncol); - if (b->w < ncol) - zero(sbuf + r, b->w, ncol - b->w); - } - b->maxw = b->w = ncol; - } else if (b->w != ncol) { - for (r = 0; r < b->h; r++) - row[r].dirty = 1; - b->w = ncol; - } - - d = 0; - if (b->h < nrow) { - while (b->h < nrow) { - row[b->h].cells = calloc(b->maxw, sizeof(Cell)); - zero(row + b->h, 0, b->maxw); - b->h++; - } - - /* prepare for backfill */ - if (cur >= b->scroll.bot - 1) { - d = b->row + nrow - cur - 1; - if (d > b->scroll.above) - d = b->scroll.above; - } - } - - b->cur.row += row - b->row; - b->scroll.top = row; - b->scroll.bot = row + nrow; - b->row = row; - - /* perform backfill */ - if (d > 0) { - bscroll(b, -d); - b->cur.row += d; - } -} - -static -bool -binit(Buffer *b, int cols, int rows, int scroll) -{ - int size; - - b->pen.state = PenNormal; - b->pen.col.fg = b->pen.col.bg = -1; - - size = MAX(scroll, 0); - if (size && !(b->scroll.buf = calloc(size, sizeof(Row)))) - return false; - - b->scroll.size = size; - bresize(b, rows, cols); - - b->cur = (Dot){0}; - b->save = b->cur; - - return true; -} - -static -void -bboundary(Buffer *b, Row **bs, Row **be, Row **as, Row **ae) -{ - if (bs) - *bs = nil; - if (be) - *be = nil; - if (as) - *as = nil; - if (ae) - *ae = nil; - if (!b->scroll.size) - return; - - if (b->scroll.above) { - if (bs) - *bs = &b->scroll.buf[(b->scroll.index - b->scroll.above + b->scroll.size) % b->scroll.size]; - if (be) - *be = &b->scroll.buf[(b->scroll.index-1 + b->scroll.size) % b->scroll.size]; - } - if (b->scroll.below) { - if (as) - *as = &b->scroll.buf[b->scroll.index]; - if (ae) - *ae = &b->scroll.buf[(b->scroll.index + b->scroll.below-1) % b->scroll.size]; - } -} - -static -Row * -browfirst(Buffer *b) -{ - Row *bstart; - if (!b->scroll.size || !b->scroll.above) - return b->row; - bboundary(b, &bstart, nil, nil, nil); - return bstart; -} - -static -Row * -browlast(Buffer *b) -{ - Row *aend; - if (!b->scroll.size || !b->scroll.below) - return b->row + b->h - 1; - bboundary(b, nil, nil, nil, &aend); - return aend; -} - -static -Row * -brownext(Buffer *b, Row *row) -{ - Row *before_start, *before_end, *after_start, *after_end; - Row *first = b->row, *last = b->row + b->h - 1; - - if (!row) - return nil; - - bboundary(b, &before_start, &before_end, &after_start, &after_end); - - if (row >= first && row < last) - return ++row; - if (row == last) - return after_start; - if (row == before_end) - return first; - if (row == after_end) - return nil; - if (row == &b->scroll.buf[b->scroll.size - 1]) - return b->scroll.buf; - return ++row; -} - -static -Row * -bprevrow(Buffer *b, Row *row) -{ - Row *before_start, *before_end, *after_start, *after_end; - Row *first = b->row, *last = b->row + b->h - 1; - - if (!row) - return nil; - - bboundary(b, &before_start, &before_end, &after_start, &after_end); - - if (row > first && row <= last) - return --row; - if (row == first) - return before_end; - if (row == before_start) - return nil; - if (row == after_start) - return last; - if (row == b->scroll.buf) - return &b->scroll.buf[b->scroll.size - 1]; - return --row; -} - -// ----------------------------------------------------------------------- -// windows - -Window * -wmake(Window *root, int top, int left, int w, int h, int scroll) -{ - Window *child, *it; - - child = calloc(1, sizeof(*child)); - child->top = top; - child->left = left; - child->parent = root; - if (root) { - if (root->child) { - for (it = root->child; it->link != nil; it = it->link) - ; - it->link = child; - } else - root->child = child; - - child->curvis = root->curvis; - child->blink = root->blink; - } - - if (!binit((Buffer*)child, w, h, scroll)) { - free(child); - return nil; - } - - return child; -} - -void -wfree(Window *win) -{ - free(win); -} - -void -wresize(Window *win, int w, int h) -{ - bresize((Buffer*)win, w, h); -} - -/* TODO: more sophisticated damage tracking */ -void -wputrune(Window *win, rune r) -{ - Row *row = win->row + win->cur.row; - Cell *cell = row->cells + win->cur.col; - - cell->pen = win->pen; - cell->txt = r; - - if (win->cur.col++ >= win->w) { - win->cur.col = 0; - if (win->cur.row++ >= win->h) - win->cur.row = win->h-1; - } - row->dirty = 1; -} - -void -wscroll(Window *win, int s) -{ - bscroll((Buffer*)win, s); -} -- cgit v1.2.1