1/**
2 * @file grid_ref.h
3 *
4 * Terminal grid reference type for referencing a resolved position in the
5 * terminal grid.
6 */
7
8#ifndef GHOSTTY_VT_GRID_REF_H
9#define GHOSTTY_VT_GRID_REF_H
10
11#include <stddef.h>
12#include <stdint.h>
13#include <ghostty/vt/types.h>
14#include <ghostty/vt/screen.h>
15#include <ghostty/vt/style.h>
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21/** @defgroup grid_ref Grid Reference
22 *
23 * A grid reference is a reference to a specific cell position in the
24 * terminal. Obtain a grid reference from `ghostty_terminal_grid_ref`
25 * for untracked or `ghostty_terminal_grid_ref_track` for tracked. Untracked
26 * vs tracked is explained next.
27 *
28 * Important: The grid reference APIs are not meant to be used as the core of a render
29 * loop. They are not built to sustain the framerates needed for rendering large
30 * screens. Use the render state API for that.
31 *
32 * ## Untracked vs Tracked References
33 *
34 * ### Untracked Reference
35 *
36 * An untracked grid reference is a value type that snapshots a specific
37 * cell. It is only valid until the next update to the terminal instance.
38 * There is no guarantee that it will remain valid after any operation,
39 * even if a seemingly unrelated part of the grid is changed. These are meant
40 * to be read and have their values cached immediately after obtaining it.
41 *
42 * An untracked grid reference has a performance cost in its initial lookup,
43 * but doesn't affect the ongoing performance of the terminal in any way,
44 * since it is a one-time snapshot.
45 *
46 * ### Tracked Reference
47 *
48 * A tracked grid reference follows its cell across normal screen operations.
49 * For example scrolling, scrollback pruning, resize/reflow, and other
50 * terminal mutations update the tracked reference automatically.
51 *
52 * A tracked reference can still lose its original semantic location. This can
53 * happen when the underlying grid is reset, pruned, or otherwise discarded in a
54 * way that cannot be mapped to a meaningful new cell. In that state,
55 * ghostty_tracked_grid_ref_has_value() returns false and
56 * ghostty_tracked_grid_ref_snapshot() / ghostty_tracked_grid_ref_point() return
57 * GHOSTTY_NO_VALUE. The handle remains valid, and callers may move it to a new
58 * point with ghostty_tracked_grid_ref_set().
59 *
60 * To read cell data from a tracked reference, first snapshot it with
61 * ghostty_tracked_grid_ref_snapshot(). The returned `GhosttyGridRef` is again
62 * an untracked reference and follows the same short lifetime rules as any other
63 * untracked grid reference.
64 *
65 * A tracked reference belongs to the terminal screen/page-list that was active
66 * when it was created or last set. Converting it to a point uses that owning
67 * screen/page-list, even if the terminal has since switched between primary and
68 * alternate screens. Calling ghostty_tracked_grid_ref_set() resolves the new
69 * point against the terminal's currently active screen/page-list and may move
70 * the tracked reference between screens.
71 *
72 * Tracked references are owned by the caller and must be freed with
73 * ghostty_tracked_grid_ref_free(). If the terminal that created a tracked
74 * reference is freed first, the handle remains valid only for tracked-grid-ref
75 * APIs: it reports no value and can still be freed.
76 *
77 * Each tracked reference adds bookkeeping to terminal mutations. Use them
78 * sparingly for long-lived anchors such as selections, search state, marks,
79 * or application-side bookmarks.
80 *
81 * ## Lifetime
82 *
83 * An untracked reference is a snapshot. It doesn't need to be freed.
84 * The safety of accessing the value is documented explicitly above: it
85 * is only safe to access any data until the next terminal mutating
86 * operation (including free).
87 *
88 * A tracked reference is allocated and must be freed when it is no
89 * longer needed. A tracked reference may outlive the terminal that created it;
90 * after terminal free, it reports no value and can still be freed.
91 *
92 * ## Examples
93 *
94 * @snippet c-vt-grid-traverse/src/main.c grid-ref-traverse
95 * @snippet c-vt-grid-ref-tracked/src/main.c grid-ref-tracked
96 *
97 * @{
98 */
99
100/**
101 * A resolved reference to a terminal cell position.
102 *
103 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
104 *
105 * @ingroup grid_ref
106 */
107typedef struct {
108 size_t size;
109 void *node;
110 uint16_t x;
111 uint16_t y;
112} GhosttyGridRef;
113
114/**
115 * Get the cell from a grid reference.
116 *
117 * @param ref Pointer to the grid reference
118 * @param[out] out_cell On success, set to the cell at the ref's position (may be NULL)
119 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
120 * node is NULL
121 *
122 * @ingroup grid_ref
123 */
124GHOSTTY_API GhosttyResult ghostty_grid_ref_cell(const GhosttyGridRef *ref,
125 GhosttyCell *out_cell);
126
127/**
128 * Get the row from a grid reference.
129 *
130 * @param ref Pointer to the grid reference
131 * @param[out] out_row On success, set to the row at the ref's position (may be NULL)
132 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
133 * node is NULL
134 *
135 * @ingroup grid_ref
136 */
137GHOSTTY_API GhosttyResult ghostty_grid_ref_row(const GhosttyGridRef *ref,
138 GhosttyRow *out_row);
139
140/**
141 * Get the grapheme cluster codepoints for the cell at the grid reference's
142 * position.
143 *
144 * Writes the full grapheme cluster (the cell's primary codepoint followed by
145 * any combining codepoints) into the provided buffer. If the cell has no text,
146 * out_len is set to 0 and GHOSTTY_SUCCESS is returned.
147 *
148 * If the buffer is too small (or NULL), the function returns
149 * GHOSTTY_OUT_OF_SPACE and writes the required number of codepoints to
150 * out_len. The caller can then retry with a sufficiently sized buffer.
151 *
152 * @param ref Pointer to the grid reference
153 * @param buf Output buffer of uint32_t codepoints (may be NULL)
154 * @param buf_len Number of uint32_t elements in the buffer
155 * @param[out] out_len On success, the number of codepoints written. On
156 * GHOSTTY_OUT_OF_SPACE, the required buffer size in codepoints.
157 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
158 * node is NULL, GHOSTTY_OUT_OF_SPACE if the buffer is too small
159 *
160 * @ingroup grid_ref
161 */
162GHOSTTY_API GhosttyResult ghostty_grid_ref_graphemes(const GhosttyGridRef *ref,
163 uint32_t *buf,
164 size_t buf_len,
165 size_t *out_len);
166
167/**
168 * Get the hyperlink URI for the cell at the grid reference's position.
169 *
170 * Writes the URI bytes into the provided buffer. If the cell has no
171 * hyperlink, out_len is set to 0 and GHOSTTY_SUCCESS is returned.
172 *
173 * If the buffer is too small (or NULL), the function returns
174 * GHOSTTY_OUT_OF_SPACE and writes the required number of bytes to
175 * out_len. The caller can then retry with a sufficiently sized buffer.
176 *
177 * @param ref Pointer to the grid reference
178 * @param buf Output buffer for the URI bytes (may be NULL)
179 * @param buf_len Size of the output buffer in bytes
180 * @param[out] out_len On success, the number of bytes written. On
181 * GHOSTTY_OUT_OF_SPACE, the required buffer size in bytes.
182 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
183 * node is NULL, GHOSTTY_OUT_OF_SPACE if the buffer is too small
184 *
185 * @ingroup grid_ref
186 */
187GHOSTTY_API GhosttyResult ghostty_grid_ref_hyperlink_uri(
188 const GhosttyGridRef *ref,
189 uint8_t *buf,
190 size_t buf_len,
191 size_t *out_len);
192
193/**
194 * Get the style of the cell at the grid reference's position.
195 *
196 * @param ref Pointer to the grid reference
197 * @param[out] out_style On success, set to the cell's style (may be NULL)
198 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
199 * node is NULL
200 *
201 * @ingroup grid_ref
202 */
203GHOSTTY_API GhosttyResult ghostty_grid_ref_style(const GhosttyGridRef *ref,
204 GhosttyStyle *out_style);
205
206/** @} */
207
208#ifdef __cplusplus
209}
210#endif
211
212#endif /* GHOSTTY_VT_GRID_REF_H */