aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/dvtm/vt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/dvtm/vt.c')
-rw-r--r--sys/cmd/dvtm/vt.c1282
1 files changed, 944 insertions, 338 deletions
diff --git a/sys/cmd/dvtm/vt.c b/sys/cmd/dvtm/vt.c
index 4e1f427..aff4ab0 100644
--- a/sys/cmd/dvtm/vt.c
+++ b/sys/cmd/dvtm/vt.c
@@ -9,8 +9,6 @@
#include <sys/ioctl.h>
#include <sys/types.h>
-#include "term.h"
-
#if defined(__linux__) || defined(__CYGWIN__)
# include <pty.h>
#elif defined(__FreeBSD__) || defined(__DragonFly__)
@@ -19,121 +17,609 @@
# include <util.h>
#endif
+#include "vt.h"
+
+#ifndef NCURSES_ATTR_SHIFT
+# define NCURSES_ATTR_SHIFT 8
+#endif
+
+#ifndef NCURSES_ACS
+# ifdef PDCURSES
+# define NCURSES_ACS(c) (acs_map[(uchar)(c)])
+# else /* BSD curses */
+# define NCURSES_ACS(c) (_acs_map[(uchar)(c)])
+# endif
+#endif
+
+#ifdef NCURSES_VERSION
+
+#ifndef NCURSES_EXT_COLORS
+# define NCURSES_EXT_COLORS 0
+#endif
+
+#if !NCURSES_EXT_COLORS
+# define MAX_COLOR_PAIRS MIN(COLOR_PAIRS, 256)
+#endif
+
+#endif
+
+#ifndef MAX_COLOR_PAIRS
+# define MAX_COLOR_PAIRS COLOR_PAIRS
+#endif
+
+#if defined _AIX && defined CTRL
+# undef CTRL
+#endif
+#ifndef CTRL
+# define CTRL(k) ((k) & 0x1F)
+#endif
+
#define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
-typedef struct Vt Vt;
+static bool is_utf8, has_default_colors;
+static int color_pairs_reserved, color_pairs_max, color_pair_current;
+static short *color2palette, default_fg, default_bg;
+static char vt_term[32];
+
+typedef struct {
+ wchar_t text;
+ attr_t attr;
+ union {
+ struct {
+ short fg;
+ short bg;
+ };
+ struct {
+ uint8 r;
+ uint8 g;
+ uint8 b;
+ };
+ };
+} Cell;
+
+typedef struct {
+ Cell *cells;
+ uint dirty:1;
+} Row;
+
+/* Buffer holding the current terminal window content (as an array) as well
+ * as the scroll back buffer content (as a circular/ring buffer).
+ *
+ * If new content is added to terminal the view port slides down and the
+ * previously top most line is moved into the scroll back buffer at postion
+ * scroll_index. This index will eventually wrap around and thus overwrite
+ * the oldest lines.
+ *
+ * In the scenerio below a scroll up has been performed. That is 'scroll_above'
+ * lines still lie above the current view port. Further scrolling up will show
+ * them. Similarly 'scroll_below' is the amount of lines below the current
+ * viewport.
+ *
+ * The function buffer_boundary sets the row pointers to the start/end range
+ * of the section delimiting the region before/after the viewport. The functions
+ * buffer_row_{first,last} return the first/last logical row. And
+ * buffer_row_{next,prev} allows to iterate over the logical lines in either
+ * direction.
+ *
+ * scroll back buffer
+ *
+ * scroll_buf->+----------------+-----+
+ * | | | ^ \
+ * | before | | | |
+ * current terminal content | viewport | | | |
+ * | | | |
+ * +----------------+-----+\ | | | s > scroll_above
+ * ^ | | i | \ | | i | c |
+ * | | | n | \ | | n | r |
+ * | | v | \ | | v | o |
+ * r | | i | \ | | i | l /
+ * o | viewport | s | >|<- scroll_index | s | l \
+ * w | | i | / | | i | |
+ * s | | b | / | after | b | s > scroll_below
+ * | | l | / | viewport | l | i |
+ * v | | e | / | | e | z /
+ * +----------------+-----+/ | unused | | e
+ * <- maxcols -> | scroll back | |
+ * <- cols -> | buffer | | |
+ * | | | |
+ * | | | v
+ * scroll_buf + scroll_size->+----------------+-----+
+ * <- maxcols ->
+ * <- cols ->
+ */
+typedef struct {
+ Row *lines; /* array of Row pointers of size 'rows' */
+ Row *curs_row; /* row on which the cursor currently resides */
+ Row *scroll_buf; /* a ring buffer holding the scroll back content */
+ Row *scroll_top; /* row in lines where scrolling region starts */
+ Row *scroll_bot; /* row in lines where scrolling region ends */
+ bool *tabs; /* a boolean flag for each column whether it is a tab */
+ int scroll_size; /* maximal capacity of scroll back buffer (in lines) */
+ int scroll_index; /* current index into the ring buffer */
+ int scroll_above; /* number of lines above current viewport */
+ int scroll_below; /* number of lines below current viewport */
+ int rows, cols; /* current dimension of buffer */
+ int maxcols; /* allocated cells (maximal cols over time) */
+ attr_t curattrs, savattrs; /* current and saved attributes for cells */
+ int curs_col; /* current cursor column (zero based) */
+ int curs_srow, curs_scol; /* saved cursor row/colmn (zero based) */
+ short curfg, curbg; /* current fore and background colors */
+ short savfg, savbg; /* saved colors */
+} Buffer;
struct Vt {
- Buffer buf[2]; /* normal & alternative screen buffer */
- Buffer *buffer; /* currently active buffer (one of the above) */
- Pen pen; /* default pen */
- int pty; /* master side pty file descriptor */
- pid_t pid; /* process id of the process running in this vt */
+ Buffer buffer_normal; /* normal screen buffer */
+ Buffer buffer_alternate; /* alternate screen buffer */
+ Buffer *buffer; /* currently active buffer (one of the above) */
+ attr_t defattrs; /* attributes to use for normal/empty cells */
+ int deffg, defbg; /* colors to use for back normal/empty cells (white/black) */
+ int pty; /* master side pty file descriptor */
+ pid_t pid; /* process id of the process running in this vt */
/* flags */
- char title[256]; /* xterm style window title */
- void *data; /* user supplied data */
- uint seen_input : 1;
- uint insert : 1;
- uint escaped : 1;
- uint curshid : 1;
- uint curskeymode : 1;
- uint bell : 1;
- uint relposmode : 1;
- uint mousetrack : 1;
- uint graphmode : 1;
- uint savgraphmode : 1;
+ uint seen_input:1;
+ uint insert:1;
+ uint escaped:1;
+ uint curshid:1;
+ uint curskeymode:1;
+ uint bell:1;
+ uint relposmode:1;
+ uint mousetrack:1;
+ uint graphmode:1;
+ uint savgraphmode:1;
bool charsets[2];
/* buffers and parsing state */
char rbuf[BUFSIZ];
char ebuf[BUFSIZ];
uint rlen, elen;
- int srow, scol; /* last known offset to display start row, start column */
+ int srow, scol; /* last known offset to display start row, start column */
+ char title[256]; /* xterm style window title */
+ vt_title_handler_t title_handler; /* hook which is called when title changes */
+ vt_urgent_handler_t urgent_handler; /* hook which is called upon bell */
+ void *data; /* user supplied data */
};
-/* forward declares */
-
-void vt·noscroll(Vt *t);
-void vt·dirty(Vt *t);
-void vt·scroll(Vt *t, int rows);
+static const char *keytable[KEY_MAX+1] = {
+ [KEY_ENTER] = "\r",
+ ['\n'] = "\n",
+ /* for the arrow keys the CSI / SS3 sequences are not stored here
+ * because they depend on the current cursor terminal mode
+ */
+ [KEY_UP] = "A",
+ [KEY_DOWN] = "B",
+ [KEY_RIGHT] = "C",
+ [KEY_LEFT] = "D",
+#ifdef KEY_SUP
+ [KEY_SUP] = "\e[1;2A",
+#endif
+#ifdef KEY_SDOWN
+ [KEY_SDOWN] = "\e[1;2B",
+#endif
+ [KEY_SRIGHT] = "\e[1;2C",
+ [KEY_SLEFT] = "\e[1;2D",
+ [KEY_BACKSPACE] = "\177",
+ [KEY_IC] = "\e[2~",
+ [KEY_DC] = "\e[3~",
+ [KEY_PPAGE] = "\e[5~",
+ [KEY_NPAGE] = "\e[6~",
+ [KEY_HOME] = "\e[7~",
+ [KEY_END] = "\e[8~",
+ [KEY_BTAB] = "\e[Z",
+ [KEY_SUSPEND] = "\x1A", /* Ctrl+Z gets mapped to this */
+ [KEY_F(1)] = "\e[11~",
+ [KEY_F(2)] = "\e[12~",
+ [KEY_F(3)] = "\e[13~",
+ [KEY_F(4)] = "\e[14~",
+ [KEY_F(5)] = "\e[15~",
+ [KEY_F(6)] = "\e[17~",
+ [KEY_F(7)] = "\e[18~",
+ [KEY_F(8)] = "\e[19~",
+ [KEY_F(9)] = "\e[20~",
+ [KEY_F(10)] = "\e[21~",
+ [KEY_F(11)] = "\e[23~",
+ [KEY_F(12)] = "\e[24~",
+ [KEY_F(13)] = "\e[23~",
+ [KEY_F(14)] = "\e[24~",
+ [KEY_F(15)] = "\e[25~",
+ [KEY_F(16)] = "\e[26~",
+ [KEY_F(17)] = "\e[28~",
+ [KEY_F(18)] = "\e[29~",
+ [KEY_F(19)] = "\e[31~",
+ [KEY_F(20)] = "\e[32~",
+ [KEY_F(21)] = "\e[33~",
+ [KEY_F(22)] = "\e[34~",
+ [KEY_RESIZE] = "",
+#ifdef KEY_EVENT
+ [KEY_EVENT] = "",
+#endif
+};
static void puttab(Vt *t, int count);
-static void process_nonprinting(Vt *t, rune r);
-static void sendcurs(Vt *t);
+static void process_nonprinting(Vt *t, wchar_t wc);
+static void send_curs(Vt *t);
-/* globals */
-static int isutf8;
-static char vtname[36];
+const static
+attr_t
+build_attrs(attr_t curattrs)
+{
+ return ((curattrs & ~A_COLOR) | COLOR_PAIR(curattrs & 0xff)) >> NCURSES_ATTR_SHIFT;
+}
static
void
-cclamp(Vt *t)
+row_set(Row *row, int start, int len, Buffer *t)
{
- Buffer *b = t->buffer;
- Row *lines = t->relposmode ? b->scroll.top : b->lines;
- int rows = t->relposmode ? b->scroll.bot - b->scroll.top : b->rows;
+ Cell cell = {
+ .text = L'\0',
+ .attr = t ? build_attrs(t->curattrs) : 0,
+ .fg = t ? t->curfg : -1,
+ .bg = t ? t->curbg : -1,
+ };
- if (b->crow < lines)
- b->crow = lines;
- if (b->crow >= lines + rows)
- b->crow = lines + rows - 1;
- if (b->ccol < 0)
- b->ccol = 0;
- if (b->ccol >= b->cols)
- b->ccol = b->cols - 1;
+ for (int i = start; i < len + start; i++)
+ row->cells[i] = cell;
+ row->dirty = true;
}
static
void
-clinedown(Vt *t)
+row_roll(Row *start, Row *end, int count)
{
- Buffer *b = t->buffer;
- zero(b->crow, b->cols, b->maxcols - b->cols);
- b->crow++;
- if (b->crow < b->scroll.bot)
+ int n = end - start;
+
+ count %= n;
+ if (count < 0)
+ count += n;
+
+ if (count) {
+ char buf[count * sizeof(Row)];
+ 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 = true;
+ }
+}
+
+static
+void
+buffer_clear(Buffer *b)
+{
+ Cell cell = {
+ .text = L'\0',
+ .attr = A_NORMAL,
+ .fg = -1,
+ .bg = -1,
+ };
+
+ for (int i = 0; i < b->rows; i++) {
+ Row *row = b->lines + i;
+ for (int j = 0; j < b->cols; j++) {
+ row->cells[j] = cell;
+ row->dirty = true;
+ }
+ }
+}
+
+static
+void
+buffer_free(Buffer *b)
+{
+ for (int i = 0; i < b->rows; i++)
+ free(b->lines[i].cells);
+ free(b->lines);
+ for (int i = 0; i < b->scroll_size; i++)
+ free(b->scroll_buf[i].cells);
+ free(b->scroll_buf);
+ free(b->tabs);
+}
+
+static
+void
+buffer_scroll(Buffer *b, int s)
+{
+ /* work in screenfuls */
+ int ssz = b->scroll_bot - b->scroll_top;
+ if (s > ssz) {
+ buffer_scroll(b, ssz);
+ buffer_scroll(b, s - ssz);
+ return;
+ }
+ if (s < -ssz) {
+ buffer_scroll(b, -ssz);
+ buffer_scroll(b, s + ssz);
return;
+ }
+
+ b->scroll_above += s;
+ if (b->scroll_above >= b->scroll_size)
+ b->scroll_above = b->scroll_size;
+
+ if (s > 0 && b->scroll_size) {
+ for (int i = 0; i < s; i++) {
+ Row 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;
+ }
+ }
+ row_roll(b->scroll_top, b->scroll_bot, s);
+ if (s < 0 && b->scroll_size) {
+ for (int i = (-s) - 1; i >= 0; i--) {
+ b->scroll_index--;
+ if (b->scroll_index == -1)
+ b->scroll_index = b->scroll_size - 1;
+
+ Row 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 = true;
+ }
+ }
+}
+
+static
+void
+buffer_resize(Buffer *b, int rows, int cols)
+{
+ Row *lines = b->lines;
+
+ if (b->rows != rows) {
+ if (b->curs_row >= lines + rows) {
+ /* scroll up instead of simply chopping off bottom */
+ buffer_scroll(b, (b->curs_row - b->lines) - rows + 1);
+ }
+ while (b->rows > rows) {
+ free(lines[b->rows - 1].cells);
+ b->rows--;
+ }
+
+ lines = realloc(lines, sizeof(Row) * rows);
+ }
+
+ if (b->maxcols < cols) {
+ for (int row = 0; row < b->rows; row++) {
+ lines[row].cells = realloc(lines[row].cells, sizeof(Cell) * cols);
+ if (b->cols < cols)
+ row_set(lines + row, b->cols, cols - b->cols, nil);
+ lines[row].dirty = true;
+ }
+ Row *sbuf = b->scroll_buf;
+ for (int row = 0; row < b->scroll_size; row++) {
+ sbuf[row].cells = realloc(sbuf[row].cells, sizeof(Cell) * cols);
+ if (b->cols < cols)
+ row_set(sbuf + row, b->cols, cols - b->cols, nil);
+ }
+ b->tabs = realloc(b->tabs, sizeof(*b->tabs) * cols);
+ for (int col = b->cols; col < cols; col++)
+ b->tabs[col] = !(col & 7);
+ b->maxcols = cols;
+ b->cols = cols;
+ } else if (b->cols != cols) {
+ for (int row = 0; row < b->rows; row++)
+ lines[row].dirty = true;
+ b->cols = cols;
+ }
+
+ int deltarows = 0;
+ if (b->rows < rows) {
+ while (b->rows < rows) {
+ lines[b->rows].cells = calloc(b->maxcols, sizeof(Cell));
+ row_set(lines + b->rows, 0, b->maxcols, b);
+ b->rows++;
+ }
+
+ /* prepare for backfill */
+ if (b->curs_row >= b->scroll_bot - 1) {
+ deltarows = b->lines + rows - b->curs_row - 1;
+ if (deltarows > b->scroll_above)
+ deltarows = b->scroll_above;
+ }
+ }
+
+ b->curs_row += lines - b->lines;
+ b->scroll_top = lines;
+ b->scroll_bot = lines + rows;
+ b->lines = lines;
+
+ /* perform backfill */
+ if (deltarows > 0) {
+ buffer_scroll(b, -deltarows);
+ b->curs_row += deltarows;
+ }
+}
+
+static
+bool
+buffer_init(Buffer *b, int rows, int cols, int scroll_size)
+{
+ b->curattrs = A_NORMAL; /* white text over black background */
+ b->curfg = b->curbg = -1;
+ if (scroll_size < 0)
+ scroll_size = 0;
+ if (scroll_size && !(b->scroll_buf = calloc(scroll_size, sizeof(Row))))
+ return false;
+ b->scroll_size = scroll_size;
+ buffer_resize(b, rows, cols);
+ return true;
+}
+
+static
+void
+buffer_boundry(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];
+ }
+}
- vt·noscroll(t);
+static
+Row *
+buffer_row_first(Buffer *b) {
+ Row *bstart;
+ if (!b->scroll_size || !b->scroll_above)
+ return b->lines;
+ buffer_boundry(b, &bstart, nil, nil, nil);
+ return bstart;
+}
- b->crow = b->scroll.bot - 1;
- bscroll(b, 1);
- zero(b->crow, 0, b->cols);
+static
+Row *
+buffer_row_last(Buffer *b) {
+ Row *aend;
+ if (!b->scroll_size || !b->scroll_below)
+ return b->lines + b->rows - 1;
+ buffer_boundry(b, nil, nil, nil, &aend);
+ return aend;
}
-
+
+static
+Row *
+buffer_row_next(Buffer *b, Row *row)
+{
+ Row *before_start, *before_end, *after_start, *after_end;
+ Row *first = b->lines, *last = b->lines + b->rows - 1;
+
+ if (!row)
+ return nil;
+
+ buffer_boundry(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 *
+buffer_row_prev(Buffer *b, Row *row)
+{
+ Row *before_start, *before_end, *after_start, *after_end;
+ Row *first = b->lines, *last = b->lines + b->rows - 1;
+
+ if (!row)
+ return nil;
+
+ buffer_boundry(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;
+}
+
static
void
-csave(Vt *t)
+cursor_clamp(Vt *t)
{
Buffer *b = t->buffer;
- b->scrow = b->crow - b->lines;
- b->sccol = b->ccol;
+ Row *lines = t->relposmode ? b->scroll_top : b->lines;
+ int rows = t->relposmode ? b->scroll_bot - b->scroll_top : b->rows;
+
+ if (b->curs_row < lines)
+ b->curs_row = lines;
+ if (b->curs_row >= lines + rows)
+ b->curs_row = lines + rows - 1;
+ if (b->curs_col < 0)
+ b->curs_col = 0;
+ if (b->curs_col >= b->cols)
+ b->curs_col = b->cols - 1;
}
static
void
-crestore(Vt *t)
+cursor_line_down(Vt *t)
{
Buffer *b = t->buffer;
- b->crow = b->lines + b->scrow;
- b->ccol = b->sccol;
- cclamp(t);
+ row_set(b->curs_row, b->cols, b->maxcols - b->cols, nil);
+ b->curs_row++;
+ if (b->curs_row < b->scroll_bot)
+ return;
+
+ vt_noscroll(t);
+
+ b->curs_row = b->scroll_bot - 1;
+ buffer_scroll(b, 1);
+ row_set(b->curs_row, 0, b->cols, b);
}
static
void
-savepen(Vt *t)
+cursor_save(Vt *t)
{
Buffer *b = t->buffer;
- b->spen = b->pen;
+ b->curs_srow = b->curs_row - b->lines;
+ b->curs_scol = b->curs_col;
}
static
void
-loadpen(Vt *t)
+cursor_restore(Vt *t)
{
Buffer *b = t->buffer;
- b->pen = b->spen;
+ b->curs_row = b->lines + b->curs_srow;
+ b->curs_col = b->curs_scol;
+ cursor_clamp(t);
}
+static
+void
+attributes_save(Vt *t)
+{
+ Buffer *b = t->buffer;
+ b->savattrs = b->curattrs;
+ b->savfg = b->curfg;
+ b->savbg = b->curbg;
+ t->savgraphmode = t->graphmode;
+}
+
+static
+void
+attributes_restore(Vt *t)
+{
+ Buffer *b = t->buffer;
+ b->curattrs = b->savattrs;
+ b->curfg = b->savfg;
+ b->curbg = b->savbg;
+ t->graphmode = t->savgraphmode;
+}
static
void
@@ -170,85 +656,89 @@ interpret_csi_sgr(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
if (pcount == 0) {
/* special case: reset attributes */
- b->pen.state = PenNormal;
- b->pen.col.fg = b->pen.col.bg = -1;
+ b->curattrs = A_NORMAL;
+ b->curfg = b->curbg = -1;
return;
}
for (int i = 0; i < pcount; i++) {
switch (param[i]) {
case 0:
- b->pen.state = PenNormal;
- b->pen.col.fg = b->pen.col.bg = -1;
+ b->curattrs = A_NORMAL;
+ b->curfg = b->curbg = -1;
break;
case 1:
- b->pen.state |= PenBold;
+ b->curattrs |= A_BOLD;
break;
case 2:
- b->pen.state |= PenDim;
+ b->curattrs |= A_DIM;
break;
+#ifdef A_ITALIC
case 3:
- b->pen.state |= PenItalic;
+ b->curattrs |= A_ITALIC;
break;
+#endif
case 4:
- b->pen.state |= PenUnderline;
+ b->curattrs |= A_UNDERLINE;
break;
case 5:
- b->pen.state |= PenBlink;
+ b->curattrs |= A_BLINK;
break;
case 7:
- b->pen.state |= PenReverse;
+ b->curattrs |= A_REVERSE;
break;
case 8:
- b->pen.state |= PenInvis;
+ b->curattrs |= A_INVIS;
break;
case 22:
- b->pen.state &= ~(PenBold | PenDim);
+ b->curattrs &= ~(A_BOLD | A_DIM);
break;
+#ifdef A_ITALIC
case 23:
- b->pen.state &= ~PenItalic;
+ b->curattrs &= ~A_ITALIC;
break;
+#endif
case 24:
- b->pen.state &= ~PenUnderline;
+ b->curattrs &= ~A_UNDERLINE;
break;
case 25:
- b->pen.state &= ~PenBlink;
+ b->curattrs &= ~A_BLINK;
break;
case 27:
- b->pen.state &= ~PenReverse;
+ b->curattrs &= ~A_REVERSE;
break;
case 28:
- b->pen.state &= ~PenInvis;
+ b->curattrs &= ~A_INVIS;
break;
case 30 ... 37: /* fg */
- b->pen.col.fg = param[i] - 30;
+ b->curfg = param[i] - 30;
break;
case 38:
if ((i + 2) < pcount && param[i + 1] == 5) {
- b->pen.col.fg = param[i + 2];
+ b->curfg = param[i + 2];
i += 2;
}
break;
case 39:
- b->pen.col.fg = -1;
+ b->curfg = -1;
break;
case 40 ... 47: /* bg */
- b->pen.col.bg = param[i] - 40;
+ b->curbg = param[i] - 40;
break;
case 48:
if ((i + 2) < pcount && param[i + 1] == 5) {
- b->pen.col.bg = param[i + 2];
+ b->curbg = param[i + 2];
i += 2;
}
break;
case 49:
- b->pen.col.bg = -1;
+ b->curbg = -1;
break;
- case 90 ... 97: /* hi fg */
- b->pen.col.fg = param[i] - 82;
+ case 90 ... 97: /* hi fg */
+ b->curfg = param[i] - 82;
break;
case 100 ... 107: /* hi bg */
- b->pen.col.bg = param[i] - 92;
+ b->curbg = param[i] - 92;
break;
default:
break;
@@ -264,27 +754,27 @@ interpret_csi_ed(Vt *t, int param[], int pcount)
Row *row, *start, *end;
Buffer *b = t->buffer;
- savepen(t);
- b->pen.state = PenNormal;
- b->pen.col.fg = b->pen.col.bg = -1;
+ attributes_save(t);
+ b->curattrs = A_NORMAL;
+ b->curfg = b->curbg = -1;
if (pcount && param[0] == 2) {
start = b->lines;
- end = b->lines + b->rows;
+ end = b->lines + b->rows;
} else if (pcount && param[0] == 1) {
start = b->lines;
- end = b->crow;
- zero(b->crow, 0, b->ccol + 1);
+ end = b->curs_row;
+ row_set(b->curs_row, 0, b->curs_col + 1, b);
} else {
- zero(b->crow, b->ccol, b->cols - b->ccol);
- start = b->crow + 1;
- end = b->lines + b->rows;
+ row_set(b->curs_row, b->curs_col, b->cols - b->curs_col, b);
+ start = b->curs_row + 1;
+ end = b->lines + b->rows;
}
for (row = start; row < end; row++)
- zero(row, 0, b->cols);
+ row_set(row, 0, b->cols, b);
- loadpen(t);
+ attributes_restore(t);
}
/* interprets a 'move cursor' (CUP) escape sequence */
@@ -292,21 +782,21 @@ static
void
interpret_csi_cup(Vt *t, int param[], int pcount)
{
- Buffer *b = t->buffer;
- Row *lines = t->relposmode ? b->scroll.top : b->lines;
+ Buffer *b = t->buffer;
+ Row *lines = t->relposmode ? b->scroll_top : b->lines;
if (pcount == 0) {
- b->crow = lines;
- b->ccol = 0;
+ b->curs_row = lines;
+ b->curs_col = 0;
} else if (pcount == 1) {
- b->crow = lines + param[0] - 1;
- b->ccol = 0;
+ b->curs_row = lines + param[0] - 1;
+ b->curs_col = 0;
} else {
- b->crow = lines + param[0] - 1;
- b->ccol = param[1] - 1;
+ b->curs_row = lines + param[0] - 1;
+ b->curs_col = param[1] - 1;
}
- cclamp(t);
+ cursor_clamp(t);
}
/* Interpret the 'relative mode' sequences: CUU, CUD, CUF, CUB, CNL,
@@ -320,37 +810,37 @@ interpret_csi_c(Vt *t, char verb, int param[], int pcount)
switch (verb) {
case 'A':
- b->crow -= n;
+ b->curs_row -= n;
break;
case 'B':
case 'e':
- b->crow += n;
+ b->curs_row += n;
break;
case 'C':
case 'a':
- b->ccol += n;
+ b->curs_col += n;
break;
case 'D':
- b->ccol -= n;
+ b->curs_col -= n;
break;
case 'E':
- b->crow += n;
- b->ccol = 0;
+ b->curs_row += n;
+ b->curs_col = 0;
break;
case 'F':
- b->crow -= n;
- b->ccol = 0;
+ b->curs_row -= n;
+ b->curs_col = 0;
break;
case 'G':
case '`':
- b->ccol = n - 1;
+ b->curs_col = n - 1;
break;
case 'd':
- b->crow = b->lines + n - 1;
+ b->curs_row = b->lines + n - 1;
break;
}
- cclamp(t);
+ cursor_clamp(t);
}
/* Interpret the 'erase line' escape sequence */
@@ -361,13 +851,13 @@ interpret_csi_el(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
switch (pcount ? param[0] : 0) {
case 1:
- zero(b->crow, 0, b->ccol + 1);
+ row_set(b->curs_row, 0, b->curs_col + 1, b);
break;
case 2:
- zero(b->crow, 0, b->cols);
+ row_set(b->curs_row, 0, b->cols, b);
break;
default:
- zero(b->crow, b->ccol, b->cols - b->ccol);
+ row_set(b->curs_row, b->curs_col, b->cols - b->curs_col, b);
break;
}
}
@@ -378,16 +868,16 @@ void
interpret_csi_ich(Vt *t, int param[], int pcount)
{
Buffer *b = t->buffer;
- Row *row = b->crow;
+ Row *row = b->curs_row;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->ccol + n > b->cols)
- n = b->cols - b->ccol;
+ if (b->curs_col + n > b->cols)
+ n = b->cols - b->curs_col;
- for (int i = b->cols - 1; i >= b->ccol + n; i--)
+ for (int i = b->cols - 1; i >= b->curs_col + n; i--)
row->cells[i] = row->cells[i - n];
- zero(row, b->ccol, n);
+ row_set(row, b->curs_col, n, b);
}
/* Interpret the 'delete chars' sequence (DCH) */
@@ -396,16 +886,16 @@ void
interpret_csi_dch(Vt *t, int param[], int pcount)
{
Buffer *b = t->buffer;
- Row *row = b->crow;
+ Row *row = b->curs_row;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->ccol + n > b->cols)
- n = b->cols - b->ccol;
+ if (b->curs_col + n > b->cols)
+ n = b->cols - b->curs_col;
- for (int i = b->ccol; i < b->cols - n; i++)
+ for (int i = b->curs_col; i < b->cols - n; i++)
row->cells[i] = row->cells[i + n];
- zero(row, b->cols - n, n);
+ row_set(row, b->cols - n, n, b);
}
/* Interpret an 'insert line' sequence (IL) */
@@ -416,13 +906,13 @@ interpret_csi_il(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->crow + n >= b->scroll.bot) {
- for (Row *row = b->crow; row < b->scroll.bot; row++)
- zero(row, 0, b->cols);
+ if (b->curs_row + n >= b->scroll_bot) {
+ for (Row *row = b->curs_row; row < b->scroll_bot; row++)
+ row_set(row, 0, b->cols, b);
} else {
- roll(b->crow, b->scroll.bot, -n);
- for (Row *row = b->crow; row < b->crow + n; row++)
- zero(row, 0, b->cols);
+ row_roll(b->curs_row, b->scroll_bot, -n);
+ for (Row *row = b->curs_row; row < b->curs_row + n; row++)
+ row_set(row, 0, b->cols, b);
}
}
@@ -434,13 +924,13 @@ interpret_csi_dl(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->crow + n >= b->scroll.bot) {
- for (Row *row = b->crow; row < b->scroll.bot; row++)
- zero(row, 0, b->cols);
+ if (b->curs_row + n >= b->scroll_bot) {
+ for (Row *row = b->curs_row; row < b->scroll_bot; row++)
+ row_set(row, 0, b->cols, b);
} else {
- roll(b->crow, b->scroll.bot, n);
- for (Row *row = b->scroll.bot - n; row < b->scroll.bot; row++)
- zero(row, 0, b->cols);
+ row_roll(b->curs_row, b->scroll_bot, n);
+ for (Row *row = b->scroll_bot - n; row < b->scroll_bot; row++)
+ row_set(row, 0, b->cols, b);
}
}
@@ -452,10 +942,10 @@ interpret_csi_ech(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->ccol + n > b->cols)
- n = b->cols - b->ccol;
+ if (b->curs_col + n > b->cols)
+ n = b->cols - b->curs_col;
- zero(b->crow, b->ccol, n);
+ row_set(b->curs_row, b->curs_col, n, b);
}
/* Interpret a 'set scrolling region' (DECSTBM) sequence */
@@ -468,8 +958,8 @@ interpret_csi_decstbm(Vt *t, int param[], int pcount)
switch (pcount) {
case 0:
- b->scroll.top = b->lines;
- b->scroll.bot = b->lines + b->rows;
+ b->scroll_top = b->lines;
+ b->scroll_bot = b->lines + b->rows;
break;
case 2:
new_top = param[0] - 1;
@@ -487,15 +977,15 @@ interpret_csi_decstbm(Vt *t, int param[], int pcount)
/* check for range validity */
if (new_top < new_bot) {
- b->scroll.top = b->lines + new_top;
- b->scroll.bot = b->lines + new_bot;
+ b->scroll_top = b->lines + new_top;
+ b->scroll_bot = b->lines + new_bot;
}
break;
default:
return; /* malformed */
}
- b->crow = b->scroll.top;
- b->ccol = 0;
+ b->curs_row = b->scroll_top;
+ b->curs_col = 0;
}
static
@@ -530,17 +1020,17 @@ interpret_csi_priv_mode(Vt *t, int param[], int pcount, bool set)
case 47: /* use alternate/normal screen buffer */
case 1047:
if (!set)
- bclear(&t->buf[1]);
- t->buffer = set ? &t->buf[1] : &t->buf[0];
- vt·dirty(t);
+ buffer_clear(&t->buffer_alternate);
+ t->buffer = set ? &t->buffer_alternate : &t->buffer_normal;
+ vt_dirty(t);
if (param[i] != 1049)
break;
/* fall through */
case 1048: /* save/restore cursor */
if (set)
- csave(t);
+ cursor_save(t);
else
- crestore(t);
+ cursor_restore(t);
break;
case 1000: /* enable/disable normal mouse tracking */
t->mousetrack = set;
@@ -633,10 +1123,10 @@ interpret_csi(Vt *t)
interpret_csi_ech(t, csiparam, param_count);
break;
case 'S': /* SU: scroll up */
- vt·scroll(t, param_count ? -csiparam[0] : -1);
+ vt_scroll(t, param_count ? -csiparam[0] : -1);
break;
case 'T': /* SD: scroll down */
- vt·scroll(t, param_count ? csiparam[0] : 1);
+ vt_scroll(t, param_count ? csiparam[0] : 1);
break;
case 'Z': /* CBT: cursor backward tabulation */
puttab(t, param_count ? -csiparam[0] : -1);
@@ -644,7 +1134,7 @@ interpret_csi(Vt *t)
case 'g': /* TBC: tabulation clear */
switch (param_count ? csiparam[0] : 0) {
case 0:
- b->tabs[b->ccol] = false;
+ b->tabs[b->curs_col] = false;
break;
case 3:
memset(b->tabs, 0, sizeof(*b->tabs) * b->maxcols);
@@ -655,14 +1145,14 @@ interpret_csi(Vt *t)
interpret_csi_decstbm(t, csiparam, param_count);
break;
case 's': /* save cursor location */
- csave(t);
+ cursor_save(t);
break;
case 'u': /* restore cursor location */
- crestore(t);
+ cursor_restore(t);
break;
case 'n': /* query cursor location */
if (param_count == 1 && csiparam[0] == 6)
- sendcurs(t);
+ send_curs(t);
break;
default:
break;
@@ -675,8 +1165,8 @@ void
interpret_csi_ind(Vt *t)
{
Buffer *b = t->buffer;
- if (b->crow < b->lines + b->rows - 1)
- b->crow++;
+ if (b->curs_row < b->lines + b->rows - 1)
+ b->curs_row++;
}
/* Interpret a 'reverse index' (RI) sequence */
@@ -685,11 +1175,11 @@ void
interpret_csi_ri(Vt *t)
{
Buffer *b = t->buffer;
- if (b->crow > b->scroll.top)
- b->crow--;
+ if (b->curs_row > b->scroll_top)
+ b->curs_row--;
else {
- roll(b->scroll.top, b->scroll.bot, -1);
- zero(b->scroll.top, 0, b->cols);
+ row_roll(b->scroll_top, b->scroll_bot, -1);
+ row_set(b->scroll_top, 0, b->cols, b);
}
}
@@ -699,9 +1189,9 @@ void
interpret_csi_nel(Vt *t)
{
Buffer *b = t->buffer;
- if (b->crow < b->lines + b->rows - 1) {
- b->crow++;
- b->ccol = 0;
+ if (b->curs_row < b->lines + b->rows - 1) {
+ b->curs_row++;
+ b->curs_col = 0;
}
}
@@ -730,8 +1220,8 @@ interpret_osc(Vt *t)
switch (command) {
case 0: /* icon name and window title */
case 2: /* window title */
- // if (t->title_handler)
- // t->title_handler(t, data+1);
+ if (t->title_handler)
+ t->title_handler(t, data+1);
break;
case 1: /* icon name */
break;
@@ -786,12 +1276,12 @@ try_interpret_escape_seq(Vt *t)
}
break;
case '7': /* DECSC: save cursor and attributes */
- savepen(t);
- csave(t);
+ attributes_save(t);
+ cursor_save(t);
goto handled;
case '8': /* DECRC: restore cursor and attributes */
- loadpen(t);
- crestore(t);
+ attributes_restore(t);
+ cursor_restore(t);
goto handled;
case 'D': /* IND: index */
interpret_csi_ind(t);
@@ -803,7 +1293,7 @@ try_interpret_escape_seq(Vt *t)
interpret_csi_nel(t);
goto handled;
case 'H': /* HTS: horizontal tab set */
- t->buffer->tabs[t->buffer->ccol] = true;
+ t->buffer->tabs[t->buffer->curs_col] = true;
goto handled;
default:
goto cancel;
@@ -833,17 +1323,17 @@ puttab(Vt *t, int count)
{
Buffer *b = t->buffer;
int direction = count >= 0 ? 1 : -1;
- for (int col = b->ccol + direction; count; col += direction) {
+ for (int col = b->curs_col + direction; count; col += direction) {
if (col < 0) {
- b->ccol = 0;
+ b->curs_col = 0;
break;
}
if (col >= b->cols) {
- b->ccol = b->cols - 1;
+ b->curs_col = b->cols - 1;
break;
}
if (b->tabs[col]) {
- b->ccol = col;
+ b->curs_col = col;
count -= direction;
}
}
@@ -851,31 +1341,31 @@ puttab(Vt *t, int count)
static
void
-process_nonprinting(Vt *t, rune r)
+process_nonprinting(Vt *t, wchar_t wc)
{
Buffer *b = t->buffer;
- switch (r) {
+ switch (wc) {
case '\e': /* ESC */
new_escape_sequence(t);
break;
case '\a': /* BEL */
- // if (t->urgent_handler)
- // t->urgent_handler(t);
+ if (t->urgent_handler)
+ t->urgent_handler(t);
break;
case '\b': /* BS */
- if (b->ccol > 0)
- b->ccol--;
+ if (b->curs_col > 0)
+ b->curs_col--;
break;
case '\t': /* HT */
puttab(t, 1);
break;
case '\r': /* CR */
- b->ccol = 0;
+ b->curs_col = 0;
break;
case '\v': /* VT */
case '\f': /* FF */
case '\n': /* LF */
- clinedown(t);
+ cursor_line_down(t);
break;
case '\016': /* SO: shift out, invoke the G1 character set */
t->graphmode = t->charsets[1];
@@ -893,7 +1383,7 @@ is_utf8_locale(void)
const char *cset = nl_langinfo(CODESET);
if (!cset)
cset = "ANSI_X3.4-1968";
- isutf8 = !strcmp(cset, "UTF-8");
+ is_utf8 = !strcmp(cset, "UTF-8");
}
static
@@ -917,18 +1407,17 @@ get_vt100_graphic(char c)
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
};
- if (isutf8)
+ if (is_utf8)
return vt100_utf8[c - 0x41];
- // else if (strchr(vt100_acs, c))
- // return NCURSES_ACS(c);
+ else if (strchr(vt100_acs, c))
+ return NCURSES_ACS(c);
return '\0';
}
static
void
-putrune(Vt *t, rune r)
+put_wc(Vt *t, wchar_t wc)
{
- Cell blank;
int width = 0;
if (!t->seen_input) {
@@ -938,61 +1427,54 @@ putrune(Vt *t, rune r)
if (t->escaped) {
if (t->elen + 1 < sizeof(t->ebuf)) {
- t->ebuf[t->elen] = r;
+ t->ebuf[t->elen] = wc;
t->ebuf[++t->elen] = '\0';
try_interpret_escape_seq(t);
} else {
cancel_escape_sequence(t);
}
- } else if (IS_CONTROL(r)) {
- process_nonprinting(t, r);
+ } else if (IS_CONTROL(wc)) {
+ process_nonprinting(t, wc);
} else {
if (t->graphmode) {
- if (r >= 0x41 && r <= 0x7e) {
- wchar_t gc = get_vt100_graphic(r);
+ if (wc >= 0x41 && wc <= 0x7e) {
+ wchar_t gc = get_vt100_graphic(wc);
if (gc)
- r = gc;
+ wc = gc;
}
width = 1;
- } else if ((width = wcwidth(r)) < 1) {
+ } else if ((width = wcwidth(wc)) < 1) {
width = 1;
}
Buffer *b = t->buffer;
- blank = (Cell){
- .r = L'\0',
- .pen = (Pen){
- .state = b->pen.state,
- .col = b->pen.col
- },
- };
- if (width == 2 && b->ccol == b->cols - 1) {
- b->crow->cells[b->ccol++] = blank;
- b->crow->dirty = true;
+ Cell blank_cell = { L'\0', build_attrs(b->curattrs), b->curfg, b->curbg };
+ if (width == 2 && b->curs_col == b->cols - 1) {
+ b->curs_row->cells[b->curs_col++] = blank_cell;
+ b->curs_row->dirty = true;
}
- if (b->ccol >= b->cols) {
- b->ccol = 0;
- clinedown(t);
+ if (b->curs_col >= b->cols) {
+ b->curs_col = 0;
+ cursor_line_down(t);
}
if (t->insert) {
- Cell *src = b->crow->cells + b->ccol;
+ Cell *src = b->curs_row->cells + b->curs_col;
Cell *dest = src + width;
- size_t len = b->cols - b->ccol - width;
+ size_t len = b->cols - b->curs_col - width;
memmove(dest, src, len * sizeof *dest);
}
- b->crow->cells[b->ccol] = blank;
- b->crow->cells[b->ccol++].r = r;
- b->crow->dirty = true;
-
+ b->curs_row->cells[b->curs_col] = blank_cell;
+ b->curs_row->cells[b->curs_col++].text = wc;
+ b->curs_row->dirty = true;
if (width == 2)
- b->crow->cells[b->ccol++] = blank;
+ b->curs_row->cells[b->curs_col++] = blank_cell;
}
}
int
-vt·process(Vt *t)
+vt_process(Vt *t)
{
int res;
uint pos = 0;
@@ -1004,17 +1486,18 @@ vt·process(Vt *t)
return -1;
}
+ /* read from the pty */
res = read(t->pty, t->rbuf + t->rlen, sizeof(t->rbuf) - t->rlen);
if (res < 0)
return -1;
+ /* process the bytes you read */
t->rlen += res;
while (pos < t->rlen) {
- rune r;
- size_t len;
+ wchar_t wc;
+ ssize_t len;
- // XXX: convert this to use utf8 functions
- len = (ssize_t)mbrtowc((wchar*)&r, t->rbuf + pos, t->rlen - pos, &ps);
+ len = (ssize_t)mbrtowc(&wc, t->rbuf + pos, t->rlen - pos, &ps);
if (len == -2) {
t->rlen -= pos;
memmove(t->rbuf, t->rbuf + pos, t->rlen);
@@ -1023,11 +1506,11 @@ vt·process(Vt *t)
if (len == -1) {
len = 1;
- r = t->rbuf[pos];
+ wc = t->rbuf[pos];
}
pos += len ? len : 1;
- putrune(t, r);
+ put_wc(t, wc);
}
t->rlen -= pos;
@@ -1035,9 +1518,16 @@ vt·process(Vt *t)
return 0;
}
-/* size is the number of rows kept in the scrollback */
+void
+vt_default_colors_set(Vt *t, attr_t attrs, short fg, short bg)
+{
+ t->defattrs = attrs;
+ t->deffg = fg;
+ t->defbg = bg;
+}
+
Vt *
-vt·make(int rows, int cols, int size)
+vt_create(int rows, int cols, int scroll_size)
{
if (rows <= 0 || cols <= 0)
return nil;
@@ -1047,14 +1537,11 @@ vt·make(int rows, int cols, int size)
return nil;
t->pty = -1;
- t->pen = (Pen) {
- .state = PenNormal,
- .col = {-1, -1},
- };
- t->buffer = &t->buf[0];
+ t->deffg = t->defbg = -1;
+ t->buffer = &t->buffer_normal;
- if (!binit(&t->buf[0], rows, cols, size) ||
- !binit(&t->buf[1], rows, cols, 0)) {
+ if (!buffer_init(&t->buffer_normal, rows, cols, scroll_size) ||
+ !buffer_init(&t->buffer_alternate, rows, cols, 0)) {
free(t);
return nil;
}
@@ -1063,34 +1550,34 @@ vt·make(int rows, int cols, int size)
}
void
-vt·resize(Vt *t, int rows, int cols)
+vt_resize(Vt *t, int rows, int cols)
{
struct winsize ws = { .ws_row = rows, .ws_col = cols };
if (rows <= 0 || cols <= 0)
return;
- vt·noscroll(t);
- bresize(&t->buf[0], rows, cols);
- bresize(&t->buf[1], rows, cols);
- cclamp(t);
+ vt_noscroll(t);
+ buffer_resize(&t->buffer_normal, rows, cols);
+ buffer_resize(&t->buffer_alternate, rows, cols);
+ cursor_clamp(t);
ioctl(t->pty, TIOCSWINSZ, &ws);
kill(-t->pid, SIGWINCH);
}
void
-vt·free(Vt *t)
+vt_destroy(Vt *t)
{
if (!t)
return;
- bfree(&t->buf[0]);
- bfree(&t->buf[1]);
+ buffer_free(&t->buffer_normal);
+ buffer_free(&t->buffer_alternate);
close(t->pty);
free(t);
}
void
-vt·dirty(Vt *t)
+vt_dirty(Vt *t)
{
Buffer *b = t->buffer;
for (Row *row = b->lines, *end = row + b->rows; row < end; row++)
@@ -1098,49 +1585,51 @@ vt·dirty(Vt *t)
}
void
-vt·draw(Vt *t, Window *win, int srow, int scol)
+vt_draw(Vt *t, WINDOW *win, int srow, int scol)
{
- int i, j;
- Cell *cell, *prev;
Buffer *b = t->buffer;
if (srow != t->srow || scol != t->scol) {
- vt·dirty(t);
+ vt_dirty(t);
t->srow = srow;
t->scol = scol;
}
- for (i = 0; i < b->rows; i++) {
+ for (int i = 0; i < b->rows; i++) {
Row *row = b->lines + i;
if (!row->dirty)
continue;
wmove(win, srow + i, scol);
- for (j = 0; j < b->cols; j++) {
- prev = cell;
+ Cell *cell = nil;
+ for (int j = 0; j < b->cols; j++) {
+ Cell *prev_cell = cell;
cell = row->cells + j;
- if (!prev || !peneq(cell->pen, prev->pen)) {
- if (cell->pen.state == PenNormal)
- cell->pen.state = t->pen.state;
- if (cell->pen.col.fg == -1)
- cell->pen.col.fg = t->pen.col.fg;
- if (cell->pen.col.bg == -1)
- cell->pen.col.bg = t->pen.col.bg;
- // wattrset(win, cell->attr << NCURSES_ATTR_SHIFT);
- // wcolor_set(win, vt_color_get(t, cell->fg, cell->bg), nil);
+ if (!prev_cell || cell->attr != prev_cell->attr
+ || cell->fg != prev_cell->fg
+ || cell->bg != prev_cell->bg) {
+ if (cell->attr == A_NORMAL)
+ cell->attr = t->defattrs;
+ if (cell->fg == -1)
+ cell->fg = t->deffg;
+ if (cell->bg == -1)
+ cell->bg = t->defbg;
+ wattrset(win, cell->attr << NCURSES_ATTR_SHIFT);
+ wcolor_set(win, vt_color_get(t, cell->fg, cell->bg), nil);
}
- if (isutf8 && cell->r >= RuneSync) {
+ if (is_utf8 && cell->text >= 128) {
char buf[MB_CUR_MAX + 1];
- size_t len = wcrtomb(buf, cell->r, nil);
+ size_t len = wcrtomb(buf, cell->text, nil);
if (len > 0) {
waddnstr(win, buf, len);
- if (wcwidth(cell->r) > 1)
+ if (wcwidth(cell->text) > 1)
j++;
}
- } else
- waddch(win, cell->r > ' ' ? cell->r: ' ');
+ } else {
+ waddch(win, cell->text > ' ' ? cell->text : ' ');
+ }
}
int x, y;
@@ -1152,36 +1641,36 @@ vt·draw(Vt *t, Window *win, int srow, int scol)
row->dirty = false;
}
- wmove(win, srow + b->crow - b->lines, scol + b->ccol);
+ wmove(win, srow + b->curs_row - b->lines, scol + b->curs_col);
}
void
-vt·scroll(Vt *t, int rows)
+vt_scroll(Vt *t, int rows)
{
Buffer *b = t->buffer;
- if (!b->scroll.size)
+ if (!b->scroll_size)
return;
if (rows < 0) { /* scroll back */
- if (rows < -b->scroll.above)
- rows = -b->scroll.above;
+ if (rows < -b->scroll_above)
+ rows = -b->scroll_above;
} else { /* scroll forward */
- if (rows > b->scroll.below)
- rows = b->scroll.below;
+ if (rows > b->scroll_below)
+ rows = b->scroll_below;
}
- bscroll(b, rows);
- b->scroll.below -= rows;
+ buffer_scroll(b, rows);
+ b->scroll_below -= rows;
}
void
-vt·noscroll(Vt *t)
+vt_noscroll(Vt *t)
{
- int below = t->buffer->scroll.below;
- if (below)
- vt·scroll(t, below);
+ int scroll_below = t->buffer->scroll_below;
+ if (scroll_below)
+ vt_scroll(t, scroll_below);
}
pid_t
-vt·forkpty(Vt *t, const char *p, const char *argv[], const char *cwd, const char *env[], int *to, int *from)
+vt_forkpty(Vt *t, const char *p, const char *argv[], const char *cwd, const char *env[], int *to, int *from)
{
int vt2ed[2], ed2vt[2];
struct winsize ws;
@@ -1228,7 +1717,7 @@ vt·forkpty(Vt *t, const char *p, const char *argv[], const char *cwd, const cha
for (const char **envp = env; envp && envp[0]; envp += 2)
setenv(envp[0], envp[1], 1);
- setenv("TERM", vtname, 1);
+ setenv("TERM", vt_term, 1);
if (cwd)
chdir(cwd);
@@ -1257,13 +1746,13 @@ vt_pty_get(Vt *t)
return t->pty;
}
-uintptr
-vt·write(Vt *t, const char *buf, size_t len)
+ssize_t
+vt_write(Vt *t, const char *buf, size_t len)
{
- uintptr res, ret = len;
+ ssize_t ret = len;
while (len > 0) {
- res = write(t->pty, buf, len);
+ ssize_t res = write(t->pty, buf, len);
if (res < 0) {
if (errno != EAGAIN && errno != EINTR)
return -1;
@@ -1278,19 +1767,18 @@ vt·write(Vt *t, const char *buf, size_t len)
static
void
-sendcurs(Vt *t)
+send_curs(Vt *t)
{
Buffer *b = t->buffer;
char keyseq[16];
- snprintf(keyseq, sizeof keyseq, "\e[%d;%dR", (int)(b->crow - b->lines), b->ccol);
- vt·write(t, keyseq, strlen(keyseq));
+ snprintf(keyseq, sizeof keyseq, "\e[%d;%dR", (int)(b->curs_row - b->lines), b->curs_col);
+ vt_write(t, keyseq, strlen(keyseq));
}
-#if 0
void
-vt·keypress(Vt *t, int keycode)
+vt_keypress(Vt *t, int keycode)
{
- vt·noscroll(t);
+ vt_noscroll(t);
if (keycode >= 0 && keycode <= KEY_MAX && keytable[keycode]) {
switch (keycode) {
@@ -1299,23 +1787,26 @@ vt·keypress(Vt *t, int keycode)
case KEY_RIGHT:
case KEY_LEFT: {
char keyseq[3] = { '\e', (t->curskeymode ? 'O' : '['), keytable[keycode][0] };
- vt·write(t, keyseq, sizeof keyseq);
+ vt_write(t, keyseq, sizeof keyseq);
break;
}
default:
- vt·write(t, keytable[keycode], strlen(keytable[keycode]));
+ vt_write(t, keytable[keycode], strlen(keytable[keycode]));
}
} else if (keycode <= UCHAR_MAX) {
char c = keycode;
- vt·write(t, &c, 1);
+ vt_write(t, &c, 1);
} else {
+#ifndef NDEBUG
fprintf(stderr, "unhandled key %#o\n", keycode);
+#endif
}
}
void
-vt·mouse(Vt *t, int x, int y, mmask_t mask)
+vt_mouse(Vt *t, int x, int y, mmask_t mask)
{
+#ifdef NCURSES_MOUSE_VERSION
char seq[6] = { '\e', '[', 'M' }, state = 0, button = 0;
if (!t->mousetrack)
@@ -1341,16 +1832,16 @@ vt·mouse(Vt *t, int x, int y, mmask_t mask)
seq[4] = 32 + x;
seq[5] = 32 + y;
- vt·write(t, seq, sizeof seq);
+ vt_write(t, seq, sizeof seq);
if (mask & (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED)) {
/* send a button release event */
button = 3;
seq[3] = 32 + button + state;
- vt·write(t, seq, sizeof seq);
+ vt_write(t, seq, sizeof seq);
}
+#endif /* NCURSES_MOUSE_VERSION */
}
-#endif
static
uint
@@ -1363,8 +1854,124 @@ color_hash(short fg, short bg)
return fg * (COLORS + 2) + bg;
}
+int
+vt_rgb_get(Vt *t, uint8 r, uint8 g, uint8 b)
+{
+ return 0;
+}
+
+
+int
+vt_color_get(Vt *t, short fg, short bg)
+{
+ if (fg >= COLORS)
+ fg = (t ? t->deffg : default_fg);
+ if (bg >= COLORS)
+ bg = (t ? t->defbg : default_bg);
+
+ if (!has_default_colors) {
+ if (fg == -1)
+ fg = (t && t->deffg != -1 ? t->deffg : default_fg);
+ if (bg == -1)
+ bg = (t && t->defbg != -1 ? t->defbg : default_bg);
+ }
+
+ if (!color2palette || (fg == -1 && bg == -1))
+ return 0;
+ uint index = color_hash(fg, bg);
+ if (color2palette[index] == 0) {
+ short oldfg, oldbg;
+ for (;;) {
+ if (++color_pair_current >= color_pairs_max)
+ color_pair_current = color_pairs_reserved + 1;
+ pair_content(color_pair_current, &oldfg, &oldbg);
+ uint old_index = color_hash(oldfg, oldbg);
+ if (color2palette[old_index] >= 0) {
+ if (init_pair(color_pair_current, fg, bg) == OK) {
+ color2palette[old_index] = 0;
+ color2palette[index] = color_pair_current;
+ }
+ break;
+ }
+ }
+ }
+
+ int color_pair = color2palette[index];
+ return color_pair >= 0 ? color_pair : -color_pair;
+}
+
+int
+vt_color_reserve(short fg, short bg)
+{
+ if (!color2palette || fg >= COLORS || bg >= COLORS)
+ return 0;
+
+ if (!has_default_colors && fg == -1)
+ fg = default_fg;
+ if (!has_default_colors && bg == -1)
+ bg = default_bg;
+ if (fg == -1 && bg == -1)
+ return 0;
+
+ uint index = color_hash(fg, bg);
+ if (color2palette[index] >= 0) {
+ if (init_pair(color_pairs_reserved + 1, fg, bg) == OK)
+ color2palette[index] = -(++color_pairs_reserved);
+ }
+ int color_pair = color2palette[index];
+ return color_pair >= 0 ? color_pair : -color_pair;
+}
+
+int
+vt_rgb_reserve(short fg, short bg)
+{
+ if (!color2palette || fg >= COLORS || bg >= COLORS)
+ return 0;
+
+ if (!has_default_colors && fg == -1)
+ fg = default_fg;
+ if (!has_default_colors && bg == -1)
+ bg = default_bg;
+ if (fg == -1 && bg == -1)
+ return 0;
+
+ uint index = color_hash(fg, bg);
+ if (color2palette[index] >= 0) {
+ if (init_pair(color_pairs_reserved + 1, fg, bg) == OK)
+ color2palette[index] = -(++color_pairs_reserved);
+ }
+ int color_pair = color2palette[index];
+ return color_pair >= 0 ? color_pair : -color_pair;
+}
+
+static
+void
+init_colors(void)
+{
+ pair_content(0, &default_fg, &default_bg);
+ if (default_fg == -1)
+ default_fg = COLOR_WHITE;
+ if (default_bg == -1)
+ default_bg = COLOR_BLACK;
+ has_default_colors = (use_default_colors() == OK);
+ color_pairs_max = MIN(MAX_COLOR_PAIRS, SHRT_MAX);
+
+ if (COLORS)
+ color2palette = calloc((COLORS + 2) * (COLORS + 2), sizeof(int));
+ /*
+ * XXX: On undefined color-pairs NetBSD curses pair_content() set fg
+ * and bg to default colors while ncurses set them respectively to
+ * 0 and 0. Initialize all color-pairs in order to have consistent
+ * behaviour despite the implementation used.
+ */
+ for (short i = 1; i < color_pairs_max; i++)
+ init_extended_pair(i, 0, 0);
+
+ vt_color_reserve(COLOR_WHITE, COLOR_BLACK);
+}
+
void
-vt·init(void)
+vt_init(void)
{
init_colors();
is_utf8_locale();
@@ -1372,17 +1979,11 @@ vt·init(void)
if (!term)
term = "dvtm";
- snprintf(vtname, sizeof vtname, "%s%s", term, COLORS >= 256 ? "-256color" : "");
-}
-
-void
-vt·shutdown(void)
-{
+ snprintf(vt_term, sizeof vt_term, "%s%s", term, COLORS >= 256 ? "-256color" : "");
}
-#if 0
void
-vt·setkeytable(const char * const keytable_overlay[], int count)
+vt_keytable_set(const char * const keytable_overlay[], int count)
{
for (int k = 0; k < count && k < KEY_MAX; k++) {
const char *keyseq = keytable_overlay[k];
@@ -1392,47 +1993,52 @@ vt·setkeytable(const char * const keytable_overlay[], int count)
}
void
-vt·settitlecb(Vt *t, vt_title_handler_t handler)
+vt_shutdown(void)
+{
+ free(color2palette);
+}
+
+void
+vt_title_handler_set(Vt *t, vt_title_handler_t handler)
{
t->title_handler = handler;
}
void
-vt·seturgentcb(Vt *t, vt_urgent_handler_t handler)
+vt_urgent_handler_set(Vt *t, vt_urgent_handler_t handler)
{
t->urgent_handler = handler;
}
-#endif
void
-vt·setdata(Vt *t, void *data)
+vt_data_set(Vt *t, void *data)
{
t->data = data;
}
void *
-vt·getdata(Vt *t)
+vt_data_get(Vt *t)
{
return t->data;
}
bool
-vt·cursorvisible(Vt *t)
+vt_cursor_visible(Vt *t)
{
- return t->buffer->scroll.below ? false : !t->curshid;
+ return t->buffer->scroll_below ? false : !t->curshid;
}
pid_t
-vt·pid(Vt *t)
+vt_pid_get(Vt *t)
{
return t->pid;
}
size_t
-vt·content(Vt *t, char **buf, bool colored)
+vt_content_get(Vt *t, char **buf, bool colored)
{
Buffer *b = t->buffer;
- int lines = b->scroll.above + b->scroll.below + b->rows + 1;
+ int lines = b->scroll_above + b->scroll_below + b->rows + 1;
size_t size = lines * ((b->cols + 1) * ((colored ? 64 : 0) + MB_CUR_MAX));
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
@@ -1441,28 +2047,28 @@ vt·content(Vt *t, char **buf, bool colored)
return 0;
char *s = *buf;
- Cell *prev = nil;
+ Cell *prev_cell = nil;
- for (Row *row = browfirst(b); row; row = brownext(b, row)) {
+ for (Row *row = buffer_row_first(b); row; row = buffer_row_next(b, row)) {
size_t len = 0;
char *last_non_space = s;
for (int col = 0; col < b->cols; col++) {
Cell *cell = row->cells + col;
if (colored) {
int esclen = 0;
- if (!prev || cell->attr != prev->attr) {
+ if (!prev_cell || cell->attr != prev_cell->attr) {
attr_t attr = cell->attr << NCURSES_ATTR_SHIFT;
esclen = sprintf(s, "\033[0%s%s%s%s%s%sm",
- attr & PenBold ? ";1" : "",
- attr & PenDim ? ";2" : "",
- attr & PenUnderline ? ";4" : "",
- attr & PenBlink ? ";5" : "",
- attr & PenReverse ? ";7" : "",
- attr & PenInvis ? ";8" : "");
+ attr & A_BOLD ? ";1" : "",
+ attr & A_DIM ? ";2" : "",
+ attr & A_UNDERLINE ? ";4" : "",
+ attr & A_BLINK ? ";5" : "",
+ attr & A_REVERSE ? ";7" : "",
+ attr & A_INVIS ? ";8" : "");
if (esclen > 0)
s += esclen;
}
- if (!prev || cell->fg != prev->fg || cell->attr != prev->attr) {
+ if (!prev_cell || cell->fg != prev_cell->fg || cell->attr != prev_cell->attr) {
if (cell->fg == -1)
esclen = sprintf(s, "\033[39m");
else
@@ -1470,7 +2076,7 @@ vt·content(Vt *t, char **buf, bool colored)
if (esclen > 0)
s += esclen;
}
- if (!prev || cell->bg != prev->bg || cell->attr != prev->attr) {
+ if (!prev_cell || cell->bg != prev_cell->bg || cell->attr != prev_cell->attr) {
if (cell->bg == -1)
esclen = sprintf(s, "\033[49m");
else
@@ -1478,7 +2084,7 @@ vt·content(Vt *t, char **buf, bool colored)
if (esclen > 0)
s += esclen;
}
- prev = cell;
+ prev_cell = cell;
}
if (cell->text) {
len = wcrtomb(s, cell->text, &ps);
@@ -1500,7 +2106,7 @@ vt·content(Vt *t, char **buf, bool colored)
}
int
-vt·contentstart(Vt *t)
+vt_content_start(Vt *t)
{
- return t->buffer->scroll.above;
+ return t->buffer->scroll_above;
}