aboutsummaryrefslogtreecommitdiff
path: root/sys/libterm/term.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/libterm/term.h')
-rw-r--r--sys/libterm/term.h489
1 files changed, 489 insertions, 0 deletions
diff --git a/sys/libterm/term.h b/sys/libterm/term.h
new file mode 100644
index 0000000..acae95f
--- /dev/null
+++ b/sys/libterm/term.h
@@ -0,0 +1,489 @@
+#pragma once
+
+#include <u.h>
+#include <libn.h>
+
+#include <termios.h>
+#include <unibilium.h>
+
+#define iota(x) 1 << (x)
+/*
+ * obtained from:
+ * https://invisible-island.net/ncurses/man/curs_add_wch.3x.html
+ */
+#define ACSRUNES \
+ /* name utf8 ascii acsc*/ \
+ ACSRUNE("block", 0x25ae, '#', '0') \
+ ACSRUNE("board", 0x2592, '#', 'h') \
+ ACSRUNE("btee", 0x2534, '+', 'v') \
+ ACSRUNE("bullet", 0x00b7, 'o', '~') \
+ ACSRUNE("ckboard", 0x2592, ':', 'a') \
+ ACSRUNE("darrow", 0x2193, 'v', '.') \
+ ACSRUNE("degree", 0x00b0, '\'','f') \
+ ACSRUNE("diamond", 0x25c6, '+', '`') \
+ ACSRUNE("gequal", 0x2265, '>', '>') \
+ ACSRUNE("hline", 0x2500, '-', 'q') \
+ ACSRUNE("antern", 0x2603, '#', 'i') \
+ ACSRUNE("larrow", 0x2190, '<', ',') \
+ ACSRUNE("lequal", 0x2264, '<', 'y') \
+ ACSRUNE("llcorner", 0x2514, '+', 'm') \
+ ACSRUNE("lrcorner", 0x2518, '+', 'j') \
+ ACSRUNE("ltee", 0x2524, '+', 't') \
+ ACSRUNE("nequal", 0x2260, '!', '|') \
+ ACSRUNE("pi", 0x03c0, '*', '{') \
+ ACSRUNE("plminus", 0x00b1, '#', 'g') \
+ ACSRUNE("plus", 0x253c, '+', 'n') \
+ ACSRUNE("rarrow", 0x2192, '>', '+') \
+ ACSRUNE("rtee", 0x251c, '+', 'u') \
+ ACSRUNE("s1", 0x23ba, '-', 'o') \
+ ACSRUNE("s3", 0x23bb, '-', 'p') \
+ ACSRUNE("s7", 0x23bc, '-', 'r') \
+ ACSRUNE("s9", 0x23bd, '_', 's') \
+ ACSRUNE("sterling", 0x00a3, 'f', '}') \
+ ACSRUNE("ttee", 0x252c, '+', 'w') \
+ ACSRUNE("uarrow", 0x2191, '^', '-') \
+ ACSRUNE("ulcorner", 0x250c, '+', 'l') \
+ ACSRUNE("urcorner", 0x2510, '+', 'k') \
+ ACSRUNE("vline", 0x2502, '|', 'x') \
+ /* thick versions */ \
+ ACSRUNE("t_btee", 0x253b, '+', 'V') \
+ ACSRUNE("t_hline", 0x2501, '-', 'Q') \
+ ACSRUNE("t_llcorner", 0x2517, '+', 'M') \
+ ACSRUNE("t_lrcorner", 0x251b, '+', 'J') \
+ ACSRUNE("t_ltee", 0x252b, '+', 'T') \
+ ACSRUNE("t_plus", 0x254b, '+', 'N') \
+ ACSRUNE("t_rtee", 0x2523, '+', 'U') \
+ ACSRUNE("t_ttee", 0x2533, '+', 'W') \
+ ACSRUNE("t_ulcorner", 0x250f, '+', 'L') \
+ ACSRUNE("t_urcorner", 0x2513, '+', 'K') \
+ ACSRUNE("t_vline", 0x2503, '|', 'X') \
+ /* double version */ \
+ ACSRUNE("d_btee", 0x2569, '+', 'H') \
+ ACSRUNE("d_hline", 0x2550, '-', 'R') \
+ ACSRUNE("d_llcorner", 0x255a, '+', 'D') \
+ ACSRUNE("d_lrcorner", 0x255d, '+', 'A') \
+ ACSRUNE("d_ltee", 0x2560, '+', 'F') \
+ ACSRUNE("d_plus", 0x256c, '+', 'E') \
+ ACSRUNE("d_rtee", 0x2563, '+', 'G') \
+ ACSRUNE("d_ttee", 0x2566, '+', 'I') \
+ ACSRUNE("d_ulcorner", 0x2554, '+', 'C') \
+ ACSRUNE("d_urcorner", 0x2557, '+', 'B') \
+ ACSRUNE("d_vline", 0x2551, '|', 'Y')
+
+/* enums */
+
+/* key 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),
+};
+
+/* types */
+typedef struct RGB8 RGB8;
+typedef struct Pen Pen;
+
+typedef struct Cell Cell;
+typedef struct Row Row;
+typedef struct Buffer Buffer;
+typedef struct Window Window;
+
+typedef struct Node Node;
+typedef struct Key Key;
+typedef struct Input Input;
+
+typedef struct Term Term;
+
+struct RGB8
+{
+ uint8 r, g, b;
+};
+
+enum
+{
+ PenNormal = 0,
+ PenBold = iota(0),
+ PenDim = iota(1),
+ PenInvis = iota(2),
+ PenItalic = iota(3),
+ PenReverse = iota(4),
+ PenStrike = iota(5),
+ PenUnderline = iota(6),
+ PenBlink = iota(7),
+ /* ... */
+ PenTrueClr = iota(15),
+};
+
+struct Pen
+{
+ ushort state;
+ union {
+ /* 256 color (legacy) */
+ struct {
+ sshort fg : 8, bg : 8; /* 0 - 255 or COLOUR_DEFAULT */
+ } col;
+ /* true color (modern) */
+ struct {
+ RGB8 fg, bg;
+ } rgb;
+ };
+};
+
+/* outputs */
+struct Cell {
+ rune 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 *row; /* 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;
+ Pen pen, spen;
+ int nrow, ncol; /* current dimension of buffer */
+ int maxcols; /* allocated cells (maximal cols over time) */
+ int srow, scol; /* saved cursor row/column (zero based) */
+};
+
+/* 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;
+};
+
+/* make opaque? */
+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;
+};
+
+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 */
+ Window *root;
+ Pen pen;
+
+ /* 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
+
+ /* augmentations to terminfo */
+ struct {
+ char *rgbf; // rgb foreground
+ char *rgbb; // rgb background
+ char *smxx; // strikethrough
+ char *smulx; // curly underline
+ } ext;
+ } esc;
+
+ /* basic shapes */
+ struct {
+ rune block;
+ rune board;
+ rune hline;
+ rune vline;
+ rune plus;
+ rune ltee;
+ rune rtee;
+ rune ttee;
+ rune btee;
+ rune ulcorner;
+ rune urcorner;
+ rune llcorner;
+ rune lrcorner;
+ } acs;
+};
+
+/*
+ * exported functions
+ */
+
+#if 0
+/* buffer.c */
+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 brender(Buffer *b, Term *t);
+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);
+
+/* input.c */
+Input *makeinput(int fd, int flags, unibi_term *info);
+void freeinput(Input *in);
+int startrecord(Input *in);
+int stoprecord(Input *in);
+char *keyname(Input *in, int sym);
+
+enum KeyEvent term·waitkey(Input *in, Key *key); /* block until next keypress */
+enum KeyEvent term·getkey(Input *in, Key *key); /* grab key if we can */
+enum KeyEvent term·demandkey(Input *in, Key *key); /* grab now and interpret as best we can */
+
+/* unpack key event into useful data */
+enum KeyEvent decodemouse(Input *in, Key *key, enum MouseEvent *ev, int *button, int *row, int *col);
+enum KeyEvent decodepos(Input *in, Key *key, int *row, int *col);
+enum KeyEvent decodemode(Input *in, Key *key, int *init, int *mode, int *val);
+#endif
+
+/* term.c */
+void term·init(Term *t);
+void term·fini(Term *t);
+void term·flush(Term *t);
+void term·write(Term *t, long len, char *s);
+int term·goto(Term *t, int row, int col);
+void term·jump(Term *t, int down, int right);
+void term·del(Term *t, int num);
+void term·setpen(Term *t, Pen pen);
+void term·clear(Term *t);
+
+/* input.c */
+enum KeyEvent term·waitkey(Term *t, Key *key); /* block until next keypress */
+enum KeyEvent term·getkey(Term *t, Key *key); /* grab key if we can */
+enum KeyEvent term·demandkey(Term *t, Key *key); /* grab now and interpret as best we can */