From af6a37b1c4509c7766933a7cb45d2ee9a3a23f98 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Thu, 15 Oct 2026 11:37:31 +0300 Subject: Return owned text and share cell attribute flags with snapshots Make text queries return allocated strings released with term_text_free, keeping each capture atomic. Align public attributes with the write core, remove snapshot conversion tables, and migrate tests and the Kitty adapter. --- include/term/term.h | 77 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'include/term') diff --git a/include/term/term.h b/include/term/term.h index 9c6281b..dc41114 100644 --- a/include/term/term.h +++ b/include/term/term.h @@ -11,8 +11,9 @@ * 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. A function that returns - * text copies it into a buffer that the caller owns. + * 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 @@ -262,11 +263,13 @@ TERM_API struct term_input_result term_input_encode_paste( ); /* The cursor in screen coordinates (not the viewport). */ TERM_API struct term_cursor term_cursor(const struct term *t); -/* Copy the directory from OSC 7 into buf, with the rules of - * term_selection_text(). Return 0 when there is none. */ -TERM_API size_t term_cwd(const struct term *t, char *buf, size_t cap); -/* Copy the pointer shape name from OSC 22 the same way. */ -TERM_API size_t term_pointer_shape(const struct term *t, char *buf, size_t cap); +/* 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 @@ -302,30 +305,36 @@ TERM_API void term_select_start(struct term *t, struct term_vector2i cell, bool TERM_API void 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); -/* Copy the selected text as UTF-8 into buf. Return its length without the NUL. - * With a NULL buf or a zero cap, only the length is returned. Otherwise the - * copy is cut to cap - 1 bytes and NUL-terminated. Return 0 when nothing is - * selected. Hold term_lock across the length query and the copy to keep the - * length stable. */ -TERM_API size_t term_selection_text(const struct term *t, char *buf, size_t cap); -/* The OSC 8 link or the detected URL at a viewport cell. Copies it with the - * same rules as term_selection_text(). Return 0 when there is no link. */ -TERM_API size_t term_link_at(const struct term *t, struct term_vector2i cell, char *buf, size_t cap); - -/* Cell attributes. */ +/* 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_FAINT = 1u << 2, + TERM_ATTR_UNDERLINE = 1u << 2, TERM_ATTR_STRIKE = 1u << 3, TERM_ATTR_OVERLINE = 1u << 4, - TERM_ATTR_LINK = 1u << 5, - TERM_ATTR_EMOJI = 1u << 6, /* the text requested emoji presentation */ - TERM_ATTR_TEXT = 1u << 7, /* the text requested text presentation */ + 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_SHIFT 8 -#define TERM_ATTR_UNDERLINE_MASK (7u << TERM_ATTR_UNDERLINE_SHIFT) +#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, @@ -338,7 +347,11 @@ enum term_underline { static inline enum term_underline term_attr_underline(uint16_t attrs) { - return (enum term_underline)((attrs & TERM_ATTR_UNDERLINE_MASK) >> TERM_ATTR_UNDERLINE_SHIFT); + 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(). */ @@ -348,7 +361,7 @@ static inline enum term_underline term_attr_underline(uint16_t attrs) 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 and the underline style */ + 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; }; @@ -404,12 +417,12 @@ 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); -/* Copy up to max_rows history rows before the current viewport as UTF-8 into - * buf, with the same rules as term_selection_text(). Join soft-wrapped rows. - * End closed lines with a newline. This does not change the selection. - * Return 0 when there is no history text, and also when the text cannot be - * built. */ -TERM_API size_t term_history_text(struct term *t, int max_rows, char *buf, size_t cap); +/* 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); 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 -- cgit v1.2.3