diff options
Diffstat (limited to 'README.tmt')
-rw-r--r-- | README.tmt | 637 |
1 files changed, 0 insertions, 637 deletions
diff --git a/README.tmt b/README.tmt deleted file mode 100644 index f3819df..0000000 --- a/README.tmt +++ /dev/null @@ -1,637 +0,0 @@ - -============================================ -libtmt - a simple terminal emulation library -============================================ - -libtmt is the Tiny Mock Terminal Library. It provides emulation of a classic -smart text terminal, by maintaining an in-memory screen image. Sending text -and command sequences to libtmt causes it to update this in-memory image, -which can then be examined and rendered however the user sees fit. - -The imagined primary goal for libtmt is to for terminal emulators and -multiplexers; it provides the terminal emulation layer for the `mtm`_ -terminal multiplexer, for example. Other uses include screen-scraping and -automated test harnesses. - -libtmt is similar in purpose to `libtsm`_, but considerably smaller (500 -lines versus 6500 lines). libtmt is also, in this author's humble opinion, -considerably easier to use. - -.. _`mtm`: https://github.com/deadpixi/mtm -.. _`libtsm`: https://www.freedesktop.org/wiki/Software/kmscon/libtsm/ - -Major Features and Advantages -============================= - -Works Out-of-the-Box - libtmt emulates a well-known terminal type (`ansi`), the definition of - which has been in the terminfo database since at least 1995. There's no - need to install a custom terminfo entry. There's no claiming to be an - xterm but only emulating a small subset of its features. Any program - using terminfo works automatically: this includes vim, emacs, mc, - cmus, nano, nethack, ... - -Portable - Written in pure C99. - Optionally, the POSIX-mandated `wcwidth` function can be used, which - provides minimal support for combining characters. - -Small - Less than 500 lines of C, including comments and whitespace. - -Free - Released under a BSD-style license, free for commercial and - non-commerical use, with no restrictions on source code release or - redistribution. - -Simple - Only 8 functions to learn, and really you can get by with 6! - -International - libtmt internally uses wide characters exclusively, and uses your C - library's multibyte encoding functions. - This means that the library automatically supports any encoding that - your operating system does. - -How to Use libtmt -================= - -libtmt is a single C file and a single header. Just include these files -in your project and you should be good to go. - -By default, libtmt uses only ISO standard C99 features, -but see `Compile-Time Options`_ below. - -Example Code ------------- - -Below is a simple program fragment giving the flavor of libtmt. -Note that another good example is the `mtm`_ terminal multiplexer: - -.. _`mtm`: https://github.com/deadpixi/mtm - -.. code:: c - - #include <stdio.h> - #include <stdlib.h> - #include "tmt.h" - - /* Forward declaration of a callback. - * libtmt will call this function when the terminal's state changes. - */ - void callback(tmt_msg_t m, TMT *vt, const void *a, void *p); - - int - main(void) - { - /* Open a virtual terminal with 2 lines and 10 columns. - * The first NULL is just a pointer that will be provided to the - * callback; it can be anything. The second NULL specifies that - * we want to use the default Alternate Character Set; this - * could be a pointer to a wide string that has the desired - * characters to be displayed when in ACS mode. - */ - TMT *vt = tmt_open(2, 10, callback, NULL, NULL); - if (!vt) - return perror("could not allocate terminal"), EXIT_FAILURE; - - /* Write some text to the terminal, using escape sequences to - * use a bold rendition. - * - * The final argument is the length of the input; 0 means that - * libtmt will determine the length dynamically using strlen. - */ - tmt_write(vt, "\033[1mhello, world (in bold!)\033[0m", 0); - - /* Writing input to the virtual terminal can (and in this case, did) - * call the callback letting us know the screen was updated. See the - * callback below to see how that works. - */ - tmt_close(vt); - return EXIT_SUCCESS; - } - - void - callback(tmt_msg_t m, TMT *vt, const void *a, void *p) - { - /* grab a pointer to the virtual screen */ - const TMTSCREEN *s = tmt_screen(vt); - const TMTPOINT *c = tmt_cursor(vt); - - switch (m){ - case TMT_MSG_BELL: - /* the terminal is requesting that we ring the bell/flash the - * screen/do whatever ^G is supposed to do; a is NULL - */ - printf("bing!\n"); - break; - - case TMT_MSG_UPDATE: - /* the screen image changed; a is a pointer to the TMTSCREEN */ - for (size_t r = 0; r < s->nline; r++){ - if (s->lines[r]->dirty){ - for (size_t c = 0; c < s->ncol; c++){ - printf("contents of %zd,%zd: %lc (%s bold)\n", r, c, - s->lines[r]->chars[c].c, - s->lines[r]->chars[c].a.bold? "is" : "is not"); - } - } - } - - /* let tmt know we've redrawn the screen */ - tmt_clean(vt); - break; - - case TMT_MSG_ANSWER: - /* the terminal has a response to give to the program; a is a - * pointer to a string */ - printf("terminal answered %s\n", (const char *)a); - break; - - case TMT_MSG_MOVED: - /* the cursor moved; a is a pointer to the cursor's TMTPOINT */ - printf("cursor is now at %zd,%zd\n", c->r, c->c); - break; - } - } - -Data Types and Enumerations ---------------------------- - -.. code:: c - - /* an opaque structure */ - typedef struct TMT TMT; - - /* possible messages sent to the callback */ - typedef enum{ - TMT_MSG_MOVED, /* the cursor changed position */ - TMT_MSG_UPDATE, /* the screen image changed */ - TMT_MSG_ANSWER, /* the terminal responded to a query */ - TMT_MSG_BELL /* the terminal bell was rung */ - } tmt_msg_T; - - /* a callback for the library - * m is one of the message constants above - * vt is a pointer to the vt structure - * r is NULL for TMT_MSG_BELL - * is a pointer to the cursor's TMTPOINT for TMT_MSG_MOVED - * is a pointer to the terminal's TMTSCREEN for TMT_MSG_UPDATE - * is a pointer to a string for TMT_MSG_ANSWER - * p is whatever was passed to tmt_open (see below). - */ - typedef void (*TMTCALLBACK)(tmt_msg_t m, struct TMT *vt, - const void *r, void *p); - - /* color definitions */ - typedef enum{ - TMT_COLOR_BLACK, - TMT_COLOR_RED, - TMT_COLOR_GREEN, - TMT_COLOR_YELLOW, - TMT_COLOR_BLUE, - TMT_COLOR_MAGENTA, - TMT_COLOR_CYAN, - TMT_COLOR_WHITE, - TMT_COLOR_DEFAULT /* whatever the host terminal wants it to mean */ - } tmt_color_t; - - /* graphical rendition */ - typedef struct TMTATTRS TMTATTRS; - struct TMTATTRS{ - bool bold; /* character is bold */ - bool dim; /* character is half-bright */ - bool underline; /* character is underlined */ - bool blink; /* character is blinking */ - bool reverse; /* character is in reverse video */ - bool invisible; /* character is invisible */ - tmt_color_t fg; /* character foreground color */ - tmt_color_t bg; /* character background color */ - }; - - /* characters */ - typedef struct TMTCHAR TMTCHAR; - struct TMTCHAR{ - wchar_t c; /* the character */ - TMTATTRS a; /* its rendition */ - }; - - /* a position on the screen; upper left corner is 0,0 */ - typedef struct TMTPOINT TMTPOINT; - struct TMTPOINT{ - size_t r; /* row */ - size_t c; /* column */ - }; - - /* a line of characters on the screen; - * every line is always as wide as the screen - */ - typedef struct TMTLINE TMTLINE; - struct TMTLINE{ - bool dirty; /* line has changed since it was last drawn */ - TMTCHAR chars; /* the contents of the line */ - }; - - /* a virtual terminal screen image */ - typedef struct TMTSCREEN TMTSCREEN; - struct TMTSCREEN{ - size_t nline; /* number of rows */ - size_t ncol; /* number of columns */ - TMTLINE **lines; /* the lines on the screen */ - }; - -Functions ---------- - -`TMT *tmt_open(size_t nrows, size_t ncols, TMTCALLBACK cb, VOID *p, const wchar *acs);` - Creates a new virtual terminal, with `nrows` rows and `ncols` columns. - The callback `cb` will be called on updates, and passed `p` as a final - argument. See the definition of `tmt_msg_t` above for possible values - of each argument to the callback. - - Terminals must have a size of at least two rows and two columns. - - `acs` specifies the characters to use when in Alternate Character Set - (ACS) mode. The default string (used if `NULL` is specified) is:: - - L"><^v#+:o##+++++~---_++++|<>*!fo" - - See `Alternate Character Set`_ for more information. - - Note that the callback must be ready to be called immediately, as - it will be called after initialization of the terminal is done, but - before the call to `tmt_open` returns. - -`void tmt_close(TMT *vt)` - Close and free all resources associated with `vt`. - -`bool tmt_resize(TMT *vt, size_t nrows, size_t ncols)` - Resize the virtual terminal to have `nrows` rows and `ncols` columns. - The contents of the area in common between the two sizes will be preserved. - - Terminals must have a size of at least two rows and two columns. - - If this function returns false, the resize failed (only possible in - out-of-memory conditions or invalid sizes). If this happens, the terminal - is trashed and the only valid operation is the close the terminal. - -`void tmt_write(TMT *vt, const char *s, size_t n);` - Write the provided string to the terminal, interpreting any escape - sequences contained threin, and update the screen image. The last - argument is the length of the input. If set to 0, the length is - determined using `strlen`. - - The terminal's callback function may be invoked one or more times before - a call to this function returns. - - The string is converted internally to a wide-character string using the - system's current multibyte encoding. Each terminal maintains a private - multibyte decoding state, and correctly handles mulitbyte characters that - span multiple calls to this function (that is, the final byte(s) of `s` - may be a partial mulitbyte character to be completed on the next call). - -`const TMTSCREEN *tmt_screen(const TMT *vt);` - Returns a pointer to the terminal's screen image. - -`const TMTPOINT *tmt_cursor(cosnt TMT *vt);` - Returns a pointer to the terminal's cursor position. - -`void tmt_clean(TMT *vt);` - Call this after receiving a `TMT_MSG_UPDATE` or `TMT_MSG_MOVED` callback - to let the library know that the program has handled all reported changes - to the screen image. - -`void tmt_reset(TMT *vt);` - Resets the virtual terminal to its default state (colors, multibyte - decoding state, rendition, etc). - -Special Keys ------------- - -To send special keys to a program that is using libtmt for its display, -write one of the `TMT_KEY_*` strings to that program's standard input -(*not* to libtmt; it makes no sense to send any of these constants to -libtmt itself). - -The following macros are defined, and are all constant strings: - -- TMT_KEY_UP -- TMT_KEY_DOWN -- TMT_KEY_RIGHT -- TMT_KEY_LEFT -- TMT_KEY_HOME -- TMT_KEY_END -- TMT_KEY_INSERT -- TMT_KEY_BACKSPACE -- TMT_KEY_ESCAPE -- TMT_KEY_BACK_TAB -- TMT_KEY_PAGE_UP -- TMT_KEY_PAGE_DOWN -- TMT_KEY_F1 through TMT_KEY_F10 - -Note also that the classic PC console sent the enter key as -a carriage return, not a linefeed. Many programs don't care, -but some do. - -Compile-Time Options --------------------- - -There are two preprocessor macros that affect libtmt: - -`TMT_INVALID_CHAR` - Define this to a wide-character. This character will be added to - the virtual display when an invalid multibyte character sequence - is encountered. - - By default (if you don't define it as something else before compiling), - this is `((wchar_t)0xfffd)`, which is the codepoint for the Unicode - 'REPLACEMENT CHARACTER'. Note that your system might not use Unicode, - and its wide-character type might not be able to store a constant as - large as `0xfffd`, in which case you'll want to use an alternative. - -`TMT_HAS_WCWIDTH` - By default, libtmt uses only standard C99 features. If you define - TMT_HAS_WCWIDTH before compiling, libtmt will use the POSIX `wcwidth` - function to detect combining characters. - - Note that combining characters are still not handled particularly - well, regardless of whether this was defined. Also note that what - your C library's `wcwidth` considers a combining character and what - the written language in question considers one could be different. - -Alternate Character Set ------------------------ - -The terminal can be switched to and from its "Alternate Character Set" (ACS) -using escape sequences. The ACS traditionally contained box-drawing and other -semigraphic characters. - -The characters in the ACS are configurable at runtime, by passing a wide string -to `tmt_open`. The default if none is provided (i.e. the argument is `NULL`) -uses ASCII characters to approximate the traditional characters. - -The string passed to `tmt_open` must be 31 characters long. The characters, -and their default ASCII-safe values, are in order: - -- RIGHT ARROW ">" -- LEFT ARROW "<" -- UP ARROW "^" -- DOWN ARROW "v" -- BLOCK "#" -- DIAMOND "+" -- CHECKERBOARD "#" -- DEGREE "o" -- PLUS/MINUS "+" -- BOARD ":" -- LOWER RIGHT CORNER "+" -- UPPER RIGHT CORNER "+" -- UPPER LEFT CORNER "+" -- LOWER LEFT CORNER "+" -- CROSS "+" -- SCAN LINE 1 "~" -- SCAN LINE 3 "-" -- HORIZONTAL LINE "-" -- SCAN LINE 7 "-" -- SCAN LINE 9 "_" -- LEFT TEE "+" -- RIGHT TEE "+" -- BOTTOM TEE "+" -- TOP TEE "+" -- VERTICAL LINE "|" -- LESS THAN OR EQUAL "<" -- GREATER THAN OR EQUAL ">" -- PI "*" -- NOT EQUAL "!" -- POUND STERLING "f" -- BULLET "o" - -If your system's wide character type's character set corresponds to the -Universal Character Set (UCS/Unicode), the following wide string is a -good option to use:: - - L"→←↑↓■◆▒°±▒┘┐┌└┼⎺───⎽├┤┴┬│≤≥π≠£•" - -**Note that multibyte decoding is disabled in ACS mode.** The traditional -implementations of the "ansi" terminal type (i.e. IBM PCs and compatibles) -had no concept of multibyte encodings and used the character codes -outside the ASCII range for various special semigraphic characters. -(Technically they had an entire alternate character set as well via the -code page mechanism, but that's beyond the scope of this explanation.) - -The end result is that the terminfo definition of "ansi" sends characters -with the high bit set when in ACS mode. This breaks several multibyte -encoding schemes (including, most importantly, UTF-8). - -As a result, libtmt does not attempt to decode multibyte characters in -ACS mode, since that would break the multibyte encoding, the semigraphic -characters, or both. - -In general this isn't a problem, since programs explicitly switch to and -from ACS mode using escape sequences. - -When in ACS mode, bytes that are not special members of the alternate -character set (that is, bytes not mapped to the string provided to -`tmt_open`) are passed unchanged to the terminal. - -Supported Input and Escape Sequences -==================================== - -Internally libtmt uses your C library's/compiler's idea of a wide character -for all characters, so you should be able to use whatever characters you want -when writing to the virtual terminal (but see `Alternate Character Set`_). - -The following escape sequences are recognized and will be processed -specially. - -In the descriptions below, "ESC" means a literal escape character and "Ps" -means zero or more decimal numeric arguments separated by semicolons. -In descriptions "P1", "P2", etc, refer to the first parameter, second -parameter, and so on. If a required parameter is omitted, it defaults -to the smallest meaningful value (zero if the command accepts zero as -an argument, one otherwise). Any number of parameters may be passed, -but any after the first eight are ignored. - -Unless explicitly stated below, cursor motions past the edges of the screen -are ignored and do not result in scrolling. When characters are moved, -the spaces left behind are filled with blanks and any characters moved -off the edges of the screen are lost. - -====================== ====================================================================== -Sequence Action -====================== ====================================================================== -0x07 (Bell) Callback with TMT_MSG_BELL -0x08 (Backspace) Cursor left one cell -0x09 (Tab) Cursor to next tab stop or end of line -0x0a (Carriage Return) Cursor to first cell on this line -0x0d (Linefeed) Cursor to same column one line down, scroll if needed -ESC H Set a tabstop in this column -ESC 7 Save cursor position and current graphical state -ESC 8 Restore saved cursor position and current graphical state -ESC c Reset terminal to default state -ESC [ Ps A Cursor up P1 rows -ESC [ Ps B Cursor down P1 rows -ESC [ Ps C Cursor right P1 columns -ESC [ Ps D Cursor left P1 columns -ESC [ Ps E Cursor to first column of line P1 rows down from current -ESC [ Ps F Cursor to first column of line P1 rows up from current -ESC [ Ps G Cursor to column P1 -ESC [ Ps d Cursor to row P1 -ESC [ Ps H Cursor to row P1, column P2 -ESC [ Ps f Alias for ESC [ Ps H -ESC [ Ps I Cursor to next tab stop -ESC [ Ps J Clear screen - P1 == 0: from cursor to end of screen - P1 == 1: from beginning of screen to cursor - P1 == 2: entire screen -ESC [ Ps K Clear line - P1 == 0: from cursor to end of line - P1 == 1: from beginning of line to cursor - P1 == 2: entire line -ESC [ Ps L Insert P1 lines at cursor, scrolling lines below down -ESC [ Ps M Delete P1 lines at cursor, scrolling lines below up -ESC [ Ps P Delete P1 characters at cursor, moving characters to the right over -ESC [ Ps S Scroll screen up P1 lines -ESC [ Ps T Scroll screen down P1 lines -ESC [ Ps X Erase P1 characters at cursor (overwrite with spaces) -ESC [ Ps Z Go to previous tab stop -ESC [ Ps b Repeat previous character P1 times -ESC [ Ps c Callback with TMT_MSG_ANSWER "\033[?6c" -ESC [ Ps g If P1 == 3, clear all tabstops -ESC [ Ps h If P1 == 25, show the cursor (if it was hidden) -ESC [ Ps m Change graphical rendition state; see below -ESC [ Ps l If P1 == 25, hide the cursor -ESC [ Ps n If P1 == 6, callback with TMT_MSG_ANSWER "\033[%d;%dR" - with cursor row, column -ESC [ Ps s Alias for ESC 7 -ESC [ Ps u Alias for ESC 8 -ESC [ Ps @ Insert P1 blank spaces at cursor, moving characters to the right over -====================== ====================================================================== - -For the `ESC [ Ps m` escape sequence above ("Set Graphic Rendition"), -up to eight parameters may be passed; the results are cumulative: - -============== ================================================= -Rendition Code Meaning -============== ================================================= -0 Reset all graphic rendition attributes to default -1 Bold -2 Dim (half bright) -4 Underline -5 Blink -7 Reverse video -8 Invisible -10 Leave ACS mode -11 Enter ACS mode -22 Bold off -23 Dim (half bright) off -24 Underline off -25 Blink off -27 Reverse video off -28 Invisible off -30 Foreground black -31 Foreground red -32 Foreground green -33 Foreground yellow -34 Foreground blue -35 Foreground magenta -36 Foreground cyan -37 Foreground white -39 Foreground default color -40 Background black -41 Background red -42 Background green -43 Background yellow -44 Background blue -45 Background magenta -46 Background cyan -47 Background white -49 Background default color -============== ================================================= - -Other escape sequences are recognized but ignored. This includes escape -sequences for switching out codesets (officially, all code sets are defined -as equivalent in libtmt), and the various "Media Copy" escape sequences -used to print output on paper (officially, there is no printer attached -to libtmt). - -Additionally, "?" characters are stripped out of escape sequence parameter -lists for compatibility purposes. - -Known Issues -============ - -- Combining characters are "handled" by ignoring them - (when compiled with `TMT_HAS_WCWIDTH`) or by printing them separately. -- Double-width characters are rendered as single-width invalid - characters. -- The documentation and error messages are available only in English. - -Frequently Asked Questions -========================== - -What programs work with libtmt? -------------------------------- - -Pretty much all of them. Any program that doesn't assume what terminal -it's running under should work without problem; this includes any program -that uses the terminfo, termcap, or (pd|n)?curses libraries. Any program -that assumes it's running under some specific terminal might fail if its -assumption is wrong, and not just under libtmt. - -I've tested quite a few applications in libtmt and they've worked flawlessly: -vim, GNU emacs, nano, cmus, mc (Midnight Commander), and others just work -with no changes. - -What programs don't work with libtmt? -------------------------------------- - -Breakage with libtmt is of two kinds: breakage due to assuming a terminal -type, and reduced functionality. - -In all my testing, I only found one program that didn't work correctly by -default with libtmt: recent versions of Debian's `apt`_ assume a terminal -with definable scrolling regions to draw a fancy progress bar during -package installation. Using apt in its default configuration in libtmt will -result in a corrupted display (that can be fixed by clearing the screen). - -.. _`apt`: https://wiki.debian.org/Apt - -In my honest opinion, this is a bug in apt: it shouldn't assume the type -of terminal it's running in. - -The second kind of breakage is when not all of a program's features are -available. The biggest missing feature here is mouse support: libtmt -doesn't, and probably never will, support mouse tracking. I know of many -programs that *can* use mouse tracking in a terminal, but I don't know -of any that *require* it. Most (if not all?) programs of this kind would -still be completely usable in libtmt. - -License -------- - -Copyright (c) 2017 Rob King -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -- Neither the name of the copyright holder nor the - names of contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS, -COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |