libghostty
Loading...
Searching...
No Matches
libghostty-vt - Virtual Terminal Emulator Library

libghostty-vt is a C library which implements a modern terminal emulator, extracted from the Ghostty 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.

Stability

libghostty-vt is released separately from Ghostty, with its own version numbers.

Until 1.0, each minor release may change the API (the functions and types in these headers) and the ABI (how compiled programs call the library). A program built against 0.1 may not compile against 0.2, or may not run with a 0.2 library installed. Patch releases, such as 0.1.1, never break programs built against an earlier 0.1 release.

From 1.0, only a new major version can break programs, and it comes with a new shared library name such as libghostty-vt.so.2. Minor and patch releases only add to the library.

Every 0.x release uses the same shared library name, so the system can't stop a program built against 0.1 from loading a 0.2 library. A program can check this itself when it starts, by comparing the library's version with the version of the headers it was compiled against:

// Returns true if the library loaded at runtime can be used with the
// headers this program was compiled against.
bool library_is_compatible() {
size_t major = 0;
size_t minor = 0;
// Until 1.0, any minor release may change the ABI, so the minor
// versions must match exactly.
return major == 0 && minor == GHOSTTY_VT_VERSION_MINOR;
}
// From 1.0, the major versions must match. The library may be newer
// than the headers but not older, because an older library is missing
// the functions that newer headers declare.
return major == GHOSTTY_VT_VERSION_MAJOR &&
}

See Version for the version macros and more examples.

API Reference

The API is organized into the following groups:

  • Terminal - Complete terminal emulator state and rendering
  • Render State - Incremental render state updates for custom renderers
  • Formatter - Format terminal content as plain text, VT sequences, or HTML
  • Terminal Snapshot - Encode and incrementally restore terminal state
  • Search - Search terminal contents, including scrollback
  • OSC Parser - Parse OSC (Operating System Command) sequences
  • SGR Parser - Parse SGR (Select Graphic Rendition) sequences
  • Paste - Paste into a terminal, validate and encode paste data
  • Unicode Utilities - Codepoint properties for text layout
  • Version - Check the version of the headers and the library
  • Build Info - Query compile-time build configuration
  • Memory Management - Memory management and custom allocators
  • Byte-stream I/O - Reusable synchronous reader and writer callbacks
  • WebAssembly Utilities - WebAssembly convenience functions

Encoding related APIs:

Reading and Writing Values by Key

Much of the API reads and writes values through a small set of functions that take a key. The key is an enum value that names the value you want, and the value itself is passed through a void * whose type is documented on each key. For example, this reads the terminal's column count:

uint16_t cols = 0;
GhosttyResult result =
GHOSTTY_API GhosttyResult ghostty_terminal_get(GhosttyTerminal terminal, GhosttyTerminalData data, void *out)
@ GHOSTTY_TERMINAL_DATA_COLS
Definition terminal.h:2872
GhosttyResult
Definition types.h:137

The same pattern is used by every function whose name ends in _get, _set or _get_multi, such as ghostty_terminal_get(), ghostty_render_state_set() and ghostty_key_encoder_set().

Newer Headers, Older Libraries

New keys are added over time. A program built with a newer header can end up running against an older copy of the library, for example when the library is installed separately as a shared library. If you pass a key that the loaded library does not know, the call returns GHOSTTY_UNSUPPORTED and does not touch your output. This works the same way in debug and release builds of the library.

This lets you use a newer key when it is available and fall back when it is not. In this example, imagine that GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING was added in a later release than the library your program loads:

bool blinking = false;
&blinking)) {
break;
// This library predates the key. Use a sensible default instead.
blinking = true;
break;
default:
// A real error, such as a NULL state. Handle it as usual.
return;
}
GHOSTTY_API GhosttyResult ghostty_render_state_get(GhosttyRenderState state, GhosttyRenderStateData data, void *out)
@ GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING
Definition render.h:608
@ GHOSTTY_SUCCESS
Definition types.h:139
@ GHOSTTY_UNSUPPORTED
Definition types.h:179

GHOSTTY_UNSUPPORTED and GHOSTTY_INVALID_VALUE mean different things. GHOSTTY_UNSUPPORTED means the library does not know the key at all. GHOSTTY_INVALID_VALUE means the library knows the key, but something you passed with it is wrong, such as a NULL pointer or an enum value that is out of range.

The same check applies to enum values you pass as plain arguments or inside option values, such as a GhosttyKeyAction or the tag of a GhosttyPoint. A value the library does not recognize returns GHOSTTY_INVALID_VALUE and leaves the object unchanged.

Reading Several Values at Once

The _get_multi functions read several keys in one call, which helps when each call is expensive, such as across FFI. They process keys in order and stop at the first one that fails. Values for the keys before it have already been written, and out_written receives the index of the key that failed. That makes it easy to see exactly which key the library rejected:

};
uint16_t cols = 0, rows = 0;
void *values[] = { &cols, &rows };
size_t written = 0;
GhosttyResult result =
ghostty_terminal_get_multi(terminal, 2, keys, values, &written);
if (result != GHOSTTY_SUCCESS) {
// keys[written] failed. Every value before it is valid.
}
GHOSTTY_API GhosttyResult ghostty_terminal_get_multi(GhosttyTerminal terminal, size_t count, const GhosttyTerminalData *keys, void **values, size_t *out_written)
GhosttyTerminalData
Definition terminal.h:2863
@ GHOSTTY_TERMINAL_DATA_ROWS
Definition terminal.h:2879

Sized Structs

Some structs begin with a size_t size field. These are called sized structs. The size field records how large the struct was in the header your program was compiled against. This lets later releases add fields to the end of a struct without breaking programs built with older headers.

Initialize every sized struct with GHOSTTY_INIT_SIZED(). It sets size for you and sets every other field to zero. Then fill in the fields you need:

opts.ref = ref;
GhosttySelection selection;
GhosttyResult result =
ghostty_terminal_select_line(terminal, &opts, &selection);
GHOSTTY_API GhosttyResult ghostty_terminal_select_line(GhosttyTerminal terminal, const GhosttyTerminalSelectLineOptions *options, GhosttySelection *out_selection)
#define GHOSTTY_INIT_SIZED(type)
Definition types.h:538

Language bindings that cannot use a C macro can call ghostty_sized_init() instead.

Zero is always the default value of a field. A field you leave at zero behaves the same way the library did before that field existed. This is why initializing with GHOSTTY_INIT_SIZED() matters: it keeps every field you did not set, including fields added in later releases, at its default.

Newer Headers, Older Libraries

Your program and the library it loads may come from different releases. The size field lets the library handle either case:

  • When you pass a struct to the library, such as an options struct or a clipboard reply, and the library is newer than your header, the library reads the fields your struct does not have as zero.
  • When the library is older than your header, it accepts your struct as long as every field it does not know about is still zero. If you set one of those fields, the call returns GHOSTTY_INVALID_VALUE instead of silently ignoring a setting it cannot honor.
  • When the library fills a struct for you, such as GhosttyRenderStateCursor, it writes only the fields that fit within size. Fields the library does not know about keep the value you gave them, which is zero if you used GHOSTTY_INIT_SIZED().

In every case, a size smaller than the struct has ever been returns GHOSTTY_INVALID_VALUE. Clipboard replies are the one exception. The reply function has no return value, so a reply with an invalid size is treated as unsupported instead.

Here is how a program can use a newer field when the library supports it and fall back when it does not. Imagine that semantic_prompt_boundary was added in a later release than the library your program loads:

opts.ref = ref;
GhosttySelection selection;
GhosttyResult result =
ghostty_terminal_select_line(terminal, &opts, &selection);
if (result == GHOSTTY_INVALID_VALUE) {
// This library may predate semantic_prompt_boundary. Try again
// without it.
result = ghostty_terminal_select_line(terminal, &opts, &selection);
}
@ GHOSTTY_INVALID_VALUE
Definition types.h:150

Output Buffers

Functions that write bytes for you take a buffer, its length and an out_written pointer. Pass NULL with a length of 0 to learn the size needed. When there is nothing to write, the call returns GHOSTTY_SUCCESS and sets out_written to 0, even for a size query. When the buffer is too small, the call returns GHOSTTY_OUT_OF_SPACE and sets out_written to the size needed. The contents of the buffer are then unspecified unless the function says otherwise, so discard them and retry with a larger buffer.

Threads

The library creates no threads, and every callback runs on the thread whose call triggered it. Calls on one handle, and on any handle borrowed from it, must not run at the same time unless a function's documentation says otherwise. Handles that share nothing can be used on different threads.

Optional Features

Some parts of libghostty-vt are optional. A program that only draws a terminal doesn't need search or snapshots, for example, so the library can be built without them to make it smaller. Features are chosen when the library is built, with the -Dvt-features build option.

Every function in these headers exists in every build, whichever features it includes. A program links and loads the same way against any build. When it calls a function whose feature was left out, the function does nothing and returns GHOSTTY_UNSUPPORTED.

Feature Functions
snapshot ghostty_snapshot_*
formatter ghostty_formatter_*
selection ghostty_terminal_select_*, ghostty_terminal_selection_*, ghostty_selection_gesture_*
search ghostty_search_*
render_state ghostty_render_state_*
input_encode ghostty_key_event_*, ghostty_key_encoder_*, ghostty_mouse_event_*, ghostty_mouse_encoder_*, ghostty_focus_encode(), ghostty_paste_*, ghostty_terminal_paste()
color ghostty_color_*
grid_introspection ghostty_grid_ref_*, ghostty_tracked_grid_ref_*, ghostty_cell_get*, ghostty_row_get*, ghostty_terminal_grid_ref_track()
glyph_protocol None. It lets applications register custom glyphs with Ghostty's glyph protocol.
kitty_graphics ghostty_kitty_graphics_*, and the Kitty options and data of ghostty_terminal_set() and ghostty_terminal_get()

A few functions depend on two features:

Kitty graphics need a clock, so builds for targets without an operating system, such as wasm32-freestanding, never include kitty_graphics.

Checking for a Feature

To find out up front, for example to hide a menu item, ask ghostty_build_info() with the feature's key. Each feature has a GHOSTTY_BUILD_INFO_FEATURE_* key, except Kitty graphics, which uses GHOSTTY_BUILD_INFO_KITTY_GRAPHICS:

bool has_search = false;
if (!has_search) {
// Hide the find bar.
}
GHOSTTY_API GhosttyResult ghostty_build_info(GhosttyBuildInfo data, void *out)
@ GHOSTTY_BUILD_INFO_FEATURE_SEARCH
Definition build_info.h:164

You can also just call the function and check its result. A function that creates a handle sets the handle to NULL, so cleanup code that frees it still works:

GhosttySearch search = NULL;
GhosttyResult result = ghostty_search_new(NULL, &search, terminal);
if (result == GHOSTTY_UNSUPPORTED) {
// This library was built without search. search is NULL.
}
GHOSTTY_API GhosttyResult ghostty_search_new(const GhosttyAllocator *allocator, GhosttySearch *out_search, GhosttyTerminal terminal)
struct GhosttySearchImpl * GhosttySearch
Definition types.h:281

Functions Without a Result

A function that doesn't return a GhosttyResult can't report GHOSTTY_UNSUPPORTED. When its feature is left out, it returns a fixed value instead:

In practice these values rarely matter. Most of these functions take a handle that could only come from a _new function of the same feature, and that function returned GHOSTTY_UNSUPPORTED.

Examples

Complete working examples: