chore: import upstream snapshot with attribution
Test / build-libghostty-vt (x86_64-windows-gnu) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-ios) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt-macos (x86_64-macos) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsimd=false (push) Has been cancelled
Test / Build -Dsimd=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / GitHub Actions Pins (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / swiftlint (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Nix / check-zig-cache-hash (push) Has been cancelled
Test / skip (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / list-examples (push) Has been cancelled
Test / Example ${{ matrix.dir }} (Windows) (push) Has been cancelled
Test / build-cmake (push) Has been cancelled
Test / test-lib-vt-pkgconfig (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-snap (push) Has been cancelled
Test / build-libghostty-vt (aarch64-linux) (push) Has been cancelled
Test / build-libghostty-vt (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt (wasm32-freestanding) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux-musl) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-macos) (push) Has been cancelled
Test / build-libghostty-vt-android (aarch64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-android (arm-linux-androideabi) (push) Has been cancelled
Test / build-libghostty-vt-android (x86_64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-windows (push) Has been cancelled
Test / build-libghostty-windows-gnu (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-dist-lib-vt (push) Has been cancelled
Test / trigger-snap (push) Has been cancelled
Test / trigger-flatpak (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-freetype (push) Has been cancelled
Test / test (push) Has been cancelled
Test / test-lib-vt (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / test-windows (push) Has been cancelled
Test / Build -Di18n=false (push) Has been cancelled
Test / Build -Di18n=true (push) Has been cancelled
Test / Build test/fuzz-libghostty (push) Has been cancelled
Test / shellcheck (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 13 (push) Has been cancelled
Test / valgrind (push) Has been cancelled
Test / Example ${{ matrix.dir }} (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:02:48 +08:00
commit bd44b5aa08
5770 changed files with 506778 additions and 0 deletions
+1209
View File
File diff suppressed because it is too large Load Diff
+163
View File
@@ -0,0 +1,163 @@
/**
* @file vt.h
*
* libghostty-vt - Virtual terminal emulator library
*
* This library provides functionality for parsing and handling terminal
* escape sequences as well as maintaining terminal state such as styles,
* cursor position, screen, scrollback, and more.
*
* WARNING: This is an incomplete, work-in-progress API. It is not yet
* stable and is definitely going to change.
*/
/**
* @mainpage libghostty-vt - Virtual Terminal Emulator Library
*
* libghostty-vt is a C library which implements a modern terminal emulator,
* extracted from the [Ghostty](https://ghostty.org) terminal emulator.
*
* libghostty-vt contains the logic for handling the core parts of a terminal
* emulator: parsing terminal escape sequences, maintaining terminal state,
* encoding input events, etc. It can handle scrollback, line wrapping,
* reflow on resize, and more.
*
* @warning This library is currently in development and the API is not yet stable.
* Breaking changes are expected in future versions. Use with caution in production code.
*
* @section groups_sec API Reference
*
* The API is organized into the following groups:
* - @ref terminal "Terminal" - Complete terminal emulator state and rendering
* - @ref render "Render State" - Incremental render state updates for custom renderers
* - @ref formatter "Formatter" - Format terminal content as plain text, VT sequences, or HTML
* - @ref osc "OSC Parser" - Parse OSC (Operating System Command) sequences
* - @ref sgr "SGR Parser" - Parse SGR (Select Graphic Rendition) sequences
* - @ref paste "Paste Utilities" - Validate paste data safety
* - @ref unicode "Unicode Utilities" - Codepoint properties for text layout
* - @ref build_info "Build Info" - Query compile-time build configuration
* - @ref allocator "Memory Management" - Memory management and custom allocators
* - @ref wasm "WebAssembly Utilities" - WebAssembly convenience functions
*
* Encoding related APIs:
* - @ref focus "Focus Encoding" - Encode focus in/out events into terminal sequences
* - @ref key "Key Encoding" - Encode key events into terminal sequences
* - @ref mouse "Mouse Encoding" - Encode mouse events into terminal sequences
*
* @section examples_sec Examples
*
* Complete working examples:
* - @ref c-vt-build-info/src/main.c - Build info query example
* - @ref c-vt/src/main.c - OSC parser example
* - @ref c-vt-encode-key/src/main.c - Key encoding example
* - @ref c-vt-encode-mouse/src/main.c - Mouse encoding example
* - @ref c-vt-paste/src/main.c - Paste safety check example
* - @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
* - @ref c-vt-compression/src/main.c - Idle scrollback compression example
*
*/
/** @example c-vt-build-info/src/main.c
* This example demonstrates how to query compile-time build configuration
* such as SIMD support, Kitty graphics, and tmux control mode availability.
*/
/** @example c-vt/src/main.c
* This example demonstrates how to use the OSC parser to parse an OSC sequence,
* extract command information, and retrieve command-specific data like window titles.
*/
/** @example c-vt-encode-key/src/main.c
* This example demonstrates how to use the key encoder to convert key events
* into terminal escape sequences using the Kitty keyboard protocol.
*/
/** @example c-vt-encode-mouse/src/main.c
* This example demonstrates how to use the mouse encoder to convert mouse events
* into terminal escape sequences using the SGR mouse format.
*/
/** @example c-vt-paste/src/main.c
* This example demonstrates how to use the paste utilities to check if
* paste data is safe before sending it to the terminal.
*/
/** @example c-vt-sgr/src/main.c
* This example demonstrates how to use the SGR parser to parse terminal
* styling sequences and extract text attributes like colors and underline styles.
*/
/** @example c-vt-formatter/src/main.c
* This example demonstrates how to use the terminal and formatter APIs to
* create a terminal, write VT-encoded content into it, and format the screen
* contents as plain text.
*/
/** @example c-vt-grid-traverse/src/main.c
* This example demonstrates how to traverse the entire terminal grid using
* 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-compression/src/main.c
* This example demonstrates how to schedule incremental scrollback compression
* after compression-relevant terminal activity becomes idle.
*/
/** @example c-vt-selection-gesture/src/main.c
* This example demonstrates how to use synthetic selection gesture events to
* derive drag and deep-press selection snapshots.
*/
/** @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.
*/
#ifndef GHOSTTY_VT_H
#define GHOSTTY_VT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/build_info.h>
#include <ghostty/vt/color.h>
#include <ghostty/vt/color_scheme.h>
#include <ghostty/vt/device.h>
#include <ghostty/vt/focus.h>
#include <ghostty/vt/formatter.h>
#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>
#include <ghostty/vt/sys.h>
#include <ghostty/vt/key.h>
#include <ghostty/vt/kitty_graphics.h>
#include <ghostty/vt/modes.h>
#include <ghostty/vt/mouse.h>
#include <ghostty/vt/paste.h>
#include <ghostty/vt/point.h>
#include <ghostty/vt/screen.h>
#include <ghostty/vt/selection.h>
#include <ghostty/vt/size_report.h>
#include <ghostty/vt/unicode.h>
#include <ghostty/vt/wasm.h>
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_H */
+255
View File
@@ -0,0 +1,255 @@
/**
* @file allocator.h
*
* Memory management interface for libghostty-vt.
*/
#ifndef GHOSTTY_VT_ALLOCATOR_H
#define GHOSTTY_VT_ALLOCATOR_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
/** @defgroup allocator Memory Management
*
* libghostty-vt does require memory allocation for various operations,
* but is resilient to allocation failures and will gracefully handle
* out-of-memory situations by returning error codes.
*
* The exact memory management semantics are documented in the relevant
* functions and data structures.
*
* libghostty-vt uses explicit memory allocation via an allocator
* interface provided by GhosttyAllocator. The interface is based on the
* [Zig](https://ziglang.org) allocator interface, since this has been
* shown to be a flexible and powerful interface in practice and enables
* a wide variety of allocation strategies.
*
* **For the common case, you can pass NULL as the allocator for any
* function that accepts one,** and libghostty will use a default allocator.
* The default allocator will be libc malloc/free if libc is linked.
* Otherwise, a custom allocator is used (currently Zig's SMP allocator)
* that doesn't require any external dependencies.
*
* ## Basic Usage
*
* For simple use cases, you can ignore this interface entirely by passing NULL
* as the allocator parameter to functions that accept one. This will use the
* default allocator (typically libc malloc/free, if libc is linked, but
* we provide our own default allocator if libc isn't linked).
*
* To use a custom allocator:
* 1. Implement the GhosttyAllocatorVtable function pointers
* 2. Create a GhosttyAllocator struct with your vtable and context
* 3. Pass the allocator to functions that accept one
*
* ## Alloc/Free Helpers
*
* ghostty_alloc() and ghostty_free() provide a simple malloc/free-style
* interface for allocating and freeing byte buffers through the library's
* allocator. These are useful when:
*
* - You need to allocate a buffer to pass into a libghostty-vt function
* (e.g. preparing input data for ghostty_terminal_vt_write()).
* - You need to free a buffer returned by a libghostty-vt function
* (e.g. the output of ghostty_formatter_format_alloc()).
* - You are on a platform where the library's internal allocator differs
* from the consumer's C runtime (e.g. Windows, where Zig's libc and
* MSVC's CRT maintain separate heaps), so calling the standard C
* free() on library-allocated memory would be undefined behavior.
*
* Always use the same allocator (or NULL) for both the allocation and
* the corresponding free.
*
* @{
*/
/**
* Function table for custom memory allocator operations.
*
* This vtable defines the interface for a custom memory allocator. All
* function pointers must be valid and non-NULL.
*
* @ingroup allocator
*
* If you're not going to use a custom allocator, you can ignore all of
* this. All functions that take an allocator pointer allow NULL to use a
* default allocator.
*
* The interface is based on the Zig allocator interface. I'll say up front
* that it is easy to look at this interface and think "wow, this is really
* overcomplicated". The reason for this complexity is well thought out by
* the Zig folks, and it enables a diverse set of allocation strategies
* as shown by the Zig ecosystem. As a consolation, please note that many
* of the arguments are only needed for advanced use cases and can be
* safely ignored in simple implementations. For example, if you look at
* the Zig implementation of the libc allocator in `lib/std/heap.zig`
* (search for CAllocator), you'll see it is very simple.
*
* We chose to align with the Zig allocator interface because:
*
* 1. It is a proven interface that serves a wide variety of use cases
* in the real world via the Zig ecosystem. It's shown to work.
*
* 2. Our core implementation itself is Zig, and this lets us very
* cheaply and easily convert between C and Zig allocators.
*
* NOTE(mitchellh): In the future, we can have default implementations of
* resize/remap and allow those to be null.
*/
typedef struct {
/**
* Return a pointer to `len` bytes with specified `alignment`, or return
* `NULL` indicating the allocation failed.
*
* @param ctx The allocator context
* @param len Number of bytes to allocate
* @param alignment Required alignment for the allocation. Guaranteed to
* be a power of two between 1 and 16 inclusive.
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return Pointer to allocated memory, or NULL if allocation failed
*/
void* (*alloc)(void *ctx, size_t len, uint8_t alignment, uintptr_t ret_addr);
/**
* Attempt to expand or shrink memory in place.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* `new_len` must be greater than zero.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to resize
* @param memory_len Current size of the memory block
* @param alignment Alignment (must match original allocation)
* @param new_len New requested size
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return true if resize was successful in-place, false if relocation would be required
*/
bool (*resize)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
/**
* Attempt to expand or shrink memory, allowing relocation.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* A non-`NULL` return value indicates the resize was successful. The
* allocation may have same address, or may have been relocated. In either
* case, the allocation now has size of `new_len`. A `NULL` return value
* indicates that the resize would be equivalent to allocating new memory,
* copying the bytes from the old memory, and then freeing the old memory.
* In such case, it is more efficient for the caller to perform the copy.
*
* `new_len` must be greater than zero.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to remap
* @param memory_len Current size of the memory block
* @param alignment Alignment (must match original allocation)
* @param new_len New requested size
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return Pointer to resized memory (may be relocated), or NULL if manual copy is needed
*/
void* (*remap)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
/**
* Free and invalidate a region of memory.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to free
* @param memory_len Size of the memory block
* @param alignment Alignment (must match original allocation)
* @param ret_addr First return address of the allocation call stack (0 if not provided)
*/
void (*free)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, uintptr_t ret_addr);
} GhosttyAllocatorVtable;
/**
* Custom memory allocator.
*
* For functions that take an allocator pointer, a NULL pointer indicates
* that the default allocator should be used. The default allocator will
* be libc malloc/free if we're linking to libc. If libc isn't linked,
* a custom allocator is used (currently Zig's SMP allocator).
*
* @ingroup allocator
*
* Usage example:
* @code
* GhosttyAllocator allocator = {
* .vtable = &my_allocator_vtable,
* .ctx = my_allocator_state
* };
* @endcode
*/
typedef struct GhosttyAllocator {
/**
* Opaque context pointer passed to all vtable functions.
* This allows the allocator implementation to maintain state
* or reference external resources needed for memory management.
*/
void *ctx;
/**
* Pointer to the allocator's vtable containing function pointers
* for memory operations (alloc, resize, remap, free).
*/
const GhosttyAllocatorVtable *vtable;
} GhosttyAllocator;
/**
* Allocate a buffer of `len` bytes.
*
* Uses the provided allocator, or the default allocator if NULL is passed.
* The returned buffer must be freed with ghostty_free() using the same
* allocator.
*
* @param allocator Pointer to the allocator to use, or NULL for the default
* @param len Number of bytes to allocate
* @return Pointer to the allocated buffer, or NULL if allocation failed
*
* @ingroup allocator
*/
GHOSTTY_API uint8_t* ghostty_alloc(const GhosttyAllocator* allocator, size_t len);
/**
* Free memory that was allocated by a libghostty-vt function.
*
* Use this to free buffers returned by functions such as
* ghostty_formatter_format_alloc(). Pass the same allocator that was
* used for the allocation, or NULL if the default allocator was used.
*
* On platforms where the library's internal allocator differs from the
* consumer's C runtime (e.g. Windows, where Zig's libc and MSVC's CRT
* maintain separate heaps), calling the standard C free() on memory
* allocated by the library causes undefined behavior. This function
* guarantees the correct allocator is used regardless of platform.
*
* It is safe to pass a NULL pointer; the call is a no-op in that case.
*
* @param allocator Pointer to the allocator that was used to allocate the
* memory, or NULL if the default allocator was used
* @param ptr Pointer to the memory to free (may be NULL)
* @param len Length of the allocation in bytes (must match the original
* allocation size)
*
* @ingroup allocator
*/
GHOSTTY_API void ghostty_free(const GhosttyAllocator* allocator, uint8_t* ptr, size_t len);
/** @} */
#endif /* GHOSTTY_VT_ALLOCATOR_H */
+150
View File
@@ -0,0 +1,150 @@
/**
* @file build_info.h
*
* Build info - query compile-time build configuration of libghostty-vt.
*/
#ifndef GHOSTTY_VT_BUILD_INFO_H
#define GHOSTTY_VT_BUILD_INFO_H
/** @defgroup build_info Build Info
*
* Query compile-time build configuration of libghostty-vt.
*
* These values reflect the options the library was built with and are
* constant for the lifetime of the process.
*
* ## Basic Usage
*
* Use ghostty_build_info() to query individual build options:
*
* @snippet c-vt-build-info/src/main.c build-info-query
*
* @{
*/
#include <stddef.h>
#include <stdbool.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Build optimization mode.
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_OPTIMIZE_DEBUG = 0,
GHOSTTY_OPTIMIZE_RELEASE_SAFE = 1,
GHOSTTY_OPTIMIZE_RELEASE_SMALL = 2,
GHOSTTY_OPTIMIZE_RELEASE_FAST = 3,
GHOSTTY_OPTIMIZE_MODE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOptimizeMode;
/**
* Build info data types that can be queried.
*
* Each variant documents the expected output pointer type.
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid data type. Never results in any data extraction. */
GHOSTTY_BUILD_INFO_INVALID = 0,
/**
* Whether SIMD-accelerated code paths are enabled.
*
* Output type: bool *
*/
GHOSTTY_BUILD_INFO_SIMD = 1,
/**
* Whether Kitty graphics protocol support is available.
*
* Output type: bool *
*/
GHOSTTY_BUILD_INFO_KITTY_GRAPHICS = 2,
/**
* Whether tmux control mode support is available.
*
* Output type: bool *
*/
GHOSTTY_BUILD_INFO_TMUX_CONTROL_MODE = 3,
/**
* The optimization mode the library was built with.
*
* Output type: GhosttyOptimizeMode *
*/
GHOSTTY_BUILD_INFO_OPTIMIZE = 4,
/**
* The full version string (e.g. "1.2.3" or "1.2.3-dev+abcdef").
*
* Output type: GhosttyString *
*/
GHOSTTY_BUILD_INFO_VERSION_STRING = 5,
/**
* The major version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_MAJOR = 6,
/**
* The minor version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_MINOR = 7,
/**
* The patch version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_PATCH = 8,
/**
* The pre metadata string (e.g. "alpha", "beta", "dev"). Has zero length if
* no pre metadata is present.
*
* Output type: GhosttyString *
*/
GHOSTTY_BUILD_INFO_VERSION_PRE = 9,
/**
* The build metadata string (e.g. commit hash). Has zero length if
* no build metadata is present.
*
* Output type: GhosttyString *
*/
GHOSTTY_BUILD_INFO_VERSION_BUILD = 10,
GHOSTTY_BUILD_INFO_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyBuildInfo;
/**
* Query a compile-time build configuration value.
*
* The caller must pass a pointer to the correct output type for the
* requested data (see GhosttyBuildInfo variants for types).
*
* @param data The build info field to query
* @param out Pointer to store the result (type depends on data parameter)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
* data type is invalid
*
* @ingroup build_info
*/
GHOSTTY_API GhosttyResult ghostty_build_info(GhosttyBuildInfo data, void *out);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_BUILD_INFO_H */
+479
View File
@@ -0,0 +1,479 @@
/**
* @file color.h
*
* Color types and utilities.
*/
#ifndef GHOSTTY_VT_COLOR_H
#define GHOSTTY_VT_COLOR_H
/** @defgroup color Color Utilities
*
* Color parsing, palette generation, color math, and X11 color name
* utilities shared by libghostty-vt.
*
* These APIs expose Ghostty's color semantics directly to embedders. Use
* them when an application needs to parse the same color strings as Ghostty
* config and theme files, generate the same 256-color palette used by the
* terminal, list supported X11 color names, or make UI decisions from
* luminance and contrast values.
*
* ## Parsing Colors
*
* ghostty_color_parse() accepts the flexible syntax used by Ghostty for
* terminal colors:
*
* - X11 color names, matched ASCII case-insensitively.
* - 3- or 6-digit hex colors, with or without a leading `#`.
* - 9- or 12-digit hex colors, with a leading `#`.
* - XParseColor-style `rgb:<red>/<green>/<blue>` values.
* - XParseColor-style `rgbi:<red>/<green>/<blue>` values.
*
* Leading and trailing spaces and tabs are ignored. Use
* ghostty_color_parse_x11() when only X11 names should be accepted.
*
* @code{.c}
* GhosttyColorRgb color;
*
* if (ghostty_color_parse(
* "ForestGreen",
* sizeof("ForestGreen") - 1,
* &color) != GHOSTTY_SUCCESS) {
* // Handle invalid color input.
* }
*
* ghostty_color_parse("#abc", sizeof("#abc") - 1, &color);
* ghostty_color_parse("rgb:12/34/56", sizeof("rgb:12/34/56") - 1, &color);
* @endcode
*
* ## Palette Entries
*
* ghostty_color_parse_palette_entry() parses a single Ghostty palette
* override in `INDEX=COLOR` form. The index may be decimal or use a `0x`,
* `0o`, or `0b` prefix. The color side uses ghostty_color_parse().
*
* @code{.c}
* GhosttyColorRgb palette[256];
* ghostty_color_palette_default(palette);
*
* uint8_t index;
* GhosttyColorRgb rgb;
*
* if (ghostty_color_parse_palette_entry(
* "0x10=#282c34",
* sizeof("0x10=#282c34") - 1,
* &index,
* &rgb) == GHOSTTY_SUCCESS) {
* palette[index] = rgb;
* }
* @endcode
*
* ## Palette Generation
*
* ghostty_color_palette_generate() derives the 216-color cube and grayscale
* ramp from a base palette, background, and foreground. Set bits in
* GhosttyColorPaletteMask preserve specific indices from the base palette.
* The output may alias the base input.
*
* @code{.c}
* GhosttyColorRgb palette[256];
* ghostty_color_palette_default(palette);
*
* GhosttyColorPaletteMask skip = {0};
* GHOSTTY_COLOR_PALETTE_MASK_SET(&skip, 16);
*
* GhosttyColorRgb background = {40, 44, 52};
* GhosttyColorRgb foreground = {220, 223, 228};
*
* ghostty_color_palette_generate(
* palette,
* &skip,
* &background,
* &foreground,
* true,
* palette);
* @endcode
*
* ## X11 Color Names
*
* The X11 name table is static program-lifetime memory. Entries are in
* rgb.txt order and are terminated by an entry with `name == NULL`.
* ghostty_color_x11_name_count() returns the number of non-terminator
* entries.
*
* @code{.c}
* const GhosttyColorX11Entry* names = ghostty_color_x11_names();
* size_t count = ghostty_color_x11_name_count();
*
* for (size_t i = 0; i < count; i++) {
* // names[i].name and names[i].color are valid here.
* }
* @endcode
*
* @{
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* RGB color value.
*
* @ingroup color
*/
typedef struct {
uint8_t r; /**< Red component (0-255) */
uint8_t g; /**< Green component (0-255) */
uint8_t b; /**< Blue component (0-255) */
} GhosttyColorRgb;
/**
* Palette color index (0-255).
*
* @ingroup color
*/
typedef uint8_t GhosttyColorPaletteIndex;
/**
* A 256-bit mask of palette indices.
*
* Index i is set iff `(bits[i >> 6] >> (i & 63)) & 1` is 1.
* The mask is typically initialized to zero and then populated with
* GHOSTTY_COLOR_PALETTE_MASK_SET().
*
* @code{.c}
* GhosttyColorPaletteMask mask = {0};
* GHOSTTY_COLOR_PALETTE_MASK_SET(&mask, 20);
* if (GHOSTTY_COLOR_PALETTE_MASK_IS_SET(&mask, 20)) {
* // Index 20 will be preserved.
* }
* @endcode
*
* @ingroup color
*/
typedef struct {
uint64_t bits[4];
} GhosttyColorPaletteMask;
/**
* An entry in Ghostty's X11 color name table.
*
* @ingroup color
*/
typedef struct {
/** Null-terminated color name. NULL marks the end of the table. */
const char* name;
/** The RGB value of the color. */
GhosttyColorRgb color;
} GhosttyColorX11Entry;
/**
* Return the storage word for a palette mask index.
*
* @param index The palette index (0-255)
*
* @ingroup color
*/
#define GHOSTTY_COLOR_PALETTE_MASK_WORD(index) ((index) >> 6)
/**
* Return the storage bit for a palette mask index.
*
* @param index The palette index (0-255)
*
* @ingroup color
*/
#define GHOSTTY_COLOR_PALETTE_MASK_BIT(index) (UINT64_C(1) << ((index) & 63))
/**
* Set a palette mask index.
*
* @param mask Pointer to a GhosttyColorPaletteMask
* @param index The palette index (0-255)
*
* @ingroup color
*/
#define GHOSTTY_COLOR_PALETTE_MASK_SET(mask, index) \
((mask)->bits[GHOSTTY_COLOR_PALETTE_MASK_WORD(index)] |= GHOSTTY_COLOR_PALETTE_MASK_BIT(index))
/**
* Clear a palette mask index.
*
* @param mask Pointer to a GhosttyColorPaletteMask
* @param index The palette index (0-255)
*
* @ingroup color
*/
#define GHOSTTY_COLOR_PALETTE_MASK_UNSET(mask, index) \
((mask)->bits[GHOSTTY_COLOR_PALETTE_MASK_WORD(index)] &= ~GHOSTTY_COLOR_PALETTE_MASK_BIT(index))
/**
* Test whether a palette mask index is set.
*
* @param mask Pointer to a GhosttyColorPaletteMask
* @param index The palette index (0-255)
* @return true if the palette index is set, false otherwise
*
* @ingroup color
*/
#define GHOSTTY_COLOR_PALETTE_MASK_IS_SET(mask, index) \
(((mask)->bits[GHOSTTY_COLOR_PALETTE_MASK_WORD(index)] & GHOSTTY_COLOR_PALETTE_MASK_BIT(index)) != 0)
/** Black color (0) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BLACK 0
/** Red color (1) @ingroup color */
#define GHOSTTY_COLOR_NAMED_RED 1
/** Green color (2) @ingroup color */
#define GHOSTTY_COLOR_NAMED_GREEN 2
/** Yellow color (3) @ingroup color */
#define GHOSTTY_COLOR_NAMED_YELLOW 3
/** Blue color (4) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BLUE 4
/** Magenta color (5) @ingroup color */
#define GHOSTTY_COLOR_NAMED_MAGENTA 5
/** Cyan color (6) @ingroup color */
#define GHOSTTY_COLOR_NAMED_CYAN 6
/** White color (7) @ingroup color */
#define GHOSTTY_COLOR_NAMED_WHITE 7
/** Bright black color (8) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_BLACK 8
/** Bright red color (9) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_RED 9
/** Bright green color (10) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_GREEN 10
/** Bright yellow color (11) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_YELLOW 11
/** Bright blue color (12) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_BLUE 12
/** Bright magenta color (13) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_MAGENTA 13
/** Bright cyan color (14) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_CYAN 14
/** Bright white color (15) @ingroup color */
#define GHOSTTY_COLOR_NAMED_BRIGHT_WHITE 15
/**
* Get the RGB color components.
*
* This function extracts the individual red, green, and blue components
* from a GhosttyColorRgb value. Primarily useful in WebAssembly environments
* where accessing struct fields directly is difficult.
*
* @param color Pointer to the RGB color value
* @param r Pointer to store the red component (0-255)
* @param g Pointer to store the green component (0-255)
* @param b Pointer to store the blue component (0-255)
*
* @ingroup color
*/
GHOSTTY_API void ghostty_color_rgb_get(const GhosttyColorRgb* color,
uint8_t* r,
uint8_t* g,
uint8_t* b);
/**
* Parse an X11 color name.
*
* The color name is resolved from Ghostty's embedded rgb.txt table.
* Leading and trailing spaces and tabs are trimmed, and matching is
* ASCII case-insensitive. Hex values are not accepted by this function.
*
* @param name The color name bytes (must not be NULL)
* @param len The length of @p name in bytes
* @param[out] out The parsed RGB color
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if no color
* matches or @p name is NULL
*
* @ingroup color
*/
GHOSTTY_API GhosttyResult ghostty_color_parse_x11(
const char* name,
size_t len,
GhosttyColorRgb* out);
/**
* Parse a flexible Ghostty color value.
*
* Accepts Ghostty's terminal color syntax: X11 color names, hex colors
* in 3-, 6-, 9-, or 12-digit form (the leading # is optional for 3- and
* 6-digit values), and rgb:<red>/<green>/<blue> or
* rgbi:<red>/<green>/<blue> specifications. Leading and trailing spaces
* and tabs are trimmed.
*
* @param value The color value bytes (must not be NULL)
* @param len The length of @p value in bytes
* @param[out] out The parsed RGB color
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if parsing
* fails or @p value is NULL
*
* @ingroup color
*/
GHOSTTY_API GhosttyResult ghostty_color_parse(
const char* value,
size_t len,
GhosttyColorRgb* out);
/**
* Parse a Ghostty palette entry.
*
* Accepts Ghostty palette config syntax: N=COLOR. N is a palette index
* from 0 to 255 in decimal or in 0x, 0o, or 0b-prefixed form. Spaces and
* tabs around N and COLOR are ignored. COLOR accepts the same syntax as
* ghostty_color_parse().
*
* @param value The palette entry bytes (must not be NULL)
* @param len The length of @p value in bytes
* @param[out] out_index The parsed palette index
* @param[out] out_rgb The parsed RGB color
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE on any
* failure, including index overflow
*
* @ingroup color
*/
GHOSTTY_API GhosttyResult ghostty_color_parse_palette_entry(
const char* value,
size_t len,
uint8_t* out_index,
GhosttyColorRgb* out_rgb);
/**
* Get Ghostty's built-in default 256-color palette.
*
* Writes exactly 256 entries: Ghostty's base16 defaults, the xterm
* 6x6x6 color cube, and the grayscale ramp.
*
* @param[out] out The output palette, an array of exactly 256
* GhosttyColorRgb values
*
* @ingroup color
*/
GHOSTTY_API void ghostty_color_palette_default(GhosttyColorRgb* out);
/**
* Generate a 256-color palette from base colors.
*
* The base palette supplies indices 0-15, which are always preserved.
* If @p base is NULL, Ghostty's default palette is used. If @p skip is
* NULL, no extra indices are skipped. Set bits in @p skip preserve those
* indices from @p base. The 216-color cube at indices 16-231 is generated
* with trilinear CIELAB interpolation, and the grayscale ramp at indices
* 232-255 is interpolated from the background to the foreground.
*
* For light themes, @p harmonious controls whether the generated palette
* keeps the background-to-foreground orientation. When false, Ghostty
* swaps the light background and dark foreground so the cube and ramp run
* dark-to-light. The output palette may be the same pointer as @p base.
*
* @param base The base palette, an array of exactly 256 GhosttyColorRgb
* values, or NULL to use Ghostty's default palette
* @param skip The palette indices to preserve from @p base, or NULL for
* an empty mask
* @param bg The terminal background color (must not be NULL)
* @param fg The terminal foreground color (must not be NULL)
* @param harmonious Whether light themes keep background-to-foreground
* orientation
* @param[out] out The output palette, an array of exactly 256
* GhosttyColorRgb values
*
* @ingroup color
*/
GHOSTTY_API void ghostty_color_palette_generate(
const GhosttyColorRgb* base,
const GhosttyColorPaletteMask* skip,
const GhosttyColorRgb* bg,
const GhosttyColorRgb* fg,
bool harmonious,
GhosttyColorRgb* out);
/**
* Calculate W3C relative luminance for an RGB color.
*
* Returns a normalized value from 0.0 for black to 1.0 for white.
* See https://www.w3.org/TR/WCAG20/#relativeluminancedef.
*
* @param color The RGB color (must not be NULL)
* @return Relative luminance in the range 0.0 to 1.0
*
* @ingroup color
*/
GHOSTTY_API double ghostty_color_luminance(const GhosttyColorRgb* color);
/**
* Calculate perceived luminance for an RGB color.
*
* Returns a normalized value from 0.0 for black to 1.0 for white.
* Ghostty treats a background color as light when this exceeds 0.5.
* This is not the metric used internally by
* ghostty_color_palette_generate(), which uses CIELAB lightness.
*
* @param color The RGB color (must not be NULL)
* @return Perceived luminance in the range 0.0 to 1.0
*
* @ingroup color
*/
GHOSTTY_API double ghostty_color_perceived_luminance(const GhosttyColorRgb* color);
/**
* Calculate the WCAG contrast ratio between two RGB colors.
*
* The contrast ratio is symmetric and ranges from 1.0 for identical
* colors to 21.0 for black and white.
*
* @param a The first RGB color (must not be NULL)
* @param b The second RGB color (must not be NULL)
* @return WCAG contrast ratio in the range 1.0 to 21.0
*
* @ingroup color
*/
GHOSTTY_API double ghostty_color_contrast(const GhosttyColorRgb* a,
const GhosttyColorRgb* b);
/**
* Get Ghostty's X11 color name table.
*
* The returned pointer references static memory valid for the program
* lifetime and is never NULL. Entries are in rgb.txt order and are
* terminated by an entry with name == NULL. Aliases are separate entries,
* such as "medium spring green" and "MediumSpringGreen". Names are the
* exact supported spellings from rgb.txt; ghostty_color_parse_x11() also
* matches them case-insensitively.
*
* @code{.c}
* for (const GhosttyColorX11Entry* e = ghostty_color_x11_names();
* e->name != NULL;
* e++) {
* // e->name and e->color are valid here.
* }
* @endcode
*
* @return Pointer to the first X11 color entry
*
* @ingroup color
*/
GHOSTTY_API const GhosttyColorX11Entry* ghostty_color_x11_names(void);
/**
* Get the number of X11 color name entries.
*
* The returned count excludes the NULL terminator and is provided so
* bindings can preallocate storage before reading ghostty_color_x11_names().
*
* @return Number of X11 color name entries
*
* @ingroup color
*/
GHOSTTY_API size_t ghostty_color_x11_name_count(void);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_COLOR_H */
+73
View File
@@ -0,0 +1,73 @@
/**
* @file color_scheme.h
*
* Color scheme report encoding - encode terminal color scheme reports into
* escape sequences.
*/
#ifndef GHOSTTY_VT_COLOR_SCHEME_H
#define GHOSTTY_VT_COLOR_SCHEME_H
/** @defgroup color_scheme Color Scheme Report Encoding
*
* Utilities for encoding color scheme reports into terminal escape
* sequences for color scheme reporting mode (mode 2031).
*
* ## Basic Usage
*
* Use ghostty_color_scheme_report_encode() to encode a color scheme report
* into a caller-provided buffer. If the buffer is too small, the function
* returns GHOSTTY_OUT_OF_SPACE and sets the required size in the output
* parameter.
*
* ## Example
*
* @snippet c-vt-color-scheme/src/main.c color-scheme-report-encode
*
* @{
*/
#include <stddef.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Encode a color scheme report into an escape sequence.
*
* Encodes a color scheme report into the provided buffer. Dark color schemes
* emit ESC [ ? 997 ; 1 n, and light color schemes emit ESC [ ? 997 ; 2 n.
* The encoded bytes are identical to the terminal's internal CSI ? 996 n
* query response.
*
* Hosts should gate unsolicited sends on GHOSTTY_MODE_COLOR_SCHEME_REPORT
* (mode 2031) being set, which can be checked via the mode getters.
*
* If the buffer is too small, the function returns GHOSTTY_OUT_OF_SPACE
* and writes the required buffer size to @p out_written. The caller can
* then retry with a sufficiently sized buffer.
*
* @param scheme The color scheme to encode
* @param buf Output buffer to write the encoded sequence into (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_written On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
* is too small
*/
GHOSTTY_API GhosttyResult ghostty_color_scheme_report_encode(
GhosttyColorScheme scheme,
char* buf,
size_t buf_len,
size_t* out_written);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_COLOR_SCHEME_H */
+151
View File
@@ -0,0 +1,151 @@
/**
* @file device.h
*
* Device types used by the terminal for device status and device attribute
* queries.
*/
#ifndef GHOSTTY_VT_DEVICE_H
#define GHOSTTY_VT_DEVICE_H
#include <stddef.h>
#include <stdint.h>
/* DA1 conformance levels (Pp parameter). */
#define GHOSTTY_DA_CONFORMANCE_VT100 1
#define GHOSTTY_DA_CONFORMANCE_VT101 1
#define GHOSTTY_DA_CONFORMANCE_VT102 6
#define GHOSTTY_DA_CONFORMANCE_VT125 12
#define GHOSTTY_DA_CONFORMANCE_VT131 7
#define GHOSTTY_DA_CONFORMANCE_VT132 4
#define GHOSTTY_DA_CONFORMANCE_VT220 62
#define GHOSTTY_DA_CONFORMANCE_VT240 62
#define GHOSTTY_DA_CONFORMANCE_VT320 63
#define GHOSTTY_DA_CONFORMANCE_VT340 63
#define GHOSTTY_DA_CONFORMANCE_VT420 64
#define GHOSTTY_DA_CONFORMANCE_VT510 65
#define GHOSTTY_DA_CONFORMANCE_VT520 65
#define GHOSTTY_DA_CONFORMANCE_VT525 65
#define GHOSTTY_DA_CONFORMANCE_LEVEL_2 62
#define GHOSTTY_DA_CONFORMANCE_LEVEL_3 63
#define GHOSTTY_DA_CONFORMANCE_LEVEL_4 64
#define GHOSTTY_DA_CONFORMANCE_LEVEL_5 65
/* DA1 feature codes (Ps parameters). */
#define GHOSTTY_DA_FEATURE_COLUMNS_132 1
#define GHOSTTY_DA_FEATURE_PRINTER 2
#define GHOSTTY_DA_FEATURE_REGIS 3
#define GHOSTTY_DA_FEATURE_SIXEL 4
#define GHOSTTY_DA_FEATURE_SELECTIVE_ERASE 6
#define GHOSTTY_DA_FEATURE_USER_DEFINED_KEYS 8
#define GHOSTTY_DA_FEATURE_NATIONAL_REPLACEMENT 9
#define GHOSTTY_DA_FEATURE_TECHNICAL_CHARACTERS 15
#define GHOSTTY_DA_FEATURE_LOCATOR 16
#define GHOSTTY_DA_FEATURE_TERMINAL_STATE 17
#define GHOSTTY_DA_FEATURE_WINDOWING 18
#define GHOSTTY_DA_FEATURE_HORIZONTAL_SCROLLING 21
#define GHOSTTY_DA_FEATURE_ANSI_COLOR 22
#define GHOSTTY_DA_FEATURE_RECTANGULAR_EDITING 28
#define GHOSTTY_DA_FEATURE_ANSI_TEXT_LOCATOR 29
#define GHOSTTY_DA_FEATURE_CLIPBOARD 52
/* DA2 device type identifiers (Pp parameter). */
#define GHOSTTY_DA_DEVICE_TYPE_VT100 0
#define GHOSTTY_DA_DEVICE_TYPE_VT220 1
#define GHOSTTY_DA_DEVICE_TYPE_VT240 2
#define GHOSTTY_DA_DEVICE_TYPE_VT330 18
#define GHOSTTY_DA_DEVICE_TYPE_VT340 19
#define GHOSTTY_DA_DEVICE_TYPE_VT320 24
#define GHOSTTY_DA_DEVICE_TYPE_VT382 32
#define GHOSTTY_DA_DEVICE_TYPE_VT420 41
#define GHOSTTY_DA_DEVICE_TYPE_VT510 61
#define GHOSTTY_DA_DEVICE_TYPE_VT520 64
#define GHOSTTY_DA_DEVICE_TYPE_VT525 65
#ifdef __cplusplus
extern "C" {
#endif
/**
* Color scheme reported in response to a CSI ? 996 n query.
*
* @ingroup terminal
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_COLOR_SCHEME_LIGHT = 0,
GHOSTTY_COLOR_SCHEME_DARK = 1,
GHOSTTY_COLOR_SCHEME_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyColorScheme;
/**
* Primary device attributes (DA1) response data.
*
* Returned as part of GhosttyDeviceAttributes in response to a CSI c query.
* The conformance_level is the Pp parameter and features contains the Ps
* feature codes.
*
* @ingroup terminal
*/
typedef struct {
/** Conformance level (Pp parameter). E.g. 62 for VT220. */
uint16_t conformance_level;
/** DA1 feature codes. Only the first num_features entries are valid. */
uint16_t features[64];
/** Number of valid entries in the features array. */
size_t num_features;
} GhosttyDeviceAttributesPrimary;
/**
* Secondary device attributes (DA2) response data.
*
* Returned as part of GhosttyDeviceAttributes in response to a CSI > c query.
* Response format: CSI > Pp ; Pv ; Pc c
*
* @ingroup terminal
*/
typedef struct {
/** Terminal type identifier (Pp). E.g. 1 for VT220. */
uint16_t device_type;
/** Firmware/patch version number (Pv). */
uint16_t firmware_version;
/** ROM cartridge registration number (Pc). Always 0 for emulators. */
uint16_t rom_cartridge;
} GhosttyDeviceAttributesSecondary;
/**
* Tertiary device attributes (DA3) response data.
*
* Returned as part of GhosttyDeviceAttributes in response to a CSI = c query.
* Response format: DCS ! | D...D ST (DECRPTUI).
*
* @ingroup terminal
*/
typedef struct {
/** Unit ID encoded as 8 uppercase hex digits in the response. */
uint32_t unit_id;
} GhosttyDeviceAttributesTertiary;
/**
* Device attributes response data for all three DA levels.
*
* Filled by the device_attributes callback in response to CSI c,
* CSI > c, or CSI = c queries. The terminal uses whichever sub-struct
* matches the request type.
*
* @ingroup terminal
*/
typedef struct {
GhosttyDeviceAttributesPrimary primary;
GhosttyDeviceAttributesSecondary secondary;
GhosttyDeviceAttributesTertiary tertiary;
} GhosttyDeviceAttributes;
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_DEVICE_H */
+76
View File
@@ -0,0 +1,76 @@
/**
* @file focus.h
*
* Focus encoding - encode focus in/out events into terminal escape sequences.
*/
#ifndef GHOSTTY_VT_FOCUS_H
#define GHOSTTY_VT_FOCUS_H
/** @defgroup focus Focus Encoding
*
* Utilities for encoding focus gained/lost events into terminal escape
* sequences (CSI I / CSI O) for focus reporting mode (mode 1004).
*
* ## Basic Usage
*
* Use ghostty_focus_encode() to encode a focus event into a caller-provided
* buffer. If the buffer is too small, the function returns
* GHOSTTY_OUT_OF_SPACE and sets the required size in the output parameter.
*
* ## Example
*
* @snippet c-vt-encode-focus/src/main.c focus-encode
*
* @{
*/
#include <stddef.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Focus event types for focus reporting mode (mode 1004).
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Terminal window gained focus */
GHOSTTY_FOCUS_GAINED = 0,
/** Terminal window lost focus */
GHOSTTY_FOCUS_LOST = 1,
GHOSTTY_FOCUS_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyFocusEvent;
/**
* Encode a focus event into a terminal escape sequence.
*
* Encodes a focus gained (CSI I) or focus lost (CSI O) report into the
* provided buffer.
*
* If the buffer is too small, the function returns GHOSTTY_OUT_OF_SPACE
* and writes the required buffer size to @p out_written. The caller can
* then retry with a sufficiently sized buffer.
*
* @param event The focus event to encode
* @param buf Output buffer to write the encoded sequence into (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_written On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
* is too small
*/
GHOSTTY_API GhosttyResult ghostty_focus_encode(
GhosttyFocusEvent event,
char* buf,
size_t buf_len,
size_t* out_written);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_FOCUS_H */
+207
View File
@@ -0,0 +1,207 @@
/**
* @file formatter.h
*
* Format terminal content as plain text, VT sequences, or HTML.
*/
#ifndef GHOSTTY_VT_FORMATTER_H
#define GHOSTTY_VT_FORMATTER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/selection.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/terminal.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup formatter Formatter
*
* Format terminal content as plain text, VT sequences, or HTML.
*
* A formatter captures a reference to a terminal and formatting options.
* It can be used repeatedly to produce output that reflects the current
* terminal state at the time of each format call.
*
* The terminal must outlive the formatter.
*
* @{
*/
/**
* Extra screen state to include in styled output.
*
* @ingroup formatter
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyFormatterScreenExtra). */
size_t size;
/** Emit cursor position using CUP (CSI H). */
bool cursor;
/** Emit current SGR style state based on the cursor's active style_id. */
bool style;
/** Emit current hyperlink state using OSC 8 sequences. */
bool hyperlink;
/** Emit character protection mode using DECSCA. */
bool protection;
/** Emit Kitty keyboard protocol state using CSI > u and CSI = sequences. */
bool kitty_keyboard;
/** Emit character set designations and invocations. */
bool charsets;
} GhosttyFormatterScreenExtra;
/**
* Extra terminal state to include in styled output.
*
* @ingroup formatter
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyFormatterTerminalExtra). */
size_t size;
/** Emit the palette using OSC 4 sequences. */
bool palette;
/** Emit terminal modes that differ from their defaults using CSI h/l. */
bool modes;
/** Emit scrolling region state using DECSTBM and DECSLRM sequences. */
bool scrolling_region;
/** Emit tabstop positions by clearing all tabs and setting each one. */
bool tabstops;
/** Emit the present working directory using OSC 7. */
bool pwd;
/** Emit keyboard modes such as ModifyOtherKeys. */
bool keyboard;
/** Screen-level extras. */
GhosttyFormatterScreenExtra screen;
} GhosttyFormatterTerminalExtra;
/**
* Options for creating a terminal formatter.
*
* @ingroup formatter
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyFormatterTerminalOptions). */
size_t size;
/** Output format to emit. */
GhosttyFormatterFormat emit;
/** Whether to unwrap soft-wrapped lines. */
bool unwrap;
/** Whether to trim trailing whitespace on non-blank lines. */
bool trim;
/** Extra terminal state to include in styled output. */
GhosttyFormatterTerminalExtra extra;
/** Optional selection to restrict output to a range.
* If NULL, the entire screen is formatted. */
const GhosttySelection *selection;
} GhosttyFormatterTerminalOptions;
/**
* Create a formatter for a terminal's active screen.
*
* The terminal must outlive the formatter. The formatter stores a borrowed
* reference to the terminal and reads its current state on each format call.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param formatter Pointer to store the created formatter handle
* @param terminal The terminal to format (must not be NULL)
* @param options Formatting options
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup formatter
*/
GHOSTTY_API GhosttyResult ghostty_formatter_terminal_new(
const GhosttyAllocator* allocator,
GhosttyFormatter* formatter,
GhosttyTerminal terminal,
GhosttyFormatterTerminalOptions options);
/**
* Run the formatter and produce output into the caller-provided buffer.
*
* Each call formats the current terminal state. Pass NULL for buf to
* query the required buffer size without writing any output; in that case
* out_written receives the required size and the return value is
* GHOSTTY_OUT_OF_SPACE.
*
* If the buffer is too small, returns GHOSTTY_OUT_OF_SPACE and sets
* out_written to the required size. The caller can then retry with a
* larger buffer.
*
* @param formatter The formatter handle (must not be NULL)
* @param buf Pointer to the output buffer, or NULL to query size
* @param buf_len Length of the output buffer in bytes
* @param out_written Pointer to receive the number of bytes written,
* or the required size on failure
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup formatter
*/
GHOSTTY_API GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatter,
uint8_t* buf,
size_t buf_len,
size_t* out_written);
/**
* Run the formatter and return an allocated buffer with the output.
*
* Each call formats the current terminal state. The buffer is allocated
* using the provided allocator (or the default allocator if NULL).
* The caller is responsible for freeing the returned buffer with
* ghostty_free(), passing the same allocator (or NULL for the default)
* that was used for the allocation.
*
* @param formatter The formatter handle (must not be NULL)
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param out_ptr Pointer to receive the allocated buffer
* @param out_len Pointer to receive the length of the output in bytes
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
* failure
*
* @ingroup formatter
*/
GHOSTTY_API GhosttyResult ghostty_formatter_format_alloc(GhosttyFormatter formatter,
const GhosttyAllocator* allocator,
uint8_t** out_ptr,
size_t* out_len);
/**
* Free a formatter instance.
*
* Releases all resources associated with the formatter. After this call,
* the formatter handle becomes invalid.
*
* @param formatter The formatter handle to free (may be NULL)
*
* @ingroup formatter
*/
GHOSTTY_API void ghostty_formatter_free(GhosttyFormatter formatter);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_FORMATTER_H */
+212
View File
@@ -0,0 +1,212 @@
/**
* @file grid_ref.h
*
* Terminal grid reference type for referencing a resolved position in the
* terminal grid.
*/
#ifndef GHOSTTY_VT_GRID_REF_H
#define GHOSTTY_VT_GRID_REF_H
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/screen.h>
#include <ghostty/vt/style.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup grid_ref Grid Reference
*
* 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.
*
* 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.
*
* ## Untracked vs Tracked References
*
* ### Untracked Reference
*
* 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(). If the terminal that created a tracked
* reference is freed first, the handle remains valid only for tracked-grid-ref
* APIs: it reports no value and can still be 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. A tracked reference may outlive the terminal that created it;
* after terminal free, it reports no value and can still be 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
*
* @{
*/
/**
* A resolved reference to a terminal cell position.
*
* This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
*
* @ingroup grid_ref
*/
typedef struct {
size_t size;
void *node;
uint16_t x;
uint16_t y;
} GhosttyGridRef;
/**
* Get the cell from a grid reference.
*
* @param ref Pointer to the grid reference
* @param[out] out_cell On success, set to the cell at the ref's position (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
* node is NULL
*
* @ingroup grid_ref
*/
GHOSTTY_API GhosttyResult ghostty_grid_ref_cell(const GhosttyGridRef *ref,
GhosttyCell *out_cell);
/**
* Get the row from a grid reference.
*
* @param ref Pointer to the grid reference
* @param[out] out_row On success, set to the row at the ref's position (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
* node is NULL
*
* @ingroup grid_ref
*/
GHOSTTY_API GhosttyResult ghostty_grid_ref_row(const GhosttyGridRef *ref,
GhosttyRow *out_row);
/**
* Get the grapheme cluster codepoints for the cell at the grid reference's
* position.
*
* Writes the full grapheme cluster (the cell's primary codepoint followed by
* any combining codepoints) into the provided buffer. If the cell has no text,
* out_len is set to 0 and GHOSTTY_SUCCESS is returned.
*
* If the buffer is too small (or NULL), the function returns
* GHOSTTY_OUT_OF_SPACE and writes the required number of codepoints to
* out_len. The caller can then retry with a sufficiently sized buffer.
*
* @param ref Pointer to the grid reference
* @param buf Output buffer of uint32_t codepoints (may be NULL)
* @param buf_len Number of uint32_t elements in the buffer
* @param[out] out_len On success, the number of codepoints written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size in codepoints.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
* node is NULL, GHOSTTY_OUT_OF_SPACE if the buffer is too small
*
* @ingroup grid_ref
*/
GHOSTTY_API GhosttyResult ghostty_grid_ref_graphemes(const GhosttyGridRef *ref,
uint32_t *buf,
size_t buf_len,
size_t *out_len);
/**
* Get the hyperlink URI for the cell at the grid reference's position.
*
* Writes the URI bytes into the provided buffer. If the cell has no
* hyperlink, out_len is set to 0 and GHOSTTY_SUCCESS is returned.
*
* If the buffer is too small (or NULL), the function returns
* GHOSTTY_OUT_OF_SPACE and writes the required number of bytes to
* out_len. The caller can then retry with a sufficiently sized buffer.
*
* @param ref Pointer to the grid reference
* @param buf Output buffer for the URI bytes (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_len On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size in bytes.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
* node is NULL, GHOSTTY_OUT_OF_SPACE if the buffer is too small
*
* @ingroup grid_ref
*/
GHOSTTY_API GhosttyResult ghostty_grid_ref_hyperlink_uri(
const GhosttyGridRef *ref,
uint8_t *buf,
size_t buf_len,
size_t *out_len);
/**
* Get the style of the cell at the grid reference's position.
*
* @param ref Pointer to the grid reference
* @param[out] out_style On success, set to the cell's style (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
* node is NULL
*
* @ingroup grid_ref
*/
GHOSTTY_API GhosttyResult ghostty_grid_ref_style(const GhosttyGridRef *ref,
GhosttyStyle *out_style);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_GRID_REF_H */
+139
View File
@@ -0,0 +1,139 @@
/**
* @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. A tracked reference may be freed
* after 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.
*
* If the terminal that created the tracked reference has been freed, this
* returns false.
*
* @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, including after the
* terminal that created the tracked reference has been freed.
*
* @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. This includes references whose owning terminal has been
* freed.
*
* @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 */
+73
View File
@@ -0,0 +1,73 @@
/**
* @file key.h
*
* Key encoding module - encode key events into terminal escape sequences.
*/
#ifndef GHOSTTY_VT_KEY_H
#define GHOSTTY_VT_KEY_H
/** @defgroup key Key Encoding
*
* Utilities for encoding key events into terminal escape sequences,
* supporting both legacy encoding as well as Kitty Keyboard Protocol.
*
* ## Basic Usage
*
* 1. Create an encoder instance with ghostty_key_encoder_new()
* 2. Configure encoder options with ghostty_key_encoder_setopt()
* or ghostty_key_encoder_setopt_from_terminal() if you have a
* GhosttyTerminal.
* 3. For each key event:
* - Create a key event with ghostty_key_event_new()
* - Set event properties (action, key, modifiers, etc.)
* - Encode with ghostty_key_encoder_encode()
* - Free the event with ghostty_key_event_free()
* - Note: You can also reuse the same key event multiple times by
* changing its properties.
* 4. Free the encoder with ghostty_key_encoder_free() when done
*
* For a complete working example, see example/c-vt-encode-key in the
* repository.
*
* ## Example
*
* @snippet c-vt-encode-key/src/main.c key-encode
*
* ## Example: Encoding with Terminal State
*
* When you have a GhosttyTerminal, you can sync its modes (cursor key
* application, Kitty flags, etc.) into the encoder automatically:
*
* @code{.c}
* // Create a terminal and feed it some VT data that changes modes
* GhosttyTerminal terminal;
* ghostty_terminal_new(NULL, &terminal,
* (GhosttyTerminalOptions){.cols = 80, .rows = 24, .max_scrollback = 0});
*
* // Application might write data that enables Kitty keyboard protocol, etc.
* ghostty_terminal_vt_write(terminal, vt_data, vt_len);
*
* // Create an encoder and sync its options from the terminal
* GhosttyKeyEncoder encoder;
* ghostty_key_encoder_new(NULL, &encoder);
* ghostty_key_encoder_setopt_from_terminal(encoder, terminal);
*
* // Encode a key event using the terminal-derived options
* char buf[128];
* size_t written = 0;
* ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
*
* ghostty_key_encoder_free(encoder);
* ghostty_terminal_free(terminal);
* @endcode
*
* @{
*/
#include <ghostty/vt/key/event.h>
#include <ghostty/vt/key/encoder.h>
/** @} */
#endif /* GHOSTTY_VT_KEY_H */
+255
View File
@@ -0,0 +1,255 @@
/**
* @file encoder.h
*
* Key event encoding to terminal escape sequences.
*/
#ifndef GHOSTTY_VT_KEY_ENCODER_H
#define GHOSTTY_VT_KEY_ENCODER_H
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/terminal.h>
#include <ghostty/vt/key/event.h>
/**
* Opaque handle to a key encoder instance.
*
* This handle represents a key encoder that converts key events into terminal
* escape sequences.
*
* @ingroup key
*/
typedef struct GhosttyKeyEncoderImpl *GhosttyKeyEncoder;
/**
* Kitty keyboard protocol flags.
*
* Bitflags representing the various modes of the Kitty keyboard protocol.
* These can be combined using bitwise OR operations. Valid values all
* start with `GHOSTTY_KITTY_KEY_`.
*
* @ingroup key
*/
typedef uint8_t GhosttyKittyKeyFlags;
/** Kitty keyboard protocol disabled (all flags off) */
#define GHOSTTY_KITTY_KEY_DISABLED 0
/** Disambiguate escape codes */
#define GHOSTTY_KITTY_KEY_DISAMBIGUATE (1 << 0)
/** Report key press and release events */
#define GHOSTTY_KITTY_KEY_REPORT_EVENTS (1 << 1)
/** Report alternate key codes */
#define GHOSTTY_KITTY_KEY_REPORT_ALTERNATES (1 << 2)
/** Report all key events including those normally handled by the terminal */
#define GHOSTTY_KITTY_KEY_REPORT_ALL (1 << 3)
/** Report associated text with key events */
#define GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED (1 << 4)
/** All Kitty keyboard protocol flags enabled */
#define GHOSTTY_KITTY_KEY_ALL (GHOSTTY_KITTY_KEY_DISAMBIGUATE | GHOSTTY_KITTY_KEY_REPORT_EVENTS | GHOSTTY_KITTY_KEY_REPORT_ALTERNATES | GHOSTTY_KITTY_KEY_REPORT_ALL | GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED)
/**
* macOS option key behavior.
*
* Determines whether the "option" key on macOS is treated as "alt" or not.
* See the Ghostty `macos-option-as-alt` configuration option for more details.
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Option key is not treated as alt */
GHOSTTY_OPTION_AS_ALT_FALSE = 0,
/** Option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_TRUE = 1,
/** Only left option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_LEFT = 2,
/** Only right option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_RIGHT = 3,
GHOSTTY_OPTION_AS_ALT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOptionAsAlt;
/**
* Key encoder option identifiers.
*
* These values are used with ghostty_key_encoder_setopt() to configure
* the behavior of the key encoder.
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Terminal DEC mode 1: cursor key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_CURSOR_KEY_APPLICATION = 0,
/** Terminal DEC mode 66: keypad key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_KEYPAD_KEY_APPLICATION = 1,
/** Terminal DEC mode 1035: ignore keypad with numlock (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_IGNORE_KEYPAD_WITH_NUMLOCK = 2,
/** Terminal DEC mode 1036: alt sends escape prefix (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_ALT_ESC_PREFIX = 3,
/** xterm modifyOtherKeys mode 2 (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_MODIFY_OTHER_KEYS_STATE_2 = 4,
/** Kitty keyboard protocol flags (value: GhosttyKittyKeyFlags bitmask) */
GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS = 5,
/** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */
GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6,
/** Backarrow key mode (value: bool)
* See https://vt100.net/dec/ek-vt3xx-tp-002.pdf page 170
* If `false` (the default), `backspace` emits 0x7f
* If `true`, `backspace` emits 0x08
*/
GHOSTTY_KEY_ENCODER_OPT_BACKARROW_KEY_MODE = 7,
GHOSTTY_KEY_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKeyEncoderOption;
/**
* Create a new key encoder instance.
*
* Creates a new key encoder with default options. The encoder can be configured
* using ghostty_key_encoder_setopt() and must be freed using
* ghostty_key_encoder_free() when no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param encoder Pointer to store the created encoder handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup key
*/
GHOSTTY_API GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder);
/**
* Free a key encoder instance.
*
* Releases all resources associated with the key encoder. After this call,
* the encoder handle becomes invalid and must not be used.
*
* @param encoder The encoder handle to free (may be NULL)
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
/**
* Set an option on the key encoder.
*
* Configures the behavior of the key encoder. Options control various aspects
* of encoding such as terminal modes (cursor key application mode, keypad mode),
* protocol selection (Kitty keyboard protocol flags), and platform-specific
* behaviors (macOS option-as-alt).
*
* If you are using a terminal instance, you can set the key encoding
* options based on the active terminal state (e.g. legacy vs Kitty mode
* and associated flags) with ghostty_key_encoder_setopt_from_terminal().
*
* A null pointer value does nothing. It does not reset the value to the
* default. The setopt call will do nothing.
*
* @param encoder The encoder handle, must not be NULL
* @param option The option to set
* @param value Pointer to the value to set (type depends on the option)
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value);
/**
* Set encoder options from a terminal's current state.
*
* Reads the terminal's current modes and flags and applies them to the
* encoder's options. This sets cursor key application mode, keypad mode,
* alt escape prefix, modifyOtherKeys state, and Kitty keyboard protocol
* flags from the terminal state.
*
* Note that the `macos_option_as_alt` option cannot be determined from
* terminal state and is reset to `GHOSTTY_OPTION_AS_ALT_FALSE` by this
* call. Use ghostty_key_encoder_setopt() to set it afterward if needed.
*
* @param encoder The encoder handle, must not be NULL
* @param terminal The terminal handle, must not be NULL
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, GhosttyTerminal terminal);
/**
* Encode a key event into a terminal escape sequence.
*
* Converts a key event into the appropriate terminal escape sequence based on
* the encoder's current options. The sequence is written to the provided buffer.
*
* Not all key events produce output. For example, unmodified modifier keys
* typically don't generate escape sequences. Check the out_len parameter to
* determine if any data was written.
*
* If the output buffer is too small, this function returns GHOSTTY_OUT_OF_SPACE
* and out_len will contain the required buffer size. The caller can then
* allocate a larger buffer and call the function again.
*
* @param encoder The encoder handle, must not be NULL
* @param event The key event to encode, must not be NULL
* @param out_buf Buffer to write the encoded sequence to
* @param out_buf_size Size of the output buffer in bytes
* @param out_len Pointer to store the number of bytes written (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if buffer too small, or other error code
*
* ## Example: Calculate required buffer size
*
* @code{.c}
* // Query the required size with a NULL buffer (always returns OUT_OF_SPACE)
* size_t required = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
* assert(result == GHOSTTY_OUT_OF_SPACE);
*
* // Allocate buffer of required size
* char *buf = malloc(required);
*
* // Encode with properly sized buffer
* size_t written = 0;
* result = ghostty_key_encoder_encode(encoder, event, buf, required, &written);
* assert(result == GHOSTTY_SUCCESS);
*
* // Use the encoded sequence...
*
* free(buf);
* @endcode
*
* ## Example: Direct encoding with static buffer
*
* @code{.c}
* // Most escape sequences are short, so a static buffer often suffices
* char buf[128];
* size_t written = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
*
* if (result == GHOSTTY_SUCCESS) {
* // Write the encoded sequence to the terminal
* write(pty_fd, buf, written);
* } else if (result == GHOSTTY_OUT_OF_SPACE) {
* // Buffer too small, written contains required size
* char *dynamic_buf = malloc(written);
* result = ghostty_key_encoder_encode(encoder, event, dynamic_buf, written, &written);
* assert(result == GHOSTTY_SUCCESS);
* write(pty_fd, dynamic_buf, written);
* free(dynamic_buf);
* }
* @endcode
*
* @ingroup key
*/
GHOSTTY_API GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len);
#endif /* GHOSTTY_VT_KEY_ENCODER_H */
+482
View File
@@ -0,0 +1,482 @@
/**
* @file event.h
*
* Key event representation and manipulation.
*/
#ifndef GHOSTTY_VT_KEY_EVENT_H
#define GHOSTTY_VT_KEY_EVENT_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
/**
* Opaque handle to a key event.
*
* This handle represents a keyboard input event containing information about
* the physical key pressed, modifiers, and generated text.
*
* @ingroup key
*/
typedef struct GhosttyKeyEventImpl *GhosttyKeyEvent;
/**
* Keyboard input event types.
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Key was released */
GHOSTTY_KEY_ACTION_RELEASE = 0,
/** Key was pressed */
GHOSTTY_KEY_ACTION_PRESS = 1,
/** Key is being repeated (held down) */
GHOSTTY_KEY_ACTION_REPEAT = 2,
GHOSTTY_KEY_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKeyAction;
/**
* Keyboard modifier keys bitmask.
*
* A bitmask representing all keyboard modifiers. This tracks which modifier keys
* are pressed and, where supported by the platform, which side (left or right)
* of each modifier is active.
*
* Use the GHOSTTY_MODS_* constants to test and set individual modifiers.
*
* Modifier side bits are only meaningful when the corresponding modifier bit is set.
* Not all platforms support distinguishing between left and right modifier
* keys and Ghostty is built to expect that some platforms may not provide this
* information.
*
* @ingroup key
*/
typedef uint16_t GhosttyMods;
/** Shift key is pressed */
#define GHOSTTY_MODS_SHIFT (1 << 0)
/** Control key is pressed */
#define GHOSTTY_MODS_CTRL (1 << 1)
/** Alt/Option key is pressed */
#define GHOSTTY_MODS_ALT (1 << 2)
/** Super/Command/Windows key is pressed */
#define GHOSTTY_MODS_SUPER (1 << 3)
/** Caps Lock is active */
#define GHOSTTY_MODS_CAPS_LOCK (1 << 4)
/** Num Lock is active */
#define GHOSTTY_MODS_NUM_LOCK (1 << 5)
/**
* Right shift is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_SHIFT is set.
*/
#define GHOSTTY_MODS_SHIFT_SIDE (1 << 6)
/**
* Right ctrl is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_CTRL is set.
*/
#define GHOSTTY_MODS_CTRL_SIDE (1 << 7)
/**
* Right alt is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_ALT is set.
*/
#define GHOSTTY_MODS_ALT_SIDE (1 << 8)
/**
* Right super is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_SUPER is set.
*/
#define GHOSTTY_MODS_SUPER_SIDE (1 << 9)
/**
* Physical key codes.
*
* The set of key codes that Ghostty is aware of. These represent physical keys
* on the keyboard and are layout-independent. For example, the "a" key on a US
* keyboard is the same as the "ф" key on a Russian keyboard, but both will
* report the same key_a value.
*
* Layout-dependent strings are provided separately as UTF-8 text and are produced
* by the platform. These values are based on the W3C UI Events KeyboardEvent code
* standard. See: https://www.w3.org/TR/uievents-code
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_KEY_UNIDENTIFIED = 0,
// Writing System Keys (W3C § 3.1.1)
GHOSTTY_KEY_BACKQUOTE,
GHOSTTY_KEY_BACKSLASH,
GHOSTTY_KEY_BRACKET_LEFT,
GHOSTTY_KEY_BRACKET_RIGHT,
GHOSTTY_KEY_COMMA,
GHOSTTY_KEY_DIGIT_0,
GHOSTTY_KEY_DIGIT_1,
GHOSTTY_KEY_DIGIT_2,
GHOSTTY_KEY_DIGIT_3,
GHOSTTY_KEY_DIGIT_4,
GHOSTTY_KEY_DIGIT_5,
GHOSTTY_KEY_DIGIT_6,
GHOSTTY_KEY_DIGIT_7,
GHOSTTY_KEY_DIGIT_8,
GHOSTTY_KEY_DIGIT_9,
GHOSTTY_KEY_EQUAL,
GHOSTTY_KEY_INTL_BACKSLASH,
GHOSTTY_KEY_INTL_RO,
GHOSTTY_KEY_INTL_YEN,
GHOSTTY_KEY_A,
GHOSTTY_KEY_B,
GHOSTTY_KEY_C,
GHOSTTY_KEY_D,
GHOSTTY_KEY_E,
GHOSTTY_KEY_F,
GHOSTTY_KEY_G,
GHOSTTY_KEY_H,
GHOSTTY_KEY_I,
GHOSTTY_KEY_J,
GHOSTTY_KEY_K,
GHOSTTY_KEY_L,
GHOSTTY_KEY_M,
GHOSTTY_KEY_N,
GHOSTTY_KEY_O,
GHOSTTY_KEY_P,
GHOSTTY_KEY_Q,
GHOSTTY_KEY_R,
GHOSTTY_KEY_S,
GHOSTTY_KEY_T,
GHOSTTY_KEY_U,
GHOSTTY_KEY_V,
GHOSTTY_KEY_W,
GHOSTTY_KEY_X,
GHOSTTY_KEY_Y,
GHOSTTY_KEY_Z,
GHOSTTY_KEY_MINUS,
GHOSTTY_KEY_PERIOD,
GHOSTTY_KEY_QUOTE,
GHOSTTY_KEY_SEMICOLON,
GHOSTTY_KEY_SLASH,
// Functional Keys (W3C § 3.1.2)
GHOSTTY_KEY_ALT_LEFT,
GHOSTTY_KEY_ALT_RIGHT,
GHOSTTY_KEY_BACKSPACE,
GHOSTTY_KEY_CAPS_LOCK,
GHOSTTY_KEY_CONTEXT_MENU,
GHOSTTY_KEY_CONTROL_LEFT,
GHOSTTY_KEY_CONTROL_RIGHT,
GHOSTTY_KEY_ENTER,
GHOSTTY_KEY_META_LEFT,
GHOSTTY_KEY_META_RIGHT,
GHOSTTY_KEY_SHIFT_LEFT,
GHOSTTY_KEY_SHIFT_RIGHT,
GHOSTTY_KEY_SPACE,
GHOSTTY_KEY_TAB,
GHOSTTY_KEY_CONVERT,
GHOSTTY_KEY_KANA_MODE,
GHOSTTY_KEY_NON_CONVERT,
// Control Pad Section (W3C § 3.2)
GHOSTTY_KEY_DELETE,
GHOSTTY_KEY_END,
GHOSTTY_KEY_HELP,
GHOSTTY_KEY_HOME,
GHOSTTY_KEY_INSERT,
GHOSTTY_KEY_PAGE_DOWN,
GHOSTTY_KEY_PAGE_UP,
// Arrow Pad Section (W3C § 3.3)
GHOSTTY_KEY_ARROW_DOWN,
GHOSTTY_KEY_ARROW_LEFT,
GHOSTTY_KEY_ARROW_RIGHT,
GHOSTTY_KEY_ARROW_UP,
// Numpad Section (W3C § 3.4)
GHOSTTY_KEY_NUM_LOCK,
GHOSTTY_KEY_NUMPAD_0,
GHOSTTY_KEY_NUMPAD_1,
GHOSTTY_KEY_NUMPAD_2,
GHOSTTY_KEY_NUMPAD_3,
GHOSTTY_KEY_NUMPAD_4,
GHOSTTY_KEY_NUMPAD_5,
GHOSTTY_KEY_NUMPAD_6,
GHOSTTY_KEY_NUMPAD_7,
GHOSTTY_KEY_NUMPAD_8,
GHOSTTY_KEY_NUMPAD_9,
GHOSTTY_KEY_NUMPAD_ADD,
GHOSTTY_KEY_NUMPAD_BACKSPACE,
GHOSTTY_KEY_NUMPAD_CLEAR,
GHOSTTY_KEY_NUMPAD_CLEAR_ENTRY,
GHOSTTY_KEY_NUMPAD_COMMA,
GHOSTTY_KEY_NUMPAD_DECIMAL,
GHOSTTY_KEY_NUMPAD_DIVIDE,
GHOSTTY_KEY_NUMPAD_ENTER,
GHOSTTY_KEY_NUMPAD_EQUAL,
GHOSTTY_KEY_NUMPAD_MEMORY_ADD,
GHOSTTY_KEY_NUMPAD_MEMORY_CLEAR,
GHOSTTY_KEY_NUMPAD_MEMORY_RECALL,
GHOSTTY_KEY_NUMPAD_MEMORY_STORE,
GHOSTTY_KEY_NUMPAD_MEMORY_SUBTRACT,
GHOSTTY_KEY_NUMPAD_MULTIPLY,
GHOSTTY_KEY_NUMPAD_PAREN_LEFT,
GHOSTTY_KEY_NUMPAD_PAREN_RIGHT,
GHOSTTY_KEY_NUMPAD_SUBTRACT,
GHOSTTY_KEY_NUMPAD_SEPARATOR,
GHOSTTY_KEY_NUMPAD_UP,
GHOSTTY_KEY_NUMPAD_DOWN,
GHOSTTY_KEY_NUMPAD_RIGHT,
GHOSTTY_KEY_NUMPAD_LEFT,
GHOSTTY_KEY_NUMPAD_BEGIN,
GHOSTTY_KEY_NUMPAD_HOME,
GHOSTTY_KEY_NUMPAD_END,
GHOSTTY_KEY_NUMPAD_INSERT,
GHOSTTY_KEY_NUMPAD_DELETE,
GHOSTTY_KEY_NUMPAD_PAGE_UP,
GHOSTTY_KEY_NUMPAD_PAGE_DOWN,
// Function Section (W3C § 3.5)
GHOSTTY_KEY_ESCAPE,
GHOSTTY_KEY_F1,
GHOSTTY_KEY_F2,
GHOSTTY_KEY_F3,
GHOSTTY_KEY_F4,
GHOSTTY_KEY_F5,
GHOSTTY_KEY_F6,
GHOSTTY_KEY_F7,
GHOSTTY_KEY_F8,
GHOSTTY_KEY_F9,
GHOSTTY_KEY_F10,
GHOSTTY_KEY_F11,
GHOSTTY_KEY_F12,
GHOSTTY_KEY_F13,
GHOSTTY_KEY_F14,
GHOSTTY_KEY_F15,
GHOSTTY_KEY_F16,
GHOSTTY_KEY_F17,
GHOSTTY_KEY_F18,
GHOSTTY_KEY_F19,
GHOSTTY_KEY_F20,
GHOSTTY_KEY_F21,
GHOSTTY_KEY_F22,
GHOSTTY_KEY_F23,
GHOSTTY_KEY_F24,
GHOSTTY_KEY_F25,
GHOSTTY_KEY_FN,
GHOSTTY_KEY_FN_LOCK,
GHOSTTY_KEY_PRINT_SCREEN,
GHOSTTY_KEY_SCROLL_LOCK,
GHOSTTY_KEY_PAUSE,
// Media Keys (W3C § 3.6)
GHOSTTY_KEY_BROWSER_BACK,
GHOSTTY_KEY_BROWSER_FAVORITES,
GHOSTTY_KEY_BROWSER_FORWARD,
GHOSTTY_KEY_BROWSER_HOME,
GHOSTTY_KEY_BROWSER_REFRESH,
GHOSTTY_KEY_BROWSER_SEARCH,
GHOSTTY_KEY_BROWSER_STOP,
GHOSTTY_KEY_EJECT,
GHOSTTY_KEY_LAUNCH_APP_1,
GHOSTTY_KEY_LAUNCH_APP_2,
GHOSTTY_KEY_LAUNCH_MAIL,
GHOSTTY_KEY_MEDIA_PLAY_PAUSE,
GHOSTTY_KEY_MEDIA_SELECT,
GHOSTTY_KEY_MEDIA_STOP,
GHOSTTY_KEY_MEDIA_TRACK_NEXT,
GHOSTTY_KEY_MEDIA_TRACK_PREVIOUS,
GHOSTTY_KEY_POWER,
GHOSTTY_KEY_SLEEP,
GHOSTTY_KEY_AUDIO_VOLUME_DOWN,
GHOSTTY_KEY_AUDIO_VOLUME_MUTE,
GHOSTTY_KEY_AUDIO_VOLUME_UP,
GHOSTTY_KEY_WAKE_UP,
// Legacy, Non-standard, and Special Keys (W3C § 3.7)
GHOSTTY_KEY_COPY,
GHOSTTY_KEY_CUT,
GHOSTTY_KEY_PASTE,
GHOSTTY_KEY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKey;
/**
* Create a new key event instance.
*
* Creates a new key event with default values. The event must be freed using
* ghostty_key_event_free() when no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param event Pointer to store the created key event handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup key
*/
GHOSTTY_API GhosttyResult ghostty_key_event_new(const GhosttyAllocator *allocator, GhosttyKeyEvent *event);
/**
* Free a key event instance.
*
* Releases all resources associated with the key event. After this call,
* the event handle becomes invalid and must not be used.
*
* @param event The key event handle to free (may be NULL)
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_free(GhosttyKeyEvent event);
/**
* Set the key action (press, release, repeat).
*
* @param event The key event handle, must not be NULL
* @param action The action to set
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_action(GhosttyKeyEvent event, GhosttyKeyAction action);
/**
* Get the key action (press, release, repeat).
*
* @param event The key event handle, must not be NULL
* @return The key action
*
* @ingroup key
*/
GHOSTTY_API GhosttyKeyAction ghostty_key_event_get_action(GhosttyKeyEvent event);
/**
* Set the physical key code.
*
* @param event The key event handle, must not be NULL
* @param key The physical key code to set
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_key(GhosttyKeyEvent event, GhosttyKey key);
/**
* Get the physical key code.
*
* @param event The key event handle, must not be NULL
* @return The physical key code
*
* @ingroup key
*/
GHOSTTY_API GhosttyKey ghostty_key_event_get_key(GhosttyKeyEvent event);
/**
* Set the modifier keys bitmask.
*
* @param event The key event handle, must not be NULL
* @param mods The modifier keys bitmask to set
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_mods(GhosttyKeyEvent event, GhosttyMods mods);
/**
* Get the modifier keys bitmask.
*
* @param event The key event handle, must not be NULL
* @return The modifier keys bitmask
*
* @ingroup key
*/
GHOSTTY_API GhosttyMods ghostty_key_event_get_mods(GhosttyKeyEvent event);
/**
* Set the consumed modifiers bitmask.
*
* @param event The key event handle, must not be NULL
* @param consumed_mods The consumed modifiers bitmask to set
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_consumed_mods(GhosttyKeyEvent event, GhosttyMods consumed_mods);
/**
* Get the consumed modifiers bitmask.
*
* @param event The key event handle, must not be NULL
* @return The consumed modifiers bitmask
*
* @ingroup key
*/
GHOSTTY_API GhosttyMods ghostty_key_event_get_consumed_mods(GhosttyKeyEvent event);
/**
* Set whether the key event is part of a composition sequence.
*
* @param event The key event handle, must not be NULL
* @param composing Whether the key event is part of a composition sequence
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_composing(GhosttyKeyEvent event, bool composing);
/**
* Get whether the key event is part of a composition sequence.
*
* @param event The key event handle, must not be NULL
* @return Whether the key event is part of a composition sequence
*
* @ingroup key
*/
GHOSTTY_API bool ghostty_key_event_get_composing(GhosttyKeyEvent event);
/**
* Set the UTF-8 text generated by the key for the current keyboard layout.
*
* Must contain the unmodified character before any Ctrl/Meta transformations.
* The encoder derives modifier sequences from the logical key and mods
* bitmask, not from this text. Do not pass C0 control characters
* (U+0000-U+001F, U+007F) or platform function key codes (e.g. macOS PUA
* U+F700-U+F8FF); pass NULL instead and let the encoder use the logical key.
*
* The key event does NOT take ownership of the text pointer. The caller
* must ensure the string remains valid for the lifetime needed by the event.
*
* @param event The key event handle, must not be NULL
* @param utf8 The UTF-8 text to set (or NULL for empty)
* @param len Length of the UTF-8 text in bytes
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_utf8(GhosttyKeyEvent event, const char *utf8, size_t len);
/**
* Get the UTF-8 text generated by the key event.
*
* The returned pointer is valid until the event is freed or the UTF-8 text is modified.
*
* @param event The key event handle, must not be NULL
* @param len Pointer to store the length of the UTF-8 text in bytes (may be NULL)
* @return The UTF-8 text (or NULL for empty)
*
* @ingroup key
*/
GHOSTTY_API const char *ghostty_key_event_get_utf8(GhosttyKeyEvent event, size_t *len);
/**
* Set the unshifted Unicode codepoint.
*
* @param event The key event handle, must not be NULL
* @param codepoint The unshifted Unicode codepoint to set
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_event_set_unshifted_codepoint(GhosttyKeyEvent event, uint32_t codepoint);
/**
* Get the unshifted Unicode codepoint.
*
* @param event The key event handle, must not be NULL
* @return The unshifted Unicode codepoint
*
* @ingroup key
*/
GHOSTTY_API uint32_t ghostty_key_event_get_unshifted_codepoint(GhosttyKeyEvent event);
#endif /* GHOSTTY_VT_KEY_EVENT_H */
+859
View File
@@ -0,0 +1,859 @@
/**
* @file kitty_graphics.h
*
* Kitty graphics protocol
*
* See @ref kitty_graphics for a full usage guide.
*/
#ifndef GHOSTTY_VT_KITTY_GRAPHICS_H
#define GHOSTTY_VT_KITTY_GRAPHICS_H
#include <stdbool.h>
#include <stdint.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/selection.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup kitty_graphics Kitty Graphics
*
* API for inspecting images and placements stored via the
* [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/).
*
* The central object is @ref GhosttyKittyGraphics, an opaque handle to
* the image storage associated with a terminal's active screen. From it
* you can iterate over placements and look up individual images.
*
* ## Obtaining a KittyGraphics Handle
*
* A @ref GhosttyKittyGraphics handle is obtained from a terminal via
* ghostty_terminal_get() with @ref GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS.
* The handle is borrowed from the terminal and remains valid until the
* next mutating terminal call (e.g. ghostty_terminal_vt_write() or
* ghostty_terminal_reset()).
*
* Before images can be stored, Kitty graphics must be enabled on the
* terminal by setting a non-zero storage limit with
* @ref GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT, and a PNG
* decoder callback must be installed via ghostty_sys_set() with
* @ref GHOSTTY_SYS_OPT_DECODE_PNG.
*
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-decode-png
*
* ## Iterating Placements
*
* Placements are inspected through a @ref GhosttyKittyGraphicsPlacementIterator.
* The typical workflow is:
*
* 1. Create an iterator with ghostty_kitty_graphics_placement_iterator_new().
* 2. Populate it from the storage with ghostty_kitty_graphics_get() using
* @ref GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR.
* 3. Optionally filter by z-layer with
* ghostty_kitty_graphics_placement_iterator_set().
* 4. Advance with ghostty_kitty_graphics_placement_next() and read
* per-placement data with ghostty_kitty_graphics_placement_get().
* 5. For each placement, look up its image with
* ghostty_kitty_graphics_image() to access pixel data and dimensions.
* 6. Free the iterator with ghostty_kitty_graphics_placement_iterator_free().
*
* ## Looking Up Images
*
* Given an image ID (obtained from a placement via
* @ref GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID), call
* ghostty_kitty_graphics_image() to get a @ref GhosttyKittyGraphicsImage
* handle. From this handle, ghostty_kitty_graphics_image_get() provides
* the image dimensions, pixel format, compression, and a borrowed pointer
* to the raw pixel data.
*
* ## Rendering Helpers
*
* Several functions assist with rendering a placement:
*
* - ghostty_kitty_graphics_placement_pixel_size() — rendered pixel
* dimensions accounting for source rect and aspect ratio.
* - ghostty_kitty_graphics_placement_grid_size() — number of grid
* columns and rows the placement occupies.
* - ghostty_kitty_graphics_placement_viewport_pos() — viewport-relative
* grid position (may be negative for partially scrolled placements).
* - ghostty_kitty_graphics_placement_source_rect() — resolved source
* rectangle in pixels, clamped to image bounds.
* - ghostty_kitty_graphics_placement_rect() — bounding rectangle as a
* @ref GhosttySelection.
*
* ## Change Detection
*
* Generation stamps allow renderers to cheaply detect whether Kitty
* graphics state changed between frames:
*
* - @ref GHOSTTY_KITTY_GRAPHICS_DATA_GENERATION is a storage-wide stamp
* updated on any transmit, placement, or delete. If unchanged, the
* placement set and all image data are identical and both placement
* snapshots and per-image staleness checks can be skipped. Placement
* geometry can still change independently (scrolling moves
* placements), so ghostty_kitty_graphics_placement_render_info()
* should still be recomputed on dirty frames.
* - @ref GHOSTTY_KITTY_IMAGE_DATA_GENERATION is a per-image stamp
* changed on every add/replace of that image ID. Texture caches
* should treat a cached texture as stale when this differs from the
* cached value; dimension/length heuristics cannot detect a
* same-sized retransmission.
*
* Stamps are unique and monotonically increasing process-wide, so
* caches keyed on a generation value never alias across screens
* (main/alternate), resets, or terminals.
*
* ## Lifetime and Thread Safety
*
* All handles borrowed from the terminal (GhosttyKittyGraphics,
* GhosttyKittyGraphicsImage) are invalidated by any mutating terminal
* call. The placement iterator is independently owned and must be freed
* by the caller, but the data it yields is only valid while the
* underlying terminal is not mutated.
*
* ## Example
*
* The following example creates a terminal, sends a Kitty graphics
* image, then iterates placements and prints image metadata:
*
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-main
*
* @{
*/
/**
* Queryable data kinds for ghostty_kitty_graphics_get().
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_KITTY_GRAPHICS_DATA_INVALID = 0,
/**
* Populate a pre-allocated placement iterator with placement data from
* the storage. Iterator data is only valid as long as the underlying
* terminal is not mutated.
*
* Output type: GhosttyKittyGraphicsPlacementIterator *
*/
GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR = 1,
/**
* Generation stamp of the last content mutation to this storage:
* any image transmit/replace, placement add, or delete. Zero means
* the storage has never been mutated (and is therefore empty).
*
* If the generation is unchanged since a previous query, the set of
* placements and all image data are identical, so placement iteration
* and image staleness checks can be skipped entirely. Note that
* placement *geometry* may still have changed (scrolling and resizing
* move placements without changing the storage contents), so rendering
* geometry such as ghostty_kitty_graphics_placement_render_info()
* must still be recomputed for frames marked dirty.
*
* Stamps are unique and monotonically increasing process-wide: a
* value observed from any storage never recurs for different content,
* even across screen switches (main vs. alternate screen have
* independent storages) or terminal resets. It is therefore safe to
* key caches on this value alone.
*
* Output type: uint64_t *
*/
GHOSTTY_KITTY_GRAPHICS_DATA_GENERATION = 2,
GHOSTTY_KITTY_GRAPHICS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsData;
/**
* Queryable data kinds for ghostty_kitty_graphics_placement_get().
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INVALID = 0,
/**
* The image ID this placement belongs to.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID = 1,
/**
* The placement ID.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID = 2,
/**
* Whether this is a virtual placement (unicode placeholder).
*
* Output type: bool *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL = 3,
/**
* Pixel offset from the left edge of the cell.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET = 4,
/**
* Pixel offset from the top edge of the cell.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET = 5,
/**
* Source rectangle x origin in pixels.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X = 6,
/**
* Source rectangle y origin in pixels.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y = 7,
/**
* Source rectangle width in pixels (0 = full image width).
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH = 8,
/**
* Source rectangle height in pixels (0 = full image height).
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT = 9,
/**
* Number of columns this placement occupies.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS = 10,
/**
* Number of rows this placement occupies.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_ROWS = 11,
/**
* Z-index for this placement.
*
* Output type: int32_t *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsPlacementData;
/**
* Z-layer classification for kitty graphics placements.
*
* Based on the kitty protocol z-index conventions:
* - BELOW_BG: z < INT32_MIN/2 (drawn below cell background)
* - BELOW_TEXT: INT32_MIN/2 <= z < 0 (above background, below text)
* - ABOVE_TEXT: z >= 0 (above text)
* - ALL: no filtering (current behavior)
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_KITTY_PLACEMENT_LAYER_ALL = 0,
GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_BG = 1,
GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_TEXT = 2,
GHOSTTY_KITTY_PLACEMENT_LAYER_ABOVE_TEXT = 3,
GHOSTTY_KITTY_PLACEMENT_LAYER_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyPlacementLayer;
/**
* Settable options for ghostty_kitty_graphics_placement_iterator_set().
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
/**
* Set the z-layer filter for the iterator.
*
* Input type: GhosttyKittyPlacementLayer *
*/
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_LAYER = 0,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsPlacementIteratorOption;
/**
* Pixel format of a Kitty graphics image.
*
* Note that stored images are always fully decoded:
* GHOSTTY_KITTY_IMAGE_FORMAT_PNG is never returned by
* ghostty_kitty_graphics_image_get() because PNG payloads are decoded
* to GHOSTTY_KITTY_IMAGE_FORMAT_RGBA before storage. The PNG value
* exists only for protocol-level completeness.
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_KITTY_IMAGE_FORMAT_RGB = 0,
GHOSTTY_KITTY_IMAGE_FORMAT_RGBA = 1,
GHOSTTY_KITTY_IMAGE_FORMAT_PNG = 2,
GHOSTTY_KITTY_IMAGE_FORMAT_GRAY_ALPHA = 3,
GHOSTTY_KITTY_IMAGE_FORMAT_GRAY = 4,
GHOSTTY_KITTY_IMAGE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyImageFormat;
/**
* Compression of a Kitty graphics image.
*
* Note that stored images are always decompressed:
* GHOSTTY_KITTY_IMAGE_COMPRESSION_ZLIB_DEFLATE payloads are inflated
* before storage, so ghostty_kitty_graphics_image_get() always reports
* GHOSTTY_KITTY_IMAGE_COMPRESSION_NONE. Consumers never need to
* inflate image data themselves.
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_KITTY_IMAGE_COMPRESSION_NONE = 0,
GHOSTTY_KITTY_IMAGE_COMPRESSION_ZLIB_DEFLATE = 1,
GHOSTTY_KITTY_IMAGE_COMPRESSION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyImageCompression;
/**
* Queryable data kinds for ghostty_kitty_graphics_image_get().
*
* @ingroup kitty_graphics
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_KITTY_IMAGE_DATA_INVALID = 0,
/**
* The image ID.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_ID = 1,
/**
* The image number.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_NUMBER = 2,
/**
* Image width in pixels.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_WIDTH = 3,
/**
* Image height in pixels.
*
* Output type: uint32_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_HEIGHT = 4,
/**
* Pixel format of the image. Never GHOSTTY_KITTY_IMAGE_FORMAT_PNG;
* PNG payloads are decoded to RGBA before storage.
*
* Output type: GhosttyKittyImageFormat *
*/
GHOSTTY_KITTY_IMAGE_DATA_FORMAT = 5,
/**
* Compression of the image. Always
* GHOSTTY_KITTY_IMAGE_COMPRESSION_NONE; compressed payloads are
* inflated before storage.
*
* Output type: GhosttyKittyImageCompression *
*/
GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION = 6,
/**
* Borrowed pointer to the raw pixel data. Valid as long as the
* underlying terminal is not mutated.
*
* The data is always fully decoded, uncompressed pixels in the
* format reported by GHOSTTY_KITTY_IMAGE_DATA_FORMAT: zlib payloads
* are inflated and PNG payloads are decoded to RGBA at transmission
* time, before the image is stored. Consumers can upload this
* directly to the GPU without any decode step.
*
* Output type: const uint8_t **
*/
GHOSTTY_KITTY_IMAGE_DATA_DATA_PTR = 7,
/**
* Length of the raw pixel data in bytes. Always equal to
* width * height * bytes-per-pixel for the reported format.
*
* Output type: size_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN = 8,
/**
* Generation stamp assigned when this image was added to (or
* replaced in) the storage. A changed generation for a given image
* ID means the pixel contents may have changed even when the
* dimensions, format, and data length are identical (e.g. a
* retransmission of the same image ID), so texture caches must key
* staleness on this value rather than on size heuristics.
*
* Stamps are unique and monotonically increasing process-wide and
* are drawn from the same sequence as
* GHOSTTY_KITTY_GRAPHICS_DATA_GENERATION. Never zero for a stored
* image, so zero can be used as an "empty" sentinel by callers.
*
* Output type: uint64_t *
*/
GHOSTTY_KITTY_IMAGE_DATA_GENERATION = 9,
GHOSTTY_KITTY_IMAGE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKittyGraphicsImageData;
/**
* Combined rendering geometry for a placement in a single sized struct.
*
* Combines the results of ghostty_kitty_graphics_placement_pixel_size(),
* ghostty_kitty_graphics_placement_grid_size(),
* ghostty_kitty_graphics_placement_viewport_pos(), and
* ghostty_kitty_graphics_placement_source_rect() into one call. This is
* an optimization over calling those four functions individually,
* particularly useful in environments with high per-call overhead such
* as FFI or Cgo.
*
* This struct uses the sized-struct ABI pattern. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementRenderInfo) before calling
* ghostty_kitty_graphics_placement_render_info().
*
* @ingroup kitty_graphics
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsPlacementRenderInfo). */
size_t size;
/** Rendered width in pixels. */
uint32_t pixel_width;
/** Rendered height in pixels. */
uint32_t pixel_height;
/** Number of grid columns the placement occupies. */
uint32_t grid_cols;
/** Number of grid rows the placement occupies. */
uint32_t grid_rows;
/** Viewport-relative column (may be negative for partially visible placements). */
int32_t viewport_col;
/** Viewport-relative row (may be negative for partially visible placements). */
int32_t viewport_row;
/** False when the placement is fully off-screen or virtual. */
bool viewport_visible;
/** Resolved source rectangle x origin in pixels. */
uint32_t source_x;
/** Resolved source rectangle y origin in pixels. */
uint32_t source_y;
/** Resolved source rectangle width in pixels. */
uint32_t source_width;
/** Resolved source rectangle height in pixels. */
uint32_t source_height;
} GhosttyKittyGraphicsPlacementRenderInfo;
/**
* Get data from a kitty graphics storage instance.
*
* The output pointer must be of the appropriate type for the requested
* data kind.
*
* Returns GHOSTTY_NO_VALUE when Kitty graphics are disabled at build time.
*
* @param graphics The kitty graphics handle
* @param data The type of data to extract
* @param[out] out Pointer to store the extracted data
* @return GHOSTTY_SUCCESS on success
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_get(
GhosttyKittyGraphics graphics,
GhosttyKittyGraphicsData data,
void* out);
/**
* Look up a Kitty graphics image by its image ID.
*
* Returns NULL if no image with the given ID exists or if Kitty graphics
* are disabled at build time.
*
* @param graphics The kitty graphics handle
* @param image_id The image ID to look up
* @return An opaque image handle, or NULL if not found
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyKittyGraphicsImage ghostty_kitty_graphics_image(
GhosttyKittyGraphics graphics,
uint32_t image_id);
/**
* Get data from a Kitty graphics image.
*
* The output pointer must be of the appropriate type for the requested
* data kind.
*
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param data The data kind to query
* @param[out] out Pointer to receive the queried value
* @return GHOSTTY_SUCCESS on success
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get(
GhosttyKittyGraphicsImage image,
GhosttyKittyGraphicsImageData data,
void* out);
/**
* Get multiple data fields from a Kitty graphics image in a single call.
*
* This is an optimization over calling ghostty_kitty_graphics_image_get()
* repeatedly, particularly useful in environments with high per-call
* overhead such as FFI or Cgo.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
* The type of each values[i] pointer must match the output type
* documented for keys[i].
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get_multi(
GhosttyKittyGraphicsImage image,
size_t count,
const GhosttyKittyGraphicsImageData* keys,
void** values,
size_t* out_written);
/**
* Create a new placement iterator instance.
*
* All fields except the allocator are left undefined until populated
* via ghostty_kitty_graphics_get() with
* GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param[out] out_iterator On success, receives the created iterator handle
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
* failure
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_iterator_new(
const GhosttyAllocator* allocator,
GhosttyKittyGraphicsPlacementIterator* out_iterator);
/**
* Free a placement iterator.
*
* @param iterator The iterator handle to free (may be NULL)
*
* @ingroup kitty_graphics
*/
GHOSTTY_API void ghostty_kitty_graphics_placement_iterator_free(
GhosttyKittyGraphicsPlacementIterator iterator);
/**
* Set an option on a placement iterator.
*
* Use GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_LAYER with a
* GhosttyKittyPlacementLayer value to filter placements by z-layer.
* The filter is applied during iteration: ghostty_kitty_graphics_placement_next()
* will skip placements that do not match the configured layer.
*
* The default layer is GHOSTTY_KITTY_PLACEMENT_LAYER_ALL (no filtering).
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param option The option to set
* @param value Pointer to the value (type depends on option; NULL returns
* GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_iterator_set(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsPlacementIteratorOption option,
const void* value);
/**
* Advance the placement iterator to the next placement.
*
* If a layer filter has been set via
* ghostty_kitty_graphics_placement_iterator_set(), only placements
* matching that layer are returned.
*
* @param iterator The iterator handle (may be NULL)
* @return true if advanced to the next placement, false if at the end
*
* @ingroup kitty_graphics
*/
GHOSTTY_API bool ghostty_kitty_graphics_placement_next(
GhosttyKittyGraphicsPlacementIterator iterator);
/**
* Get data from the current placement in a placement iterator.
*
* Call ghostty_kitty_graphics_placement_next() at least once before
* calling this function.
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param data The data kind to query
* @param[out] out Pointer to receive the queried value
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
* iterator is NULL or not positioned on a placement
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsPlacementData data,
void* out);
/**
* Get multiple data fields from the current placement in a single call.
*
* This is an optimization over calling ghostty_kitty_graphics_placement_get()
* repeatedly, particularly useful in environments with high per-call
* overhead such as FFI or Cgo.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
* The type of each values[i] pointer must match the output type
* documented for keys[i].
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get_multi(
GhosttyKittyGraphicsPlacementIterator iterator,
size_t count,
const GhosttyKittyGraphicsPlacementData* keys,
void** values,
size_t* out_written);
/**
* Compute the grid rectangle occupied by the current placement.
*
* Uses the placement's pin, the image dimensions, and the terminal's
* cell/pixel geometry to calculate the bounding rectangle. Virtual
* placements (unicode placeholders) return GHOSTTY_NO_VALUE.
*
* @param terminal The terminal handle
* @param image The image handle for this placement's image
* @param iterator The placement iterator positioned on a placement
* @param[out] out_selection On success, receives the bounding rectangle
* as a selection with rectangle=true
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE for
* virtual placements or when Kitty graphics are disabled
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_rect(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
GhosttyTerminal terminal,
GhosttySelection* out_selection);
/**
* Compute the rendered pixel size of the current placement.
*
* Takes into account the placement's source rectangle, specified
* columns/rows, and aspect ratio to calculate the final rendered
* pixel dimensions.
*
* @param iterator The placement iterator positioned on a placement
* @param image The image handle for this placement's image
* @param terminal The terminal handle
* @param[out] out_width On success, receives the width in pixels
* @param[out] out_height On success, receives the height in pixels
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE when
* Kitty graphics are disabled
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_pixel_size(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
GhosttyTerminal terminal,
uint32_t* out_width,
uint32_t* out_height);
/**
* Compute the grid cell size of the current placement.
*
* Returns the number of columns and rows that the placement occupies
* in the terminal grid. If the placement specifies explicit columns
* and rows, those are returned directly; otherwise they are calculated
* from the pixel size and cell dimensions.
*
* @param iterator The placement iterator positioned on a placement
* @param image The image handle for this placement's image
* @param terminal The terminal handle
* @param[out] out_cols On success, receives the number of columns
* @param[out] out_rows On success, receives the number of rows
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE when
* Kitty graphics are disabled
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_grid_size(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
GhosttyTerminal terminal,
uint32_t* out_cols,
uint32_t* out_rows);
/**
* Get the viewport-relative grid position of the current placement.
*
* Converts the placement's internal pin to viewport-relative column and
* row coordinates. The returned coordinates represent the top-left
* corner of the placement in the viewport's grid coordinate space.
*
* The row value can be negative when the placement's origin has
* scrolled above the top of the viewport. For example, a 4-row
* image that has scrolled up by 2 rows returns row=-2, meaning
* its top 2 rows are above the visible area but its bottom 2 rows
* are still on screen. Embedders should use these coordinates
* directly when computing the destination rectangle for rendering;
* the embedder is responsible for clipping the portion of the image
* that falls outside the viewport.
*
* Returns GHOSTTY_SUCCESS for any placement that is at least
* partially visible in the viewport. Returns GHOSTTY_NO_VALUE when
* the placement is completely outside the viewport (its bottom edge
* is above the viewport or its top edge is at or below the last
* viewport row), or when the placement is a virtual (unicode
* placeholder) placement.
*
* @param iterator The placement iterator positioned on a placement
* @param image The image handle for this placement's image
* @param terminal The terminal handle
* @param[out] out_col On success, receives the viewport-relative column
* @param[out] out_row On success, receives the viewport-relative row
* (may be negative for partially visible placements)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if fully
* off-screen or virtual, GHOSTTY_INVALID_VALUE if any handle
* is NULL or the iterator is not positioned
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_viewport_pos(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
GhosttyTerminal terminal,
int32_t* out_col,
int32_t* out_row);
/**
* Get the resolved source rectangle for the current placement.
*
* Applies kitty protocol semantics: a width or height of 0 in the
* placement means "use the full image dimension", and the resulting
* rectangle is clamped to the actual image bounds. The returned
* values are in pixels and are ready to use for texture sampling.
*
* @param iterator The placement iterator positioned on a placement
* @param image The image handle for this placement's image
* @param[out] out_x Source rect x origin in pixels
* @param[out] out_y Source rect y origin in pixels
* @param[out] out_width Source rect width in pixels
* @param[out] out_height Source rect height in pixels
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any
* handle is NULL or the iterator is not positioned
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_source_rect(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
uint32_t* out_x,
uint32_t* out_y,
uint32_t* out_width,
uint32_t* out_height);
/**
* Get all rendering geometry for a placement in a single call.
*
* Combines pixel size, grid size, viewport position, and source
* rectangle into one struct. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementRenderInfo).
*
* When viewport_visible is false, the placement is fully off-screen
* or is a virtual placement; viewport_col and viewport_row may
* contain meaningless values in that case.
*
* @param iterator The iterator positioned on a placement
* @param image The image handle for this placement's image
* @param terminal The terminal handle
* @param[out] out_info Pointer to receive the rendering geometry
* @return GHOSTTY_SUCCESS on success
*
* @ingroup kitty_graphics
*/
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_render_info(
GhosttyKittyGraphicsPlacementIterator iterator,
GhosttyKittyGraphicsImage image,
GhosttyTerminal terminal,
GhosttyKittyGraphicsPlacementRenderInfo* out_info);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_KITTY_GRAPHICS_H */
+198
View File
@@ -0,0 +1,198 @@
/**
* @file modes.h
*
* Terminal mode utilities - pack and unpack ANSI/DEC mode identifiers.
*/
#ifndef GHOSTTY_VT_MODES_H
#define GHOSTTY_VT_MODES_H
/** @defgroup modes Mode Utilities
*
* Utilities for working with terminal modes. A mode is a compact
* 16-bit representation of a terminal mode identifier that encodes both
* the numeric mode value (up to 15 bits) and whether the mode is an ANSI
* mode or a DEC private mode (?-prefixed).
*
* The packed layout (least-significant bit first) is:
* - Bits 014: mode value (u15)
* - Bit 15: ANSI flag (0 = DEC private mode, 1 = ANSI mode)
*
* ## Example
*
* @snippet c-vt-modes/src/main.c modes-pack-unpack
*
* ## DECRPM Report Encoding
*
* Use ghostty_mode_report_encode() to encode a DECRPM response into a
* caller-provided buffer:
*
* @snippet c-vt-modes/src/main.c modes-decrpm
*
* @{
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @name ANSI Modes
* Modes for standard ANSI modes.
* @{
*/
#define GHOSTTY_MODE_KAM (ghostty_mode_new(2, true)) /**< Keyboard action (disable keyboard) */
#define GHOSTTY_MODE_INSERT (ghostty_mode_new(4, true)) /**< Insert mode */
#define GHOSTTY_MODE_SRM (ghostty_mode_new(12, true)) /**< Send/receive mode */
#define GHOSTTY_MODE_LINEFEED (ghostty_mode_new(20, true)) /**< Linefeed/new line mode */
/** @} */
/** @name DEC Private Modes
* Modes for DEC private modes (?-prefixed).
* @{
*/
#define GHOSTTY_MODE_DECCKM (ghostty_mode_new(1, false)) /**< Cursor keys */
#define GHOSTTY_MODE_132_COLUMN (ghostty_mode_new(3, false)) /**< 132/80 column mode */
#define GHOSTTY_MODE_SLOW_SCROLL (ghostty_mode_new(4, false)) /**< Slow scroll */
#define GHOSTTY_MODE_REVERSE_COLORS (ghostty_mode_new(5, false)) /**< Reverse video */
#define GHOSTTY_MODE_ORIGIN (ghostty_mode_new(6, false)) /**< Origin mode */
#define GHOSTTY_MODE_WRAPAROUND (ghostty_mode_new(7, false)) /**< Auto-wrap mode */
#define GHOSTTY_MODE_AUTOREPEAT (ghostty_mode_new(8, false)) /**< Auto-repeat keys */
#define GHOSTTY_MODE_X10_MOUSE (ghostty_mode_new(9, false)) /**< X10 mouse reporting */
#define GHOSTTY_MODE_CURSOR_BLINKING (ghostty_mode_new(12, false)) /**< Cursor blink */
#define GHOSTTY_MODE_CURSOR_VISIBLE (ghostty_mode_new(25, false)) /**< Cursor visible (DECTCEM) */
#define GHOSTTY_MODE_ENABLE_MODE_3 (ghostty_mode_new(40, false)) /**< Allow 132 column mode */
#define GHOSTTY_MODE_REVERSE_WRAP (ghostty_mode_new(45, false)) /**< Reverse wrap */
#define GHOSTTY_MODE_ALT_SCREEN_LEGACY (ghostty_mode_new(47, false)) /**< Alternate screen (legacy) */
#define GHOSTTY_MODE_KEYPAD_KEYS (ghostty_mode_new(66, false)) /**< Application keypad */
#define GHOSTTY_MODE_BACKARROW_KEY_MODE (ghostty_mode_new(67, false)) /**< Backarrow key mode (DECBKM) */
#define GHOSTTY_MODE_LEFT_RIGHT_MARGIN (ghostty_mode_new(69, false)) /**< Left/right margin mode */
#define GHOSTTY_MODE_NORMAL_MOUSE (ghostty_mode_new(1000, false)) /**< Normal mouse tracking */
#define GHOSTTY_MODE_BUTTON_MOUSE (ghostty_mode_new(1002, false)) /**< Button-event mouse tracking */
#define GHOSTTY_MODE_ANY_MOUSE (ghostty_mode_new(1003, false)) /**< Any-event mouse tracking */
#define GHOSTTY_MODE_FOCUS_EVENT (ghostty_mode_new(1004, false)) /**< Focus in/out events */
#define GHOSTTY_MODE_UTF8_MOUSE (ghostty_mode_new(1005, false)) /**< UTF-8 mouse format */
#define GHOSTTY_MODE_SGR_MOUSE (ghostty_mode_new(1006, false)) /**< SGR mouse format */
#define GHOSTTY_MODE_ALT_SCROLL (ghostty_mode_new(1007, false)) /**< Alternate scroll mode */
#define GHOSTTY_MODE_URXVT_MOUSE (ghostty_mode_new(1015, false)) /**< URxvt mouse format */
#define GHOSTTY_MODE_SGR_PIXELS_MOUSE (ghostty_mode_new(1016, false)) /**< SGR-Pixels mouse format */
#define GHOSTTY_MODE_NUMLOCK_KEYPAD (ghostty_mode_new(1035, false)) /**< Ignore keypad with NumLock */
#define GHOSTTY_MODE_ALT_ESC_PREFIX (ghostty_mode_new(1036, false)) /**< Alt key sends ESC prefix */
#define GHOSTTY_MODE_ALT_SENDS_ESC (ghostty_mode_new(1039, false)) /**< Alt sends escape */
#define GHOSTTY_MODE_REVERSE_WRAP_EXT (ghostty_mode_new(1045, false)) /**< Extended reverse wrap */
#define GHOSTTY_MODE_ALT_SCREEN (ghostty_mode_new(1047, false)) /**< Alternate screen */
#define GHOSTTY_MODE_SAVE_CURSOR (ghostty_mode_new(1048, false)) /**< Save cursor (DECSC) */
#define GHOSTTY_MODE_ALT_SCREEN_SAVE (ghostty_mode_new(1049, false)) /**< Alt screen + save cursor + clear */
#define GHOSTTY_MODE_BRACKETED_PASTE (ghostty_mode_new(2004, false)) /**< Bracketed paste mode */
#define GHOSTTY_MODE_SYNC_OUTPUT (ghostty_mode_new(2026, false)) /**< Synchronized output */
#define GHOSTTY_MODE_GRAPHEME_CLUSTER (ghostty_mode_new(2027, false)) /**< Grapheme cluster mode */
#define GHOSTTY_MODE_COLOR_SCHEME_REPORT (ghostty_mode_new(2031, false)) /**< Report color scheme */
#define GHOSTTY_MODE_IN_BAND_RESIZE (ghostty_mode_new(2048, false)) /**< In-band size reports */
/** @} */
/**
* A packed 16-bit terminal mode.
*
* Encodes a mode value (bits 014) and an ANSI flag (bit 15) into a
* single 16-bit integer. Use the inline helper functions to construct
* and inspect modes rather than manipulating bits directly.
*/
typedef uint16_t GhosttyMode;
/**
* Create a mode from a mode value and ANSI flag.
*
* @param value The numeric mode value (032767)
* @param ansi true for an ANSI mode, false for a DEC private mode
* @return The packed mode
*
* @ingroup modes
*/
static inline GhosttyMode ghostty_mode_new(uint16_t value, bool ansi) {
return (GhosttyMode)((value & 0x7FFF) | ((uint16_t)ansi << 15));
}
/**
* Extract the numeric mode value from a mode.
*
* @param mode The mode
* @return The mode value (032767)
*
* @ingroup modes
*/
static inline uint16_t ghostty_mode_value(GhosttyMode mode) {
return mode & 0x7FFF;
}
/**
* Check whether a mode represents an ANSI mode.
*
* @param mode The mode
* @return true if this is an ANSI mode, false if it is a DEC private mode
*
* @ingroup modes
*/
static inline bool ghostty_mode_ansi(GhosttyMode mode) {
return (mode >> 15) != 0;
}
/**
* DECRPM report state values.
*
* These correspond to the Ps2 parameter in a DECRPM response
* sequence (CSI ? Ps1 ; Ps2 $ y).
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Mode is not recognized */
GHOSTTY_MODE_REPORT_NOT_RECOGNIZED = 0,
/** Mode is set (enabled) */
GHOSTTY_MODE_REPORT_SET = 1,
/** Mode is reset (disabled) */
GHOSTTY_MODE_REPORT_RESET = 2,
/** Mode is permanently set */
GHOSTTY_MODE_REPORT_PERMANENTLY_SET = 3,
/** Mode is permanently reset */
GHOSTTY_MODE_REPORT_PERMANENTLY_RESET = 4,
GHOSTTY_MODE_REPORT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyModeReportState;
/**
* Encode a DECRPM (DEC Private Mode Report) response sequence.
*
* Writes a mode report escape sequence into the provided buffer.
* The generated sequence has the form:
* - DEC private mode: CSI ? Ps1 ; Ps2 $ y
* - ANSI mode: CSI Ps1 ; Ps2 $ y
*
* If the buffer is too small, the function returns GHOSTTY_OUT_OF_SPACE
* and writes the required buffer size to @p out_written. The caller can
* then retry with a sufficiently sized buffer.
*
* @param mode The mode identifying the mode to report on
* @param state The report state for this mode
* @param buf Output buffer to write the encoded sequence into (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_written On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
* is too small
*/
GHOSTTY_API GhosttyResult ghostty_mode_report_encode(
GhosttyMode mode,
GhosttyModeReportState state,
char* buf,
size_t buf_len,
size_t* out_written);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_MODES_H */
+70
View File
@@ -0,0 +1,70 @@
/**
* @file mouse.h
*
* Mouse encoding module - encode mouse events into terminal escape sequences.
*/
#ifndef GHOSTTY_VT_MOUSE_H
#define GHOSTTY_VT_MOUSE_H
/** @defgroup mouse Mouse Encoding
*
* Utilities for encoding mouse events into terminal escape sequences,
* supporting X10, UTF-8, SGR, URxvt, and SGR-Pixels mouse protocols.
*
* ## Basic Usage
*
* 1. Create an encoder instance with ghostty_mouse_encoder_new().
* 2. Configure encoder options with ghostty_mouse_encoder_setopt() or
* ghostty_mouse_encoder_setopt_from_terminal().
* 3. For each mouse event:
* - Create a mouse event with ghostty_mouse_event_new().
* - Set event properties (action, button, modifiers, position).
* - Encode with ghostty_mouse_encoder_encode().
* - Free the event with ghostty_mouse_event_free() or reuse it.
* 4. Free the encoder with ghostty_mouse_encoder_free() when done.
*
* For a complete working example, see example/c-vt-encode-mouse in the
* repository.
*
* ## Example
*
* @snippet c-vt-encode-mouse/src/main.c mouse-encode
*
* ## Example: Encoding with Terminal State
*
* When you have a GhosttyTerminal, you can sync its tracking mode and
* output format into the encoder automatically:
*
* @code{.c}
* // Create a terminal and feed it some VT data that enables mouse tracking
* GhosttyTerminal terminal;
* ghostty_terminal_new(NULL, &terminal,
* (GhosttyTerminalOptions){.cols = 80, .rows = 24, .max_scrollback = 0});
*
* // Application might write data that enables mouse reporting, etc.
* ghostty_terminal_vt_write(terminal, vt_data, vt_len);
*
* // Create an encoder and sync its options from the terminal
* GhosttyMouseEncoder encoder;
* ghostty_mouse_encoder_new(NULL, &encoder);
* ghostty_mouse_encoder_setopt_from_terminal(encoder, terminal);
*
* // Encode a mouse event using the terminal-derived options
* char buf[128];
* size_t written = 0;
* ghostty_mouse_encoder_encode(encoder, event, buf, sizeof(buf), &written);
*
* ghostty_mouse_encoder_free(encoder);
* ghostty_terminal_free(terminal);
* @endcode
*
* @{
*/
#include <ghostty/vt/mouse/event.h>
#include <ghostty/vt/mouse/encoder.h>
/** @} */
#endif /* GHOSTTY_VT_MOUSE_H */
+214
View File
@@ -0,0 +1,214 @@
/**
* @file encoder.h
*
* Mouse event encoding to terminal escape sequences.
*/
#ifndef GHOSTTY_VT_MOUSE_ENCODER_H
#define GHOSTTY_VT_MOUSE_ENCODER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/mouse/event.h>
#include <ghostty/vt/terminal.h>
#include <ghostty/vt/types.h>
/**
* Opaque handle to a mouse encoder instance.
*
* This handle represents a mouse encoder that converts normalized
* mouse events into terminal escape sequences.
*
* @ingroup mouse
*/
typedef struct GhosttyMouseEncoderImpl *GhosttyMouseEncoder;
/**
* Mouse tracking mode.
*
* @ingroup mouse
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Mouse reporting disabled. */
GHOSTTY_MOUSE_TRACKING_NONE = 0,
/** X10 mouse mode. */
GHOSTTY_MOUSE_TRACKING_X10 = 1,
/** Normal mouse mode (button press/release only). */
GHOSTTY_MOUSE_TRACKING_NORMAL = 2,
/** Button-event tracking mode. */
GHOSTTY_MOUSE_TRACKING_BUTTON = 3,
/** Any-event tracking mode. */
GHOSTTY_MOUSE_TRACKING_ANY = 4,
GHOSTTY_MOUSE_TRACKING_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyMouseTrackingMode;
/**
* Mouse output format.
*
* @ingroup mouse
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_MOUSE_FORMAT_X10 = 0,
GHOSTTY_MOUSE_FORMAT_UTF8 = 1,
GHOSTTY_MOUSE_FORMAT_SGR = 2,
GHOSTTY_MOUSE_FORMAT_URXVT = 3,
GHOSTTY_MOUSE_FORMAT_SGR_PIXELS = 4,
GHOSTTY_MOUSE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyMouseFormat;
/**
* Mouse encoder size and geometry context.
*
* This describes the rendered terminal geometry used to convert
* surface-space positions into encoded coordinates.
*
* @ingroup mouse
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyMouseEncoderSize). */
size_t size;
/** Full screen width in pixels. */
uint32_t screen_width;
/** Full screen height in pixels. */
uint32_t screen_height;
/** Cell width in pixels. Must be non-zero. */
uint32_t cell_width;
/** Cell height in pixels. Must be non-zero. */
uint32_t cell_height;
/** Top padding in pixels. */
uint32_t padding_top;
/** Bottom padding in pixels. */
uint32_t padding_bottom;
/** Right padding in pixels. */
uint32_t padding_right;
/** Left padding in pixels. */
uint32_t padding_left;
} GhosttyMouseEncoderSize;
/**
* Mouse encoder option identifiers.
*
* These values are used with ghostty_mouse_encoder_setopt() to configure
* the behavior of the mouse encoder.
*
* @ingroup mouse
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Mouse tracking mode (value: GhosttyMouseTrackingMode). */
GHOSTTY_MOUSE_ENCODER_OPT_EVENT = 0,
/** Mouse output format (value: GhosttyMouseFormat). */
GHOSTTY_MOUSE_ENCODER_OPT_FORMAT = 1,
/** Renderer size context (value: GhosttyMouseEncoderSize). */
GHOSTTY_MOUSE_ENCODER_OPT_SIZE = 2,
/** Whether any mouse button is currently pressed (value: bool). */
GHOSTTY_MOUSE_ENCODER_OPT_ANY_BUTTON_PRESSED = 3,
/** Whether to enable motion deduplication by last cell (value: bool). */
GHOSTTY_MOUSE_ENCODER_OPT_TRACK_LAST_CELL = 4,
GHOSTTY_MOUSE_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyMouseEncoderOption;
/**
* Create a new mouse encoder instance.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param encoder Pointer to store the created encoder handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyResult ghostty_mouse_encoder_new(const GhosttyAllocator *allocator,
GhosttyMouseEncoder *encoder);
/**
* Free a mouse encoder instance.
*
* @param encoder The encoder handle to free (may be NULL)
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_encoder_free(GhosttyMouseEncoder encoder);
/**
* Set an option on the mouse encoder.
*
* A null pointer value does nothing. It does not reset to defaults.
*
* @param encoder The encoder handle, must not be NULL
* @param option The option to set
* @param value Pointer to option value (type depends on option)
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_encoder_setopt(GhosttyMouseEncoder encoder,
GhosttyMouseEncoderOption option,
const void *value);
/**
* Set encoder options from a terminal's current state.
*
* This sets tracking mode and output format from terminal state.
* It does not modify size or any-button state.
*
* @param encoder The encoder handle, must not be NULL
* @param terminal The terminal handle, must not be NULL
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_encoder_setopt_from_terminal(GhosttyMouseEncoder encoder,
GhosttyTerminal terminal);
/**
* Reset internal encoder state.
*
* This clears motion deduplication state (last tracked cell).
*
* @param encoder The encoder handle (may be NULL)
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_encoder_reset(GhosttyMouseEncoder encoder);
/**
* Encode a mouse event into a terminal escape sequence.
*
* Not all mouse events produce output. In such cases this returns
* GHOSTTY_SUCCESS with out_len set to 0.
*
* If the output buffer is too small, this returns GHOSTTY_OUT_OF_SPACE
* and out_len contains the required size.
*
* @param encoder The encoder handle, must not be NULL
* @param event The mouse event to encode, must not be NULL
* @param out_buf Buffer to write encoded bytes to, or NULL to query required size
* @param out_buf_size Size of out_buf in bytes
* @param out_len Pointer to store bytes written (or required bytes on failure)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if buffer is too small,
* or another error code
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyResult ghostty_mouse_encoder_encode(GhosttyMouseEncoder encoder,
GhosttyMouseEvent event,
char *out_buf,
size_t out_buf_size,
size_t *out_len);
#endif /* GHOSTTY_VT_MOUSE_ENCODER_H */
+195
View File
@@ -0,0 +1,195 @@
/**
* @file event.h
*
* Mouse event representation and manipulation.
*/
#ifndef GHOSTTY_VT_MOUSE_EVENT_H
#define GHOSTTY_VT_MOUSE_EVENT_H
#include <stdbool.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/key/event.h>
#include <ghostty/vt/types.h>
/**
* Opaque handle to a mouse event.
*
* This handle represents a normalized mouse input event containing
* action, button, modifiers, and surface-space position.
*
* @ingroup mouse
*/
typedef struct GhosttyMouseEventImpl *GhosttyMouseEvent;
/**
* Mouse event action type.
*
* @ingroup mouse
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Mouse button was pressed. */
GHOSTTY_MOUSE_ACTION_PRESS = 0,
/** Mouse button was released. */
GHOSTTY_MOUSE_ACTION_RELEASE = 1,
/** Mouse moved. */
GHOSTTY_MOUSE_ACTION_MOTION = 2,
GHOSTTY_MOUSE_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyMouseAction;
/**
* Mouse button identity.
*
* @ingroup mouse
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_MOUSE_BUTTON_UNKNOWN = 0,
GHOSTTY_MOUSE_BUTTON_LEFT = 1,
GHOSTTY_MOUSE_BUTTON_RIGHT = 2,
GHOSTTY_MOUSE_BUTTON_MIDDLE = 3,
GHOSTTY_MOUSE_BUTTON_FOUR = 4,
GHOSTTY_MOUSE_BUTTON_FIVE = 5,
GHOSTTY_MOUSE_BUTTON_SIX = 6,
GHOSTTY_MOUSE_BUTTON_SEVEN = 7,
GHOSTTY_MOUSE_BUTTON_EIGHT = 8,
GHOSTTY_MOUSE_BUTTON_NINE = 9,
GHOSTTY_MOUSE_BUTTON_TEN = 10,
GHOSTTY_MOUSE_BUTTON_ELEVEN = 11,
GHOSTTY_MOUSE_BUTTON_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyMouseButton;
/**
* Mouse position in surface-space pixels.
*
* @ingroup mouse
*/
typedef struct {
float x;
float y;
} GhosttyMousePosition;
/**
* Create a new mouse event instance.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param event Pointer to store the created event handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyResult ghostty_mouse_event_new(const GhosttyAllocator *allocator,
GhosttyMouseEvent *event);
/**
* Free a mouse event instance.
*
* @param event The mouse event handle to free (may be NULL)
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_free(GhosttyMouseEvent event);
/**
* Set the event action.
*
* @param event The event handle, must not be NULL
* @param action The action to set
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_set_action(GhosttyMouseEvent event,
GhosttyMouseAction action);
/**
* Get the event action.
*
* @param event The event handle, must not be NULL
* @return The event action
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyMouseAction ghostty_mouse_event_get_action(GhosttyMouseEvent event);
/**
* Set the event button.
*
* This sets a concrete button identity for the event.
* To represent "no button" (for motion events), use
* ghostty_mouse_event_clear_button().
*
* @param event The event handle, must not be NULL
* @param button The button to set
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_set_button(GhosttyMouseEvent event,
GhosttyMouseButton button);
/**
* Clear the event button.
*
* This sets the event button to "none".
*
* @param event The event handle, must not be NULL
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_clear_button(GhosttyMouseEvent event);
/**
* Get the event button.
*
* @param event The event handle, must not be NULL
* @param out_button Output pointer for the button value (may be NULL)
* @return true if a button is set, false if no button is set
*
* @ingroup mouse
*/
GHOSTTY_API bool ghostty_mouse_event_get_button(GhosttyMouseEvent event,
GhosttyMouseButton *out_button);
/**
* Set keyboard modifiers held during the event.
*
* @param event The event handle, must not be NULL
* @param mods Modifier bitmask
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_set_mods(GhosttyMouseEvent event,
GhosttyMods mods);
/**
* Get keyboard modifiers held during the event.
*
* @param event The event handle, must not be NULL
* @return Modifier bitmask
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyMods ghostty_mouse_event_get_mods(GhosttyMouseEvent event);
/**
* Set the event position in surface-space pixels.
*
* @param event The event handle, must not be NULL
* @param position The position to set
*
* @ingroup mouse
*/
GHOSTTY_API void ghostty_mouse_event_set_position(GhosttyMouseEvent event,
GhosttyMousePosition position);
/**
* Get the event position in surface-space pixels.
*
* @param event The event handle, must not be NULL
* @return The current event position
*
* @ingroup mouse
*/
GHOSTTY_API GhosttyMousePosition ghostty_mouse_event_get_position(GhosttyMouseEvent event);
#endif /* GHOSTTY_VT_MOUSE_EVENT_H */
+215
View File
@@ -0,0 +1,215 @@
/**
* @file osc.h
*
* OSC (Operating System Command) sequence parser and command handling.
*/
#ifndef GHOSTTY_VT_OSC_H
#define GHOSTTY_VT_OSC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
/** @defgroup osc OSC Parser
*
* OSC (Operating System Command) sequence parser and command handling.
*
* The parser operates in a streaming fashion, processing input byte-by-byte
* to handle OSC sequences that may arrive in fragments across multiple reads.
* This interface makes it easy to integrate into most environments and avoids
* over-allocating buffers.
*
* ## Basic Usage
*
* 1. Create a parser instance with ghostty_osc_new()
* 2. Feed bytes to the parser using ghostty_osc_next()
* 3. Finalize parsing with ghostty_osc_end() to get the command
* 4. Query command type and extract data using ghostty_osc_command_type()
* and ghostty_osc_command_data()
* 5. Free the parser with ghostty_osc_free() when done
*
* @{
*/
/**
* OSC command types.
*
* @ingroup osc
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_OSC_COMMAND_INVALID = 0,
GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_TITLE = 1,
GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_ICON = 2,
GHOSTTY_OSC_COMMAND_SEMANTIC_PROMPT = 3,
GHOSTTY_OSC_COMMAND_CLIPBOARD_CONTENTS = 4,
GHOSTTY_OSC_COMMAND_REPORT_PWD = 5,
GHOSTTY_OSC_COMMAND_MOUSE_SHAPE = 6,
GHOSTTY_OSC_COMMAND_COLOR_OPERATION = 7,
GHOSTTY_OSC_COMMAND_KITTY_COLOR_PROTOCOL = 8,
GHOSTTY_OSC_COMMAND_SHOW_DESKTOP_NOTIFICATION = 9,
GHOSTTY_OSC_COMMAND_HYPERLINK_START = 10,
GHOSTTY_OSC_COMMAND_HYPERLINK_END = 11,
GHOSTTY_OSC_COMMAND_CONEMU_SLEEP = 12,
GHOSTTY_OSC_COMMAND_CONEMU_SHOW_MESSAGE_BOX = 13,
GHOSTTY_OSC_COMMAND_CONEMU_CHANGE_TAB_TITLE = 14,
GHOSTTY_OSC_COMMAND_CONEMU_PROGRESS_REPORT = 15,
GHOSTTY_OSC_COMMAND_CONEMU_WAIT_INPUT = 16,
GHOSTTY_OSC_COMMAND_CONEMU_GUIMACRO = 17,
GHOSTTY_OSC_COMMAND_CONEMU_RUN_PROCESS = 18,
GHOSTTY_OSC_COMMAND_CONEMU_OUTPUT_ENVIRONMENT_VARIABLE = 19,
GHOSTTY_OSC_COMMAND_CONEMU_XTERM_EMULATION = 20,
GHOSTTY_OSC_COMMAND_CONEMU_COMMENT = 21,
GHOSTTY_OSC_COMMAND_KITTY_TEXT_SIZING = 22,
GHOSTTY_OSC_COMMAND_TYPE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOscCommandType;
/**
* OSC command data types.
*
* These values specify what type of data to extract from an OSC command
* using `ghostty_osc_command_data`.
*
* @ingroup osc
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid data type. Never results in any data extraction. */
GHOSTTY_OSC_DATA_INVALID = 0,
/**
* Window title string data.
*
* Valid for: GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_TITLE
*
* Output type: const char ** (pointer to null-terminated string)
*
* Lifetime: Valid until the next call to any ghostty_osc_* function with
* the same parser instance. Memory is owned by the parser.
*/
GHOSTTY_OSC_DATA_CHANGE_WINDOW_TITLE_STR = 1,
GHOSTTY_OSC_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOscCommandData;
/**
* Create a new OSC parser instance.
*
* Creates a new OSC (Operating System Command) parser using the provided
* allocator. The parser must be freed using ghostty_vt_osc_free() when
* no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param parser Pointer to store the created parser handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup osc
*/
GHOSTTY_API GhosttyResult ghostty_osc_new(const GhosttyAllocator *allocator, GhosttyOscParser *parser);
/**
* Free an OSC parser instance.
*
* Releases all resources associated with the OSC parser. After this call,
* the parser handle becomes invalid and must not be used.
*
* @param parser The parser handle to free (may be NULL)
*
* @ingroup osc
*/
GHOSTTY_API void ghostty_osc_free(GhosttyOscParser parser);
/**
* Reset an OSC parser instance to its initial state.
*
* Resets the parser state, clearing any partially parsed OSC sequences
* and returning the parser to its initial state. This is useful for
* reusing a parser instance or recovering from parse errors.
*
* @param parser The parser handle to reset, must not be null.
*
* @ingroup osc
*/
GHOSTTY_API void ghostty_osc_reset(GhosttyOscParser parser);
/**
* Parse the next byte in an OSC sequence.
*
* Processes a single byte as part of an OSC sequence. The parser maintains
* internal state to track the progress through the sequence. Call this
* function for each byte in the sequence data.
*
* When finished pumping the parser with bytes, call ghostty_osc_end
* to get the final result.
*
* @param parser The parser handle, must not be null.
* @param byte The next byte to parse
*
* @ingroup osc
*/
GHOSTTY_API void ghostty_osc_next(GhosttyOscParser parser, uint8_t byte);
/**
* Finalize OSC parsing and retrieve the parsed command.
*
* Call this function after feeding all bytes of an OSC sequence to the parser
* using ghostty_osc_next() with the exception of the terminating character
* (ESC or ST). This function finalizes the parsing process and returns the
* parsed OSC command.
*
* The return value is never NULL. Invalid commands will return a command
* with type GHOSTTY_OSC_COMMAND_INVALID.
*
* The terminator parameter specifies the byte that terminated the OSC sequence
* (typically 0x07 for BEL or 0x5C for ST after ESC). This information is
* preserved in the parsed command so that responses can use the same terminator
* format for better compatibility with the calling program. For commands that
* do not require a response, this parameter is ignored and the resulting
* command will not retain the terminator information.
*
* The returned command handle is valid until the next call to any
* `ghostty_osc_*` function with the same parser instance with the exception
* of command introspection functions such as `ghostty_osc_command_type`.
*
* @param parser The parser handle, must not be null.
* @param terminator The terminating byte of the OSC sequence (0x07 for BEL, 0x5C for ST)
* @return Handle to the parsed OSC command
*
* @ingroup osc
*/
GHOSTTY_API GhosttyOscCommand ghostty_osc_end(GhosttyOscParser parser, uint8_t terminator);
/**
* Get the type of an OSC command.
*
* Returns the type identifier for the given OSC command. This can be used
* to determine what kind of command was parsed and what data might be
* available from it.
*
* @param command The OSC command handle to query (may be NULL)
* @return The command type, or GHOSTTY_OSC_COMMAND_INVALID if command is NULL
*
* @ingroup osc
*/
GHOSTTY_API GhosttyOscCommandType ghostty_osc_command_type(GhosttyOscCommand command);
/**
* Extract data from an OSC command.
*
* Extracts typed data from the given OSC command based on the specified
* data type. The output pointer must be of the appropriate type for the
* requested data kind. Valid command types, output types, and memory
* safety information are documented in the `GhosttyOscCommandData` enum.
*
* @param command The OSC command handle to query (may be NULL)
* @param data The type of data to extract
* @param out Pointer to store the extracted data (type depends on data parameter)
* @return true if data extraction was successful, false otherwise
*
* @ingroup osc
*/
GHOSTTY_API bool ghostty_osc_command_data(GhosttyOscCommand command, GhosttyOscCommandData data, void *out);
/** @} */
#endif /* GHOSTTY_VT_OSC_H */
+101
View File
@@ -0,0 +1,101 @@
/**
* @file paste.h
*
* Paste utilities - validate and encode paste data for terminal input.
*/
#ifndef GHOSTTY_VT_PASTE_H
#define GHOSTTY_VT_PASTE_H
/** @defgroup paste Paste Utilities
*
* Utilities for validating and encoding paste data for terminal input.
*
* ## Basic Usage
*
* Use ghostty_paste_is_safe() to check if paste data contains potentially
* dangerous sequences before sending it to the terminal.
*
* Use ghostty_paste_encode() to encode paste data for writing to the pty,
* including bracketed paste wrapping and unsafe byte stripping.
*
* ## Examples
*
* ### Safety Check
*
* @snippet c-vt-paste/src/main.c paste-safety
*
* ### Encoding
*
* @snippet c-vt-paste/src/main.c paste-encode
*
* @{
*/
#include <stdbool.h>
#include <stddef.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Check if paste data is safe to paste into the terminal.
*
* Data is considered unsafe if it contains:
* - Newlines (`\n`) which can inject commands
* - The bracketed paste end sequence (`\x1b[201~`) which can be used
* to exit bracketed paste mode and inject commands
*
* This check is conservative and considers data unsafe regardless of
* current terminal state.
*
* @param data The paste data to check (must not be NULL)
* @param len The length of the data in bytes
* @return true if the data is safe to paste, false otherwise
*/
GHOSTTY_API bool ghostty_paste_is_safe(const char* data, size_t len);
/**
* Encode paste data for writing to the terminal pty.
*
* This function prepares paste data for terminal input by:
* - Stripping unsafe control bytes (NUL, ESC, DEL, etc.) by replacing
* them with spaces
* - Wrapping the data in bracketed paste sequences if @p bracketed is true
* - Replacing newlines with carriage returns if @p bracketed is false
*
* The input @p data buffer is modified in place during encoding. The
* encoded result (potentially with bracketed paste prefix/suffix) is
* written to the output buffer.
*
* If the output buffer is too small, the function returns
* GHOSTTY_OUT_OF_SPACE and sets the required size in @p out_written.
* The caller can then retry with a sufficiently sized buffer.
*
* @param data The paste data to encode (modified in place, may be NULL)
* @param data_len The length of the input data in bytes
* @param bracketed Whether bracketed paste mode is active
* @param buf Output buffer to write the encoded result into (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_written On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
* is too small
*/
GHOSTTY_API GhosttyResult ghostty_paste_encode(
char* data,
size_t data_len,
bool bracketed,
char* buf,
size_t buf_len,
size_t* out_written);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_PASTE_H */
+89
View File
@@ -0,0 +1,89 @@
/**
* @file point.h
*
* Terminal point types for referencing locations in the terminal grid.
*/
#ifndef GHOSTTY_VT_POINT_H
#define GHOSTTY_VT_POINT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup point Point
*
* Types for referencing x/y positions in the terminal grid under
* different coordinate systems (active area, viewport, full screen,
* scrollback history).
*
* @{
*/
/**
* A coordinate in the terminal grid.
*
* @ingroup point
*/
typedef struct {
/** Column (0-indexed). */
uint16_t x;
/** Row (0-indexed). May exceed page size for screen/history tags. */
uint32_t y;
} GhosttyPointCoordinate;
/**
* Point reference tag.
*
* Determines which coordinate system a point uses.
*
* @ingroup point
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Active area where the cursor can move. */
GHOSTTY_POINT_TAG_ACTIVE = 0,
/** Visible viewport (changes when scrolled). */
GHOSTTY_POINT_TAG_VIEWPORT = 1,
/** Full screen including scrollback. */
GHOSTTY_POINT_TAG_SCREEN = 2,
/** Scrollback history only (before active area). */
GHOSTTY_POINT_TAG_HISTORY = 3,
GHOSTTY_POINT_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyPointTag;
/**
* Point value union.
*
* @ingroup point
*/
typedef union {
/** Coordinate (used for all tag variants). */
GhosttyPointCoordinate coordinate;
/** Padding for ABI compatibility. Do not use. */
uint64_t _padding[2];
} GhosttyPointValue;
/**
* Tagged union for a point in the terminal grid.
*
* @ingroup point
*/
typedef struct {
GhosttyPointTag tag;
GhosttyPointValue value;
} GhosttyPoint;
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_POINT_H */
+795
View File
@@ -0,0 +1,795 @@
/**
* @file render.h
*
* Render state for creating high performance renderers.
*/
#ifndef GHOSTTY_VT_RENDER_H
#define GHOSTTY_VT_RENDER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/color.h>
#include <ghostty/vt/terminal.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup render Render State
*
* Represents the state required to render a visible screen (a viewport)
* of a terminal instance. This is stateful and optimized for repeated
* updates from a single terminal instance and only updating dirty regions
* of the screen.
*
* The key design principle of this API is that it only needs read/write
* access to the terminal instance during the update call. This allows
* the render state to minimally impact terminal IO performance and also
* allows the renderer to be safely multi-threaded (as long as a lock is
* held during the update call to ensure exclusive access to the terminal
* instance).
*
* The basic usage of this API is:
*
* 1. Create an empty render state
* 2. Update it from a terminal instance whenever you need.
* 3. Read from the render state to get the data needed to draw your frame.
*
* ## Two-Phase Updates
*
* For callers that synchronize terminal access (e.g. a renderer thread
* sharing a lock with an IO thread), the update can be split into two
* phases to minimize the time the terminal must be held exclusively:
* ghostty_render_state_begin_update requires terminal access, while
* ghostty_render_state_end_update completes any deferred work using only
* memory owned by the render state. A typical renderer would lock, begin
* the update, unlock, and then end the update while the IO thread is free
* to continue modifying the terminal. ghostty_render_state_update is a
* convenience that performs both phases in one call.
*
* ## Dirty Tracking
*
* Dirty tracking is a key feature of the render state that allows renderers
* to efficiently determine what parts of the screen have changed and only
* redraw changed regions.
*
* The render state API keeps track of dirty state at two independent layers:
* a global dirty state that indicates whether the entire frame is clean,
* partially dirty, or fully dirty, and a per-row dirty state that allows
* tracking which rows in a partially dirty frame have changed.
*
* The user of the render state API is expected to unset both of these.
* The `update` call does not unset dirty state, it only updates it.
*
* An extremely important detail: setting one dirty state doesn't unset
* the other. For example, setting the global dirty state to false does not
* reset the row-level dirty flags. So, the caller of the render state API must
* be careful to manage both layers of dirty state correctly.
*
* ## Examples
*
* ### Creating and updating render state
* @snippet c-vt-render/src/main.c render-state-update
*
* ### Checking dirty state
* @snippet c-vt-render/src/main.c render-dirty-check
*
* ### Reading colors
* @snippet c-vt-render/src/main.c render-colors
*
* ### Reading cursor state
* @snippet c-vt-render/src/main.c render-cursor
*
* ### Iterating rows and cells
* @snippet c-vt-render/src/main.c render-row-iterate
*
* ### Resetting dirty state after rendering
* @snippet c-vt-render/src/main.c render-dirty-reset
*
* @{
*/
/**
* Dirty state of a render state after update.
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Not dirty at all; rendering can be skipped. */
GHOSTTY_RENDER_STATE_DIRTY_FALSE = 0,
/** Some rows changed; renderer can redraw incrementally. */
GHOSTTY_RENDER_STATE_DIRTY_PARTIAL = 1,
/** Global state changed; renderer should redraw everything. */
GHOSTTY_RENDER_STATE_DIRTY_FULL = 2,
GHOSTTY_RENDER_STATE_DIRTY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateDirty;
/**
* Visual style of the cursor.
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Bar cursor (DECSCUSR 5, 6). */
GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BAR = 0,
/** Block cursor (DECSCUSR 1, 2). */
GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK = 1,
/** Underline cursor (DECSCUSR 3, 4). */
GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_UNDERLINE = 2,
/** Hollow block cursor. */
GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK_HOLLOW = 3,
GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateCursorVisualStyle;
/**
* Queryable data kinds for ghostty_render_state_get().
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_RENDER_STATE_DATA_INVALID = 0,
/** Viewport width in cells (uint16_t). */
GHOSTTY_RENDER_STATE_DATA_COLS = 1,
/** Viewport height in cells (uint16_t). */
GHOSTTY_RENDER_STATE_DATA_ROWS = 2,
/** Current dirty state (GhosttyRenderStateDirty). */
GHOSTTY_RENDER_STATE_DATA_DIRTY = 3,
/** Populate a pre-allocated GhosttyRenderStateRowIterator with row data
* from the render state (GhosttyRenderStateRowIterator). Row data is
* only valid as long as the underlying render state is not updated.
* It is unsafe to use row data after updating the render state.
* */
GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR = 4,
/** Default/current background color (GhosttyColorRgb). */
GHOSTTY_RENDER_STATE_DATA_COLOR_BACKGROUND = 5,
/** Default/current foreground color (GhosttyColorRgb). */
GHOSTTY_RENDER_STATE_DATA_COLOR_FOREGROUND = 6,
/** Cursor color when explicitly set by terminal state (GhosttyColorRgb).
* Returns GHOSTTY_INVALID_VALUE if no explicit cursor color is set;
* use COLOR_CURSOR_HAS_VALUE to check first. */
GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR = 7,
/** Whether an explicit cursor color is set (bool). */
GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR_HAS_VALUE = 8,
/** The active 256-color palette (GhosttyColorRgb[256]). */
GHOSTTY_RENDER_STATE_DATA_COLOR_PALETTE = 9,
/** The visual style of the cursor (GhosttyRenderStateCursorVisualStyle). */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE = 10,
/** Whether the cursor is visible based on terminal modes (bool). */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE = 11,
/** Whether the cursor should blink based on terminal modes (bool). */
GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING = 12,
/** Whether the cursor is at a password input field (bool). */
GHOSTTY_RENDER_STATE_DATA_CURSOR_PASSWORD_INPUT = 13,
/** Whether the cursor is visible within the viewport (bool).
* If false, the cursor viewport position values are undefined. */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE = 14,
/** Cursor viewport x position in cells (uint16_t).
* Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X = 15,
/** Cursor viewport y position in cells (uint16_t).
* Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y = 16,
/** Whether the cursor is on the tail of a wide character (bool).
* Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */
GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_WIDE_TAIL = 17,
GHOSTTY_RENDER_STATE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateData;
/**
* Settable options for ghostty_render_state_set().
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Set dirty state (GhosttyRenderStateDirty). */
GHOSTTY_RENDER_STATE_OPTION_DIRTY = 0,
GHOSTTY_RENDER_STATE_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateOption;
/**
* Queryable data kinds for ghostty_render_state_row_get().
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_RENDER_STATE_ROW_DATA_INVALID = 0,
/** Whether the current row is dirty (bool). */
GHOSTTY_RENDER_STATE_ROW_DATA_DIRTY = 1,
/** The raw row value (GhosttyRow). */
GHOSTTY_RENDER_STATE_ROW_DATA_RAW = 2,
/** Populate a pre-allocated GhosttyRenderStateRowCells with cell data for
* the current row (GhosttyRenderStateRowCells). Cell data is only
* valid as long as the underlying render state is not updated.
* It is unsafe to use cell data after updating the render state. */
GHOSTTY_RENDER_STATE_ROW_DATA_CELLS = 3,
/** Row-local selected cell range (GhosttyRenderStateRowSelection). */
GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION = 4,
GHOSTTY_RENDER_STATE_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateRowData;
/**
* Settable options for ghostty_render_state_row_set().
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Set dirty state for the current row (bool). */
GHOSTTY_RENDER_STATE_ROW_OPTION_DIRTY = 0,
GHOSTTY_RENDER_STATE_ROW_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateRowOption;
/**
* Row-local selection range.
*
* This struct uses the sized-struct ABI pattern. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyRenderStateRowSelection) before querying
* GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION.
*
* Querying GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION returns GHOSTTY_NO_VALUE
* if the current row does not intersect the current selection.
*
* @ingroup render
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyRenderStateRowSelection). */
size_t size;
/** Start column of the row-local selection range, inclusive. */
uint16_t start_x;
/** End column of the row-local selection range, inclusive. */
uint16_t end_x;
} GhosttyRenderStateRowSelection;
/**
* Render-state color information.
*
* This struct uses the sized-struct ABI pattern. Initialize with
* GHOSTTY_INIT_SIZED(GhosttyRenderStateColors) before calling
* ghostty_render_state_colors_get().
*
* Example:
* @code
* GhosttyRenderStateColors colors = GHOSTTY_INIT_SIZED(GhosttyRenderStateColors);
* GhosttyResult result = ghostty_render_state_colors_get(state, &colors);
* @endcode
*
* @ingroup render
*/
typedef struct {
/** Size of this struct in bytes. Must be set to sizeof(GhosttyRenderStateColors). */
size_t size;
/** The default/current background color for the render state. */
GhosttyColorRgb background;
/** The default/current foreground color for the render state. */
GhosttyColorRgb foreground;
/** The cursor color when explicitly set by terminal state. */
GhosttyColorRgb cursor;
/**
* True when cursor contains a valid explicit cursor color value.
* If this is false, the cursor color should be ignored; it will
* contain undefined data.
* */
bool cursor_has_value;
/** The active 256-color palette for this render state. */
GhosttyColorRgb palette[256];
} GhosttyRenderStateColors;
/**
* Create a new render state instance.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param state Pointer to store the created render state handle
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
* failure
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_new(const GhosttyAllocator* allocator,
GhosttyRenderState* state);
/**
* Free a render state instance.
*
* Releases all resources associated with the render state. After this call,
* the render state handle becomes invalid.
*
* @param state The render state handle to free (may be NULL)
*
* @ingroup render
*/
GHOSTTY_API void ghostty_render_state_free(GhosttyRenderState state);
/**
* Update a render state instance from a terminal.
*
* This consumes terminal/screen dirty state in the same way as the internal
* render state update path.
*
* This is a convenience function that performs a full update in one call,
* equivalent to ghostty_render_state_begin_update immediately followed by
* ghostty_render_state_end_update. Callers that hold a lock over the
* terminal state should prefer calling the two phases directly so that the
* lock is only held for the begin phase.
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param terminal The terminal handle to read from (NULL returns GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
* `terminal` is NULL, GHOSTTY_OUT_OF_MEMORY if updating the state requires
* allocation and that allocation fails
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
GhosttyTerminal terminal);
/**
* Begin an update of a render state instance from a terminal.
*
* Every begin must be completed with a ghostty_render_state_end_update call
* before the render state is read.
*
* This two-phase structure exists for callers that synchronize access to the
* terminal state (e.g. with a lock shared with an IO thread): only this
* function requires terminal access, so a caller can hold its lock for this
* call only and then call ghostty_render_state_end_update after releasing
* it. The end phase exclusively reads and writes memory owned by the render
* state, so it is safe to call while the terminal is being modified.
*
* Work that doesn't require terminal access may be deferred to the end phase
* to keep this call (and therefore lock hold time) as short as possible.
* Callers must treat the render state as incomplete until
* ghostty_render_state_end_update is called.
*
* This consumes terminal/screen dirty state in the same way as the internal
* render state update path.
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param terminal The terminal handle to read from (NULL returns GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
* `terminal` is NULL, GHOSTTY_OUT_OF_MEMORY if updating the state requires
* allocation and that allocation fails
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_begin_update(GhosttyRenderState state,
GhosttyTerminal terminal);
/**
* Complete a prior ghostty_render_state_begin_update call by performing any
* deferred work.
*
* This only reads and writes memory owned by the render state, so it is safe
* to call while the terminal is being modified (no terminal synchronization
* is required). Calling this without a prior begin is a safe no-op.
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
* NULL
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_end_update(GhosttyRenderState state);
/**
* Get a value from a render state.
*
* The `out` pointer must point to a value of the type corresponding to the
* requested data kind (see GhosttyRenderStateData).
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param data The data kind to query
* @param[out] out Pointer to receive the queried value
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
* NULL or `data` is not a recognized enum value
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_get(GhosttyRenderState state,
GhosttyRenderStateData data,
void* out);
/**
* Get multiple data fields from a render state in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_get_multi(
GhosttyRenderState state,
size_t count,
const GhosttyRenderStateData* keys,
void** values,
size_t* out_written);
/**
* Set an option on a render state.
*
* The `value` pointer must point to a value of the type corresponding to the
* requested option kind (see GhosttyRenderStateOption).
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param option The option to set
* @param[in] value Pointer to the value to set (NULL returns
* GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
* `value` is NULL
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_set(GhosttyRenderState state,
GhosttyRenderStateOption option,
const void* value);
/**
* Get the current color information from a render state.
*
* This writes as many fields as fit in the caller-provided sized struct.
* `out_colors->size` must be set by the caller (typically via
* GHOSTTY_INIT_SIZED(GhosttyRenderStateColors)).
*
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param[out] out_colors Sized output struct to receive render-state colors
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
* `out_colors` is NULL, or if `out_colors->size` is smaller than
* `sizeof(size_t)`
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_colors_get(GhosttyRenderState state,
GhosttyRenderStateColors* out_colors);
/**
* Create a new row iterator instance.
*
* All fields except the allocator are left undefined until populated
* via ghostty_render_state_get() with
* GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param[out] out_iterator On success, receives the created iterator handle
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
* failure
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_iterator_new(
const GhosttyAllocator* allocator,
GhosttyRenderStateRowIterator* out_iterator);
/**
* Free a render-state row iterator.
*
* @param iterator The iterator handle to free (may be NULL)
*
* @ingroup render
*/
GHOSTTY_API void ghostty_render_state_row_iterator_free(GhosttyRenderStateRowIterator iterator);
/**
* Move a render-state row iterator to the next row.
*
* Returns true if the iterator moved successfully and row data is
* available to read at the new position.
*
* @param iterator The iterator handle to advance (may be NULL)
* @return true if advanced to the next row, false if `iterator` is
* NULL or if the iterator has reached the end
*
* @ingroup render
*/
GHOSTTY_API bool ghostty_render_state_row_iterator_next(GhosttyRenderStateRowIterator iterator);
/**
* Get a value from the current row in a render-state row iterator.
*
* The `out` pointer must point to a value of the type corresponding to the
* requested data kind (see GhosttyRenderStateRowData).
* Call ghostty_render_state_row_iterator_next() at least once before
* calling this function.
*
* @param iterator The iterator handle to query (NULL returns GHOSTTY_INVALID_VALUE)
* @param data The data kind to query
* @param[out] out Pointer to receive the queried value
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
* `iterator` is NULL or the iterator is not positioned on a row
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_get(
GhosttyRenderStateRowIterator iterator,
GhosttyRenderStateRowData data,
void* out);
/**
* Get multiple data fields from the current row in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_get_multi(
GhosttyRenderStateRowIterator iterator,
size_t count,
const GhosttyRenderStateRowData* keys,
void** values,
size_t* out_written);
/**
* Set an option on the current row in a render-state row iterator.
*
* The `value` pointer must point to a value of the type corresponding to the
* requested option kind (see GhosttyRenderStateRowOption).
* Call ghostty_render_state_row_iterator_next() at least once before
* calling this function.
*
* @param iterator The iterator handle to update (NULL returns GHOSTTY_INVALID_VALUE)
* @param option The option to set
* @param[in] value Pointer to the value to set (NULL returns
* GHOSTTY_INVALID_VALUE)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
* `iterator` is NULL or the iterator is not positioned on a row
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_set(
GhosttyRenderStateRowIterator iterator,
GhosttyRenderStateRowOption option,
const void* value);
/**
* Create a new row cells instance.
*
* All fields except the allocator are left undefined until populated
* via ghostty_render_state_row_get() with
* GHOSTTY_RENDER_STATE_ROW_DATA_CELLS.
*
* You can reuse this value repeatedly with ghostty_render_state_row_get() to
* avoid allocating a new cells container for every row.
*
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param[out] out_cells On success, receives the created row cells handle
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
* failure
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_new(
const GhosttyAllocator* allocator,
GhosttyRenderStateRowCells* out_cells);
/**
* Queryable data kinds for ghostty_render_state_row_cells_get().
*
* @ingroup render
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid / sentinel value. */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_INVALID = 0,
/** The raw cell value (GhosttyCell). */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_RAW = 1,
/** The style for the current cell (GhosttyStyle). */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_STYLE = 2,
/** The total number of grapheme codepoints including the base codepoint
* (uint32_t). Returns 0 if the cell has no text. */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN = 3,
/** Write grapheme codepoints into a caller-provided buffer (uint32_t*).
* The buffer must be at least graphemes_len elements. The base codepoint
* is written first, followed by any extra codepoints. */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF = 4,
/** The resolved background color of the cell (GhosttyColorRgb).
* Flattens the three possible sources: content-tag bg_color_rgb,
* content-tag bg_color_palette (looked up in the palette), or the
* style's bg_color. Returns GHOSTTY_INVALID_VALUE if the cell has
* no background color, in which case the caller should use whatever
* default background color it wants (e.g. the terminal background). */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_BG_COLOR = 5,
/** The resolved foreground color of the cell (GhosttyColorRgb).
* Resolves palette indices through the palette. Bold color handling
* is not applied; the caller should handle bold styling separately.
* Returns GHOSTTY_INVALID_VALUE if the cell has no explicit foreground
* color, in which case the caller should use whatever default foreground
* color it wants (e.g. the terminal foreground). */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_FG_COLOR = 6,
/** Whether the cell is contained within the current selection (bool).
* This returns true when the cell's column is within the current row's
* row-local selection range, and false otherwise. Rendering policy for
* selected cells (colors, inversion, etc.) is left to the caller.
*
* Renderers that can draw cells in spans may be more efficient querying
* GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION once per row and applying that
* range directly, avoiding one C API call per cell for selection state. */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_SELECTED = 7,
/** Whether the cell has any explicit styling (bool).
* This is equivalent to querying the raw cell's
* GHOSTTY_CELL_DATA_HAS_STYLING value, but avoids materializing the raw
* GhosttyCell for renderers that only need to know whether fetching the
* full style is necessary. */
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_HAS_STYLING = 8,
/**
* Encode the current cell's full grapheme cluster as UTF-8 into a
* caller-provided buffer (GhosttyBuffer).
*
* The base codepoint is encoded first, followed by any extra grapheme
* codepoints. Returns GHOSTTY_SUCCESS with len=0 when the cell has no text.
*
* If ptr is NULL or cap is too small for a non-empty cell, returns
* GHOSTTY_OUT_OF_SPACE without writing any bytes and sets len to the required
* buffer size in bytes.
*/
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_UTF8 = 9,
GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateRowCellsData;
/**
* Move a render-state row cells iterator to the next cell.
*
* Returns true if the iterator moved successfully and cell data is
* available to read at the new position.
*
* @param cells The row cells handle to advance (may be NULL)
* @return true if advanced to the next cell, false if `cells` is
* NULL or if the iterator has reached the end
*
* @ingroup render
*/
GHOSTTY_API bool ghostty_render_state_row_cells_next(GhosttyRenderStateRowCells cells);
/**
* Move a render-state row cells iterator to a specific column.
*
* Positions the iterator at the given x (column) index so that
* subsequent reads return data for that cell.
*
* @param cells The row cells handle to reposition (NULL returns
* GHOSTTY_INVALID_VALUE)
* @param x The zero-based column index to select
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `cells`
* is NULL or `x` is out of range
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_select(
GhosttyRenderStateRowCells cells, uint16_t x);
/**
* Get a value from the current cell in a render-state row cells iterator.
*
* The `out` pointer must point to a value of the type corresponding to the
* requested data kind (see GhosttyRenderStateRowCellsData).
* Call ghostty_render_state_row_cells_next() or
* ghostty_render_state_row_cells_select() at least once before
* calling this function.
*
* @param cells The row cells handle to query (NULL returns GHOSTTY_INVALID_VALUE)
* @param data The data kind to query
* @param[out] out Pointer to receive the queried value
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
* `cells` is NULL or the iterator is not positioned on a cell
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get(
GhosttyRenderStateRowCells cells,
GhosttyRenderStateRowCellsData data,
void* out);
/**
* Get multiple data fields from the current cell in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param cells The row cells handle (NULL returns GHOSTTY_INVALID_VALUE)
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup render
*/
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get_multi(
GhosttyRenderStateRowCells cells,
size_t count,
const GhosttyRenderStateRowCellsData* keys,
void** values,
size_t* out_written);
/**
* Free a row cells instance.
*
* @param cells The row cells handle to free (may be NULL)
*
* @ingroup render
*/
GHOSTTY_API void ghostty_render_state_row_cells_free(GhosttyRenderStateRowCells cells);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_RENDER_H */
+400
View File
@@ -0,0 +1,400 @@
/**
* @file screen.h
*
* Terminal screen cell and row types.
*/
#ifndef GHOSTTY_VT_SCREEN_H
#define GHOSTTY_VT_SCREEN_H
#include <stdbool.h>
#include <stdint.h>
#include <ghostty/vt/color.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup screen Screen
*
* Terminal screen cell and row types.
*
* These types represent the contents of a terminal screen. A GhosttyCell
* is a single grid cell and a GhosttyRow is a single row. Both are opaque
* values whose fields are accessed via ghostty_cell_get() and
* ghostty_row_get() respectively.
*
* @{
*/
/**
* Opaque cell value.
*
* Represents a single terminal cell. The internal layout is opaque and
* must be queried via ghostty_cell_get(). Obtain cell values from
* terminal query APIs.
*
* @ingroup screen
*/
typedef uint64_t GhosttyCell;
/**
* Opaque row value.
*
* Represents a single terminal row. The internal layout is opaque and
* must be queried via ghostty_row_get(). Obtain row values from
* terminal query APIs.
*
* @ingroup screen
*/
typedef uint64_t GhosttyRow;
/**
* Cell content tag.
*
* Describes what kind of content a cell holds.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** A single codepoint (may be zero for empty). */
GHOSTTY_CELL_CONTENT_CODEPOINT = 0,
/** A codepoint that is part of a multi-codepoint grapheme cluster. */
GHOSTTY_CELL_CONTENT_CODEPOINT_GRAPHEME = 1,
/** No text; background color from palette. */
GHOSTTY_CELL_CONTENT_BG_COLOR_PALETTE = 2,
/** No text; background color as RGB. */
GHOSTTY_CELL_CONTENT_BG_COLOR_RGB = 3,
GHOSTTY_CELL_CONTENT_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyCellContentTag;
/**
* Cell wide property.
*
* Describes the width behavior of a cell.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Not a wide character, cell width 1. */
GHOSTTY_CELL_WIDE_NARROW = 0,
/** Wide character, cell width 2. */
GHOSTTY_CELL_WIDE_WIDE = 1,
/** Spacer after wide character. Do not render. */
GHOSTTY_CELL_WIDE_SPACER_TAIL = 2,
/** Spacer at end of soft-wrapped line for a wide character. */
GHOSTTY_CELL_WIDE_SPACER_HEAD = 3,
GHOSTTY_CELL_WIDE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyCellWide;
/**
* Semantic content type of a cell.
*
* Set by semantic prompt sequences (OSC 133) to distinguish between
* command output, user input, and shell prompt text.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Regular output content, such as command output. */
GHOSTTY_CELL_SEMANTIC_OUTPUT = 0,
/** Content that is part of user input. */
GHOSTTY_CELL_SEMANTIC_INPUT = 1,
/** Content that is part of a shell prompt. */
GHOSTTY_CELL_SEMANTIC_PROMPT = 2,
GHOSTTY_CELL_SEMANTIC_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyCellSemanticContent;
/**
* Cell data types.
*
* These values specify what type of data to extract from a cell
* using `ghostty_cell_get`.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid data type. Never results in any data extraction. */
GHOSTTY_CELL_DATA_INVALID = 0,
/**
* The codepoint of the cell (0 if empty or bg-color-only).
*
* Output type: uint32_t *
*/
GHOSTTY_CELL_DATA_CODEPOINT = 1,
/**
* The content tag describing what kind of content is in the cell.
*
* Output type: GhosttyCellContentTag *
*/
GHOSTTY_CELL_DATA_CONTENT_TAG = 2,
/**
* The wide property of the cell.
*
* Output type: GhosttyCellWide *
*/
GHOSTTY_CELL_DATA_WIDE = 3,
/**
* Whether the cell has text to render.
*
* Output type: bool *
*/
GHOSTTY_CELL_DATA_HAS_TEXT = 4,
/**
* Whether the cell has non-default styling.
*
* Output type: bool *
*/
GHOSTTY_CELL_DATA_HAS_STYLING = 5,
/**
* The style ID for the cell (for use with style lookups).
*
* Output type: uint16_t *
*/
GHOSTTY_CELL_DATA_STYLE_ID = 6,
/**
* Whether the cell has a hyperlink.
*
* Output type: bool *
*/
GHOSTTY_CELL_DATA_HAS_HYPERLINK = 7,
/**
* Whether the cell is protected.
*
* Output type: bool *
*/
GHOSTTY_CELL_DATA_PROTECTED = 8,
/**
* The semantic content type of the cell (from OSC 133).
*
* Output type: GhosttyCellSemanticContent *
*/
GHOSTTY_CELL_DATA_SEMANTIC_CONTENT = 9,
/**
* The palette index for the cell's background color.
* Only valid when content_tag is GHOSTTY_CELL_CONTENT_BG_COLOR_PALETTE.
*
* Output type: GhosttyColorPaletteIndex *
*/
GHOSTTY_CELL_DATA_COLOR_PALETTE = 10,
/**
* The RGB value for the cell's background color.
* Only valid when content_tag is GHOSTTY_CELL_CONTENT_BG_COLOR_RGB.
*
* Output type: GhosttyColorRgb *
*/
GHOSTTY_CELL_DATA_COLOR_RGB = 11,
GHOSTTY_CELL_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyCellData;
/**
* Row semantic prompt state.
*
* Indicates whether any cells in a row are part of a shell prompt,
* as reported by OSC 133 sequences.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** No prompt cells in this row. */
GHOSTTY_ROW_SEMANTIC_NONE = 0,
/** Prompt cells exist and this is a primary prompt line. */
GHOSTTY_ROW_SEMANTIC_PROMPT = 1,
/** Prompt cells exist and this is a continuation line. */
GHOSTTY_ROW_SEMANTIC_PROMPT_CONTINUATION = 2,
GHOSTTY_ROW_SEMANTIC_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRowSemanticPrompt;
/**
* Row data types.
*
* These values specify what type of data to extract from a row
* using `ghostty_row_get`.
*
* @ingroup screen
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Invalid data type. Never results in any data extraction. */
GHOSTTY_ROW_DATA_INVALID = 0,
/**
* Whether this row is soft-wrapped.
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_WRAP = 1,
/**
* Whether this row is a continuation of a soft-wrapped row.
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_WRAP_CONTINUATION = 2,
/**
* Whether any cells in this row have grapheme clusters.
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_GRAPHEME = 3,
/**
* Whether any cells in this row have styling (may have false positives).
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_STYLED = 4,
/**
* Whether any cells in this row have hyperlinks (may have false positives).
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_HYPERLINK = 5,
/**
* The semantic prompt state of this row.
*
* Output type: GhosttyRowSemanticPrompt *
*/
GHOSTTY_ROW_DATA_SEMANTIC_PROMPT = 6,
/**
* Whether this row contains a Kitty virtual placeholder.
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_KITTY_VIRTUAL_PLACEHOLDER = 7,
/**
* Whether this row is dirty and requires a redraw.
*
* Output type: bool *
*/
GHOSTTY_ROW_DATA_DIRTY = 8,
GHOSTTY_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRowData;
/**
* Get data from a cell.
*
* Extracts typed data from the given cell based on the specified
* data type. The output pointer must be of the appropriate type for the
* requested data kind. Valid data types and output types are documented
* in the `GhosttyCellData` enum.
*
* @param cell The cell value
* @param data The type of data to extract
* @param out Pointer to store the extracted data (type depends on data parameter)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
* data type is invalid
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_cell_get(GhosttyCell cell,
GhosttyCellData data,
void *out);
/**
* Get multiple data fields from a cell in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param cell The cell value
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_cell_get_multi(GhosttyCell cell,
size_t count,
const GhosttyCellData* keys,
void** values,
size_t* out_written);
/**
* Get data from a row.
*
* Extracts typed data from the given row based on the specified
* data type. The output pointer must be of the appropriate type for the
* requested data kind. Valid data types and output types are documented
* in the `GhosttyRowData` enum.
*
* @param row The row value
* @param data The type of data to extract
* @param out Pointer to store the extracted data (type depends on data parameter)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
* data type is invalid
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_row_get(GhosttyRow row,
GhosttyRowData data,
void *out);
/**
* Get multiple data fields from a row in a single call.
*
* Each element in the keys array specifies a data kind, and the
* corresponding element in the values array receives the result.
*
* Processing stops at the first error; on success out_written
* is set to count, on error it is set to the index of the
* failing key (i.e. the number of values successfully written).
*
* @param row The row value
* @param count Number of key/value pairs
* @param keys Array of data kinds to query
* @param values Array of output pointers (types must match each key's
* documented output type)
* @param[out] out_written On return, receives the number of values
* successfully written (may be NULL)
* @return GHOSTTY_SUCCESS if all queries succeed
*
* @ingroup screen
*/
GHOSTTY_API GhosttyResult ghostty_row_get_multi(GhosttyRow row,
size_t count,
const GhosttyRowData* keys,
void** values,
size_t* out_written);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_SCREEN_H */
File diff suppressed because it is too large Load Diff
+353
View File
@@ -0,0 +1,353 @@
/**
* @file sgr.h
*
* SGR (Select Graphic Rendition) attribute parsing and handling.
*/
#ifndef GHOSTTY_VT_SGR_H
#define GHOSTTY_VT_SGR_H
/** @defgroup sgr SGR Parser
*
* SGR (Select Graphic Rendition) attribute parser.
*
* SGR sequences are the syntax used to set styling attributes such as
* bold, italic, underline, and colors for text in terminal emulators.
* For example, you may be familiar with sequences like `ESC[1;31m`. The
* `1;31` is the SGR attribute list.
*
* The parser processes SGR parameters from CSI sequences (e.g., `ESC[1;31m`)
* and returns individual text attributes like bold, italic, colors, etc.
* It supports both semicolon (`;`) and colon (`:`) separators, possibly mixed,
* and handles SGR color attributes including 8-color, 16-color, 256-color,
* direct RGB, underline color, and reset forms. Color values are returned
* using the shared @ref color types; applications that need to parse Ghostty
* config/theme color strings, generate palettes, inspect X11 color names, or
* calculate luminance and contrast should use the @ref color APIs directly.
*
* ## Basic Usage
*
* 1. Create a parser instance with ghostty_sgr_new()
* 2. Set SGR parameters with ghostty_sgr_set_params()
* 3. Iterate through attributes using ghostty_sgr_next()
* 4. Free the parser with ghostty_sgr_free() when done
*
* ## Example
*
* @snippet c-vt-sgr/src/main.c sgr-basic
*
* @{
*/
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/color.h>
#include <ghostty/vt/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* SGR attribute tags.
*
* These values identify the type of an SGR attribute in a tagged union.
* Use the tag to determine which field in the attribute value union to access.
*
* @ingroup sgr
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_SGR_ATTR_UNSET = 0,
GHOSTTY_SGR_ATTR_UNKNOWN = 1,
GHOSTTY_SGR_ATTR_BOLD = 2,
GHOSTTY_SGR_ATTR_RESET_BOLD = 3,
GHOSTTY_SGR_ATTR_ITALIC = 4,
GHOSTTY_SGR_ATTR_RESET_ITALIC = 5,
GHOSTTY_SGR_ATTR_FAINT = 6,
GHOSTTY_SGR_ATTR_UNDERLINE = 7,
GHOSTTY_SGR_ATTR_UNDERLINE_COLOR = 8,
GHOSTTY_SGR_ATTR_UNDERLINE_COLOR_256 = 9,
GHOSTTY_SGR_ATTR_RESET_UNDERLINE_COLOR = 10,
GHOSTTY_SGR_ATTR_OVERLINE = 11,
GHOSTTY_SGR_ATTR_RESET_OVERLINE = 12,
GHOSTTY_SGR_ATTR_BLINK = 13,
GHOSTTY_SGR_ATTR_RESET_BLINK = 14,
GHOSTTY_SGR_ATTR_INVERSE = 15,
GHOSTTY_SGR_ATTR_RESET_INVERSE = 16,
GHOSTTY_SGR_ATTR_INVISIBLE = 17,
GHOSTTY_SGR_ATTR_RESET_INVISIBLE = 18,
GHOSTTY_SGR_ATTR_STRIKETHROUGH = 19,
GHOSTTY_SGR_ATTR_RESET_STRIKETHROUGH = 20,
GHOSTTY_SGR_ATTR_DIRECT_COLOR_FG = 21,
GHOSTTY_SGR_ATTR_DIRECT_COLOR_BG = 22,
GHOSTTY_SGR_ATTR_BG_8 = 23,
GHOSTTY_SGR_ATTR_FG_8 = 24,
GHOSTTY_SGR_ATTR_RESET_FG = 25,
GHOSTTY_SGR_ATTR_RESET_BG = 26,
GHOSTTY_SGR_ATTR_BRIGHT_BG_8 = 27,
GHOSTTY_SGR_ATTR_BRIGHT_FG_8 = 28,
GHOSTTY_SGR_ATTR_BG_256 = 29,
GHOSTTY_SGR_ATTR_FG_256 = 30,
GHOSTTY_SGR_ATTR_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySgrAttributeTag;
/**
* Underline style types.
*
* @ingroup sgr
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_SGR_UNDERLINE_NONE = 0,
GHOSTTY_SGR_UNDERLINE_SINGLE = 1,
GHOSTTY_SGR_UNDERLINE_DOUBLE = 2,
GHOSTTY_SGR_UNDERLINE_CURLY = 3,
GHOSTTY_SGR_UNDERLINE_DOTTED = 4,
GHOSTTY_SGR_UNDERLINE_DASHED = 5,
GHOSTTY_SGR_UNDERLINE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySgrUnderline;
/**
* Unknown SGR attribute data.
*
* Contains the full parameter list and the partial list where parsing
* encountered an unknown or invalid sequence.
*
* @ingroup sgr
*/
typedef struct {
const uint16_t* full_ptr;
size_t full_len;
const uint16_t* partial_ptr;
size_t partial_len;
} GhosttySgrUnknown;
/**
* SGR attribute value union.
*
* This union contains all possible attribute values. Use the tag field
* to determine which union member is active. Attributes without associated
* data (like bold, italic) don't use the union value.
*
* @ingroup sgr
*/
typedef union {
GhosttySgrUnknown unknown;
GhosttySgrUnderline underline;
GhosttyColorRgb underline_color;
GhosttyColorPaletteIndex underline_color_256;
GhosttyColorRgb direct_color_fg;
GhosttyColorRgb direct_color_bg;
GhosttyColorPaletteIndex bg_8;
GhosttyColorPaletteIndex fg_8;
GhosttyColorPaletteIndex bright_bg_8;
GhosttyColorPaletteIndex bright_fg_8;
GhosttyColorPaletteIndex bg_256;
GhosttyColorPaletteIndex fg_256;
uint64_t _padding[8];
} GhosttySgrAttributeValue;
/**
* SGR attribute (tagged union).
*
* A complete SGR attribute with both its type tag and associated value.
* Always check the tag field to determine which value union member is valid.
*
* Attributes without associated data (e.g., GHOSTTY_SGR_ATTR_BOLD) can be
* identified by tag alone; the value union is not used for these and
* the memory in the value field is undefined.
*
* @ingroup sgr
*/
typedef struct {
GhosttySgrAttributeTag tag;
GhosttySgrAttributeValue value;
} GhosttySgrAttribute;
/**
* Create a new SGR parser instance.
*
* Creates a new SGR (Select Graphic Rendition) parser using the provided
* allocator. The parser must be freed using ghostty_sgr_free() when
* no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or
* NULL to use the default allocator
* @param parser Pointer to store the created parser handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup sgr
*/
GHOSTTY_API GhosttyResult ghostty_sgr_new(const GhosttyAllocator* allocator,
GhosttySgrParser* parser);
/**
* Free an SGR parser instance.
*
* Releases all resources associated with the SGR parser. After this call,
* the parser handle becomes invalid and must not be used. This includes
* any attributes previously returned by ghostty_sgr_next().
*
* @param parser The parser handle to free (may be NULL)
*
* @ingroup sgr
*/
GHOSTTY_API void ghostty_sgr_free(GhosttySgrParser parser);
/**
* Reset an SGR parser instance to the beginning of the parameter list.
*
* Resets the parser's iteration state without clearing the parameters.
* After calling this, ghostty_sgr_next() will start from the beginning
* of the parameter list again.
*
* @param parser The parser handle to reset, must not be NULL
*
* @ingroup sgr
*/
GHOSTTY_API void ghostty_sgr_reset(GhosttySgrParser parser);
/**
* Set SGR parameters for parsing.
*
* Sets the SGR parameter list to parse. Parameters are the numeric values
* from a CSI SGR sequence (e.g., for `ESC[1;31m`, params would be {1, 31}).
*
* The separators array optionally specifies the separator type for each
* parameter position. Each byte should be either ';' for semicolon or ':'
* for colon. This is needed for certain color formats that use colon
* separators (e.g., `ESC[4:3m` for curly underline). Any invalid separator
* values are treated as semicolons. The separators array must have the same
* length as the params array, if it is not NULL.
*
* If separators is NULL, all parameters are assumed to be semicolon-separated.
*
* This function makes an internal copy of the parameter and separator data,
* so the caller can safely free or modify the input arrays after this call.
*
* After calling this function, the parser is automatically reset and ready
* to iterate from the beginning.
*
* @param parser The parser handle, must not be NULL
* @param params Array of SGR parameter values
* @param separators Optional array of separator characters (';' or ':'), or
* NULL
* @param len Number of parameters (and separators if provided)
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup sgr
*/
GHOSTTY_API GhosttyResult ghostty_sgr_set_params(GhosttySgrParser parser,
const uint16_t* params,
const char* separators,
size_t len);
/**
* Get the next SGR attribute.
*
* Parses and returns the next attribute from the parameter list.
* Call this function repeatedly until it returns false to process
* all attributes in the sequence.
*
* @param parser The parser handle, must not be NULL
* @param attr Pointer to store the next attribute
* @return true if an attribute was returned, false if no more attributes
*
* @ingroup sgr
*/
GHOSTTY_API bool ghostty_sgr_next(GhosttySgrParser parser, GhosttySgrAttribute* attr);
/**
* Get the full parameter list from an unknown SGR attribute.
*
* This function retrieves the full parameter list that was provided to the
* parser when an unknown attribute was encountered. Primarily useful in
* WebAssembly environments where accessing struct fields directly is difficult.
*
* @param unknown The unknown attribute data
* @param ptr Pointer to store the pointer to the parameter array (may be NULL)
* @return The length of the full parameter array
*
* @ingroup sgr
*/
GHOSTTY_API size_t ghostty_sgr_unknown_full(GhosttySgrUnknown unknown,
const uint16_t** ptr);
/**
* Get the partial parameter list from an unknown SGR attribute.
*
* This function retrieves the partial parameter list where parsing stopped
* when an unknown attribute was encountered. Primarily useful in WebAssembly
* environments where accessing struct fields directly is difficult.
*
* @param unknown The unknown attribute data
* @param ptr Pointer to store the pointer to the parameter array (may be NULL)
* @return The length of the partial parameter array
*
* @ingroup sgr
*/
GHOSTTY_API size_t ghostty_sgr_unknown_partial(GhosttySgrUnknown unknown,
const uint16_t** ptr);
/**
* Get the tag from an SGR attribute.
*
* This function extracts the tag that identifies which type of attribute
* this is. Primarily useful in WebAssembly environments where accessing
* struct fields directly is difficult.
*
* @param attr The SGR attribute
* @return The attribute tag
*
* @ingroup sgr
*/
GHOSTTY_API GhosttySgrAttributeTag ghostty_sgr_attribute_tag(GhosttySgrAttribute attr);
/**
* Get the value from an SGR attribute.
*
* This function returns a pointer to the value union from an SGR attribute. Use
* the tag to determine which field of the union is valid. Primarily useful in
* WebAssembly environments where accessing struct fields directly is difficult.
*
* @param attr Pointer to the SGR attribute
* @return Pointer to the attribute value union
*
* @ingroup sgr
*/
GHOSTTY_API GhosttySgrAttributeValue* ghostty_sgr_attribute_value(
GhosttySgrAttribute* attr);
#ifdef __wasm__
/**
* Allocate memory for an SGR attribute (WebAssembly only).
*
* This is a convenience function for WebAssembly environments to allocate
* memory for an SGR attribute structure that can be passed to ghostty_sgr_next.
*
* @return Pointer to the allocated attribute structure
*
* @ingroup wasm
*/
GHOSTTY_API GhosttySgrAttribute* ghostty_wasm_alloc_sgr_attribute(void);
/**
* Free memory for an SGR attribute (WebAssembly only).
*
* Frees memory allocated by ghostty_wasm_alloc_sgr_attribute.
*
* @param attr Pointer to the attribute structure to free
*
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_sgr_attribute(GhosttySgrAttribute* attr);
#endif
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_SGR_H */
+101
View File
@@ -0,0 +1,101 @@
/**
* @file size_report.h
*
* Size report encoding - encode terminal size reports into escape sequences.
*/
#ifndef GHOSTTY_VT_SIZE_REPORT_H
#define GHOSTTY_VT_SIZE_REPORT_H
/** @defgroup size_report Size Report Encoding
*
* Utilities for encoding terminal size reports into escape sequences,
* supporting in-band size reports (mode 2048) and XTWINOPS responses
* (CSI 14 t, CSI 16 t, CSI 18 t).
*
* ## Basic Usage
*
* Use ghostty_size_report_encode() to encode a size report into a
* caller-provided buffer. If the buffer is too small, the function
* returns GHOSTTY_OUT_OF_SPACE and sets the required size in the
* output parameter.
*
* ## Example
*
* @snippet c-vt-size-report/src/main.c size-report-encode
*
* @{
*/
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Size report style.
*
* Determines the output format for the terminal size report.
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** In-band size report (mode 2048): ESC [ 48 ; rows ; cols ; height ; width t */
GHOSTTY_SIZE_REPORT_MODE_2048 = 0,
/** XTWINOPS text area size in pixels: ESC [ 4 ; height ; width t */
GHOSTTY_SIZE_REPORT_CSI_14_T = 1,
/** XTWINOPS cell size in pixels: ESC [ 6 ; height ; width t */
GHOSTTY_SIZE_REPORT_CSI_16_T = 2,
/** XTWINOPS text area size in characters: ESC [ 8 ; rows ; cols t */
GHOSTTY_SIZE_REPORT_CSI_18_T = 3,
GHOSTTY_SIZE_REPORT_STYLE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySizeReportStyle;
/**
* Terminal size information for encoding size reports.
*/
typedef struct {
/** Terminal row count in cells. */
uint16_t rows;
/** Terminal column count in cells. */
uint16_t columns;
/** Width of a single terminal cell in pixels. */
uint32_t cell_width;
/** Height of a single terminal cell in pixels. */
uint32_t cell_height;
} GhosttySizeReportSize;
/**
* Encode a terminal size report into an escape sequence.
*
* Encodes a size report in the format specified by @p style into the
* provided buffer.
*
* If the buffer is too small, the function returns GHOSTTY_OUT_OF_SPACE
* and writes the required buffer size to @p out_written. The caller can
* then retry with a sufficiently sized buffer.
*
* @param style The size report format to encode
* @param size Terminal size information
* @param buf Output buffer to write the encoded sequence into (may be NULL)
* @param buf_len Size of the output buffer in bytes
* @param[out] out_written On success, the number of bytes written. On
* GHOSTTY_OUT_OF_SPACE, the required buffer size.
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
* is too small
*/
GHOSTTY_API GhosttyResult ghostty_size_report_encode(
GhosttySizeReportStyle style,
GhosttySizeReportSize size,
char* buf,
size_t buf_len,
size_t* out_written);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_SIZE_REPORT_H */
+139
View File
@@ -0,0 +1,139 @@
/**
* @file style.h
*
* Terminal cell style types.
*/
#ifndef GHOSTTY_VT_STYLE_H
#define GHOSTTY_VT_STYLE_H
#include <ghostty/vt/color.h>
#include <ghostty/vt/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup style Style
*
* Terminal cell style attributes.
*
* A style describes the visual attributes of a terminal cell, including
* foreground, background, and underline colors, as well as flags for
* bold, italic, underline, and other text decorations.
*
* @{
*/
/**
* Style identifier type.
*
* Used to look up the full style from a grid reference.
* Obtain this from a cell via GHOSTTY_CELL_DATA_STYLE_ID.
*
* @ingroup style
*/
typedef uint16_t GhosttyStyleId;
/**
* Style color tags.
*
* These values identify the type of color in a style color.
* Use the tag to determine which field in the color value union to access.
*
* @ingroup style
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_STYLE_COLOR_NONE = 0,
GHOSTTY_STYLE_COLOR_PALETTE = 1,
GHOSTTY_STYLE_COLOR_RGB = 2,
GHOSTTY_STYLE_COLOR_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyStyleColorTag;
/**
* Style color value union.
*
* Use the tag to determine which field is active.
*
* @ingroup style
*/
typedef union {
GhosttyColorPaletteIndex palette;
GhosttyColorRgb rgb;
uint64_t _padding;
} GhosttyStyleColorValue;
/**
* Style color (tagged union).
*
* A color used in a style attribute. Can be unset (none), a palette
* index, or a direct RGB value.
*
* @ingroup style
*/
typedef struct {
GhosttyStyleColorTag tag;
GhosttyStyleColorValue value;
} GhosttyStyleColor;
/**
* Terminal cell style.
*
* Describes the complete visual style for a terminal cell, including
* foreground, background, and underline colors, as well as text
* decoration flags. The underline field uses the same values as
* GhosttySgrUnderline.
*
* This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
*
* @ingroup style
*/
typedef struct {
size_t size;
GhosttyStyleColor fg_color;
GhosttyStyleColor bg_color;
GhosttyStyleColor underline_color;
bool bold;
bool italic;
bool faint;
bool blink;
bool inverse;
bool invisible;
bool strikethrough;
bool overline;
int underline; /**< One of GHOSTTY_SGR_UNDERLINE_* values */
} GhosttyStyle;
/**
* Get the default style.
*
* Initializes the style to the default values (no colors, no flags).
*
* @param style Pointer to the style to initialize
*
* @ingroup style
*/
GHOSTTY_API void ghostty_style_default(GhosttyStyle* style);
/**
* Check if a style is the default style.
*
* Returns true if all colors are unset and all flags are off.
*
* @param style Pointer to the style to check
* @return true if the style is the default style
*
* @ingroup style
*/
GHOSTTY_API bool ghostty_style_is_default(const GhosttyStyle* style);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_STYLE_H */
+210
View File
@@ -0,0 +1,210 @@
/**
* @file sys.h
*
* System interface - runtime-swappable implementations for external dependencies.
*/
#ifndef GHOSTTY_VT_SYS_H
#define GHOSTTY_VT_SYS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
/** @defgroup sys System Interface
*
* Runtime-swappable function pointers for operations that depend on
* external implementations (e.g. image decoding).
*
* These are process-global settings that must be configured at startup
* before any terminal functionality that depends on them is used.
* Setting these enables various optional features of the terminal. For
* example, setting a PNG decoder enables PNG image support in the Kitty
* Graphics Protocol.
*
* Use ghostty_sys_set() with a `GhosttySysOption` to install or clear
* an implementation. Passing NULL as the value clears the implementation
* and disables the corresponding feature.
*
* ## Example
*
* ### Defining a PNG decode callback
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-decode-png
*
* ### Installing the callback and sending a PNG image
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-main
*
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Result of decoding an image.
*
* The `data` buffer must be allocated through the allocator provided to
* the decode callback. The library takes ownership and will free it
* with the same allocator.
*/
typedef struct {
/** Image width in pixels. */
uint32_t width;
/** Image height in pixels. */
uint32_t height;
/** Pointer to the decoded RGBA pixel data. */
uint8_t* data;
/** Length of the pixel data in bytes. */
size_t data_len;
} GhosttySysImage;
/**
* Log severity levels for the log callback.
*/
typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_SYS_LOG_LEVEL_ERROR = 0,
GHOSTTY_SYS_LOG_LEVEL_WARNING = 1,
GHOSTTY_SYS_LOG_LEVEL_INFO = 2,
GHOSTTY_SYS_LOG_LEVEL_DEBUG = 3,
GHOSTTY_SYS_LOG_LEVEL_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySysLogLevel;
/**
* Callback type for logging.
*
* When installed, internal library log messages are delivered through
* this callback instead of being discarded. The embedder is responsible
* for formatting and routing log output.
*
* @p scope is the log scope name as UTF-8 bytes (e.g. "osc", "kitty").
* When the log is unscoped (default scope), @p scope_len is 0.
*
* All pointer arguments are only valid for the duration of the callback.
* The callback must be safe to call from any thread.
*
* @param userdata The userdata pointer set via GHOSTTY_SYS_OPT_USERDATA
* @param level The severity level of the log message
* @param scope Pointer to the scope name bytes
* @param scope_len Length of the scope name in bytes
* @param message Pointer to the log message bytes
* @param message_len Length of the log message in bytes
*/
typedef void (*GhosttySysLogFn)(
void* userdata,
GhosttySysLogLevel level,
const uint8_t* scope,
size_t scope_len,
const uint8_t* message,
size_t message_len);
/**
* Callback type for PNG decoding.
*
* Decodes raw PNG data into RGBA pixels. The output pixel data must be
* allocated through the provided allocator. The library takes ownership
* of the buffer and will free it with the same allocator.
*
* @param userdata The userdata pointer set via GHOSTTY_SYS_OPT_USERDATA
* @param allocator The allocator to use for the output pixel buffer
* @param data Pointer to the raw PNG data
* @param data_len Length of the raw PNG data in bytes
* @param[out] out On success, filled with the decoded image
* @return true on success, false on failure
*/
typedef bool (*GhosttySysDecodePngFn)(
void* userdata,
const GhosttyAllocator* allocator,
const uint8_t* data,
size_t data_len,
GhosttySysImage* out);
/**
* System option identifiers for ghostty_sys_set().
*/
typedef enum GHOSTTY_ENUM_TYPED {
/**
* Set the userdata pointer passed to all sys callbacks.
*
* Input type: void* (or NULL)
*/
GHOSTTY_SYS_OPT_USERDATA = 0,
/**
* Set the PNG decode function.
*
* When set, the terminal can accept PNG images via the Kitty
* Graphics Protocol. When cleared (NULL value), PNG decoding is
* unsupported and PNG image data will be rejected.
*
* Input type: GhosttySysDecodePngFn (function pointer, or NULL)
*/
GHOSTTY_SYS_OPT_DECODE_PNG = 1,
/**
* Set the log callback.
*
* When set, internal library log messages are delivered to this
* callback. When cleared (NULL value), log messages are silently
* discarded.
*
* Use ghostty_sys_log_stderr as a convenience callback that
* writes formatted messages to stderr.
*
* Which log levels are emitted depends on the build mode of the
* library and is not configurable at runtime. Debug builds emit
* all levels (debug and above). Release builds emit info and
* above; debug-level messages are compiled out entirely and will
* never reach the callback.
*
* Input type: GhosttySysLogFn (function pointer, or NULL)
*/
GHOSTTY_SYS_OPT_LOG = 2,
GHOSTTY_SYS_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySysOption;
/**
* Set a system-level option.
*
* Configures a process-global implementation function. These should be
* set once at startup before using any terminal functionality that
* depends on them.
*
* @param option The option to set
* @param value Pointer to the value (type depends on the option),
* or NULL to clear it
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
* option is not recognized
*/
GHOSTTY_API GhosttyResult ghostty_sys_set(GhosttySysOption option,
const void* value);
/**
* Built-in log callback that writes to stderr.
*
* Formats each message as "[level](scope): message\n".
* Can be passed directly to ghostty_sys_set():
*
* @code
* ghostty_sys_set(GHOSTTY_SYS_OPT_LOG, &ghostty_sys_log_stderr);
* @endcode
*/
GHOSTTY_API void ghostty_sys_log_stderr(void* userdata,
GhosttySysLogLevel level,
const uint8_t* scope,
size_t scope_len,
const uint8_t* message,
size_t message_len);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_SYS_H */
File diff suppressed because it is too large Load Diff
+335
View File
@@ -0,0 +1,335 @@
/**
* @file types.h
*
* Common types, macros, and utilities for libghostty-vt.
*/
#ifndef GHOSTTY_VT_TYPES_H
#define GHOSTTY_VT_TYPES_H
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
// Symbol visibility for shared library builds. On Windows, functions
// are exported from the DLL when building and imported when consuming.
// On other platforms with GCC/Clang, functions are marked with default
// visibility so they remain accessible when the library is built with
// -fvisibility=hidden. For static library builds, define GHOSTTY_STATIC
// before including this header to make this a no-op.
#ifndef GHOSTTY_API
#if defined(GHOSTTY_STATIC)
#define GHOSTTY_API
#elif defined(_WIN32) || defined(_WIN64)
#ifdef GHOSTTY_BUILD_SHARED
#define GHOSTTY_API __declspec(dllexport)
#else
#define GHOSTTY_API __declspec(dllimport)
#endif
#elif defined(__GNUC__) && __GNUC__ >= 4
#define GHOSTTY_API __attribute__((visibility("default")))
#else
#define GHOSTTY_API
#endif
#endif
/**
* Enum int-sizing helpers.
*
* The Zig side backs all C enums with c_int, so the C declarations
* must use int as their underlying type to maintain ABI compatibility.
*
* C23 (detected via __STDC_VERSION__ >= 202311L) supports explicit
* enum underlying types with `enum : int { ... }`. For pre-C23
* compilers, which are free to choose any type that can represent
* all values (C11 §6.7.2.2), we add an INT_MAX sentinel as the last
* entry to force the compiler to use int.
*
* INT_MAX is used rather than a fixed constant like 0xFFFFFFFF
* because enum constants must have type int (which is signed).
* Values above INT_MAX overflow signed int and are a constraint
* violation in standard C; compilers that accept them interpret them
* as negative values via two's complement, which can collide with
* legitimate negative enum values.
*
* Usage:
* @code
* typedef enum GHOSTTY_ENUM_TYPED {
* FOO_A = 0,
* FOO_B = 1,
* FOO_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
* } Foo;
* @endcode
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
#define GHOSTTY_ENUM_TYPED : int
#else
#define GHOSTTY_ENUM_TYPED
#endif
#define GHOSTTY_ENUM_MAX_VALUE INT_MAX
/**
* Result codes for libghostty-vt operations.
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Operation completed successfully */
GHOSTTY_SUCCESS = 0,
/** Operation failed due to failed allocation */
GHOSTTY_OUT_OF_MEMORY = -1,
/** Operation failed due to invalid value */
GHOSTTY_INVALID_VALUE = -2,
/** Operation failed because the provided buffer was too small */
GHOSTTY_OUT_OF_SPACE = -3,
/** The requested value has no value */
GHOSTTY_NO_VALUE = -4,
GHOSTTY_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyResult;
/* ---- Opaque handles ---- */
/**
* Opaque handle to a terminal instance.
*
* @ingroup terminal
*/
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(). If the terminal that created it is freed
* first, the handle remains valid only for tracked-grid-ref APIs: it reports no
* value and can still be freed.
*
* @ingroup grid_ref
*/
typedef struct GhosttyTrackedGridRefImpl* GhosttyTrackedGridRef;
/**
* Opaque handle to a Kitty graphics image storage.
*
* Obtained via ghostty_terminal_get() with
* GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS. The pointer is borrowed from
* the terminal and remains valid until the next mutating terminal call
* (e.g. ghostty_terminal_vt_write() or ghostty_terminal_reset()).
*
* @ingroup kitty_graphics
*/
typedef struct GhosttyKittyGraphicsImpl* GhosttyKittyGraphics;
/**
* Opaque handle to a Kitty graphics image.
*
* Obtained via ghostty_kitty_graphics_image() with an image ID. The
* pointer is borrowed from the storage and remains valid until the next
* mutating terminal call.
*
* @ingroup kitty_graphics
*/
typedef const struct GhosttyKittyGraphicsImageImpl* GhosttyKittyGraphicsImage;
/**
* Opaque handle to a Kitty graphics placement iterator.
*
* @ingroup kitty_graphics
*/
typedef struct GhosttyKittyGraphicsPlacementIteratorImpl* GhosttyKittyGraphicsPlacementIterator;
/**
* Opaque handle to a render state instance.
*
* @ingroup render
*/
typedef struct GhosttyRenderStateImpl* GhosttyRenderState;
/**
* Opaque handle to a render-state row iterator.
*
* @ingroup render
*/
typedef struct GhosttyRenderStateRowIteratorImpl* GhosttyRenderStateRowIterator;
/**
* Opaque handle to render-state row cells.
*
* @ingroup render
*/
typedef struct GhosttyRenderStateRowCellsImpl* GhosttyRenderStateRowCells;
/**
* Opaque handle to an SGR parser instance.
*
* This handle represents an SGR (Select Graphic Rendition) parser that can
* be used to parse SGR sequences and extract individual text attributes.
*
* @ingroup sgr
*/
typedef struct GhosttySgrParserImpl* GhosttySgrParser;
/**
* Opaque handle to a formatter instance.
*
* @ingroup formatter
*/
typedef struct GhosttyFormatterImpl* GhosttyFormatter;
/**
* Opaque handle to an OSC parser instance.
*
* This handle represents an OSC (Operating System Command) parser that can
* be used to parse the contents of OSC sequences.
*
* @ingroup osc
*/
typedef struct GhosttyOscParserImpl* GhosttyOscParser;
/**
* Opaque handle to a single OSC command.
*
* This handle represents a parsed OSC (Operating System Command) command.
* The command can be queried for its type and associated data.
*
* @ingroup osc
*/
typedef struct GhosttyOscCommandImpl* GhosttyOscCommand;
/* ---- Common value types ---- */
/**
* Terminal content output format.
*
* @ingroup formatter
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Plain text (no escape sequences). */
GHOSTTY_FORMATTER_FORMAT_PLAIN,
/** VT sequences preserving colors, styles, URLs, etc. */
GHOSTTY_FORMATTER_FORMAT_VT,
/** HTML with inline styles. */
GHOSTTY_FORMATTER_FORMAT_HTML,
GHOSTTY_FORMATTER_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyFormatterFormat;
/**
* A borrowed byte string (pointer + length).
*
* The memory is not owned by this struct. The pointer is only valid
* for the lifetime documented by the API that produces or consumes it.
*/
typedef struct {
/** Pointer to the string bytes. */
const uint8_t* ptr;
/** Length of the string in bytes. */
size_t len;
} GhosttyString;
/**
* A caller-provided byte buffer.
*
* APIs that write to this type use `len` for the number of bytes written on
* GHOSTTY_SUCCESS and the required byte capacity on GHOSTTY_OUT_OF_SPACE.
*/
typedef struct {
/** Destination buffer for bytes. May be NULL when cap is 0 to query required size. */
uint8_t* ptr;
/** Capacity of ptr in bytes. */
size_t cap;
/** Bytes written on success, or required byte capacity on GHOSTTY_OUT_OF_SPACE. */
size_t len;
} GhosttyBuffer;
/**
* A surface-space position in pixels.
*
* This is not a terminal grid coordinate. It represents an x/y position in the
* rendered surface coordinate space, with (0, 0) at the top-left of the
* surface.
*/
typedef struct {
/** X position in surface pixels. */
double x;
/** Y position in surface pixels. */
double y;
} GhosttySurfacePosition;
/**
* A borrowed list of Unicode scalar values.
*
* Values are encoded as uint32_t scalar values. The memory is not owned by this
* struct. The pointer is only valid for the lifetime documented by the API that
* consumes or produces it.
*
* APIs may document special handling for NULL + len 0, such as “use defaults”.
*/
typedef struct {
/** Pointer to Unicode scalar values. */
const uint32_t* ptr;
/** Number of entries in ptr. */
size_t len;
} GhosttyCodepoints;
/**
* Initialize a sized struct to zero and set its size field.
*
* Sized structs use a `size` field as the first member for ABI
* compatibility. This macro zero-initializes the struct and sets the
* size field to `sizeof(type)`, which allows the library to detect
* which version of the struct the caller was compiled against.
*
* @param type The struct type to initialize
* @return A zero-initialized struct with the size field set
*
* Example:
* @code
* GhosttyFormatterTerminalOptions opts = GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
* opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
* opts.trim = true;
* @endcode
*/
#define GHOSTTY_INIT_SIZED(type) \
((type){ .size = sizeof(type) })
/**
* Return a pointer to a null-terminated JSON string describing the
* layout of every C API struct for the current target.
*
* This is primarily useful for language bindings that can't easily
* set C struct fields and need to do so via byte offsets. For example,
* WebAssembly modules can't share struct definitions with the host.
*
* Example (abbreviated):
* @code{.json}
* {
* "GhosttyMouseEncoderSize": {
* "size": 40,
* "align": 8,
* "fields": {
* "size": { "offset": 0, "size": 8, "type": "u64" },
* "screen_width": { "offset": 8, "size": 4, "type": "u32" },
* "screen_height": { "offset": 12, "size": 4, "type": "u32" },
* "cell_width": { "offset": 16, "size": 4, "type": "u32" },
* "cell_height": { "offset": 20, "size": 4, "type": "u32" },
* "padding_top": { "offset": 24, "size": 4, "type": "u32" },
* "padding_bottom": { "offset": 28, "size": 4, "type": "u32" },
* "padding_right": { "offset": 32, "size": 4, "type": "u32" },
* "padding_left": { "offset": 36, "size": 4, "type": "u32" }
* }
* }
* }
* @endcode
*
* The returned pointer is valid for the lifetime of the process.
*
* @return Pointer to the null-terminated JSON string.
*/
GHOSTTY_API const char *ghostty_type_json(void);
#endif /* GHOSTTY_VT_TYPES_H */
+154
View File
@@ -0,0 +1,154 @@
/**
* @file unicode.h
*
* Unicode utilities - codepoint properties matching the terminal's
* text layout semantics.
*/
#ifndef GHOSTTY_VT_UNICODE_H
#define GHOSTTY_VT_UNICODE_H
/** @defgroup unicode Unicode Utilities
*
* Unicode codepoint properties matching the terminal's text layout
* semantics.
*
* ## Basic Usage
*
* Use ghostty_unicode_codepoint_width() to determine how many terminal
* grid cells a codepoint occupies, using the exact same width table the
* terminal itself uses when laying out printed text. Use
* ghostty_unicode_grapheme_width() to segment and measure full grapheme
* clusters with the same rules the terminal uses when mode 2027 is
* enabled. These functions are useful for predicting column layout of
* text that has not yet been written to the terminal, such as IME
* preedit (composition) overlays.
*
* @{
*/
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns the terminal display width of a Unicode codepoint in
* terminal grid cells: 0, 1, or 2.
*
* This is the same width table the terminal itself uses when laying
* out printed text, so callers can predict column layout (e.g. IME
* preedit overlays) that exactly matches what the terminal will do
* when the text is actually written to it.
*
* Semantics:
* - Returns 0 for zero-width codepoints: C0/C1 control characters,
* nonspacing and enclosing combining marks, default-ignorable
* codepoints (ZWJ, ZWNJ, variation selectors, etc.), and
* surrogate codepoints.
* - Returns 2 for wide codepoints: East Asian Wide/Fullwidth
* (including emoji with default emoji presentation) and regional
* indicators. Width is clamped to 2 (e.g. the three-em dash).
* - Returns 1 for everything else, including invalid codepoints
* beyond U+10FFFF (this function is total; it never fails).
*
* This operates on a single codepoint only and therefore cannot account
* for grapheme-cluster-level width rules (VS16 emoji presentation,
* combining sequences, etc.). For cluster-accurate widths, use
* ghostty_unicode_grapheme_width(). Summing per-codepoint widths is only
* correct when mode 2027 (grapheme clustering) is disabled.
*
* This function is pure, allocates nothing, and is thread-safe.
*
* @param cp The Unicode codepoint to measure
* @return Display width in cells: 0, 1, or 2
*/
GHOSTTY_API uint8_t ghostty_unicode_codepoint_width(uint32_t cp);
/**
* Measures the terminal display width of the first grapheme cluster in a
* sequence of Unicode codepoints.
*
* This uses the exact same grapheme segmentation and cluster width rules
* the terminal itself uses when printing text with grapheme clustering
* enabled (mode 2027), so callers can predict column layout (e.g. IME
* preedit overlays) that exactly matches what the terminal will do when
* the text is actually written to it. Unlike
* ghostty_unicode_codepoint_width(), this accounts for cluster-level
* rules: emoji variation selectors, ZWJ sequences, combining marks, and
* skin tone modifiers.
*
* Reads codepoints from cps until the terminal would consider the
* grapheme cluster complete, stores the cluster's total width in cells
* (0, 1, or 2) into width (which may be NULL if only segmentation is
* desired), and returns the number of codepoints consumed. Returns 0 if
* and only if len is 0; otherwise consumes at least one codepoint. Measure
* a whole string by calling in a loop:
*
* @code
* size_t total = 0;
* for (size_t i = 0; i < len;) {
* uint8_t width;
* i += ghostty_unicode_grapheme_width(cps + i, len - i, &width);
* total += width;
* }
* @endcode
*
* This is not a streaming API. The provided sequence must contain a
* complete first grapheme cluster, or the logical end of the string. If
* input arrives in chunks, keep buffering while this function consumes all
* available codepoints (return value == len) and the stream may still
* continue; a later codepoint could still extend the cluster and change
* its width.
*
* Width semantics, matching the terminal with mode 2027 enabled:
* - The cluster starts at the width of its first codepoint, as returned by
* ghostty_unicode_codepoint_width().
* - VS16 (U+FE0F) forces the cluster wide (2) and VS15 (U+FE0E) forces it
* narrow (1), but only when the immediately preceding codepoint in the
* cluster is a valid emoji variation sequence base (per Unicode
* emoji-variation-sequences.txt). Invalid variation selectors are
* ignored entirely.
* - Any other continuation codepoint that contributes to grapheme width
* forces the cluster wide (2). Note this means cluster width is NOT the
* maximum of per-codepoint widths: some continuation marks have narrow
* codepoint width yet still widen the cluster.
*
* Mode dependence: this models mode 2027 (grapheme clustering) enabled,
* which is Ghostty's recommended configuration. When mode 2027 is
* disabled, clusters never combine and variation selectors never change
* width; predict layout in that case by summing
* ghostty_unicode_codepoint_width() over each codepoint instead.
*
* Edge cases:
* - Codepoints beyond U+10FFFF consume one codepoint, have width 1, and
* are always cluster boundaries. This function is total; it never fails.
* - Control characters (C0/C1, CR, LF) are never printed through the
* terminal's text path; passing them here returns an unspecified (but
* stable and bounded) result.
* - A cluster whose first codepoint is zero-width (e.g. a lone combining
* mark) is malformed at a cell start; the terminal may attach it to
* earlier screen content. This function reports the fold result for the
* sequence in isolation (typically 0).
*
* This function is pure, allocates nothing, and is thread-safe.
*
* @param cps Pointer to codepoints (may be NULL only when len is 0)
* @param len Number of codepoints available
* @param width Out: cluster display width in cells (0-2); may be NULL
* @return Number of codepoints in the first grapheme cluster
*/
GHOSTTY_API size_t ghostty_unicode_grapheme_width(const uint32_t *cps,
size_t len,
uint8_t *width);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_UNICODE_H */
+160
View File
@@ -0,0 +1,160 @@
/**
* @file wasm.h
*
* WebAssembly utility functions for libghostty-vt.
*/
#ifndef GHOSTTY_VT_WASM_H
#define GHOSTTY_VT_WASM_H
#ifdef __wasm__
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
/** @defgroup wasm WebAssembly Utilities
*
* Convenience functions for allocating various types in WebAssembly builds.
* **These are only available the libghostty-vt wasm module.**
*
* Ghostty relies on pointers to various types for ABI compatibility, and
* creating those pointers in Wasm can be tedious. These functions provide
* a purely additive set of utilities that simplify memory management in
* Wasm environments without changing the core C library API.
*
* @note These functions always use the default allocator. If you need
* custom allocation strategies, you should allocate types manually using
* your custom allocator. This is a very rare use case in the WebAssembly
* world so these are optimized for simplicity.
*
* ## Example Usage
*
* Here's a simple example of using the Wasm utilities with the key encoder:
*
* @code
* const { exports } = wasmInstance;
* const view = new DataView(wasmMemory.buffer);
*
* // Create key encoder
* const encoderPtr = exports.ghostty_wasm_alloc_opaque();
* exports.ghostty_key_encoder_new(null, encoderPtr);
* const encoder = view.getUint32(encoder, true);
*
* // Configure encoder with Kitty protocol flags
* const flagsPtr = exports.ghostty_wasm_alloc_u8();
* view.setUint8(flagsPtr, 0x1F);
* exports.ghostty_key_encoder_setopt(encoder, 5, flagsPtr);
*
* // Allocate output buffer and size pointer
* const bufferSize = 32;
* const bufPtr = exports.ghostty_wasm_alloc_u8_array(bufferSize);
* const writtenPtr = exports.ghostty_wasm_alloc_usize();
*
* // Encode the key event
* exports.ghostty_key_encoder_encode(
* encoder, eventPtr, bufPtr, bufferSize, writtenPtr
* );
*
* // Read encoded output
* const bytesWritten = view.getUint32(writtenPtr, true);
* const encoded = new Uint8Array(wasmMemory.buffer, bufPtr, bytesWritten);
* @endcode
*
* @remark The code above is pretty ugly! This is the lowest level interface
* to the libghostty-vt Wasm module. In practice, this should be wrapped
* in a higher-level API that abstracts away all this.
*
* @{
*/
/**
* Allocate an opaque pointer. This can be used for any opaque pointer
* types such as GhosttyKeyEncoder, GhosttyKeyEvent, etc.
*
* @return Pointer to allocated opaque pointer, or NULL if allocation failed
* @ingroup wasm
*/
GHOSTTY_API void** ghostty_wasm_alloc_opaque(void);
/**
* Free an opaque pointer allocated by ghostty_wasm_alloc_opaque().
*
* @param ptr Pointer to free, or NULL (NULL is safely ignored)
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_opaque(void **ptr);
/**
* Allocate an array of uint8_t values.
*
* @param len Number of uint8_t elements to allocate
* @return Pointer to allocated array, or NULL if allocation failed
* @ingroup wasm
*/
GHOSTTY_API uint8_t* ghostty_wasm_alloc_u8_array(size_t len);
/**
* Free an array allocated by ghostty_wasm_alloc_u8_array().
*
* @param ptr Pointer to the array to free, or NULL (NULL is safely ignored)
* @param len Length of the array (must match the length passed to alloc)
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_u8_array(uint8_t *ptr, size_t len);
/**
* Allocate an array of uint16_t values.
*
* @param len Number of uint16_t elements to allocate
* @return Pointer to allocated array, or NULL if allocation failed
* @ingroup wasm
*/
GHOSTTY_API uint16_t* ghostty_wasm_alloc_u16_array(size_t len);
/**
* Free an array allocated by ghostty_wasm_alloc_u16_array().
*
* @param ptr Pointer to the array to free, or NULL (NULL is safely ignored)
* @param len Length of the array (must match the length passed to alloc)
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_u16_array(uint16_t *ptr, size_t len);
/**
* Allocate a single uint8_t value.
*
* @return Pointer to allocated uint8_t, or NULL if allocation failed
* @ingroup wasm
*/
GHOSTTY_API uint8_t* ghostty_wasm_alloc_u8(void);
/**
* Free a uint8_t allocated by ghostty_wasm_alloc_u8().
*
* @param ptr Pointer to free, or NULL (NULL is safely ignored)
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_u8(uint8_t *ptr);
/**
* Allocate a single size_t value.
*
* @return Pointer to allocated size_t, or NULL if allocation failed
* @ingroup wasm
*/
GHOSTTY_API size_t* ghostty_wasm_alloc_usize(void);
/**
* Free a size_t allocated by ghostty_wasm_alloc_usize().
*
* @param ptr Pointer to free, or NULL (NULL is safely ignored)
* @ingroup wasm
*/
GHOSTTY_API void ghostty_wasm_free_usize(size_t *ptr);
/** @} */
#endif /* __wasm__ */
#endif /* GHOSTTY_VT_WASM_H */
+7
View File
@@ -0,0 +1,7 @@
// This makes Ghostty available to the XCode build for the macOS app.
// We append "Kit" to it not to be cute, but because targets have to have
// unique names and we use Ghostty for other things.
module GhosttyKit {
umbrella header "ghostty.h"
export *
}