mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-28 10:01:38 +00:00
libghostty: add tracked grid ref API
Add a C API for tracked pins, known as a tracked grid ref in C. The new API can create tracked refs from terminal points, snapshot them back to regular grid refs for cell access, convert them to coordinates, move them to a new point, report when their semantic location was lost, and free the tracked pin bookkeeping. This is backed by PageList tracked pins and exposed through the libghostty-vt export layer and headers.
This commit is contained in:
@@ -54,6 +54,7 @@
|
||||
* - @ref c-vt-sgr/src/main.c - SGR parser example
|
||||
* - @ref c-vt-formatter/src/main.c - Terminal formatter example
|
||||
* - @ref c-vt-grid-traverse/src/main.c - Grid traversal example using grid refs
|
||||
* - @ref c-vt-grid-ref-tracked/src/main.c - Tracked grid ref example
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -98,6 +99,11 @@
|
||||
* grid refs to inspect cell codepoints, row wrap state, and cell styles.
|
||||
*/
|
||||
|
||||
/** @example c-vt-grid-ref-tracked/src/main.c
|
||||
* This example demonstrates how to track a grid ref as the terminal scrolls,
|
||||
* detect when it loses its value, and move it to a new point.
|
||||
*/
|
||||
|
||||
/** @example c-vt-kitty-graphics/src/main.c
|
||||
* This example demonstrates how to use the system interface to install a
|
||||
* PNG decoder callback and send a Kitty Graphics Protocol image.
|
||||
@@ -120,6 +126,7 @@ extern "C" {
|
||||
#include <ghostty/vt/render.h>
|
||||
#include <ghostty/vt/terminal.h>
|
||||
#include <ghostty/vt/grid_ref.h>
|
||||
#include <ghostty/vt/grid_ref_tracked.h>
|
||||
#include <ghostty/vt/osc.h>
|
||||
#include <ghostty/vt/sgr.h>
|
||||
#include <ghostty/vt/style.h>
|
||||
|
||||
@@ -20,24 +20,78 @@ extern "C" {
|
||||
|
||||
/** @defgroup grid_ref Grid Reference
|
||||
*
|
||||
* A grid reference is a resolved reference to a specific cell position in the
|
||||
* terminal's internal page structure. Obtain a grid reference from
|
||||
* ghostty_terminal_grid_ref(), then extract the cell or row via
|
||||
* ghostty_grid_ref_cell() and ghostty_grid_ref_row().
|
||||
* A grid reference is a reference to a specific cell position in the
|
||||
* terminal. Obtain a grid reference from `ghostty_terminal_grid_ref`
|
||||
* for untracked or `ghostty_terminal_grid_ref_track` for tracked. Untracked
|
||||
* vs tracked is explained next.
|
||||
*
|
||||
* A grid reference is only valid until the next update to the terminal
|
||||
* instance. There is no guarantee that a grid reference will remain
|
||||
* valid after ANY operation, even if a seemingly unrelated part of
|
||||
* the grid is changed, so any information related to the grid reference
|
||||
* should be read and cached immediately after obtaining the grid reference.
|
||||
* Important: The grid reference APIs are not meant to be used as the core of a render
|
||||
* loop. They are not built to sustain the framerates needed for rendering large
|
||||
* screens. Use the render state API for that.
|
||||
*
|
||||
* This API is not meant to be used as the core of render loop. It isn't
|
||||
* built to sustain the framerates needed for rendering large screens.
|
||||
* Use the render state API for that.
|
||||
* ## Untracked vs Tracked References
|
||||
*
|
||||
* ### Untracked Reference
|
||||
*
|
||||
* ## Example
|
||||
* An untracked grid reference is a value type that snapshots a specific
|
||||
* cell. It is only valid until the next update to the terminal instance.
|
||||
* There is no guarantee that it will remain valid after any operation,
|
||||
* even if a seemingly unrelated part of the grid is changed. These are meant
|
||||
* to be read and have their values cached immediately after obtaining it.
|
||||
*
|
||||
* An untracked grid reference has a performance cost in its initial lookup,
|
||||
* but doesn't affect the ongoing performance of the terminal in any way,
|
||||
* since it is a one-time snapshot.
|
||||
*
|
||||
* ### Tracked Reference
|
||||
*
|
||||
* A tracked grid reference follows its cell across normal screen operations.
|
||||
* For example scrolling, scrollback pruning, resize/reflow, and other
|
||||
* terminal mutations update the tracked reference automatically.
|
||||
*
|
||||
* A tracked reference can still lose its original semantic location. This can
|
||||
* happen when the underlying grid is reset, pruned, or otherwise discarded in a
|
||||
* way that cannot be mapped to a meaningful new cell. In that state,
|
||||
* ghostty_tracked_grid_ref_has_value() returns false and
|
||||
* ghostty_tracked_grid_ref_snapshot() / ghostty_tracked_grid_ref_point() return
|
||||
* GHOSTTY_NO_VALUE. The handle remains valid, and callers may move it to a new
|
||||
* point with ghostty_tracked_grid_ref_set().
|
||||
*
|
||||
* To read cell data from a tracked reference, first snapshot it with
|
||||
* ghostty_tracked_grid_ref_snapshot(). The returned `GhosttyGridRef` is again
|
||||
* an untracked reference and follows the same short lifetime rules as any other
|
||||
* untracked grid reference.
|
||||
*
|
||||
* A tracked reference belongs to the terminal screen/page-list that was active
|
||||
* when it was created or last set. Converting it to a point uses that owning
|
||||
* screen/page-list, even if the terminal has since switched between primary and
|
||||
* alternate screens. Calling ghostty_tracked_grid_ref_set() resolves the new
|
||||
* point against the terminal's currently active screen/page-list and may move
|
||||
* the tracked reference between screens.
|
||||
*
|
||||
* Tracked references are owned by the caller and must be freed with
|
||||
* ghostty_tracked_grid_ref_free() before the terminal that created them is
|
||||
* freed.
|
||||
*
|
||||
* Each tracked reference adds bookkeeping to terminal mutations. Use them
|
||||
* sparingly for long-lived anchors such as selections, search state, marks,
|
||||
* or application-side bookmarks.
|
||||
*
|
||||
* ## Lifetime
|
||||
*
|
||||
* An untracked reference is a snapshot. It doesn't need to be freed.
|
||||
* The safety of accessing the value is documented explicitly above: it
|
||||
* is only safe to access any data until the next terminal mutating
|
||||
* operation (including free).
|
||||
*
|
||||
* A tracked reference is allocated and must be freed when it is no
|
||||
* longer needed. All tracked references must be freed prior to the
|
||||
* terminal being freed.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* @snippet c-vt-grid-traverse/src/main.c grid-ref-traverse
|
||||
* @snippet c-vt-grid-ref-tracked/src/main.c grid-ref-tracked
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
134
include/ghostty/vt/grid_ref_tracked.h
Normal file
134
include/ghostty/vt/grid_ref_tracked.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @file grid_ref_tracked.h
|
||||
*
|
||||
* Tracked terminal grid references.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_GRID_REF_TRACKED_H
|
||||
#define GHOSTTY_VT_GRID_REF_TRACKED_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
#include <ghostty/vt/grid_ref.h>
|
||||
#include <ghostty/vt/point.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Tracked grid references are owned grid references that move with the
|
||||
* terminal. See @ref grid_ref for the full overview of tracked and untracked
|
||||
* grid reference behavior.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
|
||||
/**
|
||||
* Free a tracked grid reference.
|
||||
*
|
||||
* Passing NULL is allowed and has no effect. The reference must be freed before
|
||||
* the terminal that created it is freed.
|
||||
*
|
||||
* @param ref Tracked grid reference to free.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API void ghostty_tracked_grid_ref_free(GhosttyTrackedGridRef ref);
|
||||
|
||||
/**
|
||||
* Return whether a tracked grid reference currently has a meaningful value.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @return true if the reference currently has a meaningful value.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API bool ghostty_tracked_grid_ref_has_value(
|
||||
GhosttyTrackedGridRef ref);
|
||||
|
||||
/**
|
||||
* Convert a tracked grid reference to a point in the requested coordinate
|
||||
* space.
|
||||
*
|
||||
* This is the tracked equivalent of ghostty_terminal_point_from_grid_ref().
|
||||
* Unlike snapshotting, this does not expose an intermediate untracked
|
||||
* GhosttyGridRef.
|
||||
*
|
||||
* A tracked reference is resolved against the terminal screen/page-list that
|
||||
* currently owns the reference. If the terminal has switched between primary
|
||||
* and alternate screens since the reference was created or last set, this may
|
||||
* be different from the terminal's currently active screen.
|
||||
*
|
||||
* If the tracked reference no longer has a meaningful value, this returns
|
||||
* GHOSTTY_NO_VALUE. GHOSTTY_NO_VALUE is also returned when the reference cannot
|
||||
* be represented in the requested coordinate space.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param tag Coordinate space to convert into.
|
||||
* @param[out] out_point On success, receives the coordinate. May be NULL.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref is invalid,
|
||||
* or GHOSTTY_NO_VALUE if there is no representable value.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_point(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyPointTag tag,
|
||||
GhosttyPointCoordinate *out_point);
|
||||
|
||||
/**
|
||||
* Move an existing tracked grid reference to a new terminal point.
|
||||
*
|
||||
* On success, the tracked reference begins tracking the new point and any prior
|
||||
* "no value" state is cleared. On GHOSTTY_OUT_OF_MEMORY, the original tracked
|
||||
* reference is left unchanged.
|
||||
*
|
||||
* The terminal must be the same terminal that created the tracked reference.
|
||||
* The point is resolved against the terminal screen/page-list that is active at
|
||||
* the time this function is called. If the terminal has switched between
|
||||
* primary and alternate screens, this may move the tracked reference from one
|
||||
* screen/page-list to the other.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param terminal Terminal instance that owns the reference.
|
||||
* @param point New point to track.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref, terminal,
|
||||
* or point is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation fails.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_set(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyTerminal terminal,
|
||||
GhosttyPoint point);
|
||||
|
||||
/**
|
||||
* Snapshot a tracked grid reference into a regular GhosttyGridRef.
|
||||
*
|
||||
* The returned GhosttyGridRef is an untracked snapshot and has the same
|
||||
* lifetime rules as ghostty_terminal_grid_ref(): it is only valid until the
|
||||
* next terminal update. Snapshot immediately before calling
|
||||
* ghostty_grid_ref_cell(), ghostty_grid_ref_row(),
|
||||
* ghostty_grid_ref_graphemes(), ghostty_grid_ref_hyperlink_uri(), or
|
||||
* ghostty_grid_ref_style().
|
||||
*
|
||||
* If the tracked reference no longer has a meaningful value, this returns
|
||||
* GHOSTTY_NO_VALUE.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param[out] out_ref On success, receives an untracked snapshot. May be NULL.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref is invalid,
|
||||
* or GHOSTTY_NO_VALUE if the tracked location was discarded.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_snapshot(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyGridRef *out_ref);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GHOSTTY_VT_GRID_REF_TRACKED_H */
|
||||
@@ -1120,6 +1120,37 @@ GHOSTTY_API GhosttyResult ghostty_terminal_grid_ref(GhosttyTerminal terminal,
|
||||
GhosttyPoint point,
|
||||
GhosttyGridRef *out_ref);
|
||||
|
||||
/**
|
||||
* Create an owned tracked grid reference for a terminal point.
|
||||
*
|
||||
* This is the tracked variant of ghostty_terminal_grid_ref(). The returned
|
||||
* handle follows the referenced cell as the terminal's page list is modified:
|
||||
* scrolling, pruning, resize/reflow, and other page-list operations update the
|
||||
* tracked reference automatically.
|
||||
*
|
||||
* The reference is attached to the terminal screen/page-list that is active at
|
||||
* creation time.
|
||||
*
|
||||
* If the point is outside the requested coordinate space, this returns
|
||||
* GHOSTTY_INVALID_VALUE and writes NULL to out_ref.
|
||||
*
|
||||
* The returned handle must be freed with ghostty_tracked_grid_ref_free() before
|
||||
* the terminal is freed.
|
||||
*
|
||||
* @param terminal Terminal instance.
|
||||
* @param point Point to track.
|
||||
* @param[out] out_ref On success, receives the tracked reference handle.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if terminal,
|
||||
* point, or out_ref is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation
|
||||
* fails.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_terminal_grid_ref_track(
|
||||
GhosttyTerminal terminal,
|
||||
GhosttyPoint point,
|
||||
GhosttyTrackedGridRef *out_ref);
|
||||
|
||||
/**
|
||||
* Convert a grid reference back to a point in the given coordinate system.
|
||||
*
|
||||
|
||||
@@ -94,6 +94,16 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
*/
|
||||
typedef struct GhosttyTerminalImpl* GhosttyTerminal;
|
||||
|
||||
/**
|
||||
* Opaque handle to a tracked grid reference.
|
||||
*
|
||||
* A tracked grid reference is owned by the caller and must be freed with
|
||||
* ghostty_tracked_grid_ref_free() before the terminal that created it is freed.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
typedef struct GhosttyTrackedGridRefImpl* GhosttyTrackedGridRef;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics image storage.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user