diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 13:04:01 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 13:04:01 +0300 |
| commit | dcebf9c7f954a55350b68d0ead1935612c4e2e05 (patch) | |
| tree | 3eb3e9f6154c6760bcb89a565f8ddc8f8b66cb90 /include | |
| parent | bd8222e615134c3ec5e7a07b6b1fa97c9bd4a471 (diff) | |
Rename the library to wsap_vtcore
ncurses installs <term.h> and defines struct term. In a file that
includes both headers, an ncurses TERMINAL * and this library's terminal
are silently the same type. The name wsap_vtcore avoids the clash.
The public header is now <wsap_vtcore/wsap_vtcore.h>. Every global
symbol uses the wsap_vtcore_ prefix, every macro uses WSAP_VTCORE_, and
the shared library is libwsap_vtcore.so.0. The default terminal name is
now "wsap_vtcore". The ISA override variable is WSAP_VTCORE_ISA.
No other behavior changes. The amalgamation writes wsap_vtcore.c and
wsap_vtcore.h.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Diffstat (limited to 'include')
| -rw-r--r-- | include/term/term.h | 492 | ||||
| -rw-r--r-- | include/term/term_input.h | 202 | ||||
| -rw-r--r-- | include/term/unicode/grapheme.h | 26 | ||||
| -rw-r--r-- | include/term/unicode/unicode.h | 6 | ||||
| -rw-r--r-- | include/term/unicode/width.h | 56 | ||||
| -rw-r--r-- | include/wsap_vtcore/unicode/grapheme.h | 26 | ||||
| -rw-r--r-- | include/wsap_vtcore/unicode/unicode.h | 6 | ||||
| -rw-r--r-- | include/wsap_vtcore/unicode/unicode_data.inc (renamed from include/term/unicode/unicode_data.inc) | 14 | ||||
| -rw-r--r-- | include/wsap_vtcore/unicode/utf8.h (renamed from include/term/unicode/utf8.h) | 70 | ||||
| -rw-r--r-- | include/wsap_vtcore/unicode/width.h | 56 | ||||
| -rw-r--r-- | include/wsap_vtcore/wsap_vtcore.h | 492 | ||||
| -rw-r--r-- | include/wsap_vtcore/wsap_vtcore_input.h | 202 | ||||
| -rw-r--r-- | include/wsap_vtcore/wsap_vtcore_types.h (renamed from include/term/term_types.h) | 14 |
13 files changed, 831 insertions, 831 deletions
diff --git a/include/term/term.h b/include/term/term.h deleted file mode 100644 index 8b98a25..0000000 --- a/include/term/term.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef TERM_H -#define TERM_H - -/* - * Terminal emulator core. - * - * A struct term parses the bytes that a program writes and keeps the screen, - * the history, and the modes. The application feeds bytes with term_feed() - * and reads state with the getters below. A renderer never reads the - * terminal directly: it copies the viewport into a struct term_snapshot and - * paints from that copy. - * - * All functions take the terminal as the first argument. Functions that take - * a const struct term do not change what it shows. Selection, history, link, - * directory, and pointer-shape queries return owned strings; release them - * with term_text_free(). - * - * Threads. Any thread can call any function. Each call that reads or changes - * a terminal enters its writer section, so calls on one terminal run one at a - * time. A thread that waits for the section sleeps. On POSIX the section is a - * mutex with priority inheritance where the platform has it. A snapshot - * belongs to one thread at a time. term_free() is the last call on a terminal. - */ - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#include "term_input.h" -#include "term_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct term; -struct term_snapshot; - -/* A row holds at most this many cells. */ -#define TERM_MAX_COLS 65535 -/* The history limit when term_options.scrollback is 0. */ -#define TERM_SCROLLBACK_DEFAULT 10000 -/* The largest term_options.scrollback. */ -#define TERM_SCROLLBACK_MAX 1000000 - -/* - * The version of this header. A host compares TERM_VERSION_CODE with - * term_version() to check that the library matches the header. - */ -#define TERM_VERSION(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) -#define TERM_VERSION_MAJOR 0 -#define TERM_VERSION_MINOR 1 -#define TERM_VERSION_PATCH 0 -#define TERM_VERSION_CODE TERM_VERSION(TERM_VERSION_MAJOR, TERM_VERSION_MINOR, TERM_VERSION_PATCH) - -/* - * Colors. A term_color is either a direct color (alpha 0xFF, then RGB) or a - * palette slot: an index 0-255, the default foreground, or the default - * background. A slot resolves when a snapshot is painted, so a theme change - * recolors text that is already on screen. - */ -typedef uint32_t term_color; - -#define TERM_COLOR_SLOT 0x01000000u -/* The palette index of a slot; see struct term_view.palette. */ -#define TERM_COLOR_SLOT_INDEX 0x1FFu -#define TERM_COLOR_FG (TERM_COLOR_SLOT | 0x100u) -#define TERM_COLOR_BG (TERM_COLOR_SLOT | 0x101u) - -static inline term_color term_color_index(int n) -{ - return TERM_COLOR_SLOT | ((uint32_t)n & 0xFFu); -} - -static inline term_color term_color_rgb(uint8_t r, uint8_t g, uint8_t b) -{ - return 0xFF000000u | (uint32_t)r << 16 | (uint32_t)g << 8 | b; -} - -static inline bool term_color_is_slot(term_color c) -{ - return (c >> 24) == (TERM_COLOR_SLOT >> 24); -} - -/* Parse an X11 or OSC color specification ("#rgb", "rgb:r/g/b", ...). */ -TERM_API bool term_color_parse(const char *spec, uint32_t *argb); - -/* The colors a terminal starts with. All values are ARGB. An all-zero theme - * selects the built-in theme. */ -struct term_theme { - uint32_t fg, bg, cursor; - uint32_t ansi[16]; -}; - -/* Fill theme with the built-in theme. */ -TERM_API void term_theme_default(struct term_theme *theme); -/* Fill theme with the high-contrast theme. */ -TERM_API void term_theme_high_contrast(struct term_theme *theme); -/* Sets one palette key: foreground, background, or color0 to color15. - * An empty value resets the key to the built-in theme. False, with no - * change, for an unknown key or a bad color. */ -TERM_API bool term_theme_set_key(struct term_theme *p, const char *key, const char *val); - -enum term_cursor_style { - TERM_CURSOR_BLOCK, - TERM_CURSOR_UNDERLINE, - TERM_CURSOR_BAR, -}; - -/* Mouse reporting modes and encodings. The values are the DEC mode numbers. */ -enum term_mouse { - TERM_MOUSE_OFF = 0, - TERM_MOUSE_X10 = 9, - TERM_MOUSE_NORMAL = 1000, - TERM_MOUSE_BUTTON = 1002, - TERM_MOUSE_ANY = 1003, -}; - -enum term_mouse_encoding { - TERM_MOUSE_ENC_X10 = 0, - TERM_MOUSE_ENC_UTF8 = 1005, - TERM_MOUSE_ENC_SGR = 1006, - TERM_MOUSE_ENC_URXVT = 1015, - TERM_MOUSE_ENC_SGR_PIXELS = 1016, -}; - -/* - * Callbacks. They run inside term_feed() and term_focus(), on the thread - * that calls those functions. A callback must not call back into the - * terminal. String arguments are valid only during the call. - */ -struct term_callbacks { - void *ud; - /* Bytes the terminal sends back to the program (replies to queries). */ - void (*reply)(void *ud, const char *bytes, size_t len); - void (*title)(void *ud, const char *title); - /* - * OSC 52 clipboard callback. - * selection names the target clipboard buffer(s), commonly: - * "c" - clipboard (system clipboard) - * "p" - primary selection (X11 primary) - * "q" - secondary selection - * "s" - select selection - * "0".."7" - cut buffers 0 to 7 - * A parameter may contain multiple targets (e.g. "cp"). - * data contains decoded bytes of length len. - */ - void (*clipboard)(void *ud, const char *selection, const char *data, size_t len); - void (*notify)(void *ud, const char *title, const char *body); - void (*bell)(void *ud); - /* Parser trace lines for debugging. NULL turns tracing off. The line has no newline. */ - void (*trace)(void *ud, const char *line); -}; - -/* - * Options for term_new(). An all-zero value is valid. A size component of 0 - * selects 80 columns or 24 rows. A negative component, or columns above - * TERM_MAX_COLS, makes term_new() fail. A scrollback below 0 or above - * TERM_SCROLLBACK_MAX fails too. - * cursor_style must be a value of enum term_cursor_style. - */ -struct term_options { - struct term_vector2i size; /* columns and rows */ - int scrollback; /* history lines; 0 selects TERM_SCROLLBACK_DEFAULT */ - struct term_theme theme; - enum term_cursor_style cursor_style; - bool cursor_steady; /* false: the cursor blinks */ - /* - * The terminal's name. Programs read it with XTVERSION and XTGETTCAP. - * It is also the title of a notification that has none. NULL or "" - * selects "term". Otherwise 1 to 63 printable ASCII bytes, or term_new() - * returns NULL. term_new() copies the name. - */ - const char *name; - struct term_callbacks callbacks; - /* Must be zero. term_new() returns NULL if any word is nonzero, so a - * later version can give a word a meaning. */ - uint32_t reserved[8]; -}; - -/* The Unicode version of the width tables, such as "18.0.0". A host can - * pass it to programs as UNICODE_VERSION. */ -TERM_API const char *term_unicode_version(void); -/* The TERM_VERSION_CODE the library was built with. */ -TERM_API unsigned term_version(void); - -/* The length of the prefix of buf made of bytes in [0x20, hi). With hi - * 0x7f, it finds a run of printable ASCII in UTF-8 text, so a host can - * skip shaping for it. Any thread can call it. */ -TERM_API size_t term_scan_printable_span(const char *buf, size_t len, unsigned char hi); - -/* The instruction set level of the running code: "base", "avx2", "avx512", - * or "neon". On x86-64, the first term_new() picks the highest level the CPU - * supports. Set TERM_HEADLESS_ISA to a lower level to force it, for tests - * and comparisons. */ -TERM_API const char *term_isa(void); - -/* NULL when memory runs out or an option is invalid. */ -TERM_API struct term *term_new(const struct term_options *opt); -TERM_API void term_free(struct term *t); - -/* Hold the writer section across several calls, so that no other thread - * changes the terminal between them. The section is a mutex, and a waiting - * thread sleeps. Keep it short. The thread that holds it can call every - * function, and it can enter the section again. Each term_lock() needs one - * term_unlock(). */ -TERM_API void term_lock(struct term *t); -TERM_API void term_unlock(struct term *t); - -/* Change the size in cells. Returns false, and the terminal is unchanged, - * when a component is below 1, when cols is above TERM_MAX_COLS, or when - * memory runs out. The screen reflows to the new width. */ -TERM_API bool term_resize(struct term *t, struct term_vector2i size); - -/* Replace the theme. A different theme also drops the colors that the - * program set with OSC; the same theme changes nothing. */ -TERM_API void term_set_theme(struct term *t, const struct term_theme *theme); - -/* The cursor style that DECSCUSR 0 and a reset restore. */ -TERM_API void term_set_cursor_default(struct term *t, enum term_cursor_style style, bool steady); - -/* - * Bytes from the program. - * - * TERM_FEED_ONLCR: a line feed also returns the cursor to column 0, as a tty - * with OPOST and ONLCR does. Set it when the bytes did not pass through the - * tty output processing (for example the fast pipe). - */ -enum term_feed_flags { - TERM_FEED_ONLCR = 1u << 0, -}; - -/* - * Feed bytes from the program. Returns false, and changes nothing, when t is - * NULL, when bytes is NULL and len is not 0, or when flags has a bit that is - * not in enum term_feed_flags. A len of 0 is a no-op that returns true. - */ -TERM_API bool term_feed(struct term *t, const char *bytes, size_t len, unsigned flags); - -/* Report a focus change. The terminal replies only in focus-event mode. */ -TERM_API void term_focus(struct term *t, bool focused); - -/* Modes that affect how the application encodes input. */ -struct term_modes { - unsigned keyboard; /* kitty keyboard protocol flags */ - enum term_mouse mouse; - enum term_mouse_encoding mouse_encoding; - struct term_vector2i grid; /* columns and rows */ - bool app_cursor; /* DECCKM */ - bool app_keypad; /* DECKPAM */ - bool backarrow_bs; /* DECBKM */ - bool bracketed_paste; - bool focus_events; - bool alternate; /* the alternate screen is active */ - bool reverse_video; /* DECSCNM */ - bool synchronized; /* mode 2026 */ -}; - -struct term_cursor { - struct term_vector2i pos; - enum term_cursor_style style; - bool visible; - bool blink; -}; - -TERM_API struct term_vector2i term_size(const struct term *t); -TERM_API struct term_modes term_modes(const struct term *t); - -/* - * Encode an input event as the bytes the program expects. Get modes from - * term_modes(). Record ev in keyboard with term_keyboard_update() first. Send - * the bytes to the program yourself. - */ -TERM_API struct term_input_result term_input_encode_key( - const struct term_keyboard_state *keyboard, - const struct term_key_event *ev, - const struct term_modes *modes, - char *buf, size_t capacity -); - -TERM_API struct term_input_result term_input_encode_mouse( - const struct term_mouse_event *ev, - const struct term_modes *modes, - char *buf, size_t capacity -); - -/* Bytes term_input_encode_paste() adds to the text at most. */ -#define TERM_PASTE_EXTRA 12 - -/* - * Encode pasted text. Drop control characters and bidi controls, so the - * program sees only what the user saw. Send a line break as CR. Add the - * bracketed-paste markers when the program asked for them. A buffer of - * len + TERM_PASTE_EXTRA bytes is always large enough. Text that is empty - * after the filter gives TERM_INPUT_CONSUMED. - */ -TERM_API struct term_input_result term_input_encode_paste( - const struct term_modes *modes, - const char *text, size_t len, - char *buf, size_t capacity -); -/* The cursor in screen coordinates (not the viewport). */ -TERM_API struct term_cursor term_cursor(const struct term *t); -/* Owned, NUL-terminated text from OSC 7 and OSC 22. NULL when unavailable - * or allocation fails. The strings stay valid after the terminal changes - * or is freed. Release them with term_text_free(). */ -TERM_API char *term_cwd(const struct term *t); -TERM_API char *term_pointer_shape(const struct term *t); -/* Release any owned text returned by the library. NULL is safe. */ -TERM_API void term_text_free(char *text); - -/* - * Viewport. The viewport shows as many rows as the screen. Offset 0 shows - * the live screen; a larger offset shows that many rows of history above it. - * The alternate screen has no history, so its offset is always 0. - */ -struct term_scrollback { - int offset; /* rows between the viewport and the live screen */ - int total; /* history rows at the current width */ -}; - -TERM_API struct term_scrollback term_scrollback(const struct term *t); -/* Scroll the viewport. A positive count moves back into history. */ -TERM_API void term_scroll(struct term *t, int lines); -TERM_API void term_scroll_to(struct term *t, int offset); - -/* - * Selection, in viewport coordinates. A selection starts at one cell and - * extends to another; the unit widens both ends to words or whole lines. - * The terminal clears the selection when the text under it changes. - */ -enum term_select_unit { - TERM_SELECT_CELL, - TERM_SELECT_WORD, - TERM_SELECT_LINE, -}; - -/* Start a selection at cell. For TERM_SELECT_CELL, right_half means the - * pointer is on the right half of the cell, so the selection starts after it. - * Returns false when memory runs out; the selection is then unchanged. */ -TERM_API bool term_select_start(struct term *t, struct term_vector2i cell, bool right_half, - enum term_select_unit unit); -/* Extend the selection from its start to cell. Returns false when memory runs - * out; the selection is then unchanged. */ -TERM_API bool term_select_extend(struct term *t, struct term_vector2i cell, bool right_half); -TERM_API void term_select_clear(struct term *t); -TERM_API bool term_has_selection(const struct term *t); -/* Owned, NUL-terminated UTF-8 of the selection. NULL when nothing is - * selected or allocation fails; a selection of blanks may produce an empty - * string. Capture is atomic with respect to other calls on t. Release the - * result with term_text_free(). */ -TERM_API char *term_selection_text(const struct term *t); -/* Owned OSC 8 link or detected URL at a viewport cell. NULL when there is - * no link or allocation fails. Release the result with term_text_free(). */ -TERM_API char *term_link_at(const struct term *t, struct term_vector2i cell); - -/* Cell attributes share the write core's bit layout. Underline styles are - * mutually exclusive flags, not a shifted enum; use term_attr_underline(). */ -enum term_attr { - TERM_ATTR_BOLD = 1u << 0, - TERM_ATTR_ITALIC = 1u << 1, - TERM_ATTR_UNDERLINE = 1u << 2, - TERM_ATTR_STRIKE = 1u << 3, - TERM_ATTR_OVERLINE = 1u << 4, - TERM_ATTR_EMOJI = 1u << 5, /* the text requested emoji presentation */ - TERM_ATTR_TEXT = 1u << 6, /* the text requested text presentation */ - TERM_ATTR_FAINT = 1u << 10, - TERM_ATTR_DOUBLE_UNDERLINE = 1u << 11, - TERM_ATTR_CURLY_UNDERLINE = 1u << 12, - TERM_ATTR_DOTTED_UNDERLINE = 1u << 13, - TERM_ATTR_DASHED_UNDERLINE = 1u << 14, - TERM_ATTR_LINK = 1u << 15, -}; - -#define TERM_ATTR_UNDERLINE_MASK \ - (TERM_ATTR_UNDERLINE | TERM_ATTR_DOUBLE_UNDERLINE | TERM_ATTR_CURLY_UNDERLINE | \ - TERM_ATTR_DOTTED_UNDERLINE | TERM_ATTR_DASHED_UNDERLINE) - -enum term_underline { - TERM_UNDERLINE_NONE, - TERM_UNDERLINE_SINGLE, - TERM_UNDERLINE_DOUBLE, - TERM_UNDERLINE_CURLY, - TERM_UNDERLINE_DOTTED, - TERM_UNDERLINE_DASHED, -}; - -static inline enum term_underline term_attr_underline(uint16_t attrs) -{ - if (attrs & TERM_ATTR_DOUBLE_UNDERLINE) return TERM_UNDERLINE_DOUBLE; - if (attrs & TERM_ATTR_CURLY_UNDERLINE) return TERM_UNDERLINE_CURLY; - if (attrs & TERM_ATTR_DOTTED_UNDERLINE) return TERM_UNDERLINE_DOTTED; - if (attrs & TERM_ATTR_DASHED_UNDERLINE) return TERM_UNDERLINE_DASHED; - return attrs & TERM_ATTR_UNDERLINE ? TERM_UNDERLINE_SINGLE : TERM_UNDERLINE_NONE; -} - -/* text refers to a grapheme cluster in the snapshot; see term_snapshot_cluster(). */ -#define TERM_TEXT_CLUSTER 0x80000000u - -/* One cell as a snapshot shows it. */ -struct term_cell { - uint32_t text; /* a code point, TERM_TEXT_CLUSTER | n, or 0 for an empty cell */ - term_color fg, bg; - uint16_t attrs; /* enum term_attr flags; at most one underline flag */ - uint8_t width; /* 1; 2 for a wide glyph; 0 for the right half of a wide glyph */ - uint8_t reserved; -}; - -#ifdef __cplusplus -static_assert(sizeof(struct term_cell) == 16, "four cells fill one 64-byte line"); -#else -_Static_assert(sizeof(struct term_cell) == 16, "four cells fill one 64-byte line"); -#endif - -/* - * Snapshot: a copy of the viewport for a renderer. It holds no pointer into - * the terminal, so it stays valid while the terminal changes. One terminal - * may have several snapshots, for example a window and a tab preview. - */ -TERM_API struct term_snapshot *term_snapshot_new(void); -TERM_API void term_snapshot_free(struct term_snapshot *s); - -/* Copy the viewport of t into s. Keep rows with unchanged content keys. - * Update the history view index and refine counts for visible wide lines. - * Return false when memory runs out. The snapshot then keeps its previous content. */ -TERM_API bool term_snapshot_update(struct term_snapshot *s, struct term *t); - -/* Palette entries of struct term_view.palette after the 256 indexed colors. */ -enum { - TERM_PALETTE_FG = 256, - TERM_PALETTE_BG = 257, - TERM_PALETTE_CURSOR = 258, - TERM_PALETTE_SIZE = 259, -}; - -struct term_view { - struct term_vector2i size; - struct term_cursor cursor; /* viewport coordinates; not visible when scrolled away */ - int scroll_offset; - /* Rows the content moved up since the previous update, when that movement - * explains the change; otherwise 0. */ - int scrolled; - bool reverse_video; - /* Changes when any part of the view changes. */ - uint64_t version; - /* Changes when a palette entry changes. */ - uint64_t palette_version; - const uint32_t *palette; /* TERM_PALETTE_SIZE ARGB entries */ -}; - -/* The view of s, NULL for a NULL s. The view and view->palette keep their - * address until term_snapshot_free(); their contents change on each update. */ -TERM_API const struct term_view *term_snapshot_view(const struct term_snapshot *s); -/* The cells of viewport row y: view->size.x entries. NULL when y is outside - * the viewport or s is NULL. An update can move the cells, so the pointer is - * valid only until the next term_snapshot_update() or term_snapshot_free() of s. */ -TERM_API const struct term_cell *term_snapshot_row(const struct term_snapshot *s, int y); -/* An identity for the content of row y. Two rows with the same key hold the - * same cells, also when the content moved to another row. 0 when y is outside - * the viewport or s is NULL. */ -TERM_API uint64_t term_snapshot_row_key(const struct term_snapshot *s, int y); - -/* Number of rows in history above the screen. 0 if alternate screen or no history. */ -TERM_API int term_history_rows(const struct term *t); -/* Owned, NUL-terminated UTF-8 of up to max_rows history rows before the - * current viewport. Join soft-wrapped rows and end closed lines with a - * newline. Does not change the selection. No history or max_rows <= 0 gives - * an empty string; NULL means allocation failed or t is NULL. Release the - * result with term_text_free(). */ -TERM_API char *term_history_text(struct term *t, int max_rows); -/* The selected columns of viewport row y, end exclusive. An empty span when y - * is outside the viewport or s is NULL. */ -TERM_API struct term_span term_snapshot_row_selection(const struct term_snapshot *s, int y); - -/* The code points of a cluster cell. Returns the number of code points and - * writes at most cap of them. Writes nothing when cps is NULL or cap is 0. - * Returns 0 when s is NULL. */ -TERM_API int term_snapshot_cluster(const struct term_snapshot *s, uint32_t text, uint32_t *cps, int cap); - -/* The ARGB value of a color in a view. */ -static inline uint32_t term_view_color(const struct term_view *v, term_color c) -{ - if (!term_color_is_slot(c)) - return c; - return v->palette[c & TERM_COLOR_SLOT_INDEX]; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/term/term_input.h b/include/term/term_input.h deleted file mode 100644 index 19d9355..0000000 --- a/include/term/term_input.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef TERM_INPUT_H -#define TERM_INPUT_H - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include "term_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum term_key { - TERM_KEY_NONE = 0, - - TERM_KEY_RETURN, - TERM_KEY_BACKSPACE, - TERM_KEY_TAB, - TERM_KEY_ESCAPE, - - TERM_KEY_UP, - TERM_KEY_DOWN, - TERM_KEY_RIGHT, - TERM_KEY_LEFT, - TERM_KEY_HOME, - TERM_KEY_END, - TERM_KEY_PAGE_UP, - TERM_KEY_PAGE_DOWN, - TERM_KEY_INSERT, - TERM_KEY_DELETE, - - TERM_KEY_F1, TERM_KEY_F2, TERM_KEY_F3, TERM_KEY_F4, TERM_KEY_F5, - TERM_KEY_F6, TERM_KEY_F7, TERM_KEY_F8, TERM_KEY_F9, TERM_KEY_F10, - TERM_KEY_F11, TERM_KEY_F12, TERM_KEY_F13, TERM_KEY_F14, TERM_KEY_F15, - TERM_KEY_F16, TERM_KEY_F17, TERM_KEY_F18, TERM_KEY_F19, TERM_KEY_F20, - TERM_KEY_F21, TERM_KEY_F22, TERM_KEY_F23, TERM_KEY_F24, TERM_KEY_F25, - TERM_KEY_F26, TERM_KEY_F27, TERM_KEY_F28, TERM_KEY_F29, TERM_KEY_F30, - TERM_KEY_F31, TERM_KEY_F32, TERM_KEY_F33, TERM_KEY_F34, TERM_KEY_F35, - - TERM_KEY_KP_0, TERM_KEY_KP_1, TERM_KEY_KP_2, TERM_KEY_KP_3, TERM_KEY_KP_4, - TERM_KEY_KP_5, TERM_KEY_KP_6, TERM_KEY_KP_7, TERM_KEY_KP_8, TERM_KEY_KP_9, - TERM_KEY_KP_DECIMAL, - TERM_KEY_KP_ENTER, - TERM_KEY_KP_ADD, - TERM_KEY_KP_SUBTRACT, - TERM_KEY_KP_MULTIPLY, - TERM_KEY_KP_DIVIDE, - TERM_KEY_KP_EQUAL, - TERM_KEY_KP_SEPARATOR, - TERM_KEY_KP_LEFT, - TERM_KEY_KP_RIGHT, - TERM_KEY_KP_UP, - TERM_KEY_KP_DOWN, - TERM_KEY_KP_PAGE_UP, - TERM_KEY_KP_PAGE_DOWN, - TERM_KEY_KP_HOME, - TERM_KEY_KP_END, - TERM_KEY_KP_INSERT, - TERM_KEY_KP_DELETE, - TERM_KEY_KP_BEGIN, - - TERM_KEY_CAPS_LOCK, - TERM_KEY_SCROLL_LOCK, - TERM_KEY_NUM_LOCK, - TERM_KEY_PRINT_SCREEN, - TERM_KEY_PAUSE, - TERM_KEY_MENU, - - TERM_KEY_MEDIA_PLAY, - TERM_KEY_MEDIA_PAUSE, - TERM_KEY_MEDIA_STOP, - TERM_KEY_MEDIA_FORWARD, - TERM_KEY_MEDIA_REWIND, - TERM_KEY_MEDIA_NEXT, - TERM_KEY_MEDIA_PREV, - TERM_KEY_MEDIA_RECORD, - TERM_KEY_VOLUME_DOWN, - TERM_KEY_VOLUME_UP, - TERM_KEY_MUTE, - - TERM_KEY_LSHIFT, - TERM_KEY_LCTRL, - TERM_KEY_LALT, - TERM_KEY_LSUPER, - TERM_KEY_LHYPER, - TERM_KEY_LMETA, - TERM_KEY_RSHIFT, - TERM_KEY_RCTRL, - TERM_KEY_RALT, - TERM_KEY_RSUPER, - TERM_KEY_RHYPER, - TERM_KEY_RMETA, - TERM_KEY_ISO_LEVEL3_SHIFT, - TERM_KEY_ISO_LEVEL5_SHIFT, - - TERM_KEY_COUNT -}; - -enum term_mod { - TERM_MOD_SHIFT = 1, - TERM_MOD_ALT = 2, - TERM_MOD_CTRL = 4, - TERM_MOD_SUPER = 8, - TERM_MOD_HYPER = 16, - TERM_MOD_META = 32, - TERM_MOD_CAPS = 64, - TERM_MOD_NUM = 128, -}; - -enum term_key_action { - TERM_KEY_PRESS = 1, - TERM_KEY_REPEAT = 2, - TERM_KEY_RELEASE = 3, -}; - -enum term_mouse_button { - TERM_MOUSE_BUTTON_PRIMARY = 0, - TERM_MOUSE_BUTTON_MIDDLE, - TERM_MOUSE_BUTTON_SECONDARY, - TERM_MOUSE_BUTTON_NONE, - /* Extra buttons 8 through 11 in xterm mouse reporting (encoded as 128..131). */ - TERM_MOUSE_BUTTON_EXTRA_1, - TERM_MOUSE_BUTTON_EXTRA_2, - TERM_MOUSE_BUTTON_EXTRA_3, - TERM_MOUSE_BUTTON_EXTRA_4, - TERM_MOUSE_WHEEL_UP = 16, - TERM_MOUSE_WHEEL_DOWN, - TERM_MOUSE_WHEEL_LEFT, - TERM_MOUSE_WHEEL_RIGHT, -}; - -enum term_mouse_event_kind { - TERM_MOUSE_PRESS = 0, - TERM_MOUSE_RELEASE, - TERM_MOUSE_MOTION, - TERM_MOUSE_SCROLL, - TERM_MOUSE_LEAVE, -}; - -struct term_key_event { - enum term_key_action action; - uint16_t key; /* enum term_key; TERM_KEY_NONE for a text key */ - uint16_t keypad; /* the TERM_KEY_KP_* key when the key is on the keypad */ - unsigned mods; /* enum term_mod */ - uint32_t codepoint; /* the code point of the key without modifiers */ - uint32_t shifted; /* the code point of the key with Shift */ - uint32_t base; /* the code point of the key in the US layout */ - uint32_t text; /* the code point the key types, or 0 */ - bool text_deferred; /* an input method sends the text later */ -}; - -struct term_mouse_event { - struct term_vector2i pos; /* Grid cell coordinates (col, row) */ - struct term_vector2i pixel; /* Absolute pixel position in terminal grid */ - /* - * Button identifier: - * - Press and release: the button that changed state (TERM_MOUSE_BUTTON_*). - * - Motion: the held button for drag events, or TERM_MOUSE_BUTTON_NONE for hover. - * - Scroll: the wheel direction (TERM_MOUSE_WHEEL_*). - */ - int button; - unsigned mods; - int scroll_lines; - float scroll_delta; - enum term_mouse_event_kind kind; -}; - -/* The keys that are down. An all-zero value has no keys down. */ -struct term_keyboard_state { - uint64_t down[(TERM_KEY_COUNT + 63) / 64]; -}; - -/* Record a press, repeat, or release in s. */ -TERM_API void term_keyboard_update(struct term_keyboard_state *s, const struct term_key_event *ev); -TERM_API bool term_keyboard_key_down(const struct term_keyboard_state *s, enum term_key key); - -/* Kitty keyboard protocol flags, as in term_modes.keyboard. */ -enum term_keyboard_flag { - TERM_KEYBOARD_DISAMBIGUATE = 1, - TERM_KEYBOARD_EVENT_TYPES = 2, - TERM_KEYBOARD_ALTERNATE_KEYS = 4, - TERM_KEYBOARD_ALL_KEYS = 8, - TERM_KEYBOARD_ASSOCIATED_TEXT = 16, -}; - -enum term_input_status { - TERM_INPUT_UNHANDLED = 0, /* the terminal does not use the event */ - TERM_INPUT_CONSUMED, /* the terminal uses the event but sends nothing */ - TERM_INPUT_BYTES, /* send the len bytes in buf to the program */ - TERM_INPUT_BUFFER_FULL, /* buf is too small; len is 0 */ -}; - -struct term_input_result { - size_t len; - enum term_input_status status; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* TERM_INPUT_H */ diff --git a/include/term/unicode/grapheme.h b/include/term/unicode/grapheme.h deleted file mode 100644 index 0946bb6..0000000 --- a/include/term/unicode/grapheme.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef TERM_UNICODE_GRAPHEME_H -#define TERM_UNICODE_GRAPHEME_H - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#define TERM_GRAPHEME_MAX_LEN 20 -#define TERM_GRAPHEME_HANDLE_BASE 0x7F000000u - -static inline bool term_grapheme_is_handle(uint32_t c) -{ - return c >= TERM_GRAPHEME_HANDLE_BASE; -} - -static inline bool term_grapheme_regional_indicator(uint32_t cp) -{ - return cp >= 0x1F1E6 && cp <= 0x1F1FF; -} - -static inline bool term_grapheme_emoji_modifier(uint32_t cp) -{ - return cp >= 0x1F3FB && cp <= 0x1F3FF; -} - -#endif diff --git a/include/term/unicode/unicode.h b/include/term/unicode/unicode.h deleted file mode 100644 index 932cbf6..0000000 --- a/include/term/unicode/unicode.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef TERM_UNICODE_UNICODE_H -#define TERM_UNICODE_UNICODE_H - -#include "width.h" - -#endif diff --git a/include/term/unicode/width.h b/include/term/unicode/width.h deleted file mode 100644 index a85ec77..0000000 --- a/include/term/unicode/width.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef TERM_UNICODE_WIDTH_H -#define TERM_UNICODE_WIDTH_H - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -struct term_unicode_range { uint32_t lo, hi; }; - -#include "unicode_data.inc" - -static inline bool term_in_ranges(const struct term_unicode_range *ranges, size_t count, uint32_t cp) -{ - if (count == 0 || cp < ranges[0].lo || cp > ranges[count - 1].hi) - return false; - const struct term_unicode_range *base = ranges; - size_t n = count; - while (n > 1) { - size_t half = n / 2; - base = (base[half].lo <= cp) ? base + half : base; - n -= half; - } - return cp <= base->hi; -} - -#define TERM_IN_TABLE(table, cp) term_in_ranges(table, sizeof(table) / sizeof(table[0]), cp) - -static inline int term_unicode_width(uint32_t cp) -{ - if (cp > 0x10FFFF || TERM_IN_TABLE(term_nonprintable, cp)) - return -1; - if (TERM_IN_TABLE(term_zero_width, cp)) - return 0; - return TERM_IN_TABLE(term_unicode_wide, cp) ? 2 : 1; -} - -static inline bool term_unicode_extended_pictographic(uint32_t cp) -{ - return TERM_IN_TABLE(term_extended_pictographic, cp); -} - -static inline bool term_unicode_emoji_presentation(uint32_t cp) -{ - return TERM_IN_TABLE(term_emoji_presentation, cp); -} - -static inline bool term_unicode_spacing_mark(uint32_t cp) -{ - if (cp < 0x903 || ((cp - 0xABEDu) < (0x11000u - 0xABEDu)) || cp > 0x1D281) - return false; - return TERM_IN_TABLE(term_spacing_mark, cp); -} - -#undef TERM_IN_TABLE - -#endif diff --git a/include/wsap_vtcore/unicode/grapheme.h b/include/wsap_vtcore/unicode/grapheme.h new file mode 100644 index 0000000..6146239 --- /dev/null +++ b/include/wsap_vtcore/unicode/grapheme.h @@ -0,0 +1,26 @@ +#ifndef WSAP_VTCORE_UNICODE_GRAPHEME_H +#define WSAP_VTCORE_UNICODE_GRAPHEME_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define WSAP_VTCORE_GRAPHEME_MAX_LEN 20 +#define WSAP_VTCORE_GRAPHEME_HANDLE_BASE 0x7F000000u + +static inline bool wsap_vtcore_grapheme_is_handle(uint32_t c) +{ + return c >= WSAP_VTCORE_GRAPHEME_HANDLE_BASE; +} + +static inline bool wsap_vtcore_grapheme_regional_indicator(uint32_t cp) +{ + return cp >= 0x1F1E6 && cp <= 0x1F1FF; +} + +static inline bool wsap_vtcore_grapheme_emoji_modifier(uint32_t cp) +{ + return cp >= 0x1F3FB && cp <= 0x1F3FF; +} + +#endif diff --git a/include/wsap_vtcore/unicode/unicode.h b/include/wsap_vtcore/unicode/unicode.h new file mode 100644 index 0000000..02181b4 --- /dev/null +++ b/include/wsap_vtcore/unicode/unicode.h @@ -0,0 +1,6 @@ +#ifndef WSAP_VTCORE_UNICODE_UNICODE_H +#define WSAP_VTCORE_UNICODE_UNICODE_H + +#include "width.h" + +#endif diff --git a/include/term/unicode/unicode_data.inc b/include/wsap_vtcore/unicode/unicode_data.inc index 4ab1461..35831e5 100644 --- a/include/term/unicode/unicode_data.inc +++ b/include/wsap_vtcore/unicode/unicode_data.inc @@ -1,8 +1,8 @@ /* Generated from Unicode 18.0.0 data by tools/generate_unicode.py. */ -#define TERM_UNICODE_DATA_VERSION "18.0.0" +#define WSAP_VTCORE_UNICODE_DATA_VERSION "18.0.0" -static const struct term_unicode_range term_zero_width[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_zero_width[] = { {0xAD,0xAD},{0x300,0x36F},{0x483,0x489},{0x591,0x5BD}, {0x5BF,0x5BF},{0x5C1,0x5C2},{0x5C4,0x5C5},{0x5C7,0x5C9}, {0x600,0x605},{0x610,0x61A},{0x61C,0x61C},{0x64B,0x65F}, @@ -101,11 +101,11 @@ static const struct term_unicode_range term_zero_width[] = { {0xE0020,0xE007F},{0xE0100,0xE01EF}, }; -static const struct term_unicode_range term_nonprintable[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_nonprintable[] = { {0x0,0x1F},{0x7F,0x9F},{0xD800,0xDFFF}, }; -static const struct term_unicode_range term_unicode_wide[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_unicode_wide[] = { {0x1100,0x115F},{0x231A,0x231B},{0x2329,0x232A},{0x23E9,0x23EC}, {0x23F0,0x23F0},{0x23F3,0x23F3},{0x25FD,0x25FE},{0x2614,0x2615}, {0x2630,0x2637},{0x2648,0x2653},{0x267F,0x267F},{0x268A,0x268F}, @@ -140,7 +140,7 @@ static const struct term_unicode_range term_unicode_wide[] = { {0x20000,0x2FFFD},{0x30000,0x3FFFD}, }; -static const struct term_unicode_range term_spacing_mark[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_spacing_mark[] = { {0x903,0x903},{0x93B,0x93B},{0x93E,0x940},{0x949,0x94C}, {0x94E,0x94F},{0x982,0x983},{0x9BE,0x9C0},{0x9C7,0x9C8}, {0x9CB,0x9CC},{0x9D7,0x9D7},{0xA03,0xA03},{0xA3E,0xA40}, @@ -192,7 +192,7 @@ static const struct term_unicode_range term_spacing_mark[] = { {0x1D16D,0x1D172},{0x1D250,0x1D252},{0x1D25F,0x1D25F},{0x1D280,0x1D281}, }; -static const struct term_unicode_range term_extended_pictographic[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_extended_pictographic[] = { {0xA9,0xA9},{0xAE,0xAE},{0x203C,0x203C},{0x2049,0x2049}, {0x2122,0x2122},{0x2139,0x2139},{0x2194,0x2199},{0x21A9,0x21AA}, {0x231A,0x231B},{0x2328,0x2328},{0x23CF,0x23CF},{0x23E9,0x23F3}, @@ -234,7 +234,7 @@ static const struct term_unicode_range term_extended_pictographic[] = { {0x1F947,0x1F9FF},{0x1FA58,0x1FA5F},{0x1FA6E,0x1FAFF},{0x1FC00,0x1FFFD}, }; -static const struct term_unicode_range term_emoji_presentation[] = { +static const struct wsap_vtcore_unicode_range wsap_vtcore_emoji_presentation[] = { {0x231A,0x231B},{0x23E9,0x23EC},{0x23F0,0x23F0},{0x23F3,0x23F3}, {0x25FD,0x25FE},{0x2614,0x2615},{0x2648,0x2653},{0x267F,0x267F}, {0x2693,0x2693},{0x26A1,0x26A1},{0x26AA,0x26AB},{0x26BD,0x26BE}, diff --git a/include/term/unicode/utf8.h b/include/wsap_vtcore/unicode/utf8.h index ad44465..7660e41 100644 --- a/include/term/unicode/utf8.h +++ b/include/wsap_vtcore/unicode/utf8.h @@ -1,19 +1,19 @@ -#ifndef TERM_UNICODE_UTF8_H -#define TERM_UNICODE_UTF8_H +#ifndef WSAP_VTCORE_UNICODE_UTF8_H +#define WSAP_VTCORE_UNICODE_UTF8_H #include <stdint.h> #include <stddef.h> #include <stdlib.h> #include <string.h> -#define TERM_UTF8_ACCEPT 0 -#define TERM_UTF8_REJECT 1 +#define WSAP_VTCORE_UTF8_ACCEPT 0 +#define WSAP_VTCORE_UTF8_REJECT 1 -#define TERM_UTF8_3BYTE_MIN 0x800u -#define TERM_UTF8_SURROGATE_LO 0xd800u -#define TERM_UTF8_SURROGATE_HI 0xdfffu +#define WSAP_VTCORE_UTF8_3BYTE_MIN 0x800u +#define WSAP_VTCORE_UTF8_SURROGATE_LO 0xd800u +#define WSAP_VTCORE_UTF8_SURROGATE_HI 0xdfffu -static const uint8_t term_utf8d[] = { +static const uint8_t wsap_vtcore_utf8d[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -30,19 +30,19 @@ static const uint8_t term_utf8d[] = { 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, }; -static inline uint32_t term_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte) { +static inline uint32_t wsap_vtcore_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte) { byte &= 0xff; - uint32_t type = term_utf8d[byte]; + uint32_t type = wsap_vtcore_utf8d[byte]; - *codep = (*state != TERM_UTF8_ACCEPT) ? + *codep = (*state != WSAP_VTCORE_UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); - *state = term_utf8d[256 + *state*16 + type]; + *state = wsap_vtcore_utf8d[256 + *state*16 + type]; return *state; } -static const uint8_t term_utf8_acc_state[256] = { +static const uint8_t wsap_vtcore_utf8_acc_state[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -60,7 +60,7 @@ static const uint8_t term_utf8_acc_state[256] = { 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 6, 7, 7, 7, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; -static const uint8_t term_utf8_acc_codep[256] = { +static const uint8_t wsap_vtcore_utf8_acc_codep[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, @@ -86,7 +86,7 @@ static const uint8_t term_utf8_acc_codep[256] = { * ends an unfinished sequence the same way. An unfinished sequence at the * end of buf gives *cp = 0 and keeps the state. */ -static inline int term_utf8_decode_ground(uint32_t *state, uint32_t *codep, +static inline int wsap_vtcore_utf8_decode_ground(uint32_t *state, uint32_t *codep, const char *buf, size_t len, uint32_t *cp) { uint32_t st = *state; uint32_t cpv = *codep; @@ -97,25 +97,25 @@ static inline int term_utf8_decode_ground(uint32_t *state, uint32_t *codep, do { unsigned char c = (unsigned char)buf[n]; if (c < 0x20) { - if (st != TERM_UTF8_ACCEPT) *cp = 0xFFFD; - st = TERM_UTF8_ACCEPT; + if (st != WSAP_VTCORE_UTF8_ACCEPT) *cp = 0xFFFD; + st = WSAP_VTCORE_UTF8_ACCEPT; break; } uint32_t before = st; n++; - if (st == TERM_UTF8_ACCEPT) { - cpv = term_utf8_acc_codep[c]; - st = term_utf8_acc_state[c]; + if (st == WSAP_VTCORE_UTF8_ACCEPT) { + cpv = wsap_vtcore_utf8_acc_codep[c]; + st = wsap_vtcore_utf8_acc_state[c]; } else { - uint32_t type = term_utf8d[c]; + uint32_t type = wsap_vtcore_utf8d[c]; cpv = (c & 0x3fu) | (cpv << 6); - st = term_utf8d[256 + st*16 + type]; + st = wsap_vtcore_utf8d[256 + st*16 + type]; } - if (st == TERM_UTF8_ACCEPT) { *cp = cpv; break; } - if (st == TERM_UTF8_REJECT) { - st = TERM_UTF8_ACCEPT; + if (st == WSAP_VTCORE_UTF8_ACCEPT) { *cp = cpv; break; } + if (st == WSAP_VTCORE_UTF8_REJECT) { + st = WSAP_VTCORE_UTF8_ACCEPT; *cp = 0xFFFD; - if (before != TERM_UTF8_ACCEPT) n--; + if (before != WSAP_VTCORE_UTF8_ACCEPT) n--; break; } } while ((size_t)n < len); @@ -125,7 +125,7 @@ static inline int term_utf8_decode_ground(uint32_t *state, uint32_t *codep, } static inline int -term_utf8_decode_one(const char *buf, size_t len, uint32_t *codep) +wsap_vtcore_utf8_decode_one(const char *buf, size_t len, uint32_t *codep) { const unsigned char *s = (const unsigned char *)buf; unsigned c0, c1, c2, c3; @@ -159,8 +159,8 @@ term_utf8_decode_one(const char *buf, size_t len, uint32_t *codep) if ((c1 & 0xc0) != 0x80 || (c2 & 0xc0) != 0x80) return 0; cp = ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f); - if (cp < TERM_UTF8_3BYTE_MIN || - (cp >= TERM_UTF8_SURROGATE_LO && cp <= TERM_UTF8_SURROGATE_HI)) + if (cp < WSAP_VTCORE_UTF8_3BYTE_MIN || + (cp >= WSAP_VTCORE_UTF8_SURROGATE_LO && cp <= WSAP_VTCORE_UTF8_SURROGATE_HI)) return 0; *codep = cp; return 3; @@ -183,14 +183,14 @@ term_utf8_decode_one(const char *buf, size_t len, uint32_t *codep) } static inline void -term_utf8_sanitize(char *dst, size_t cap, const char *src) +wsap_vtcore_utf8_sanitize(char *dst, size_t cap, const char *src) { if (!cap) return; size_t i = 0, len = strlen(src), off = 0; while (off < len && i + 1 < cap) { uint32_t cp; - int n = term_utf8_decode_one(src + off, len - off, &cp); + int n = wsap_vtcore_utf8_decode_one(src + off, len - off, &cp); if (n <= 0 || i + (size_t)n >= cap) { off++; continue; @@ -204,17 +204,17 @@ term_utf8_sanitize(char *dst, size_t cap, const char *src) /* A sanitized copy of src. Sanitizing only drops bytes, so the copy is * never longer than src. */ -static inline char *term_utf8_sanitize_dup(const char *src) +static inline char *wsap_vtcore_utf8_sanitize_dup(const char *src) { size_t cap = strlen(src) + 1; char *dst = (char *)malloc(cap); if (dst) - term_utf8_sanitize(dst, cap, src); + wsap_vtcore_utf8_sanitize(dst, cap, src); return dst; } -#define TERM_UTF8_MAX_BYTES 4 -static inline int term_utf8_encode(uint32_t cp, char *out) +#define WSAP_VTCORE_UTF8_MAX_BYTES 4 +static inline int wsap_vtcore_utf8_encode(uint32_t cp, char *out) { if (cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) cp = 0xfffd; diff --git a/include/wsap_vtcore/unicode/width.h b/include/wsap_vtcore/unicode/width.h new file mode 100644 index 0000000..21d8252 --- /dev/null +++ b/include/wsap_vtcore/unicode/width.h @@ -0,0 +1,56 @@ +#ifndef WSAP_VTCORE_UNICODE_WIDTH_H +#define WSAP_VTCORE_UNICODE_WIDTH_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +struct wsap_vtcore_unicode_range { uint32_t lo, hi; }; + +#include "unicode_data.inc" + +static inline bool wsap_vtcore_in_ranges(const struct wsap_vtcore_unicode_range *ranges, size_t count, uint32_t cp) +{ + if (count == 0 || cp < ranges[0].lo || cp > ranges[count - 1].hi) + return false; + const struct wsap_vtcore_unicode_range *base = ranges; + size_t n = count; + while (n > 1) { + size_t half = n / 2; + base = (base[half].lo <= cp) ? base + half : base; + n -= half; + } + return cp <= base->hi; +} + +#define WSAP_VTCORE_IN_TABLE(table, cp) wsap_vtcore_in_ranges(table, sizeof(table) / sizeof(table[0]), cp) + +static inline int wsap_vtcore_unicode_width(uint32_t cp) +{ + if (cp > 0x10FFFF || WSAP_VTCORE_IN_TABLE(wsap_vtcore_nonprintable, cp)) + return -1; + if (WSAP_VTCORE_IN_TABLE(wsap_vtcore_zero_width, cp)) + return 0; + return WSAP_VTCORE_IN_TABLE(wsap_vtcore_unicode_wide, cp) ? 2 : 1; +} + +static inline bool wsap_vtcore_unicode_extended_pictographic(uint32_t cp) +{ + return WSAP_VTCORE_IN_TABLE(wsap_vtcore_extended_pictographic, cp); +} + +static inline bool wsap_vtcore_unicode_emoji_presentation(uint32_t cp) +{ + return WSAP_VTCORE_IN_TABLE(wsap_vtcore_emoji_presentation, cp); +} + +static inline bool wsap_vtcore_unicode_spacing_mark(uint32_t cp) +{ + if (cp < 0x903 || ((cp - 0xABEDu) < (0x11000u - 0xABEDu)) || cp > 0x1D281) + return false; + return WSAP_VTCORE_IN_TABLE(wsap_vtcore_spacing_mark, cp); +} + +#undef WSAP_VTCORE_IN_TABLE + +#endif diff --git a/include/wsap_vtcore/wsap_vtcore.h b/include/wsap_vtcore/wsap_vtcore.h new file mode 100644 index 0000000..d72a55b --- /dev/null +++ b/include/wsap_vtcore/wsap_vtcore.h @@ -0,0 +1,492 @@ +#ifndef WSAP_VTCORE_H +#define WSAP_VTCORE_H + +/* + * Terminal emulator core. + * + * A struct wsap_vtcore parses the bytes that a program writes and keeps + * the screen, the history, and the modes. The application feeds bytes with + * wsap_vtcore_feed() and reads state with the getters below. A renderer + * never reads the terminal directly: it copies the viewport into a + * struct wsap_vtcore_snapshot and paints from that copy. + * + * All functions take the terminal as the first argument. Functions that take + * a const struct wsap_vtcore do not change what it shows. Selection, history, link, + * directory, and pointer-shape queries return owned strings; release them + * with wsap_vtcore_text_free(). + * + * Threads. Any thread can call any function. Each call that reads or changes + * a terminal enters its writer section, so calls on one terminal run one at a + * time. A thread that waits for the section sleeps. On POSIX the section is a + * mutex with priority inheritance where the platform has it. A snapshot + * belongs to one thread at a time. wsap_vtcore_free() is the last call on a terminal. + */ + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "wsap_vtcore_input.h" +#include "wsap_vtcore_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wsap_vtcore; +struct wsap_vtcore_snapshot; + +/* A row holds at most this many cells. */ +#define WSAP_VTCORE_MAX_COLS 65535 +/* The history limit when wsap_vtcore_options.scrollback is 0. */ +#define WSAP_VTCORE_SCROLLBACK_DEFAULT 10000 +/* The largest wsap_vtcore_options.scrollback. */ +#define WSAP_VTCORE_SCROLLBACK_MAX 1000000 + +/* + * The version of this header. A host compares WSAP_VTCORE_VERSION_CODE with + * wsap_vtcore_version() to check that the library matches the header. + */ +#define WSAP_VTCORE_VERSION(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) +#define WSAP_VTCORE_VERSION_MAJOR 0 +#define WSAP_VTCORE_VERSION_MINOR 1 +#define WSAP_VTCORE_VERSION_PATCH 0 +#define WSAP_VTCORE_VERSION_CODE WSAP_VTCORE_VERSION(WSAP_VTCORE_VERSION_MAJOR, WSAP_VTCORE_VERSION_MINOR, WSAP_VTCORE_VERSION_PATCH) + +/* + * Colors. A wsap_vtcore_color is either a direct color (alpha 0xFF, then RGB) or a + * palette slot: an index 0-255, the default foreground, or the default + * background. A slot resolves when a snapshot is painted, so a theme change + * recolors text that is already on screen. + */ +typedef uint32_t wsap_vtcore_color; + +#define WSAP_VTCORE_COLOR_SLOT 0x01000000u +/* The palette index of a slot; see struct wsap_vtcore_view.palette. */ +#define WSAP_VTCORE_COLOR_SLOT_INDEX 0x1FFu +#define WSAP_VTCORE_COLOR_FG (WSAP_VTCORE_COLOR_SLOT | 0x100u) +#define WSAP_VTCORE_COLOR_BG (WSAP_VTCORE_COLOR_SLOT | 0x101u) + +static inline wsap_vtcore_color wsap_vtcore_color_index(int n) +{ + return WSAP_VTCORE_COLOR_SLOT | ((uint32_t)n & 0xFFu); +} + +static inline wsap_vtcore_color wsap_vtcore_color_rgb(uint8_t r, uint8_t g, uint8_t b) +{ + return 0xFF000000u | (uint32_t)r << 16 | (uint32_t)g << 8 | b; +} + +static inline bool wsap_vtcore_color_is_slot(wsap_vtcore_color c) +{ + return (c >> 24) == (WSAP_VTCORE_COLOR_SLOT >> 24); +} + +/* Parse an X11 or OSC color specification ("#rgb", "rgb:r/g/b", ...). */ +WSAP_VTCORE_API bool wsap_vtcore_color_parse(const char *spec, uint32_t *argb); + +/* The colors a terminal starts with. All values are ARGB. An all-zero theme + * selects the built-in theme. */ +struct wsap_vtcore_theme { + uint32_t fg, bg, cursor; + uint32_t ansi[16]; +}; + +/* Fill theme with the built-in theme. */ +WSAP_VTCORE_API void wsap_vtcore_theme_default(struct wsap_vtcore_theme *theme); +/* Fill theme with the high-contrast theme. */ +WSAP_VTCORE_API void wsap_vtcore_theme_high_contrast(struct wsap_vtcore_theme *theme); +/* Sets one palette key: foreground, background, or color0 to color15. + * An empty value resets the key to the built-in theme. False, with no + * change, for an unknown key or a bad color. */ +WSAP_VTCORE_API bool wsap_vtcore_theme_set_key(struct wsap_vtcore_theme *p, const char *key, const char *val); + +enum wsap_vtcore_cursor_style { + WSAP_VTCORE_CURSOR_BLOCK, + WSAP_VTCORE_CURSOR_UNDERLINE, + WSAP_VTCORE_CURSOR_BAR, +}; + +/* Mouse reporting modes and encodings. The values are the DEC mode numbers. */ +enum wsap_vtcore_mouse { + WSAP_VTCORE_MOUSE_OFF = 0, + WSAP_VTCORE_MOUSE_X10 = 9, + WSAP_VTCORE_MOUSE_NORMAL = 1000, + WSAP_VTCORE_MOUSE_BUTTON = 1002, + WSAP_VTCORE_MOUSE_ANY = 1003, +}; + +enum wsap_vtcore_mouse_encoding { + WSAP_VTCORE_MOUSE_ENC_X10 = 0, + WSAP_VTCORE_MOUSE_ENC_UTF8 = 1005, + WSAP_VTCORE_MOUSE_ENC_SGR = 1006, + WSAP_VTCORE_MOUSE_ENC_URXVT = 1015, + WSAP_VTCORE_MOUSE_ENC_SGR_PIXELS = 1016, +}; + +/* + * Callbacks. They run inside wsap_vtcore_feed() and wsap_vtcore_focus(), on the thread + * that calls those functions. A callback must not call back into the + * terminal. String arguments are valid only during the call. + */ +struct wsap_vtcore_callbacks { + void *ud; + /* Bytes the terminal sends back to the program (replies to queries). */ + void (*reply)(void *ud, const char *bytes, size_t len); + void (*title)(void *ud, const char *title); + /* + * OSC 52 clipboard callback. + * selection names the target clipboard buffer(s), commonly: + * "c" - clipboard (system clipboard) + * "p" - primary selection (X11 primary) + * "q" - secondary selection + * "s" - select selection + * "0".."7" - cut buffers 0 to 7 + * A parameter may contain multiple targets (e.g. "cp"). + * data contains decoded bytes of length len. + */ + void (*clipboard)(void *ud, const char *selection, const char *data, size_t len); + void (*notify)(void *ud, const char *title, const char *body); + void (*bell)(void *ud); + /* Parser trace lines for debugging. NULL turns tracing off. The line has no newline. */ + void (*trace)(void *ud, const char *line); +}; + +/* + * Options for wsap_vtcore_new(). An all-zero value is valid. A size component of 0 + * selects 80 columns or 24 rows. A negative component, or columns above + * WSAP_VTCORE_MAX_COLS, makes wsap_vtcore_new() fail. A scrollback below 0 or above + * WSAP_VTCORE_SCROLLBACK_MAX fails too. + * cursor_style must be a value of enum wsap_vtcore_cursor_style. + */ +struct wsap_vtcore_options { + struct wsap_vtcore_vector2i size; /* columns and rows */ + int scrollback; /* history lines; 0 selects WSAP_VTCORE_SCROLLBACK_DEFAULT */ + struct wsap_vtcore_theme theme; + enum wsap_vtcore_cursor_style cursor_style; + bool cursor_steady; /* false: the cursor blinks */ + /* + * The terminal's name. Programs read it with XTVERSION and XTGETTCAP. + * It is also the title of a notification that has none. NULL or "" + * selects "wsap_vtcore". Otherwise 1 to 63 printable ASCII bytes, or + * wsap_vtcore_new() returns NULL. wsap_vtcore_new() copies the name. + */ + const char *name; + struct wsap_vtcore_callbacks callbacks; + /* Must be zero. wsap_vtcore_new() returns NULL if any word is nonzero, so a + * later version can give a word a meaning. */ + uint32_t reserved[8]; +}; + +/* The Unicode version of the width tables, such as "18.0.0". A host can + * pass it to programs as UNICODE_VERSION. */ +WSAP_VTCORE_API const char *wsap_vtcore_unicode_version(void); +/* The WSAP_VTCORE_VERSION_CODE the library was built with. */ +WSAP_VTCORE_API unsigned wsap_vtcore_version(void); + +/* The length of the prefix of buf made of bytes in [0x20, hi). With hi + * 0x7f, it finds a run of printable ASCII in UTF-8 text, so a host can + * skip shaping for it. Any thread can call it. */ +WSAP_VTCORE_API size_t wsap_vtcore_scan_printable_span(const char *buf, size_t len, unsigned char hi); + +/* The instruction set level of the running code: "base", "avx2", "avx512", + * or "neon". On x86-64, the first wsap_vtcore_new() picks the highest level the CPU + * supports. Set WSAP_VTCORE_ISA to a lower level to force it, for tests + * and comparisons. */ +WSAP_VTCORE_API const char *wsap_vtcore_isa(void); + +/* NULL when memory runs out or an option is invalid. */ +WSAP_VTCORE_API struct wsap_vtcore *wsap_vtcore_new(const struct wsap_vtcore_options *opt); +WSAP_VTCORE_API void wsap_vtcore_free(struct wsap_vtcore *t); + +/* Hold the writer section across several calls, so that no other thread + * changes the terminal between them. The section is a mutex, and a waiting + * thread sleeps. Keep it short. The thread that holds it can call every + * function, and it can enter the section again. Each wsap_vtcore_lock() needs one + * wsap_vtcore_unlock(). */ +WSAP_VTCORE_API void wsap_vtcore_lock(struct wsap_vtcore *t); +WSAP_VTCORE_API void wsap_vtcore_unlock(struct wsap_vtcore *t); + +/* Change the size in cells. Returns false, and the terminal is unchanged, + * when a component is below 1, when cols is above WSAP_VTCORE_MAX_COLS, or when + * memory runs out. The screen reflows to the new width. */ +WSAP_VTCORE_API bool wsap_vtcore_resize(struct wsap_vtcore *t, struct wsap_vtcore_vector2i size); + +/* Replace the theme. A different theme also drops the colors that the + * program set with OSC; the same theme changes nothing. */ +WSAP_VTCORE_API void wsap_vtcore_set_theme(struct wsap_vtcore *t, const struct wsap_vtcore_theme *theme); + +/* The cursor style that DECSCUSR 0 and a reset restore. */ +WSAP_VTCORE_API void wsap_vtcore_set_cursor_default(struct wsap_vtcore *t, enum wsap_vtcore_cursor_style style, bool steady); + +/* + * Bytes from the program. + * + * WSAP_VTCORE_FEED_ONLCR: a line feed also returns the cursor to column 0, as a tty + * with OPOST and ONLCR does. Set it when the bytes did not pass through the + * tty output processing (for example the fast pipe). + */ +enum wsap_vtcore_feed_flags { + WSAP_VTCORE_FEED_ONLCR = 1u << 0, +}; + +/* + * Feed bytes from the program. Returns false, and changes nothing, when t is + * NULL, when bytes is NULL and len is not 0, or when flags has a bit that is + * not in enum wsap_vtcore_feed_flags. A len of 0 is a no-op that returns true. + */ +WSAP_VTCORE_API bool wsap_vtcore_feed(struct wsap_vtcore *t, const char *bytes, size_t len, unsigned flags); + +/* Report a focus change. The terminal replies only in focus-event mode. */ +WSAP_VTCORE_API void wsap_vtcore_focus(struct wsap_vtcore *t, bool focused); + +/* Modes that affect how the application encodes input. */ +struct wsap_vtcore_modes { + unsigned keyboard; /* kitty keyboard protocol flags */ + enum wsap_vtcore_mouse mouse; + enum wsap_vtcore_mouse_encoding mouse_encoding; + struct wsap_vtcore_vector2i grid; /* columns and rows */ + bool app_cursor; /* DECCKM */ + bool app_keypad; /* DECKPAM */ + bool backarrow_bs; /* DECBKM */ + bool bracketed_paste; + bool focus_events; + bool alternate; /* the alternate screen is active */ + bool reverse_video; /* DECSCNM */ + bool synchronized; /* mode 2026 */ +}; + +struct wsap_vtcore_cursor { + struct wsap_vtcore_vector2i pos; + enum wsap_vtcore_cursor_style style; + bool visible; + bool blink; +}; + +WSAP_VTCORE_API struct wsap_vtcore_vector2i wsap_vtcore_size(const struct wsap_vtcore *t); +WSAP_VTCORE_API struct wsap_vtcore_modes wsap_vtcore_modes(const struct wsap_vtcore *t); + +/* + * Encode an input event as the bytes the program expects. Get modes from + * wsap_vtcore_modes(). Record ev in keyboard with wsap_vtcore_keyboard_update() first. Send + * the bytes to the program yourself. + */ +WSAP_VTCORE_API struct wsap_vtcore_input_result wsap_vtcore_input_encode_key( + const struct wsap_vtcore_keyboard_state *keyboard, + const struct wsap_vtcore_key_event *ev, + const struct wsap_vtcore_modes *modes, + char *buf, size_t capacity +); + +WSAP_VTCORE_API struct wsap_vtcore_input_result wsap_vtcore_input_encode_mouse( + const struct wsap_vtcore_mouse_event *ev, + const struct wsap_vtcore_modes *modes, + char *buf, size_t capacity +); + +/* Bytes wsap_vtcore_input_encode_paste() adds to the text at most. */ +#define WSAP_VTCORE_PASTE_EXTRA 12 + +/* + * Encode pasted text. Drop control characters and bidi controls, so the + * program sees only what the user saw. Send a line break as CR. Add the + * bracketed-paste markers when the program asked for them. A buffer of + * len + WSAP_VTCORE_PASTE_EXTRA bytes is always large enough. Text that is empty + * after the filter gives WSAP_VTCORE_INPUT_CONSUMED. + */ +WSAP_VTCORE_API struct wsap_vtcore_input_result wsap_vtcore_input_encode_paste( + const struct wsap_vtcore_modes *modes, + const char *text, size_t len, + char *buf, size_t capacity +); +/* The cursor in screen coordinates (not the viewport). */ +WSAP_VTCORE_API struct wsap_vtcore_cursor wsap_vtcore_cursor(const struct wsap_vtcore *t); +/* Owned, NUL-terminated text from OSC 7 and OSC 22. NULL when unavailable + * or allocation fails. The strings stay valid after the terminal changes + * or is freed. Release them with wsap_vtcore_text_free(). */ +WSAP_VTCORE_API char *wsap_vtcore_cwd(const struct wsap_vtcore *t); +WSAP_VTCORE_API char *wsap_vtcore_pointer_shape(const struct wsap_vtcore *t); +/* Release any owned text returned by the library. NULL is safe. */ +WSAP_VTCORE_API void wsap_vtcore_text_free(char *text); + +/* + * Viewport. The viewport shows as many rows as the screen. Offset 0 shows + * the live screen; a larger offset shows that many rows of history above it. + * The alternate screen has no history, so its offset is always 0. + */ +struct wsap_vtcore_scrollback { + int offset; /* rows between the viewport and the live screen */ + int total; /* history rows at the current width */ +}; + +WSAP_VTCORE_API struct wsap_vtcore_scrollback wsap_vtcore_scrollback(const struct wsap_vtcore *t); +/* Scroll the viewport. A positive count moves back into history. */ +WSAP_VTCORE_API void wsap_vtcore_scroll(struct wsap_vtcore *t, int lines); +WSAP_VTCORE_API void wsap_vtcore_scroll_to(struct wsap_vtcore *t, int offset); + +/* + * Selection, in viewport coordinates. A selection starts at one cell and + * extends to another; the unit widens both ends to words or whole lines. + * The terminal clears the selection when the text under it changes. + */ +enum wsap_vtcore_select_unit { + WSAP_VTCORE_SELECT_CELL, + WSAP_VTCORE_SELECT_WORD, + WSAP_VTCORE_SELECT_LINE, +}; + +/* Start a selection at cell. For WSAP_VTCORE_SELECT_CELL, right_half means the + * pointer is on the right half of the cell, so the selection starts after it. + * Returns false when memory runs out; the selection is then unchanged. */ +WSAP_VTCORE_API bool wsap_vtcore_select_start(struct wsap_vtcore *t, struct wsap_vtcore_vector2i cell, bool right_half, + enum wsap_vtcore_select_unit unit); +/* Extend the selection from its start to cell. Returns false when memory runs + * out; the selection is then unchanged. */ +WSAP_VTCORE_API bool wsap_vtcore_select_extend(struct wsap_vtcore *t, struct wsap_vtcore_vector2i cell, bool right_half); +WSAP_VTCORE_API void wsap_vtcore_select_clear(struct wsap_vtcore *t); +WSAP_VTCORE_API bool wsap_vtcore_has_selection(const struct wsap_vtcore *t); +/* Owned, NUL-terminated UTF-8 of the selection. NULL when nothing is + * selected or allocation fails; a selection of blanks may produce an empty + * string. Capture is atomic with respect to other calls on t. Release the + * result with wsap_vtcore_text_free(). */ +WSAP_VTCORE_API char *wsap_vtcore_selection_text(const struct wsap_vtcore *t); +/* Owned OSC 8 link or detected URL at a viewport cell. NULL when there is + * no link or allocation fails. Release the result with wsap_vtcore_text_free(). */ +WSAP_VTCORE_API char *wsap_vtcore_link_at(const struct wsap_vtcore *t, struct wsap_vtcore_vector2i cell); + +/* Cell attributes share the write core's bit layout. Underline styles are + * mutually exclusive flags, not a shifted enum; use wsap_vtcore_attr_underline(). */ +enum wsap_vtcore_attr { + WSAP_VTCORE_ATTR_BOLD = 1u << 0, + WSAP_VTCORE_ATTR_ITALIC = 1u << 1, + WSAP_VTCORE_ATTR_UNDERLINE = 1u << 2, + WSAP_VTCORE_ATTR_STRIKE = 1u << 3, + WSAP_VTCORE_ATTR_OVERLINE = 1u << 4, + WSAP_VTCORE_ATTR_EMOJI = 1u << 5, /* the text requested emoji presentation */ + WSAP_VTCORE_ATTR_TEXT = 1u << 6, /* the text requested text presentation */ + WSAP_VTCORE_ATTR_FAINT = 1u << 10, + WSAP_VTCORE_ATTR_DOUBLE_UNDERLINE = 1u << 11, + WSAP_VTCORE_ATTR_CURLY_UNDERLINE = 1u << 12, + WSAP_VTCORE_ATTR_DOTTED_UNDERLINE = 1u << 13, + WSAP_VTCORE_ATTR_DASHED_UNDERLINE = 1u << 14, + WSAP_VTCORE_ATTR_LINK = 1u << 15, +}; + +#define WSAP_VTCORE_ATTR_UNDERLINE_MASK \ + (WSAP_VTCORE_ATTR_UNDERLINE | WSAP_VTCORE_ATTR_DOUBLE_UNDERLINE | WSAP_VTCORE_ATTR_CURLY_UNDERLINE | \ + WSAP_VTCORE_ATTR_DOTTED_UNDERLINE | WSAP_VTCORE_ATTR_DASHED_UNDERLINE) + +enum wsap_vtcore_underline { + WSAP_VTCORE_UNDERLINE_NONE, + WSAP_VTCORE_UNDERLINE_SINGLE, + WSAP_VTCORE_UNDERLINE_DOUBLE, + WSAP_VTCORE_UNDERLINE_CURLY, + WSAP_VTCORE_UNDERLINE_DOTTED, + WSAP_VTCORE_UNDERLINE_DASHED, +}; + +static inline enum wsap_vtcore_underline wsap_vtcore_attr_underline(uint16_t attrs) +{ + if (attrs & WSAP_VTCORE_ATTR_DOUBLE_UNDERLINE) return WSAP_VTCORE_UNDERLINE_DOUBLE; + if (attrs & WSAP_VTCORE_ATTR_CURLY_UNDERLINE) return WSAP_VTCORE_UNDERLINE_CURLY; + if (attrs & WSAP_VTCORE_ATTR_DOTTED_UNDERLINE) return WSAP_VTCORE_UNDERLINE_DOTTED; + if (attrs & WSAP_VTCORE_ATTR_DASHED_UNDERLINE) return WSAP_VTCORE_UNDERLINE_DASHED; + return attrs & WSAP_VTCORE_ATTR_UNDERLINE ? WSAP_VTCORE_UNDERLINE_SINGLE : WSAP_VTCORE_UNDERLINE_NONE; +} + +/* text refers to a grapheme cluster in the snapshot; see wsap_vtcore_snapshot_cluster(). */ +#define WSAP_VTCORE_TEXT_CLUSTER 0x80000000u + +/* One cell as a snapshot shows it. */ +struct wsap_vtcore_cell { + uint32_t text; /* a code point, WSAP_VTCORE_TEXT_CLUSTER | n, or 0 for an empty cell */ + wsap_vtcore_color fg, bg; + uint16_t attrs; /* enum wsap_vtcore_attr flags; at most one underline flag */ + uint8_t width; /* 1; 2 for a wide glyph; 0 for the right half of a wide glyph */ + uint8_t reserved; +}; + +#ifdef __cplusplus +static_assert(sizeof(struct wsap_vtcore_cell) == 16, "four cells fill one 64-byte line"); +#else +_Static_assert(sizeof(struct wsap_vtcore_cell) == 16, "four cells fill one 64-byte line"); +#endif + +/* + * Snapshot: a copy of the viewport for a renderer. It holds no pointer into + * the terminal, so it stays valid while the terminal changes. One terminal + * may have several snapshots, for example a window and a tab preview. + */ +WSAP_VTCORE_API struct wsap_vtcore_snapshot *wsap_vtcore_snapshot_new(void); +WSAP_VTCORE_API void wsap_vtcore_snapshot_free(struct wsap_vtcore_snapshot *s); + +/* Copy the viewport of t into s. Keep rows with unchanged content keys. + * Update the history view index and refine counts for visible wide lines. + * Return false when memory runs out. The snapshot then keeps its previous content. */ +WSAP_VTCORE_API bool wsap_vtcore_snapshot_update(struct wsap_vtcore_snapshot *s, struct wsap_vtcore *t); + +/* Palette entries of struct wsap_vtcore_view.palette after the 256 indexed colors. */ +enum { + WSAP_VTCORE_PALETTE_FG = 256, + WSAP_VTCORE_PALETTE_BG = 257, + WSAP_VTCORE_PALETTE_CURSOR = 258, + WSAP_VTCORE_PALETTE_SIZE = 259, +}; + +struct wsap_vtcore_view { + struct wsap_vtcore_vector2i size; + struct wsap_vtcore_cursor cursor; /* viewport coordinates; not visible when scrolled away */ + int scroll_offset; + /* Rows the content moved up since the previous update, when that movement + * explains the change; otherwise 0. */ + int scrolled; + bool reverse_video; + /* Changes when any part of the view changes. */ + uint64_t version; + /* Changes when a palette entry changes. */ + uint64_t palette_version; + const uint32_t *palette; /* WSAP_VTCORE_PALETTE_SIZE ARGB entries */ +}; + +/* The view of s, NULL for a NULL s. The view and view->palette keep their + * address until wsap_vtcore_snapshot_free(); their contents change on each update. */ +WSAP_VTCORE_API const struct wsap_vtcore_view *wsap_vtcore_snapshot_view(const struct wsap_vtcore_snapshot *s); +/* The cells of viewport row y: view->size.x entries. NULL when y is outside + * the viewport or s is NULL. An update can move the cells, so the pointer is + * valid only until the next wsap_vtcore_snapshot_update() or wsap_vtcore_snapshot_free() of s. */ +WSAP_VTCORE_API const struct wsap_vtcore_cell *wsap_vtcore_snapshot_row(const struct wsap_vtcore_snapshot *s, int y); +/* An identity for the content of row y. Two rows with the same key hold the + * same cells, also when the content moved to another row. 0 when y is outside + * the viewport or s is NULL. */ +WSAP_VTCORE_API uint64_t wsap_vtcore_snapshot_row_key(const struct wsap_vtcore_snapshot *s, int y); + +/* Number of rows in history above the screen. 0 if alternate screen or no history. */ +WSAP_VTCORE_API int wsap_vtcore_history_rows(const struct wsap_vtcore *t); +/* Owned, NUL-terminated UTF-8 of up to max_rows history rows before the + * current viewport. Join soft-wrapped rows and end closed lines with a + * newline. Does not change the selection. No history or max_rows <= 0 gives + * an empty string; NULL means allocation failed or t is NULL. Release the + * result with wsap_vtcore_text_free(). */ +WSAP_VTCORE_API char *wsap_vtcore_history_text(struct wsap_vtcore *t, int max_rows); +/* The selected columns of viewport row y, end exclusive. An empty span when y + * is outside the viewport or s is NULL. */ +WSAP_VTCORE_API struct wsap_vtcore_span wsap_vtcore_snapshot_row_selection(const struct wsap_vtcore_snapshot *s, int y); + +/* The code points of a cluster cell. Returns the number of code points and + * writes at most cap of them. Writes nothing when cps is NULL or cap is 0. + * Returns 0 when s is NULL. */ +WSAP_VTCORE_API int wsap_vtcore_snapshot_cluster(const struct wsap_vtcore_snapshot *s, uint32_t text, uint32_t *cps, int cap); + +/* The ARGB value of a color in a view. */ +static inline uint32_t wsap_vtcore_view_color(const struct wsap_vtcore_view *v, wsap_vtcore_color c) +{ + if (!wsap_vtcore_color_is_slot(c)) + return c; + return v->palette[c & WSAP_VTCORE_COLOR_SLOT_INDEX]; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wsap_vtcore/wsap_vtcore_input.h b/include/wsap_vtcore/wsap_vtcore_input.h new file mode 100644 index 0000000..337a292 --- /dev/null +++ b/include/wsap_vtcore/wsap_vtcore_input.h @@ -0,0 +1,202 @@ +#ifndef WSAP_VTCORE_INPUT_H +#define WSAP_VTCORE_INPUT_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include "wsap_vtcore_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum wsap_vtcore_key { + WSAP_VTCORE_KEY_NONE = 0, + + WSAP_VTCORE_KEY_RETURN, + WSAP_VTCORE_KEY_BACKSPACE, + WSAP_VTCORE_KEY_TAB, + WSAP_VTCORE_KEY_ESCAPE, + + WSAP_VTCORE_KEY_UP, + WSAP_VTCORE_KEY_DOWN, + WSAP_VTCORE_KEY_RIGHT, + WSAP_VTCORE_KEY_LEFT, + WSAP_VTCORE_KEY_HOME, + WSAP_VTCORE_KEY_END, + WSAP_VTCORE_KEY_PAGE_UP, + WSAP_VTCORE_KEY_PAGE_DOWN, + WSAP_VTCORE_KEY_INSERT, + WSAP_VTCORE_KEY_DELETE, + + WSAP_VTCORE_KEY_F1, WSAP_VTCORE_KEY_F2, WSAP_VTCORE_KEY_F3, WSAP_VTCORE_KEY_F4, WSAP_VTCORE_KEY_F5, + WSAP_VTCORE_KEY_F6, WSAP_VTCORE_KEY_F7, WSAP_VTCORE_KEY_F8, WSAP_VTCORE_KEY_F9, WSAP_VTCORE_KEY_F10, + WSAP_VTCORE_KEY_F11, WSAP_VTCORE_KEY_F12, WSAP_VTCORE_KEY_F13, WSAP_VTCORE_KEY_F14, WSAP_VTCORE_KEY_F15, + WSAP_VTCORE_KEY_F16, WSAP_VTCORE_KEY_F17, WSAP_VTCORE_KEY_F18, WSAP_VTCORE_KEY_F19, WSAP_VTCORE_KEY_F20, + WSAP_VTCORE_KEY_F21, WSAP_VTCORE_KEY_F22, WSAP_VTCORE_KEY_F23, WSAP_VTCORE_KEY_F24, WSAP_VTCORE_KEY_F25, + WSAP_VTCORE_KEY_F26, WSAP_VTCORE_KEY_F27, WSAP_VTCORE_KEY_F28, WSAP_VTCORE_KEY_F29, WSAP_VTCORE_KEY_F30, + WSAP_VTCORE_KEY_F31, WSAP_VTCORE_KEY_F32, WSAP_VTCORE_KEY_F33, WSAP_VTCORE_KEY_F34, WSAP_VTCORE_KEY_F35, + + WSAP_VTCORE_KEY_KP_0, WSAP_VTCORE_KEY_KP_1, WSAP_VTCORE_KEY_KP_2, WSAP_VTCORE_KEY_KP_3, WSAP_VTCORE_KEY_KP_4, + WSAP_VTCORE_KEY_KP_5, WSAP_VTCORE_KEY_KP_6, WSAP_VTCORE_KEY_KP_7, WSAP_VTCORE_KEY_KP_8, WSAP_VTCORE_KEY_KP_9, + WSAP_VTCORE_KEY_KP_DECIMAL, + WSAP_VTCORE_KEY_KP_ENTER, + WSAP_VTCORE_KEY_KP_ADD, + WSAP_VTCORE_KEY_KP_SUBTRACT, + WSAP_VTCORE_KEY_KP_MULTIPLY, + WSAP_VTCORE_KEY_KP_DIVIDE, + WSAP_VTCORE_KEY_KP_EQUAL, + WSAP_VTCORE_KEY_KP_SEPARATOR, + WSAP_VTCORE_KEY_KP_LEFT, + WSAP_VTCORE_KEY_KP_RIGHT, + WSAP_VTCORE_KEY_KP_UP, + WSAP_VTCORE_KEY_KP_DOWN, + WSAP_VTCORE_KEY_KP_PAGE_UP, + WSAP_VTCORE_KEY_KP_PAGE_DOWN, + WSAP_VTCORE_KEY_KP_HOME, + WSAP_VTCORE_KEY_KP_END, + WSAP_VTCORE_KEY_KP_INSERT, + WSAP_VTCORE_KEY_KP_DELETE, + WSAP_VTCORE_KEY_KP_BEGIN, + + WSAP_VTCORE_KEY_CAPS_LOCK, + WSAP_VTCORE_KEY_SCROLL_LOCK, + WSAP_VTCORE_KEY_NUM_LOCK, + WSAP_VTCORE_KEY_PRINT_SCREEN, + WSAP_VTCORE_KEY_PAUSE, + WSAP_VTCORE_KEY_MENU, + + WSAP_VTCORE_KEY_MEDIA_PLAY, + WSAP_VTCORE_KEY_MEDIA_PAUSE, + WSAP_VTCORE_KEY_MEDIA_STOP, + WSAP_VTCORE_KEY_MEDIA_FORWARD, + WSAP_VTCORE_KEY_MEDIA_REWIND, + WSAP_VTCORE_KEY_MEDIA_NEXT, + WSAP_VTCORE_KEY_MEDIA_PREV, + WSAP_VTCORE_KEY_MEDIA_RECORD, + WSAP_VTCORE_KEY_VOLUME_DOWN, + WSAP_VTCORE_KEY_VOLUME_UP, + WSAP_VTCORE_KEY_MUTE, + + WSAP_VTCORE_KEY_LSHIFT, + WSAP_VTCORE_KEY_LCTRL, + WSAP_VTCORE_KEY_LALT, + WSAP_VTCORE_KEY_LSUPER, + WSAP_VTCORE_KEY_LHYPER, + WSAP_VTCORE_KEY_LMETA, + WSAP_VTCORE_KEY_RSHIFT, + WSAP_VTCORE_KEY_RCTRL, + WSAP_VTCORE_KEY_RALT, + WSAP_VTCORE_KEY_RSUPER, + WSAP_VTCORE_KEY_RHYPER, + WSAP_VTCORE_KEY_RMETA, + WSAP_VTCORE_KEY_ISO_LEVEL3_SHIFT, + WSAP_VTCORE_KEY_ISO_LEVEL5_SHIFT, + + WSAP_VTCORE_KEY_COUNT +}; + +enum wsap_vtcore_mod { + WSAP_VTCORE_MOD_SHIFT = 1, + WSAP_VTCORE_MOD_ALT = 2, + WSAP_VTCORE_MOD_CTRL = 4, + WSAP_VTCORE_MOD_SUPER = 8, + WSAP_VTCORE_MOD_HYPER = 16, + WSAP_VTCORE_MOD_META = 32, + WSAP_VTCORE_MOD_CAPS = 64, + WSAP_VTCORE_MOD_NUM = 128, +}; + +enum wsap_vtcore_key_action { + WSAP_VTCORE_KEY_PRESS = 1, + WSAP_VTCORE_KEY_REPEAT = 2, + WSAP_VTCORE_KEY_RELEASE = 3, +}; + +enum wsap_vtcore_mouse_button { + WSAP_VTCORE_MOUSE_BUTTON_PRIMARY = 0, + WSAP_VTCORE_MOUSE_BUTTON_MIDDLE, + WSAP_VTCORE_MOUSE_BUTTON_SECONDARY, + WSAP_VTCORE_MOUSE_BUTTON_NONE, + /* Extra buttons 8 through 11 in xterm mouse reporting (encoded as 128..131). */ + WSAP_VTCORE_MOUSE_BUTTON_EXTRA_1, + WSAP_VTCORE_MOUSE_BUTTON_EXTRA_2, + WSAP_VTCORE_MOUSE_BUTTON_EXTRA_3, + WSAP_VTCORE_MOUSE_BUTTON_EXTRA_4, + WSAP_VTCORE_MOUSE_WHEEL_UP = 16, + WSAP_VTCORE_MOUSE_WHEEL_DOWN, + WSAP_VTCORE_MOUSE_WHEEL_LEFT, + WSAP_VTCORE_MOUSE_WHEEL_RIGHT, +}; + +enum wsap_vtcore_mouse_event_kind { + WSAP_VTCORE_MOUSE_PRESS = 0, + WSAP_VTCORE_MOUSE_RELEASE, + WSAP_VTCORE_MOUSE_MOTION, + WSAP_VTCORE_MOUSE_SCROLL, + WSAP_VTCORE_MOUSE_LEAVE, +}; + +struct wsap_vtcore_key_event { + enum wsap_vtcore_key_action action; + uint16_t key; /* enum wsap_vtcore_key; WSAP_VTCORE_KEY_NONE for a text key */ + uint16_t keypad; /* the WSAP_VTCORE_KEY_KP_* key when the key is on the keypad */ + unsigned mods; /* enum wsap_vtcore_mod */ + uint32_t codepoint; /* the code point of the key without modifiers */ + uint32_t shifted; /* the code point of the key with Shift */ + uint32_t base; /* the code point of the key in the US layout */ + uint32_t text; /* the code point the key types, or 0 */ + bool text_deferred; /* an input method sends the text later */ +}; + +struct wsap_vtcore_mouse_event { + struct wsap_vtcore_vector2i pos; /* Grid cell coordinates (col, row) */ + struct wsap_vtcore_vector2i pixel; /* Absolute pixel position in terminal grid */ + /* + * Button identifier: + * - Press and release: the button that changed state (WSAP_VTCORE_MOUSE_BUTTON_*). + * - Motion: the held button for drag events, or WSAP_VTCORE_MOUSE_BUTTON_NONE for hover. + * - Scroll: the wheel direction (WSAP_VTCORE_MOUSE_WHEEL_*). + */ + int button; + unsigned mods; + int scroll_lines; + float scroll_delta; + enum wsap_vtcore_mouse_event_kind kind; +}; + +/* The keys that are down. An all-zero value has no keys down. */ +struct wsap_vtcore_keyboard_state { + uint64_t down[(WSAP_VTCORE_KEY_COUNT + 63) / 64]; +}; + +/* Record a press, repeat, or release in s. */ +WSAP_VTCORE_API void wsap_vtcore_keyboard_update(struct wsap_vtcore_keyboard_state *s, const struct wsap_vtcore_key_event *ev); +WSAP_VTCORE_API bool wsap_vtcore_keyboard_key_down(const struct wsap_vtcore_keyboard_state *s, enum wsap_vtcore_key key); + +/* Kitty keyboard protocol flags, as in wsap_vtcore_modes.keyboard. */ +enum wsap_vtcore_keyboard_flag { + WSAP_VTCORE_KEYBOARD_DISAMBIGUATE = 1, + WSAP_VTCORE_KEYBOARD_EVENT_TYPES = 2, + WSAP_VTCORE_KEYBOARD_ALTERNATE_KEYS = 4, + WSAP_VTCORE_KEYBOARD_ALL_KEYS = 8, + WSAP_VTCORE_KEYBOARD_ASSOCIATED_TEXT = 16, +}; + +enum wsap_vtcore_input_status { + WSAP_VTCORE_INPUT_UNHANDLED = 0, /* the terminal does not use the event */ + WSAP_VTCORE_INPUT_CONSUMED, /* the terminal uses the event but sends nothing */ + WSAP_VTCORE_INPUT_BYTES, /* send the len bytes in buf to the program */ + WSAP_VTCORE_INPUT_BUFFER_FULL, /* buf is too small; len is 0 */ +}; + +struct wsap_vtcore_input_result { + size_t len; + enum wsap_vtcore_input_status status; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* WSAP_VTCORE_INPUT_H */ diff --git a/include/term/term_types.h b/include/wsap_vtcore/wsap_vtcore_types.h index 78be371..0944da3 100644 --- a/include/term/term_types.h +++ b/include/wsap_vtcore/wsap_vtcore_types.h @@ -1,14 +1,14 @@ -#ifndef TERM_TYPES_H -#define TERM_TYPES_H +#ifndef WSAP_VTCORE_TYPES_H +#define WSAP_VTCORE_TYPES_H /* Marks the public functions. The library builds with hidden symbols, so * only these are visible outside a shared build. A host can define it * first, for example as __declspec(dllimport). */ -#ifndef TERM_API +#ifndef WSAP_VTCORE_API #if defined(__GNUC__) || defined(__clang__) -#define TERM_API __attribute__((visibility("default"))) +#define WSAP_VTCORE_API __attribute__((visibility("default"))) #else -#define TERM_API +#define WSAP_VTCORE_API #endif #endif @@ -16,11 +16,11 @@ extern "C" { #endif -struct term_vector2i { +struct wsap_vtcore_vector2i { int x, y; }; -struct term_span { +struct wsap_vtcore_span { int begin; int end; }; |
