diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e10ead --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +*.os diff --git a/tmt.c b/tmt.c index 7ace141..b57d7df 100644 --- a/tmt.c +++ b/tmt.c @@ -59,6 +59,8 @@ struct TMT{ TMTSCREEN screen; TMTLINE *tabs; + TMTSCREEN scroll; + TMTCALLBACK cb; void *p; const wchar_t *acschars; @@ -70,7 +72,7 @@ struct TMT{ size_t pars[PAR_MAX]; size_t npar; size_t arg; - enum {S_NUL, S_ESC, S_ARG} state; + enum {S_NUL, S_ESC, S_ARG, S_OS} state; }; static TMTATTRS defattrs = {.fg = TMT_COLOR_DEFAULT, .bg = TMT_COLOR_DEFAULT}; @@ -116,13 +118,23 @@ clearlines(TMT *vt, size_t r, size_t n) clearline(vt, vt->screen.lines[i], 0, vt->screen.ncol); } +static void +savescroll(TMT *vt, TMTLINE **lines, size_t n) +{ + for (int i=0; iscroll.lines[i]->dirty = true; + memcpy(vt->scroll.lines[i]->chars, lines[i]->chars, vt->screen.ncol * sizeof(TMTCHAR)); + } + CB(vt, TMT_MSG_SCROLL, &vt->scroll); +} + static void scrup(TMT *vt, size_t r, size_t n) { n = MIN(n, vt->screen.nline - 1 - r); if (n){ - TMTLINE *buf[n]; + TMTLINE** buf = malloc(n * sizeof(TMTLINE*)); memcpy(buf, vt->screen.lines + r, n * sizeof(TMTLINE *)); memmove(vt->screen.lines + r, vt->screen.lines + r + n, @@ -130,8 +142,12 @@ scrup(TMT *vt, size_t r, size_t n) memcpy(vt->screen.lines + (vt->screen.nline - n), buf, n * sizeof(TMTLINE *)); + if (r == 0) { + savescroll(vt, buf, n); + } clearlines(vt, vt->screen.nline - n, n); dirtylines(vt, r, vt->screen.nline); + free(buf); } } @@ -141,7 +157,7 @@ scrdn(TMT *vt, size_t r, size_t n) n = MIN(n, vt->screen.nline - 1 - r); if (n){ - TMTLINE *buf[n]; + TMTLINE** buf = malloc(n * sizeof(TMTLINE*)); memcpy(buf, vt->screen.lines + (vt->screen.nline - n), n * sizeof(TMTLINE *)); @@ -151,6 +167,7 @@ scrdn(TMT *vt, size_t r, size_t n) clearlines(vt, r, n); dirtylines(vt, r, vt->screen.nline); + free(buf); } } @@ -161,7 +178,9 @@ HANDLER(ed) switch (P0(0)){ case 0: b = c->r + 1; clearline(vt, l, c->c, vt->screen.ncol); break; case 1: e = c->r - 1; clearline(vt, l, 0, c->c); break; - case 2: /* use defaults */ break; + case 2: + savescroll(vt, vt->screen.lines, vt->screen.nline); + break; default: /* do nothing */ return; } @@ -202,7 +221,11 @@ HANDLER(el) } HANDLER(sgr) - #define FGBG(c) *(P0(i) < 40? &vt->attrs.fg : &vt->attrs.bg) = c + #define FGBG(c) *(P0(i) < 40? &vt->attrs.fg.code : &vt->attrs.bg.code) = c + #define FGBGB(c) *(P0(i) < 100? &vt->attrs.fg.code : &vt->attrs.bg.code) = c + #define FGBGRED() *(P0(i) < 40? &vt->attrs.fg.red : &vt->attrs.bg.red) = (i < vt->npar-2) ? vt->pars[i+2] : 0 + #define FGBGGRN() *(P0(i) < 40? &vt->attrs.fg.green : &vt->attrs.bg.green) = (i < vt->npar-3) ? vt->pars[i+3] : 0 + #define FGBGBLU() *(P0(i) < 40? &vt->attrs.fg.blue : &vt->attrs.bg.blue) = (i < vt->npar-4) ? vt->pars[i+4] : 0 for (size_t i = 0; i < vt->npar; i++) switch (P0(i)){ case 0: vt->attrs = defattrs; break; case 1: case 22: vt->attrs.bold = P0(0) < 20; break; @@ -220,7 +243,22 @@ HANDLER(sgr) case 35: case 45: FGBG(TMT_COLOR_MAGENTA); break; case 36: case 46: FGBG(TMT_COLOR_CYAN); break; case 37: case 47: FGBG(TMT_COLOR_WHITE); break; + case 38: case 48: if ((i < vt->npar-1) && (vt->pars[i+1] == 2)) { + FGBG(TMT_COLOR_RGB); + FGBGRED(); + FGBGGRN(); + FGBGBLU(); + } + break; case 39: case 49: FGBG(TMT_COLOR_DEFAULT); break; + case 90: case 100: FGBGB(TMT_COLOR_BRIGHT_BLACK); break; + case 91: case 101: FGBGB(TMT_COLOR_BRIGHT_RED); break; + case 92: case 102: FGBGB(TMT_COLOR_BRIGHT_GREEN); break; + case 93: case 103: FGBGB(TMT_COLOR_BRIGHT_YELLOW); break; + case 94: case 104: FGBGB(TMT_COLOR_BRIGHT_BLUE); break; + case 95: case 105: FGBGB(TMT_COLOR_BRIGHT_MAGENTA); break; + case 96: case 106: FGBGB(TMT_COLOR_BRIGHT_CYAN); break; + case 97: case 107: FGBGB(TMT_COLOR_BRIGHT_WHITE); break; } } @@ -262,6 +300,7 @@ handlechar(TMT *vt, char i) #define ON(S, C, A) if (vt->state == (S) && strchr(C, i)){ A; return true;} #define DO(S, C, A) ON(S, C, consumearg(vt); if (!vt->ignored) {A;} \ fixcursor(vt); resetparser(vt);); + #define SK(S) if (vt->state == (S)) { return true; } DO(S_NUL, "\x07", CB(vt, TMT_MSG_BELL, NULL)) DO(S_NUL, "\x08", if (c->c) c->c--) @@ -276,6 +315,10 @@ handlechar(TMT *vt, char i) ON(S_ESC, "+*()", vt->ignored = true; vt->state = S_ARG) DO(S_ESC, "c", tmt_reset(vt)) ON(S_ESC, "[", vt->state = S_ARG) + ON(S_ESC, "]", vt->state = S_OS) + ON(S_OS, "\x1b", vt->state = S_ESC) + ON(S_OS, "\x07", vt->state = S_NUL) + SK(S_OS) ON(S_ARG, "\x1b", vt->state = S_ESC) ON(S_ARG, ";", consumearg(vt)) ON(S_ARG, "?", (void)0) @@ -315,10 +358,12 @@ handlechar(TMT *vt, char i) } static void +//notify(TMT *vt, bool update, bool moved, bool scroll) notify(TMT *vt, bool update, bool moved) { if (update) CB(vt, TMT_MSG_UPDATE, &vt->screen); if (moved) CB(vt, TMT_MSG_MOVED, &vt->curs); + //if (scroll) CB(vt, TMT_MSG_SCROLL, &vt->scroll); } static TMTLINE * @@ -339,6 +384,12 @@ freelines(TMT *vt, size_t s, size_t n, bool screen) vt->screen.lines[i] = NULL; } if (screen) free(vt->screen.lines); + + for (size_t i = s; vt->scroll.lines && i < s + n; i++){ + free(vt->scroll.lines[i]); + vt->scroll.lines[i] = NULL; + } + if (screen) free(vt->scroll.lines); } TMT * @@ -386,10 +437,29 @@ tmt_resize(TMT *vt, size_t nline, size_t ncol) nl = allocline(vt, vt->screen.lines[i], ncol, pc); if (!nl) return false; + vt->screen.lines[i] = nl; } vt->screen.nline = nline; + TMTLINE **sl = realloc(vt->scroll.lines, nline * sizeof(TMTLINE *)); + if (!sl) return false; + + vt->scroll.lines = sl; + vt->scroll.ncol = ncol; + for (size_t i = 0; i < nline; i++){ + TMTLINE *nl = NULL; + if (i >= vt->scroll.nline) + nl = vt->scroll.lines[i] = allocline(vt, NULL, ncol, 0); + else + nl = allocline(vt, vt->scroll.lines[i], ncol, pc); + + if (!nl) return false; + nl->dirty = false; + vt->scroll.lines[i] = nl; + } + vt->scroll.nline = nline; + vt->tabs = allocline(vt, vt->tabs, ncol, 0); if (!vt->tabs) return free(l), false; vt->tabs->chars[0].c = vt->tabs->chars[ncol - 1].c = L'*'; @@ -398,6 +468,7 @@ tmt_resize(TMT *vt, size_t nline, size_t ncol) fixcursor(vt); dirtylines(vt, 0, nline); + //notify(vt, true, true, false); notify(vt, true, true); return true; } @@ -413,21 +484,24 @@ writecharatcurs(TMT *vt, wchar_t w) if (wcwidth(w) < 0) return; #endif + /* If at end of screen, wrap to next line */ + if (c->c >= s->ncol) { + c->c = 0; + c->r++; + } + if (c->r >= s->nline){ + c->r = s->nline - 1; + scrup(vt, 0, 1); + } + CLINE(vt)->chars[vt->curs.c].c = w; CLINE(vt)->chars[vt->curs.c].a = vt->attrs; CLINE(vt)->dirty = vt->dirty = true; - if (c->c < s->ncol - 1) - c->c++; - else{ - c->c = 0; - c->r++; - } + /* Advance cursor to next column + Will wrap if necessary when trying to write next character. */ + c->c++; - if (c->r >= s->nline){ - c->r = s->nline - 1; - scrup(vt, 0, 1); - } } static inline size_t @@ -470,6 +544,7 @@ tmt_write(TMT *vt, const char *s, size_t n) } } + //notify(vt, vt->dirty, memcmp(&oc, &vt->curs, sizeof(oc)) != 0, (vt->scroll.lines[0]->dirty)); notify(vt, vt->dirty, memcmp(&oc, &vt->curs, sizeof(oc)) != 0); } @@ -492,6 +567,13 @@ tmt_clean(TMT *vt) vt->dirty = vt->screen.lines[i]->dirty = false; } +void +tmt_clean_scroll(TMT *vt) +{ + for (size_t i = 0; i < vt->scroll.nline; i++) + vt->scroll.lines[i]->dirty = false; +} + void tmt_reset(TMT *vt) { @@ -501,5 +583,6 @@ tmt_reset(TMT *vt) memset(&vt->ms, 0, sizeof(vt->ms)); clearlines(vt, 0, vt->screen.nline); CB(vt, TMT_MSG_CURSOR, "t"); + //notify(vt, true, true, false); notify(vt, true, true); } diff --git a/tmt.h b/tmt.h index ae0ddbb..b609bea 100644 --- a/tmt.h +++ b/tmt.h @@ -74,7 +74,23 @@ typedef enum{ TMT_COLOR_MAGENTA, TMT_COLOR_CYAN, TMT_COLOR_WHITE, + TMT_COLOR_BRIGHT_BLACK, + TMT_COLOR_BRIGHT_RED, + TMT_COLOR_BRIGHT_GREEN, + TMT_COLOR_BRIGHT_YELLOW, + TMT_COLOR_BRIGHT_BLUE, + TMT_COLOR_BRIGHT_MAGENTA, + TMT_COLOR_BRIGHT_CYAN, + TMT_COLOR_BRIGHT_WHITE, + TMT_COLOR_RGB, TMT_COLOR_MAX +} tmt_color_code_t; + +typedef struct { + tmt_color_code_t code; + unsigned char red; + unsigned char green; + unsigned char blue; } tmt_color_t; typedef struct TMTATTRS TMTATTRS; @@ -121,7 +137,8 @@ typedef enum{ TMT_MSG_UPDATE, TMT_MSG_ANSWER, TMT_MSG_BELL, - TMT_MSG_CURSOR + TMT_MSG_CURSOR, + TMT_MSG_SCROLL } tmt_msg_t; typedef void (*TMTCALLBACK)(tmt_msg_t m, struct TMT *v, const void *r, void *p); @@ -135,6 +152,7 @@ void tmt_write(TMT *vt, const char *s, size_t n); const TMTSCREEN *tmt_screen(const TMT *vt); const TMTPOINT *tmt_cursor(const TMT *vt); void tmt_clean(TMT *vt); +void tmt_clean_scroll(TMT *vt); void tmt_reset(TMT *vt); #endif