Render-state rows already expose their selected range, but
cell-oriented C API consumers had to fetch that row range separately
and duplicate the containment check while rendering.
Add a SELECTED row-cells data kind that carries the row selection into
the row-cells wrapper and returns whether the current cell column is in
that inclusive range. The field remains separate from cell colors and
style so selection stays an explicit render overlay policy.
For performance reasons, the span-based row getter is recommended still
but this is a convenient thing to do for cell-oriented folks.
Tracked grid references previously held a raw terminal wrapper pointer
and were required to be freed before the terminal. If callers kept one
past terminal destruction, later tracked-ref calls could dereference
freed terminal or page-list memory before detecting that the reference
was no longer meaningful.
Track live C tracked-grid-ref handles from the terminal wrapper and
detach them before tearing down terminal storage. Detached refs now
report no value through the tracked-ref APIs and can still be freed by
the caller. Update the C API docs to describe this lifetime behavior and
add a regression test for using a tracked ref after terminal free.
This introduces some overhead but tracked pins shouldn't be numerous and
this dramatically improves safety.
No API changes due to this (just more safety).
Tracked grid references previously held a raw terminal wrapper pointer and
were required to be freed before the terminal. If callers kept one past
terminal destruction, later tracked-ref calls could dereference freed
terminal or page-list memory before detecting that the reference was no
longer meaningful.
Track live C tracked-grid-ref handles from the terminal wrapper and detach
them before tearing down terminal storage. Detached refs now report no
value through the tracked-ref APIs and can still be freed by the caller.
Update the C API docs to describe this lifetime behavior and add a
regression test for using a tracked ref after terminal free.
This introduces some overhead but tracked pins shouldn't be numerous
and this dramatically improves safety.
Expose a C API for checking whether a GhosttyPoint is inside a
GhosttySelection. The new terminal helper validates the selection snapshot
against the active screen, resolves the point to a grid pin, and delegates
to the internal Selection.contains implementation so C consumers get the
same linear and rectangular selection semantics as Ghostty.
Wire the symbol through the C API exports and public headers, and add a
focused test covering linear containment and rectangular selection behavior.
Expose selection endpoint ordering through the libghostty-vt C API so
embedders can safely normalize selections whose start and end refs may be
reversed. The new APIs report the current order and return a fresh
untracked selection with forward or reverse bounds.
Selection.Order now uses lib.Enum, matching the existing adjustment enum
pattern and keeping the C ABI enum generated from the same Zig source of
truth. The new functions are wired through the C API re-export and lib-vt
export paths, with coverage for mirrored rectangular selection ordering.
Render state already tracks the selected cell range for each viewport row,
but C renderers could only get the full terminal selection. That required
consumers to map global selection pins back into row-local spans themselves.
Add row selection data to the render-state row API. Querying the new row
data returns GHOSTTY_NO_VALUE for unselected rows and writes the inclusive
start and end columns for selected rows. The render example now demonstrates
setting a selection and reading the row-local range while iterating rows.
Add terminal set/get support for the active screen selection through the
existing option and data APIs. Setting a selection copies the C snapshot
into terminal-owned tracked state, while passing NULL clears the current
selection.
Getting the selection now returns an untracked GhosttySelection snapshot
or GHOSTTY_NO_VALUE when there is no selection. The C header documents
the different lifetimes for set and get so embedders know when input and
returned grid references remain valid.
Add a C API for tracked pins, known as a tracked grid ref in C.
The new API can create tracked refs from terminal points, snapshot them
back to regular grid refs for cell access, convert them to coordinates,
move them to a new point, report when their semantic location was lost,
and free the tracked pin bookkeeping. This is backed by PageList tracked
pins and exposed through the libghostty-vt export layer and headers.
Add a C API for tracked pins, known as a tracked grid ref in C.
The new API can create tracked refs from terminal points, snapshot them
back to regular grid refs for cell access, convert them to coordinates,
move them to a new point, report when their semantic location was lost,
and free the tracked pin bookkeeping. This is backed by PageList tracked
pins and exposed through the libghostty-vt export layer and headers.
This PR fixes an issue where reflowing could leave the active cursor
attached to a clipped trailing blank cell instead of following the
current write position.
This PR fixes an issue where reflowing could leave the active cursor
attached to a clipped trailing blank cell instead of following the
current write position.
This fixes a bug where the variation selectors (VS15 & VS16) were
checked against the first codepoint in a cell instead of the previous
codepoint in the cell's grapheme cluster, causing them to be dropped if
the first codepoint was not a valid base.
This PR fixes an issue where a zero-width combining mark could attach to
the wrong cell when the preceding character was written in the final
column and the cursor had a pending wrap.
`allocTmpDir` previously read `%TMP%` via `getenvW` and returned `null`
if the variable wasn't set, requiring each caller to to deal with the
nullable. Unfortunately, there isn't a platform-neutral default value
that makes sense for those cases (i.e. `/tmp` is POSIX-y).
We now use `GetTempPathW` on Windows, which is the official way to get
this directory: `TMP` → `TEMP` → `USERPROFILE` → `GetWindowsDirectoryW`.
With a real system call behind it, the function no longer needs to be
nullable: the only remaining failure modes are OOM (propagated) and the
syscall itself failing or returning data we can't decode. In those later
cases, we use `C:\Windows\Temp` as a fallback, similar to how we use
`/tmp` in the POSIX case.
The Windows path always allocates so it still must be paired with
`freeTmpDir`, which matches the existing contract.
Stop trying to use POSIX shared memory functions such as
`shm_open` on Android as it's unsupported and the platform libc does not
have those symbols.
This avoids an error such as the below when trying to use
`libghostty-vt` on Android:
> dlopen failed: cannot locate symbol "shm_open" referenced by [..]
Maybe related to #12298?
When Screen resize forwards the active cursor into PageList reflow, a
history-pinned viewport can be remapped into the active area before the
preserved-cursor grow step finishes. The old code kept treating that
viewport as a history pin during the intermediate grow calls, which left
too few rows beneath the pin and tripped the viewport integrity checks.
Fix this by normalizing the viewport back to active as soon as reflow
moves the pinned row into the active area. Add a Screen-level regression
test that exercises the full resize path with bounded scrollback and
wrapped rows, and document the setup so the unwrap and viewport
transition are clear.
This mode allows programs to modify the code that the `backspace`
key (backarrow key in DEC parlance) sends. If this mode is
`off`/`false`/`reset` (the default, the same as before this PR), we
send the byte `0x7f`. If this mode is `on`/`true`/`set` we send the
byte `0x08`.
Replace the ImageInfo and PlacementInfo sized structs and their
associated .info enum variants with a new _get_multi pattern that
batches multiple enum+pointer pairs into a single call. This avoids
struct ABI concerns (field order, padding, alignment, GHOSTTY_INIT_SIZED)
while preserving the single-call-crossing performance benefit for FFI
and Cgo callers.
Each _get_multi function takes an array of enum keys, an array of
output pointers, and an optional out_written parameter that reports
how many values were successfully written before any error. This
applies uniformly to all _get APIs: terminal_get, cell_get, row_get,
render_state_get, render_state_row_get, render_state_row_cells_get,
kitty_graphics_image_get, and kitty_graphics_placement_get.
The C example is updated to use compound-literal _get_multi calls,
and tests cover both success and error paths for every new function.
Add three sized structs that let callers fetch all image, placement,
or rendering metadata in a single call instead of many individual
queries. This is an optimization for environments with high per-call
overhead such as FFI or Cgo.
GhosttyKittyGraphicsImageInfo is returned via image_get() with the
new GHOSTTY_KITTY_IMAGE_DATA_INFO data kind. It bundles id, number,
width, height, format, compression, data pointer, and data length.
GhosttyKittyGraphicsPlacementInfo is returned via placement_get()
with the new GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO data kind.
It bundles image id, placement id, virtual flag, offsets, source
rect, columns, rows, and z-index.
GhosttyKittyGraphicsPlacementRenderInfo is returned by the new
ghostty_kitty_graphics_placement_render_info() function, which
combines pixel size, grid size, viewport position, and resolved
source rectangle. This one requires image and terminal handles so
it does not fit the existing _get() pattern and is a dedicated
function.
All three use the sized-struct ABI pattern with GHOSTTY_INIT_SIZED
for forward compatibility.
In C ABI builds, the Zig std.log default writes to stderr which is
not appropriate for a library. Override std_options.logFn with a
custom sink that dispatches to an embedder-provided callback, or
silently discards when none is registered.
Add GHOSTTY_SYS_OPT_LOG to ghostty_sys_set() following the existing
decode_png pattern. The callback receives the log level as a
GhosttySysLogLevel enum, scope and message as separate byte slices,
giving embedders full control over formatting and routing.
Export ghostty_sys_log_stderr as a built-in convenience callback that
writes to stderr using std.debug.lockStderrWriter for thread-safe
output. Embedders who want the old behavior can install it at startup
with a single ghostty_sys_set call.
Fix three categories of test bugs in the kitty graphics C API tests:
The placement iterator reset in getTyped was clobbering the
layer_filter field when reinitializing the iterator struct,
causing the layer filter test to see unfiltered placements.
Preserve layer_filter across resets.
The viewport position tests were not accounting for the default
cursor_movement=after behavior of the kitty display command,
which calls index() for each row of the placement before the
test scroll sequence. Add C=1 to suppress cursor movement so
the scroll math in the tests is correct.
The source_rect tests used an 88-character all-A base64 payload
which decodes to 66 bytes, but a 4x4 RGBA image requires exactly
64 bytes. Fix the payload to use proper base64 padding (AA==).
Add ghostty_kitty_graphics_placement_source_rect which returns the
fully resolved and clamped source rectangle for a placement. This
applies kitty protocol semantics (width/height of 0 means full
image dimension) and clamps the result to the actual image bounds,
eliminating ~20 lines of protocol-aware logic from each embedder.
Add ghostty_kitty_graphics_placement_viewport_pos which converts a
placement's internal pin to viewport-relative grid coordinates.
The returned row can be negative when the placement's origin has
scrolled above the viewport, allowing embedders to compute the
correct destination rectangle for partially visible images.
Returns GHOSTTY_NO_VALUE only when the placement is completely
outside the viewport (bottom edge above the viewport or top edge
at or below the last row), so embedders do not need to perform
their own visibility checks. Partially visible placements always
return GHOSTTY_SUCCESS with their true signed coordinates.
Add a placement_iterator_set function that configures iterator
properties via an enum, following the same pattern as other set
functions in the C API (e.g. render_state_set). The first settable
option is a z-layer filter.
The GhosttyKittyPlacementLayer enum classifies placements into three
layers based on kitty protocol z-index conventions: below background
(z < INT32_MIN/2), below text (INT32_MIN/2 <= z < 0), and above text
(z >= 0). The default is ALL which preserves existing behavior.
When a layer filter is set, placement_iterator_next automatically
skips non-matching placements, so embedders no longer need to
reimplement the z-index bucketing logic or iterate all placements
three times per frame just to filter by layer.
Add the inverse of ghostty_terminal_grid_ref(), converting a grid
reference back to coordinates in a requested coordinate system
(active, viewport, screen, or history). This wraps the existing
internal PageList.pointFromPin and is placed on the terminal API
since it requires terminal-owned PageList state to resolve the
top-left anchor for each coordinate system.
Returns GHOSTTY_NO_VALUE when the ref falls outside the requested
range, e.g. a scrollback ref cannot be expressed in active
coordinates.
The PlacementIterator, PlacementMap, and PlacementIteratorWrapper
types in the C API were unconditionally referencing
kitty_storage.ImageStorage, which transitively pulled in
Image.transmit_time (std.time.Instant). On wasm32-freestanding,
std.time.Instant requires posix.timespec which does not exist,
causing a compilation error.
Gate these types behind build_options.kitty_graphics, matching the
existing pattern used for KittyGraphics and ImageHandle. When
kitty graphics is disabled, they fall back to opaque/void types.
Add early-return guards to placement_iterator_new and
placement_iterator_free which directly operate on the wrapper
struct.
The test transmits an image with f=24 (24-bit RGB) but was asserting
that the format field equals .rgba (32-bit). Corrected the expectation
to .rgb to match the transmitted pixel format.
Expose Placement.pixelSize() and Placement.gridSize() as new C API
functions ghostty_kitty_graphics_placement_pixel_size() and
ghostty_kitty_graphics_placement_grid_size(). Both take the placement
iterator, image handle, and terminal, returning their results via
out params.
Rename the internal Zig method from calculatedSize to pixelSize to
pair naturally with gridSize — one returns pixels, the other grid
cells. Updated all callers including the renderer.
Expose Placement.rect() from the Zig kitty graphics storage as a new
C API function ghostty_kitty_graphics_placement_rect(). It takes the
terminal, image handle, and a positioned placement iterator, and
writes the bounding grid rectangle into a GhosttySelection out param.
Virtual placements return GHOSTTY_NO_VALUE.
Move all opaque handle typedefs (GhosttyTerminal, GhosttyKittyGraphics,
GhosttyRenderState, GhosttySgrParser, GhosttyFormatter, GhosttyOsc*)
into types.h so they are available everywhere without circular includes
and Doxygen renders them in the correct @ingroup sections.
Convert the Transmission.Format, Transmission.Medium, and
Transmission.Compression types from plain Zig enums to lib.Enum so
they get a C-compatible backing type when building with c_abi. This
lets the C API layer reuse the types directly instead of maintaining
separate mirror enums.
Move Format.bpp() to a standalone Transmission.formatBpp() function
since lib.Enum types cannot have decls.
In the C API layer, rename kitty_gfx to kitty_storage and command to
kitty_cmd for clarity, and simplify the format/compression getters
to direct assignment now that the types are shared.