aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/include
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/include
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/include')
-rw-r--r--vendor/libghostty-vt/include/ghostty.h97
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt.h23
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/allocator.h16
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/device.h2
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/formatter.h27
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/io.h151
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/key.h3
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/kitty_graphics.h18
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/modes.h2
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/mouse.h3
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/osc.h4
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/paste.h182
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/point.h2
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/render.h149
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/screen.h34
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/search.h501
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/selection.h25
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/sgr.h25
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/snapshot.h569
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/sys.h33
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/terminal.h1112
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/types.h135
-rw-r--r--vendor/libghostty-vt/include/ghostty/vt/wasm.h168
23 files changed, 2935 insertions, 346 deletions
diff --git a/vendor/libghostty-vt/include/ghostty.h b/vendor/libghostty-vt/include/ghostty.h
index 72bbb57a..518af3ff 100644
--- a/vendor/libghostty-vt/include/ghostty.h
+++ b/vendor/libghostty-vt/include/ghostty.h
@@ -1,10 +1,14 @@
-// Ghostty embedding API. The documentation for the embedding API is
-// only within the Zig source files that define the implementations. This
-// isn't meant to be a general purpose embedding API (yet) so there hasn't
-// been documentation or example work beyond that.
+// Ghostty's internal embedder API, a.k.a. "libghostty-internal".
//
-// The only consumer of this API is the macOS app, but the API is built to
-// be more general purpose.
+// The only consumer of this API is the macOS app, and while it is fairly
+// comprehensive, it is tailored to the needs of the macOS app and not designed
+// for external use, hence why most functions are undocumented and some are
+// macOS-specific (e.g. ones dealing with the Metal graphics API).
+//
+// External embedders should instead use `libghostty-vt` or other related
+// packages, which are extensively documented and designed from the ground up
+// to be used in other software. Header files for which can be found in
+// `include/ghostty/`.
#ifndef GHOSTTY_H
#define GHOSTTY_H
@@ -71,19 +75,56 @@ typedef enum {
typedef enum {
GHOSTTY_CLIPBOARD_STANDARD,
GHOSTTY_CLIPBOARD_SELECTION,
+ GHOSTTY_CLIPBOARD_PRIMARY,
} ghostty_clipboard_e;
+// One representation of clipboard contents. The data is binary-safe with
+// an explicit length; it is not necessarily null-terminated.
typedef struct {
const char *mime;
const char *data;
+ size_t len;
} ghostty_clipboard_content_s;
+// The payload for completing a clipboard read request. See
+// ghostty_surface_complete_clipboard_request.
+typedef struct {
+ const ghostty_clipboard_content_s *contents;
+ size_t contents_len;
+ const char *const *available;
+ size_t available_len;
+ bool confirmed;
+ bool remember;
+} ghostty_clipboard_complete_s;
+
+// The payload of a clipboard read confirmation request: the would-be
+// completion contents plus the information shown in the permission
+// prompt. See ghostty_runtime_confirm_read_clipboard_cb.
+typedef struct {
+ const ghostty_clipboard_content_s *contents;
+ size_t contents_len;
+ const char *const *available;
+ size_t available_len;
+ const char *name;
+ bool can_remember;
+} ghostty_clipboard_confirm_s;
+
typedef enum {
GHOSTTY_CLIPBOARD_REQUEST_PASTE,
GHOSTTY_CLIPBOARD_REQUEST_OSC_52_READ,
GHOSTTY_CLIPBOARD_REQUEST_OSC_52_WRITE,
+ GHOSTTY_CLIPBOARD_REQUEST_KITTY_READ,
+ GHOSTTY_CLIPBOARD_REQUEST_KITTY_WRITE,
+ GHOSTTY_CLIPBOARD_REQUEST_LIST,
} ghostty_clipboard_request_e;
+// apprt.ClipboardReadResult
+typedef enum {
+ GHOSTTY_CLIPBOARD_READ_STARTED,
+ GHOSTTY_CLIPBOARD_READ_UNAVAILABLE,
+ GHOSTTY_CLIPBOARD_READ_UNSUPPORTED,
+} ghostty_clipboard_read_result_e;
+
typedef enum {
GHOSTTY_MOUSE_RELEASE,
GHOSTTY_MOUSE_PRESS,
@@ -645,6 +686,12 @@ typedef enum {
GHOSTTY_INSPECTOR_HIDE,
} ghostty_action_inspector_e;
+// apprt.action.ExportTerminalIO.C
+typedef struct {
+ const char* contents;
+ size_t len;
+} ghostty_action_export_terminal_io_s;
+
// apprt.action.QuitTimer
typedef enum {
GHOSTTY_QUIT_TIMER_START,
@@ -672,6 +719,7 @@ typedef struct {
typedef enum {
GHOSTTY_PROMPT_TITLE_SURFACE,
GHOSTTY_PROMPT_TITLE_TAB,
+ GHOSTTY_PROMPT_TITLE_WINDOW,
} ghostty_action_prompt_title_e;
// apprt.action.Pwd.C
@@ -679,6 +727,14 @@ typedef struct {
const char* pwd;
} ghostty_action_pwd_s;
+// apprt.action.OpenConfig
+typedef enum {
+ // Open the config in the OS default editor.
+ GHOSTTY_ACTION_OPEN_CONFIG_OS_OPEN,
+ // Open the config in a new window using $EDITOR or $VISUAL
+ GHOSTTY_ACTION_OPEN_CONFIG_NEW_WINDOW,
+} ghostty_action_open_config_e;
+
// terminal.MouseShape
typedef enum {
GHOSTTY_MOUSE_SHAPE_DEFAULT,
@@ -812,6 +868,7 @@ typedef enum {
GHOSTTY_ACTION_OPEN_URL_KIND_UNKNOWN,
GHOSTTY_ACTION_OPEN_URL_KIND_TEXT,
GHOSTTY_ACTION_OPEN_URL_KIND_HTML,
+ GHOSTTY_ACTION_OPEN_URL_KIND_OSC8,
} ghostty_action_open_url_kind_e;
// apprt.action.OpenUrl.C
@@ -914,9 +971,11 @@ typedef enum {
GHOSTTY_ACTION_INSPECTOR,
GHOSTTY_ACTION_SHOW_GTK_INSPECTOR,
GHOSTTY_ACTION_RENDER_INSPECTOR,
+ GHOSTTY_ACTION_EXPORT_TERMINAL_IO,
GHOSTTY_ACTION_DESKTOP_NOTIFICATION,
GHOSTTY_ACTION_SET_TITLE,
GHOSTTY_ACTION_SET_TAB_TITLE,
+ GHOSTTY_ACTION_SET_WINDOW_TITLE,
GHOSTTY_ACTION_PROMPT_TITLE,
GHOSTTY_ACTION_PWD,
GHOSTTY_ACTION_MOUSE_SHAPE,
@@ -949,6 +1008,7 @@ typedef enum {
GHOSTTY_ACTION_SEARCH_SELECTED,
GHOSTTY_ACTION_READONLY,
GHOSTTY_ACTION_COPY_TITLE_TO_CLIPBOARD,
+ GHOSTTY_ACTION_MOVE_TAB_TO_NEW_WINDOW,
} ghostty_action_tag_e;
typedef union {
@@ -964,6 +1024,7 @@ typedef union {
ghostty_action_cell_size_s cell_size;
ghostty_action_scrollbar_s scrollbar;
ghostty_action_inspector_e inspector;
+ ghostty_action_export_terminal_io_s export_terminal_io;
ghostty_action_desktop_notification_s desktop_notification;
ghostty_action_set_title_s set_title;
ghostty_action_set_title_s set_tab_title;
@@ -990,6 +1051,7 @@ typedef union {
ghostty_action_search_total_s search_total;
ghostty_action_search_selected_s search_selected;
ghostty_action_readonly_e readonly;
+ ghostty_action_open_config_e open_config;
} ghostty_action_u;
typedef struct {
@@ -998,12 +1060,16 @@ typedef struct {
} ghostty_action_s;
typedef void (*ghostty_runtime_wakeup_cb)(void*);
-typedef bool (*ghostty_runtime_read_clipboard_cb)(void*,
- ghostty_clipboard_e,
- void*);
+typedef ghostty_clipboard_read_result_e (*ghostty_runtime_read_clipboard_cb)(
+ void*,
+ ghostty_clipboard_e,
+ void*,
+ const char* const*,
+ size_t,
+ bool);
typedef void (*ghostty_runtime_confirm_read_clipboard_cb)(
void*,
- const char*,
+ const ghostty_clipboard_confirm_s*,
void*,
ghostty_clipboard_request_e);
typedef void (*ghostty_runtime_write_clipboard_cb)(void*,
@@ -1055,6 +1121,7 @@ typedef union {
// apprt.ipc.Action.Key
typedef enum {
GHOSTTY_IPC_ACTION_NEW_WINDOW,
+ GHOSTTY_IPC_ACTION_NEW_TAB,
GHOSTTY_IPC_ACTION_TOGGLE_QUICK_TERMINAL,
} ghostty_ipc_action_tag_e;
@@ -1152,10 +1219,12 @@ GHOSTTY_API void ghostty_surface_split_resize(ghostty_surface_t,
uint16_t);
GHOSTTY_API void ghostty_surface_split_equalize(ghostty_surface_t);
GHOSTTY_API bool ghostty_surface_binding_action(ghostty_surface_t, const char*, uintptr_t);
-GHOSTTY_API void ghostty_surface_complete_clipboard_request(ghostty_surface_t,
- const char*,
- void*,
- bool);
+GHOSTTY_API void ghostty_surface_complete_clipboard_request(
+ ghostty_surface_t,
+ const ghostty_clipboard_complete_s*,
+ void*);
+GHOSTTY_API void ghostty_surface_deny_clipboard_request(ghostty_surface_t,
+ void*);
GHOSTTY_API bool ghostty_surface_has_selection(ghostty_surface_t);
GHOSTTY_API bool ghostty_surface_read_selection(ghostty_surface_t, ghostty_text_s*);
GHOSTTY_API bool ghostty_surface_read_text(ghostty_surface_t,
diff --git a/vendor/libghostty-vt/include/ghostty/vt.h b/vendor/libghostty-vt/include/ghostty/vt.h
index 5606f169..cfa1017e 100644
--- a/vendor/libghostty-vt/include/ghostty/vt.h
+++ b/vendor/libghostty-vt/include/ghostty/vt.h
@@ -31,12 +31,15 @@
* - @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 snapshot "Terminal Snapshot" - Encode and incrementally restore terminal state
+ * - @ref search "Search" - Search terminal contents, including scrollback
* - @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 paste "Paste" - Paste into a terminal, validate and encode paste data
* - @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 io "Byte-stream I/O" - Reusable synchronous reader and writer callbacks
* - @ref wasm "WebAssembly Utilities" - WebAssembly convenience functions
*
* Encoding related APIs:
@@ -51,12 +54,13 @@
* - @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-paste/src/main.c - Paste 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
+ * - @ref c-vt-search/src/main.c - Terminal search example
*
*/
@@ -81,8 +85,10 @@
*/
/** @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.
+ * This example demonstrates how to paste into a terminal, including the
+ * unsafe-paste confirmation flow and Kitty clipboard protocol paste events
+ * (mode 5522), as well as the terminal-free paste safety and encoding
+ * utilities.
*/
/** @example c-vt-sgr/src/main.c
@@ -121,6 +127,12 @@
* PNG decoder callback and send a Kitty Graphics Protocol image.
*/
+/** @example c-vt-search/src/main.c
+ * This example demonstrates how to search terminal contents for a
+ * string, navigate between the matches like a find bar, and read the
+ * viewport matches used to draw highlights.
+ */
+
#ifndef GHOSTTY_VT_H
#define GHOSTTY_VT_H
@@ -140,6 +152,7 @@ extern "C" {
#include <ghostty/vt/terminal.h>
#include <ghostty/vt/grid_ref.h>
#include <ghostty/vt/grid_ref_tracked.h>
+#include <ghostty/vt/io.h>
#include <ghostty/vt/osc.h>
#include <ghostty/vt/sgr.h>
#include <ghostty/vt/style.h>
@@ -151,8 +164,10 @@ extern "C" {
#include <ghostty/vt/paste.h>
#include <ghostty/vt/point.h>
#include <ghostty/vt/screen.h>
+#include <ghostty/vt/search.h>
#include <ghostty/vt/selection.h>
#include <ghostty/vt/size_report.h>
+#include <ghostty/vt/snapshot.h>
#include <ghostty/vt/unicode.h>
#include <ghostty/vt/wasm.h>
diff --git a/vendor/libghostty-vt/include/ghostty/vt/allocator.h b/vendor/libghostty-vt/include/ghostty/vt/allocator.h
index 2e8685e8..f68ffa2f 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/allocator.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/allocator.h
@@ -31,14 +31,17 @@
* 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.
+ * that doesn't require any external dependencies. On native freestanding
+ * targets, the default allocator always fails instead.
*
* ## 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).
+ * we provide our own default allocator if libc isn't linked). Native
+ * freestanding builds must provide a custom allocator for operations that
+ * allocate memory.
*
* To use a custom allocator:
* 1. Implement the GhosttyAllocatorVtable function pointers
@@ -76,7 +79,8 @@
*
* 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.
+ * default allocator. Native freestanding builds must provide an allocator
+ * for operations that allocate memory.
*
* 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
@@ -183,7 +187,8 @@ typedef struct {
* 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).
+ * a custom allocator is used (currently Zig's SMP allocator). On native
+ * freestanding targets, the default allocator always fails instead.
*
* @ingroup allocator
*
@@ -219,7 +224,8 @@ typedef struct GhosttyAllocator {
*
* @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
+ * @return Pointer to the allocated buffer, or NULL if len is zero or
+ * allocation failed
*
* @ingroup allocator
*/
diff --git a/vendor/libghostty-vt/include/ghostty/vt/device.h b/vendor/libghostty-vt/include/ghostty/vt/device.h
index 0a156728..419748a8 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/device.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/device.h
@@ -11,6 +11,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <ghostty/vt/types.h>
+
/* DA1 conformance levels (Pp parameter). */
#define GHOSTTY_DA_CONFORMANCE_VT100 1
#define GHOSTTY_DA_CONFORMANCE_VT101 1
diff --git a/vendor/libghostty-vt/include/ghostty/vt/formatter.h b/vendor/libghostty-vt/include/ghostty/vt/formatter.h
index 5cdcd11a..fd593b13 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/formatter.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/formatter.h
@@ -11,6 +11,7 @@
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/allocator.h>
+#include <ghostty/vt/io.h>
#include <ghostty/vt/selection.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/terminal.h>
@@ -138,6 +139,30 @@ GHOSTTY_API GhosttyResult ghostty_formatter_terminal_new(
GhosttyFormatterTerminalOptions options);
/**
+ * Run the formatter and stream output to a writer.
+ *
+ * Each call formats the current terminal state and invokes the writer
+ * synchronously as output becomes available. The callback may be called more
+ * than once and must not call formatter or terminal APIs using the same
+ * formatter or its terminal.
+ *
+ * If an error occurs, the writer may already contain a partial formatted
+ * output. The operation cannot be resumed from that partial output. This
+ * function does not flush or make the caller's destination durable.
+ *
+ * @param formatter The formatter handle (must not be NULL)
+ * @param writer Destination writer whose write callback must not be NULL
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_IO_ERROR if the writer rejects
+ * output, GHOSTTY_LIMIT_EXCEEDED if output accounting overflows, or
+ * GHOSTTY_INVALID_VALUE if an argument is invalid
+ *
+ * @ingroup formatter
+ */
+GHOSTTY_API GhosttyResult ghostty_formatter_format(
+ GhosttyFormatter formatter,
+ GhosttyWriter writer);
+
+/**
* Run the formatter and produce output into the caller-provided buffer.
*
* Each call formats the current terminal state. Pass NULL for buf to
@@ -171,6 +196,8 @@ GHOSTTY_API GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatte
* 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.
+ * Empty output returns GHOSTTY_SUCCESS with *out_ptr set to NULL and
+ * *out_len set to zero. This result can be passed to ghostty_free().
*
* @param formatter The formatter handle (must not be NULL)
* @param allocator Pointer to allocator, or NULL to use the default allocator
diff --git a/vendor/libghostty-vt/include/ghostty/vt/io.h b/vendor/libghostty-vt/include/ghostty/vt/io.h
new file mode 100644
index 00000000..ad2c57ad
--- /dev/null
+++ b/vendor/libghostty-vt/include/ghostty/vt/io.h
@@ -0,0 +1,151 @@
+/**
+ * @file io.h
+ *
+ * Generic IO callbacks for libghostty-vt.
+ */
+
+#ifndef GHOSTTY_VT_IO_H
+#define GHOSTTY_VT_IO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <ghostty/vt/types.h>
+
+/** @defgroup io I/O
+ *
+ * Synchronous callback interfaces used by APIs that consume or produce byte
+ * streams. The callback and userdata pointers must remain valid for the full
+ * lifetime documented by the API receiving a GhosttyReader or GhosttyWriter.
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Read bytes from a source.
+ *
+ * The callback must set @p out_read to a value no greater than @p capacity
+ * when returning true. A positive value reports progress; it may be less than
+ * capacity and does not indicate end-of-file. A zero value is definitive
+ * end-of-file. It must not be used to report temporary input starvation or a
+ * would-block condition.
+ *
+ * Returning false reports a fatal read error and the value of @p out_read is
+ * ignored. The library does not inspect or modify errno.
+ *
+ * All pointer arguments are borrowed and valid only for the duration of the
+ * callback. The callback is invoked synchronously on the calling thread.
+ *
+ * @param userdata Opaque userdata from GhosttyReader
+ * @param buffer Destination for read bytes; always non-NULL
+ * @param capacity Writable capacity of @p buffer; always greater than zero
+ * @param[out] out_read Number of bytes read when returning true; non-NULL
+ * @return true for a successful read or end-of-file, false for a fatal error
+ */
+typedef bool (*GhosttyReaderFn)(
+ void* userdata,
+ uint8_t* buffer,
+ size_t capacity,
+ size_t* out_read);
+
+/**
+ * Write bytes to a destination.
+ *
+ * Returning true means all @p len bytes were accepted. Returning false
+ * reports a fatal write error. A callback wrapping an interface that permits
+ * partial writes must retry internally until the full slice is accepted or
+ * an error occurs.
+ *
+ * On failure, the destination may already contain a prefix of the bytes. The
+ * calling operation fails and must not be resumed from that partial output.
+ * The library does not inspect or modify errno.
+ *
+ * @p data is borrowed and valid only for the duration of the callback. The
+ * callback is invoked synchronously on the calling thread. Successful return
+ * means the bytes were handed to the destination; it does not imply that the
+ * destination was flushed or made durable.
+ *
+ * @param userdata Opaque userdata from GhosttyWriter
+ * @param data Source bytes; always non-NULL
+ * @param len Number of source bytes; always greater than zero
+ * @return true if the complete slice was accepted, false on fatal error
+ */
+typedef bool (*GhosttyWriterFn)(
+ void* userdata,
+ const uint8_t* data,
+ size_t len);
+
+/**
+ * A byte source callback and its opaque context.
+ *
+ * The struct is passed by value. @p read must be non-NULL.
+ */
+typedef struct {
+ GhosttyReaderFn read;
+ void* userdata;
+} GhosttyReader;
+
+/**
+ * A byte destination callback and its opaque context.
+ *
+ * The struct is passed by value. @p write must be non-NULL.
+ */
+typedef struct {
+ GhosttyWriterFn write;
+ void* userdata;
+} GhosttyWriter;
+
+/**
+ * Read one MIME-typed representation of some content, streaming its
+ * bytes to a writer.
+ *
+ * The library calls this with the MIME type of the representation it
+ * needs. The callback writes all of that representation's data to
+ * @p writer, in as many calls to `writer.write(writer.userdata, data,
+ * len)` as is convenient (one call with everything or many small
+ * pieces both work), and returns true. Nothing written is retained
+ * beyond each write call, so the data may be borrowed from anywhere:
+ * a pasteboard item, a file being read, a stream.
+ *
+ * Returning false reports that the data could not be read. If the
+ * writer refuses a write (returns false), stop and return false
+ * without writing more.
+ *
+ * All pointer arguments, the mime, and the writer are borrowed and
+ * valid only for the duration of the callback. The callback is
+ * invoked synchronously on the calling thread. The API receiving the
+ * GhosttyMimeReader defines which MIME types are requested, how many
+ * times, and any consistency requirements across repeated reads.
+ *
+ * @param userdata Opaque userdata from GhosttyMimeReader
+ * @param mime The MIME type of the representation to read
+ * @param writer Where to write the data; valid only during this call
+ * @return true once all the data was written, false if it could not
+ * be read or the writer refused a write
+ */
+typedef bool (*GhosttyMimeReaderFn)(
+ void* userdata,
+ GhosttyString mime,
+ GhosttyWriter writer);
+
+/**
+ * A MIME-typed content source callback and its opaque context.
+ *
+ * The struct is passed by value. @p read must be non-NULL.
+ */
+typedef struct {
+ GhosttyMimeReaderFn read;
+ void* userdata;
+} GhosttyMimeReader;
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* GHOSTTY_VT_IO_H */
diff --git a/vendor/libghostty-vt/include/ghostty/vt/key.h b/vendor/libghostty-vt/include/ghostty/vt/key.h
index 61b95475..517d0c30 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/key.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/key.h
@@ -42,8 +42,7 @@
* @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});
+ * ghostty_terminal_new(NULL, &terminal, 80, 24);
*
* // Application might write data that enables Kitty keyboard protocol, etc.
* ghostty_terminal_vt_write(terminal, vt_data, vt_len);
diff --git a/vendor/libghostty-vt/include/ghostty/vt/kitty_graphics.h b/vendor/libghostty-vt/include/ghostty/vt/kitty_graphics.h
index dda8b836..99cee60a 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/kitty_graphics.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/kitty_graphics.h
@@ -390,7 +390,8 @@ typedef enum GHOSTTY_ENUM_TYPED {
/**
* Borrowed pointer to the raw pixel data. Valid as long as the
- * underlying terminal is not mutated.
+ * underlying terminal is not mutated. Returns GHOSTTY_NO_VALUE when
+ * the image metadata is resident but its pixel payload is pending.
*
* The data is always fully decoded, uncompressed pixels in the
* format reported by GHOSTTY_KITTY_IMAGE_DATA_FORMAT: zlib payloads
@@ -398,13 +399,21 @@ typedef enum GHOSTTY_ENUM_TYPED {
* time, before the image is stored. Consumers can upload this
* directly to the GPU without any decode step.
*
+ * For an animated image (Kitty graphics animation, actions a=f/a=a)
+ * this is the pixel data of the current animation frame. The
+ * image's GHOSTTY_KITTY_IMAGE_DATA_GENERATION changes whenever the
+ * current frame changes, so generation-keyed caches remain
+ * coherent.
+ *
* 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.
+ * width * height * bytes-per-pixel for the reported format. For a
+ * pending image, this is the expected length reserved against the
+ * storage limit even though DATA_PTR is not available yet.
*
* Output type: size_t *
*/
@@ -421,7 +430,10 @@ typedef enum GHOSTTY_ENUM_TYPED {
* 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.
+ * image, so zero can be used as an "empty" sentinel by callers. Pending
+ * payload completion preserves this value to retain image age; consumers
+ * detect that completion through GHOSTTY_KITTY_GRAPHICS_DATA_GENERATION
+ * and retry DATA_PTR.
*
* Output type: uint64_t *
*/
diff --git a/vendor/libghostty-vt/include/ghostty/vt/modes.h b/vendor/libghostty-vt/include/ghostty/vt/modes.h
index 8e1fd911..6786f004 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/modes.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/modes.h
@@ -92,7 +92,9 @@ extern "C" {
#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_VISIBILITY_REPORT (ghostty_mode_new(2033, false)) /**< Report terminal visibility */
#define GHOSTTY_MODE_IN_BAND_RESIZE (ghostty_mode_new(2048, false)) /**< In-band size reports */
+#define GHOSTTY_MODE_PASTE_EVENTS (ghostty_mode_new(5522, false)) /**< Kitty clipboard protocol paste events */
/** @} */
/**
diff --git a/vendor/libghostty-vt/include/ghostty/vt/mouse.h b/vendor/libghostty-vt/include/ghostty/vt/mouse.h
index 4ba5f52e..4a582a23 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/mouse.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/mouse.h
@@ -39,8 +39,7 @@
* @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});
+ * ghostty_terminal_new(NULL, &terminal, 80, 24);
*
* // Application might write data that enables mouse reporting, etc.
* ghostty_terminal_vt_write(terminal, vt_data, vt_len);
diff --git a/vendor/libghostty-vt/include/ghostty/vt/osc.h b/vendor/libghostty-vt/include/ghostty/vt/osc.h
index 9409ebc7..7a681c3b 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/osc.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/osc.h
@@ -63,6 +63,10 @@ typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_OSC_COMMAND_CONEMU_XTERM_EMULATION = 20,
GHOSTTY_OSC_COMMAND_CONEMU_COMMENT = 21,
GHOSTTY_OSC_COMMAND_KITTY_TEXT_SIZING = 22,
+ GHOSTTY_OSC_COMMAND_KITTY_CLIPBOARD_PROTOCOL = 23,
+ GHOSTTY_OSC_COMMAND_KITTY_DND_PROTOCOL = 24,
+ GHOSTTY_OSC_COMMAND_CONTEXT_SIGNAL = 25,
+ GHOSTTY_OSC_COMMAND_KITTY_DESKTOP_NOTIFICATION = 26,
GHOSTTY_OSC_COMMAND_TYPE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOscCommandType;
diff --git a/vendor/libghostty-vt/include/ghostty/vt/paste.h b/vendor/libghostty-vt/include/ghostty/vt/paste.h
index b3df5be4..4ba21a9a 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/paste.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/paste.h
@@ -1,26 +1,67 @@
/**
* @file paste.h
*
- * Paste utilities - validate and encode paste data for terminal input.
+ * Paste - paste into a terminal, and validate and encode paste data.
*/
#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,
+/** @defgroup paste Paste
+ *
+ * Pasting into a terminal, plus the terminal-free utilities for
+ * validating and encoding paste data.
+ *
+ * ## Pasting into a Terminal
+ *
+ * What a paste writes to the pty depends on the terminal's state, so
+ * the recommended way to paste is ghostty_terminal_paste(). The embedder
+ * hands over the MIME types the clipboard holds (just `text/plain` for
+ * an ordinary paste), a GhosttyMimeReader that produces the data of
+ * any one of them, and where the paste came from, and the terminal
+ * decides how its current modes apply:
+ *
+ * - If Kitty clipboard protocol paste events (mode 5522,
+ * GHOSTTY_MODE_PASTE_EVENTS) are enabled, the paste was user-initiated
+ * (GHOSTTY_PASTE_SOURCE_CLIPBOARD), and a clipboard_read callback is
+ * installed, the terminal sends the program a paste event listing the
+ * clipboard's MIME types with a one-time password instead of the data.
+ * The program then reads what it wants through the clipboard_read
+ * callback, which arrives with `granted` set so no permission prompt
+ * is needed. No data is read for the event.
+ * - Otherwise the first text representation is written: unsafe control
+ * bytes are replaced with spaces, and it is wrapped in bracketed paste
+ * sequences if mode 2004 (GHOSTTY_MODE_BRACKETED_PASTE) is enabled, or
+ * has its newlines converted to carriage returns if not.
+ *
+ * The data is pulled through GhosttyPaste::reader only when a
+ * representation is actually pasted (so a clipboard holding a large
+ * image next to some text costs nothing), and the encoded bytes
+ * stream to the write_pty callback (GHOSTTY_TERMINAL_OPT_WRITE_PTY)
+ * in chunks as they are produced, never in one piece. The callback
+ * may be invoked several times for a single paste; the pieces must be
+ * written to the pty in order.
+ *
+ * Text that could inject commands (a newline when unbracketed, or the
+ * bracketed paste terminator when bracketed) is refused with
+ * GHOSTTY_REJECTED and nothing written unless GhosttyPaste::allow_unsafe
+ * is set. The usual flow is to call once, confirm with the user on
+ * GHOSTTY_REJECTED, and call again with `allow_unsafe` set. Each call
+ * reads the text at most once and buffers it whole while the rule is
+ * applied, so the source needs no stability across reads (the
+ * confirmed retry simply pastes whatever the source holds then) and a
+ * refused or failed paste writes nothing at all.
+ *
+ * @snippet c-vt-paste/src/main.c terminal-paste
+ *
+ * ## Building Blocks
+ *
+ * For embedders that encode without a terminal, ghostty_paste_is_safe()
+ * checks if paste data contains potentially dangerous sequences
+ * (conservatively, regardless of terminal state) and
+ * ghostty_paste_encode() encodes 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
@@ -35,12 +76,120 @@
#include <stdbool.h>
#include <stddef.h>
#include <ghostty/vt/types.h>
+#include <ghostty/vt/io.h>
+#include <ghostty/vt/terminal.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
+ * Why a paste happened.
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** The user pasted from a clipboard: keybind, menu, middle click. */
+ GHOSTTY_PASTE_SOURCE_CLIPBOARD = 0,
+
+ /**
+ * Text inserted some other way: IME commit, drag and drop, scripted
+ * input. Always written as text, never as a paste event, matching
+ * kitty. This is not a way to opt out of paste events; an embedder
+ * that doesn't want them doesn't install a clipboard_read callback.
+ */
+ GHOSTTY_PASTE_SOURCE_TEXT = 1,
+ GHOSTTY_PASTE_SOURCE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttyPasteSource;
+
+/**
+ * A paste of clipboard contents into the terminal.
+ *
+ * This is a sized struct; set `size` to `sizeof(GhosttyPaste)`. The
+ * MIME type array and the strings it points to are borrowed only for
+ * the duration of the ghostty_terminal_paste() call, as is everything
+ * the reader produces.
+ */
+typedef struct {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /**
+ * The clipboard the contents came from. Reported to the program on a
+ * paste event (the selection and primary locations are both reported
+ * as the primary selection, the protocol knows only two); no effect
+ * on a text paste.
+ */
+ GhosttyClipboardLocation location;
+
+ /** Why this paste happened. */
+ GhosttyPasteSource source;
+
+ /**
+ * Borrowed array of the MIME types of the representations available,
+ * in preferred order. A text paste reads and writes the first entry
+ * with a text MIME type such as "text/plain" and ignores the rest. A
+ * paste event lists every entry and reads none. May be NULL when
+ * mimes_len is zero, which is nothing to paste.
+ */
+ const GhosttyString* mimes;
+
+ /** Number of entries in mimes. */
+ size_t mimes_len;
+
+ /**
+ * Produces the data of a representation on demand. Required when
+ * mimes_len is nonzero.
+ *
+ * Called at most once per ghostty_terminal_paste() call: for the
+ * text representation being pasted, never for anything else and
+ * never for a paste event. The MIME type requested is always an
+ * entry of `mimes`, passed through exactly as given there (the same
+ * pointer and length), so the callback may identify the
+ * representation by pointer or by content. A false return fails the
+ * paste with GHOSTTY_IO_ERROR.
+ */
+ GhosttyMimeReader reader;
+
+ /**
+ * Write text that could inject commands. Call with false, confirm
+ * with the user on GHOSTTY_REJECTED, and call again with true.
+ */
+ bool allow_unsafe;
+} GhosttyPaste;
+
+/**
+ * Paste into the terminal according to its current state: a Kitty
+ * clipboard protocol paste event if mode 5522 is enabled and a
+ * clipboard_read callback is installed, otherwise the text framed per
+ * mode 2004. See the group documentation for the full behavior. Output
+ * streams through the write_pty callback in chunks. The viewport is not
+ * scrolled; that is up to the embedder, as for key input.
+ *
+ * A paste event records a session grant for its one-time password only
+ * once the event is written; a failed call never leaves a grant for an
+ * event that was never sent.
+ *
+ * @param terminal The terminal handle
+ * @param paste The paste request, borrowed for the duration of the call
+ * @param[out] out_written On success, whether anything was written to
+ * the pty (the encoded text or a paste event). False means
+ * there was nothing to paste: no non-empty text
+ * representation. May be NULL.
+ * @return GHOSTTY_SUCCESS on success (see @p out_written);
+ * GHOSTTY_REJECTED if the text could inject commands and
+ * GhosttyPaste::allow_unsafe is false (nothing was written);
+ * GHOSTTY_INVALID_VALUE for a NULL terminal or paste, MIME
+ * types without a reader, or when no write_pty callback is
+ * installed; GHOSTTY_OUT_OF_MEMORY; GHOSTTY_IO_ERROR if the
+ * reader failed or there is no secure entropy source to mint a
+ * paste event password (wasm32-freestanding without
+ * GHOSTTY_SYS_OPT_RANDOM_SECURE set). Errors write nothing.
+ */
+GHOSTTY_API GhosttyResult ghostty_terminal_paste(
+ GhosttyTerminal terminal,
+ const GhosttyPaste* paste,
+ bool* out_written);
+
+/**
* Check if paste data is safe to paste into the terminal.
*
* Data is considered unsafe if it contains:
@@ -49,7 +198,9 @@ extern "C" {
* to exit bracketed paste mode and inject commands
*
* This check is conservative and considers data unsafe regardless of
- * current terminal state.
+ * current terminal state. ghostty_terminal_paste() applies the
+ * terminal-state-aware rule itself (newlines are safe inside a
+ * bracketed paste); use this to apply the stricter rule on top.
*
* @param data The paste data to check (must not be NULL)
* @param len The length of the data in bytes
@@ -74,6 +225,9 @@ GHOSTTY_API bool ghostty_paste_is_safe(const char* data, size_t len);
* GHOSTTY_OUT_OF_SPACE and sets the required size in @p out_written.
* The caller can then retry with a sufficiently sized buffer.
*
+ * This is the encoder ghostty_terminal_paste() uses for a text paste;
+ * use it directly when there is no terminal to paste into.
+ *
* @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
diff --git a/vendor/libghostty-vt/include/ghostty/vt/point.h b/vendor/libghostty-vt/include/ghostty/vt/point.h
index 8b717f49..9cab2758 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/point.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/point.h
@@ -9,6 +9,8 @@
#include <stdint.h>
+#include <ghostty/vt/types.h>
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/vendor/libghostty-vt/include/ghostty/vt/render.h b/vendor/libghostty-vt/include/ghostty/vt/render.h
index 2e3f2f71..f6b5e222 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/render.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/render.h
@@ -63,7 +63,10 @@ extern "C" {
* 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.
+ * The `update` call does not unset dirty state, it only updates it. After
+ * successfully rendering a complete frame, use ghostty_render_state_clean()
+ * to unset both layers in one call. The granular setters remain available
+ * for callers that only consume part of a frame.
*
* An extremely important detail: setting one dirty state doesn't unset
* the other. For example, setting the global dirty state to false does not
@@ -199,6 +202,14 @@ typedef enum GHOSTTY_ENUM_TYPED {
/** 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,
+
+ /** All cursor state in one sized struct (GhosttyRenderStateCursor).
+ * Initialize the output with GHOSTTY_INIT_SIZED before querying. */
+ GHOSTTY_RENDER_STATE_DATA_CURSOR = 18,
+
+ /** All render-state colors in one sized struct (GhosttyRenderStateColors).
+ * Initialize the output with GHOSTTY_INIT_SIZED before querying. */
+ GHOSTTY_RENDER_STATE_DATA_COLORS = 19,
GHOSTTY_RENDER_STATE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateData;
@@ -236,6 +247,22 @@ typedef enum GHOSTTY_ENUM_TYPED {
/** Row-local selected cell range (GhosttyRenderStateRowSelection). */
GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION = 4,
+
+ /** A borrowed view of the raw cell values for the current row
+ * (GhosttyCellsView). One value per column, identical to querying
+ * GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_RAW for each cell. The view
+ * is only valid as long as the underlying render state is not
+ * updated; it is unsafe to use after updating the render state.
+ *
+ * This is the bulk alternative to iterating cells one at a time.
+ * It lets callers with expensive call boundaries (e.g. WebAssembly
+ * embedders) read an entire row with a single call.
+ *
+ * Bit positions aren't protected by ABI, so callers should parse them
+ * out of the manifest from `ghostty_type_json`. Callers with access
+ * to the C header or without high FFI costs should use `ghostty_cell_get`.
+ */
+ GHOSTTY_RENDER_STATE_ROW_DATA_CELLS_RAW = 5,
GHOSTTY_RENDER_STATE_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyRenderStateRowData;
@@ -274,16 +301,58 @@ typedef struct {
} GhosttyRenderStateRowSelection;
/**
+ * Render-state cursor information.
+ *
+ * This struct uses the sized-struct ABI pattern. Initialize with
+ * GHOSTTY_INIT_SIZED(GhosttyRenderStateCursor) before querying
+ * GHOSTTY_RENDER_STATE_DATA_CURSOR.
+ *
+ * When viewport_has_value is false, viewport_x, viewport_y, and wide_tail
+ * contain undefined data and must not be read.
+ *
+ * @ingroup render
+ */
+typedef struct {
+ /** Size of this struct in bytes. Must be set to sizeof(GhosttyRenderStateCursor). */
+ size_t size;
+
+ /** Whether the cursor is visible within the viewport. */
+ bool viewport_has_value;
+
+ /** Cursor viewport x position in cells. */
+ uint16_t viewport_x;
+
+ /** Cursor viewport y position in cells. */
+ uint16_t viewport_y;
+
+ /** Whether the cursor is on the tail of a wide character. */
+ bool wide_tail;
+
+ /** Whether the cursor is visible based on terminal modes. */
+ bool visible;
+
+ /** Whether the cursor should blink based on terminal modes. */
+ bool blinking;
+
+ /** Whether the cursor is at a password input field. */
+ bool password_input;
+
+ /** The visual style of the cursor. */
+ GhosttyRenderStateCursorVisualStyle visual_style;
+} GhosttyRenderStateCursor;
+
+/**
* 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().
+ * GHOSTTY_INIT_SIZED(GhosttyRenderStateColors) before querying
+ * GHOSTTY_RENDER_STATE_DATA_COLORS.
*
* Example:
* @code
* GhosttyRenderStateColors colors = GHOSTTY_INIT_SIZED(GhosttyRenderStateColors);
- * GhosttyResult result = ghostty_render_state_colors_get(state, &colors);
+ * GhosttyResult result = ghostty_render_state_get(
+ * state, GHOSTTY_RENDER_STATE_DATA_COLORS, &colors);
* @endcode
*
* @ingroup render
@@ -409,6 +478,23 @@ GHOSTTY_API GhosttyResult ghostty_render_state_begin_update(GhosttyRenderState s
GHOSTTY_API GhosttyResult ghostty_render_state_end_update(GhosttyRenderState state);
/**
+ * Mark all dirty render-state data as consumed.
+ *
+ * This sets the global dirty state to GHOSTTY_RENDER_STATE_DIRTY_FALSE and
+ * clears every per-row dirty flag. It is idempotent and does not modify cell
+ * contents or dirty state owned by the terminal. Call this only after a
+ * complete frame has been rendered successfully; partial consumers should
+ * use ghostty_render_state_set() and ghostty_render_state_row_set() instead.
+ *
+ * @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_clean(GhosttyRenderState state);
+
+/**
* Get a value from a render state.
*
* The `out` pointer must point to a value of the type corresponding to the
@@ -417,8 +503,9 @@ GHOSTTY_API GhosttyResult ghostty_render_state_end_update(GhosttyRenderState sta
* @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
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
+ * `out` is NULL, `data` is not a recognized enum value, or a sized
+ * output struct is smaller than `sizeof(size_t)`
*
* @ingroup render
*/
@@ -474,24 +561,6 @@ GHOSTTY_API GhosttyResult ghostty_render_state_set(GhosttyRenderState state,
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
@@ -521,7 +590,8 @@ GHOSTTY_API void ghostty_render_state_row_iterator_free(GhosttyRenderStateRowIte
/**
* Move a render-state row iterator to the next row.
*
- * Returns true if the iterator moved successfully and row data is
+ * Rows are visited contiguously in ascending viewport order, starting at
+ * y = 0. 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)
@@ -533,11 +603,35 @@ GHOSTTY_API void ghostty_render_state_row_iterator_free(GhosttyRenderStateRowIte
GHOSTTY_API bool ghostty_render_state_row_iterator_next(GhosttyRenderStateRowIterator iterator);
/**
+ * Move a render-state row iterator to the next row requiring a redraw.
+ *
+ * If the global dirty state is GHOSTTY_RENDER_STATE_DIRTY_FALSE, this returns
+ * false. If it is GHOSTTY_RENDER_STATE_DIRTY_PARTIAL, clean rows are skipped.
+ * If it is GHOSTTY_RENDER_STATE_DIRTY_FULL, every remaining row is returned
+ * regardless of its per-row dirty flag. Rows are returned in ascending
+ * viewport order. This function does not clear any dirty state.
+ *
+ * @param iterator The iterator handle to advance (NULL returns false)
+ * @param[out] out_y Receives the viewport y coordinate when true is returned
+ * (NULL returns false); it is not modified when false is
+ * returned
+ * @return true if advanced to a row requiring a redraw, false if an argument
+ * is NULL or the iterator has reached the end of the effective dirty
+ * rows
+ *
+ * @ingroup render
+ */
+GHOSTTY_API bool ghostty_render_state_row_iterator_next_dirty(
+ GhosttyRenderStateRowIterator iterator,
+ uint16_t* out_y);
+
+/**
* 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
+ * Call ghostty_render_state_row_iterator_next() or
+ * ghostty_render_state_row_iterator_next_dirty() at least once before
* calling this function.
*
* @param iterator The iterator handle to query (NULL returns GHOSTTY_INVALID_VALUE)
@@ -586,7 +680,8 @@ GHOSTTY_API GhosttyResult ghostty_render_state_row_get_multi(
*
* 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
+ * Call ghostty_render_state_row_iterator_next() or
+ * ghostty_render_state_row_iterator_next_dirty() at least once before
* calling this function.
*
* @param iterator The iterator handle to update (NULL returns GHOSTTY_INVALID_VALUE)
diff --git a/vendor/libghostty-vt/include/ghostty/vt/screen.h b/vendor/libghostty-vt/include/ghostty/vt/screen.h
index 9f639b58..2899989d 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/screen.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/screen.h
@@ -21,19 +21,21 @@ extern "C" {
* 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.
+ * is a single grid cell and a GhosttyRow is a single row. Cell fields can
+ * be accessed via ghostty_cell_get() or decoded from the packed layout in
+ * ghostty_type_json(). Rows are opaque and accessed via ghostty_row_get().
*
* @{
*/
/**
- * Opaque cell value.
+ * Packed 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.
+ * Represents a single terminal cell. Portable callers can query fields via
+ * ghostty_cell_get(). Boundary-sensitive callers can decode the packed value
+ * using the GhosttyCell descriptor returned by ghostty_type_json(). The
+ * manifest is authoritative for the linked build; hardcoding bit positions
+ * is unsupported.
*
* @ingroup screen
*/
@@ -51,6 +53,24 @@ typedef uint64_t GhosttyCell;
typedef uint64_t GhosttyRow;
/**
+ * A borrowed view of contiguous raw cell values.
+ *
+ * The memory is not owned by this struct. The pointer is only valid
+ * for the lifetime documented by the API that produces it. Each value
+ * can be queried via ghostty_cell_get() or decoded using the GhosttyCell
+ * packed descriptor returned by ghostty_type_json().
+ *
+ * @ingroup screen
+ */
+typedef struct {
+ /** Pointer to len contiguous cell values. */
+ const GhosttyCell* ptr;
+
+ /** Number of cells. */
+ size_t len;
+} GhosttyCellsView;
+
+/**
* Cell content tag.
*
* Describes what kind of content a cell holds.
diff --git a/vendor/libghostty-vt/include/ghostty/vt/search.h b/vendor/libghostty-vt/include/ghostty/vt/search.h
new file mode 100644
index 00000000..68aebcc4
--- /dev/null
+++ b/vendor/libghostty-vt/include/ghostty/vt/search.h
@@ -0,0 +1,501 @@
+/**
+ * @file search.h
+ *
+ * Search terminal contents, including scrollback, for a string.
+ */
+
+#ifndef GHOSTTY_VT_SEARCH_H
+#define GHOSTTY_VT_SEARCH_H
+
+#include <stddef.h>
+#include <ghostty/vt/allocator.h>
+#include <ghostty/vt/selection.h>
+#include <ghostty/vt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup search Search
+ *
+ * Search a terminal for a string, covering the active area and
+ * scrollback of both the primary and alternate screens.
+ *
+ * A GhosttySearch searches the terminal it was created with for a
+ * needle set with GHOSTTY_SEARCH_OPT_NEEDLE. It handles the hard
+ * parts of terminal search internally: results stay in sync with the
+ * live screens, survive primary/alternate screen switches (entering
+ * and leaving a fullscreen app such as vim does not restart a
+ * scrollback search), and recover from resize, reflow, resets, and
+ * scrollback pruning.
+ *
+ * A search starts idle. Setting the needle starts the search,
+ * changing it restarts the search from scratch, and clearing it
+ * returns the search to idle. Matching is byte-exact except ASCII
+ * letters, which compare case-insensitively.
+ *
+ * ## Driving a search
+ *
+ * Searching a large scrollback takes time, so the work is split into
+ * small steps the caller drives so that the caller can control
+ * performance more directly:
+ *
+ * - ghostty_search_tick() makes a bounded amount of progress on data
+ * the search has already copied. It never touches the terminal,
+ * meaning it can be safely called from a thread.
+ * - ghostty_search_feed() reads the terminal to copy in more data and
+ * pick up terminal changes. Feeding is the only way the search
+ * learns that the terminal changed, so keep feeding periodically
+ * while the search is in use. This requires exclusive terminal access.
+ * - ghostty_search_run() is a blocking convenience that feeds and
+ * ticks until the search is caught up.
+ *
+ * GHOSTTY_SEARCH_STATUS_COMPLETE means the search is caught up with
+ * the terminal as of the last feed. It never means finished forever,
+ * since later terminal writes require another feed to be seen.
+ *
+ * ## Matches are selections
+ *
+ * Every match is returned as a GhosttySelection snapshot with
+ * rectangle set to false, so the existing selection APIs all work on
+ * matches: ghostty_terminal_selection_format_buf() to copy the
+ * matched text, ghostty_terminal_point_from_grid_ref() with
+ * GHOSTTY_POINT_TAG_VIEWPORT to position highlight rectangles,
+ * ghostty_terminal_selection_contains() for hit testing, and
+ * ghostty_terminal_set() with GHOSTTY_TERMINAL_OPT_SELECTION to make
+ * a match the terminal's selection.
+ *
+ * Returned matches follow the usual snapshot lifetime rules: they are
+ * only valid until the next operation that modifies the terminal,
+ * including ghostty_terminal_vt_write(), resize, reset, and free.
+ * Read matches after a feed, use them before the terminal changes
+ * again, and re-read them rather than caching them. The selected
+ * match is kept accurate internally across terminal changes, so the
+ * safe way to follow a match is to re-read
+ * GHOSTTY_SEARCH_DATA_SELECTED_MATCH after each feed.
+ *
+ * ## Lifetime
+ *
+ * The search borrows the terminal it was created with and never frees
+ * it. Any number of searches, alongside other terminal readers such
+ * as formatters and render states, may share one terminal.
+ *
+ * The search and its terminal can be freed in either order. Freeing
+ * the search first releases tracked state it holds within the
+ * terminal. If the terminal is freed first, the search detects this:
+ * calls that need the terminal return GHOSTTY_INVALID_VALUE, reads
+ * return whatever the search last saw, and ghostty_search_free()
+ * releases only search-owned memory. A search cannot be rebound, so
+ * searching another terminal means creating a new search.
+ *
+ * ## Threading
+ *
+ * The library creates no threads. Calls on one GhosttySearch are not
+ * safe to make concurrently with each other, so the caller must
+ * serialize them.
+ *
+ * Functions that touch the terminal (ghostty_search_new(),
+ * ghostty_search_feed(), ghostty_search_run(), ghostty_search_set()
+ * with the needle and select options, and ghostty_search_free()) must
+ * also be serialized with all other access to the same terminal.
+ *
+ * Everything else (ghostty_search_tick(), ghostty_search_get(), and
+ * ghostty_search_get_multi()) only touches memory owned by the search
+ * and is safe to call while another thread modifies the terminal.
+ * This split is how Ghostty runs search on a background thread: tick
+ * freely, and take the terminal lock only to feed. Reading returned
+ * match values is always safe, but passing them to APIs that take the
+ * terminal follows the terminal serialization rule above.
+ *
+ * ## Example
+ *
+ * @snippet c-vt-search/src/main.c search-main
+ *
+ * @{
+ */
+
+/**
+ * Progress state of a search.
+ *
+ * @ingroup search
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /**
+ * ghostty_search_tick() can make progress without terminal access.
+ */
+ GHOSTTY_SEARCH_STATUS_RUNNING = 0,
+
+ /**
+ * Blocked until ghostty_search_feed(). This is also the state right
+ * after a needle is set, since the search has not yet seen the
+ * terminal.
+ */
+ GHOSTTY_SEARCH_STATUS_FEED_REQUIRED = 1,
+
+ /**
+ * Caught up with the terminal state as of the last feed. This never
+ * means finished forever, since later terminal writes require
+ * another feed to be seen. A search with no needle set also reports
+ * complete, since there is nothing to look for.
+ */
+ GHOSTTY_SEARCH_STATUS_COMPLETE = 2,
+
+ GHOSTTY_SEARCH_STATUS_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySearchStatus;
+
+/**
+ * Scroll policy applied when a match becomes selected via
+ * GHOSTTY_SEARCH_OPT_SELECT_NEXT or GHOSTTY_SEARCH_OPT_SELECT_PREV.
+ *
+ * @ingroup search
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** Scroll the viewport so the match is visible, only if it is not
+ * already visible. This is the default. */
+ GHOSTTY_SEARCH_SCROLL_IF_NEEDED = 0,
+
+ /** Never scroll the viewport. */
+ GHOSTTY_SEARCH_SCROLL_NONE = 1,
+
+ GHOSTTY_SEARCH_SCROLL_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySearchScroll;
+
+/**
+ * Data fields readable with ghostty_search_get(). The output value
+ * type is documented per field.
+ *
+ * All reads reflect the terminal's active screen as of the last feed.
+ * When the running application switches to the alternate screen, the
+ * next feed switches counts, matches, and selection to that screen's
+ * results. Primary screen results, including completed scrollback
+ * searches, are retained and restored on the way back.
+ *
+ * @ingroup search
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** Current search status: GhosttySearchStatus*. */
+ GHOSTTY_SEARCH_DATA_STATUS = 0,
+
+ /**
+ * The needle this search is looking for: GhosttyString*. The bytes
+ * are borrowed from the search and remain valid until the needle is
+ * changed or the search is freed. Returns GHOSTTY_NO_VALUE when no
+ * needle is set.
+ */
+ GHOSTTY_SEARCH_DATA_NEEDLE = 1,
+
+ /**
+ * Total matches found so far on the active screen: size_t*. Zero
+ * until the first feed.
+ */
+ GHOSTTY_SEARCH_DATA_TOTAL_MATCHES = 2,
+
+ /**
+ * Index of the selected match: size_t*. This indexes the newest to
+ * oldest ordering of GHOSTTY_SEARCH_DATA_MATCHES, where 0 is the
+ * newest match, so a "k of n" find bar renders index + 1 of
+ * GHOSTTY_SEARCH_DATA_TOTAL_MATCHES. Returns GHOSTTY_NO_VALUE when
+ * nothing is selected.
+ */
+ GHOSTTY_SEARCH_DATA_SELECTED_INDEX = 3,
+
+ /**
+ * The selected match: GhosttySelection*. This is an untracked
+ * snapshot with standard GhosttySelection lifetime rules. Returns
+ * GHOSTTY_NO_VALUE when nothing is selected.
+ */
+ GHOSTTY_SEARCH_DATA_SELECTED_MATCH = 4,
+
+ /**
+ * All matches on the active screen, ordered newest to oldest, from
+ * the bottom of the active area up through scrollback:
+ * GhosttySelectionBuffer*. Set ptr to NULL with cap 0 to query the
+ * required capacity. An undersized buffer returns
+ * GHOSTTY_OUT_OF_SPACE with the required capacity in len.
+ */
+ GHOSTTY_SEARCH_DATA_MATCHES = 5,
+
+ /**
+ * Matches on the pages covering the viewport, for drawing highlight
+ * rectangles: GhosttySelectionBuffer*. The list is computed during
+ * feeds and cached, so it reflects the viewport as of the last
+ * feed.
+ *
+ * Matches are found a page at a time, so the list can include
+ * matches slightly outside the visible viewport when they share a
+ * page with it. Ghostty's own renderer behaves the same way.
+ * Converting each match to viewport coordinates with
+ * ghostty_terminal_point_from_grid_ref() clips this naturally: skip
+ * matches that fail the conversion or whose row is beyond the
+ * visible row count.
+ */
+ GHOSTTY_SEARCH_DATA_VIEWPORT_MATCHES = 6,
+
+ /** Current scroll policy: GhosttySearchScroll*. */
+ GHOSTTY_SEARCH_DATA_SELECT_SCROLL = 7,
+
+ GHOSTTY_SEARCH_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySearchData;
+
+/**
+ * Options writable with ghostty_search_set(). The value type, and
+ * what a NULL value means, is documented per option.
+ *
+ * @ingroup search
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /**
+ * Set the needle to search for: const GhosttyString*. The bytes are
+ * copied, so the caller's memory does not need to outlive the call.
+ * Matching is byte-exact except ASCII letters, which compare
+ * case-insensitively.
+ *
+ * Changing the needle restarts the search from scratch and drops
+ * all results. As an exception, setting a needle equal to the current
+ * one (compared the same way as matching) keeps existing results,
+ * so find bars can resubmit freely. A NULL or empty value clears
+ * the needle and returns the search to idle.
+ *
+ * Replacing or clearing a needle releases tracked state held
+ * within the terminal, so the caller must serialize this with all
+ * other access to the same terminal. Returns GHOSTTY_INVALID_VALUE
+ * after the terminal was freed.
+ */
+ GHOSTTY_SEARCH_OPT_NEEDLE = 0,
+
+ /**
+ * Select the next match, moving toward older content: from the
+ * bottom of the screen upward into history, the direction a search
+ * from the prompt usually wants. Wraps around past the oldest
+ * match.
+ *
+ * The value must be NULL. It is reserved for future use.
+ *
+ * This catches up with the terminal first, so it is safe to call at
+ * any time relative to feeds. The viewport scrolls to the newly
+ * selected match according to GHOSTTY_SEARCH_OPT_SELECT_SCROLL.
+ * This reads the terminal, so the caller must serialize it with all
+ * other access to the same terminal. Returns GHOSTTY_NO_VALUE when
+ * there are no matches.
+ */
+ GHOSTTY_SEARCH_OPT_SELECT_NEXT = 1,
+
+ /**
+ * Select the previous match, moving toward newer content, wrapping
+ * around past the newest match. Otherwise identical to
+ * GHOSTTY_SEARCH_OPT_SELECT_NEXT.
+ */
+ GHOSTTY_SEARCH_OPT_SELECT_PREV = 2,
+
+ /**
+ * Set the scroll policy applied by the select options: const
+ * GhosttySearchScroll*. The policy persists until changed. A NULL
+ * value resets it to GHOSTTY_SEARCH_SCROLL_IF_NEEDED. This only
+ * modifies search-owned state and never reads the terminal.
+ */
+ GHOSTTY_SEARCH_OPT_SELECT_SCROLL = 3,
+
+ GHOSTTY_SEARCH_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySearchOption;
+
+/**
+ * Create a search bound to a terminal.
+ *
+ * The search borrows the terminal and never frees it. The search and
+ * the terminal can be freed in either order; see ghostty_search_free().
+ *
+ * The search starts idle with no needle: it reports
+ * GHOSTTY_SEARCH_STATUS_COMPLETE and finds nothing. Set
+ * GHOSTTY_SEARCH_OPT_NEEDLE to start searching.
+ *
+ * Creation is cheap and does not read terminal contents, but it
+ * registers the search with the terminal so the two can be freed in
+ * any order. The caller must serialize this call with all other
+ * access to the same terminal.
+ *
+ * @param allocator Allocator, or NULL for the default allocator
+ * @param out_search Receives the created search handle
+ * @param terminal Terminal to bind the search to
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if
+ * out_search or terminal is invalid, or GHOSTTY_OUT_OF_MEMORY
+ * if allocation fails
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_new(
+ const GhosttyAllocator* allocator,
+ GhosttySearch* out_search,
+ GhosttyTerminal terminal);
+
+/**
+ * Free a search.
+ *
+ * If the bound terminal is still alive, this releases tracked state
+ * the search holds within it, so the caller must serialize this call
+ * with all other access to the same terminal. If the terminal was
+ * already freed, the search has been detached and this releases only
+ * search-owned memory. Passing NULL is allowed and is a no-op.
+ *
+ * @param search Search handle to free
+ *
+ * @ingroup search
+ */
+GHOSTTY_API void ghostty_search_free(GhosttySearch search);
+
+/**
+ * Make a bounded amount of search progress.
+ *
+ * This only works on data the search has already copied and never
+ * reads the terminal, so it is safe to call while another thread
+ * modifies the terminal. Call it in a loop while the status is
+ * GHOSTTY_SEARCH_STATUS_RUNNING. When the status becomes
+ * GHOSTTY_SEARCH_STATUS_FEED_REQUIRED, call ghostty_search_feed() to
+ * unblock it.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @param[out] out_status Receives the status after the tick (may be NULL)
+ * @return GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if
+ * search is NULL
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_tick(
+ GhosttySearch search,
+ GhosttySearchStatus* out_status);
+
+/**
+ * Read the terminal to update the search.
+ *
+ * Each feed catches the search up with the terminal: it reconciles
+ * the tracked screens against the live ones, re-scans the active
+ * area, refreshes the viewport match list, gives the scrollback
+ * searcher its next chunk of data, and prunes results that scrollback
+ * eviction invalidated. Feeding is also the only way the search
+ * learns about terminal changes, so keep feeding periodically while
+ * the search is in use, even after it reports complete.
+ *
+ * This reads the terminal, so the caller must serialize it with all
+ * other access to the same terminal. Each call does a bounded amount
+ * of work so that any caller-held terminal lock is held only briefly.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @return GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if
+ * search is NULL or the terminal was freed
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_feed(GhosttySearch search);
+
+/**
+ * Feed and tick until the search is caught up with the terminal.
+ *
+ * This is a blocking convenience for one-shot and single-threaded
+ * embedders. It always performs at least one feed, so it also picks
+ * up any terminal changes since the last feed, then loops until the
+ * status is GHOSTTY_SEARCH_STATUS_COMPLETE. Searching a large
+ * scrollback can take a while, so interactive embedders should drive
+ * ghostty_search_tick() and ghostty_search_feed() themselves.
+ *
+ * This reads the terminal for the entire call, so the caller must
+ * serialize it with all other access to the same terminal.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @return GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if
+ * search is NULL or the terminal was freed
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_run(GhosttySearch search);
+
+/**
+ * Write an option to a search.
+ *
+ * The value type, and what a NULL value means, depends on the option
+ * and is documented by GhosttySearchOption. The needle and select
+ * options touch the terminal, so the caller must serialize those
+ * calls with all other access to the same terminal.
+ * GHOSTTY_SEARCH_OPT_SELECT_SCROLL only modifies search-owned state.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @param option Option to write
+ * @param value Pointer to the input value for the option. The meaning
+ * of NULL is documented per option.
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if a select
+ * option found no matches, GHOSTTY_OUT_OF_MEMORY if
+ * allocation fails, or GHOSTTY_INVALID_VALUE if search,
+ * option, or value is invalid or the option needs a terminal
+ * that was already freed
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_set(
+ GhosttySearch search,
+ GhosttySearchOption option,
+ const void* value);
+
+/**
+ * Read a data field from a search.
+ *
+ * The output value type depends on data and is documented by
+ * GhosttySearchData. This never reads the terminal, so it is safe to
+ * call while another thread modifies the terminal. Returned
+ * selections are untracked snapshots with standard GhosttySelection
+ * lifetime rules.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @param data Data field to read
+ * @param value Output pointer whose type depends on data
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the
+ * requested data has no value, GHOSTTY_OUT_OF_SPACE if a
+ * provided GhosttySelectionBuffer is too small (required
+ * capacity in its len), GHOSTTY_OUT_OF_MEMORY if collecting
+ * viewport matches fails, or GHOSTTY_INVALID_VALUE if search,
+ * data, or value is invalid
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_get(
+ GhosttySearch search,
+ GhosttySearchData data,
+ void* value);
+
+/**
+ * Read multiple data fields from a search in a single call.
+ *
+ * This is an optimization over calling ghostty_search_get() multiple
+ * times. Each entry in values must point to storage of the type
+ * documented by the corresponding GhosttySearchData key.
+ *
+ * If any individual read fails, the function returns that error and
+ * writes the index of the failing key to out_written when out_written
+ * is non-NULL. Earlier keys have already been written. On success,
+ * out_written receives count when non-NULL. A too-small
+ * GhosttySelectionBuffer stops the batch with GHOSTTY_OUT_OF_SPACE at
+ * that key's index with the required capacity in its len, so order
+ * buffer-valued keys after scalar keys.
+ *
+ * @param search Search handle (NULL returns GHOSTTY_INVALID_VALUE)
+ * @param count Number of data fields to read
+ * @param keys Data fields to read (must not be NULL)
+ * @param values Output pointers corresponding to keys (must not be NULL)
+ * @param out_written Optional number of fields read, or failing index
+ * on error
+ * @return GHOSTTY_SUCCESS on success, or the first failing read's
+ * result
+ *
+ * @ingroup search
+ */
+GHOSTTY_API GhosttyResult ghostty_search_get_multi(
+ GhosttySearch search,
+ size_t count,
+ const GhosttySearchData* keys,
+ void** values,
+ size_t* out_written);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GHOSTTY_VT_SEARCH_H */
diff --git a/vendor/libghostty-vt/include/ghostty/vt/selection.h b/vendor/libghostty-vt/include/ghostty/vt/selection.h
index 3b926aab..0158965e 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/selection.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/selection.h
@@ -117,6 +117,29 @@ typedef struct {
} GhosttySelection;
/**
+ * A caller-provided buffer of selections.
+ *
+ * This follows the same conventions as GhosttyBuffer: ptr may be NULL with
+ * cap 0 to query the required capacity. APIs that fill this type set len to
+ * the number of entries written on GHOSTTY_SUCCESS, or to the required entry
+ * capacity on GHOSTTY_OUT_OF_SPACE.
+ *
+ * @ingroup selection
+ */
+typedef struct {
+ /** Destination buffer for selections. May be NULL when cap is 0 to query
+ * the required capacity. */
+ GhosttySelection* ptr;
+
+ /** Capacity of ptr in entries. */
+ size_t cap;
+
+ /** Entries written on success, or required entry capacity on
+ * GHOSTTY_OUT_OF_SPACE. */
+ size_t len;
+} GhosttySelectionBuffer;
+
+/**
* Options for deriving a word selection from a terminal grid reference.
*
* This is a sized struct. Use GHOSTTY_INIT_SIZED() to initialize it.
@@ -884,6 +907,8 @@ GHOSTTY_API GhosttyResult ghostty_terminal_selection_format_buf(
* The returned buffer is allocated using allocator, or the default allocator
* if NULL is passed. The caller owns the returned buffer and must free it with
* ghostty_free(), passing the same allocator and returned length.
+ * Empty output returns GHOSTTY_SUCCESS with *out_ptr set to NULL and
+ * *out_len set to zero. This result can be passed to ghostty_free().
*
* The returned bytes are not NUL-terminated. This supports plain text, VT, and
* HTML uniformly as byte output.
diff --git a/vendor/libghostty-vt/include/ghostty/vt/sgr.h b/vendor/libghostty-vt/include/ghostty/vt/sgr.h
index 757c5aed..b8aecb64 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/sgr.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/sgr.h
@@ -319,31 +319,6 @@ GHOSTTY_API GhosttySgrAttributeTag ghostty_sgr_attribute_tag(GhosttySgrAttribute
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
diff --git a/vendor/libghostty-vt/include/ghostty/vt/snapshot.h b/vendor/libghostty-vt/include/ghostty/vt/snapshot.h
new file mode 100644
index 00000000..89cb5398
--- /dev/null
+++ b/vendor/libghostty-vt/include/ghostty/vt/snapshot.h
@@ -0,0 +1,569 @@
+/**
+ * @file snapshot.h
+ *
+ * Encode and restore complete terminal snapshots.
+ */
+
+#ifndef GHOSTTY_VT_SNAPSHOT_H
+#define GHOSTTY_VT_SNAPSHOT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ghostty/vt/allocator.h>
+#include <ghostty/vt/io.h>
+#include <ghostty/vt/terminal.h>
+#include <ghostty/vt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup snapshot Terminal Snapshot
+ *
+ * Encode and restore the complete state of a terminal via a binary format.
+ *
+ * A snapshot is an ordered, CRC-protected record stream. Its READY marker
+ * follows enough state to render and resume the terminal, including any
+ * unfinished VT parser input. Older scrollback pages follow READY and the
+ * FINISH marker terminates the complete snapshot.
+ *
+ * End-of-file before an operation's required READY or FINISH marker is
+ * malformed, truncated snapshot data and returns GHOSTTY_INVALID_VALUE.
+ * GHOSTTY_IO_ERROR is reserved for a reader callback that returns false.
+ *
+ * ## Examples
+ *
+ * The complete working example is available in `example/c-vt-snapshot`.
+ *
+ * ### Encode a terminal and its unfinished VT continuation
+ * @snippet c-vt-snapshot/src/main.c snapshot-encode
+ *
+ * ### Restore a complete snapshot in one call
+ * @snippet c-vt-snapshot/src/main.c snapshot-decode
+ *
+ * ### Adapt a byte source to GhosttyReader
+ * @snippet c-vt-snapshot/src/main.c snapshot-buffer-reader
+ *
+ * ### Restore READY first, then incrementally prepend history
+ * @snippet c-vt-snapshot/src/main.c snapshot-incremental
+ *
+ * ## Format
+ *
+ * Every integer is unsigned and little-endian. The stream begins with this
+ * fixed ten-byte envelope:
+ *
+ * @code{.unparsed}
+ * byte 0 8 10
+ * +---------------+--------+
+ * | "GHOSTSNP" | version|
+ * | 8-byte magic | u16 |
+ * +---------------+--------+
+ * @endcode
+ *
+ * The envelope is followed by independently checksummed records. A record's
+ * CRC32C covers its encoded tag and payload length followed by its payload; it
+ * does not cover the CRC field itself.
+ *
+ * @code{.unparsed}
+ * byte 0 2 6 10 10 + payload_len
+ * +-------+-------------+-----------+----------------+
+ * | tag | payload_len | CRC32C | payload |
+ * | u16 | u32 | u32 | payload_len B |
+ * +-------+-------------+-----------+----------------+
+ * \____________________/ \______________/
+ * CRC prefix CRC suffix
+ * @endcode
+ *
+ * Record groups occur in this strict order. SCREEN and HISTORY groups contain
+ * one entry for each screen declared by TERMINAL. Each manifest is followed
+ * by the number of PAGE records it declares. Active SCREEN pages make the
+ * terminal renderable; HISTORY pages are older scrollback ordered newest to
+ * oldest so an incremental decoder can prepend them as they arrive.
+ *
+ * @code{.unparsed}
+ * +---------------- TERMINAL ----------------+
+ * | terminal-wide state and screen count |
+ * +----------------- SCREEN -----------------+ repeated per screen
+ * | active-screen manifest |
+ * +------------------ PAGE ------------------+ repeated per manifest
+ * | active screen rows |
+ * +------------- CONTINUATION ---------------+
+ * | unfinished VT/UTF-8 input, or ground |
+ * +------------------ READY -----------------+
+ * | empty renderable-state marker | ready() returns here
+ * +----------------- HISTORY ----------------+ repeated per screen
+ * | scrollback manifest |
+ * +------------------ PAGE ------------------+ next() consumes one page
+ * | older screen rows |
+ * +------------------ FINISH ----------------+
+ * | empty end-of-snapshot marker | next() returns NO_VALUE
+ * +------------------------------------------+
+ * | trailing transport bytes (not consumed) |
+ * +------------------------------------------+
+ * @endcode
+ *
+ * READY separates the renderable prefix through CONTINUATION from history.
+ * FINISH terminates the record sequence. Both are empty records protected by
+ * CRC32C, like every other record. Declared record counts, tags, and strict
+ * decoding enforce the stream's ordering and completeness.
+ *
+ * Snapshot format version 1 is a work in progress and does not yet carry a
+ * binary-compatibility guarantee.
+ *
+ * @see <a href="https://github.com/ghostty-org/ghostty/blob/main/src/terminal/snapshot/main.zig">Snapshot format and Zig codec documentation</a>
+ *
+ * @{
+ */
+
+/**
+ * Configurable snapshot decoder options.
+ *
+ * Options may only be changed before decoding starts. Calling
+ * ghostty_snapshot_decoder_set() after ghostty_snapshot_decoder_ready() or
+ * ghostty_snapshot_decoder_decode() returns GHOSTTY_INVALID_VALUE.
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /**
+ * Largest non-ground continuation the decoder will accept.
+ *
+ * A value of zero accepts only snapshots whose VT parser is in the ground
+ * state. The decoder default matches the largest built-in APC protocol
+ * buffer limit, currently 65 MiB.
+ *
+ * This is primarily an input validation limit. When
+ * GHOSTTY_SNAPSHOT_DECODER_OPT_RETAIN_CONTINUATION is true, the same value
+ * also becomes the continuation tracking limit on the returned terminal.
+ *
+ * Input type: size_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_OPT_MAX_CONTINUATION_BYTES = 0,
+
+ /**
+ * Retain the decoded continuation on the returned terminal.
+ *
+ * When true, terminals returned by ghostty_snapshot_decoder_ready() and
+ * ghostty_snapshot_decoder_decode() use
+ * GHOSTTY_SNAPSHOT_DECODER_OPT_MAX_CONTINUATION_BYTES as their continuation
+ * tracking limit. The existing ghostty_terminal_continuation_* APIs can then
+ * export the exact unfinished VT or UTF-8 input restored from the snapshot.
+ *
+ * This is false by default. A maximum continuation size of zero leaves
+ * tracking disabled. With a nonzero maximum, tracking remains enabled even
+ * when the decoded continuation is empty. Exporting an empty continuation
+ * does not disable it. Callers that do not need ongoing tracking must still
+ * set GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to zero after export and
+ * before writing post-snapshot input.
+ *
+ * Input type: bool *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_OPT_RETAIN_CONTINUATION = 1,
+
+ GHOSTTY_SNAPSHOT_DECODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySnapshotDecoderOption;
+
+/**
+ * Queryable snapshot decoder data.
+ *
+ * Each variant documents the output pointer type expected by
+ * ghostty_snapshot_decoder_get().
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** Invalid data type. Never results in data extraction. */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_INVALID = 0,
+
+ /**
+ * Current maximum accepted continuation size.
+ *
+ * This value is available in every non-failed decoder state.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_MAX_CONTINUATION_BYTES = 1,
+
+ /**
+ * Number of snapshot source bytes consumed so far.
+ *
+ * At FINISH this identifies the first byte after the snapshot. Trailing
+ * bytes are not consumed. This value is unavailable after a decoding error,
+ * because the decoder can no longer guarantee its source position.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_SOURCE_OFFSET = 2,
+
+ /**
+ * Advisory complete logical history extent for the primary screen.
+ *
+ * The value counts rows before the active area, including any resident
+ * overlap carried before READY. It becomes available after READY validates.
+ *
+ * Output type: uint64_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_HISTORY_ROWS_PRIMARY = 3,
+
+ /**
+ * Advisory complete logical history extent for the alternate screen.
+ *
+ * The value has the same semantics and lifetime as
+ * GHOSTTY_SNAPSHOT_DECODER_DATA_HISTORY_ROWS_PRIMARY. Querying it returns
+ * GHOSTTY_NO_VALUE when the snapshot does not declare an alternate screen.
+ *
+ * Output type: uint64_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_HISTORY_ROWS_ALTERNATE = 4,
+
+ /**
+ * Screen associated with the most recently decoded history page.
+ *
+ * This value is available only after ghostty_snapshot_decoder_next()
+ * returns GHOSTTY_SUCCESS. A later call to next replaces it or clears it
+ * when FINISH is reached or an error occurs.
+ *
+ * Output type: GhosttyTerminalScreen *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_PROGRESS_SCREEN = 5,
+
+ /**
+ * Rows prepended by the most recently decoded history page.
+ *
+ * Zero means the page was consumed and validated but could not be
+ * applied to the live terminal.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_PROGRESS_ROWS = 6,
+
+ /**
+ * Page records remaining in the same screen's HISTORY sequence.
+ *
+ * This is not a count of all pages remaining in the snapshot.
+ *
+ * Output type: uint32_t *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_PROGRESS_REMAINING = 7,
+
+ /**
+ * Whether decoded continuation tracking is retained on returned terminals.
+ *
+ * This value is available in every non-failed decoder state.
+ *
+ * Output type: bool *
+ */
+ GHOSTTY_SNAPSHOT_DECODER_DATA_RETAIN_CONTINUATION = 8,
+
+ GHOSTTY_SNAPSHOT_DECODER_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttySnapshotDecoderData;
+
+/**
+ * Encode a complete terminal snapshot to a writer.
+ *
+ * The terminal's persistent VT stream supplies the continuation bytes needed
+ * to reconstruct unfinished parser state. The caller must prevent concurrent
+ * writes or other terminal mutation for the duration of this call. The writer
+ * callback must not call terminal APIs with the same terminal handle.
+ * A terminal can be encoded with tracking disabled when its VT parser and
+ * UTF-8 decoder are both at ground. If either is unfinished, tracking must
+ * have been enabled before the input that produced that state was written;
+ * otherwise this returns GHOSTTY_INVALID_VALUE.
+ *
+ * Encoding begins at the writer's current position. If an error occurs, the
+ * writer may contain a partial snapshot without a valid FINISH marker.
+ * Calls to the writer are synchronous; this function does not flush or make
+ * the caller's destination durable.
+ *
+ * @param terminal Terminal to encode (must not be NULL)
+ * @param writer Destination writer whose write callback must not be NULL
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_IO_ERROR if the writer rejects
+ * output, GHOSTTY_LIMIT_EXCEEDED if output accounting overflows, or
+ * another error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_encode(GhosttyTerminal terminal,
+ GhosttyWriter writer);
+
+/**
+ * Encode a complete terminal snapshot to a caller-provided buffer.
+ *
+ * Pass NULL for buf with buf_len zero to query the required size. If the
+ * buffer is too small, this returns GHOSTTY_OUT_OF_SPACE and stores the
+ * required capacity in out_written. A non-NULL undersized buffer may contain
+ * a partial snapshot prefix. On success, out_written receives the number of
+ * bytes encoded.
+ *
+ * A terminal can be encoded with tracking disabled when its VT parser and
+ * UTF-8 decoder are both at ground. If either is unfinished, tracking must
+ * have been enabled before the input that produced that state was written;
+ * otherwise this returns GHOSTTY_INVALID_VALUE.
+ *
+ * @param terminal Terminal to encode (must not be NULL)
+ * @param buf Destination buffer, or NULL when buf_len is zero
+ * @param buf_len Destination buffer capacity in bytes
+ * @param[out] out_written Bytes written, or required capacity on
+ * GHOSTTY_OUT_OF_SPACE (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_encode_buf(
+ GhosttyTerminal terminal,
+ uint8_t* buf,
+ size_t buf_len,
+ size_t* out_written);
+
+/**
+ * Encode a complete terminal snapshot to an allocated buffer.
+ *
+ * The returned buffer is allocated with allocator, or the default allocator
+ * when allocator is NULL. The caller must release it with ghostty_free(),
+ * passing the same allocator used here.
+ *
+ * A terminal can be encoded with tracking disabled when its VT parser and
+ * UTF-8 decoder are both at ground. If either is unfinished, tracking must
+ * have been enabled before the input that produced that state was written;
+ * otherwise this returns GHOSTTY_INVALID_VALUE.
+ *
+ * @param terminal Terminal to encode (must not be NULL)
+ * @param allocator Allocator for the output, or NULL for the default allocator
+ * @param[out] out_ptr Allocated snapshot bytes (must not be NULL)
+ * @param[out] out_len Number of allocated snapshot bytes (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_encode_alloc(
+ GhosttyTerminal terminal,
+ const GhosttyAllocator* allocator,
+ uint8_t** out_ptr,
+ size_t* out_len);
+
+/**
+ * Create a snapshot decoder that reads from a caller-provided reader.
+ *
+ * The decoder stores a copy of reader. Its read callback must not be NULL, and
+ * both the callback and its caller-owned context must remain valid until
+ * FINISH is reached or the decoder is freed. Reads are synchronous and occur
+ * only during ready, next, or decode calls. A zero-byte successful read is
+ * permanent end-of-file, not temporary starvation; nonblocking sources must
+ * wait outside the decoder or block in their callback. The read callback must
+ * not call APIs, including ghostty_snapshot_decoder_free(), on the decoder
+ * that owns it. Returning false reports GHOSTTY_IO_ERROR; returning true with
+ * zero bytes before a required marker reports truncated snapshot data as
+ * GHOSTTY_INVALID_VALUE.
+ *
+ * @param allocator Allocator for decoder and decoded terminal state, or NULL
+ * for the default allocator
+ * @param decoder Pointer to receive the decoder handle (must not be NULL)
+ * @param reader Snapshot source reader
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_new(
+ const GhosttyAllocator* allocator,
+ GhosttySnapshotDecoder* decoder,
+ GhosttyReader reader);
+
+/**
+ * Create a snapshot decoder over a borrowed byte buffer.
+ *
+ * The bytes are not copied. ptr must remain valid and immutable until FINISH
+ * is reached or the decoder is freed. Bytes after FINISH are not consumed;
+ * query GHOSTTY_SNAPSHOT_DECODER_DATA_SOURCE_OFFSET to locate them.
+ *
+ * @param allocator Allocator for decoder and decoded terminal state, or NULL
+ * for the default allocator
+ * @param decoder Pointer to receive the decoder handle (must not be NULL)
+ * @param ptr Snapshot source bytes
+ * @param len Number of source bytes
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_new_buf(
+ const GhosttyAllocator* allocator,
+ GhosttySnapshotDecoder* decoder,
+ const uint8_t* ptr,
+ size_t len);
+
+/**
+ * Free a snapshot decoder.
+ *
+ * This does not release the caller's ownership of a terminal returned by
+ * ready or decode. Abandoning an incremental decode leaves that terminal
+ * usable with whatever history had already been restored.
+ *
+ * @param decoder Decoder to free (may be NULL)
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API void ghostty_snapshot_decoder_free(GhosttySnapshotDecoder decoder);
+
+/**
+ * Set a snapshot decoder option.
+ *
+ * The value pointer must have the type documented by option. Options may only
+ * be changed before decoding starts.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @param option Option to change
+ * @param value Pointer to the option value (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if decoding has
+ * started or an argument is invalid, or another error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_set(
+ GhosttySnapshotDecoder decoder,
+ GhosttySnapshotDecoderOption option,
+ const void* value);
+
+/**
+ * Decode and validate the renderable snapshot prefix through READY.
+ *
+ * On success, terminal receives a caller-owned terminal with its persistent
+ * VT stream already restored from the snapshot continuation. The terminal is
+ * immediately usable for rendering and live input. Older scrollback remains
+ * to be restored with ghostty_snapshot_decoder_next().
+ *
+ * The restored parser state may be unfinished. By default, terminal
+ * continuation tracking is disabled and
+ * GHOSTTY_TERMINAL_DATA_CONTINUATION_MAX_BYTES returns zero. When
+ * GHOSTTY_SNAPSHOT_DECODER_OPT_RETAIN_CONTINUATION is true, the decoder's
+ * maximum continuation size is applied to the terminal, and the terminal
+ * continuation APIs export the exact current continuation when that limit is
+ * nonzero. Tracking remains enabled even if the exported continuation is
+ * empty. Callers that do not need ongoing tracking must set
+ * GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to zero after export and before
+ * writing any post-snapshot bytes, because later input may change it.
+ *
+ * The caller must keep the returned terminal alive until FINISH validates or
+ * the decoder is freed. The decoder borrows this terminal handle while it
+ * restores history; ghostty_snapshot_decoder_next() uses it automatically.
+ *
+ * This operation may only be called once and only before decoding starts.
+ * terminal is set to NULL on every error. A decoding, I/O, or allocation
+ * error after input consumption begins poisons the decoder, after which it
+ * must be freed. An invalid argument or lifecycle error detected before the
+ * operation consumes input does not poison it.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @param[out] terminal Pointer to receive the terminal (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_ready(
+ GhosttySnapshotDecoder decoder,
+ GhosttyTerminal* terminal);
+
+/**
+ * Decode one history page into the terminal returned by READY.
+ *
+ * Each GHOSTTY_SUCCESS consumes and validates one PAGE record. Query the
+ * GHOSTTY_SNAPSHOT_DECODER_DATA_PROGRESS_* values before calling next again.
+ * GHOSTTY_NO_VALUE means FINISH was validated; repeated calls after FINISH
+ * also return GHOSTTY_NO_VALUE.
+ *
+ * The terminal may be rendered, resized, and fed live PTY input between calls.
+ * If a history page can no longer be applied safely, it is still consumed and
+ * validated and progress reports zero rows. The decoder applies history
+ * to the caller-owned terminal produced by its READY operation.
+ *
+ * A decoding error invalidates the decoder's source position. The terminal
+ * remains caller-owned and usable with its already-restored history, but only
+ * ghostty_snapshot_decoder_free() may subsequently be called on the decoder.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @return GHOSTTY_SUCCESS for one page, GHOSTTY_NO_VALUE after FINISH, or an
+ * error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_next(
+ GhosttySnapshotDecoder decoder);
+
+/**
+ * Decode and validate one complete snapshot.
+ *
+ * This is the one-shot form of READY followed by all history pages through
+ * FINISH. It may only be called before decoding starts. Bytes following FINISH
+ * are left unread. On success terminal receives a caller-owned terminal with
+ * its persistent VT stream restored. Continuation tracking on the returned
+ * terminal is disabled by default. When
+ * GHOSTTY_SNAPSHOT_DECODER_OPT_RETAIN_CONTINUATION is true, the decoder's
+ * maximum continuation size is applied to the terminal, and the terminal
+ * continuation APIs export the exact current continuation when that limit is
+ * nonzero. Tracking remains enabled even if the exported continuation is
+ * empty. Callers that do not need ongoing tracking must set
+ * GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to zero after export and before
+ * writing any post-snapshot bytes, because later input may change it.
+ * terminal is set to NULL on every error.
+ * A decoding, I/O, or allocation error after input consumption begins poisons
+ * the decoder, after which it must be freed. An invalid argument or
+ * lifecycle error detected before the operation consumes input does not
+ * poison it.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @param[out] terminal Pointer to receive the terminal (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, or an error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_decode(
+ GhosttySnapshotDecoder decoder,
+ GhosttyTerminal* terminal);
+
+/**
+ * Get typed data from a snapshot decoder.
+ *
+ * The output pointer must have the type documented by data. A phase-dependent
+ * value that is not currently available returns GHOSTTY_NO_VALUE.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @param data Data kind to query
+ * @param[out] out Pointer to receive the value (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the requested data
+ * is unavailable, or another error code on failure
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_get(
+ GhosttySnapshotDecoder decoder,
+ GhosttySnapshotDecoderData data,
+ void* out);
+
+/**
+ * Get multiple snapshot decoder data fields in a single call.
+ *
+ * Each keys element selects a data kind and the corresponding values element
+ * points to storage of the documented output type. Processing stops at the
+ * first error. On success out_written is set to count; on error it is set to
+ * the number of values written before the failing key. Invalid array arguments
+ * report zero values written.
+ *
+ * @param decoder Decoder handle (must not be NULL)
+ * @param count Number of key/value pairs
+ * @param keys Array of data kinds to query
+ * @param values Array of output pointers corresponding to keys
+ * @param[out] out_written Number of successfully written values (may be NULL)
+ * @return GHOSTTY_SUCCESS if every query succeeds, or the first error
+ *
+ * @ingroup snapshot
+ */
+GHOSTTY_API GhosttyResult ghostty_snapshot_decoder_get_multi(
+ GhosttySnapshotDecoder decoder,
+ size_t count,
+ const GhosttySnapshotDecoderData* keys,
+ void** values,
+ size_t* out_written);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GHOSTTY_VT_SNAPSHOT_H */
diff --git a/vendor/libghostty-vt/include/ghostty/vt/sys.h b/vendor/libghostty-vt/include/ghostty/vt/sys.h
index ae905969..c5e5903b 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/sys.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/sys.h
@@ -125,6 +125,24 @@ typedef bool (*GhosttySysDecodePngFn)(
GhosttySysImage* out);
/**
+ * Callback type for secure random bytes.
+ *
+ * Fills @p buf with @p len cryptographically secure random bytes. The
+ * library uses this for secrets, so it must be a real CSPRNG (getrandom,
+ * arc4random_buf, BCryptGenRandom, crypto.getRandomValues, ...); a
+ * predictable source is a security hole.
+ *
+ * @param userdata The userdata pointer set via GHOSTTY_SYS_OPT_USERDATA
+ * @param buf Buffer to fill
+ * @param len Number of bytes to fill
+ * @return true if the buffer was filled, false if no entropy is available
+ */
+typedef bool (*GhosttySysRandomSecureFn)(
+ void* userdata,
+ uint8_t* buf,
+ size_t len);
+
+/**
* System option identifiers for ghostty_sys_set().
*/
typedef enum GHOSTTY_ENUM_TYPED {
@@ -165,6 +183,21 @@ typedef enum GHOSTTY_ENUM_TYPED {
* Input type: GhosttySysLogFn (function pointer, or NULL)
*/
GHOSTTY_SYS_OPT_LOG = 2,
+
+ /**
+ * Override the secure random source.
+ *
+ * By default the library draws secure random bytes from the
+ * platform (getrandom or arc4random_buf on POSIX, CNG on Windows).
+ * Targets without one, such as wasm32-freestanding, have no default
+ * and operations that need entropy fail with GHOSTTY_IO_ERROR until
+ * this is set. When set,
+ * it is used instead of the platform source on every target. When
+ * cleared (NULL value), the platform default is restored.
+ *
+ * Input type: GhosttySysRandomSecureFn (function pointer, or NULL)
+ */
+ GHOSTTY_SYS_OPT_RANDOM_SECURE = 3,
GHOSTTY_SYS_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttySysOption;
diff --git a/vendor/libghostty-vt/include/ghostty/vt/terminal.h b/vendor/libghostty-vt/include/ghostty/vt/terminal.h
index 9bb961d3..ad5eec54 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/terminal.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/terminal.h
@@ -16,6 +16,7 @@
#include <ghostty/vt/modes.h>
#include <ghostty/vt/size_report.h>
#include <ghostty/vt/grid_ref.h>
+#include <ghostty/vt/io.h>
#include <ghostty/vt/kitty_graphics.h>
#include <ghostty/vt/screen.h>
#include <ghostty/vt/point.h>
@@ -53,17 +54,17 @@ extern "C" {
*
* ## Effects
*
- * By default, the terminal sequence processing with ghostty_terminal_vt_write()
- * only process sequences that directly affect terminal state and
+ * By default, terminal sequence processing with the VT write functions only
+ * processes sequences that directly affect terminal state and
* ignores sequences that have side effect behavior or require responses.
* These sequences include things like bell characters, title changes, device
* attributes queries, and more. To handle these sequences, the embedder
* must configure "effects."
*
* Effects are callbacks that the terminal invokes in response to VT
- * sequences processed during ghostty_terminal_vt_write(). They let the
- * embedding application react to terminal-initiated events such as bell
- * characters, title changes, device status report responses, and more.
+ * sequences processed during VT writes. They let the embedding application
+ * react to terminal-initiated events such as bell characters, title changes,
+ * device status report responses, and more.
*
* Each effect is registered with ghostty_terminal_set() using the
* corresponding `GhosttyTerminalOption` identifier. A `NULL` value
@@ -74,9 +75,10 @@ extern "C" {
* back to their own application state without global variables.
* You cannot specify different userdata for different callbacks.
*
- * All callbacks are invoked synchronously during
- * ghostty_terminal_vt_write(). Callbacks **must not** call
- * ghostty_terminal_vt_write() on the same terminal (no reentrancy).
+ * All callbacks are invoked synchronously during VT writes. Callbacks
+ * **must not** call ghostty_terminal_vt_write() or
+ * ghostty_terminal_vt_write_until_ground() on the same terminal
+ * (no reentrancy).
* And callbacks must be very careful to not block for too long or perform
* expensive operations, since they are blocking further IO processing.
*
@@ -84,16 +86,20 @@ extern "C" {
*
* | Option | Callback Type | Trigger |
* |-----------------------------------------|-----------------------------------|-------------------------------------------|
- * | `GHOSTTY_TERMINAL_OPT_WRITE_PTY` | `GhosttyTerminalWritePtyFn` | Query responses written back to the pty |
+ * | `GHOSTTY_TERMINAL_OPT_WRITE_PTY` | `GhosttyTerminalWritePtyFn` | VT query and mode reports written back to the PTY |
* | `GHOSTTY_TERMINAL_OPT_BELL` | `GhosttyTerminalBellFn` | BEL character (0x07) |
* | `GHOSTTY_TERMINAL_OPT_TITLE_CHANGED` | `GhosttyTerminalTitleChangedFn` | Title change via OSC 0 / OSC 2 |
* | `GHOSTTY_TERMINAL_OPT_PWD_CHANGED` | `GhosttyTerminalPwdChangedFn` | Pwd change via OSC 7 / OSC 9 / OSC 1337 |
* | `GHOSTTY_TERMINAL_OPT_ENQUIRY` | `GhosttyTerminalEnquiryFn` | ENQ character (0x05) |
* | `GHOSTTY_TERMINAL_OPT_XTVERSION` | `GhosttyTerminalXtversionFn` | XTVERSION query (CSI > q) |
- * | `GHOSTTY_TERMINAL_OPT_SIZE` | `GhosttyTerminalSizeFn` | XTWINOPS size query (CSI 14/16/18 t) |
+ * | `GHOSTTY_TERMINAL_OPT_SIZE` | `GhosttyTerminalSizeFn` | XTWINOPS query (CSI 14/16/18 t) or mode 2048 enable |
* | `GHOSTTY_TERMINAL_OPT_COLOR_SCHEME` | `GhosttyTerminalColorSchemeFn` | Color scheme query (CSI ? 996 n) |
* | `GHOSTTY_TERMINAL_OPT_DEVICE_ATTRIBUTES`| `GhosttyTerminalDeviceAttributesFn`| Device attributes query (CSI c / > c / = c)|
- * | `GHOSTTY_TERMINAL_OPT_CLIPBOARD_WRITE` | `GhosttyTerminalClipboardWriteFn` | Clipboard write via OSC 52 / OSC 1337 |
+ * | `GHOSTTY_TERMINAL_OPT_CLIPBOARD_WRITE` | `GhosttyTerminalClipboardWriteFn` | Clipboard write via OSC 52 / OSC 1337 / OSC 5522 |
+ * | `GHOSTTY_TERMINAL_OPT_CLIPBOARD_READ` | `GhosttyTerminalClipboardReadFn` | Clipboard read via OSC 52 "?" / OSC 5522 |
+ * | `GHOSTTY_TERMINAL_OPT_DESKTOP_NOTIFICATION`| `GhosttyTerminalDesktopNotificationFn` | Desktop notification via OSC 9 / OSC 777 |
+ * | `GHOSTTY_TERMINAL_OPT_PROGRESS_REPORT` | `GhosttyTerminalProgressReportFn` | Progress report via OSC 9;4 |
+ * | `GHOSTTY_TERMINAL_OPT_UNKNOWN_SEQUENCE` | `GhosttyTerminalUnknownSequenceFn` | Unsupported sequence identifier |
*
* ### Defining a write_pty callback
* @snippet c-vt-effects/src/main.c effects-write-pty
@@ -107,6 +113,12 @@ extern "C" {
* ### Defining a clipboard_write callback
* @snippet c-vt-effects/src/main.c effects-clipboard-write
*
+ * ### Defining a clipboard_read callback
+ * @snippet c-vt-effects/src/main.c effects-clipboard-read
+ *
+ * ### Defining an unknown_sequence callback
+ * @snippet c-vt-effects/src/main.c effects-unknown-sequence
+ *
* ### Registering effects and processing VT data
* @snippet c-vt-effects/src/main.c effects-register
*
@@ -173,26 +185,6 @@ extern "C" {
*/
/**
- * Terminal initialization options.
- *
- * @ingroup terminal
- */
-typedef struct {
- /** Terminal width in cells. Must be greater than zero. */
- uint16_t cols;
-
- /** Terminal height in cells. Must be greater than zero. */
- uint16_t rows;
-
- /** Maximum number of lines to keep in scrollback history. */
- size_t max_scrollback;
-
- // TODO: Consider ABI compatibility implications of this struct.
- // We may want to artificially pad it significantly to support
- // future options.
-} GhosttyTerminalOptions;
-
-/**
* Amount of compression work to perform before returning.
*
* @ingroup terminal
@@ -349,6 +341,88 @@ typedef void (*GhosttyTerminalBellFn)(GhosttyTerminal terminal,
void* userdata);
/**
+ * Unsupported terminal sequence tags.
+ *
+ * Only APC sequences are currently reported. Additional sequence types may
+ * be added without changing the callback shape.
+ *
+ * @ingroup terminal
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** Application Program Command (APC). */
+ GHOSTTY_TERMINAL_UNKNOWN_SEQUENCE_APC = 0,
+ GHOSTTY_TERMINAL_UNKNOWN_SEQUENCE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttyTerminalUnknownSequenceTag;
+
+/**
+ * An unsupported string terminal sequence.
+ *
+ * The content is borrowed and valid only for the callback duration. It
+ * contains the bytes between the sequence introducer and terminator, may
+ * contain arbitrary binary data, and is not null-terminated.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Whether content was shortened by the byte limit or allocation failure. */
+ bool truncated;
+
+ /** Retained sequence content. */
+ GhosttyString content;
+} GhosttyTerminalUnknownStringSequence;
+
+/**
+ * Unsupported terminal sequence value.
+ *
+ * @ingroup terminal
+ */
+typedef union {
+ /** Application Program Command (APC). */
+ GhosttyTerminalUnknownStringSequence apc;
+
+ /**
+ * Padding for ABI compatibility. Do not use.
+ *
+ * 128 bytes leaves room for future structured sequence payloads, such as
+ * CSI with borrowed parameter, separator, and intermediate arrays, without
+ * changing the tagged union's ABI.
+ */
+ uint64_t _padding[16];
+} GhosttyTerminalUnknownSequenceValue;
+
+/**
+ * An unsupported terminal sequence.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ GhosttyTerminalUnknownSequenceTag tag;
+ GhosttyTerminalUnknownSequenceValue value;
+} GhosttyTerminalUnknownSequence;
+
+/**
+ * Callback function type for unsupported terminal sequences.
+ *
+ * Called synchronously for normally terminated sequences whose identifier is
+ * not supported by the active terminal handler. Aborted sequences, malformed
+ * recognized commands, and explicitly disabled known protocols are ignored.
+ *
+ * Capture must also be enabled with a nonzero
+ * GHOSTTY_TERMINAL_OPT_UNKNOWN_MAX_BYTES value. Installing this callback alone
+ * does not retain sequence content or allocate memory.
+ *
+ * @param terminal The terminal handle
+ * @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
+ * @param sequence Borrowed unsupported sequence
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyTerminalUnknownSequenceFn)(
+ GhosttyTerminal terminal,
+ void* userdata,
+ const GhosttyTerminalUnknownSequence* sequence);
+
+/**
* Clipboard destination for a clipboard write.
*
* Protocol-specific destination identifiers are normalized to these values
@@ -389,7 +463,78 @@ typedef struct {
} GhosttyClipboardContent;
/**
- * A semantic, atomic clipboard write.
+ * Result of a clipboard write reply.
+ *
+ * @ingroup terminal
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** The clipboard write completed successfully. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_SUCCESS = 0,
+
+ /** The clipboard write was denied by policy or the user. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_DENIED = 1,
+
+ /** The destination or one or more representations are unsupported. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_UNSUPPORTED = 2,
+
+ /** The clipboard is temporarily unavailable. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_BUSY = 3,
+
+ /** One or more representations contain invalid data. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_INVALID_DATA = 4,
+
+ /** The clipboard write failed due to an I/O error. */
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_IO_ERROR = 5,
+ GHOSTTY_CLIPBOARD_WRITE_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttyClipboardWriteResult;
+
+/**
+ * The reply to a clipboard write request.
+ *
+ * This is a sized struct; set `size` to `sizeof(GhosttyClipboardWriteReply)`.
+ * The reply is borrowed only for the duration of the reply call and may be
+ * freed as soon as it returns.
+ *
+ * The result answers the program with the matching protocol status for
+ * protocols with a write acknowledgement (OSC 5522: DONE, EPERM, ENOSYS,
+ * EBUSY, EINVAL, EIO); protocols without one (OSC 52, OSC 1337 Copy)
+ * discard the reply. `remember` is ignored on any result other than
+ * GHOSTTY_CLIPBOARD_WRITE_RESULT_SUCCESS.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /** Outcome of the write. */
+ GhosttyClipboardWriteResult result;
+
+ /**
+ * Record a session grant so future requests from the same program skip
+ * the permission prompt. Only honored on success when
+ * GhosttyClipboardWrite::can_remember is set.
+ */
+ bool remember;
+} GhosttyClipboardWriteReply;
+
+typedef struct GhosttyClipboardWrite GhosttyClipboardWrite;
+
+/**
+ * Function type used to answer a clipboard write request. Obtained from
+ * GhosttyClipboardWrite::reply; see that struct for the contract.
+ *
+ * @param write The request being answered
+ * @param reply The reply, borrowed only for the duration of this call
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyClipboardWriteReplyFn)(
+ const GhosttyClipboardWrite* write,
+ const GhosttyClipboardWriteReply* reply);
+
+/**
+ * A synchronous request to write clipboard contents.
*
* This is a sized struct. The callback must only access fields present in the
* size reported by `size`. The request, contents array, MIME strings, and
@@ -400,9 +545,15 @@ typedef struct {
* the destination be cleared. This is distinct from a content entry whose data
* has zero length.
*
+ * The write is answered by calling `reply` with this request and a
+ * GhosttyClipboardWriteReply. This must happen within the clipboard write
+ * request callback. This struct is only valid during that time. Calling
+ * `reply` more than once is safely ignored. Returning without replying
+ * denies the write.
+ *
* @ingroup terminal
*/
-typedef struct {
+struct GhosttyClipboardWrite {
/** Size of this struct in bytes. */
size_t size;
@@ -414,58 +565,351 @@ typedef struct {
/** Number of entries in contents; zero means clear the destination. */
size_t contents_len;
-} GhosttyClipboardWrite;
+
+ /**
+ * Name of the writing program for permission prompts, if the protocol
+ * carries one. Empty otherwise.
+ */
+ GhosttyString name;
+
+ /**
+ * True if the terminal already holds a session grant for this request
+ * The embedder should skip any permission prompt and perform the write.
+ */
+ bool granted;
+
+ /**
+ * True if the program supplied a session password, so the embedder may
+ * offer to remember the user's decision through
+ * GhosttyClipboardWriteReply::remember. When false, remember is ignored.
+ */
+ bool can_remember;
+
+ /** Terminal-owned reply state. Do not access. */
+ const void* ctx;
+
+ /** Answer the write; see the struct documentation. */
+ GhosttyClipboardWriteReplyFn reply;
+};
/**
- * Result of a clipboard write callback.
+ * Callback function type for clipboard_write.
*
- * Protocols without write acknowledgements, including OSC 52 and iTerm2
- * OSC 1337 Copy, ignore this result.
+ * The embedder may ask for permission to write or perform the write
+ * async, but the callback itself is synchronous and the reply function
+ * must be called during the lifetime of this function. While this callback
+ * is active the VT stream is paused.
+ *
+ * Answer by calling `write->reply(write, &reply)` before returning. See
+ * GhosttyClipboardWrite for the full contract.
+ *
+ * The request may carry an optional program name requesting the write
+ * and the state of prior permission granted. If `can_remember` is set
+ * the response may set the `remember` flag and future requests from this
+ * same program will be "granted" and the embedder can skip permission
+ * requests.
+ *
+ * Clipboard read requests (OSC 52 "?" and OSC 5522 reads) are delivered
+ * to GhosttyTerminalClipboardReadFn instead.
+ *
+ * @param terminal The terminal handle
+ * @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
+ * @param write Borrowed atomic clipboard write request
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyTerminalClipboardWriteFn)(
+ GhosttyTerminal terminal,
+ void* userdata,
+ const GhosttyClipboardWrite* write);
+
+/**
+ * Result of a clipboard read reply.
*
* @ingroup terminal
*/
typedef enum GHOSTTY_ENUM_TYPED {
- /** The clipboard write completed successfully. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_SUCCESS = 0,
+ /** The clipboard was read; the reply carries its contents. */
+ GHOSTTY_CLIPBOARD_READ_RESULT_SUCCESS = 0,
- /** The clipboard write was denied by policy or the user. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_DENIED = 1,
+ /** The clipboard read was denied by policy or the user. */
+ GHOSTTY_CLIPBOARD_READ_RESULT_DENIED = 1,
- /** The destination or one or more representations are unsupported. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_UNSUPPORTED = 2,
+ /** The embedder cannot read this clipboard. */
+ GHOSTTY_CLIPBOARD_READ_RESULT_UNSUPPORTED = 2,
/** The clipboard is temporarily unavailable. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_BUSY = 3,
+ GHOSTTY_CLIPBOARD_READ_RESULT_BUSY = 3,
- /** One or more representations contain invalid data. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_INVALID_DATA = 4,
+ /** Reading the clipboard failed due to an I/O error. */
+ GHOSTTY_CLIPBOARD_READ_RESULT_IO_ERROR = 4,
+ GHOSTTY_CLIPBOARD_READ_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttyClipboardReadResult;
- /** The clipboard write failed due to an I/O error. */
- GHOSTTY_CLIPBOARD_WRITE_RESULT_IO_ERROR = 5,
- GHOSTTY_CLIPBOARD_WRITE_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
-} GhosttyClipboardWriteResult;
+/**
+ * The reply to a clipboard read request.
+ *
+ * This is a sized struct; set `size` to `sizeof(GhosttyClipboardReadReply)`.
+ * All arrays and the strings they point to are borrowed only for the
+ * duration of the reply call and may be freed as soon as it returns.
+ *
+ * Any result other than GHOSTTY_CLIPBOARD_READ_RESULT_SUCCESS answers the
+ * program with an empty clipboard (OSC 52) or the matching protocol status
+ * (OSC 5522: EPERM, ENOSYS, EBUSY, EIO); the other fields are ignored in
+ * that case. On success, `contents` should carry one representation per
+ * requested MIME type (GhosttyClipboardRead::mimes) that the clipboard
+ * has; unrequested representations are ignored. Protocols that carry a
+ * single text value (OSC 52) use the first entry with a text MIME type
+ * such as "text/plain".
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /** Outcome of the read. */
+ GhosttyClipboardReadResult result;
+
+ /** Borrowed array of MIME representations of the clipboard contents. */
+ const GhosttyClipboardContent* contents;
+
+ /** Number of entries in contents. */
+ size_t contents_len;
+
+ /**
+ * Borrowed array of all MIME types available on the clipboard. Only
+ * used when GhosttyClipboardRead::list is set; may be NULL otherwise.
+ */
+ const GhosttyString* available;
+
+ /** Number of entries in available. */
+ size_t available_len;
+
+ /**
+ * Record a session grant so future requests from the same program skip
+ * the permission prompt. Only honored on success when
+ * GhosttyClipboardRead::can_remember is set.
+ */
+ bool remember;
+} GhosttyClipboardReadReply;
+
+typedef struct GhosttyClipboardRead GhosttyClipboardRead;
/**
- * Callback function type for clipboard_write.
+ * Function type used to answer a clipboard read request. Obtained from
+ * GhosttyClipboardRead::reply; see that struct for the contract.
+ *
+ * @param read The request being answered
+ * @param reply The reply, borrowed only for the duration of this call
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyClipboardReadReplyFn)(
+ const GhosttyClipboardRead* read,
+ const GhosttyClipboardReadReply* reply);
+
+/**
+ * A synchronous request to read clipboard contents.
*
- * Called synchronously for a complete logical clipboard write. Protocol
- * details such as OSC 52 selectors, base64 encoding, multipart chunks,
- * aliases, and terminators are normalized before this callback is invoked.
- * OSC 52 and iTerm2 OSC 1337 Copy writes therefore use the same callback
- * shape. OSC 52 clipboard read requests ("?") are always ignored and never
- * forwarded to this callback.
+ * This is a sized struct. The callback must only access fields present in the
+ * size reported by `size`. The request is borrowed and valid only for the
+ * callback duration.
+ *
+ * The read is answered by calling `reply` with this request and a
+ * GhosttyClipboardReadReply. This must happen before the callback returns;
+ * the request is invalid afterwards. Calling `reply` more than once is
+ * ignored. Returning without replying answers the program with an empty
+ * clipboard (OSC 52) or EPERM (OSC 5522).
+ *
+ * @ingroup terminal
+ */
+struct GhosttyClipboardRead {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /** Clipboard to read. */
+ GhosttyClipboardLocation location;
+
+ /**
+ * Borrowed array of the MIME types the program wants, in order of
+ * preference. Protocols that only carry text (OSC 52) request
+ * "text/plain". NULL when mimes_len is zero.
+ */
+ const GhosttyString* mimes;
+
+ /** Number of entries in mimes. */
+ size_t mimes_len;
+
+ /**
+ * True if the program also wants the list of MIME types available on the
+ * clipboard, delivered through GhosttyClipboardReadReply::available.
+ */
+ bool list;
+
+ /**
+ * Name of the requesting program for permission prompts, if the protocol
+ * carries one. Empty otherwise.
+ */
+ GhosttyString name;
+
+ /**
+ * True if the terminal already holds a session grant for this request
+ * (kitty clipboard protocol passwords). The embedder should skip any
+ * permission prompt and serve the read.
+ *
+ * Always false when mimes_len is zero: such a request is served
+ * without a prompt (see the callback docs), so the terminal never
+ * consults grants for it and a one-time password is preserved for
+ * the follow-up data read.
+ */
+ bool granted;
+
+ /**
+ * True if the program supplied a session password, so the embedder may
+ * offer to remember the user's decision through
+ * GhosttyClipboardReadReply::remember. When false, remember is ignored.
+ */
+ bool can_remember;
+
+ /** Terminal-owned reply state. Do not access. */
+ const void* ctx;
+
+ /** Answer the read; see the struct documentation. */
+ GhosttyClipboardReadReplyFn reply;
+};
+
+/**
+ * Callback function type for clipboard_read.
+ *
+ * Called synchronously when the running program requests clipboard contents
+ * via OSC 52 with a "?" payload or a Kitty clipboard (OSC 5522) read.
+ * Answering lets the program read the user's clipboard, so the embedder is
+ * expected to mediate consent. Because the read is synchronous, an embedder
+ * that needs to ask the user must block (for example by running a modal
+ * prompt) until it has an answer; the VT stream waits until the callback
+ * returns.
+ *
+ * Answer by calling `read->reply(read, &reply)` before returning. See
+ * GhosttyClipboardRead for the full contract.
+ *
+ * OSC 5522 requests carry the program's MIME list, name, and password grant
+ * state; a reply that sets `remember` records a session grant so later
+ * requests with the same password arrive with `granted` set. Kitty itself
+ * serves a request for only the targets listing (`list` with no `mimes`)
+ * without prompting, and embedders are expected to do the same; the
+ * terminal never consults grants for such requests (`granted` is false
+ * and one-time passwords are not consumed).
+ *
+ * Installing this callback also enables Kitty paste events (mode 5522):
+ * ghostty_terminal_paste() sends the program an event instead of the text,
+ * and the program's follow-up read arrives here with `granted` set since
+ * the user already pasted. See ghostty_terminal_paste().
*
* @param terminal The terminal handle
* @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
- * @param write Borrowed atomic clipboard write request
- * @return The result of attempting the clipboard write
+ * @param read Borrowed clipboard read request
*
* @ingroup terminal
*/
-typedef GhosttyClipboardWriteResult (*GhosttyTerminalClipboardWriteFn)(
+typedef void (*GhosttyTerminalClipboardReadFn)(
GhosttyTerminal terminal,
void* userdata,
- const GhosttyClipboardWrite* write);
+ const GhosttyClipboardRead* read);
+
+/**
+ * A request to show a desktop notification.
+ *
+ * This is a sized struct. The callback must only access fields present in the
+ * size reported by `size`. Both strings are borrowed and valid only for the
+ * duration of the callback.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /** Notification title, or an empty string when the protocol omits it. */
+ GhosttyString title;
+
+ /** Notification body. */
+ GhosttyString body;
+} GhosttyTerminalDesktopNotification;
+
+/**
+ * Callback function type for desktop notifications.
+ *
+ * Called synchronously when the terminal receives OSC 9 or OSC 777.
+ *
+ * @param terminal The terminal handle
+ * @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
+ * @param notification Borrowed desktop notification request
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyTerminalDesktopNotificationFn)(
+ GhosttyTerminal terminal,
+ void* userdata,
+ const GhosttyTerminalDesktopNotification* notification);
+
+/**
+ * State of a terminal progress report.
+ *
+ * @ingroup terminal
+ */
+typedef enum GHOSTTY_ENUM_TYPED {
+ /** Remove any visible progress indication. */
+ GHOSTTY_TERMINAL_PROGRESS_STATE_REMOVE = 0,
+
+ /** Show determinate progress. */
+ GHOSTTY_TERMINAL_PROGRESS_STATE_SET = 1,
+
+ /** Show a failed progress state. */
+ GHOSTTY_TERMINAL_PROGRESS_STATE_ERROR = 2,
+
+ /** Show indeterminate progress. */
+ GHOSTTY_TERMINAL_PROGRESS_STATE_INDETERMINATE = 3,
+
+ /** Show paused progress. */
+ GHOSTTY_TERMINAL_PROGRESS_STATE_PAUSE = 4,
+ GHOSTTY_TERMINAL_PROGRESS_STATE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
+} GhosttyTerminalProgressState;
+
+/**
+ * A progress report emitted by the running program.
+ *
+ * This is a sized struct. The callback must only access fields present in the
+ * size reported by `size`.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Size of this struct in bytes. */
+ size_t size;
+
+ /** Literal progress state reported by the running program. */
+ GhosttyTerminalProgressState state;
+
+ /** Progress percentage from 0 through 100, or -1 when omitted. */
+ int8_t progress;
+} GhosttyTerminalProgressReport;
+
+/**
+ * Callback function type for progress reports.
+ *
+ * Called synchronously when the terminal receives OSC 9;4.
+ *
+ * @param terminal The terminal handle
+ * @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
+ * @param report Borrowed progress report
+ *
+ * @ingroup terminal
+ */
+typedef void (*GhosttyTerminalProgressReportFn)(
+ GhosttyTerminal terminal,
+ void* userdata,
+ const GhosttyTerminalProgressReport* report);
/**
* Callback function type for color scheme queries (CSI ? 996 n).
@@ -524,16 +968,18 @@ typedef GhosttyString (*GhosttyTerminalEnquiryFn)(GhosttyTerminal terminal,
void* userdata);
/**
- * Callback function type for size queries (XTWINOPS).
+ * Callback function type for terminal size reports.
*
- * Called in response to XTWINOPS size queries (CSI 14/16/18 t).
+ * Called in response to XTWINOPS size queries (CSI 14/16/18 t) and when VT
+ * input enables in-band size reports (mode 2048).
* Return true and fill *out_size with the current terminal geometry,
- * or return false to silently ignore the query.
+ * or return false to suppress the report.
*
* @param terminal The terminal handle
* @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
* @param[out] out_size Pointer to store the terminal size information
- * @return true if size was filled, false to ignore the query
+ * @return true if size was filled, false to suppress the XTWINOPS response or
+ * mode 2048 report
*
* @ingroup terminal
*/
@@ -585,9 +1031,9 @@ typedef void (*GhosttyTerminalPwdChangedFn)(GhosttyTerminal terminal,
* Callback function type for write_pty.
*
* Called when the terminal needs to write data back to the pty, for
- * example in response to a device status report or mode query. The
- * data is only valid for the duration of the call; callers must copy
- * it if it needs to persist.
+ * example in response to a device status report, mode query, or VT-driven
+ * mode 2048 enable. The data is only valid for the duration of the call;
+ * callers must copy it if it needs to persist.
*
* @param terminal The terminal handle
* @param userdata The userdata pointer set via GHOSTTY_TERMINAL_OPT_USERDATA
@@ -619,6 +1065,24 @@ typedef GhosttyString (*GhosttyTerminalXtversionFn)(GhosttyTerminal terminal,
void* userdata);
/**
+ * A terminal mode and boolean value used for mode configuration and queries.
+ *
+ * For GHOSTTY_TERMINAL_DATA_MODE, initialize `mode` before calling
+ * ghostty_terminal_get(). On success, `value` contains the current mode value.
+ *
+ * This struct has a frozen layout and will not gain fields in future versions.
+ *
+ * @ingroup terminal
+ */
+typedef struct {
+ /** Mode to configure or query. */
+ GhosttyMode mode;
+
+ /** Value to set, or the current value returned by a query. */
+ bool value;
+} GhosttyTerminalModeConfig;
+
+/**
* Terminal option identifiers.
*
* These values are used with ghostty_terminal_set() to configure
@@ -636,8 +1100,9 @@ typedef enum GHOSTTY_ENUM_TYPED {
/**
* Callback invoked when the terminal needs to write data back
- * to the pty (e.g. in response to a DECRQM query or device
- * status report). Set to NULL to ignore such sequences.
+ * to the pty (e.g. in response to a DECRQM query, device status
+ * report, or VT-driven mode 2048 enable). Set to NULL to ignore such
+ * sequences.
*
* Input type: GhosttyTerminalWritePtyFn
*/
@@ -785,12 +1250,13 @@ typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_MEDIUM_FILE = 16,
/**
- * Enable or disable Kitty image loading via the temporary file medium.
+ * Enable Kitty image loading via the temporary file medium, restricted to
+ * the provided directory. The string data is copied into the terminal.
*
- * A NULL value pointer is a no-op. Has no effect when Kitty graphics
- * are disabled at build time.
+ * A NULL value pointer disables the temporary file medium. Has no effect
+ * when Kitty graphics are disabled at build time.
*
- * Input type: bool*
+ * Input type: GhosttyString*
*/
GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_MEDIUM_TEMP_FILE = 17,
@@ -879,14 +1345,206 @@ typedef enum GHOSTTY_ENUM_TYPED {
/**
* Callback invoked when the running program performs a clipboard write.
- * OSC 52 and iTerm2 OSC 1337 Copy writes are normalized to an atomic set
- * of decoded MIME representations. Set to NULL to ignore clipboard writes.
- * Clipboard read requests are always ignored; see
- * GhosttyTerminalClipboardWriteFn.
+ * OSC 52, iTerm2 OSC 1337 Copy, and Kitty clipboard (OSC 5522) writes
+ * are normalized to an atomic set of decoded MIME representations. Set
+ * to NULL to ignore clipboard writes (Kitty clipboard writes are then
+ * refused with ENOSYS). Clipboard read requests are delivered to
+ * GHOSTTY_TERMINAL_OPT_CLIPBOARD_READ instead.
*
* Input type: GhosttyTerminalClipboardWriteFn
*/
GHOSTTY_TERMINAL_OPT_CLIPBOARD_WRITE = 26,
+
+ /**
+ * Set the maximum scrollback allocation in bytes.
+ *
+ * This is an estimate. Internally, libghostty only prunes bytes up
+ * to a "page"-granularity. A page is the minimum allocated unit of
+ * grid space within Ghostty. A page at the time of writing these docs
+ * is about 400KB, so the byte limit will be within this delta.
+ *
+ * This works alongside the line limit configuration. If both are set,
+ * the first-reached limit is used first. Both limits are dependent
+ * on external state (byte limit can be reached with less lines if
+ * more styles are used for example, line limit can be reached with
+ * a narrower terminal viewport). So, they are useful together.
+ *
+ * Lowering the limit immediately removes eligible complete historical
+ * pages. A value of zero disables scrollback and erases retained history.
+ * A NULL value pointer removes the byte limit.
+ *
+ * Input type: size_t*
+ */
+ GHOSTTY_TERMINAL_OPT_SCROLLBACK_MAX_BYTES = 27,
+
+ /**
+ * Set the maximum number of physical lines retained in scrollback.
+ *
+ * This is an estimate. Internally, libghostty only prunes lines up
+ * to a "page"-granularity. A page is the minimum allocated unit of
+ * grid space within Ghostty. As a result, the actual available scrollback
+ * lines will almost always be higher than configured. The magnitude
+ * of the difference depends on the number of used styles, graphemes, etc.
+ * since the row-count in a page is dynamic based on that. In general,
+ * it ranges from dozens to a hundred or so lines.
+ *
+ * This works alongside the line limit configuration. If both are set,
+ * the first-reached limit is used first. Both limits are dependent
+ * on external state (byte limit can be reached with less lines if
+ * more styles are used for example, line limit can be reached with
+ * a narrower terminal viewport). So, they are useful together.
+ *
+ * Lowering the limit immediately removes eligible complete historical
+ * pages. A NULL value pointer removes the line limit.
+ *
+ * Input type: size_t*
+ */
+ GHOSTTY_TERMINAL_OPT_SCROLLBACK_MAX_LINES = 28,
+
+ /**
+ * Callback invoked when the running program requests a desktop
+ * notification via OSC 9 or OSC 777. Set to NULL to ignore desktop
+ * notification requests.
+ *
+ * Input type: GhosttyTerminalDesktopNotificationFn
+ */
+ GHOSTTY_TERMINAL_OPT_DESKTOP_NOTIFICATION = 29,
+
+ /**
+ * Callback invoked when the running program reports progress via OSC 9;4.
+ * Set to NULL to ignore progress reports.
+ *
+ * Input type: GhosttyTerminalProgressReportFn
+ */
+ GHOSTTY_TERMINAL_OPT_PROGRESS_REPORT = 30,
+
+ /**
+ * Set the maximum number of replay-safe VT continuation bytes retained.
+ *
+ * Continuation bytes reconstruct an escape sequence or UTF-8 codepoint
+ * which was unfinished at the end of the most recent
+ * VT write call. They are used automatically by terminal snapshots and may
+ * also be exported directly with the continuation APIs.
+ *
+ * Tracking is disabled by default. A nonzero value enables tracking and
+ * sets its byte limit. Passing NULL or a pointer to zero disables tracking.
+ * Lowering the limit below an already-retained
+ * continuation, or enabling tracking while the parser is already
+ * unfinished, makes the current continuation unavailable because earlier
+ * bytes cannot be reconstructed. Tracking recovers automatically after a
+ * later write reaches the ground state or contains a fresh replay start.
+ *
+ * Input type: size_t*
+ */
+ GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES = 31,
+
+ /**
+ * Enable window title reports in response to CSI 21 t.
+ *
+ * This is disabled by default because a running program can set a title and
+ * query it back into the pty input stream, potentially injecting commands
+ * that execute after user interaction. Passing NULL or a pointer to false
+ * disables title reporting.
+ *
+ * Input type: bool*
+ */
+ GHOSTTY_TERMINAL_OPT_TITLE_REPORT = 32,
+
+ /**
+ * Set the reset default for a terminal mode.
+ *
+ * This unconditionally updates both the current value and the value restored
+ * by a full terminal reset (RIS).
+ *
+ * Some recognized modes represent transitions or mirror additional terminal
+ * state and cannot safely be configured as reset defaults. Those modes return
+ * GHOSTTY_INVALID_VALUE. A NULL value pointer also returns
+ * GHOSTTY_INVALID_VALUE.
+ *
+ * Input type: GhosttyTerminalModeConfig*
+ */
+ GHOSTTY_TERMINAL_OPT_MODE_DEFAULT = 33,
+
+ /**
+ * Set the current value of a terminal mode.
+ *
+ * This does not change the value restored by a full terminal reset (RIS).
+ * A NULL value pointer or unknown mode returns GHOSTTY_INVALID_VALUE.
+ *
+ * Input type: GhosttyTerminalModeConfig*
+ */
+ GHOSTTY_TERMINAL_OPT_MODE = 34,
+
+ /**
+ * Callback invoked for unsupported terminal sequence identifiers. Set to
+ * NULL to ignore unsupported sequences. Capture must also be enabled with
+ * GHOSTTY_TERMINAL_OPT_UNKNOWN_MAX_BYTES.
+ *
+ * Input type: GhosttyTerminalUnknownSequenceFn
+ */
+ GHOSTTY_TERMINAL_OPT_UNKNOWN_SEQUENCE = 35,
+
+ /**
+ * Set the maximum content bytes retained for each unsupported terminal
+ * sequence. A NULL value pointer or zero disables capture and prevents
+ * unknown-sequence callbacks.
+ *
+ * When this limit is hit, the unknown sequence callback will still
+ * be invoked but `truncated` will be set to true.
+ *
+ * Input type: size_t*
+ */
+ GHOSTTY_TERMINAL_OPT_UNKNOWN_MAX_BYTES = 36,
+
+ /**
+ * Set the name of the terminfo entry this terminal runs as, reported
+ * in response to an XTGETTCAP query for "TN" (e.g. "xterm-256color").
+ *
+ * The string data is copied into the terminal. A NULL value pointer
+ * clears the name (equivalent to setting an empty string). A name
+ * longer than 128 bytes returns GHOSTTY_INVALID_VALUE.
+ *
+ * If this is unset then we don't report anything for an XTGETTCAP
+ * TN query, because we don't know what the embedding terminal around
+ * libghostty is advertising itself as.
+ *
+ * Input type: GhosttyString*
+ */
+ GHOSTTY_TERMINAL_OPT_TERMINFO_NAME = 37,
+
+ /**
+ * Callback invoked when the running program requests clipboard contents
+ * via OSC 52 with a "?" payload or a Kitty clipboard (OSC 5522) read. The
+ * read is synchronous and must be answered before the callback returns.
+ * Set to NULL (the default) to ignore OSC 52 read requests and refuse
+ * OSC 5522 reads with EPERM.
+ *
+ * Input type: GhosttyTerminalClipboardReadFn
+ */
+ GHOSTTY_TERMINAL_OPT_CLIPBOARD_READ = 38,
+
+ /**
+ * Set the maximum total decoded bytes a single Kitty clipboard protocol
+ * (OSC 5522) write transaction may accumulate. The limit is captured
+ * when a transaction begins; an in-flight transaction keeps the limit
+ * it started with.
+ *
+ * Data beyond the limit fails the whole transaction with EFBIG. The
+ * transaction is discarded, later write-related packets are ignored
+ * until a new write begins, and nothing reaches the clipboard write
+ * callback.
+ *
+ * Transactions are buffered in memory, so this limit bounds how much
+ * memory a single write can make the terminal allocate. Pass SIZE_MAX
+ * to remove the limit. A NULL value pointer reverts to the built-in
+ * default of 64MiB, the minimum required by the protocol.
+ *
+ * This limit doesn't apply to OSC 52 writes, which are bounded by the
+ * maximum length of an escape sequence instead.
+ *
+ * Input type: size_t*
+ */
+ GHOSTTY_TERMINAL_OPT_CLIPBOARD_WRITE_MAX_BYTES = 39,
GHOSTTY_TERMINAL_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyTerminalOption;
@@ -998,9 +1656,9 @@ typedef enum GHOSTTY_ENUM_TYPED {
/**
* The terminal title as set by escape sequences (e.g. OSC 0/2).
*
- * Returns a borrowed string. The pointer is valid until the next call
- * to ghostty_terminal_vt_write() or ghostty_terminal_reset(). An empty
- * string (len=0) is returned when no title has been set.
+ * Returns a borrowed string. The pointer is valid until the next mutating
+ * terminal call. An empty string (len=0) is returned when no title has been
+ * set.
*
* Output type: GhosttyString *
*/
@@ -1010,9 +1668,9 @@ typedef enum GHOSTTY_ENUM_TYPED {
* The terminal's current working directory as set by escape sequences
* (e.g. OSC 7).
*
- * Returns a borrowed string. The pointer is valid until the next call
- * to ghostty_terminal_vt_write() or ghostty_terminal_reset(). An empty
- * string (len=0) is returned when no pwd has been set.
+ * Returns a borrowed string. The pointer is valid until the next mutating
+ * terminal call. An empty string (len=0) is returned when no pwd has been
+ * set.
*
* Output type: GhosttyString *
*/
@@ -1139,12 +1797,13 @@ typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_FILE = 27,
/**
- * Whether the temporary file medium is enabled for Kitty image loading
- * on the active screen.
+ * The directory allowed for Kitty image loading via the temporary file
+ * medium on the active screen. The string is empty when the medium is
+ * disabled.
*
* Returns GHOSTTY_NO_VALUE when Kitty graphics are disabled at build time.
*
- * Output type: bool *
+ * Output type: GhosttyString *
*/
GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_TEMP_FILE = 28,
@@ -1199,27 +1858,129 @@ typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_TERMINAL_DATA_VIEWPORT_ACTIVE = 32,
/**
+ * Whether VT processing encountered a non-gracefully handled error that may
+ * have prevented a terminal-owned semantic update.
+ *
+ * Processing remains best-effort, and ghostty_terminal_reset() does not
+ * clear it. Gracefully handled protocol failures, configured limits,
+ * malformed or unsupported input, and failures limited to external effects
+ * or query responses do not set it.
+ *
+ * This can't currently be unset. This is purely informational to consumers
+ * if there was some error that happened at some point during VT processing.
+ *
+ * Output type: bool *
+ */
+ GHOSTTY_TERMINAL_DATA_VT_PROCESSING_ERROR = 33,
+
+ /**
+ * The configured maximum scrollback allocation in bytes.
+ *
+ * This always reports the primary screen's configured value, including
+ * while an alternate screen is active. Returns GHOSTTY_NO_VALUE when the
+ * configured byte limit is unlimited.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_TERMINAL_DATA_SCROLLBACK_MAX_BYTES = 34,
+
+ /**
+ * The configured maximum number of physical scrollback lines.
+ *
+ * This always reports the primary screen's configured value, including
+ * while an alternate screen is active. Returns GHOSTTY_NO_VALUE when the
+ * configured line limit is unlimited.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_TERMINAL_DATA_SCROLLBACK_MAX_LINES = 35,
+
+ /**
+ * The configured maximum retained VT continuation size in bytes.
+ *
+ * A value of zero means continuation tracking is disabled. This reports the
+ * configured limit even when a current unfinished continuation is
+ * temporarily unavailable.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_TERMINAL_DATA_CONTINUATION_MAX_BYTES = 36,
+
+ /**
+ * Get the current value of a terminal mode.
+ *
+ * The caller must initialize the `mode` field. On success, the `value` field
+ * is updated with the current value. A NULL pointer or unknown mode returns
+ * GHOSTTY_INVALID_VALUE.
+ *
+ * Input/output type: GhosttyTerminalModeConfig *
+ */
+ GHOSTTY_TERMINAL_DATA_MODE = 37,
+
+ /**
+ * Whether VT processing is at ground.
+ *
+ * Ground is when the stream isn't in the middle of any type of sequence:
+ * UTF-8, ESC, CSI, OSC, etc. It is the stateless point of the stream.
+ *
+ * This is useful to know because it is a point at which you can
+ * safely insert out-of-band VT sequences. For example, while reading
+ * from a pty if you want to make your own changes, you can wait until
+ * the pty input reaches ground, then write yours.
+ *
+ * Output type: bool *
+ */
+ GHOSTTY_TERMINAL_DATA_VT_GROUND = 38,
+
+ /**
+ * Whether the cursor is currently at a semantic shell prompt or input area.
+ *
+ * This depends on semantic prompt markers such as OSC 133. Returns false
+ * when semantic prompt information is unavailable or the alternate screen
+ * is active.
+ *
+ * Output type: bool *
+ */
+ GHOSTTY_TERMINAL_DATA_CURSOR_AT_PROMPT = 39,
+
+ /**
+ * The configured maximum decoded bytes per Kitty clipboard protocol
+ * (OSC 5522) write transaction. See
+ * GHOSTTY_TERMINAL_OPT_CLIPBOARD_WRITE_MAX_BYTES.
+ *
+ * Output type: size_t *
+ */
+ GHOSTTY_TERMINAL_DATA_CLIPBOARD_WRITE_MAX_BYTES = 40,
+
+ /**
* Whether xterm modifyOtherKeys mode 2 is enabled.
*
* Output type: bool *
*/
- GHOSTTY_TERMINAL_DATA_MODIFY_OTHER_KEYS = 33,
+ GHOSTTY_TERMINAL_DATA_MODIFY_OTHER_KEYS = 41,
+
GHOSTTY_TERMINAL_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyTerminalData;
/**
* Create a new terminal instance.
*
+ * The terminal starts with various reasonable defaults e.g. around
+ * scrollback limits. Use ghostty_terminal_set() to change any options
+ * prior to using the terminal.
+ *
* @param allocator Pointer to allocator, or NULL to use the default allocator
* @param terminal Pointer to store the created terminal handle
- * @param options Terminal initialization options
+ * @param cols Terminal width in cells (must be greater than zero)
+ * @param rows Terminal height in cells (must be greater than zero)
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup terminal
*/
GHOSTTY_API GhosttyResult ghostty_terminal_new(const GhosttyAllocator* allocator,
- GhosttyTerminal* terminal,
- GhosttyTerminalOptions options);
+ GhosttyTerminal* terminal,
+ uint16_t cols,
+ uint16_t rows);
/**
* Free a terminal instance.
@@ -1280,11 +2041,13 @@ GHOSTTY_API GhosttyResult ghostty_terminal_resize(GhosttyTerminal terminal,
* write_pty callback and userdata pointer. The value is passed
* directly for pointer types (callbacks, userdata) or as a pointer
* to the value for non-pointer types (e.g. GhosttyString*).
- * NULL clears the option to its default.
+ * The behavior of a NULL value is specific to each option and is
+ * documented by the corresponding GhosttyTerminalOption value.
*
- * Callbacks are invoked synchronously during ghostty_terminal_vt_write().
- * Callbacks must not call ghostty_terminal_vt_write() on the same
- * terminal (no reentrancy).
+ * Callbacks are invoked synchronously during VT writes. Callbacks must not
+ * call ghostty_terminal_vt_write() or
+ * ghostty_terminal_vt_write_until_ground() on the same terminal
+ * (no reentrancy).
*
* @param terminal The terminal handle (may be NULL, in which case this is a no-op)
* @param option The option to set
@@ -1323,6 +2086,130 @@ GHOSTTY_API void ghostty_terminal_vt_write(GhosttyTerminal terminal,
size_t len);
/**
+ * Write VT-encoded data, but only the shortest prefix needed to reach ground.
+ *
+ * Ground is when the stream isn't in the middle of any type of sequence:
+ * UTF-8, ESC, CSI, OSC, etc. It is the stateless point of the stream.
+ *
+ * This is useful to know because it is a point at which you can
+ * safely insert out-of-band VT sequences. For example, while reading
+ * from a pty if you want to make your own changes, you can wait until
+ * the pty input reaches ground, then write yours.
+ *
+ * If the stream is already at ground then this consumes nothing and returns
+ * GHOSTTY_SUCCESS. On success, out_consumed is the number of bytes consumed
+ * before reaching ground, including the byte that reaches it.
+ * GHOSTTY_NO_VALUE means the full slice was consumed without reaching ground.
+ *
+ * @param terminal The terminal handle (must not be NULL)
+ * @param data Pointer to the data to write, or NULL when len is zero
+ * @param len Length of the data in bytes
+ * @param[out] out_consumed Number of bytes consumed (must not be NULL)
+ * @return GHOSTTY_SUCCESS if ground was reached, GHOSTTY_NO_VALUE if all input
+ * was consumed without reaching ground, or GHOSTTY_INVALID_VALUE if
+ * an argument is invalid
+ *
+ * @ingroup terminal
+ */
+GHOSTTY_API GhosttyResult ghostty_terminal_vt_write_until_ground(
+ GhosttyTerminal terminal,
+ const uint8_t* data,
+ size_t len,
+ size_t* out_consumed);
+
+/**
+ * Write the terminal's replay-safe VT continuation to a callback writer.
+ *
+ * The continuation is the exact byte suffix needed to reconstruct unfinished
+ * VT parser or UTF-8 decoder state in an equivalent terminal. It is empty
+ * when the stream is at ground. The callback is invoked synchronously and
+ * may be called more than once. It must not call terminal APIs with the same
+ * terminal handle.
+ *
+ * Continuation tracking must have been enabled by setting
+ * GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to a nonzero value before the
+ * input that produced the continuation was written.
+ *
+ * The caller must serialize this operation with both VT write functions and
+ * all other access to the same terminal.
+ *
+ * @param terminal Terminal to read from (must not be NULL)
+ * @param writer Destination writer whose write callback must not be NULL
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_IO_ERROR if the callback rejects
+ * a write, GHOSTTY_LIMIT_EXCEEDED if output accounting overflows, or
+ * GHOSTTY_INVALID_VALUE if an argument is invalid, tracking is
+ * disabled, or the current continuation is unavailable
+ *
+ * @ingroup terminal
+ */
+GHOSTTY_API GhosttyResult ghostty_terminal_continuation_write(
+ GhosttyTerminal terminal,
+ GhosttyWriter writer);
+
+/**
+ * Copy the terminal's replay-safe VT continuation into a caller buffer.
+ *
+ * Pass NULL for buf with buf_len zero to query the required size. A size query
+ * returns GHOSTTY_OUT_OF_SPACE and stores the required size in out_written,
+ * including zero when the stream is at ground. If a non-NULL buffer is too
+ * small, the function has the same result and reports the full required size.
+ * Continuation tracking must have been enabled by setting
+ * GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to a nonzero value before the
+ * input that produced the continuation was written.
+ *
+ * The caller must serialize this operation with all other access to the same
+ * terminal.
+ *
+ * @param terminal Terminal to read from (must not be NULL)
+ * @param buf Destination buffer, or NULL when buf_len is zero
+ * @param buf_len Destination buffer capacity in bytes
+ * @param[out] out_written Bytes written, or required size on
+ * GHOSTTY_OUT_OF_SPACE (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE for a size query or
+ * insufficient buffer, or GHOSTTY_INVALID_VALUE if an argument is
+ * invalid, tracking is disabled, or the current continuation is
+ * unavailable
+ *
+ * @ingroup terminal
+ */
+GHOSTTY_API GhosttyResult ghostty_terminal_continuation_buf(
+ GhosttyTerminal terminal,
+ uint8_t* buf,
+ size_t buf_len,
+ size_t* out_written);
+
+/**
+ * Return an allocated copy of the terminal's replay-safe VT continuation.
+ *
+ * The returned bytes are allocated with allocator, or the default allocator
+ * when allocator is NULL. The caller must release them with ghostty_free(),
+ * passing the same allocator and returned length. An empty continuation is a
+ * successful result with *out_ptr set to NULL and *out_len set to zero,
+ * which can also be passed to ghostty_free().
+ * Continuation tracking must have been enabled by setting
+ * GHOSTTY_TERMINAL_OPT_CONTINUATION_MAX_BYTES to a nonzero value before the
+ * input that produced the continuation was written.
+ *
+ * The caller must serialize this operation with all other access to the same
+ * terminal.
+ *
+ * @param terminal Terminal to read from (must not be NULL)
+ * @param allocator Allocator for the output, or NULL for the default allocator
+ * @param[out] out_ptr Allocated continuation bytes (must not be NULL)
+ * @param[out] out_len Number of continuation bytes (must not be NULL)
+ * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
+ * failure, or GHOSTTY_INVALID_VALUE if an argument is invalid,
+ * tracking is disabled, or the current continuation is unavailable
+ *
+ * @ingroup terminal
+ */
+GHOSTTY_API GhosttyResult ghostty_terminal_continuation_alloc(
+ GhosttyTerminal terminal,
+ const GhosttyAllocator* allocator,
+ uint8_t** out_ptr,
+ size_t* out_len);
+
+/**
* Scroll the terminal viewport.
*
* Scrolls the terminal's viewport according to the given behavior.
@@ -1396,41 +2283,6 @@ GHOSTTY_API GhosttyResult ghostty_terminal_compress(
GhosttyTerminalCompressionResult* out_result);
/**
- * Get the current value of a terminal mode.
- *
- * Returns the value of the mode identified by the given mode.
- *
- * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
- * @param mode The mode identifying the mode to query
- * @param[out] out_value On success, set to true if the mode is set, false
- * if it is reset
- * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal
- * is NULL or the mode does not correspond to a known mode
- *
- * @ingroup terminal
- */
-GHOSTTY_API GhosttyResult ghostty_terminal_mode_get(GhosttyTerminal terminal,
- GhosttyMode mode,
- bool* out_value);
-
-/**
- * Set the value of a terminal mode.
- *
- * Sets the mode identified by the given mode to the specified value.
- *
- * @param terminal The terminal handle (NULL returns GHOSTTY_INVALID_VALUE)
- * @param mode The mode identifying the mode to set
- * @param value true to set the mode, false to reset it
- * @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the terminal
- * is NULL or the mode does not correspond to a known mode
- *
- * @ingroup terminal
- */
-GHOSTTY_API GhosttyResult ghostty_terminal_mode_set(GhosttyTerminal terminal,
- GhosttyMode mode,
- bool value);
-
-/**
* Get data from a terminal instance.
*
* Extracts typed data from the given terminal based on the specified
diff --git a/vendor/libghostty-vt/include/ghostty/vt/types.h b/vendor/libghostty-vt/include/ghostty/vt/types.h
index 214d2822..059bc5c8 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/types.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/types.h
@@ -39,18 +39,21 @@
* 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.
+ * C++11 and C23 support explicit enum underlying types with
+ * `enum : int { ... }`. Clang and GCC 13+ also support this syntax as
+ * an extension in older C language modes, so use it when available.
+ *
+ * Other pre-C23 C compilers are free to choose any type that can
+ * represent all values (C11 §6.7.2.2). For those compilers, we add an
+ * INT_MAX sentinel as the last entry so the compatible type must be
+ * able to represent INT_MAX. The exact compatible type and its
+ * signedness remain implementation-defined in this fallback.
*
* 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.
+ * because enum constants must have type int in pre-C23 C. Values above
+ * INT_MAX are a constraint violation there; compilers that accept them
+ * may interpret them as negative values via two's complement, which can
+ * collide with legitimate negative enum values.
*
* Usage:
* @code
@@ -61,7 +64,18 @@
* } Foo;
* @endcode
*/
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#if defined(__cplusplus) && \
+ (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700))
+#define GHOSTTY_ENUM_TYPED : int
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define GHOSTTY_ENUM_TYPED : int
+#elif defined(__clang__)
+ #if __has_extension(c_fixed_enum)
+ #define GHOSTTY_ENUM_TYPED : int
+ #else
+ #define GHOSTTY_ENUM_TYPED
+ #endif
+#elif defined(__GNUC__) && __GNUC__ >= 13
#define GHOSTTY_ENUM_TYPED : int
#else
#define GHOSTTY_ENUM_TYPED
@@ -82,6 +96,16 @@ typedef enum GHOSTTY_ENUM_TYPED {
GHOSTTY_OUT_OF_SPACE = -3,
/** The requested value has no value */
GHOSTTY_NO_VALUE = -4,
+ /** Operation failed while reading from or writing to external I/O */
+ GHOSTTY_IO_ERROR = -5,
+ /** Operation failed because encoded input exceeded a configured limit */
+ GHOSTTY_LIMIT_EXCEEDED = -6,
+ /**
+ * Operation was rejected by a safety check (e.g. pasted text that could
+ * inject commands). Nothing was done. Confirm with the user and retry
+ * with the operation's allow flag set.
+ */
+ GHOSTTY_REJECTED = -7,
GHOSTTY_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyResult;
@@ -95,6 +119,13 @@ typedef enum GHOSTTY_ENUM_TYPED {
typedef struct GhosttyTerminalImpl* GhosttyTerminal;
/**
+ * Opaque handle to an incremental terminal snapshot decoder.
+ *
+ * @ingroup snapshot
+ */
+typedef struct GhosttySnapshotDecoderImpl* GhosttySnapshotDecoder;
+
+/**
* Opaque handle to a tracked grid reference.
*
* A tracked grid reference is owned by the caller and must be freed with
@@ -158,6 +189,19 @@ typedef struct GhosttyRenderStateRowIteratorImpl* GhosttyRenderStateRowIterator;
typedef struct GhosttyRenderStateRowCellsImpl* GhosttyRenderStateRowCells;
/**
+ * Opaque handle to a terminal search.
+ *
+ * A search is bound to the terminal it was created with. It borrows the
+ * terminal, so it never frees it, and the search must be freed with
+ * ghostty_search_free(). If the terminal is freed first, the search
+ * detects this: calls that need the terminal fail cleanly and the
+ * search can still be freed.
+ *
+ * @ingroup search
+ */
+typedef struct GhosttySearchImpl* GhosttySearch;
+
+/**
* Opaque handle to an SGR parser instance.
*
* This handle represents an SGR (Select Graphic Rendition) parser that can
@@ -218,6 +262,8 @@ typedef enum GHOSTTY_ENUM_TYPED {
*
* 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.
+ * Empty strings produced by the library have a non-NULL pointer to valid
+ * storage.
*/
typedef struct {
/** Pointer to the string bytes. */
@@ -294,33 +340,64 @@ typedef struct {
* opts.trim = true;
* @endcode
*/
+#ifdef __cplusplus
+#define GHOSTTY_INIT_SIZED(type) \
+ ([]() noexcept { \
+ type value{}; \
+ value.size = sizeof(value); \
+ return value; \
+ }())
+#else
#define GHOSTTY_INIT_SIZED(type) \
((type){ .size = sizeof(type) })
+#endif
/**
- * Return a pointer to a null-terminated JSON string describing the
- * layout of every C API struct for the current target.
+ * Return the versioned libghostty-vt C type manifest for the current target.
+ *
+ * The manifest defines all the public types available in the linked
+ * build. The types contain their layouts, enum values, union fields, and more.
+ *
+ * Language bindings, such as WebAssembly hosts, should obtain offsets,
+ * sizes, alignments, array shapes, enum constants, and tagged-union arms from
+ * this manifest rather than hardcoding them. Consumers should reject unknown
+ * schema versions and verify the descriptors they require at initialization.
+ *
+ * Packed type descriptors define fields using `lsb` and `width`. `lsb` is
+ * relative to bit zero of the containing numerical value; for nested packed
+ * layouts it is relative to the immediate containing field. Tagged packed
+ * unions select an inline arm layout using the named tag field. These layouts
+ * describe the current linked build and are not a cross-version stability
+ * promise.
*
- * 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.
+ * The formal format is defined by the
+ * <a href="types.schema.json">libghostty-vt ABI manifest JSON Schema</a>.
*
* 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" }
+ * "schema": 1,
+ * "abi": {
+ * "target": "wasm32", "os": "freestanding", "environment": "none",
+ * "pointer_size": 4, "usize_size": 4, "max_alignment": 16,
+ * "endian": "little"
+ * },
+ * "types": {
+ * "GhosttyRenderStateData": {
+ * "kind": "enum", "size": 4, "align": 4,
+ * "underlying": "i32", "prefix": "GHOSTTY_RENDER_STATE_DATA_",
+ * "values": { "INVALID": 0, "DIRTY": 3, "MAX_VALUE": 2147483647 }
+ * },
+ * "GhosttyStyleColor": {
+ * "kind": "struct", "size": 16, "align": 8,
+ * "fields": {
+ * "tag": { "offset": 0, "size": 4,
+ * "type": "GhosttyStyleColorTag" },
+ * "value": { "offset": 8, "size": 8,
+ * "type": "GhosttyStyleColorValue", "tag": "tag",
+ * "arms": { "NONE": null, "PALETTE": "palette",
+ * "RGB": "rgb" } }
+ * }
* }
* }
* }
diff --git a/vendor/libghostty-vt/include/ghostty/vt/wasm.h b/vendor/libghostty-vt/include/ghostty/vt/wasm.h
index e2b63e2c..2f9ff5df 100644
--- a/vendor/libghostty-vt/include/ghostty/vt/wasm.h
+++ b/vendor/libghostty-vt/include/ghostty/vt/wasm.h
@@ -10,12 +10,12 @@
#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.
+ * Convenience functions for working with the low-level C ABI in WebAssembly
+ * builds.
* **These are only available the libghostty-vt wasm module.**
*
* Ghostty relies on pointers to various types for ABI compatibility, and
@@ -28,37 +28,64 @@
* your custom allocator. This is a very rare use case in the WebAssembly
* world so these are optimized for simplicity.
*
+ * Use ghostty_wasm_alloc() and ghostty_wasm_free() for host-owned scratch
+ * buffers and ABI values. Dynamic-language hosts can use ghostty_type_json()
+ * to discover pointer and size_t widths, maximum alignment, byte order, and
+ * the size and alignment of public C structs. Do not mix allocation families:
+ * buffers returned by libghostty-vt allocating APIs must still be released
+ * with ghostty_free(), and opaque handles must be released with their
+ * type-specific destructor.
+ *
+ * ## Memory growth
+ *
+ * An exported function may grow Wasm linear memory when it allocates. Numeric
+ * pointers and handles remain valid, but JavaScript ArrayBuffer, DataView, and
+ * typed-array objects created before the growth may no longer cover the live
+ * memory. Reacquire `exports.memory.buffer` immediately before every host-side
+ * memory access. A host that caches views should recreate them whenever either
+ * the buffer identity or its byte length changes.
+ *
* ## Example Usage
*
- * Here's a simple example of using the Wasm utilities with the key encoder:
+ * Here's a simple example that creates a terminal, writes bytes, and safely
+ * handles memory growth:
*
* @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);
+ * const memory = exports.memory;
+ * let cachedBuffer = null;
+ * let cachedLength = 0;
+ * let cachedBytes = null;
+ *
+ * function bytes() {
+ * const buffer = memory.buffer;
+ * if (buffer !== cachedBuffer || buffer.byteLength !== cachedLength) {
+ * cachedBuffer = buffer;
+ * cachedLength = buffer.byteLength;
+ * cachedBytes = new Uint8Array(buffer);
+ * }
+ * return cachedBytes;
+ * }
+ *
+ * function check(result) {
+ * if (result !== 0) throw new Error(`libghostty-vt error: ${result}`);
+ * }
+ *
+ * // One slot can be reused for every opaque-handle constructor.
+ * const slot = exports.ghostty_wasm_alloc_opaque();
+ * if (slot === 0) throw new Error("out of memory");
+ * check(exports.ghostty_terminal_new(0, slot, 80, 24));
+ * const terminal = exports.ghostty_wasm_take_opaque(slot);
+ *
+ * const input = new TextEncoder().encode("Hello, world!");
+ * const inputPtr = exports.ghostty_wasm_alloc(input.length);
+ * if (inputPtr === 0) throw new Error("out of memory");
+ * bytes().set(input, inputPtr); // Acquires the current memory after alloc.
+ * exports.ghostty_terminal_vt_write(terminal, inputPtr, input.length);
+ *
+ * exports.ghostty_wasm_free(inputPtr, input.length);
+ * exports.ghostty_terminal_free(terminal);
+ * exports.ghostty_wasm_free_opaque(slot);
* @endcode
*
* @remark The code above is pretty ugly! This is the lowest level interface
@@ -69,89 +96,62 @@
*/
/**
- * 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.
+ * Allocate caller-owned storage for a Wasm ABI value or scratch buffer.
*
- * @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().
+ * The returned address is aligned to the target's maximum C ABI alignment,
+ * reported as `abi.max_alignment` by ghostty_type_json(). The memory is
+ * uninitialized. A zero-length request returns NULL.
*
- * @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.
+ * The returned pointer must be released with ghostty_wasm_free() using the
+ * exact same length.
*
- * @param len Number of uint16_t elements to allocate
- * @return Pointer to allocated array, or NULL if allocation failed
+ * @param len Number of bytes to allocate
+ * @return Pointer to allocated storage, or NULL if len is zero or allocation
+ * failed
* @ingroup wasm
*/
-GHOSTTY_API uint16_t* ghostty_wasm_alloc_u16_array(size_t len);
+GHOSTTY_API void* ghostty_wasm_alloc(size_t len);
/**
- * Free an array allocated by ghostty_wasm_alloc_u16_array().
+ * Free storage allocated by ghostty_wasm_alloc().
*
- * @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)
+ * @param ptr Pointer to free, or NULL (NULL is safely ignored)
+ * @param len Original allocation length passed to ghostty_wasm_alloc()
* @ingroup wasm
*/
-GHOSTTY_API void ghostty_wasm_free_u16_array(uint16_t *ptr, size_t len);
+GHOSTTY_API void ghostty_wasm_free(void *ptr, size_t len);
/**
- * Allocate a single uint8_t value.
+ * Allocate an opaque pointer. This can be used for any opaque pointer
+ * types such as GhosttyKeyEncoder, GhosttyKeyEvent, etc. The allocated slot
+ * is initialized to NULL and may be reused across constructors.
*
- * @return Pointer to allocated uint8_t, or NULL if allocation failed
+ * @return Pointer to allocated opaque pointer, or NULL if allocation failed
* @ingroup wasm
*/
-GHOSTTY_API uint8_t* ghostty_wasm_alloc_u8(void);
+GHOSTTY_API void** ghostty_wasm_alloc_opaque(void);
/**
- * Free a uint8_t allocated by ghostty_wasm_alloc_u8().
+ * 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_u8(uint8_t *ptr);
+GHOSTTY_API void ghostty_wasm_free_opaque(void **ptr);
/**
- * Allocate a single size_t value.
+ * Take an opaque handle from an out-parameter slot.
*
- * @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().
+ * Returns the handle currently stored in @p slot and resets the slot to NULL.
+ * This function does not allocate, free the returned handle, or free the slot.
+ * Always check the GhosttyResult returned by the function that populated the
+ * slot before calling this function.
*
- * @param ptr Pointer to free, or NULL (NULL is safely ignored)
+ * @param slot Pointer to an opaque out-parameter slot, or NULL
+ * @return Stored opaque handle, or NULL if slot or its value is NULL
* @ingroup wasm
*/
-GHOSTTY_API void ghostty_wasm_free_usize(size_t *ptr);
+GHOSTTY_API void* ghostty_wasm_take_opaque(void **slot);
/** @} */