diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/term/term.h | 71 | ||||
| -rw-r--r-- | include/term/term_input.h | 6 | ||||
| -rw-r--r-- | include/term/unicode/grapheme.h | 12 | ||||
| -rw-r--r-- | include/term/unicode/unicode_data.inc | 14 | ||||
| -rw-r--r-- | include/term/unicode/utf8.h | 72 | ||||
| -rw-r--r-- | include/term/unicode/width.h | 30 |
6 files changed, 124 insertions, 81 deletions
diff --git a/include/term/term.h b/include/term/term.h index 2447b72..380dfd3 100644 --- a/include/term/term.h +++ b/include/term/term.h @@ -17,8 +17,9 @@ * * 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 snapshot belongs to one thread at a time. term_free() is the last - * call on a terminal. + * 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> @@ -41,6 +42,16 @@ struct term_snapshot; #define TERM_SCROLLBACK_DEFAULT 10000 /* + * 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 @@ -139,20 +150,36 @@ struct term_callbacks { void (*trace)(void *ud, const char *line); }; -/* Options for term_new(). An all-zero value is valid. */ +/* + * 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 negative scrollback fails too. + * cursor_style must be a value of enum term_cursor_style. + */ struct term_options { - struct term_vector2i size; /* columns and rows; each is at least 1 */ + 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]; }; -/* NULL when memory runs out. */ /* 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 @@ -165,18 +192,21 @@ TERM_API size_t term_scan_printable_span(const char *buf, size_t len, unsigned c * 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 spin lock: keep it - * short. The thread that holds it can call every function, and it can enter - * the section again. */ + * 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 when memory runs out; the terminal - * is then unchanged. The screen reflows to the new width. */ +/* 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 @@ -197,7 +227,12 @@ enum term_feed_flags { TERM_FEED_ONLCR = 1u << 0, }; -TERM_API void term_feed(struct term *t, const char *bytes, size_t len, unsigned flags); +/* + * 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); @@ -408,11 +443,16 @@ struct term_view { 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. */ +/* 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. */ + * 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. */ @@ -423,10 +463,13 @@ TERM_API int term_history_rows(const struct term *t); * 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 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. */ diff --git a/include/term/term_input.h b/include/term/term_input.h index c317bea..19d9355 100644 --- a/include/term/term_input.h +++ b/include/term/term_input.h @@ -1,5 +1,5 @@ -#ifndef TERM_INPUT_TYPES_H -#define TERM_INPUT_TYPES_H +#ifndef TERM_INPUT_H +#define TERM_INPUT_H #include <stdbool.h> #include <stddef.h> @@ -199,4 +199,4 @@ struct term_input_result { } #endif -#endif /* TERM_INPUT_TYPES_H */ +#endif /* TERM_INPUT_H */ diff --git a/include/term/unicode/grapheme.h b/include/term/unicode/grapheme.h index 5573949..0946bb6 100644 --- a/include/term/unicode/grapheme.h +++ b/include/term/unicode/grapheme.h @@ -5,20 +5,20 @@ #include <stddef.h> #include <stdint.h> -#define GRAPHEME_MAX_LEN 20 -#define GRAPHEME_HANDLE_BASE 0x7F000000u +#define TERM_GRAPHEME_MAX_LEN 20 +#define TERM_GRAPHEME_HANDLE_BASE 0x7F000000u -static inline bool grapheme_is_handle(uint32_t c) +static inline bool term_grapheme_is_handle(uint32_t c) { - return c >= GRAPHEME_HANDLE_BASE; + return c >= TERM_GRAPHEME_HANDLE_BASE; } -static inline bool grapheme_regional_indicator(uint32_t cp) +static inline bool term_grapheme_regional_indicator(uint32_t cp) { return cp >= 0x1F1E6 && cp <= 0x1F1FF; } -static inline bool grapheme_emoji_modifier(uint32_t cp) +static inline bool term_grapheme_emoji_modifier(uint32_t cp) { return cp >= 0x1F3FB && cp <= 0x1F3FF; } diff --git a/include/term/unicode/unicode_data.inc b/include/term/unicode/unicode_data.inc index 8053b01..4ab1461 100644 --- a/include/term/unicode/unicode_data.inc +++ b/include/term/unicode/unicode_data.inc @@ -1,8 +1,8 @@ /* Generated from Unicode 18.0.0 data by tools/generate_unicode.py. */ -#define UNICODE_DATA_VERSION "18.0.0" +#define TERM_UNICODE_DATA_VERSION "18.0.0" -static const struct unicode_range zero_width[] = { +static const struct term_unicode_range term_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 unicode_range zero_width[] = { {0xE0020,0xE007F},{0xE0100,0xE01EF}, }; -static const struct unicode_range nonprintable[] = { +static const struct term_unicode_range term_nonprintable[] = { {0x0,0x1F},{0x7F,0x9F},{0xD800,0xDFFF}, }; -static const struct unicode_range unicode_wide[] = { +static const struct term_unicode_range term_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 unicode_range unicode_wide[] = { {0x20000,0x2FFFD},{0x30000,0x3FFFD}, }; -static const struct unicode_range spacing_mark[] = { +static const struct term_unicode_range term_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 unicode_range spacing_mark[] = { {0x1D16D,0x1D172},{0x1D250,0x1D252},{0x1D25F,0x1D25F},{0x1D280,0x1D281}, }; -static const struct unicode_range extended_pictographic[] = { +static const struct term_unicode_range term_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 unicode_range extended_pictographic[] = { {0x1F947,0x1F9FF},{0x1FA58,0x1FA5F},{0x1FA6E,0x1FAFF},{0x1FC00,0x1FFFD}, }; -static const struct unicode_range emoji_presentation[] = { +static const struct term_unicode_range term_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/term/unicode/utf8.h index 1c3cc3f..ad44465 100644 --- a/include/term/unicode/utf8.h +++ b/include/term/unicode/utf8.h @@ -1,19 +1,19 @@ -#ifndef UTF_8_H -#define UTF_8_H +#ifndef TERM_UNICODE_UTF8_H +#define TERM_UNICODE_UTF8_H #include <stdint.h> #include <stddef.h> #include <stdlib.h> #include <string.h> -#define UTF8_ACCEPT 0 -#define UTF8_REJECT 1 +#define TERM_UTF8_ACCEPT 0 +#define TERM_UTF8_REJECT 1 -#define UTF8_3BYTE_MIN 0x800u -#define UTF8_SURROGATE_LO 0xd800u -#define UTF8_SURROGATE_HI 0xdfffu +#define TERM_UTF8_3BYTE_MIN 0x800u +#define TERM_UTF8_SURROGATE_LO 0xd800u +#define TERM_UTF8_SURROGATE_HI 0xdfffu -static const uint8_t utf8d[] = { +static const uint8_t term_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 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 utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte) { +static inline uint32_t term_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte) { byte &= 0xff; - uint32_t type = utf8d[byte]; + uint32_t type = term_utf8d[byte]; - *codep = (*state != UTF8_ACCEPT) ? + *codep = (*state != TERM_UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); - *state = utf8d[256 + *state*16 + type]; + *state = term_utf8d[256 + *state*16 + type]; return *state; } -static const uint8_t utf8_acc_state[256] = { +static const uint8_t term_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 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 utf8_acc_codep[256] = { +static const uint8_t term_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 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 utf8_decode_ground(uint32_t *state, uint32_t *codep, +static inline int term_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 utf8_decode_ground(uint32_t *state, uint32_t *codep, do { unsigned char c = (unsigned char)buf[n]; if (c < 0x20) { - if (st != UTF8_ACCEPT) *cp = 0xFFFD; - st = UTF8_ACCEPT; + if (st != TERM_UTF8_ACCEPT) *cp = 0xFFFD; + st = TERM_UTF8_ACCEPT; break; } uint32_t before = st; n++; - if (st == UTF8_ACCEPT) { - cpv = utf8_acc_codep[c]; - st = utf8_acc_state[c]; + if (st == TERM_UTF8_ACCEPT) { + cpv = term_utf8_acc_codep[c]; + st = term_utf8_acc_state[c]; } else { - uint32_t type = utf8d[c]; + uint32_t type = term_utf8d[c]; cpv = (c & 0x3fu) | (cpv << 6); - st = utf8d[256 + st*16 + type]; + st = term_utf8d[256 + st*16 + type]; } - if (st == UTF8_ACCEPT) { *cp = cpv; break; } - if (st == UTF8_REJECT) { - st = UTF8_ACCEPT; + if (st == TERM_UTF8_ACCEPT) { *cp = cpv; break; } + if (st == TERM_UTF8_REJECT) { + st = TERM_UTF8_ACCEPT; *cp = 0xFFFD; - if (before != UTF8_ACCEPT) n--; + if (before != TERM_UTF8_ACCEPT) n--; break; } } while ((size_t)n < len); @@ -125,7 +125,7 @@ static inline int utf8_decode_ground(uint32_t *state, uint32_t *codep, } static inline int -utf8_decode_one(const char *buf, size_t len, uint32_t *codep) +term_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 @@ 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 < UTF8_3BYTE_MIN || - (cp >= UTF8_SURROGATE_LO && cp <= UTF8_SURROGATE_HI)) + if (cp < TERM_UTF8_3BYTE_MIN || + (cp >= TERM_UTF8_SURROGATE_LO && cp <= TERM_UTF8_SURROGATE_HI)) return 0; *codep = cp; return 3; @@ -183,14 +183,14 @@ utf8_decode_one(const char *buf, size_t len, uint32_t *codep) } static inline void -utf8_sanitize(char *dst, size_t cap, const char *src) +term_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 = utf8_decode_one(src + off, len - off, &cp); + int n = term_utf8_decode_one(src + off, len - off, &cp); if (n <= 0 || i + (size_t)n >= cap) { off++; continue; @@ -204,17 +204,17 @@ 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 *utf8_sanitize_dup(const char *src) +static inline char *term_utf8_sanitize_dup(const char *src) { size_t cap = strlen(src) + 1; - char *dst = malloc(cap); + char *dst = (char *)malloc(cap); if (dst) - utf8_sanitize(dst, cap, src); + term_utf8_sanitize(dst, cap, src); return dst; } -#define UTF8_MAX_BYTES 4 -static inline int utf8_encode(uint32_t cp, char *out) +#define TERM_UTF8_MAX_BYTES 4 +static inline int term_utf8_encode(uint32_t cp, char *out) { if (cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) cp = 0xfffd; diff --git a/include/term/unicode/width.h b/include/term/unicode/width.h index a7dfe66..a85ec77 100644 --- a/include/term/unicode/width.h +++ b/include/term/unicode/width.h @@ -5,15 +5,15 @@ #include <stddef.h> #include <stdint.h> -struct unicode_range { uint32_t lo, hi; }; +struct term_unicode_range { uint32_t lo, hi; }; #include "unicode_data.inc" -static inline bool in_ranges(const struct unicode_range *ranges, size_t count, uint32_t cp) +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 unicode_range *base = ranges; + const struct term_unicode_range *base = ranges; size_t n = count; while (n > 1) { size_t half = n / 2; @@ -23,34 +23,34 @@ static inline bool in_ranges(const struct unicode_range *ranges, size_t count, u return cp <= base->hi; } -#define IN_TABLE(table, cp) in_ranges(table, sizeof(table) / sizeof(table[0]), cp) +#define TERM_IN_TABLE(table, cp) term_in_ranges(table, sizeof(table) / sizeof(table[0]), cp) -static inline int unicode_width(uint32_t cp) +static inline int term_unicode_width(uint32_t cp) { - if (cp > 0x10FFFF || IN_TABLE(nonprintable, cp)) + if (cp > 0x10FFFF || TERM_IN_TABLE(term_nonprintable, cp)) return -1; - if (IN_TABLE(zero_width, cp)) + if (TERM_IN_TABLE(term_zero_width, cp)) return 0; - return IN_TABLE(unicode_wide, cp) ? 2 : 1; + return TERM_IN_TABLE(term_unicode_wide, cp) ? 2 : 1; } -static inline bool unicode_extended_pictographic(uint32_t cp) +static inline bool term_unicode_extended_pictographic(uint32_t cp) { - return IN_TABLE(extended_pictographic, cp); + return TERM_IN_TABLE(term_extended_pictographic, cp); } -static inline bool unicode_emoji_presentation(uint32_t cp) +static inline bool term_unicode_emoji_presentation(uint32_t cp) { - return IN_TABLE(emoji_presentation, cp); + return TERM_IN_TABLE(term_emoji_presentation, cp); } -static inline bool unicode_spacing_mark(uint32_t cp) +static inline bool term_unicode_spacing_mark(uint32_t cp) { if (cp < 0x903 || ((cp - 0xABEDu) < (0x11000u - 0xABEDu)) || cp > 0x1D281) return false; - return IN_TABLE(spacing_mark, cp); + return TERM_IN_TABLE(term_spacing_mark, cp); } -#undef IN_TABLE +#undef TERM_IN_TABLE #endif |
