1/**
2 * @file sgr.h
3 *
4 * SGR (Select Graphic Rendition) attribute parsing and handling.
5 */
6
7#ifndef GHOSTTY_VT_SGR_H
8#define GHOSTTY_VT_SGR_H
9
10/** @defgroup sgr SGR Parser
11 *
12 * SGR (Select Graphic Rendition) attribute parser.
13 *
14 * SGR sequences are the syntax used to set styling attributes such as
15 * bold, italic, underline, and colors for text in terminal emulators.
16 * For example, you may be familiar with sequences like `ESC[1;31m`. The
17 * `1;31` is the SGR attribute list.
18 *
19 * The parser processes SGR parameters from CSI sequences (e.g., `ESC[1;31m`)
20 * and returns individual text attributes like bold, italic, colors, etc.
21 * It supports both semicolon (`;`) and colon (`:`) separators, possibly mixed,
22 * and handles various color formats including 8-color, 16-color, 256-color,
23 * X11 named colors, and RGB in multiple formats.
24 *
25 * ## Basic Usage
26 *
27 * 1. Create a parser instance with ghostty_sgr_new()
28 * 2. Set SGR parameters with ghostty_sgr_set_params()
29 * 3. Iterate through attributes using ghostty_sgr_next()
30 * 4. Free the parser with ghostty_sgr_free() when done
31 *
32 * ## Example
33 *
34 * @snippet c-vt-sgr/src/main.c sgr-basic
35 *
36 * @{
37 */
38
39#include <ghostty/vt/allocator.h>
40#include <ghostty/vt/color.h>
41#include <ghostty/vt/types.h>
42#include <stdbool.h>
43#include <stddef.h>
44#include <stdint.h>
45
46#ifdef __cplusplus
47extern "C" {
48#endif
49
50/**
51 * SGR attribute tags.
52 *
53 * These values identify the type of an SGR attribute in a tagged union.
54 * Use the tag to determine which field in the attribute value union to access.
55 *
56 * @ingroup sgr
57 */
58typedef enum GHOSTTY_ENUM_TYPED {
59 GHOSTTY_SGR_ATTR_UNSET = 0,
60 GHOSTTY_SGR_ATTR_UNKNOWN = 1,
61 GHOSTTY_SGR_ATTR_BOLD = 2,
62 GHOSTTY_SGR_ATTR_RESET_BOLD = 3,
63 GHOSTTY_SGR_ATTR_ITALIC = 4,
64 GHOSTTY_SGR_ATTR_RESET_ITALIC = 5,
65 GHOSTTY_SGR_ATTR_FAINT = 6,
66 GHOSTTY_SGR_ATTR_UNDERLINE = 7,
67 GHOSTTY_SGR_ATTR_UNDERLINE_COLOR = 8,
68 GHOSTTY_SGR_ATTR_UNDERLINE_COLOR_256 = 9,
69 GHOSTTY_SGR_ATTR_RESET_UNDERLINE_COLOR = 10,
70 GHOSTTY_SGR_ATTR_OVERLINE = 11,
71 GHOSTTY_SGR_ATTR_RESET_OVERLINE = 12,
72 GHOSTTY_SGR_ATTR_BLINK = 13,
73 GHOSTTY_SGR_ATTR_RESET_BLINK = 14,
74 GHOSTTY_SGR_ATTR_INVERSE = 15,
75 GHOSTTY_SGR_ATTR_RESET_INVERSE = 16,
76 GHOSTTY_SGR_ATTR_INVISIBLE = 17,
77 GHOSTTY_SGR_ATTR_RESET_INVISIBLE = 18,
78 GHOSTTY_SGR_ATTR_STRIKETHROUGH = 19,
79 GHOSTTY_SGR_ATTR_RESET_STRIKETHROUGH = 20,
80 GHOSTTY_SGR_ATTR_DIRECT_COLOR_FG = 21,
81 GHOSTTY_SGR_ATTR_DIRECT_COLOR_BG = 22,
82 GHOSTTY_SGR_ATTR_BG_8 = 23,
83 GHOSTTY_SGR_ATTR_FG_8 = 24,
84 GHOSTTY_SGR_ATTR_RESET_FG = 25,
85 GHOSTTY_SGR_ATTR_RESET_BG = 26,
86 GHOSTTY_SGR_ATTR_BRIGHT_BG_8 = 27,
87 GHOSTTY_SGR_ATTR_BRIGHT_FG_8 = 28,
88 GHOSTTY_SGR_ATTR_BG_256 = 29,
89 GHOSTTY_SGR_ATTR_FG_256 = 30,
90 GHOSTTY_SGR_ATTR_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
91} GhosttySgrAttributeTag;
92
93/**
94 * Underline style types.
95 *
96 * @ingroup sgr
97 */
98typedef enum GHOSTTY_ENUM_TYPED {
99 GHOSTTY_SGR_UNDERLINE_NONE = 0,
100 GHOSTTY_SGR_UNDERLINE_SINGLE = 1,
101 GHOSTTY_SGR_UNDERLINE_DOUBLE = 2,
102 GHOSTTY_SGR_UNDERLINE_CURLY = 3,
103 GHOSTTY_SGR_UNDERLINE_DOTTED = 4,
104 GHOSTTY_SGR_UNDERLINE_DASHED = 5,
105 GHOSTTY_SGR_UNDERLINE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
106} GhosttySgrUnderline;
107
108/**
109 * Unknown SGR attribute data.
110 *
111 * Contains the full parameter list and the partial list where parsing
112 * encountered an unknown or invalid sequence.
113 *
114 * @ingroup sgr
115 */
116typedef struct {
117 const uint16_t* full_ptr;
118 size_t full_len;
119 const uint16_t* partial_ptr;
120 size_t partial_len;
121} GhosttySgrUnknown;
122
123/**
124 * SGR attribute value union.
125 *
126 * This union contains all possible attribute values. Use the tag field
127 * to determine which union member is active. Attributes without associated
128 * data (like bold, italic) don't use the union value.
129 *
130 * @ingroup sgr
131 */
132typedef union {
133 GhosttySgrUnknown unknown;
134 GhosttySgrUnderline underline;
135 GhosttyColorRgb underline_color;
136 GhosttyColorPaletteIndex underline_color_256;
137 GhosttyColorRgb direct_color_fg;
138 GhosttyColorRgb direct_color_bg;
139 GhosttyColorPaletteIndex bg_8;
140 GhosttyColorPaletteIndex fg_8;
141 GhosttyColorPaletteIndex bright_bg_8;
142 GhosttyColorPaletteIndex bright_fg_8;
143 GhosttyColorPaletteIndex bg_256;
144 GhosttyColorPaletteIndex fg_256;
145 uint64_t _padding[8];
146} GhosttySgrAttributeValue;
147
148/**
149 * SGR attribute (tagged union).
150 *
151 * A complete SGR attribute with both its type tag and associated value.
152 * Always check the tag field to determine which value union member is valid.
153 *
154 * Attributes without associated data (e.g., GHOSTTY_SGR_ATTR_BOLD) can be
155 * identified by tag alone; the value union is not used for these and
156 * the memory in the value field is undefined.
157 *
158 * @ingroup sgr
159 */
160typedef struct {
161 GhosttySgrAttributeTag tag;
162 GhosttySgrAttributeValue value;
163} GhosttySgrAttribute;
164
165/**
166 * Create a new SGR parser instance.
167 *
168 * Creates a new SGR (Select Graphic Rendition) parser using the provided
169 * allocator. The parser must be freed using ghostty_sgr_free() when
170 * no longer needed.
171 *
172 * @param allocator Pointer to the allocator to use for memory management, or
173 * NULL to use the default allocator
174 * @param parser Pointer to store the created parser handle
175 * @return GHOSTTY_SUCCESS on success, or an error code on failure
176 *
177 * @ingroup sgr
178 */
179GHOSTTY_API GhosttyResult ghostty_sgr_new(const GhosttyAllocator* allocator,
180 GhosttySgrParser* parser);
181
182/**
183 * Free an SGR parser instance.
184 *
185 * Releases all resources associated with the SGR parser. After this call,
186 * the parser handle becomes invalid and must not be used. This includes
187 * any attributes previously returned by ghostty_sgr_next().
188 *
189 * @param parser The parser handle to free (may be NULL)
190 *
191 * @ingroup sgr
192 */
193GHOSTTY_API void ghostty_sgr_free(GhosttySgrParser parser);
194
195/**
196 * Reset an SGR parser instance to the beginning of the parameter list.
197 *
198 * Resets the parser's iteration state without clearing the parameters.
199 * After calling this, ghostty_sgr_next() will start from the beginning
200 * of the parameter list again.
201 *
202 * @param parser The parser handle to reset, must not be NULL
203 *
204 * @ingroup sgr
205 */
206GHOSTTY_API void ghostty_sgr_reset(GhosttySgrParser parser);
207
208/**
209 * Set SGR parameters for parsing.
210 *
211 * Sets the SGR parameter list to parse. Parameters are the numeric values
212 * from a CSI SGR sequence (e.g., for `ESC[1;31m`, params would be {1, 31}).
213 *
214 * The separators array optionally specifies the separator type for each
215 * parameter position. Each byte should be either ';' for semicolon or ':'
216 * for colon. This is needed for certain color formats that use colon
217 * separators (e.g., `ESC[4:3m` for curly underline). Any invalid separator
218 * values are treated as semicolons. The separators array must have the same
219 * length as the params array, if it is not NULL.
220 *
221 * If separators is NULL, all parameters are assumed to be semicolon-separated.
222 *
223 * This function makes an internal copy of the parameter and separator data,
224 * so the caller can safely free or modify the input arrays after this call.
225 *
226 * After calling this function, the parser is automatically reset and ready
227 * to iterate from the beginning.
228 *
229 * @param parser The parser handle, must not be NULL
230 * @param params Array of SGR parameter values
231 * @param separators Optional array of separator characters (';' or ':'), or
232 * NULL
233 * @param len Number of parameters (and separators if provided)
234 * @return GHOSTTY_SUCCESS on success, or an error code on failure
235 *
236 * @ingroup sgr
237 */
238GHOSTTY_API GhosttyResult ghostty_sgr_set_params(GhosttySgrParser parser,
239 const uint16_t* params,
240 const char* separators,
241 size_t len);
242
243/**
244 * Get the next SGR attribute.
245 *
246 * Parses and returns the next attribute from the parameter list.
247 * Call this function repeatedly until it returns false to process
248 * all attributes in the sequence.
249 *
250 * @param parser The parser handle, must not be NULL
251 * @param attr Pointer to store the next attribute
252 * @return true if an attribute was returned, false if no more attributes
253 *
254 * @ingroup sgr
255 */
256GHOSTTY_API bool ghostty_sgr_next(GhosttySgrParser parser, GhosttySgrAttribute* attr);
257
258/**
259 * Get the full parameter list from an unknown SGR attribute.
260 *
261 * This function retrieves the full parameter list that was provided to the
262 * parser when an unknown attribute was encountered. Primarily useful in
263 * WebAssembly environments where accessing struct fields directly is difficult.
264 *
265 * @param unknown The unknown attribute data
266 * @param ptr Pointer to store the pointer to the parameter array (may be NULL)
267 * @return The length of the full parameter array
268 *
269 * @ingroup sgr
270 */
271GHOSTTY_API size_t ghostty_sgr_unknown_full(GhosttySgrUnknown unknown,
272 const uint16_t** ptr);
273
274/**
275 * Get the partial parameter list from an unknown SGR attribute.
276 *
277 * This function retrieves the partial parameter list where parsing stopped
278 * when an unknown attribute was encountered. Primarily useful in WebAssembly
279 * environments where accessing struct fields directly is difficult.
280 *
281 * @param unknown The unknown attribute data
282 * @param ptr Pointer to store the pointer to the parameter array (may be NULL)
283 * @return The length of the partial parameter array
284 *
285 * @ingroup sgr
286 */
287GHOSTTY_API size_t ghostty_sgr_unknown_partial(GhosttySgrUnknown unknown,
288 const uint16_t** ptr);
289
290/**
291 * Get the tag from an SGR attribute.
292 *
293 * This function extracts the tag that identifies which type of attribute
294 * this is. Primarily useful in WebAssembly environments where accessing
295 * struct fields directly is difficult.
296 *
297 * @param attr The SGR attribute
298 * @return The attribute tag
299 *
300 * @ingroup sgr
301 */
302GHOSTTY_API GhosttySgrAttributeTag ghostty_sgr_attribute_tag(GhosttySgrAttribute attr);
303
304/**
305 * Get the value from an SGR attribute.
306 *
307 * This function returns a pointer to the value union from an SGR attribute. Use
308 * the tag to determine which field of the union is valid. Primarily useful in
309 * WebAssembly environments where accessing struct fields directly is difficult.
310 *
311 * @param attr Pointer to the SGR attribute
312 * @return Pointer to the attribute value union
313 *
314 * @ingroup sgr
315 */
316GHOSTTY_API GhosttySgrAttributeValue* ghostty_sgr_attribute_value(
317 GhosttySgrAttribute* attr);
318
319#ifdef __wasm__
320/**
321 * Allocate memory for an SGR attribute (WebAssembly only).
322 *
323 * This is a convenience function for WebAssembly environments to allocate
324 * memory for an SGR attribute structure that can be passed to ghostty_sgr_next.
325 *
326 * @return Pointer to the allocated attribute structure
327 *
328 * @ingroup wasm
329 */
330GHOSTTY_API GhosttySgrAttribute* ghostty_wasm_alloc_sgr_attribute(void);
331
332/**
333 * Free memory for an SGR attribute (WebAssembly only).
334 *
335 * Frees memory allocated by ghostty_wasm_alloc_sgr_attribute.
336 *
337 * @param attr Pointer to the attribute structure to free
338 *
339 * @ingroup wasm
340 */
341GHOSTTY_API void ghostty_wasm_free_sgr_attribute(GhosttySgrAttribute* attr);
342#endif
343
344#ifdef __cplusplus
345}
346#endif
347
348/** @} */
349
350#endif /* GHOSTTY_VT_SGR_H */