1/**
2 * @file render.h
3 *
4 * Render state for creating high performance renderers.
5 */
6
7#ifndef GHOSTTY_VT_RENDER_H
8#define GHOSTTY_VT_RENDER_H
9
10#include <stdbool.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <ghostty/vt/allocator.h>
14#include <ghostty/vt/color.h>
15#include <ghostty/vt/terminal.h>
16#include <ghostty/vt/types.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22/** @defgroup render Render State
23 *
24 * Represents the state required to render a visible screen (a viewport)
25 * of a terminal instance. This is stateful and optimized for repeated
26 * updates from a single terminal instance and only updating dirty regions
27 * of the screen.
28 *
29 * The key design principle of this API is that it only needs read/write
30 * access to the terminal instance during the update call. This allows
31 * the render state to minimally impact terminal IO performance and also
32 * allows the renderer to be safely multi-threaded (as long as a lock is
33 * held during the update call to ensure exclusive access to the terminal
34 * instance).
35 *
36 * The basic usage of this API is:
37 *
38 * 1. Create an empty render state
39 * 2. Update it from a terminal instance whenever you need.
40 * 3. Read from the render state to get the data needed to draw your frame.
41 *
42 * ## Dirty Tracking
43 *
44 * Dirty tracking is a key feature of the render state that allows renderers
45 * to efficiently determine what parts of the screen have changed and only
46 * redraw changed regions.
47 *
48 * The render state API keeps track of dirty state at two independent layers:
49 * a global dirty state that indicates whether the entire frame is clean,
50 * partially dirty, or fully dirty, and a per-row dirty state that allows
51 * tracking which rows in a partially dirty frame have changed.
52 *
53 * The user of the render state API is expected to unset both of these.
54 * The `update` call does not unset dirty state, it only updates it.
55 *
56 * An extremely important detail: setting one dirty state doesn't unset
57 * the other. For example, setting the global dirty state to false does not
58 * reset the row-level dirty flags. So, the caller of the render state API must
59 * be careful to manage both layers of dirty state correctly.
60 *
61 * ## Examples
62 *
63 * ### Creating and updating render state
64 * @snippet c-vt-render/src/main.c render-state-update
65 *
66 * ### Checking dirty state
67 * @snippet c-vt-render/src/main.c render-dirty-check
68 *
69 * ### Reading colors
70 * @snippet c-vt-render/src/main.c render-colors
71 *
72 * ### Reading cursor state
73 * @snippet c-vt-render/src/main.c render-cursor
74 *
75 * ### Iterating rows and cells
76 * @snippet c-vt-render/src/main.c render-row-iterate
77 *
78 * ### Resetting dirty state after rendering
79 * @snippet c-vt-render/src/main.c render-dirty-reset
80 *
81 * @{
82 */
83
84/**
85 * Dirty state of a render state after update.
86 *
87 * @ingroup render
88 */
89typedef enum GHOSTTY_ENUM_TYPED {
90 /** Not dirty at all; rendering can be skipped. */
91 GHOSTTY_RENDER_STATE_DIRTY_FALSE = 0,
92
93 /** Some rows changed; renderer can redraw incrementally. */
94 GHOSTTY_RENDER_STATE_DIRTY_PARTIAL = 1,
95
96 /** Global state changed; renderer should redraw everything. */
97 GHOSTTY_RENDER_STATE_DIRTY_FULL = 2,
98 GHOSTTY_RENDER_STATE_DIRTY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
99} GhosttyRenderStateDirty;
100
101/**
102 * Visual style of the cursor.
103 *
104 * @ingroup render
105 */
106typedef enum GHOSTTY_ENUM_TYPED {
107 /** Bar cursor (DECSCUSR 5, 6). */
108 GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BAR = 0,
109
110 /** Block cursor (DECSCUSR 1, 2). */
111 GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK = 1,
112
113 /** Underline cursor (DECSCUSR 3, 4). */
114 GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_UNDERLINE = 2,
115
116 /** Hollow block cursor. */
117 GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK_HOLLOW = 3,
118 GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
119} GhosttyRenderStateCursorVisualStyle;
120
121/**
122 * Queryable data kinds for ghostty_render_state_get().
123 *
124 * @ingroup render
125 */
126typedef enum GHOSTTY_ENUM_TYPED {
127 /** Invalid / sentinel value. */
128 GHOSTTY_RENDER_STATE_DATA_INVALID = 0,
129
130 /** Viewport width in cells (uint16_t). */
131 GHOSTTY_RENDER_STATE_DATA_COLS = 1,
132
133 /** Viewport height in cells (uint16_t). */
134 GHOSTTY_RENDER_STATE_DATA_ROWS = 2,
135
136 /** Current dirty state (GhosttyRenderStateDirty). */
137 GHOSTTY_RENDER_STATE_DATA_DIRTY = 3,
138
139 /** Populate a pre-allocated GhosttyRenderStateRowIterator with row data
140 * from the render state (GhosttyRenderStateRowIterator). Row data is
141 * only valid as long as the underlying render state is not updated.
142 * It is unsafe to use row data after updating the render state.
143 * */
144 GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR = 4,
145
146 /** Default/current background color (GhosttyColorRgb). */
147 GHOSTTY_RENDER_STATE_DATA_COLOR_BACKGROUND = 5,
148
149 /** Default/current foreground color (GhosttyColorRgb). */
150 GHOSTTY_RENDER_STATE_DATA_COLOR_FOREGROUND = 6,
151
152 /** Cursor color when explicitly set by terminal state (GhosttyColorRgb).
153 * Returns GHOSTTY_INVALID_VALUE if no explicit cursor color is set;
154 * use COLOR_CURSOR_HAS_VALUE to check first. */
155 GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR = 7,
156
157 /** Whether an explicit cursor color is set (bool). */
158 GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR_HAS_VALUE = 8,
159
160 /** The active 256-color palette (GhosttyColorRgb[256]). */
161 GHOSTTY_RENDER_STATE_DATA_COLOR_PALETTE = 9,
162
163 /** The visual style of the cursor (GhosttyRenderStateCursorVisualStyle). */
164 GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE = 10,
165
166 /** Whether the cursor is visible based on terminal modes (bool). */
167 GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE = 11,
168
169 /** Whether the cursor should blink based on terminal modes (bool). */
170 GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING = 12,
171
172 /** Whether the cursor is at a password input field (bool). */
173 GHOSTTY_RENDER_STATE_DATA_CURSOR_PASSWORD_INPUT = 13,
174
175 /** Whether the cursor is visible within the viewport (bool).
176 * If false, the cursor viewport position values are undefined. */
177 GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE = 14,
178
179 /** Cursor viewport x position in cells (uint16_t).
180 * Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
181 GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X = 15,
182
183 /** Cursor viewport y position in cells (uint16_t).
184 * Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
185 GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y = 16,
186
187 /** Whether the cursor is on the tail of a wide character (bool).
188 * Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
189 GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_WIDE_TAIL = 17,
190 GHOSTTY_RENDER_STATE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
191} GhosttyRenderStateData;
192
193/**
194 * Settable options for ghostty_render_state_set().
195 *
196 * @ingroup render
197 */
198typedef enum GHOSTTY_ENUM_TYPED {
199 /** Set dirty state (GhosttyRenderStateDirty). */
200 GHOSTTY_RENDER_STATE_OPTION_DIRTY = 0,
201 GHOSTTY_RENDER_STATE_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
202} GhosttyRenderStateOption;
203
204/**
205 * Queryable data kinds for ghostty_render_state_row_get().
206 *
207 * @ingroup render
208 */
209typedef enum GHOSTTY_ENUM_TYPED {
210 /** Invalid / sentinel value. */
211 GHOSTTY_RENDER_STATE_ROW_DATA_INVALID = 0,
212
213 /** Whether the current row is dirty (bool). */
214 GHOSTTY_RENDER_STATE_ROW_DATA_DIRTY = 1,
215
216 /** The raw row value (GhosttyRow). */
217 GHOSTTY_RENDER_STATE_ROW_DATA_RAW = 2,
218
219 /** Populate a pre-allocated GhosttyRenderStateRowCells with cell data for
220 * the current row (GhosttyRenderStateRowCells). Cell data is only
221 * valid as long as the underlying render state is not updated.
222 * It is unsafe to use cell data after updating the render state. */
223 GHOSTTY_RENDER_STATE_ROW_DATA_CELLS = 3,
224
225 /** Row-local selected cell range (GhosttyRenderStateRowSelection). */
226 GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION = 4,
227 GHOSTTY_RENDER_STATE_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
228} GhosttyRenderStateRowData;
229
230/**
231 * Settable options for ghostty_render_state_row_set().
232 *
233 * @ingroup render
234 */
235typedef enum GHOSTTY_ENUM_TYPED {
236 /** Set dirty state for the current row (bool). */
237 GHOSTTY_RENDER_STATE_ROW_OPTION_DIRTY = 0,
238 GHOSTTY_RENDER_STATE_ROW_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
239} GhosttyRenderStateRowOption;
240
241/**
242 * Row-local selection range.
243 *
244 * This struct uses the sized-struct ABI pattern. Initialize with
245 * GHOSTTY_INIT_SIZED(GhosttyRenderStateRowSelection) before querying
246 * GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION.
247 *
248 * Querying GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION returns GHOSTTY_NO_VALUE
249 * if the current row does not intersect the current selection.
250 *
251 * @ingroup render
252 */
253typedef struct {
254 /** Size of this struct in bytes. Must be set to sizeof(GhosttyRenderStateRowSelection). */
255 size_t size;
256
257 /** Start column of the row-local selection range, inclusive. */
258 uint16_t start_x;
259
260 /** End column of the row-local selection range, inclusive. */
261 uint16_t end_x;
262} GhosttyRenderStateRowSelection;
263
264/**
265 * Render-state color information.
266 *
267 * This struct uses the sized-struct ABI pattern. Initialize with
268 * GHOSTTY_INIT_SIZED(GhosttyRenderStateColors) before calling
269 * ghostty_render_state_colors_get().
270 *
271 * Example:
272 * @code
273 * GhosttyRenderStateColors colors = GHOSTTY_INIT_SIZED(GhosttyRenderStateColors);
274 * GhosttyResult result = ghostty_render_state_colors_get(state, &colors);
275 * @endcode
276 *
277 * @ingroup render
278 */
279typedef struct {
280 /** Size of this struct in bytes. Must be set to sizeof(GhosttyRenderStateColors). */
281 size_t size;
282
283 /** The default/current background color for the render state. */
284 GhosttyColorRgb background;
285
286 /** The default/current foreground color for the render state. */
287 GhosttyColorRgb foreground;
288
289 /** The cursor color when explicitly set by terminal state. */
290 GhosttyColorRgb cursor;
291
292 /**
293 * True when cursor contains a valid explicit cursor color value.
294 * If this is false, the cursor color should be ignored; it will
295 * contain undefined data.
296 * */
297 bool cursor_has_value;
298
299 /** The active 256-color palette for this render state. */
300 GhosttyColorRgb palette[256];
301} GhosttyRenderStateColors;
302
303/**
304 * Create a new render state instance.
305 *
306 * @param allocator Pointer to allocator, or NULL to use the default allocator
307 * @param state Pointer to store the created render state handle
308 * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
309 * failure
310 *
311 * @ingroup render
312 */
313GHOSTTY_API GhosttyResult ghostty_render_state_new(const GhosttyAllocator* allocator,
314 GhosttyRenderState* state);
315
316/**
317 * Free a render state instance.
318 *
319 * Releases all resources associated with the render state. After this call,
320 * the render state handle becomes invalid.
321 *
322 * @param state The render state handle to free (may be NULL)
323 *
324 * @ingroup render
325 */
326GHOSTTY_API void ghostty_render_state_free(GhosttyRenderState state);
327
328/**
329 * Update a render state instance from a terminal.
330 *
331 * This consumes terminal/screen dirty state in the same way as the internal
332 * render state update path.
333 *
334 * @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
335 * @param terminal The terminal handle to read from (NULL returns GHOSTTY_INVALID_VALUE)
336 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
337 * `terminal` is NULL, GHOSTTY_OUT_OF_MEMORY if updating the state requires
338 * allocation and that allocation fails
339 *
340 * @ingroup render
341 */
342GHOSTTY_API GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
343 GhosttyTerminal terminal);
344
345/**
346 * Get a value from a render state.
347 *
348 * The `out` pointer must point to a value of the type corresponding to the
349 * requested data kind (see GhosttyRenderStateData).
350 *
351 * @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
352 * @param data The data kind to query
353 * @param[out] out Pointer to receive the queried value
354 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
355 * NULL or `data` is not a recognized enum value
356 *
357 * @ingroup render
358 */
359GHOSTTY_API GhosttyResult ghostty_render_state_get(GhosttyRenderState state,
360 GhosttyRenderStateData data,
361 void* out);
362
363/**
364 * Get multiple data fields from a render state in a single call.
365 *
366 * Each element in the keys array specifies a data kind, and the
367 * corresponding element in the values array receives the result.
368 *
369 * Processing stops at the first error; on success out_written
370 * is set to count, on error it is set to the index of the
371 * failing key (i.e. the number of values successfully written).
372 *
373 * @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
374 * @param count Number of key/value pairs
375 * @param keys Array of data kinds to query
376 * @param values Array of output pointers (types must match each key's
377 * documented output type)
378 * @param[out] out_written On return, receives the number of values
379 * successfully written (may be NULL)
380 * @return GHOSTTY_SUCCESS if all queries succeed
381 *
382 * @ingroup render
383 */
384GHOSTTY_API GhosttyResult ghostty_render_state_get_multi(
385 GhosttyRenderState state,
386 size_t count,
387 const GhosttyRenderStateData* keys,
388 void** values,
389 size_t* out_written);
390
391/**
392 * Set an option on a render state.
393 *
394 * The `value` pointer must point to a value of the type corresponding to the
395 * requested option kind (see GhosttyRenderStateOption).
396 *
397 * @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
398 * @param option The option to set
399 * @param[in] value Pointer to the value to set (NULL returns
400 * GHOSTTY_INVALID_VALUE)
401 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
402 * `value` is NULL
403 *
404 * @ingroup render
405 */
406GHOSTTY_API GhosttyResult ghostty_render_state_set(GhosttyRenderState state,
407 GhosttyRenderStateOption option,
408 const void* value);
409
410/**
411 * Get the current color information from a render state.
412 *
413 * This writes as many fields as fit in the caller-provided sized struct.
414 * `out_colors->size` must be set by the caller (typically via
415 * GHOSTTY_INIT_SIZED(GhosttyRenderStateColors)).
416 *
417 * @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
418 * @param[out] out_colors Sized output struct to receive render-state colors
419 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
420 * `out_colors` is NULL, or if `out_colors->size` is smaller than
421 * `sizeof(size_t)`
422 *
423 * @ingroup render
424 */
425GHOSTTY_API GhosttyResult ghostty_render_state_colors_get(GhosttyRenderState state,
426 GhosttyRenderStateColors* out_colors);
427
428/**
429 * Create a new row iterator instance.
430 *
431 * All fields except the allocator are left undefined until populated
432 * via ghostty_render_state_get() with
433 * GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR.
434 *
435 * @param allocator Pointer to allocator, or NULL to use the default allocator
436 * @param[out] out_iterator On success, receives the created iterator handle
437 * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
438 * failure
439 *
440 * @ingroup render
441 */
442GHOSTTY_API GhosttyResult ghostty_render_state_row_iterator_new(
443 const GhosttyAllocator* allocator,
444 GhosttyRenderStateRowIterator* out_iterator);
445
446/**
447 * Free a render-state row iterator.
448 *
449 * @param iterator The iterator handle to free (may be NULL)
450 *
451 * @ingroup render
452 */
453GHOSTTY_API void ghostty_render_state_row_iterator_free(GhosttyRenderStateRowIterator iterator);
454
455/**
456 * Move a render-state row iterator to the next row.
457 *
458 * Returns true if the iterator moved successfully and row data is
459 * available to read at the new position.
460 *
461 * @param iterator The iterator handle to advance (may be NULL)
462 * @return true if advanced to the next row, false if `iterator` is
463 * NULL or if the iterator has reached the end
464 *
465 * @ingroup render
466 */
467GHOSTTY_API bool ghostty_render_state_row_iterator_next(GhosttyRenderStateRowIterator iterator);
468
469/**
470 * Get a value from the current row in a render-state row iterator.
471 *
472 * The `out` pointer must point to a value of the type corresponding to the
473 * requested data kind (see GhosttyRenderStateRowData).
474 * Call ghostty_render_state_row_iterator_next() at least once before
475 * calling this function.
476 *
477 * @param iterator The iterator handle to query (NULL returns GHOSTTY_INVALID_VALUE)
478 * @param data The data kind to query
479 * @param[out] out Pointer to receive the queried value
480 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
481 * `iterator` is NULL or the iterator is not positioned on a row
482 *
483 * @ingroup render
484 */
485GHOSTTY_API GhosttyResult ghostty_render_state_row_get(
486 GhosttyRenderStateRowIterator iterator,
487 GhosttyRenderStateRowData data,
488 void* out);
489
490/**
491 * Get multiple data fields from the current row in a single call.
492 *
493 * Each element in the keys array specifies a data kind, and the
494 * corresponding element in the values array receives the result.
495 *
496 * Processing stops at the first error; on success out_written
497 * is set to count, on error it is set to the index of the
498 * failing key (i.e. the number of values successfully written).
499 *
500 * @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
501 * @param count Number of key/value pairs
502 * @param keys Array of data kinds to query
503 * @param values Array of output pointers (types must match each key's
504 * documented output type)
505 * @param[out] out_written On return, receives the number of values
506 * successfully written (may be NULL)
507 * @return GHOSTTY_SUCCESS if all queries succeed
508 *
509 * @ingroup render
510 */
511GHOSTTY_API GhosttyResult ghostty_render_state_row_get_multi(
512 GhosttyRenderStateRowIterator iterator,
513 size_t count,
514 const GhosttyRenderStateRowData* keys,
515 void** values,
516 size_t* out_written);
517
518/**
519 * Set an option on the current row in a render-state row iterator.
520 *
521 * The `value` pointer must point to a value of the type corresponding to the
522 * requested option kind (see GhosttyRenderStateRowOption).
523 * Call ghostty_render_state_row_iterator_next() at least once before
524 * calling this function.
525 *
526 * @param iterator The iterator handle to update (NULL returns GHOSTTY_INVALID_VALUE)
527 * @param option The option to set
528 * @param[in] value Pointer to the value to set (NULL returns
529 * GHOSTTY_INVALID_VALUE)
530 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
531 * `iterator` is NULL or the iterator is not positioned on a row
532 *
533 * @ingroup render
534 */
535GHOSTTY_API GhosttyResult ghostty_render_state_row_set(
536 GhosttyRenderStateRowIterator iterator,
537 GhosttyRenderStateRowOption option,
538 const void* value);
539
540/**
541 * Create a new row cells instance.
542 *
543 * All fields except the allocator are left undefined until populated
544 * via ghostty_render_state_row_get() with
545 * GHOSTTY_RENDER_STATE_ROW_DATA_CELLS.
546 *
547 * You can reuse this value repeatedly with ghostty_render_state_row_get() to
548 * avoid allocating a new cells container for every row.
549 *
550 * @param allocator Pointer to allocator, or NULL to use the default allocator
551 * @param[out] out_cells On success, receives the created row cells handle
552 * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
553 * failure
554 *
555 * @ingroup render
556 */
557GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_new(
558 const GhosttyAllocator* allocator,
559 GhosttyRenderStateRowCells* out_cells);
560
561/**
562 * Queryable data kinds for ghostty_render_state_row_cells_get().
563 *
564 * @ingroup render
565 */
566typedef enum GHOSTTY_ENUM_TYPED {
567 /** Invalid / sentinel value. */
568 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_INVALID = 0,
569
570 /** The raw cell value (GhosttyCell). */
571 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_RAW = 1,
572
573 /** The style for the current cell (GhosttyStyle). */
574 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_STYLE = 2,
575
576 /** The total number of grapheme codepoints including the base codepoint
577 * (uint32_t). Returns 0 if the cell has no text. */
578 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN = 3,
579
580 /** Write grapheme codepoints into a caller-provided buffer (uint32_t*).
581 * The buffer must be at least graphemes_len elements. The base codepoint
582 * is written first, followed by any extra codepoints. */
583 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF = 4,
584
585 /** The resolved background color of the cell (GhosttyColorRgb).
586 * Flattens the three possible sources: content-tag bg_color_rgb,
587 * content-tag bg_color_palette (looked up in the palette), or the
588 * style's bg_color. Returns GHOSTTY_INVALID_VALUE if the cell has
589 * no background color, in which case the caller should use whatever
590 * default background color it wants (e.g. the terminal background). */
591 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_BG_COLOR = 5,
592
593 /** The resolved foreground color of the cell (GhosttyColorRgb).
594 * Resolves palette indices through the palette. Bold color handling
595 * is not applied; the caller should handle bold styling separately.
596 * Returns GHOSTTY_INVALID_VALUE if the cell has no explicit foreground
597 * color, in which case the caller should use whatever default foreground
598 * color it wants (e.g. the terminal foreground). */
599 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_FG_COLOR = 6,
600
601 /** Whether the cell is contained within the current selection (bool).
602 * This returns true when the cell's column is within the current row's
603 * row-local selection range, and false otherwise. Rendering policy for
604 * selected cells (colors, inversion, etc.) is left to the caller.
605 *
606 * Renderers that can draw cells in spans may be more efficient querying
607 * GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION once per row and applying that
608 * range directly, avoiding one C API call per cell for selection state. */
609 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_SELECTED = 7,
610
611 /** Whether the cell has any explicit styling (bool).
612 * This is equivalent to querying the raw cell's
613 * GHOSTTY_CELL_DATA_HAS_STYLING value, but avoids materializing the raw
614 * GhosttyCell for renderers that only need to know whether fetching the
615 * full style is necessary. */
616 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_HAS_STYLING = 8,
617
618 /**
619 * Encode the current cell's full grapheme cluster as UTF-8 into a
620 * caller-provided buffer (GhosttyBuffer).
621 *
622 * The base codepoint is encoded first, followed by any extra grapheme
623 * codepoints. Returns GHOSTTY_SUCCESS with len=0 when the cell has no text.
624 *
625 * If ptr is NULL or cap is too small for a non-empty cell, returns
626 * GHOSTTY_OUT_OF_SPACE without writing any bytes and sets len to the required
627 * buffer size in bytes.
628 */
629 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_UTF8 = 9,
630 GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
631} GhosttyRenderStateRowCellsData;
632
633/**
634 * Move a render-state row cells iterator to the next cell.
635 *
636 * Returns true if the iterator moved successfully and cell data is
637 * available to read at the new position.
638 *
639 * @param cells The row cells handle to advance (may be NULL)
640 * @return true if advanced to the next cell, false if `cells` is
641 * NULL or if the iterator has reached the end
642 *
643 * @ingroup render
644 */
645GHOSTTY_API bool ghostty_render_state_row_cells_next(GhosttyRenderStateRowCells cells);
646
647/**
648 * Move a render-state row cells iterator to a specific column.
649 *
650 * Positions the iterator at the given x (column) index so that
651 * subsequent reads return data for that cell.
652 *
653 * @param cells The row cells handle to reposition (NULL returns
654 * GHOSTTY_INVALID_VALUE)
655 * @param x The zero-based column index to select
656 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `cells`
657 * is NULL or `x` is out of range
658 *
659 * @ingroup render
660 */
661GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_select(
662 GhosttyRenderStateRowCells cells, uint16_t x);
663
664/**
665 * Get a value from the current cell in a render-state row cells iterator.
666 *
667 * The `out` pointer must point to a value of the type corresponding to the
668 * requested data kind (see GhosttyRenderStateRowCellsData).
669 * Call ghostty_render_state_row_cells_next() or
670 * ghostty_render_state_row_cells_select() at least once before
671 * calling this function.
672 *
673 * @param cells The row cells handle to query (NULL returns GHOSTTY_INVALID_VALUE)
674 * @param data The data kind to query
675 * @param[out] out Pointer to receive the queried value
676 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
677 * `cells` is NULL or the iterator is not positioned on a cell
678 *
679 * @ingroup render
680 */
681GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get(
682 GhosttyRenderStateRowCells cells,
683 GhosttyRenderStateRowCellsData data,
684 void* out);
685
686/**
687 * Get multiple data fields from the current cell in a single call.
688 *
689 * Each element in the keys array specifies a data kind, and the
690 * corresponding element in the values array receives the result.
691 *
692 * Processing stops at the first error; on success out_written
693 * is set to count, on error it is set to the index of the
694 * failing key (i.e. the number of values successfully written).
695 *
696 * @param cells The row cells handle (NULL returns GHOSTTY_INVALID_VALUE)
697 * @param count Number of key/value pairs
698 * @param keys Array of data kinds to query
699 * @param values Array of output pointers (types must match each key's
700 * documented output type)
701 * @param[out] out_written On return, receives the number of values
702 * successfully written (may be NULL)
703 * @return GHOSTTY_SUCCESS if all queries succeed
704 *
705 * @ingroup render
706 */
707GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get_multi(
708 GhosttyRenderStateRowCells cells,
709 size_t count,
710 const GhosttyRenderStateRowCellsData* keys,
711 void** values,
712 size_t* out_written);
713
714/**
715 * Free a row cells instance.
716 *
717 * @param cells The row cells handle to free (may be NULL)
718 *
719 * @ingroup render
720 */
721GHOSTTY_API void ghostty_render_state_row_cells_free(GhosttyRenderStateRowCells cells);
722
723/** @} */
724
725#ifdef __cplusplus
726}
727#endif
728
729#endif /* GHOSTTY_VT_RENDER_H */