1/**
2 * @file selection.h
3 *
4 * Selection range type for specifying a region of terminal content.
5 */
6
7#ifndef GHOSTTY_VT_SELECTION_H
8#define GHOSTTY_VT_SELECTION_H
9
10#include <stdbool.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <ghostty/vt/allocator.h>
14#include <ghostty/vt/grid_ref.h>
15#include <ghostty/vt/point.h>
16#include <ghostty/vt/types.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22/** @defgroup selection Selection
23 *
24 * A snapshot selection range defined by two grid references that identifies
25 * a contiguous or rectangular region of terminal content.
26 *
27 * The start and end values are GhosttyGridRef values. They are therefore
28 * untracked grid references and inherit the same lifetime rules: they are
29 * only safe to use until the next mutating operation on the terminal that
30 * produced them, including freeing the terminal. To keep a selection valid
31 * across terminal mutations, callers must maintain tracked grid references
32 * for the endpoints and reconstruct a GhosttySelection from fresh snapshots
33 * when needed.
34 *
35 * Selection gestures provide a reusable state machine for turning UI pointer
36 * interactions into selection snapshots. A caller creates one
37 * GhosttySelectionGesture per active gesture stream, reuses typed
38 * GhosttySelectionGestureEvent objects for synthetic press, drag, release,
39 * autoscroll tick, and deep-press events, and applies each event with
40 * ghostty_selection_gesture_event(). The returned GhosttySelection is a
41 * snapshot; the embedder decides whether to render it, format/copy it, or
42 * install it as the terminal's active selection.
43 *
44 * ## Examples
45 *
46 * @snippet c-vt-selection/src/main.c selection-main
47 * @snippet c-vt-selection-gesture/src/main.c selection-gesture-main
48 *
49 * @{
50 */
51
52/**
53 * Opaque handle to state for interpreting terminal selection gestures.
54 *
55 * The gesture owns only the state required to interpret pointer events. Calls
56 * that use a gesture are not concurrency-safe and must be serialized with
57 * terminal mutations.
58 *
59 * @ingroup selection
60 */
61typedef struct GhosttySelectionGestureImpl* GhosttySelectionGesture;
62
63/**
64 * Opaque handle to reusable input data for selection gesture operations.
65 *
66 * Event options are set with ghostty_selection_gesture_event_set(). Individual
67 * gesture operations document which options are required or optional.
68 *
69 * @ingroup selection
70 */
71typedef struct GhosttySelectionGestureEventImpl* GhosttySelectionGestureEvent;
72
73/**
74 * A snapshot selection range defined by two grid references.
75 *
76 * Both endpoints are inclusive. The endpoints preserve selection direction
77 * and may be reversed; callers must not assume that start is the top-left
78 * endpoint or that end is the bottom-right endpoint.
79 *
80 * When rectangle is false, the endpoints describe a linear selection. When
81 * rectangle is true, the same endpoints are interpreted as opposite corners
82 * of a rectangular/block selection.
83 *
84 * The start and end values are untracked GhosttyGridRef snapshots and are
85 * only valid until the next mutating operation on the terminal that produced
86 * them unless the selection is reconstructed from tracked references.
87 *
88 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
89 *
90 * @ingroup selection
91 */
92typedef struct {
93 /** Size of this struct in bytes. Must be set to sizeof(GhosttySelection). */
94 size_t size;
95
96 /**
97 * Start of the selection range (inclusive).
98 *
99 * This may be after end in terminal order. It is an untracked
100 * GhosttyGridRef snapshot and follows untracked grid-ref lifetime rules.
101 */
102 GhosttyGridRef start;
103
104 /**
105 * End of the selection range (inclusive).
106 *
107 * This may be before start in terminal order. It is an untracked
108 * GhosttyGridRef snapshot and follows untracked grid-ref lifetime rules.
109 */
110 GhosttyGridRef end;
111
112 /**
113 * Whether the endpoints are interpreted as a rectangular/block selection
114 * rather than a linear selection.
115 */
116 bool rectangle;
117} GhosttySelection;
118
119/**
120 * Options for deriving a word selection from a terminal grid reference.
121 *
122 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
123 * If boundary_codepoints is NULL and boundary_codepoints_len is 0, Ghostty's
124 * default word-boundary codepoints are used. If boundary_codepoints_len is
125 * non-zero, boundary_codepoints must not be NULL.
126 *
127 * @ingroup selection
128 */
129typedef struct {
130 /** Size of this struct in bytes. Must be set to sizeof(GhosttyTerminalSelectWordOptions). */
131 size_t size;
132
133 /** Grid reference under which to derive the word selection. */
134 GhosttyGridRef ref;
135
136 /** Optional word-boundary codepoints as uint32_t scalar values. */
137 const uint32_t* boundary_codepoints;
138
139 /** Number of entries in boundary_codepoints. */
140 size_t boundary_codepoints_len;
141} GhosttyTerminalSelectWordOptions;
142
143/**
144 * Options for deriving the nearest word selection between two grid references.
145 *
146 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
147 * If boundary_codepoints is NULL and boundary_codepoints_len is 0, Ghostty's
148 * default word-boundary codepoints are used. If boundary_codepoints_len is
149 * non-zero, boundary_codepoints must not be NULL.
150 *
151 * @ingroup selection
152 */
153typedef struct {
154 /** Size of this struct in bytes. Must be set to sizeof(GhosttyTerminalSelectWordBetweenOptions). */
155 size_t size;
156
157 /** Starting grid reference for the inclusive search range. */
158 GhosttyGridRef start;
159
160 /** Ending grid reference for the inclusive search range. */
161 GhosttyGridRef end;
162
163 /** Optional word-boundary codepoints as uint32_t scalar values. */
164 const uint32_t* boundary_codepoints;
165
166 /** Number of entries in boundary_codepoints. */
167 size_t boundary_codepoints_len;
168} GhosttyTerminalSelectWordBetweenOptions;
169
170/**
171 * Options for deriving a line selection from a terminal grid reference.
172 *
173 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
174 * If whitespace is NULL and whitespace_len is 0, Ghostty's default line-trim
175 * whitespace codepoints are used. If whitespace_len is non-zero, whitespace
176 * must not be NULL.
177 *
178 * @ingroup selection
179 */
180typedef struct {
181 /** Size of this struct in bytes. Must be set to sizeof(GhosttyTerminalSelectLineOptions). */
182 size_t size;
183
184 /** Grid reference under which to derive the line selection. */
185 GhosttyGridRef ref;
186
187 /** Optional codepoints to trim from the start and end of the line. */
188 const uint32_t* whitespace;
189
190 /** Number of entries in whitespace. */
191 size_t whitespace_len;
192
193 /** Whether semantic prompt state changes should bound the line selection. */
194 bool semantic_prompt_boundary;
195} GhosttyTerminalSelectLineOptions;
196
197/**
198 * Options for one-shot formatting of a terminal selection.
199 *
200 * This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
201 *
202 * If selection is NULL, the terminal's current active selection is used.
203 * If selection is non-NULL, that caller-provided snapshot selection is used.
204 *
205 * The selection is formatted from the terminal's active screen using the same
206 * formatting semantics as GhosttyFormatter. For copy/clipboard behavior
207 * matching Ghostty's Screen.selectionString(), use plain output with unwrap
208 * and trim both set to true.
209 *
210 * @ingroup selection
211 */
212typedef struct {
213 /** Size of this struct in bytes. Must be set to sizeof(GhosttyTerminalSelectionFormatOptions). */
214 size_t size;
215
216 /** Output format to emit. */
217 GhosttyFormatterFormat emit;
218
219 /** Whether to unwrap soft-wrapped lines. */
220 bool unwrap;
221
222 /** Whether to trim trailing whitespace on non-blank lines. */
223 bool trim;
224
225 /**
226 * Optional selection to format.
227 *
228 * If NULL, the terminal's current active selection is used. If the terminal
229 * has no active selection, formatting returns GHOSTTY_NO_VALUE.
230 *
231 * If non-NULL, the pointed-to selection must be a valid snapshot selection
232 * for this terminal and must obey GhosttySelection lifetime rules.
233 */
234 const GhosttySelection *selection;
235} GhosttyTerminalSelectionFormatOptions;
236
237/**
238 * Ordering of a selection's endpoints in terminal coordinates.
239 *
240 * Mirrored orders are only produced by rectangular selections whose start
241 * and end endpoints are on opposite diagonal corners that are not simple
242 * top-left-to-bottom-right or bottom-right-to-top-left orderings.
243 *
244 * @ingroup selection
245 */
246typedef enum GHOSTTY_ENUM_TYPED {
247 /** Start is before end in top-left to bottom-right order. */
248 GHOSTTY_SELECTION_ORDER_FORWARD = 0,
249
250 /** End is before start in top-left to bottom-right order. */
251 GHOSTTY_SELECTION_ORDER_REVERSE = 1,
252
253 /** Rectangular selection from top-right to bottom-left. */
254 GHOSTTY_SELECTION_ORDER_MIRRORED_FORWARD = 2,
255
256 /** Rectangular selection from bottom-left to top-right. */
257 GHOSTTY_SELECTION_ORDER_MIRRORED_REVERSE = 3,
258
259 GHOSTTY_SELECTION_ORDER_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
260} GhosttySelectionOrder;
261
262/**
263 * Operation used to adjust a selection endpoint.
264 *
265 * Adjustment mutates the selection's logical end endpoint, not whichever
266 * endpoint is visually bottom/right. This preserves keyboard and drag
267 * behavior for both forward and reversed selections.
268 *
269 * @ingroup selection
270 */
271typedef enum GHOSTTY_ENUM_TYPED {
272 /** Move left to the previous non-empty cell, wrapping upward. */
273 GHOSTTY_SELECTION_ADJUST_LEFT = 0,
274
275 /** Move right to the next non-empty cell, wrapping downward. */
276 GHOSTTY_SELECTION_ADJUST_RIGHT = 1,
277
278 /**
279 * Move up one row at the current column, or to the beginning of the
280 * line if already at the top.
281 */
282 GHOSTTY_SELECTION_ADJUST_UP = 2,
283
284 /**
285 * Move down to the next non-blank row at the current column, or to the
286 * end of the line if none exists.
287 */
288 GHOSTTY_SELECTION_ADJUST_DOWN = 3,
289
290 /** Move to the top-left cell of the screen. */
291 GHOSTTY_SELECTION_ADJUST_HOME = 4,
292
293 /** Move to the right edge of the last non-blank row on the screen. */
294 GHOSTTY_SELECTION_ADJUST_END = 5,
295
296 /**
297 * Move up by one terminal page height, or to home if that would move
298 * past the top.
299 */
300 GHOSTTY_SELECTION_ADJUST_PAGE_UP = 6,
301
302 /**
303 * Move down by one terminal page height, or to end if that would move
304 * past the bottom.
305 */
306 GHOSTTY_SELECTION_ADJUST_PAGE_DOWN = 7,
307
308 /** Move to the left edge of the current line. */
309 GHOSTTY_SELECTION_ADJUST_BEGINNING_OF_LINE = 8,
310
311 /** Move to the right edge of the current line. */
312 GHOSTTY_SELECTION_ADJUST_END_OF_LINE = 9,
313
314 GHOSTTY_SELECTION_ADJUST_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
315} GhosttySelectionAdjust;
316
317/**
318 * Selection behavior chosen for a gesture's click sequence.
319 *
320 * @ingroup selection
321 */
322typedef enum GHOSTTY_ENUM_TYPED {
323 /** Cell-granular drag selection. */
324 GHOSTTY_SELECTION_GESTURE_BEHAVIOR_CELL = 0,
325
326 /** Word selection on press and word-granular drag selection. */
327 GHOSTTY_SELECTION_GESTURE_BEHAVIOR_WORD = 1,
328
329 /** Line selection on press and line-granular drag selection. */
330 GHOSTTY_SELECTION_GESTURE_BEHAVIOR_LINE = 2,
331
332 /** Semantic command output selection on press and drag. */
333 GHOSTTY_SELECTION_GESTURE_BEHAVIOR_OUTPUT = 3,
334
335 GHOSTTY_SELECTION_GESTURE_BEHAVIOR_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
336} GhosttySelectionGestureBehavior;
337
338/**
339 * Selection behaviors for single-, double-, and triple-click gestures.
340 *
341 * @ingroup selection
342 */
343typedef struct {
344 /** Behavior for single-click selection gestures. */
345 GhosttySelectionGestureBehavior single_click;
346
347 /** Behavior for double-click selection gestures. */
348 GhosttySelectionGestureBehavior double_click;
349
350 /** Behavior for triple-click selection gestures. */
351 GhosttySelectionGestureBehavior triple_click;
352} GhosttySelectionGestureBehaviors;
353
354/**
355 * Display geometry used to interpret selection gesture drag events.
356 *
357 * @ingroup selection
358 */
359typedef struct {
360 /** Number of columns in the rendered terminal grid. Must be non-zero. */
361 uint32_t columns;
362
363 /** Width of one terminal cell in surface pixels. Must be non-zero. */
364 uint32_t cell_width;
365
366 /** Left padding before the terminal grid begins in surface pixels. */
367 uint32_t padding_left;
368
369 /** Height of the rendered terminal surface in surface pixels. Must be non-zero. */
370 uint32_t screen_height;
371} GhosttySelectionGestureGeometry;
372
373/**
374 * Current autoscroll direction for an active selection drag gesture.
375 *
376 * @ingroup selection
377 */
378typedef enum GHOSTTY_ENUM_TYPED {
379 /** No selection autoscroll is requested. */
380 GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_NONE = 0,
381
382 /** Selection dragging should autoscroll the viewport upward. */
383 GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_UP = 1,
384
385 /** Selection dragging should autoscroll the viewport downward. */
386 GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_DOWN = 2,
387
388 GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
389} GhosttySelectionGestureAutoscroll;
390
391/**
392 * Data fields readable from a selection gesture with
393 * ghostty_selection_gesture_get().
394 *
395 * @ingroup selection
396 */
397typedef enum GHOSTTY_ENUM_TYPED {
398 /** Current click count: uint8_t*. 0 means inactive. */
399 GHOSTTY_SELECTION_GESTURE_DATA_CLICK_COUNT = 0,
400
401 /** Whether the current/last left-click gesture has dragged: bool*. */
402 GHOSTTY_SELECTION_GESTURE_DATA_DRAGGED = 1,
403
404 /** Current autoscroll request: GhosttySelectionGestureAutoscroll*. */
405 GHOSTTY_SELECTION_GESTURE_DATA_AUTOSCROLL = 2,
406
407 /** Current gesture behavior: GhosttySelectionGestureBehavior*. */
408 GHOSTTY_SELECTION_GESTURE_DATA_BEHAVIOR = 3,
409
410 /**
411 * Current left-click anchor: GhosttyGridRef*.
412 *
413 * Returns GHOSTTY_NO_VALUE if there is no valid active anchor. On success,
414 * writes an untracked GhosttyGridRef snapshot with normal GhosttyGridRef
415 * lifetime rules.
416 */
417 GHOSTTY_SELECTION_GESTURE_DATA_ANCHOR = 4,
418
419 GHOSTTY_SELECTION_GESTURE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
420} GhosttySelectionGestureData;
421
422/**
423 * Selection gesture event type.
424 *
425 * The event type is fixed when the event is created. Each event type documents
426 * which options are valid and which options are required by gesture operations.
427 *
428 * @ingroup selection
429 */
430typedef enum GHOSTTY_ENUM_TYPED {
431 /** Press event for ghostty_selection_gesture_event(). */
432 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS = 0,
433
434 /** Release event for ghostty_selection_gesture_event(). */
435 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE = 1,
436
437 /** Drag event for ghostty_selection_gesture_event(). */
438 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG = 2,
439
440 /** Autoscroll tick event for ghostty_selection_gesture_event(). */
441 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_AUTOSCROLL_TICK = 3,
442
443 /** Deep press event for ghostty_selection_gesture_event(). */
444 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS = 4,
445
446 GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
447} GhosttySelectionGestureEventType;
448
449/**
450 * Options stored on a reusable selection gesture event.
451 *
452 * Passing NULL as the value to ghostty_selection_gesture_event_set() clears the
453 * corresponding option.
454 *
455 * @ingroup selection
456 */
457typedef enum GHOSTTY_ENUM_TYPED {
458 /**
459 * Grid reference under the pointer: GhosttyGridRef*.
460 *
461 * Required for PRESS and DRAG events. Optional for RELEASE events; when unset
462 * or cleared, release records that the pointer did not map to a valid cell.
463 */
464 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF = 0,
465
466 /**
467 * Surface-space pointer position: GhosttySurfacePosition*.
468 *
469 * Valid for PRESS, DRAG, and AUTOSCROLL_TICK.
470 */
471 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION = 1,
472
473 /** Maximum repeat-click distance in pixels: double*. */
474 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REPEAT_DISTANCE = 2,
475
476 /**
477 * Optional monotonic event time in nanoseconds: uint64_t*.
478 *
479 * If unset, press treats the event as untimed and only single-click behavior
480 * is available.
481 */
482 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_TIME_NS = 3,
483
484 /** Maximum interval between repeat clicks in nanoseconds: uint64_t*. */
485 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REPEAT_INTERVAL_NS = 4,
486
487 /**
488 * Word-boundary codepoints: GhosttyCodepoints*.
489 *
490 * The codepoints are copied into event-owned storage when set. If unset,
491 * operations that need word boundaries use Ghostty's defaults.
492 *
493 * Valid for PRESS, DRAG, AUTOSCROLL_TICK, and DEEP_PRESS.
494 */
495 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_WORD_BOUNDARY_CODEPOINTS = 5,
496
497 /**
498 * Selection behavior table: GhosttySelectionGestureBehaviors*.
499 *
500 * If unset, press uses the default behavior table: cell, word, line.
501 */
502 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_BEHAVIORS = 6,
503
504 /** Whether a drag or autoscroll tick should produce a rectangular selection: bool*. */
505 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_RECTANGLE = 7,
506
507 /** Drag display geometry: GhosttySelectionGestureGeometry*. Required for DRAG and AUTOSCROLL_TICK. */
508 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY = 8,
509
510 /** Viewport coordinate for an autoscroll tick: GhosttyPointCoordinate*. Required for AUTOSCROLL_TICK. */
511 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_VIEWPORT = 9,
512
513 GHOSTTY_SELECTION_GESTURE_EVENT_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
514} GhosttySelectionGestureEventOption;
515
516/**
517 * Create a reusable selection gesture event object.
518 *
519 * @param allocator Allocator, or NULL for the default allocator
520 * @param out_event Receives the created event handle
521 * @param type Event type. This is fixed for the lifetime of the event.
522 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if out_event is
523 * NULL or type is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation fails
524 *
525 * @ingroup selection
526 */
527GHOSTTY_API GhosttyResult ghostty_selection_gesture_event_new(
528 const GhosttyAllocator* allocator,
529 GhosttySelectionGestureEvent* out_event,
530 GhosttySelectionGestureEventType type);
531
532/**
533 * Free a selection gesture event object.
534 *
535 * Passing NULL is allowed and is a no-op.
536 *
537 * @param event Selection gesture event handle to free
538 *
539 * @ingroup selection
540 */
541GHOSTTY_API void ghostty_selection_gesture_event_free(
542 GhosttySelectionGestureEvent event);
543
544/**
545 * Set or clear an option on a selection gesture event.
546 *
547 * The value type depends on option and is documented by
548 * GhosttySelectionGestureEventOption. Passing NULL for value clears the option.
549 *
550 * @param event Selection gesture event handle (NULL returns GHOSTTY_INVALID_VALUE)
551 * @param option Event option to set or clear
552 * @param value Pointer to the input value for option, or NULL to clear
553 * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY if copying
554 * event-owned data fails, or GHOSTTY_INVALID_VALUE if event, option, or
555 * value is invalid
556 *
557 * @ingroup selection
558 */
559GHOSTTY_API GhosttyResult ghostty_selection_gesture_event_set(
560 GhosttySelectionGestureEvent event,
561 GhosttySelectionGestureEventOption option,
562 const void* value);
563
564/**
565 * Apply a selection gesture event and return the resulting selection snapshot.
566 *
567 * This dispatches to the gesture operation matching the event's fixed type.
568 * For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS, the event must have
569 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF set before calling this function.
570 * All other press options use their initialized defaults when unset or cleared.
571 *
572 * For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE, only
573 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF is valid. It is optional; if unset or
574 * cleared, release records that the pointer did not map to a valid cell. Release
575 * events update gesture state but do not produce a selection, so this function
576 * returns GHOSTTY_NO_VALUE after applying them.
577 *
578 * For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG,
579 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF and
580 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY are required. Position,
581 * rectangle, and word-boundary codepoints are optional and use initialized
582 * defaults when unset or cleared.
583 *
584 * For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_AUTOSCROLL_TICK,
585 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_VIEWPORT and
586 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY are required. Position,
587 * rectangle, and word-boundary codepoints are optional and use initialized
588 * defaults when unset or cleared.
589 *
590 * For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS, only
591 * GHOSTTY_SELECTION_GESTURE_EVENT_OPT_WORD_BOUNDARY_CODEPOINTS is valid. It is
592 * optional and uses initialized defaults when unset or cleared.
593 *
594 * The returned selection is not installed as the terminal's current selection.
595 * It is a snapshot with the same lifetime rules as GhosttySelection.
596 *
597 * @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
598 * @param terminal Terminal used to interpret and update gesture state
599 * @param event Selection gesture event handle (NULL returns GHOSTTY_INVALID_VALUE)
600 * @param[out] out_selection On success, receives the resulting selection. May
601 * be NULL to apply the event and discard the selection result.
602 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the event does not
603 * currently produce a selection, GHOSTTY_OUT_OF_MEMORY if tracking
604 * gesture state fails, or GHOSTTY_INVALID_VALUE if gesture, terminal,
605 * event, or required event data is invalid
606 *
607 * @ingroup selection
608 */
609GHOSTTY_API GhosttyResult ghostty_selection_gesture_event(
610 GhosttySelectionGesture gesture,
611 GhosttyTerminal terminal,
612 GhosttySelectionGestureEvent event,
613 GhosttySelection* out_selection);
614
615/**
616 * Create a selection gesture object.
617 *
618 * The gesture stores mutable state for terminal text selection gestures. The
619 * gesture is not bound to a terminal at creation time; terminal-dependent APIs
620 * take the terminal explicitly.
621 *
622 * @param allocator Allocator, or NULL for the default allocator
623 * @param out_gesture Receives the created gesture handle
624 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if out_gesture is
625 * NULL, or GHOSTTY_OUT_OF_MEMORY if allocation fails
626 *
627 * @ingroup selection
628 */
629GHOSTTY_API GhosttyResult ghostty_selection_gesture_new(
630 const GhosttyAllocator* allocator,
631 GhosttySelectionGesture* out_gesture);
632
633/**
634 * Free a selection gesture object.
635 *
636 * This releases any tracked terminal references owned by the gesture using the
637 * provided terminal, then frees the gesture object. Passing NULL for gesture is
638 * allowed and is a no-op.
639 *
640 * If the terminal is still alive, pass the terminal most recently used with the
641 * gesture so any tracked terminal references can be released correctly. If the
642 * terminal has already been freed, pass NULL for terminal; the terminal's page
643 * storage has already released the underlying tracked references, so the
644 * gesture wrapper can be safely discarded without touching the stale terminal
645 * state.
646 *
647 * @param gesture Selection gesture handle to free
648 * @param terminal Terminal used to release tracked gesture state, or NULL if
649 * the terminal has already been freed
650 *
651 * @ingroup selection
652 */
653GHOSTTY_API void ghostty_selection_gesture_free(
654 GhosttySelectionGesture gesture,
655 GhosttyTerminal terminal);
656
657/**
658 * Reset any active selection gesture state.
659 *
660 * This cancels the active click sequence and releases any tracked terminal
661 * references owned by the gesture without freeing the gesture object.
662 * Passing NULL is allowed and is a no-op.
663 *
664 * @param gesture Selection gesture handle to reset
665 * @param terminal Terminal used to release tracked gesture state
666 *
667 * @ingroup selection
668 */
669GHOSTTY_API void ghostty_selection_gesture_reset(
670 GhosttySelectionGesture gesture,
671 GhosttyTerminal terminal);
672
673/**
674 * Read data from a selection gesture.
675 *
676 * The type of value depends on data and is documented by
677 * GhosttySelectionGestureData. For GHOSTTY_SELECTION_GESTURE_DATA_ANCHOR,
678 * the returned GhosttyGridRef is an untracked snapshot with normal grid-ref
679 * lifetime rules.
680 *
681 * @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
682 * @param terminal Terminal used to validate terminal-backed gesture state
683 * @param data Data field to read
684 * @param value Output pointer whose type depends on data
685 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the requested data
686 * has no value, or GHOSTTY_INVALID_VALUE if gesture, terminal, data, or
687 * value is invalid
688 *
689 * @ingroup selection
690 */
691GHOSTTY_API GhosttyResult ghostty_selection_gesture_get(
692 GhosttySelectionGesture gesture,
693 GhosttyTerminal terminal,
694 GhosttySelectionGestureData data,
695 void* value);
696
697/**
698 * Read multiple data fields from a selection gesture in a single call.
699 *
700 * This is an optimization over calling ghostty_selection_gesture_get() multiple
701 * times. Each entry in values must point to storage of the type documented by
702 * the corresponding GhosttySelectionGestureData key.
703 *
704 * If any individual read fails, the function returns that error and writes the
705 * index of the failing key to out_written when out_written is non-NULL. On
706 * success, out_written receives count when non-NULL.
707 *
708 * @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
709 * @param terminal Terminal used to validate terminal-backed gesture state
710 * @param count Number of data fields to read
711 * @param keys Data fields to read (must not be NULL)
712 * @param values Output pointers corresponding to keys (must not be NULL)
713 * @param out_written Optional number of fields read, or failing index on error
714 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if a requested data
715 * field has no value, or GHOSTTY_INVALID_VALUE if gesture, terminal,
716 * keys, values, or a value pointer is invalid
717 *
718 * @ingroup selection
719 */
720GHOSTTY_API GhosttyResult ghostty_selection_gesture_get_multi(
721 GhosttySelectionGesture gesture,
722 GhosttyTerminal terminal,
723 size_t count,
724 const GhosttySelectionGestureData* keys,
725 void** values,
726 size_t* out_written);
727
728/**
729 * Derive a word selection snapshot from a terminal grid reference.
730 *
731 * The returned selection is not installed as the terminal's current
732 * selection. It is a snapshot with the same lifetime rules as GhosttySelection.
733 *
734 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
735 * @param options Word-selection options
736 * @param[out] out_selection On success, receives the derived selection
737 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the valid ref has
738 * no selectable word content, or GHOSTTY_INVALID_VALUE if the
739 * terminal, options, ref, codepoint pointer, or output pointer are
740 * invalid.
741 *
742 * @ingroup selection
743 */
744GHOSTTY_API GhosttyResult ghostty_terminal_select_word(
745 GhosttyTerminal terminal,
746 const GhosttyTerminalSelectWordOptions* options,
747 GhosttySelection* out_selection);
748
749/**
750 * Derive the nearest word selection snapshot between two terminal grid refs.
751 *
752 * Starting at options->start, this searches toward options->end (inclusive)
753 * and returns the first selectable word found using Ghostty's word-selection
754 * rules.
755 *
756 * This is useful for implementing double-click-and-drag selection in a UI. If
757 * a user double-clicks one word and drags across spaces or punctuation toward
758 * another word, selecting only the word directly under the current pointer can
759 * flicker or collapse when the pointer is between words. Instead, ask for the
760 * nearest word between the original click and the drag point, ask again in the
761 * reverse direction, and combine the two word bounds into the drag selection.
762 *
763 * @snippet c-vt-selection/src/main.c selection-word-between
764 *
765 * The returned selection is not installed as the terminal's current
766 * selection. It is a snapshot with the same lifetime rules as GhosttySelection.
767 *
768 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
769 * @param options Word-between-selection options
770 * @param[out] out_selection On success, receives the derived selection
771 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if there is no
772 * selectable word content between the valid refs, or
773 * GHOSTTY_INVALID_VALUE if the terminal, options, refs, codepoint
774 * pointer, or output pointer are invalid.
775 *
776 * @ingroup selection
777 */
778GHOSTTY_API GhosttyResult ghostty_terminal_select_word_between(
779 GhosttyTerminal terminal,
780 const GhosttyTerminalSelectWordBetweenOptions* options,
781 GhosttySelection* out_selection);
782
783/**
784 * Derive a line selection snapshot from a terminal grid reference.
785 *
786 * The returned selection is not installed as the terminal's current
787 * selection. It is a snapshot with the same lifetime rules as GhosttySelection.
788 *
789 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
790 * @param options Line-selection options
791 * @param[out] out_selection On success, receives the derived selection
792 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the valid ref has
793 * no selectable line content, or GHOSTTY_INVALID_VALUE if the
794 * terminal, options, ref, codepoint pointer, or output pointer are
795 * invalid.
796 *
797 * @ingroup selection
798 */
799GHOSTTY_API GhosttyResult ghostty_terminal_select_line(
800 GhosttyTerminal terminal,
801 const GhosttyTerminalSelectLineOptions* options,
802 GhosttySelection* out_selection);
803
804/**
805 * Derive a selection snapshot covering all selectable terminal content.
806 *
807 * The returned selection is not installed as the terminal's current
808 * selection. It is a snapshot with the same lifetime rules as GhosttySelection.
809 *
810 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
811 * @param[out] out_selection On success, receives the derived selection
812 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if there is no
813 * selectable content, or GHOSTTY_INVALID_VALUE if the terminal or
814 * output pointer is invalid.
815 *
816 * @ingroup selection
817 */
818GHOSTTY_API GhosttyResult ghostty_terminal_select_all(
819 GhosttyTerminal terminal,
820 GhosttySelection* out_selection);
821
822/**
823 * Derive a command-output selection snapshot from a terminal grid reference.
824 *
825 * The returned selection is not installed as the terminal's current
826 * selection. It is a snapshot with the same lifetime rules as GhosttySelection.
827 *
828 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
829 * @param ref Grid reference within command output to select
830 * @param[out] out_selection On success, receives the derived selection
831 * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the valid ref is
832 * not selectable command output, or GHOSTTY_INVALID_VALUE if the
833 * terminal, ref, or output pointer is invalid.
834 *
835 * @ingroup selection
836 */
837GHOSTTY_API GhosttyResult ghostty_terminal_select_output(
838 GhosttyTerminal terminal,
839 GhosttyGridRef ref,
840 GhosttySelection* out_selection);
841
842/**
843 * Format a terminal selection into a caller-provided buffer.
844 *
845 * This is a one-shot convenience API for formatting either the terminal's
846 * active selection or a caller-provided GhosttySelection without explicitly
847 * creating a GhosttyFormatter.
848 *
849 * Pass NULL for buf to query the required output size. In that case,
850 * out_written receives the required size and the function returns
851 * GHOSTTY_OUT_OF_SPACE.
852 *
853 * If buf is too small, the function returns GHOSTTY_OUT_OF_SPACE and writes
854 * the required size to out_written. The caller can then retry with a larger
855 * buffer.
856 *
857 * If options.selection is NULL and the terminal has no active selection, the
858 * function returns GHOSTTY_NO_VALUE.
859 *
860 * @param terminal The terminal to read from (must not be NULL)
861 * @param options Selection formatting options
862 * @param buf Output buffer, or NULL to query required size
863 * @param buf_len Length of buf in bytes
864 * @param out_written Number of bytes written, or required size on
865 * GHOSTTY_OUT_OF_SPACE (must not be NULL)
866 * @return GHOSTTY_SUCCESS on success, or an error code on failure
867 *
868 * @ingroup selection
869 */
870GHOSTTY_API GhosttyResult ghostty_terminal_selection_format_buf(
871 GhosttyTerminal terminal,
872 GhosttyTerminalSelectionFormatOptions options,
873 uint8_t* buf,
874 size_t buf_len,
875 size_t* out_written);
876
877/**
878 * Format a terminal selection into an allocated buffer.
879 *
880 * This is a one-shot convenience API for formatting either the terminal's
881 * active selection or a caller-provided GhosttySelection without explicitly
882 * creating a GhosttyFormatter.
883 *
884 * The returned buffer is allocated using allocator, or the default allocator
885 * if NULL is passed. The caller owns the returned buffer and must free it with
886 * ghostty_free(), passing the same allocator and returned length.
887 *
888 * The returned bytes are not NUL-terminated. This supports plain text, VT, and
889 * HTML uniformly as byte output.
890 *
891 * If options.selection is NULL and the terminal has no active selection, the
892 * function returns GHOSTTY_NO_VALUE and leaves out_ptr as NULL and out_len as 0.
893 *
894 * @param terminal The terminal to read from (must not be NULL)
895 * @param allocator Allocator used for the returned buffer, or NULL for the default allocator
896 * @param options Selection formatting options
897 * @param out_ptr Receives the allocated output buffer (must not be NULL)
898 * @param out_len Receives the output length in bytes (must not be NULL)
899 * @return GHOSTTY_SUCCESS on success, or an error code on failure
900 *
901 * @ingroup selection
902 */
903GHOSTTY_API GhosttyResult ghostty_terminal_selection_format_alloc(
904 GhosttyTerminal terminal,
905 const GhosttyAllocator* allocator,
906 GhosttyTerminalSelectionFormatOptions options,
907 uint8_t** out_ptr,
908 size_t* out_len);
909
910/**
911 * Adjust a selection snapshot using terminal selection semantics.
912 *
913 * This mutates the caller-provided GhosttySelection in place. The logical end
914 * endpoint is always moved, regardless of whether the selection is forward or
915 * reversed visually. The input selection remains a snapshot: after adjustment,
916 * call ghostty_terminal_set() with GHOSTTY_TERMINAL_OPT_SELECTION to install it
917 * as the terminal-owned selection if desired.
918 *
919 * The selection's start and end grid refs must both be valid untracked
920 * snapshots for the given terminal's currently active screen. In practice,
921 * they must come from that terminal and screen, and no mutating terminal call
922 * may have occurred since the refs were produced or reconstructed from
923 * tracked refs. Passing refs from another terminal, another screen, or stale
924 * refs violates this precondition.
925 *
926 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
927 * @param selection Selection snapshot to adjust in place
928 * @param adjustment The adjustment operation to apply
929 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal,
930 * selection, or adjustment are invalid. Selection reference validity
931 * is a precondition and is not checked.
932 *
933 * @ingroup selection
934 */
935GHOSTTY_API GhosttyResult ghostty_terminal_selection_adjust(
936 GhosttyTerminal terminal,
937 GhosttySelection* selection,
938 GhosttySelectionAdjust adjustment);
939
940/**
941 * Get the current endpoint ordering of a selection snapshot.
942 *
943 * The selection's start and end grid refs must both be valid untracked
944 * snapshots for the given terminal's currently active screen. In practice,
945 * they must come from that terminal and screen, and no mutating terminal call
946 * may have occurred since the refs were produced or reconstructed from
947 * tracked refs. Passing refs from another terminal, another screen, or stale
948 * refs violates this precondition.
949 *
950 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
951 * @param selection Selection snapshot to inspect
952 * @param[out] out_order On success, receives the selection order
953 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal,
954 * selection, or output pointer are invalid. Selection reference
955 * validity is a precondition and is not checked.
956 *
957 * @ingroup selection
958 */
959GHOSTTY_API GhosttyResult ghostty_terminal_selection_order(
960 GhosttyTerminal terminal,
961 const GhosttySelection* selection,
962 GhosttySelectionOrder* out_order);
963
964/**
965 * Return a selection snapshot with endpoints ordered as requested.
966 *
967 * Use GHOSTTY_SELECTION_ORDER_FORWARD to get top-left to bottom-right bounds,
968 * and GHOSTTY_SELECTION_ORDER_REVERSE to get bottom-right to top-left bounds.
969 * Mirrored desired orders are accepted but normalized the same as forward.
970 * The output selection is a fresh untracked snapshot and is not installed as
971 * the terminal's current selection.
972 *
973 * The selection's start and end grid refs must both be valid untracked
974 * snapshots for the given terminal's currently active screen. In practice,
975 * they must come from that terminal and screen, and no mutating terminal call
976 * may have occurred since the refs were produced or reconstructed from
977 * tracked refs. Passing refs from another terminal, another screen, or stale
978 * refs violates this precondition.
979 *
980 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
981 * @param selection Selection snapshot to order
982 * @param desired Desired endpoint order
983 * @param[out] out_selection On success, receives the ordered selection
984 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal,
985 * selection, desired order, or output pointer are invalid. Selection
986 * reference validity is a precondition and is not checked.
987 *
988 * @ingroup selection
989 */
990GHOSTTY_API GhosttyResult ghostty_terminal_selection_ordered(
991 GhosttyTerminal terminal,
992 const GhosttySelection* selection,
993 GhosttySelectionOrder desired,
994 GhosttySelection* out_selection);
995
996/**
997 * Test whether a terminal point is inside a selection snapshot.
998 *
999 * This uses the same selection semantics as the terminal, including
1000 * rectangular/block selections and linear selections spanning multiple rows.
1001 *
1002 * The selection's start and end grid refs must both be valid untracked
1003 * snapshots for the given terminal's currently active screen. In practice,
1004 * they must come from that terminal and screen, and no mutating terminal call
1005 * may have occurred since the refs were produced or reconstructed from
1006 * tracked refs. Passing refs from another terminal, another screen, or stale
1007 * refs violates this precondition.
1008 *
1009 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
1010 * @param selection Selection snapshot to inspect
1011 * @param point Point to test for containment
1012 * @param[out] out_contains On success, receives whether point is inside selection
1013 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal,
1014 * selection, point, or output pointer are invalid. Selection reference
1015 * validity is a precondition and is not checked.
1016 *
1017 * @ingroup selection
1018 */
1019GHOSTTY_API GhosttyResult ghostty_terminal_selection_contains(
1020 GhosttyTerminal terminal,
1021 const GhosttySelection* selection,
1022 GhosttyPoint point,
1023 bool* out_contains);
1024
1025/**
1026 * Test whether two selection snapshots are equal.
1027 *
1028 * Equality uses the terminal's internal selection semantics: both endpoint
1029 * pins must match and both selections must have the same rectangular/block
1030 * state. This avoids requiring callers to compare raw GhosttyGridRef internals.
1031 *
1032 * Both selections' start and end grid refs must be valid untracked snapshots
1033 * for the given terminal's currently active screen. In practice, they must
1034 * come from that terminal and screen, and no mutating terminal call may have
1035 * occurred since the refs were produced or reconstructed from tracked refs.
1036 * Passing refs from another terminal, another screen, or stale refs violates
1037 * this precondition.
1038 *
1039 * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
1040 * @param a First selection snapshot to compare
1041 * @param b Second selection snapshot to compare
1042 * @param[out] out_equal On success, receives whether the selections are equal
1043 * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal,
1044 * selections, or output pointer are invalid. Selection reference
1045 * validity is a precondition and is not checked.
1046 *
1047 * @ingroup selection
1048 */
1049GHOSTTY_API GhosttyResult ghostty_terminal_selection_equal(
1050 GhosttyTerminal terminal,
1051 const GhosttySelection* a,
1052 const GhosttySelection* b,
1053 bool* out_equal);
1054
1055/** @} */
1056
1057#ifdef __cplusplus
1058}
1059#endif
1060
1061#endif /* GHOSTTY_VT_SELECTION_H */