summaryrefslogtreecommitdiff
path: root/include/wsap_vtcore/wsap_vtcore.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/wsap_vtcore/wsap_vtcore.h')
-rw-r--r--include/wsap_vtcore/wsap_vtcore.h492
1 files changed, 492 insertions, 0 deletions
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