![]() |
libghostty
|
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.
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:
See Version for the version macros and more examples.
The API is organized into the following groups:
Encoding related APIs:
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:
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().
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:
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.
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:
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:
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.
Your program and the library it loads may come from different releases. The size field lets the library handle either case:
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:
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.
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.
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.
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:
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:
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.
Complete working examples: