aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-10 14:49:45 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-10 14:49:45 -0700
commite41eb5691417ecacade402759231f64778e3147f (patch)
treec28606655266f2702a30277f283e83b62f9a2cbb /sys/cmd
parent5daf8d56cdf6aecd1b7301c622c3e35eaa47bd42 (diff)
checkin: massive restructuring of dvtm
Diffstat (limited to 'sys/cmd')
-rw-r--r--sys/cmd/dvtm/buffer.c304
-rw-r--r--sys/cmd/dvtm/buffer.h0
-rw-r--r--sys/cmd/dvtm/config.h208
-rw-r--r--sys/cmd/dvtm/driver.c335
-rw-r--r--sys/cmd/dvtm/dvtm.c161
-rw-r--r--sys/cmd/dvtm/dvtm.h117
-rw-r--r--sys/cmd/dvtm/events.c1840
-rw-r--r--sys/cmd/dvtm/rules.mk10
-rw-r--r--sys/cmd/dvtm/term.c0
-rw-r--r--sys/cmd/dvtm/term.h137
-rw-r--r--sys/cmd/dvtm/vt.c1258
-rw-r--r--sys/cmd/dvtm/vt.h12
-rw-r--r--sys/cmd/dvtm/window.c42
-rw-r--r--sys/cmd/dwm/config.h12
-rw-r--r--sys/cmd/dwm/dwm.h1
-rw-r--r--sys/cmd/rules.mk4
-rw-r--r--sys/cmd/term/term.h1
17 files changed, 3406 insertions, 1036 deletions
diff --git a/sys/cmd/dvtm/buffer.c b/sys/cmd/dvtm/buffer.c
new file mode 100644
index 0000000..f7e73c0
--- /dev/null
+++ b/sys/cmd/dvtm/buffer.c
@@ -0,0 +1,304 @@
+#include "buffer.h"
+
+/* row operations */
+void
+zero(Row *row, int start, int len)
+{
+ int i;
+ Cell cell = {
+ .r = L'\0',
+ .pen = {0};
+ };
+
+ for (i = start; i < len + start; i++)
+ row->cells[i] = cell;
+ row->dirty = true;
+}
+
+void
+roll(Row *start, Row *end, int count)
+{
+ 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;
+ }
+}
+
+/* buffer operations */
+void
+bclear(Buffer *b)
+{
+ int i;
+ Cell cell = {
+ .r = L'\0',
+ .pen = {
+ .state = PenNormal,
+ .col.fg = -1,
+ .col.bg = -1,
+ },
+ };
+
+ for (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;
+ }
+ }
+}
+
+void
+bfree(Buffer *b)
+{
+ int i;
+
+ for (i = 0; i < b->rows; i++)
+ free(b->lines[i].cells);
+
+ free(b->lines);
+
+ for (i = 0; i < b->scroll.size; i++)
+ free(b->scroll.buf[i].cells);
+
+ free(b->scroll.buf);
+ free(b->tabs);
+}
+
+void
+bscroll(Buffer *b, int s)
+{
+ /* work in screenfuls */
+ int ssz = b->scroll.bot - b->scroll.top;
+
+ 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;
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+}
+
+void
+bresize(Buffer *b, int rows, int cols)
+{
+ Row *lines = b->lines;
+
+ if (b->rows != rows) {
+ if (b->crow >= lines + rows) {
+ /* scroll up instead of simply chopping off bottom */
+ bscroll(b, (b->crow - 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)
+ zero(lines + row, b->cols, cols - b->cols);
+ 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)
+ zero(sbuf + row, b->cols, cols - b->cols);
+ }
+ 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));
+ zero(lines + b->rows, 0, b->maxcols);
+ b->rows++;
+ }
+
+ /* prepare for backfill */
+ if (b->crow >= b->scroll.bot - 1) {
+ deltarows = b->lines + rows - b->crow - 1;
+ if (deltarows > b->scroll.above)
+ deltarows = b->scroll.above;
+ }
+ }
+
+ b->crow += lines - b->lines;
+ b->scroll.top = lines;
+ b->scroll.bot = lines + rows;
+ b->lines = lines;
+
+ /* perform backfill */
+ if (deltarows > 0) {
+ bscroll(b, -deltarows);
+ b->crow += deltarows;
+ }
+}
+
+bool
+binit(Buffer *b, int rows, int cols, int size)
+{
+ b->pen.state = PenNormal;
+ b->pen.col.fg = b->pen.col.fg = -1;
+
+ if (size < 0)
+ size = 0;
+ if (size && !(b->scroll.buf = calloc(size, sizeof(Row))))
+ return false;
+
+ b->scroll.size = size;
+ bresize(b, rows, cols);
+ return true;
+}
+
+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];
+ }
+}
+
+Row *
+browfirst(Buffer *b)
+{
+ Row *bstart;
+ if (!b->scroll.size || !b->scroll.above)
+ return b->lines;
+ bboundary(b, &bstart, nil, nil, nil);
+ return bstart;
+}
+
+Row *
+browlast(Buffer *b)
+{
+ Row *aend;
+ if (!b->scroll.size || !b->scroll.below)
+ return b->lines + b->rows - 1;
+ bboundary(b, nil, nil, nil, &aend);
+ return aend;
+}
+
+Row *
+brownext(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;
+
+ 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;
+}
+
+Row *
+bprevrow(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;
+
+ 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;
+}
diff --git a/sys/cmd/dvtm/buffer.h b/sys/cmd/dvtm/buffer.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sys/cmd/dvtm/buffer.h
diff --git a/sys/cmd/dvtm/config.h b/sys/cmd/dvtm/config.h
new file mode 100644
index 0000000..ec70596
--- /dev/null
+++ b/sys/cmd/dvtm/config.h
@@ -0,0 +1,208 @@
+#define VERSION "1.0"
+
+/* valid curses attributes are listed below they can be ORed
+ *
+ * A_NORMAL Normal display (no highlight)
+ * A_STANDOUT Best highlighting mode of the terminal.
+ * A_UNDERLINE Underlining
+ * A_REVERSE Reverse video
+ * A_BLINK Blinking
+ * A_DIM Half bright
+ * A_BOLD Extra bright or bold
+ * A_PROTECT Protected mode
+ * A_INVIS Invisible or blank mode
+ */
+
+enum {
+ DEFAULT,
+ BLUE,
+ GREEN,
+};
+
+static Color colors[] = {
+ [DEFAULT] = { .fg = -1, .bg = -1, .fg256 = -1, .bg256 = -1, },
+ [BLUE] = { .fg = COLOR_BLUE, .bg = -1, .fg256 = 68, .bg256 = -1, },
+ [GREEN] = { .fg = COLOR_GREEN, .bg = -1, .fg256 = 65, .bg256 = -1, },
+};
+
+#define COLOR(c) COLOR_PAIR(colors[c].pair)
+/* curses attributes for the currently focused window */
+#define SELECTED_ATTR (COLOR(GREEN) | A_NORMAL)
+/* curses attributes for normal (not selected) windows */
+#define NORMAL_ATTR (COLOR(DEFAULT) | A_NORMAL)
+/* curses attributes for a window with pending urgent flag */
+#define URGENT_ATTR NORMAL_ATTR
+/* curses attributes for the status bar */
+#define BAR_ATTR (COLOR(GREEN) | A_NORMAL)
+/* characters for beginning and end of status bar message */
+#define BAR_BEGIN '['
+#define BAR_END ']'
+/* status bar (command line option -s) position */
+#define BAR_POS BAR_TOP /* BAR_BOTTOM, BAR_OFF */
+/* whether status bar should be hidden if only one client exists */
+#define BAR_AUTOHIDE false
+/* master width factor [0.1 .. 0.9] */
+#define MFACT 0.5
+/* number of clients in master area */
+#define NMASTER 1
+/* scroll back buffer size in lines */
+#define SCROLL_HISTORY 500
+/* printf format string for the tag in the status bar */
+#define TAG_SYMBOL "[%s]"
+/* curses attributes for the currently selected tags */
+#define TAG_SEL (COLOR(GREEN) | A_BOLD)
+/* curses attributes for not selected tags which contain no windows */
+#define TAG_NORMAL (COLOR(DEFAULT) | A_NORMAL)
+/* curses attributes for not selected tags which contain windows */
+#define TAG_OCCUPIED (COLOR(GREEN) | A_NORMAL)
+/* curses attributes for not selected tags which with urgent windows */
+#define TAG_URGENT (COLOR(GREEN) | A_NORMAL | A_BLINK)
+
+static const char tags[][8] = { "1", "2", "3", "4", "5" };
+
+/* by default the first layout entry is used */
+static Layout layouts[] = {
+ { "[]=", tile },
+ { "+++", grid },
+ { "TTT", bstack },
+ { "[ ]", fullscreen },
+};
+
+#define MOD ('`')
+#define TAGKEYS(KEY,TAG) \
+ { { MOD, 'v', KEY, }, { view, { tags[TAG] } } }, \
+ { { MOD, 't', KEY, }, { tag, { tags[TAG] } } }, \
+ { { MOD, 'V', KEY, }, { toggleview, { tags[TAG] } } }, \
+ { { MOD, 'T', KEY, }, { toggletag, { tags[TAG] } } },
+
+/* you can specifiy at most 3 arguments */
+static KeyBinding bindings[] = {
+ { { MOD, 'c', }, { create, { NULL } } },
+ { { MOD, 'C', }, { create, { NULL, NULL, "$CWD" } } },
+ { { MOD, 'x', 'x', }, { killclient, { NULL } } },
+ { { MOD, 'j', }, { focusnext, { NULL } } },
+ { { MOD, 'J', }, { focusdown, { NULL } } },
+ { { MOD, 'K', }, { focusup, { NULL } } },
+ { { MOD, 'H', }, { focusleft, { NULL } } },
+ { { MOD, 'L', }, { focusright, { NULL } } },
+ { { MOD, 'k', }, { focusprev, { NULL } } },
+ { { MOD, 'f', }, { setlayout, { "[]=" } } },
+ { { MOD, 'g', }, { setlayout, { "+++" } } },
+ { { MOD, 'b', }, { setlayout, { "TTT" } } },
+ { { MOD, 'm', }, { setlayout, { "[ ]" } } },
+ { { MOD, ' ', }, { setlayout, { NULL } } },
+ { { MOD, 'i', }, { incnmaster, { "+1" } } },
+ { { MOD, 'd', }, { incnmaster, { "-1" } } },
+ { { MOD, 'h', }, { setmfact, { "-0.05" } } },
+ { { MOD, 'l', }, { setmfact, { "+0.05" } } },
+ { { MOD, '.', }, { toggleminimize, { NULL } } },
+ { { MOD, 's', }, { togglebar, { NULL } } },
+ { { MOD, 'S', }, { togglebarpos, { NULL } } },
+ { { MOD, 'M', }, { togglemouse, { NULL } } },
+ { { MOD, '\n', }, { zoom , { NULL } } },
+ { { MOD, '\r', }, { zoom , { NULL } } },
+ { { MOD, '1', }, { focusn, { "1" } } },
+ { { MOD, '2', }, { focusn, { "2" } } },
+ { { MOD, '3', }, { focusn, { "3" } } },
+ { { MOD, '4', }, { focusn, { "4" } } },
+ { { MOD, '5', }, { focusn, { "5" } } },
+ { { MOD, '6', }, { focusn, { "6" } } },
+ { { MOD, '7', }, { focusn, { "7" } } },
+ { { MOD, '8', }, { focusn, { "8" } } },
+ { { MOD, '9', }, { focusn, { "9" } } },
+ { { MOD, '\t', }, { focuslast, { NULL } } },
+ { { MOD, 'q', 'q', }, { quit, { NULL } } },
+ { { MOD, 'a', }, { togglerunall, { NULL } } },
+ { { MOD, CTRL('L'), }, { redraw, { NULL } } },
+ { { MOD, 'r', }, { redraw, { NULL } } },
+ { { MOD, 'e', }, { copymode, { "dvtm-editor" } } },
+ { { MOD, 'E', }, { copymode, { "dvtm-pager" } } },
+ { { MOD, '/', }, { copymode, { "dvtm-pager", "/" } } },
+ { { MOD, 'p', }, { paste, { NULL } } },
+ { { MOD, KEY_PPAGE, }, { scrollback, { "-1" } } },
+ { { MOD, KEY_NPAGE, }, { scrollback, { "1" } } },
+ { { MOD, '?', }, { create, { "man dvtm", "dvtm help" } } },
+ { { MOD, MOD, }, { send, { (const char []){MOD, 0} } } },
+ { { KEY_SPREVIOUS, }, { scrollback, { "-1" } } },
+ { { KEY_SNEXT, }, { scrollback, { "1" } } },
+ { { MOD, '0', }, { view, { NULL } } },
+ { { MOD, KEY_F(1), }, { view, { tags[0] } } },
+ { { MOD, KEY_F(2), }, { view, { tags[1] } } },
+ { { MOD, KEY_F(3), }, { view, { tags[2] } } },
+ { { MOD, KEY_F(4), }, { view, { tags[3] } } },
+ { { MOD, KEY_F(5), }, { view, { tags[4] } } },
+ { { MOD, 'v', '0' }, { view, { NULL } } },
+ { { MOD, 'v', '\t', }, { viewprevtag, { NULL } } },
+ { { MOD, 't', '0' }, { tag, { NULL } } },
+ TAGKEYS( '1', 0)
+ TAGKEYS( '2', 1)
+ TAGKEYS( '3', 2)
+ TAGKEYS( '4', 3)
+ TAGKEYS( '5', 4)
+};
+
+static const ColorRule colorrules[] = {
+ { "", A_NORMAL, &colors[DEFAULT] }, /* default */
+};
+
+/* possible values for the mouse buttons are listed below:
+ *
+ * BUTTON1_PRESSED mouse button 1 down
+ * BUTTON1_RELEASED mouse button 1 up
+ * BUTTON1_CLICKED mouse button 1 clicked
+ * BUTTON1_DOUBLE_CLICKED mouse button 1 double clicked
+ * BUTTON1_TRIPLE_CLICKED mouse button 1 triple clicked
+ * BUTTON2_PRESSED mouse button 2 down
+ * BUTTON2_RELEASED mouse button 2 up
+ * BUTTON2_CLICKED mouse button 2 clicked
+ * BUTTON2_DOUBLE_CLICKED mouse button 2 double clicked
+ * BUTTON2_TRIPLE_CLICKED mouse button 2 triple clicked
+ * BUTTON3_PRESSED mouse button 3 down
+ * BUTTON3_RELEASED mouse button 3 up
+ * BUTTON3_CLICKED mouse button 3 clicked
+ * BUTTON3_DOUBLE_CLICKED mouse button 3 double clicked
+ * BUTTON3_TRIPLE_CLICKED mouse button 3 triple clicked
+ * BUTTON4_PRESSED mouse button 4 down
+ * BUTTON4_RELEASED mouse button 4 up
+ * BUTTON4_CLICKED mouse button 4 clicked
+ * BUTTON4_DOUBLE_CLICKED mouse button 4 double clicked
+ * BUTTON4_TRIPLE_CLICKED mouse button 4 triple clicked
+ * BUTTON_SHIFT shift was down during button state change
+ * BUTTON_CTRL control was down during button state change
+ * BUTTON_ALT alt was down during button state change
+ * ALL_MOUSE_EVENTS report all button state changes
+ * REPORT_MOUSE_POSITION report mouse movement
+ */
+
+#ifdef NCURSES_MOUSE_VERSION
+# define CONFIG_MOUSE /* compile in mouse support if we build against ncurses */
+#endif
+
+#define ENABLE_MOUSE true /* whether to enable mouse events by default */
+
+#ifdef CONFIG_MOUSE
+static Button buttons[] = {
+ { BUTTON1_CLICKED, { mouse_focus, { NULL } } },
+ { BUTTON1_DOUBLE_CLICKED, { mouse_fullscreen, { "[ ]" } } },
+ { BUTTON2_CLICKED, { mouse_zoom, { NULL } } },
+ { BUTTON3_CLICKED, { mouse_minimize, { NULL } } },
+};
+#endif /* CONFIG_MOUSE */
+
+static Cmd commands[] = {
+ /* create [cmd]: create a new window, run `cmd` in the shell if specified */
+ { "create", { create, { NULL } } },
+ /* focus <win_id>: focus the window whose `DVTM_WINDOW_ID` is `win_id` */
+ { "focus", { focusid, { NULL } } },
+ /* tag <win_id> <tag> [tag ...]: add +tag, remove -tag or set tag of the window with the given identifier */
+ { "tag", { tagid, { NULL } } },
+};
+
+/* gets executed when dvtm is started */
+static Action actions[] = {
+ { create, { NULL } },
+};
+
+static char const * const keytable[] = {
+ /* add your custom key escape sequences */
+};
diff --git a/sys/cmd/dvtm/driver.c b/sys/cmd/dvtm/driver.c
new file mode 100644
index 0000000..3e6a518
--- /dev/null
+++ b/sys/cmd/dvtm/driver.c
@@ -0,0 +1,335 @@
+#include <u.h>
+#include <libn.h>
+#include <vendor/unibilium.h>
+
+typedef struct RGB8 RGB8;
+typedef struct Pen Pen;
+typedef struct Term Term;
+
+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",
+};
+
+struct RGB8
+{
+ uint8 r, g, b;
+};
+
+struct Pen
+{
+ uint bold : 1;
+ uint italic : 1;
+ uint reverse : 1;
+ uint strike : 1;
+ uint blink : 1;
+
+ /* colors */
+ uint color : 3;
+ union {
+ /* 256 color (legacy) */
+ struct {
+ sint fg : 9, bg : 9; /* 0 - 255 or COLOUR_DEFAULT */
+ } idx;
+ /* true color (modern) */
+ struct {
+ RGB8 fg, bg;
+ } rgb;
+ };
+};
+
+struct Term
+{
+ /* meta data */
+ char *name;
+ unibi_term *info;
+ struct {
+ uint altscreen : 1;
+ uint cursorvis : 1;
+ uint mouse : 1;
+ } mode;
+ struct {
+ uint bce : 1;
+ int colors;
+ } cap;
+
+ /* input capture */
+ // Input *input;
+
+ /* output display */
+ int nrow, ncol;
+
+ /* output raw text */
+ 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
+ } esc;
+};
+
+// -----------------------------------------------------------------------
+// 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
+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);
+
+ 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;
+ tflush(t);
+ }
+}
+
+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 */
+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 */
+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);
+}
+
+void
+tdel(Term *t, int num)
+{
+ 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);
+ }
+}
+
+void
+tclear(Term *t)
+{
+ tfmt(t, t->esc.ed2, 0);
+}
+
+
+// -----------------------------------------------------------------------
+// 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*
+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;
+}
+
+int
+main()
+{
+ Term t;
+
+ t.name = getenv("TERM");
+ t.info = unibi_from_term(t.name);
+
+ t.mode.mouse = 0;
+ t.mode.cursorvis = 1;
+ t.mode.altscreen = 0;
+
+ if (!t.info)
+ panicf("could not identify terminal");
+
+ 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);
+}
diff --git a/sys/cmd/dvtm/dvtm.c b/sys/cmd/dvtm/dvtm.c
index 802f891..9d35b25 100644
--- a/sys/cmd/dvtm/dvtm.c
+++ b/sys/cmd/dvtm/dvtm.c
@@ -181,12 +181,14 @@ drawbar(void)
wnoutrefresh(stdscr);
}
-static int
+static
+int
show_border(void) {
return (bar.pos != BAR_OFF) || (clients && clients->next);
}
-static void
+static
+void
draw_border(Client *c) {
char t = '\0';
int x, y, maxlen, attrs = NORMAL_ATTR;
@@ -218,13 +220,17 @@ draw_border(Client *c) {
wmove(c->window, y, x);
}
-static void
-draw_content(Client *c) {
+static
+void
+draw_content(Client *c)
+{
vt_draw(c->term, c->window, c->has_title_line, 0);
}
-static void
-draw(Client *c) {
+static
+void
+draw(Client *c)
+{
if (is_content_visible(c)) {
redrawwin(c->window);
draw_content(c);
@@ -234,8 +240,10 @@ draw(Client *c) {
wnoutrefresh(c->window);
}
-static void
-draw_all(void) {
+static
+void
+draw_all(void)
+{
if (!nextvisible(clients)) {
sel = nil;
curs_set(0);
@@ -259,8 +267,10 @@ draw_all(void) {
draw(sel);
}
-static void
-arrange(void) {
+static
+void
+arrange(void)
+{
uint m = 0, n = 0;
for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) {
c->order = ++n;
@@ -295,10 +305,13 @@ arrange(void) {
draw_all();
}
-static void
-attach(Client *c) {
+static
+void
+attach(Client *c)
+{
if (clients)
clients->prev = c;
+
c->next = clients;
c->prev = nil;
clients = c;
@@ -306,8 +319,10 @@ attach(Client *c) {
c->order = o;
}
-static void
-attachafter(Client *c, Client *a) { /* attach c after a */
+static
+void
+attachafter(Client *c, Client *a)
+{ /* attach c after a */
if (c == a)
return;
if (!a)
@@ -324,14 +339,18 @@ attachafter(Client *c, Client *a) { /* attach c after a */
}
}
-static void
-attachstack(Client *c) {
+static
+void
+attachstack(Client *c)
+{
c->snext = stack;
stack = c;
}
-static void
-detach(Client *c) {
+static
+void
+detach(Client *c)
+{
Client *d;
if (c->prev)
c->prev->next = c->next;
@@ -345,8 +364,10 @@ detach(Client *c) {
c->next = c->prev = nil;
}
-static void
-settitle(Client *c) {
+static
+void
+settitle(Client *c)
+{
char *term, *t = title;
if (!t && sel == c && *c->title)
t = c->title;
@@ -356,15 +377,19 @@ settitle(Client *c) {
}
}
-static void
-detachstack(Client *c) {
+static
+void
+detachstack(Client *c)
+{
Client **tc;
- for (tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
+ for (tc = &stack; *tc && *tc != c; tc = &(*tc)->snext)
+ ;
*tc = c->snext;
}
void
-focus(Client *c) {
+focus(Client *c)
+{
if (!c)
for (c = stack; c && !isvisible(c); c = c->snext);
if (sel == c)
@@ -394,10 +419,12 @@ focus(Client *c) {
curs_set(c && !c->minimized && vt_cursor_visible(c->term));
}
-static void
-applycolorrules(Client *c) {
+static
+void
+applycolorrules(Client *c)
+{
const ColorRule *r = colorrules;
- short fg = r->color->fg, bg = r->color->bg;
+ int fg = r->color->fg, bg = r->color->bg;
attr_t attrs = r->attrs;
for (uint i = 1; i < arrlen(colorrules); i++) {
@@ -413,8 +440,10 @@ applycolorrules(Client *c) {
vt_default_colors_set(c->term, attrs, fg, bg);
}
-static void
-term_title_handler(Vt *term, const char *title) {
+static
+void
+term_title_handler(Vt *term, const char *title)
+{
Client *c = (Client *)vt_data_get(term);
if (title)
strncpy(c->title, title, sizeof(c->title) - 1);
@@ -425,7 +454,8 @@ term_title_handler(Vt *term, const char *title) {
applycolorrules(c);
}
-static void
+static
+void
term_urgent_handler(Vt *term) {
Client *c = (Client *)vt_data_get(term);
c->urgent = true;
@@ -684,9 +714,11 @@ viewprevtag(const char *args[])
tagschanged();
}
-static void
-keypress(int code) {
- int key = -1;
+static
+void
+keypress(int code)
+{
+ int key = -1;
uint len = 1;
char buf[8] = { '\e' };
@@ -710,6 +742,7 @@ keypress(int code) {
vt_write(c->term, buf, len);
else
vt_keypress(c->term, code);
+
if (key != -1)
vt_keypress(c->term, key);
}
@@ -718,8 +751,10 @@ keypress(int code) {
}
}
-static void
-mouse_setup(void) {
+static
+void
+mouse_setup(void)
+{
#ifdef CONFIG_MOUSE
mmask_t mask = 0;
@@ -755,8 +790,10 @@ getshell(void) {
return "/bin/sh";
}
-static void
-setup(void) {
+static
+void
+setup(void)
+{
shell = getshell();
setlocale(LC_CTYPE, "");
initscr();
@@ -778,6 +815,7 @@ setup(void) {
colors[i].pair = vt_color_reserve(colors[i].fg, colors[i].bg);
}
resize_screen();
+
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_flags = 0;
@@ -792,7 +830,8 @@ setup(void) {
sigaction(SIGPIPE, &sa, nil);
}
-static void
+static
+void
destroy(Client *c) {
if (sel == c)
focusnextnm(nil);
@@ -823,7 +862,8 @@ destroy(Client *c) {
arrange();
}
-static void
+static
+void
cleanup(void) {
while (clients)
destroy(clients);
@@ -840,7 +880,8 @@ cleanup(void) {
unlink(cmdfifo.file);
}
-static char *getcwd_by_pid(Client *c) {
+static
+char *getcwd_by_pid(Client *c) {
if (!c)
return nil;
char buf[32];
@@ -1664,11 +1705,12 @@ parse_args(int argc, char *argv[]) {
}
int
-main(int argc, char *argv[]) {
+main(int argc, char *argv[])
+{
KeyCombo keys;
uint key_index = 0;
memset(keys, 0, sizeof(keys));
- sigset_t emptyset, blockset;
+ sigset_t emptysigs, blockset;
setenv("DVTM", VERSION, 1);
if (!parse_args(argc, argv)) {
@@ -1676,7 +1718,7 @@ main(int argc, char *argv[]) {
startup(nil);
}
- sigemptyset(&emptyset);
+ sigemptyset(&emptysigs);
sigemptyset(&blockset);
sigaddset(&blockset, SIGWINCH);
sigaddset(&blockset, SIGCHLD);
@@ -1684,27 +1726,27 @@ main(int argc, char *argv[]) {
while (running) {
int r, nfds = 0;
- fd_set rd;
+ fd_set rdrs; /* set of file descriptors we watch */
if (screen.need_resize) {
resize_screen();
screen.need_resize = false;
}
- FD_ZERO(&rd);
- FD_SET(STDIN_FILENO, &rd);
+ FD_ZERO(&rdrs);
+ FD_SET(STDIN_FILENO, &rdrs);
if (cmdfifo.fd != -1) {
- FD_SET(cmdfifo.fd, &rd);
+ FD_SET(cmdfifo.fd, &rdrs);
nfds = cmdfifo.fd;
}
if (bar.fd != -1) {
- FD_SET(bar.fd, &rd);
+ FD_SET(bar.fd, &rdrs);
nfds = MAX(nfds, bar.fd);
}
- for (Client *c = clients; c; ) {
+ for (Client *c = clients; c;) {
if (c->editor && c->editor_died)
handle_editor(c);
if (!c->editor && c->died) {
@@ -1714,13 +1756,13 @@ main(int argc, char *argv[]) {
continue;
}
int pty = c->editor ? vt_pty_get(c->editor) : vt_pty_get(c->app);
- FD_SET(pty, &rd);
+ FD_SET(pty, &rdrs);
nfds = MAX(nfds, pty);
- c = c->next;
+ c = c->next;
}
doupdate();
- r = pselect(nfds + 1, &rd, nil, nil, nil, &emptyset);
+ r = pselect(nfds + 1, &rdrs, nil, nil, nil, &emptysigs);
if (r < 0) {
if (errno == EINTR)
@@ -1729,11 +1771,13 @@ main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
- if (FD_ISSET(STDIN_FILENO, &rd)) {
+ if (FD_ISSET(STDIN_FILENO, &rdrs)) {
+ /* NOTE: this is the input handling step */
int code = getch();
if (code >= 0) {
- keys[key_index++] = code;
+ keys[key_index++] = code;
KeyBinding *binding = nil;
+
if (code == KEY_MOUSE) {
key_index = 0;
handle_mouse();
@@ -1752,18 +1796,19 @@ main(int argc, char *argv[]) {
keypress(code);
}
}
- if (r == 1) /* no data available on pty's */
+ /* no data available on pty's */
+ if (r == 1)
continue;
}
- if (cmdfifo.fd != -1 && FD_ISSET(cmdfifo.fd, &rd))
+ if (cmdfifo.fd != -1 && FD_ISSET(cmdfifo.fd, &rdrs))
handle_cmdfifo();
- if (bar.fd != -1 && FD_ISSET(bar.fd, &rd))
+ if (bar.fd != -1 && FD_ISSET(bar.fd, &rdrs))
handle_statusbar();
for (Client *c = clients; c; c = c->next) {
- if (FD_ISSET(vt_pty_get(c->term), &rd)) {
+ if (FD_ISSET(vt_pty_get(c->term), &rdrs)) {
if (vt_process(c->term) < 0 && errno == EIO) {
if (c->editor)
c->editor_died = true;
diff --git a/sys/cmd/dvtm/dvtm.h b/sys/cmd/dvtm/dvtm.h
index c36cb87..f89f517 100644
--- a/sys/cmd/dvtm/dvtm.h
+++ b/sys/cmd/dvtm/dvtm.h
@@ -13,37 +13,49 @@
#include <sys/time.h>
#include <sys/types.h>
+// #include <vendor/curses.h>
#include <termios.h>
#include "vt.h"
-#ifdef PDCURSES
-int ESCDELAY;
-#endif
-
-#ifndef NCURSES_REENTRANT
-#define set_escdelay(d) (ESCDELAY = (d))
-#endif
+/* types */
+typedef struct Term Term;
+typedef struct Screen Screen;
+typedef struct Layout Layout;
+typedef struct Window Window;
+typedef struct Client Client;
-typedef struct {
- float mfact;
- uint nmaster;
- int history;
- int w;
- int h;
+typedef struct Cmd Cmd;
+typedef struct CmdFifo CmdFifo;
+typedef struct Register Register;
+typedef struct Editor Editor;
+
+typedef struct Button Button;
+typedef struct KeyBinding KeyBinding;
+typedef struct StatusBar StatusBar;
+
+struct Screen
+{
+ Term *backend;
+ float mfact;
+ uint nmaster;
+ int history;
+ int w, h;
volatile sig_atomic_t need_resize;
-} Screen;
+};
-typedef struct {
+struct Layout
+{
const char *symbol;
void (*arrange)(void);
-} Layout;
-
-typedef struct Client Client;
-struct Client {
- WINDOW *window;
- Vt *term;
- Vt *editor, *app;
+} ;
+
+struct Client
+{
+ Window *window;
+ Vt *term;
+ Vt *editor, *app;
+ /* meta data */
int editor_fds[2];
volatile sig_atomic_t editor_died;
const char *cmd;
@@ -51,26 +63,22 @@ struct Client {
int order;
pid_t pid;
ushort id;
- ushort x;
- ushort y;
- ushort w;
- ushort h;
+ ushort x, y, w, h;
bool has_title_line;
bool minimized;
bool urgent;
volatile sig_atomic_t died;
- Client *next;
- Client *prev;
- Client *snext;
+ Client *next, *prev, *snext;
uint tags;
};
+#if 0
typedef struct {
- short fg;
- short bg;
- short fg256;
- short bg256;
- short pair;
+ int fg;
+ int bg;
+ int fg256;
+ int bg256;
+ int pair;
} Color;
typedef struct {
@@ -78,6 +86,7 @@ typedef struct {
attr_t attrs;
Color *color;
} ColorRule;
+#endif
#define ALT(k) ((k) + (161 - 'a'))
@@ -92,7 +101,8 @@ typedef struct {
#define MAX_ARGS 8
-typedef struct {
+typedef struct
+{
void (*cmd)(const char *args[]);
const char *args[3];
} Action;
@@ -101,24 +111,28 @@ typedef struct {
typedef uint KeyCombo[MAX_KEYS];
-typedef struct {
+struct KeyBinding
+{
KeyCombo keys;
Action action;
-} KeyBinding;
+};
-typedef struct {
+struct Button
+{
mmask_t mask;
Action action;
-} Button;
+};
-typedef struct {
+struct Cmd
+{
const char *name;
Action action;
-} Cmd;
+} ;
enum { BAR_TOP, BAR_BOTTOM, BAR_OFF };
-typedef struct {
+struct StatusBar
+{
int fd;
int pos, lastpos;
bool autohide;
@@ -126,26 +140,29 @@ typedef struct {
ushort y;
char text[512];
const char *file;
-} StatusBar;
+};
-typedef struct {
+struct CmdFifo
+{
int fd;
const char *file;
ushort id;
-} CmdFifo;
+};
-typedef struct {
+struct Register
+{
char *data;
size_t len;
size_t size;
-} Register;
+};
-typedef struct {
+struct Editor
+{
char *name;
const char *argv[4];
bool filter;
bool color;
-} Editor;
+};
#define TAGMASK ((1 << arrlen(tags)) - 1)
@@ -206,7 +223,7 @@ void resize(Client *c, int x, int y, int w, int h);
extern Screen screen;
extern uint waw, wah, wax, way;
extern Client *clients;
-extern char *title;
+extern char *title;
void fibonacci(int s);
void spiral(void);
diff --git a/sys/cmd/dvtm/events.c b/sys/cmd/dvtm/events.c
new file mode 100644
index 0000000..12b0518
--- /dev/null
+++ b/sys/cmd/dvtm/events.c
@@ -0,0 +1,1840 @@
+#include <u.h>
+#include <libn.h>
+#include <poll.h>
+#include <termios.h>
+
+#include <vendor/unibilium.h>
+
+#define iota(x) 1 << (x)
+#define bufcount(in) in->buf.c - in->buf.b
+
+/* symbols */
+enum
+{
+ SymUnknown = -1,
+ SymNone = 0,
+
+ /* special names in c0 */
+ SymBackspace, SymTab, SymEnter, SymEscape,
+
+ /* special names in g0 */
+ SymSpace, SymDel,
+
+ /* special keys */
+ SymUp, SymDown, SymLeft, SymRight, SymBegin, SymFind, SymInsert,
+ SymDelete, SymSelect, SymPageup, SymPagedown, SymHome, SymEnd,
+
+ /* special keys from terminfo */
+ SymCancel, SymClear, SymClose, SymCommand, SymCopy, SymExit,
+ SymHelp, SymMark, SymMessage, SymMove, SymOpen, SymOptions,
+ SymPrint, SymRedo, SymReference, SymRefresh, SymReplace,
+ SymRestart, SymResume, SymSave, SymSuspend, SymUndo,
+
+ /* numeric keypad special keys */
+ SymKp0, SymKp1, SymKp2, SymKp3, SymKp4, SymKp5, SymKp6, SymKp7, SymKp8,
+ SymKp9, SymKpenter, SymKpplus, SymKpminus, SymKpmult, SymKpdiv, SymKpcomma,
+ SymKpperiod, SymKpequals,
+
+ /* et cetera ad nauseum */
+ NumSyms
+};
+
+/* key type */
+enum
+{
+ KeyUnicode,
+ KeyFunc,
+ KeySym,
+ KeyMouse,
+ KeyPosition,
+ KeyModeReport,
+ KeyDCS,
+ KeyOSC,
+ /* add other recognised types here */
+
+ KeyUnknownCSI = -1
+};
+
+/* key events */
+enum KeyEvent
+{
+ EvNil,
+ EvKey,
+ EvEOF,
+ EvAgain,
+ EvErr,
+};
+
+enum MouseEvent
+{
+ MouseNil,
+ MousePress,
+ MouseDrag,
+ MouseRelease,
+};
+
+enum
+{
+ ModShift = iota(0),
+ ModAlt = iota(1),
+ ModCtrl = iota(2),
+};
+
+enum
+{
+ FlagNoInterpret = iota(0),
+ FlagConvertKP = iota(1),
+ FlagRaw = iota(2),
+ FlagUTF8 = iota(3),
+ FlagNoTermIOS = iota(4),
+ FlagSpaceSymbol = iota(5),
+ FlagCtrlC = iota(6),
+ FlagEintr = iota(7),
+};
+
+enum
+{
+ HarmonizeSpace = iota(0),
+ HarmonizeDelBS = iota(1),
+};
+
+enum {
+ NodeKey,
+ NodeArr,
+};
+
+typedef struct Key Key;
+typedef struct Node Node;
+typedef struct Input 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 Node
+{
+ int type;
+};
+
+struct KeyNode
+{
+ struct Node;
+ struct KeyInfo key;
+};
+
+struct ArrNode
+{
+ struct Node;
+ uchar min, max;
+ Node *arr[];
+};
+
+struct Input
+{
+ int fd;
+ int flags;
+ int hflag;
+ int wait; /* in ms */
+
+ struct termios oldterm;
+
+ /* buffer */
+ struct {
+ long off;
+ uchar *b, *c, *e, bytes[256];
+ } buf;
+
+ /* modifiers */
+ char closed : 1;
+ char started : 1;
+ char hasold : 1;
+
+ /* key data */
+ Node *keys;
+ struct KeyInfo c0[32];
+
+ char **keynm;
+ int nkeynm;
+
+ int nsavedcsi;
+ char *savedcsi;
+};
+
+// -----------------------------------------------------------------------
+// loads data into trie
+
+static enum KeyEvent peekmousekey(Input *in, Key *key, ulong *nb);
+
+#define FuncNameMax 10
+static struct {
+ char *name;
+ int type;
+ int sym;
+ int mods;
+} funcs[] =
+{
+ /* THIS LIST MUST REMAIN SORTED ALPHABETICALLY! */
+ { "backspace", KeySym, SymBackspace, 0 },
+ { "begin", KeySym, SymBegin, 0 },
+ { "beg", KeySym, SymBegin, 0 },
+ { "btab", KeySym, SymTab, ModShift},
+ { "cancel", KeySym, SymCancel, 0 },
+ { "clear", KeySym, SymClear, 0 },
+ { "close", KeySym, SymClose, 0 },
+ { "command", KeySym, SymCommand, 0 },
+ { "copy", KeySym, SymCopy, 0 },
+ { "dc", KeySym, SymDelete, 0 },
+ { "down", KeySym, SymDown, 0 },
+ { "end", KeySym, SymEnd, 0 },
+ { "enter", KeySym, SymEnter, 0 },
+ { "exit", KeySym, SymExit, 0 },
+ { "find", KeySym, SymFind, 0 },
+ { "help", KeySym, SymHelp, 0 },
+ { "home", KeySym, SymHome, 0 },
+ { "ic", KeySym, SymInsert, 0 },
+ { "left", KeySym, SymLeft, 0 },
+ { "mark", KeySym, SymMark, 0 },
+ { "message", KeySym, SymMessage, 0 },
+ { "move", KeySym, SymMove, 0 },
+ { "next", KeySym, SymPagedown, 0 }, // Not quite, but it's the best we can do
+ { "npage", KeySym, SymPagedown, 0 },
+ { "open", KeySym, SymOpen, 0 },
+ { "options", KeySym, SymOptions, 0 },
+ { "ppage", KeySym, SymPageup, 0 },
+ { "previous", KeySym, SymPageup, 0 }, // Not quite, but it's the best we can do
+ { "print", KeySym, SymPrint, 0 },
+ { "redo", KeySym, SymRedo, 0 },
+ { "reference", KeySym, SymReference, 0 },
+ { "refresh", KeySym, SymRefresh, 0 },
+ { "replace", KeySym, SymReplace, 0 },
+ { "restart", KeySym, SymRestart, 0 },
+ { "resume", KeySym, SymResume, 0 },
+ { "right", KeySym, SymRight, 0 },
+ { "save", KeySym, SymSave, 0 },
+ { "select", KeySym, SymSelect, 0 },
+ { "suspend", KeySym, SymSuspend, 0 },
+ { "undo", KeySym, SymUndo, 0 },
+ { "up", KeySym, SymUp, 0 },
+ { nil },
+};
+
+// -----------------------------------------------------------------------
+// utility functions
+
+static
+int
+stricmp(char *s, char *t)
+{
+ if (s == nil)
+ if (t == nil)
+ return 0;
+ else
+ return -strlen(t);
+ else
+ if (t == nil)
+ return +strlen(s);
+
+ int d;
+ for (; *s && *t; s++, t++) {
+ d = tolower(*s) - tolower(*t);
+ if (d < 0 || d > 0)
+ return d;
+ }
+
+ /* XXX: not sure about passing in 0 here */
+ return tolower(*s) - tolower(*t);
+}
+
+// -----------------------------------------------------------------------
+// bytes -> keysymbols
+
+static
+Node *
+keynode(int type, int sym, int mask, int set)
+{
+ struct KeyNode *n;
+ n = malloc(sizeof(*n));
+ if (!n)
+ panicf("out of memory");
+
+ n->type = NodeKey;
+ n->key.type = type;
+ n->key.sym = sym;
+ n->key.modmask = mask;
+ n->key.modset = set;
+
+ return (Node *)n;
+}
+
+static
+Node *
+arrnode(uchar min, uchar max)
+{
+ int nb, i;
+ struct ArrNode *n;
+ nb = ((int)max-min+1)*sizeof(*n->arr);
+ n = malloc(sizeof(*n) + nb);
+ if (!n)
+ panicf("out of memory");
+
+ n->type = NodeArr;
+ n->min = min, n->max = max;
+ for (i = 0; i <= max-min; i++)
+ n->arr[i] = nil;
+
+ return (Node *)n;
+}
+
+
+static
+Node *
+nlookup(Node *n, uchar b)
+{
+ struct ArrNode *arr;
+ switch (n->type) {
+ case NodeKey:
+ panicf("attempting to subdivide a leaf key node");
+ return nil;
+ case NodeArr:
+ arr = (struct ArrNode *)n;
+ if (b < arr->min || b > arr->max)
+ return nil;
+ return arr->arr[b - arr->min];
+ default:
+ panicf("unrecognized key node type");
+ return nil;
+ }
+}
+
+static
+Node *
+compress(Node *root)
+{
+ int i;
+ uchar min, max;
+ struct ArrNode *n, *new;
+
+ if (!root)
+ return root;
+
+ switch (root->type) {
+ case NodeKey:
+ return root;
+ case NodeArr:
+ n = (struct ArrNode *)root;
+ /* find the zeros */
+ for (min = 0; !n->arr[min]; min++) {
+ if (min == 255 && !n->arr[min]) {
+ free(n);
+ return arrnode(1, 0);
+ }
+ }
+
+ for (max = 0xff; !n->arr[max]; max--)
+ ;
+
+ new = (struct ArrNode *)arrnode(min, max);
+
+ for (i = min; i <= max; i++)
+ new->arr[i-min] = compress(n->arr[i]);
+
+ free(n);
+ return (Node*)new;
+ default:
+ panicf("unrecognized key node type");
+ return nil;
+ }
+
+ return root;
+}
+
+static
+void
+teardown(Node *n)
+{
+ int i;
+ struct ArrNode *arr;
+
+ switch (n->type) {
+ case NodeKey:
+ break;
+ case NodeArr:
+ arr = (struct ArrNode *)n;
+ for (i = arr->min; i <= arr->max; i++)
+ if (arr->arr[i - arr->min])
+ teardown(arr->arr[i - arr->min]);
+ break;
+ default:
+ return;
+ }
+
+ free(n);
+}
+
+static
+int
+insert(Node *root, Node *n, char *seq)
+{
+ int pos;
+ uchar b;
+ Node *nn;
+ struct ArrNode *a;
+
+ for (pos = 0; (b = seq[pos]); pos++) {
+ nn = nlookup(root, b);
+ if (!nn)
+ break;
+ root = nn;
+ a = (struct ArrNode *)root;
+ }
+
+ for (; (b = seq[pos]); pos++) {
+ nn = (seq[pos+1]) ? arrnode(0, 0xff) : n;
+ if (!nn)
+ return 0;
+
+ if (root->type != NodeArr)
+ panicf("inserted child node onto leaf 'key' node");
+
+ a = (struct ArrNode*)root;
+ if (b < a->min || b > a->max)
+ panicf("out of bound trie insertion");
+
+ a->arr[b-a->min] = root = nn;
+ }
+
+ return 1;
+}
+
+/* unibilium helpers */
+static
+enum unibi_string
+nametostr(char *name)
+{
+ enum unibi_string ret;
+ for (ret = unibi_string_begin_+1; ret < unibi_string_end_; ret++)
+ if (!strcmp(unibi_name_str(ret), name))
+ return ret;
+
+ return -1;
+}
+
+static
+char *
+unibi_lookup(unibi_term *info, char *name)
+{
+ enum unibi_string idx;
+ if ((idx = nametostr(name)) == -1)
+ return nil;
+
+ return (char*)unibi_get_str(info, idx);
+}
+
+static
+Node *
+tryloadkey(unibi_term *info, char *name, char **val, struct KeyInfo *key)
+{
+ char *v;
+
+ v = unibi_lookup(info, name);
+ if (!v || v[0] == 0)
+ return nil;
+
+ *val = v;
+ return keynode(key->type, key->sym, key->modmask, key->modset);
+}
+
+static
+Node *
+loadtermkeys(unibi_term *info)
+{
+ int i;
+ struct Node *root, *n;
+ char *val, name[5 + FuncNameMax + 1];
+
+ root = arrnode(0, 0xff);
+ if (!root)
+ panicf("out of memory");
+
+ /* load key syms */
+ for (i = 0; funcs[i].name; i++) {
+ sprintf(name, "key_%s", funcs[i].name);
+ n = tryloadkey(info, name, &val, &(struct KeyInfo){
+ .type = funcs[i].type,
+ .sym = funcs[i].sym,
+ .modmask = funcs[i].mods,
+ .modset = funcs[i].mods,
+ });
+
+ /* try shift modified */
+ if (!n)
+ n = tryloadkey(info, name, &val, &(struct KeyInfo){
+ .type = funcs[i].type,
+ .sym = funcs[i].sym,
+ .modmask = funcs[i].mods | ModShift,
+ .modset = funcs[i].mods | ModShift,
+ });
+
+ /* give up */
+ if (n)
+ insert(root, n, val);
+ }
+
+ /* load function keys */
+ for (i = 1; i < 0xff; i++) {
+ sprintf(name, "key_f%d", i);
+ n = tryloadkey(info, name, &val, &(struct KeyInfo){
+ .type = KeyFunc,
+ .sym = i,
+ .modmask = 0,
+ .modset = 0,
+ });
+ if (!n)
+ break;
+
+ insert(root, n, val);
+ }
+
+ /* load mouse keys */
+ val = unibi_lookup(info, "key_mouse");
+ if (val && !strcmp(val, "\x1b[M")) {
+ n = keynode(KeyMouse, 0, 0, 0);
+ insert(root, n, val);
+ }
+
+ return compress(root);
+}
+
+static
+enum KeyEvent
+peeksym(Input *in, Key *key, int force, ulong *nb)
+{
+ int res;
+ uchar *b, *o;
+ Node *root;
+ struct KeyNode *kn;
+
+ root = in->keys;
+ b = in->buf.b;
+ while (b <= in->buf.c) {
+ printf("checking '%s'\n", b);
+ root = nlookup(root, *b);
+ if (!root)
+ break;
+ b++;
+
+ if (root->type != NodeKey)
+ continue;
+
+ kn = (struct KeyNode*)root;
+ if (kn->key.type == KeyMouse) {
+ o = in->buf.b, in->buf.b = b;
+ res = peekmousekey(in, key, nb);
+ in->buf.b = o;
+
+ if (res == EvKey)
+ *nb += b - in->buf.b;
+
+ return res;
+ }
+ key->type = kn->key.type;
+ key->mods = kn->key.modset;
+ key->code.sym = kn->key.type;
+ *nb = b - in->buf.b;
+
+ return EvKey;
+ }
+
+ if (root && !force)
+ return EvAgain;
+
+ return EvNil;
+}
+
+// -----------------------------------------------------------------------
+// misc commands
+
+static
+inline
+void
+setpos(Key *key, int row, int col)
+{
+ row = MIN(row, 0xfff);
+ col = MIN(col, 0xfff);
+
+ key->code.mouse[1] = (row & 0x0ff);
+ key->code.mouse[2] = (col & 0x0ff);
+ key->code.mouse[3] = (row & 0xf00) >> 8 | (col & 0x300) >> 4;
+}
+
+static
+inline
+void
+getpos(Key *key, int *row, int *col)
+{
+ if(col)
+ *col = (uchar)key->code.mouse[1] | ((uchar)key->code.mouse[3] & 0x0f) << 8;
+
+ if(row)
+ *row = (uchar)key->code.mouse[2] | ((uchar)key->code.mouse[3] & 0x70) << 4;
+}
+
+// -----------------------------------------------------------------------
+// csi/ss3 commands
+
+static int csiinit;
+
+static struct KeyInfo ss3[64];
+static char ss3kpalts[64];
+
+static struct KeyInfo csiss3[64];
+static enum KeyEvent (*do_csi[64])(Input *in, Key *key, int cmd, int narg, long *arg);
+
+static struct KeyInfo csifuncs[35];
+
+/* csi/ss3 cmd keys */
+static
+enum KeyEvent
+do_csi_full(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ if(narg > 1 && arg[1] != -1)
+ key->mods = arg[1] - 1;
+ else
+ key->mods = 0;
+
+ key->type = csiss3[cmd - 0x40].type;
+ key->code.sym = csiss3[cmd - 0x40].sym;
+ key->mods &= ~(csiss3[cmd - 0x40].modmask);
+ key->mods |= csiss3[cmd - 0x40].modset;
+
+ if(key->code.sym == SymUnknown)
+ return EvNil;
+
+ return EvKey;
+}
+
+static
+void
+put_csi_full(int type, int sym, int modset, int modmask, uchar cmd)
+{
+ if(cmd < 0x40 || cmd >= 0x80)
+ return;
+
+ csiss3[cmd - 0x40].type = type;
+ csiss3[cmd - 0x40].sym = sym;
+ csiss3[cmd - 0x40].modset = modset;
+ csiss3[cmd - 0x40].modmask = modmask;
+
+ do_csi[cmd - 0x40] = &do_csi_full;
+}
+
+/* ss3 kpad keys */
+static
+void
+put_ss3_kpalt(int type, int sym, uchar cmd, char kpalt)
+{
+ if(cmd < 0x40 || cmd >= 0x80)
+ return;
+
+ ss3[cmd - 0x40].type = type;
+ ss3[cmd - 0x40].sym = sym;
+ ss3[cmd - 0x40].modset = 0;
+ ss3[cmd - 0x40].modmask= 0;
+ ss3kpalts[cmd - 0x40] = kpalt;
+}
+
+/* csi number ~func keys */
+static void emitcodepoint(Input *in, rune r, Key *key);
+
+static
+enum KeyEvent
+do_csi_func(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ if (narg > 1 && arg[1] != -1)
+ key->mods = arg[1] - 1;
+ else
+ key->mods = 0;
+
+ key->type = KeySym;
+
+ if (arg[0] == 27) {
+ int mod = key->mods;
+ emitcodepoint(in, (rune)arg[2], key);
+ key->mods |= mod;
+ } else if (arg[0] >= 0 && arg[0] < arrlen(csifuncs)) {
+ key->type = csifuncs[arg[0]].type;
+ key->code.sym = csifuncs[arg[0]].sym;
+ key->mods &= ~(csifuncs[arg[0]].modmask);
+ key->mods |= csifuncs[arg[0]].modset;
+ } else
+ key->code.sym = SymUnknown;
+
+ if (key->code.sym == SymUnknown)
+ return EvNil;
+
+ return EvKey;
+}
+
+static
+void
+put_csi_func(int type, int sym, int num)
+{
+ if(num >= arrlen(csifuncs))
+ return;
+
+ csifuncs[num].type = type;
+ csifuncs[num].sym = sym;
+ csifuncs[num].modset = 0;
+ csifuncs[num].modmask = 0;
+
+ do_csi['~' - 0x40] = &do_csi_func;
+}
+
+/* CSI u extended unicode keys */
+static
+enum KeyEvent
+do_csi_u(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ switch(cmd) {
+ case 'u': {
+ if(narg > 1 && arg[1] != -1)
+ key->mods = arg[1] - 1;
+ else
+ key->mods = 0;
+
+ int mod = key->mods;
+ key->type = KeySym;
+ emitcodepoint(in, arg[0], key);
+ key->mods |= mod;
+
+ return EvKey;
+ }
+ default:
+ return EvNil;
+ }
+}
+
+/* csi m/M mouse events */
+
+static
+enum KeyEvent
+do_csi_m(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ int initial = cmd >> 8;
+ cmd &= 0xff;
+
+ switch(cmd) {
+ case 'M':
+ case 'm':
+ break;
+ default:
+ return EvNil;
+ }
+
+ // rxvt protocol
+ if(!initial && narg >= 3) {
+ key->type = KeyMouse;
+ key->code.mouse[0] = arg[0];
+
+ key->mods = (key->code.mouse[0] & 0x1c) >> 2;
+ key->code.mouse[0] &= ~0x1c;
+
+ setpos(key, arg[1], arg[2]);
+
+ return EvKey;
+ }
+
+ if(initial == '<' && narg >= 3) { // SGR protocol
+ key->type = KeyMouse;
+ key->code.mouse[0] = arg[0];
+
+ key->mods = (key->code.mouse[0] & 0x1c) >> 2;
+ key->code.mouse[0] &= ~0x1c;
+
+ setpos(key, arg[1], arg[2]);
+
+ if(cmd == 'm') // release
+ key->code.mouse[3] |= 0x80;
+
+ return EvKey;
+ }
+
+ return EvNil;
+}
+
+/* csi ? R position events */
+
+static
+enum KeyEvent
+do_csi_R(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ switch(cmd) {
+ case 'R'|'?'<<8:
+ if(narg < 2)
+ return EvNil;
+ key->type = KeyPosition;
+ setpos(key, arg[1], arg[0]);
+ return EvKey;
+ default:
+ return do_csi_full(in, key, cmd, narg, arg);
+ }
+}
+
+/* csi $y mode status events */
+
+static
+enum KeyEvent
+do_csi_y(Input *in, Key *key, int cmd, int narg, long *arg)
+{
+ switch (cmd) {
+ case 'y'|'$'<<16:
+ case 'y'|'$'<<16 | '?'<<8:
+ if (narg < 2)
+ return EvNil;
+
+ key->type = KeyModeReport;
+ key->code.mouse[0] = (cmd >> 8);
+ key->code.mouse[1] = arg[0] >> 8;
+ key->code.mouse[2] = arg[0] & 0xff;
+ key->code.mouse[3] = arg[1];
+ return EvKey;
+
+ default:
+ return EvNil;
+ }
+}
+
+/* parse csi events */
+static
+enum KeyEvent
+parse_csi(Input *in, ulong introlen, ulong *csi_len, ulong *nargs, long args[], unsigned long *commandp)
+{
+ ulong csi_end = introlen;
+
+ while (csi_end < bufcount(in)) {
+ if (in->buf.b[csi_end] >= 0x40 && in->buf.b[csi_end] < 0x80)
+ break;
+ csi_end++;
+ }
+
+ if(csi_end >= bufcount(in))
+ return EvAgain;
+
+ uchar cmd = in->buf.b[csi_end];
+ *commandp = cmd;
+
+ char present = 0;
+ int argi = 0;
+
+ ulong p = introlen;
+
+ // See if there is an initial byte
+ if (in->buf.b[p] >= '<' && in->buf.b[p] <= '?') {
+ *commandp |= (in->buf.b[p] << 8);
+ p++;
+ }
+
+ // Now attempt to parse out up number;number;... separated values
+ while (p < csi_end) {
+ uchar c = in->buf.b[p];
+
+ if (c >= '0' && c <= '9') {
+ if (!present) {
+ args[argi] = c - '0';
+ present = 1;
+ } else {
+ args[argi] = (args[argi] * 10) + c - '0';
+ }
+ } else if(c == ';') {
+ if (!present)
+ args[argi] = -1;
+ present = 0;
+ argi++;
+
+ if(argi > 16)
+ break;
+ } else if (c >= 0x20 && c <= 0x2f) {
+ *commandp |= c << 16;
+ break;
+ }
+ p++;
+ }
+
+ if(present)
+ argi++;
+
+ *nargs = argi;
+ *csi_len = csi_end + 1;
+
+ return EvKey;
+}
+
+static
+void
+loadctrlkeys(void)
+{
+ int i;
+ for(i = 0; i < 64; i++) {
+ csiss3[i].sym = SymUnknown;
+ ss3[i].sym = SymUnknown;
+ ss3kpalts[i] = 0;
+ }
+
+ for(i = 0; i < arrlen(csifuncs); i++)
+ csifuncs[i].sym = SymUnknown;
+
+ put_csi_full(KeySym, SymUp, 0, 0, 'A');
+ put_csi_full(KeySym, SymDown, 0, 0, 'B');
+ put_csi_full(KeySym, SymRight,0, 0, 'C');
+ put_csi_full(KeySym, SymLeft, 0, 0, 'D');
+ put_csi_full(KeySym, SymBegin,0, 0, 'E');
+ put_csi_full(KeySym, SymEnd, 0, 0, 'F');
+ put_csi_full(KeySym, SymHome, 0, 0, 'H');
+ put_csi_full(KeySym, 1, 0, 0, 'P');
+ put_csi_full(KeySym, 2, 0, 0, 'Q');
+ put_csi_full(KeySym, 3, 0, 0, 'R');
+ put_csi_full(KeySym, 4, 0, 0, 'S');
+
+ put_csi_full(KeySym, SymTab, ModShift, ModShift, 'Z');
+
+ put_ss3_kpalt(KeySym, SymKpenter, 'M', 0);
+ put_ss3_kpalt(KeySym, SymKpequals, 'X', '=');
+ put_ss3_kpalt(KeySym, SymKpmult, 'j', '*');
+ put_ss3_kpalt(KeySym, SymKpplus, 'k', '+');
+ put_ss3_kpalt(KeySym, SymKpcomma, 'l', ',');
+ put_ss3_kpalt(KeySym, SymKpminus, 'm', '-');
+ put_ss3_kpalt(KeySym, SymKpperiod, 'n', '.');
+ put_ss3_kpalt(KeySym, SymKpdiv, 'o', '/');
+ put_ss3_kpalt(KeySym, SymKp0, 'p', '0');
+ put_ss3_kpalt(KeySym, SymKp1, 'q', '1');
+ put_ss3_kpalt(KeySym, SymKp2, 'r', '2');
+ put_ss3_kpalt(KeySym, SymKp3, 's', '3');
+ put_ss3_kpalt(KeySym, SymKp4, 't', '4');
+ put_ss3_kpalt(KeySym, SymKp5, 'u', '5');
+ put_ss3_kpalt(KeySym, SymKp6, 'v', '6');
+ put_ss3_kpalt(KeySym, SymKp7, 'w', '7');
+ put_ss3_kpalt(KeySym, SymKp8, 'x', '8');
+ put_ss3_kpalt(KeySym, SymKp9, 'y', '9');
+
+ put_csi_func(KeySym, SymFind, 1);
+ put_csi_func(KeySym, SymInsert, 2);
+ put_csi_func(KeySym, SymDelete, 3);
+ put_csi_func(KeySym, SymSelect, 4);
+ put_csi_func(KeySym, SymPageup, 5);
+ put_csi_func(KeySym, SymPagedown, 6);
+ put_csi_func(KeySym, SymHome, 7);
+ put_csi_func(KeySym, SymEnd, 8);
+
+ put_csi_func(KeyFunc, 1, 11);
+ put_csi_func(KeyFunc, 2, 12);
+ put_csi_func(KeyFunc, 3, 13);
+ put_csi_func(KeyFunc, 4, 14);
+ put_csi_func(KeyFunc, 5, 15);
+ put_csi_func(KeyFunc, 6, 17);
+ put_csi_func(KeyFunc, 7, 18);
+ put_csi_func(KeyFunc, 8, 19);
+ put_csi_func(KeyFunc, 9, 20);
+ put_csi_func(KeyFunc, 10, 21);
+ put_csi_func(KeyFunc, 11, 23);
+ put_csi_func(KeyFunc, 12, 24);
+ put_csi_func(KeyFunc, 13, 25);
+ put_csi_func(KeyFunc, 14, 26);
+ put_csi_func(KeyFunc, 15, 28);
+ put_csi_func(KeyFunc, 16, 29);
+ put_csi_func(KeyFunc, 17, 31);
+ put_csi_func(KeyFunc, 18, 32);
+ put_csi_func(KeyFunc, 19, 33);
+ put_csi_func(KeyFunc, 20, 34);
+
+ do_csi['u' - 0x40] = &do_csi_u;
+ do_csi['M' - 0x40] = &do_csi_m;
+ do_csi['m' - 0x40] = &do_csi_m;
+ do_csi['R' - 0x40] = &do_csi_R;
+ do_csi['y' - 0x40] = &do_csi_y;
+
+ csiinit = 1;
+}
+
+static
+enum KeyEvent
+peekcsi(Input *in, ulong introlen, Key *key, int force, ulong *nb)
+{
+ ulong csi_len;
+ long arg[16];
+ ulong nargs = arrlen(arg);
+ ulong cmd;
+
+ enum KeyEvent ev = parse_csi(in, introlen, &csi_len, &nargs, arg, &cmd);
+
+ if (ev== EvAgain) {
+ if(!force)
+ return ev;
+
+ emitcodepoint(in, '[', key);
+ key->mods |= ModAlt;
+ *nb = introlen;
+ return EvKey;
+ }
+ // Mouse in X10 encoding consumes the next 3 bytes also
+ if (cmd == 'M' && nargs < 3) {
+ in->buf.b += csi_len;
+ ev = peekmousekey(in, key, nb);
+ in->buf.b -= csi_len;
+
+ if (ev == EvKey)
+ *nb += csi_len;
+
+ return ev;
+ }
+
+ ev = EvNil;
+
+ // We know from the logic above that cmd must be >= 0x40 and < 0x80
+ if (do_csi[(cmd & 0xff) - 0x40])
+ ev = (*do_csi[(cmd & 0xff) - 0x40])(in, key, cmd, nargs, arg);
+
+ if (ev == EvNil) {
+ key->type = KeyUnknownCSI;
+ key->code.num = cmd;
+ key->mods = 0;
+
+ in->buf.off = csi_len - introlen;
+ *nb = introlen; /* dont advance yet */
+ return EvKey;
+ }
+
+ *nb = csi_len;
+ return ev;
+}
+
+static
+enum KeyEvent
+peekss3(Input *in, ulong introlen, Key *key, int force, ulong *nb)
+{
+ if(bufcount(in) < introlen + 1) {
+ if(!force)
+ return EvAgain;
+
+ emitcodepoint(in, 'O', key);
+ key->mods |= ModAlt;
+ *nb= bufcount(in);
+ return EvKey;
+ }
+ uchar cmd = in->buf.b[introlen];
+
+ if(cmd < 0x40 || cmd >= 0x80)
+ return EvNil;
+
+ key->type = csiss3[cmd - 0x40].type;
+ key->code.sym = csiss3[cmd - 0x40].sym;
+ key->mods = csiss3[cmd - 0x40].modset;
+
+ if (key->code.sym == SymUnknown) {
+ if (in->flags & FlagConvertKP && ss3kpalts[cmd - 0x40]) {
+ key->type = KeyUnicode;
+ key->code.pt = ss3kpalts[cmd - 0x40];
+ key->mods = 0;
+
+ key->utf8[0] = key->code.pt;
+ key->utf8[1] = 0;
+ } else {
+ key->type = ss3[cmd - 0x40].type;
+ key->code.sym = ss3[cmd - 0x40].sym;
+ key->mods = ss3[cmd - 0x40].modset;
+ }
+ }
+
+ if(key->code.sym == SymUnknown)
+ return EvNil;
+
+ *nb = introlen + 1;
+
+ return EvKey;
+}
+
+static
+enum KeyEvent
+peekctrl(Input *in, ulong introlen, Key *key, int force, ulong *nb)
+{
+ ulong str_end = introlen;
+
+ while(str_end < bufcount(in)) {
+ if (in->buf.b[str_end] == 0x9c) // ST
+ break;
+ if (in->buf.b[str_end] == 0x1b &&
+ (str_end + 1) < bufcount(in) &&
+ in->buf.b[str_end+1] == 0x5c) // ESC-prefixed ST
+ break;
+
+ str_end++;
+ }
+
+ if (str_end >= bufcount(in))
+ return EvAgain;
+
+ *nb = str_end + 1;
+ if(in->buf.b[str_end] == 0x1b)
+ (*nb)++;
+
+ // XXX: read carefully
+ if(in->savedcsi)
+ free(in->savedcsi);
+
+ ulong len = str_end - introlen;
+
+ in->nsavedcsi++;
+ in->savedcsi = malloc(len + 1);
+
+ strncpy(in->savedcsi, (char *)in->buf.b + introlen, len);
+ in->savedcsi[len] = 0;
+
+ key->type = (in->buf.b[introlen-1] & 0x1f) == 0x10 ? KeyDCS : KeyOSC;
+ key->code.num = in->nsavedcsi;
+ key->mods = 0;
+
+ return EvKey;
+}
+
+static
+enum KeyEvent
+peekesc(Input *in, Key *key, int force, ulong *nb)
+{
+ if (bufcount(in) == 0)
+ return in->closed ? EvEOF : EvNil;
+
+ switch (*in->buf.b) {
+ case 0x1b:
+ if(bufcount(in) < 2)
+ return EvNil;
+
+ switch(in->buf.b[1]) {
+ case 0x4f: // ESC-prefixed SS3
+ return peekss3(in, 2, key, force, nb);
+
+ case 0x50: // ESC-prefixed DCS
+ case 0x5d: // ESC-prefixed OSC
+ return peekctrl(in, 2, key, force, nb);
+
+ case 0x5b: // ESC-prefixed CSI
+ return peekcsi(in, 2, key, force, nb);
+ }
+
+ return EvNil;
+
+ case 0x8f: // SS3
+ return peekss3(in, 1, key, force, nb);
+
+ case 0x90: // DCS
+ case 0x9d: // OSC
+ return peekctrl(in, 1, key, force, nb);
+
+ case 0x9b: // CSI
+ return peekcsi(in, 1, key, force, nb);
+ }
+
+ return EvNil;
+}
+
+
+// -----------------------------------------------------------------------
+// internal functions
+
+static
+int
+registername(Input *in, int sym, char *name)
+{
+ if (!sym)
+ sym = in->nkeynm;
+
+ if(sym >= in->nkeynm) {
+ char **tmp = realloc(in->keynm, sizeof(*tmp) * (sym + 1));
+ if(!tmp)
+ return -1;
+
+ in->keynm = tmp;
+
+ // Fill in the hole
+ for(int i = in->nkeynm; i < sym; i++)
+ in->keynm[i] = nil;
+
+ in->nkeynm = sym + 1;
+ }
+
+ in->keynm[sym] = name;
+
+ return sym;
+}
+
+static
+int
+registerc0(Input *in, int sym, int modset, int modmask, uchar ctrl, char *name)
+{
+ if(ctrl >= 0x20) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (name)
+ sym = registername(in, sym, name);
+
+ in->c0[ctrl].sym = sym;
+ in->c0[ctrl].modset = modset;
+ in->c0[ctrl].modmask = modmask;
+
+ return sym;
+}
+
+static
+void
+advance(Input *in, ulong nb)
+{
+ if (in->buf.c < in->buf.b + nb) {
+ in->buf.b = in->buf.c;
+ return;
+ }
+
+ in->buf.b += nb;
+}
+
+static
+void
+slidebuffer(Input *in)
+{
+ static const ulong halfway = arrlen(in->buf.bytes) / 2;
+ if (in->buf.b - in->buf.bytes > halfway) {
+ memmove(in->buf.bytes, in->buf.bytes + halfway, halfway);
+ in->buf.b -= halfway;
+ in->buf.c -= halfway;
+ }
+}
+
+static
+void
+harmonize(Input *in, Key *key)
+{
+ int flags = in->hflag;
+
+ if (flags & HarmonizeSpace) {
+ if (key->type == KeyUnicode && key->code.pt == 0x20) {
+ key->type = KeySym;
+ key->code.sym = SymSpace;
+ }
+ } else {
+ if (key->type == KeySym && key->code.sym == SymSpace) {
+ key->type = KeyUnicode;
+ key->code.pt = 0x20;
+ utf8·runetobyte((char*)key->utf8, &key->code.pt);
+ }
+ }
+
+ if (flags & HarmonizeDelBS) {
+ if (key->type == KeySym && key->code.sym == SymDel) {
+ key->code.sym = SymBackspace;
+ }
+ }
+}
+
+static
+void
+emitcodepoint(Input *in, rune r, Key *key)
+{
+ if (r == 0) {
+ key->type = KeySym;
+ key->code.sym = SymSpace;
+ key->mods = ModCtrl;
+ goto harmonize;
+ }
+ if (r < 0x20) {
+ key->code.pt = 0;
+ key->mods = 0;
+ if (!(in->flags & FlagNoInterpret) && in->c0[r].sym != SymUnknown) {
+ key->code.sym = in->c0[r].sym;
+ key->mods |= in->c0[r].modset;
+ }
+ if (!key->code.sym) {
+ key->type = KeyUnicode;
+ if (r+0x40 >= 'A' && r+0x40 <= 'Z')
+ // it's a letter - use lowercase instead
+ key->code.pt = r + 0x60;
+ else
+ key->code.pt = r + 0x40;
+ key->mods = ModCtrl;
+ } else
+ key->type = KeySym;
+ goto harmonize;
+ }
+ if (r == 0x7f && !(in->flags & FlagNoInterpret)) {
+ // ascii del
+ key->type = KeySym;
+ key->code.sym = SymDel;
+ key->mods = 0;
+ goto harmonize;
+ }
+ if (r >= 0x20 && r < 0x80) {
+ // ascii lowbyte range
+ key->type = KeyUnicode;
+ key->code.pt = r;
+ key->mods = 0;
+ goto harmonize;
+ }
+ if (r >= 0x80 && r < 0xa0) {
+ // UTF-8 never starts with a C1 byte. So we can be sure of these
+ key->type = KeyUnicode;
+ key->code.pt = r - 0x40;
+ key->mods = ModCtrl|ModAlt;
+ goto harmonize;
+ }
+ key->type = KeyUnicode;
+ key->code.pt = r;
+ key->mods = 0;
+
+harmonize:
+ harmonize(in, key);
+ utf8·runetobyte((char*)key->utf8, &key->code.pt);
+}
+
+static
+enum KeyEvent
+peekmousekey(Input *in, Key *key, ulong *nb)
+{
+ if (in->buf.c - in->buf.b < 3)
+ return EvAgain;
+
+ key->type = KeyMouse;
+ key->code.mouse[0] = in->buf.c[0] - 0x20;
+ key->code.mouse[1] = in->buf.c[1] - 0x20;
+ key->code.mouse[2] = in->buf.c[2] - 0x20;
+ key->code.mouse[3] = 0;
+
+ key->mods = (key->code.mouse[0] & 0x1c) >> 2;
+ key->code.mouse[0] &= ~0x1c;
+
+ *nb = 3;
+ return EvKey;
+}
+
+enum KeyEvent peekkey(Input *in, Key *key, int force, ulong *nb);
+
+static
+enum KeyEvent
+peeksimplekey(Input *in, Key *key, int force, ulong *nb)
+{
+ uchar c, *b;
+ int n;
+ rune r;
+ enum KeyEvent ev;
+
+ b = in->buf.b;
+ c = *b;
+
+ if (c == 0x1b) {
+ if (bufcount(in) == 1) {
+ if (!force)
+ return EvAgain;
+ goto ascii;
+ }
+ in->buf.b++;
+ ev = peekkey(in, key, force, nb);
+ in->buf.b--;
+
+ switch (ev) {
+ case EvKey:
+ key->mods |= ModAlt;
+ (*nb)++;
+ /* fallthrough */
+ case EvNil: case EvEOF:
+ case EvAgain: case EvErr:
+ return ev;
+ }
+ }
+ if (c == 0xa0)
+ goto ascii;
+ if (in->flags & FlagUTF8) {
+ n = utf8·bytetorune(&r, (char*)in->buf.b);
+ *nb = n; /* store the number of bytes */
+ if (n > bufcount(in)) {
+ if (!force)
+ return EvAgain;
+ r = RuneErr;
+ *nb = bufcount(in);
+ }
+ key->type = KeyUnicode;
+ key->mods = 0;
+ goto utf8;
+ }
+ /* if we are here just emit raw byte */
+ key->type = KeyUnicode;
+ key->code.pt = c;
+ key->mods = 0;
+ key->utf8[0] = c;
+ key->utf8[1] = 0;
+ *nb = 1;
+ return EvKey;
+
+ascii:
+ *nb = 1;
+ r = c;
+utf8:
+ emitcodepoint(in, r, key);
+ return EvKey;
+}
+
+// -----------------------------------------------------------------------
+// exported functions
+
+Input *
+makeinput(int fd, int flags, unibi_term *info)
+{
+ int i;
+ Input *in;
+ char *e;
+
+ if (!(in = malloc(sizeof(in))))
+ panicf("out of memory");
+
+ in->fd = fd;
+ if (!(flags & (FlagRaw|FlagUTF8))) {
+ if (((e = getenv("LANG")) || (e = getenv("LC_MESSAGES")) || (e = getenv("LC_ALL"))) &&
+ (e = strchr(e, '.')) && e++ && (!stricmp(e, "UTF-8") || !stricmp(e, "UTF8")))
+ flags |= FlagUTF8;
+ else
+ flags |= FlagRaw;
+ }
+ in->flags = flags;
+ in->wait = 50; /* in msec */
+ in->closed = 0;
+ in->started = 0;
+ in->hasold = 0;
+ in->keys = loadtermkeys(info);
+
+ /* initialize buffer */
+ in->buf.c = in->buf.b = in->buf.bytes;
+ in->buf.e = arrend(in->buf.bytes);
+ in->buf.off = 0;
+ memset(in->buf.bytes, 0, arrlen(in->buf.bytes));
+
+ /* initialize names */
+ for (i = 0; i < 32; i++)
+ in->c0[i].sym = SymNone;
+
+ registerc0(in, SymTab, 0x09, 0, 0, nil);
+ registerc0(in, SymEnter, 0x0d, 0, 0, nil);
+ registerc0(in, SymEscape, 0x1b, 0, 0, nil);
+
+ /* load in csi */
+ in->nsavedcsi = 0;
+ in->savedcsi = nil;
+ loadctrlkeys();
+
+ return in;
+}
+
+void
+freeinput(Input *in)
+{
+ // free(in);
+}
+
+int
+startrecord(Input *in)
+{
+ struct termios new;
+ if (in->started)
+ return 1;
+
+ if (in->fd != -1 && !(in->flags & FlagNoTermIOS)) {
+ if (tcgetattr(in->fd, &new) == 0) {
+ in->oldterm = new;
+ in->hasold = 1;
+
+ new.c_iflag &= ~(IXON|INLCR|ICRNL);
+ new.c_lflag &= ~(ICANON|ECHO|IEXTEN);
+
+ new.c_cc[VMIN] = 1;
+ new.c_cc[VTIME] = 0;
+
+ if (in->flags & FlagCtrlC)
+ new.c_lflag &= ~ISIG;
+ else {
+ /* Disable Ctrl-\==VQUIT and Ctrl-D==VSUSP but leave Ctrl-C as SIGINT */
+ new.c_cc[VQUIT] = _POSIX_VDISABLE;
+ new.c_cc[VSUSP] = _POSIX_VDISABLE;
+ /* Some OSes have Ctrl-Y==VDSUSP */
+# ifdef VDSUSP
+ new.c_cc[VDSUSP] = _POSIX_VDISABLE;
+# endif
+ }
+ tcsetattr(in->fd, TCSANOW, &new);
+ }
+ }
+
+ in->started = 1;
+ return 1;
+}
+
+int
+stoprecord(Input *in)
+{
+ if (!in->started)
+ return 1;
+
+ if (in->hasold)
+ tcsetattr(in->fd, TCSANOW, &in->oldterm);
+
+ in->started = 0;
+ return 1;
+}
+
+enum KeyEvent
+peekkey(Input *in, Key *key, int force, ulong *nb)
+{
+ int i, again = 0;
+ enum KeyEvent ev;
+ static enum KeyEvent (*peek[2])(Input *, Key *, int, ulong *) = { peeksym, peekesc };
+
+ if (!in->started) {
+ errno = EINVAL;
+ return EvErr;
+ }
+
+ if (in->buf.off) {
+ in->buf.b += in->buf.off;
+ in->buf.off = 0;
+ }
+
+ for (i = 0; i < arrlen(peek); i++) {
+ ev = peek[i](in, key, force, nb);
+ switch (ev) {
+ case EvKey:
+ slidebuffer(in);
+ /* fallthrough */
+ case EvEOF:
+ case EvErr:
+ return ev;
+ case EvAgain:
+ if (!force)
+ again = 1;
+ /* fallthrough */
+ case EvNil:
+ break;
+ }
+ }
+ if (again)
+ return EvAgain;
+
+ return peeksimplekey(in, key, force, nb);
+}
+
+enum KeyEvent
+getkey(Input *in, Key *key)
+{
+ ulong nb;
+ enum KeyEvent ev;
+
+ ev = peekkey(in, key, 0, &nb);
+ switch (ev) {
+ case EvKey:
+ advance(in, nb);
+ break;
+ case EvAgain:
+ peekkey(in, key, 1, &nb);
+ /* get nb but don't advance */
+ break;
+ default:
+ ;
+ }
+ return ev;
+}
+
+enum KeyEvent
+demandkey(Input *in, Key *key)
+{
+ ulong nb;
+ enum KeyEvent ev;
+
+ ev = peekkey(in, key, 1, &nb);
+ if (ev == EvKey)
+ advance(in, nb);
+
+ return ev;
+}
+
+enum KeyEvent
+readkey(Input *in)
+{
+ int n;
+ if (in->fd == -1) {
+ errno = EBADF;
+ return EvErr;
+ }
+
+ /* reset to beginning of buffer */
+ if (in->buf.b > in->buf.bytes) {
+ n = in->buf.b - in->buf.bytes;
+ memmove(in->buf.bytes, in->buf.b, n);
+ in->buf.b = in->buf.bytes;
+ in->buf.c = in->buf.b + n;
+ }
+
+read:
+ n = read(in->fd, in->buf.c, in->buf.e-in->buf.c);
+ if (n == -1) {
+ if (errno == EAGAIN)
+ return EvNil;
+ if (errno == EINTR && !(in->flags & FlagEintr))
+ goto read;
+ else
+ return EvErr;
+ }
+ if (n < 1) {
+ in->closed = 1;
+ return EvNil;
+ }
+ in->buf.c += n;
+ return EvAgain;
+}
+
+enum KeyEvent
+waitkey(Input *in, Key *key)
+{
+ enum KeyEvent ev;
+ struct pollfd p;
+
+ if (in->fd == -1) {
+ errno = EBADF;
+ return EvErr;
+ }
+
+ for (;;) {
+ ev = getkey(in, key);
+ switch (ev) {
+ case EvKey: case EvEOF: case EvErr:
+ return ev;
+ case EvNil:
+ ev = readkey(in);
+ if (ev == EvErr)
+ return ev;
+ break;
+
+ case EvAgain:
+ /* can't wait any longer */
+ if (in->closed)
+ return demandkey(in, key);
+ poll:
+ p.fd = in->fd;
+ p.events = POLLIN;
+
+ if (poll(&p, 1, in->wait) == -1) {
+ if (errno == EINTR && !(in->flags & FlagEintr))
+ goto poll;
+ return EvErr;
+ }
+
+ if (p.revents & (POLLIN|POLLHUP|POLLERR))
+ ev = readkey(in);
+ else
+ ev = EvNil;
+
+ if (ev == EvErr)
+ return ev;
+ if (ev == EvNil)
+ return demandkey(in, key);
+ break;
+ }
+ }
+ /* unreachable */
+}
+
+enum KeyEvent
+decodemouse(Input *in, Key *key, enum MouseEvent *ev, int *button, int *row, int *col)
+{
+ if (key->type != KeyMouse)
+ return EvNil;
+
+ if (button)
+ *button = 0;
+
+ getpos(key, row, col);
+
+ if(!ev)
+ return EvKey;
+
+ int btn = 0;
+ int code = key->code.mouse[0];
+ int drag = code & 0x20;
+ code &= ~0x3c;
+
+ switch(code) {
+ case 0:
+ case 1:
+ case 2:
+ *ev = drag ? MouseDrag : MousePress;
+ btn = code + 1;
+ break;
+
+ case 3:
+ *ev = MouseRelease;
+ // no button hint
+ break;
+
+ case 64:
+ case 65:
+ *ev = drag ? MouseDrag : MousePress;
+ btn = code + 4 - 64;
+ break;
+
+ default:
+ *ev = MouseNil;
+ }
+
+ if (button)
+ *button = btn;
+
+ if (key->code.mouse[3] & 0x80)
+ *ev = MouseRelease;
+
+ return EvKey;
+}
+
+enum KeyEvent
+decodepos(Input *in, Key *key, int *row, int *col)
+{
+ if (key->type != KeyPosition)
+ return EvNil;
+
+ getpos(key, row, col);
+
+ return EvKey;
+}
+
+enum KeyEvent
+decodemode(Input *in, Key *key, int *init, int *mode, int *val)
+{
+ if (key->type != KeyModeReport)
+ return EvNil;
+
+ if (init)
+ *init = key->code.mouse[0];
+
+ if (mode)
+ *mode = (key->code.mouse[1] << 8) | key->code.mouse[2];
+
+ if (val)
+ *val = key->code.mouse[3];
+
+ return EvKey;
+}
+
+char *
+keyname(Input *in, int sym)
+{
+ if (sym == SymUnknown || sym >= in->nkeynm)
+ return "<unknown>";
+
+ return in->keynm[sym];
+}
+
+// -----------------------------------------------------------------------
+// main point of entry
+
+static
+void
+printkey(Input *in, Key *key)
+{
+ enum MouseEvent ev;
+ int button, line, col;
+ int init, mode, val;
+
+ switch(key->type) {
+ case KeyUnicode:
+ fprintf(stderr, "Unicode codepoint=U+%04dx utf8='%s'", key->code.pt, key->utf8);
+ break;
+ case KeyFunc:
+ fprintf(stderr, "Function F%d", key->code.num);
+ break;
+ case KeySym:
+ fprintf(stderr, "Keysym sym=%d(%s)", key->code.sym, keyname(in, key->code.sym));
+ break;
+ case KeyMouse:
+ decodemouse(in, key, &ev, &button, &line, &col);
+ fprintf(stderr, "Mouse ev=%d button=%d pos=(%d,%d)\n", ev, button, line, col);
+ break;
+ case KeyPosition:
+ decodepos(in, key, &line, &col);
+ fprintf(stderr, "Position report pos=(%d,%d)\n", line, col);
+ break;
+ case KeyModeReport:
+ decodemode(in, key, &init, &mode, &val);
+ fprintf(stderr, "Mode report mode=%s %d val=%d\n", init == '?' ? "DEC" : "ANSI", mode, val);
+ break;
+ case KeyDCS:
+ fprintf(stderr, "Device Control String");
+ break;
+ case KeyOSC:
+ fprintf(stderr, "Operating System Control");
+ break;
+ case KeyUnknownCSI:
+ fprintf(stderr, "unknown CSI\n");
+ break;
+ }
+
+ mode = key->mods;
+ fprintf(stderr, " mod=%s%s%s+%02x",
+ (mode & ModCtrl ? "<C>" : ""),
+ (mode & ModAlt ? "<A>" : ""),
+ (mode & ModShift? "<S>" : ""),
+ mode & ~(ModCtrl|ModAlt|ModShift));
+}
+
+int
+main()
+{
+ char *name;
+ Input *in;
+ unibi_term *info;
+ Key key;
+ enum KeyEvent ev;
+
+ name = getenv("TERM");
+ info = unibi_from_term(name);
+ in = makeinput(0, FlagSpaceSymbol, info);
+
+ int n = 0; /* for debugging purposes only */
+ startrecord(in);
+ while ((ev = waitkey(in, &key)) != EvEOF) {
+ switch (ev) {
+ case EvKey:
+ printkey(in, &key);
+ printf("\n");
+ break;
+ case EvNil:
+ printf("<nil>\n");
+ case EvAgain:
+ printf("<again>\n");
+ default:
+ ;
+ }
+ n++;
+ if (n > 200)
+ break;
+ }
+ stoprecord(in);
+ freeinput(in);
+}
diff --git a/sys/cmd/dvtm/rules.mk b/sys/cmd/dvtm/rules.mk
index 6adfd3c..3ef4225 100644
--- a/sys/cmd/dvtm/rules.mk
+++ b/sys/cmd/dvtm/rules.mk
@@ -2,9 +2,11 @@ include share/push.mk
# Local sources
SRCS_$(d) := \
-$(d)/hook.c \
-$(d)/vt.c \
-$(d)/dvtm.c
+$(d)/events.c \
+# $(d)/driver.c \
+# $(d)/hook.c \
+# $(d)/vt.c \
+# $(d)/dvtm.c
# needed for additional editor target
AUX := $(d)/dvtm-editor.o
@@ -21,7 +23,7 @@ BINS_$(d) := $(DVTM) $(DVTM-ED)
include share/paths.mk
$(DVTM): TCFLAGS = -D_XOPEN_SOURCE=700 -D_XOPEN_SOURCE_EXTENDED -DNDEBUG
-$(DVTM): TCLIBS = -lncursesw -lutil -lc
+$(DVTM): TCLIBS = -lunibilium $(OBJ_DIR)/libn/libn.a
$(DVTM): $(OBJS_$(d))
$(COMPLINK)
diff --git a/sys/cmd/dvtm/term.c b/sys/cmd/dvtm/term.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sys/cmd/dvtm/term.c
diff --git a/sys/cmd/dvtm/term.h b/sys/cmd/dvtm/term.h
new file mode 100644
index 0000000..3102458
--- /dev/null
+++ b/sys/cmd/dvtm/term.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <u.h>
+#include <libn.h>
+
+#define iota(x) 1 << (x)
+
+typedef struct RGB8 RGB8;
+typedef struct Pen Pen;
+typedef struct Cell Cell;
+typedef struct Row Row;
+typedef struct Buffer Buffer;
+
+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),
+ /* ... */
+ PenTC = iota(15),
+};
+
+struct Pen
+{
+ ushort state;
+ ushort color;
+ union {
+ /* 256 color (legacy) */
+ struct {
+ sshort fg : 8, bg : 8; /* 0 - 255 or COLOUR_DEFAULT */
+ } col;
+ /* true color (modern) */
+ struct {
+ RGB8 fg, bg;
+ } rgb;
+ };
+};
+
+struct Cell {
+ rune r;
+ Pen pen;
+};
+
+struct Row {
+ Cell *cells;
+ uint dirty:1;
+};
+
+/* Buffer holding the current 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
+ * roll_buf + scroll.size->+----------------+-----+
+ * <- maxcols ->
+ * <- cols ->
+ */
+
+struct Buffer {
+ Row *lines; /* array of Row pointers of size 'rows' */
+ Row *crow; /* row on which the cursor currently resides */
+ bool *tabs; /* a boolean flag for each column whether it is a tab */
+ struct {
+ Row *buf; /* a ring buffer holding the scroll back content */
+ Row *top; /* row in lines where scrolling region starts */
+ Row *bot; /* row in lines where scrolling region ends */
+ int size; /* maximal capacity of scroll back buffer (in lines) */
+ int index; /* current index into the ring buffer */
+ int above; /* number of lines above current viewport */
+ int below; /* number of lines below current viewport */
+ } scroll;
+ int rows, cols; /* current dimension of buffer */
+ int maxcols; /* allocated cells (maximal cols over time) */
+};
+
+/* exported functions */
+
+void zero(Row *row, int start, int len);
+void roll(Row *start, Row *end, int count);
+
+void bclear(Buffer *b);
+void bfree(Buffer *b);
+void bscroll(Buffer *b, int s);
+void bresize(Buffer *b, int rows, int cols);
+bool binit(Buffer *b, int rows, int cols, int size);
+void bboundary(Buffer *b, Row **bs, Row **be, Row **as, Row **ae) ;
+Row *browfirst(Buffer *b);
+Row *browlast(Buffer *b);
+Row *brownext(Buffer *b, Row *row);
+Row *bprevrow(Buffer *b, Row *row);
diff --git a/sys/cmd/dvtm/vt.c b/sys/cmd/dvtm/vt.c
index c48a84f..efaa980 100644
--- a/sys/cmd/dvtm/vt.c
+++ b/sys/cmd/dvtm/vt.c
@@ -1,23 +1,15 @@
/* See license for details */
#include <u.h>
+#include <libn.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
#include <langinfo.h>
-#include <limits.h>
#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
+#include <termios.h>
+
#include <sys/ioctl.h>
#include <sys/types.h>
-#include <termios.h>
-#include <wchar.h>
+
+#include "buffer.h"
#if defined(__linux__) || defined(__CYGWIN__)
# include <pty.h>
@@ -27,602 +19,122 @@
# 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)
-static bool is_utf8, has_default_colors;
-static short 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;
- short fg;
- short bg;
-} 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
- * roll_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;
+typedef struct Vt Vt;
struct 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 */
- short 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 */
+ 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 */
/* flags */
- 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;
+ 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;
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 */
- 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 */
-};
-
-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
+ int srow, scol; /* last known offset to display start row, start column */
};
-static void puttab(Vt *t, int count);
-static void process_nonprinting(Vt *t, wchar_t wc);
-static void send_curs(Vt *t);
-
-const static
-attr_t
-build_attrs(attr_t curattrs)
-{
- return ((curattrs & ~A_COLOR) | COLOR_PAIR(curattrs & 0xff))
- >> NCURSES_ATTR_SHIFT;
-}
-
-static
-void
-row_set(Row *row, int start, int len, Buffer *t)
-{
- Cell cell = {
- .text = L'\0',
- .attr = t ? build_attrs(t->curattrs) : 0,
- .fg = t ? t->curfg : -1,
- .bg = t ? t->curbg : -1,
- };
-
- for (int i = start; i < len + start; i++)
- row->cells[i] = cell;
- row->dirty = true;
-}
-
-static
-void
-row_roll(Row *start, Row *end, int count)
-{
- 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;
- }
- }
+/* forward declares */
- b->curs_row += lines - b->lines;
- b->scroll_top = lines;
- b->scroll_bot = lines + rows;
- b->lines = lines;
+void vt·noscroll(Vt *t);
+void vt·dirty(Vt *t);
+void vt·scroll(Vt *t, int rows);
- /* perform backfill */
- if (deltarows > 0) {
- buffer_scroll(b, -deltarows);
- b->curs_row += deltarows;
- }
-}
+static void puttab(Vt *t, int count);
+static void process_nonprinting(Vt *t, rune r);
+static void sendcurs(Vt *t);
-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;
-}
+/* globals */
+static int isutf8;
+static char vtname[36];
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];
- }
-}
-
-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;
-}
-
-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)
+cclamp(Vt *t)
{
- 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);
+ 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;
- 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;
+ 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;
}
static
void
-cursor_clamp(Vt *t)
+clinedown(Vt *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;
-
- 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
-cursor_line_down(Vt *t)
-{
- Buffer *b = t->buffer;
- row_set(b->curs_row, b->cols, b->maxcols - b->cols, nil);
- b->curs_row++;
- if (b->curs_row < b->scroll_bot)
+ zero(b->crow, b->cols, b->maxcols - b->cols);
+ b->crow++;
+ if (b->crow < b->scroll.bot)
return;
- vt_noscroll(t);
+ vt·noscroll(t);
- b->curs_row = b->scroll_bot - 1;
- buffer_scroll(b, 1);
- row_set(b->curs_row, 0, b->cols, b);
+ b->crow = b->scroll.bot - 1;
+ bscroll(b, 1);
+ zero(b->crow, 0, b->cols);
}
static
void
-cursor_save(Vt *t)
+csave(Vt *t)
{
Buffer *b = t->buffer;
- b->curs_srow = b->curs_row - b->lines;
- b->curs_scol = b->curs_col;
+ b->scrow = b->crow - b->lines;
+ b->sccol = b->ccol;
}
static
void
-cursor_restore(Vt *t)
+crestore(Vt *t)
{
Buffer *b = t->buffer;
- b->curs_row = b->lines + b->curs_srow;
- b->curs_col = b->curs_scol;
- cursor_clamp(t);
+ b->crow = b->lines + b->scrow;
+ b->ccol = b->sccol;
+ cclamp(t);
}
static
void
-attributes_save(Vt *t)
+savepen(Vt *t)
{
Buffer *b = t->buffer;
- b->savattrs = b->curattrs;
- b->savfg = b->curfg;
- b->savbg = b->curbg;
- t->savgraphmode = t->graphmode;
+ b->spen = b->pen;
}
static
void
-attributes_restore(Vt *t)
+loadpen(Vt *t)
{
Buffer *b = t->buffer;
- b->curattrs = b->savattrs;
- b->curfg = b->savfg;
- b->curbg = b->savbg;
- t->graphmode = t->savgraphmode;
+ b->pen = b->spen;
}
+
static
void
new_escape_sequence(Vt *t)
@@ -658,89 +170,85 @@ interpret_csi_sgr(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
if (pcount == 0) {
/* special case: reset attributes */
- b->curattrs = A_NORMAL;
- b->curfg = b->curbg = -1;
+ b->pen.state = PenNormal;
+ b->pen.col.fg = b->pen.col.bg = -1;
return;
}
for (int i = 0; i < pcount; i++) {
switch (param[i]) {
case 0:
- b->curattrs = A_NORMAL;
- b->curfg = b->curbg = -1;
+ b->pen.state = PenNormal;
+ b->pen.col.fg = b->pen.col.bg = -1;
break;
case 1:
- b->curattrs |= A_BOLD;
+ b->pen.state |= PenBold;
break;
case 2:
- b->curattrs |= A_DIM;
+ b->pen.state |= PenDim;
break;
-#ifdef A_ITALIC
case 3:
- b->curattrs |= A_ITALIC;
+ b->pen.state |= PenItalic;
break;
-#endif
case 4:
- b->curattrs |= A_UNDERLINE;
+ b->pen.state |= PenUnderline;
break;
case 5:
- b->curattrs |= A_BLINK;
+ b->pen.state |= PenBlink;
break;
case 7:
- b->curattrs |= A_REVERSE;
+ b->pen.state |= PenReverse;
break;
case 8:
- b->curattrs |= A_INVIS;
+ b->pen.state |= PenInvis;
break;
case 22:
- b->curattrs &= ~(A_BOLD | A_DIM);
+ b->pen.state &= ~(PenBold | PenDim);
break;
-#ifdef A_ITALIC
case 23:
- b->curattrs &= ~A_ITALIC;
+ b->pen.state &= ~PenItalic;
break;
-#endif
case 24:
- b->curattrs &= ~A_UNDERLINE;
+ b->pen.state &= ~PenUnderline;
break;
case 25:
- b->curattrs &= ~A_BLINK;
+ b->pen.state &= ~PenBlink;
break;
case 27:
- b->curattrs &= ~A_REVERSE;
+ b->pen.state &= ~PenReverse;
break;
case 28:
- b->curattrs &= ~A_INVIS;
+ b->pen.state &= ~PenInvis;
break;
case 30 ... 37: /* fg */
- b->curfg = param[i] - 30;
+ b->pen.col.fg = param[i] - 30;
break;
case 38:
if ((i + 2) < pcount && param[i + 1] == 5) {
- b->curfg = param[i + 2];
+ b->pen.col.fg = param[i + 2];
i += 2;
}
break;
case 39:
- b->curfg = -1;
+ b->pen.col.fg = -1;
break;
case 40 ... 47: /* bg */
- b->curbg = param[i] - 40;
+ b->pen.col.bg = param[i] - 40;
break;
case 48:
if ((i + 2) < pcount && param[i + 1] == 5) {
- b->curbg = param[i + 2];
+ b->pen.col.bg = param[i + 2];
i += 2;
}
break;
case 49:
- b->curbg = -1;
+ b->pen.col.bg = -1;
break;
- case 90 ... 97: /* hi fg */
- b->curfg = param[i] - 82;
+ case 90 ... 97: /* hi fg */
+ b->pen.col.fg = param[i] - 82;
break;
case 100 ... 107: /* hi bg */
- b->curbg = param[i] - 92;
+ b->pen.col.bg = param[i] - 92;
break;
default:
break;
@@ -756,27 +264,27 @@ interpret_csi_ed(Vt *t, int param[], int pcount)
Row *row, *start, *end;
Buffer *b = t->buffer;
- attributes_save(t);
- b->curattrs = A_NORMAL;
- b->curfg = b->curbg = -1;
+ savepen(t);
+ b->pen.state = PenNormal;
+ b->pen.col.fg = b->pen.col.bg = -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->curs_row;
- row_set(b->curs_row, 0, b->curs_col + 1, b);
+ end = b->crow;
+ zero(b->crow, 0, b->ccol + 1);
} else {
- row_set(b->curs_row, b->curs_col, b->cols - b->curs_col, b);
- start = b->curs_row + 1;
- end = b->lines + b->rows;
+ zero(b->crow, b->ccol, b->cols - b->ccol);
+ start = b->crow + 1;
+ end = b->lines + b->rows;
}
for (row = start; row < end; row++)
- row_set(row, 0, b->cols, b);
+ zero(row, 0, b->cols);
- attributes_restore(t);
+ loadpen(t);
}
/* interprets a 'move cursor' (CUP) escape sequence */
@@ -784,21 +292,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->curs_row = lines;
- b->curs_col = 0;
+ b->crow = lines;
+ b->ccol = 0;
} else if (pcount == 1) {
- b->curs_row = lines + param[0] - 1;
- b->curs_col = 0;
+ b->crow = lines + param[0] - 1;
+ b->ccol = 0;
} else {
- b->curs_row = lines + param[0] - 1;
- b->curs_col = param[1] - 1;
+ b->crow = lines + param[0] - 1;
+ b->ccol = param[1] - 1;
}
- cursor_clamp(t);
+ cclamp(t);
}
/* Interpret the 'relative mode' sequences: CUU, CUD, CUF, CUB, CNL,
@@ -812,37 +320,37 @@ interpret_csi_c(Vt *t, char verb, int param[], int pcount)
switch (verb) {
case 'A':
- b->curs_row -= n;
+ b->crow -= n;
break;
case 'B':
case 'e':
- b->curs_row += n;
+ b->crow += n;
break;
case 'C':
case 'a':
- b->curs_col += n;
+ b->ccol += n;
break;
case 'D':
- b->curs_col -= n;
+ b->ccol -= n;
break;
case 'E':
- b->curs_row += n;
- b->curs_col = 0;
+ b->crow += n;
+ b->ccol = 0;
break;
case 'F':
- b->curs_row -= n;
- b->curs_col = 0;
+ b->crow -= n;
+ b->ccol = 0;
break;
case 'G':
case '`':
- b->curs_col = n - 1;
+ b->ccol = n - 1;
break;
case 'd':
- b->curs_row = b->lines + n - 1;
+ b->crow = b->lines + n - 1;
break;
}
- cursor_clamp(t);
+ cclamp(t);
}
/* Interpret the 'erase line' escape sequence */
@@ -853,13 +361,13 @@ interpret_csi_el(Vt *t, int param[], int pcount)
Buffer *b = t->buffer;
switch (pcount ? param[0] : 0) {
case 1:
- row_set(b->curs_row, 0, b->curs_col + 1, b);
+ zero(b->crow, 0, b->ccol + 1);
break;
case 2:
- row_set(b->curs_row, 0, b->cols, b);
+ zero(b->crow, 0, b->cols);
break;
default:
- row_set(b->curs_row, b->curs_col, b->cols - b->curs_col, b);
+ zero(b->crow, b->ccol, b->cols - b->ccol);
break;
}
}
@@ -870,16 +378,16 @@ void
interpret_csi_ich(Vt *t, int param[], int pcount)
{
Buffer *b = t->buffer;
- Row *row = b->curs_row;
+ Row *row = b->crow;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->curs_col + n > b->cols)
- n = b->cols - b->curs_col;
+ if (b->ccol + n > b->cols)
+ n = b->cols - b->ccol;
- for (int i = b->cols - 1; i >= b->curs_col + n; i--)
+ for (int i = b->cols - 1; i >= b->ccol + n; i--)
row->cells[i] = row->cells[i - n];
- row_set(row, b->curs_col, n, b);
+ zero(row, b->ccol, n);
}
/* Interpret the 'delete chars' sequence (DCH) */
@@ -888,16 +396,16 @@ void
interpret_csi_dch(Vt *t, int param[], int pcount)
{
Buffer *b = t->buffer;
- Row *row = b->curs_row;
+ Row *row = b->crow;
int n = (pcount && param[0] > 0) ? param[0] : 1;
- if (b->curs_col + n > b->cols)
- n = b->cols - b->curs_col;
+ if (b->ccol + n > b->cols)
+ n = b->cols - b->ccol;
- for (int i = b->curs_col; i < b->cols - n; i++)
+ for (int i = b->ccol; i < b->cols - n; i++)
row->cells[i] = row->cells[i + n];
- row_set(row, b->cols - n, n, b);
+ zero(row, b->cols - n, n);
}
/* Interpret an 'insert line' sequence (IL) */
@@ -908,13 +416,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->curs_row + n >= b->scroll_bot) {
- for (Row *row = b->curs_row; row < b->scroll_bot; row++)
- row_set(row, 0, b->cols, b);
+ if (b->crow + n >= b->scroll.bot) {
+ for (Row *row = b->crow; row < b->scroll.bot; row++)
+ zero(row, 0, b->cols);
} else {
- 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);
+ roll(b->crow, b->scroll.bot, -n);
+ for (Row *row = b->crow; row < b->crow + n; row++)
+ zero(row, 0, b->cols);
}
}
@@ -926,13 +434,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->curs_row + n >= b->scroll_bot) {
- for (Row *row = b->curs_row; row < b->scroll_bot; row++)
- row_set(row, 0, b->cols, b);
+ if (b->crow + n >= b->scroll.bot) {
+ for (Row *row = b->crow; row < b->scroll.bot; row++)
+ zero(row, 0, b->cols);
} else {
- 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);
+ roll(b->crow, b->scroll.bot, n);
+ for (Row *row = b->scroll.bot - n; row < b->scroll.bot; row++)
+ zero(row, 0, b->cols);
}
}
@@ -944,10 +452,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->curs_col + n > b->cols)
- n = b->cols - b->curs_col;
+ if (b->ccol + n > b->cols)
+ n = b->cols - b->ccol;
- row_set(b->curs_row, b->curs_col, n, b);
+ zero(b->crow, b->ccol, n);
}
/* Interpret a 'set scrolling region' (DECSTBM) sequence */
@@ -960,8 +468,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;
@@ -979,15 +487,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->curs_row = b->scroll_top;
- b->curs_col = 0;
+ b->crow = b->scroll.top;
+ b->ccol = 0;
}
static
@@ -1022,17 +530,17 @@ interpret_csi_priv_mode(Vt *t, int param[], int pcount, bool set)
case 47: /* use alternate/normal screen buffer */
case 1047:
if (!set)
- buffer_clear(&t->buffer_alternate);
- t->buffer = set ? &t->buffer_alternate : &t->buffer_normal;
- vt_dirty(t);
+ bclear(&t->buf[1]);
+ t->buffer = set ? &t->buf[1] : &t->buf[0];
+ vt·dirty(t);
if (param[i] != 1049)
break;
/* fall through */
case 1048: /* save/restore cursor */
if (set)
- cursor_save(t);
+ csave(t);
else
- cursor_restore(t);
+ crestore(t);
break;
case 1000: /* enable/disable normal mouse tracking */
t->mousetrack = set;
@@ -1125,10 +633,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);
@@ -1136,7 +644,7 @@ interpret_csi(Vt *t)
case 'g': /* TBC: tabulation clear */
switch (param_count ? csiparam[0] : 0) {
case 0:
- b->tabs[b->curs_col] = false;
+ b->tabs[b->ccol] = false;
break;
case 3:
memset(b->tabs, 0, sizeof(*b->tabs) * b->maxcols);
@@ -1147,14 +655,14 @@ interpret_csi(Vt *t)
interpret_csi_decstbm(t, csiparam, param_count);
break;
case 's': /* save cursor location */
- cursor_save(t);
+ csave(t);
break;
case 'u': /* restore cursor location */
- cursor_restore(t);
+ crestore(t);
break;
case 'n': /* query cursor location */
if (param_count == 1 && csiparam[0] == 6)
- send_curs(t);
+ sendcurs(t);
break;
default:
break;
@@ -1167,8 +675,8 @@ void
interpret_csi_ind(Vt *t)
{
Buffer *b = t->buffer;
- if (b->curs_row < b->lines + b->rows - 1)
- b->curs_row++;
+ if (b->crow < b->lines + b->rows - 1)
+ b->crow++;
}
/* Interpret a 'reverse index' (RI) sequence */
@@ -1177,11 +685,11 @@ void
interpret_csi_ri(Vt *t)
{
Buffer *b = t->buffer;
- if (b->curs_row > b->scroll_top)
- b->curs_row--;
+ if (b->crow > b->scroll.top)
+ b->crow--;
else {
- row_roll(b->scroll_top, b->scroll_bot, -1);
- row_set(b->scroll_top, 0, b->cols, b);
+ roll(b->scroll.top, b->scroll.bot, -1);
+ zero(b->scroll.top, 0, b->cols);
}
}
@@ -1191,9 +699,9 @@ void
interpret_csi_nel(Vt *t)
{
Buffer *b = t->buffer;
- if (b->curs_row < b->lines + b->rows - 1) {
- b->curs_row++;
- b->curs_col = 0;
+ if (b->crow < b->lines + b->rows - 1) {
+ b->crow++;
+ b->ccol = 0;
}
}
@@ -1222,8 +730,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;
@@ -1278,12 +786,12 @@ try_interpret_escape_seq(Vt *t)
}
break;
case '7': /* DECSC: save cursor and attributes */
- attributes_save(t);
- cursor_save(t);
+ savepen(t);
+ csave(t);
goto handled;
case '8': /* DECRC: restore cursor and attributes */
- attributes_restore(t);
- cursor_restore(t);
+ loadpen(t);
+ crestore(t);
goto handled;
case 'D': /* IND: index */
interpret_csi_ind(t);
@@ -1295,7 +803,7 @@ try_interpret_escape_seq(Vt *t)
interpret_csi_nel(t);
goto handled;
case 'H': /* HTS: horizontal tab set */
- t->buffer->tabs[t->buffer->curs_col] = true;
+ t->buffer->tabs[t->buffer->ccol] = true;
goto handled;
default:
goto cancel;
@@ -1325,17 +833,17 @@ puttab(Vt *t, int count)
{
Buffer *b = t->buffer;
int direction = count >= 0 ? 1 : -1;
- for (int col = b->curs_col + direction; count; col += direction) {
+ for (int col = b->ccol + direction; count; col += direction) {
if (col < 0) {
- b->curs_col = 0;
+ b->ccol = 0;
break;
}
if (col >= b->cols) {
- b->curs_col = b->cols - 1;
+ b->ccol = b->cols - 1;
break;
}
if (b->tabs[col]) {
- b->curs_col = col;
+ b->ccol = col;
count -= direction;
}
}
@@ -1343,31 +851,31 @@ puttab(Vt *t, int count)
static
void
-process_nonprinting(Vt *t, wchar_t wc)
+process_nonprinting(Vt *t, rune r)
{
Buffer *b = t->buffer;
- switch (wc) {
+ switch (r) {
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->curs_col > 0)
- b->curs_col--;
+ if (b->ccol > 0)
+ b->ccol--;
break;
case '\t': /* HT */
puttab(t, 1);
break;
case '\r': /* CR */
- b->curs_col = 0;
+ b->ccol = 0;
break;
case '\v': /* VT */
case '\f': /* FF */
case '\n': /* LF */
- cursor_line_down(t);
+ clinedown(t);
break;
case '\016': /* SO: shift out, invoke the G1 character set */
t->graphmode = t->charsets[1];
@@ -1385,7 +893,7 @@ is_utf8_locale(void)
const char *cset = nl_langinfo(CODESET);
if (!cset)
cset = "ANSI_X3.4-1968";
- is_utf8 = !strcmp(cset, "UTF-8");
+ isutf8 = !strcmp(cset, "UTF-8");
}
static
@@ -1409,17 +917,18 @@ get_vt100_graphic(char c)
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
};
- if (is_utf8)
+ if (isutf8)
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
-put_wc(Vt *t, wchar_t wc)
+putrune(Vt *t, rune r)
{
+ Cell blank;
int width = 0;
if (!t->seen_input) {
@@ -1429,54 +938,61 @@ put_wc(Vt *t, wchar_t wc)
if (t->escaped) {
if (t->elen + 1 < sizeof(t->ebuf)) {
- t->ebuf[t->elen] = wc;
+ t->ebuf[t->elen] = r;
t->ebuf[++t->elen] = '\0';
try_interpret_escape_seq(t);
} else {
cancel_escape_sequence(t);
}
- } else if (IS_CONTROL(wc)) {
- process_nonprinting(t, wc);
+ } else if (IS_CONTROL(r)) {
+ process_nonprinting(t, r);
} else {
if (t->graphmode) {
- if (wc >= 0x41 && wc <= 0x7e) {
- wchar_t gc = get_vt100_graphic(wc);
+ if (r >= 0x41 && r <= 0x7e) {
+ wchar_t gc = get_vt100_graphic(r);
if (gc)
- wc = gc;
+ r = gc;
}
width = 1;
- } else if ((width = wcwidth(wc)) < 1) {
+ } else if ((width = wcwidth(r)) < 1) {
width = 1;
}
Buffer *b = t->buffer;
- 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;
+ 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;
}
- if (b->curs_col >= b->cols) {
- b->curs_col = 0;
- cursor_line_down(t);
+ if (b->ccol >= b->cols) {
+ b->ccol = 0;
+ clinedown(t);
}
if (t->insert) {
- Cell *src = b->curs_row->cells + b->curs_col;
+ Cell *src = b->crow->cells + b->ccol;
Cell *dest = src + width;
- size_t len = b->cols - b->curs_col - width;
+ size_t len = b->cols - b->ccol - width;
memmove(dest, src, len * sizeof *dest);
}
- b->curs_row->cells[b->curs_col] = blank_cell;
- b->curs_row->cells[b->curs_col++].text = wc;
- b->curs_row->dirty = true;
+ b->crow->cells[b->ccol] = blank;
+ b->crow->cells[b->ccol++].r = r;
+ b->crow->dirty = true;
+
if (width == 2)
- b->curs_row->cells[b->curs_col++] = blank_cell;
+ b->crow->cells[b->ccol++] = blank;
}
}
int
-vt_process(Vt *t)
+vt·process(Vt *t)
{
int res;
uint pos = 0;
@@ -1494,10 +1010,11 @@ vt_process(Vt *t)
t->rlen += res;
while (pos < t->rlen) {
- wchar_t wc;
- ssize_t len;
+ rune r;
+ size_t len;
- len = (ssize_t)mbrtowc(&wc, t->rbuf + pos, t->rlen - pos, &ps);
+ // XXX: convert this to use utf8 functions
+ len = (ssize_t)mbrtowc((wchar*)&r, t->rbuf + pos, t->rlen - pos, &ps);
if (len == -2) {
t->rlen -= pos;
memmove(t->rbuf, t->rbuf + pos, t->rlen);
@@ -1506,11 +1023,11 @@ vt_process(Vt *t)
if (len == -1) {
len = 1;
- wc = t->rbuf[pos];
+ r = t->rbuf[pos];
}
pos += len ? len : 1;
- put_wc(t, wc);
+ putrune(t, r);
}
t->rlen -= pos;
@@ -1518,16 +1035,9 @@ vt_process(Vt *t)
return 0;
}
-void
-vt_default_colors_set(Vt *t, attr_t attrs, short fg, short bg)
-{
- t->defattrs = attrs;
- t->deffg = fg;
- t->defbg = bg;
-}
-
+/* size is the number of rows kept in the scrollback */
Vt *
-vt_create(int rows, int cols, int scroll_size)
+vt·make(int rows, int cols, int size)
{
if (rows <= 0 || cols <= 0)
return nil;
@@ -1537,11 +1047,14 @@ vt_create(int rows, int cols, int scroll_size)
return nil;
t->pty = -1;
- t->deffg = t->defbg = -1;
- t->buffer = &t->buffer_normal;
-
- if (!buffer_init(&t->buffer_normal, rows, cols, scroll_size) ||
- !buffer_init(&t->buffer_alternate, rows, cols, 0)) {
+ t->pen = (Pen) {
+ .state = PenNormal,
+ .col = {-1, -1},
+ };
+ t->buffer = &t->buf[0];
+
+ if (!binit(&t->buf[0], rows, cols, size) ||
+ !binit(&t->buf[1], rows, cols, 0)) {
free(t);
return nil;
}
@@ -1550,34 +1063,34 @@ vt_create(int rows, int cols, int scroll_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);
- buffer_resize(&t->buffer_normal, rows, cols);
- buffer_resize(&t->buffer_alternate, rows, cols);
- cursor_clamp(t);
+ vt·noscroll(t);
+ bresize(&t->buf[0], rows, cols);
+ bresize(&t->buf[1], rows, cols);
+ cclamp(t);
ioctl(t->pty, TIOCSWINSZ, &ws);
kill(-t->pid, SIGWINCH);
}
void
-vt_destroy(Vt *t)
+vt·free(Vt *t)
{
if (!t)
return;
- buffer_free(&t->buffer_normal);
- buffer_free(&t->buffer_alternate);
+ bfree(&t->buf[0]);
+ bfree(&t->buf[1]);
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++)
@@ -1585,51 +1098,49 @@ 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 (int i = 0; i < b->rows; i++) {
+ for (i = 0; i < b->rows; i++) {
Row *row = b->lines + i;
if (!row->dirty)
continue;
wmove(win, srow + i, scol);
- Cell *cell = nil;
- for (int j = 0; j < b->cols; j++) {
- Cell *prev_cell = cell;
+ for (j = 0; j < b->cols; j++) {
+ prev = cell;
cell = row->cells + j;
- 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 (!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 (is_utf8 && cell->text >= 128) {
+ if (isutf8 && cell->r >= RuneSync) {
char buf[MB_CUR_MAX + 1];
- size_t len = wcrtomb(buf, cell->text, nil);
+ size_t len = wcrtomb(buf, cell->r, nil);
if (len > 0) {
waddnstr(win, buf, len);
- if (wcwidth(cell->text) > 1)
+ if (wcwidth(cell->r) > 1)
j++;
}
- } else {
- waddch(win, cell->text > ' ' ? cell->text : ' ');
- }
+ } else
+ waddch(win, cell->r > ' ' ? cell->r: ' ');
}
int x, y;
@@ -1641,36 +1152,36 @@ vt_draw(Vt *t, WINDOW *win, int srow, int scol)
row->dirty = false;
}
- wmove(win, srow + b->curs_row - b->lines, scol + b->curs_col);
+ wmove(win, srow + b->crow - b->lines, scol + b->ccol);
}
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;
}
- buffer_scroll(b, rows);
- b->scroll_below -= rows;
+ bscroll(b, rows);
+ b->scroll.below -= rows;
}
void
-vt_noscroll(Vt *t)
+vt·noscroll(Vt *t)
{
- int scroll_below = t->buffer->scroll_below;
- if (scroll_below)
- vt_scroll(t, scroll_below);
+ int below = t->buffer->scroll.below;
+ if (below)
+ vt·scroll(t, 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;
@@ -1717,7 +1228,7 @@ vt_forkpty(Vt *t, const char *p, const char *argv[], const char *cwd, const char
for (const char **envp = env; envp && envp[0]; envp += 2)
setenv(envp[0], envp[1], 1);
- setenv("TERM", vt_term, 1);
+ setenv("TERM", vtname, 1);
if (cwd)
chdir(cwd);
@@ -1746,13 +1257,13 @@ vt_pty_get(Vt *t)
return t->pty;
}
-ssize_t
-vt_write(Vt *t, const char *buf, size_t len)
+uintptr
+vt·write(Vt *t, const char *buf, size_t len)
{
- ssize_t ret = len;
+ uintptr res, ret = len;
while (len > 0) {
- ssize_t res = write(t->pty, buf, len);
+ res = write(t->pty, buf, len);
if (res < 0) {
if (errno != EAGAIN && errno != EINTR)
return -1;
@@ -1767,18 +1278,19 @@ vt_write(Vt *t, const char *buf, size_t len)
static
void
-send_curs(Vt *t)
+sendcurs(Vt *t)
{
Buffer *b = t->buffer;
char keyseq[16];
- snprintf(keyseq, sizeof keyseq, "\e[%d;%dR", (int)(b->curs_row - b->lines), b->curs_col);
- vt_write(t, keyseq, strlen(keyseq));
+ snprintf(keyseq, sizeof keyseq, "\e[%d;%dR", (int)(b->crow - b->lines), b->ccol);
+ 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) {
@@ -1787,26 +1299,23 @@ 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)
@@ -1832,16 +1341,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
@@ -1854,102 +1363,26 @@ color_hash(short fg, short bg)
return fg * (COLORS + 2) + bg;
}
-short
-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;
- }
- }
- }
-
- short color_pair = color2palette[index];
- return color_pair >= 0 ? color_pair : -color_pair;
-}
-
-short
-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);
- }
- short 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(short));
- /*
- * 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_pair(i, 0, 0);
- vt_color_reserve(COLOR_WHITE, COLOR_BLACK);
-}
-
void
-vt_init(void)
+vt·init(void)
{
init_colors();
is_utf8_locale();
char *term = getenv("DVTM_TERM");
if (!term)
term = "dvtm";
- snprintf(vt_term, sizeof vt_term, "%s%s", term, COLORS >= 256 ? "-256color" : "");
+
+ snprintf(vtname, sizeof vtname, "%s%s", term, COLORS >= 256 ? "-256color" : "");
+}
+
+void
+vt·shutdown(void)
+{
}
+#if 0
void
-vt_keytable_set(const char * const keytable_overlay[], int count)
+vt·setkeytable(const char * const keytable_overlay[], int count)
{
for (int k = 0; k < count && k < KEY_MAX; k++) {
const char *keyseq = keytable_overlay[k];
@@ -1959,52 +1392,47 @@ vt_keytable_set(const char * const keytable_overlay[], int count)
}
void
-vt_shutdown(void)
-{
- free(color2palette);
-}
-
-void
-vt_title_handler_set(Vt *t, vt_title_handler_t handler)
+vt·settitlecb(Vt *t, vt_title_handler_t handler)
{
t->title_handler = handler;
}
void
-vt_urgent_handler_set(Vt *t, vt_urgent_handler_t handler)
+vt·seturgentcb(Vt *t, vt_urgent_handler_t handler)
{
t->urgent_handler = handler;
}
+#endif
void
-vt_data_set(Vt *t, void *data)
+vt·setdata(Vt *t, void *data)
{
t->data = data;
}
void *
-vt_data_get(Vt *t)
+vt·getdata(Vt *t)
{
return t->data;
}
bool
-vt_cursor_visible(Vt *t)
+vt·cursorvisible(Vt *t)
{
- return t->buffer->scroll_below ? false : !t->curshid;
+ return t->buffer->scroll.below ? false : !t->curshid;
}
pid_t
-vt_pid_get(Vt *t)
+vt·pid(Vt *t)
{
return t->pid;
}
size_t
-vt_content_get(Vt *t, char **buf, bool colored)
+vt·content(Vt *t, char **buf, bool colored)
{
- Buffer *b = t->buffer;
- int lines = b->scroll_above + b->scroll_below + b->rows + 1;
+ Buffer *b = t->buffer;
+ 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));
@@ -2013,28 +1441,28 @@ vt_content_get(Vt *t, char **buf, bool colored)
return 0;
char *s = *buf;
- Cell *prev_cell = nil;
+ Cell *prev = nil;
- for (Row *row = buffer_row_first(b); row; row = buffer_row_next(b, row)) {
+ for (Row *row = browfirst(b); row; row = brownext(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 || cell->attr != prev_cell->attr) {
+ if (!prev || cell->attr != prev->attr) {
attr_t attr = cell->attr << NCURSES_ATTR_SHIFT;
esclen = sprintf(s, "\033[0%s%s%s%s%s%sm",
- attr & A_BOLD ? ";1" : "",
- attr & A_DIM ? ";2" : "",
- attr & A_UNDERLINE ? ";4" : "",
- attr & A_BLINK ? ";5" : "",
- attr & A_REVERSE ? ";7" : "",
- attr & A_INVIS ? ";8" : "");
+ attr & PenBold ? ";1" : "",
+ attr & PenDim ? ";2" : "",
+ attr & PenUnderline ? ";4" : "",
+ attr & PenBlink ? ";5" : "",
+ attr & PenReverse ? ";7" : "",
+ attr & PenInvis ? ";8" : "");
if (esclen > 0)
s += esclen;
}
- if (!prev_cell || cell->fg != prev_cell->fg || cell->attr != prev_cell->attr) {
+ if (!prev || cell->fg != prev->fg || cell->attr != prev->attr) {
if (cell->fg == -1)
esclen = sprintf(s, "\033[39m");
else
@@ -2042,7 +1470,7 @@ vt_content_get(Vt *t, char **buf, bool colored)
if (esclen > 0)
s += esclen;
}
- if (!prev_cell || cell->bg != prev_cell->bg || cell->attr != prev_cell->attr) {
+ if (!prev || cell->bg != prev->bg || cell->attr != prev->attr) {
if (cell->bg == -1)
esclen = sprintf(s, "\033[49m");
else
@@ -2050,7 +1478,7 @@ vt_content_get(Vt *t, char **buf, bool colored)
if (esclen > 0)
s += esclen;
}
- prev_cell = cell;
+ prev = cell;
}
if (cell->text) {
len = wcrtomb(s, cell->text, &ps);
@@ -2072,7 +1500,7 @@ vt_content_get(Vt *t, char **buf, bool colored)
}
int
-vt_content_start(Vt *t)
+vt·contentstart(Vt *t)
{
- return t->buffer->scroll_above;
+ return t->buffer->scroll.above;
}
diff --git a/sys/cmd/dvtm/vt.h b/sys/cmd/dvtm/vt.h
index 3b738f6..3d4d129 100644
--- a/sys/cmd/dvtm/vt.h
+++ b/sys/cmd/dvtm/vt.h
@@ -1,11 +1,13 @@
/* see LICENSE for details */
#pragma once
+#include <u.h>
+// #include <vendor/curses.h>
#include <stdbool.h>
#include <sys/types.h>
#ifndef NCURSES_MOUSE_VERSION
-#define mmask_t unsigned long
+#define mmask_t ulong
#endif
typedef struct Vt Vt;
@@ -16,11 +18,11 @@ void vt_init(void);
void vt_shutdown(void);
void vt_keytable_set(char const * const keytable_overlay[], int count);
-void vt_default_colors_set(Vt*, attr_t attrs, short fg, short bg);
+void vt_default_colors_set(Vt*, attr_t attrs, int fg, int bg);
void vt_title_handler_set(Vt*, vt_title_handler_t);
void vt_urgent_handler_set(Vt*, vt_urgent_handler_t);
void vt_data_set(Vt*, void *);
-void *vt_data_get(Vt*);
+void *vt_data_get(Vt*);
Vt *vt_create(int rows, int cols, int scroll_buf_sz);
void vt_resize(Vt*, int rows, int cols);
@@ -35,8 +37,8 @@ ssize_t vt_write(Vt*, const char *buf, size_t len);
void vt_mouse(Vt*, int x, int y, mmask_t mask);
void vt_dirty(Vt*);
void vt_draw(Vt*, WINDOW *win, int startrow, int startcol);
-short vt_color_get(Vt*, short fg, short bg);
-short vt_color_reserve(short fg, short bg);
+int vt_color_get(Vt*, int fg, int bg);
+int vt_color_reserve(int fg, int bg);
void vt_scroll(Vt*, int rows);
void vt_noscroll(Vt*);
diff --git a/sys/cmd/dvtm/window.c b/sys/cmd/dvtm/window.c
new file mode 100644
index 0000000..44690c9
--- /dev/null
+++ b/sys/cmd/dvtm/window.c
@@ -0,0 +1,42 @@
+#include <u.h>
+#include <libn.h>
+
+#include "buffer.h"
+
+typedef struct Rect Rect;
+typedef struct Window Window;
+
+/* origin upper left corner */
+struct Rect
+{
+ int r0, c0, rows, cols;
+};
+
+struct Window
+{
+ Buffer buffer[2], *buf;
+ Rect area; /* on screen */
+ Pen pen, spen; /* current and saved pen */
+ struct {
+ uint visible : 1;
+ int row, col; /* saved cursor row/colmn (zero based) */
+ int srow, scol; /* saved cursor row/colmn (zero based) */
+ } c;
+}
+
+/* functions */
+
+Window *
+makewindow(
+
+ t->pen = (Pen) {
+ .state = PenNormal,
+ .col = {-1, -1},
+ };
+ t->buffer = &t->buf[0];
+
+ if (!binit(&t->buf[0], rows, cols, size) ||
+ !binit(&t->buf[1], rows, cols, 0)) {
+ free(t);
+ return nil;
+ }
diff --git a/sys/cmd/dwm/config.h b/sys/cmd/dwm/config.h
index a35e4e6..ce5b196 100644
--- a/sys/cmd/dwm/config.h
+++ b/sys/cmd/dwm/config.h
@@ -60,12 +60,22 @@ static Layout layouts[] = {
static char *menucmd[] = { "menu_run", nil };
static char *termcmd[] = { "term", nil };
static char *webscmd[] = { "qutebrowser", nil };
+static char *upvolcmd[] = { "pactl", "set-sink-volume", "0", "+5%", nil };
+static char *lovolcmd[] = { "pactl", "set-sink-volume", "0", "-5%", nil };
+static char *novolcmd[] = { "pactl", "set-sink-mute", "0", "toggle", nil };
+
+#define XK_lovol XF86XK_AudioLowerVolume
+#define XK_upvol XF86XK_AudioRaiseVolume
+#define XK_novol XF86XK_AudioMute
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_d, spawn, {.v = menucmd } },
{ MODKEY, XK_Return, spawn, {.v = termcmd } },
- { MODKEY|ShiftMask, XK_q, spawn, {.v = webscmd } },
+ { MODKEY, XK_q, spawn, {.v = webscmd } },
+ { 0, XK_upvol, spawn, {.v = upvolcmd} },
+ { 0, XK_lovol, spawn, {.v = lovolcmd} },
+ { 0, XK_novol, spawn, {.v = novolcmd} },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_f, togglefocus, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
diff --git a/sys/cmd/dwm/dwm.h b/sys/cmd/dwm/dwm.h
index 3449ff8..3f2dd0e 100644
--- a/sys/cmd/dwm/dwm.h
+++ b/sys/cmd/dwm/dwm.h
@@ -24,6 +24,7 @@
#include <xcb/res.h>
#include <X11/extensions/Xinerama.h>
#include <X11/Xft/Xft.h>
+#include <X11/XF86keysym.h>
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
diff --git a/sys/cmd/rules.mk b/sys/cmd/rules.mk
index a68231b..2364189 100644
--- a/sys/cmd/rules.mk
+++ b/sys/cmd/rules.mk
@@ -5,8 +5,8 @@ include share/push.mk
DIR := $(d)/cat
include $(DIR)/rules.mk
-DIR := $(d)/cc
-include $(DIR)/rules.mk
+# DIR := $(d)/cc
+# include $(DIR)/rules.mk
# DIR := $(d)/edo
# include $(DIR)/rules.mk
diff --git a/sys/cmd/term/term.h b/sys/cmd/term/term.h
index 00a646a..3c7e3ca 100644
--- a/sys/cmd/term/term.h
+++ b/sys/cmd/term/term.h
@@ -4,7 +4,6 @@
#include <u.h>
#include <libn.h>
-#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/select.h>