commits
Extensive notes on concurrency
Document and test cross-compilation
One of the common stigmas of cgo in Go projects is that it makes
cross-compilation overly difficult. Its more difficult than pure Go projects,
to be sure, but with the right shape of libraries and build scripts, it
can be made to work well. libghostty is a good example of this.
libghostty only depends on libc and the Zig compiler (tool, not language)
as a drop-in replacement for c/c++ compilation means we can easily
cross-compile!
This commit adds documentation, tests, and examples on how to do this.
terminal: fix checkptr failure under -race for cgo.Handle userdata
Converting a cgo.Handle (uintptr) directly to unsafe.Pointer in
NewTerminal triggered a checkptr "bad pointer value" panic when
running tests with -race. The handle is an opaque integer, not a
real Go pointer, so checkptr incorrectly rejects it.
Extract the conversion into a small handleToPointer helper
annotated with //go:nocheckptr to suppress the false positive.
terminal: pass *Terminal as first parameter to effect callbacks
Previously, effect callback function types (WritePtyFn, BellFn,
TitleChangedFn, etc.) did not receive the terminal that triggered
them. This forced callers using the functional option pattern to
pre-declare a var and use a split assignment so closures could
capture it, as seen in the effects example.
All effect callback types now take *Terminal as their first
parameter. The C trampolines already recovered the *Terminal from
userdata, so they now simply forward it to the Go handler. This
lets callers define callbacks inline in NewTerminal without any
pre-declaration workaround.
encoding: add key, mouse, and focus encoding bindings
Add Go bindings for the upstream key, mouse, and focus encoding
APIs from key/, mouse/, and focus.h headers.
Key encoding provides KeyEvent (action, key, mods, UTF-8 text,
composing state, unshifted codepoint) and KeyEncoder with setopt
methods for cursor key application mode, Kitty keyboard protocol
flags, macOS option-as-alt, and other terminal modes. The encoder
also supports syncing options from a Terminal instance.
Mouse encoding provides MouseEvent (action, button, mods, position)
and MouseEncoder with tracking mode, format, size geometry, and
terminal state syncing. The encoder supports X10, UTF-8, SGR, URxvt,
and SGR-Pixels protocols.
Focus encoding exposes FocusEncode as a standalone function producing
CSI I (gained) or CSI O (lost) sequences.
KittyKeyFlags moves from terminal.go to key_encoder.go since it is
part of the key encoding API and used by both the encoder and the
terminal.
Update libghostty to not depend on libc++
sys/png: move SysDecodePng to separate subpackage
Fixes #6
The root libghostty package previously imported image/png for
SysDecodePng. Because image/png registers itself via an init()
function, the Go linker cannot eliminate it from binaries that
never call SysDecodePng. Every consumer paid the cost.
Move the built-in PNG decoder into sys/png so users opt in
explicitly. The root package no longer imports image or image/png.
The kitty_graphics_test.go file inlines a local test helper to
avoid the import cycle that would result from an internal test
package importing its own subpackage.
bind ghostty_alloc/ghostty_free and replace C.malloc/C.free
Add alloc.go with exported Alloc and Free functions wrapping the
upstream ghostty_alloc() and ghostty_free() from allocator.h. These
use the default (NULL) allocator, matching how the rest of the
bindings pass nil for the allocator parameter.
This is important because it lets us not explicitly depend on any libc
functionality.
bind upstream get_multi APIs, replace sized-struct Info()
Update the pinned ghostty commit to pick up the new _get_multi C
APIs added across all getter types (terminal, render state, row,
cell, screen, kitty graphics image, kitty graphics placement).
The existing Info() methods on KittyGraphicsImage and
KittyGraphicsPlacementIterator previously used sized-struct C
types (GhosttyKittyGraphicsImageInfo, etc.) initialized via
GHOSTTY_INIT_SIZED. These are replaced by get_multi calls that
fetch each field individually through typed pointers, eliminating
struct ABI concerns (padding, alignment, field ordering) at the
cgo boundary. The Go-side convenience structs remain unchanged.
Each type also gains a public GetMulti method that exposes the
raw get_multi API for callers who want to batch arbitrary subsets
of queries into a single cgo crossing.
A shared cValuesArray helper in get_multi.go solves the cgo
pointer-passing rule for void**: the array of output pointers is
allocated in C heap memory, populated from Go, passed to C, then
freed.
kitty_graphics: add batch info and render info bindings
Update the pinned upstream commit to 7421b4b which adds three new
convenience APIs that return all metadata or rendering geometry in
a single sized-struct call, avoiding repeated cgo overhead.
KittyGraphicsImage.Info() returns all image metadata (ID, number,
dimensions, format, compression, pixel data) via the new
GHOSTTY_KITTY_IMAGE_DATA_INFO enum and GhosttyKittyGraphicsImageInfo
struct.
KittyGraphicsPlacementIterator.Info() returns all placement metadata
(image ID, placement ID, virtual flag, offsets, source rect, grid
size, z-index) via GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO and
GhosttyKittyGraphicsPlacementInfo.
KittyGraphicsPlacementIterator.RenderInfo() combines pixel size,
grid size, viewport position, and source rectangle into one call
via the new ghostty_kitty_graphics_placement_render_info() function
and GhosttyKittyGraphicsPlacementRenderInfo struct.
Kitty Graphics, PNG Decoding
Adds an agent skill that reviews Go bindings against upstream
libghostty-vt C headers and produces concrete API improvement
suggestions. The skill applies a checklist of known friction
patterns (multi-call data fetching, ptr/len splits, repeated
parameter triples, two-phase init) and writes findings with
impact ratings and C signature sketches to UPSTREAM.md.
Add complete Go bindings for kitty_graphics.h, covering the full
image storage and placement iteration API.
New types: KittyGraphics, KittyGraphicsImage, and
KittyGraphicsPlacementIterator along with enums for placement
layers, image formats, and compression. Terminal.KittyGraphics()
provides the entry point by querying the active screen storage.
Image handles expose ID, dimensions, format, compression, and
borrowed pixel data. The placement iterator supports z-layer
filtering and provides per-placement getters for image ID,
placement ID, offsets, source rect fields, grid size, and z-index.
Rendering helpers compute pixel size, grid size, viewport position,
source rect, and bounding selection.
Terminal option setters added for SetKittyImageStorageLimit and the
three medium toggles (file, temp file, shared memory).
Also introduces the Selection type wrapping GhosttySelection since
the placement rect API returns one.
Bind the GHOSTTY_SYS_OPT_DECODE_PNG option from ghostty_sys_set(),
which lets embedders supply a PNG-to-RGBA decoder for Kitty Graphics
Protocol support.
SysSetDecodePng installs or clears a Go callback. The C trampoline
allocates the output pixel buffer through the library allocator via
ghostty_alloc so the library can own and free it. The Go callback
returns a SysImage struct; pixel data is copied into the
library-owned buffer before returning to C.
A ready-to-use SysDecodePng function is provided in sys_builtin.go
that uses Go standard library image/png. It returns NRGBA pixels
directly when the decoded image is already in that format and falls
back to a per-pixel conversion for other image types.
Add an agent skill for discovering new or missing C APIs in the
upstream libghostty-vt headers and creating Go bindings for them.
The skill guides the agent through diffing upstream headers against
existing bindings, presenting findings, and writing idiomatic Go
wrappers following project conventions.
Includes a helper script that compares the pinned GIT_TAG in
CMakeLists.txt against the latest upstream main branch commit,
reporting whether an update is available.
sys: add log callback configuration
Bump the ghostty pin to include the new GHOSTTY_SYS_OPT_LOG API
from ghostty-org/ghostty#12227.
Add Go bindings for the log callback system in sys.go. SysSetLog
installs a Go callback that receives internal library log messages
with a level, scope, and message. SysSetLogStderr installs the
built-in ghostty_sys_log_stderr convenience callback. Passing nil
to SysSetLog clears the callback and silently discards messages.
The Go trampoline converts C types to native Go strings before
dispatching to the user callback. The API is not safe for concurrent
use and should be configured at startup before creating terminals.
This was originally broken up over many commits but I extracted this
from another project. I think a lot of people assume "one big commit" means
AI slop nowadays and while I use AI assistance, that wasn't the case here.
One of the common stigmas of cgo in Go projects is that it makes
cross-compilation overly difficult. Its more difficult than pure Go projects,
to be sure, but with the right shape of libraries and build scripts, it
can be made to work well. libghostty is a good example of this.
libghostty only depends on libc and the Zig compiler (tool, not language)
as a drop-in replacement for c/c++ compilation means we can easily
cross-compile!
This commit adds documentation, tests, and examples on how to do this.
Converting a cgo.Handle (uintptr) directly to unsafe.Pointer in
NewTerminal triggered a checkptr "bad pointer value" panic when
running tests with -race. The handle is an opaque integer, not a
real Go pointer, so checkptr incorrectly rejects it.
Extract the conversion into a small handleToPointer helper
annotated with //go:nocheckptr to suppress the false positive.
Previously, effect callback function types (WritePtyFn, BellFn,
TitleChangedFn, etc.) did not receive the terminal that triggered
them. This forced callers using the functional option pattern to
pre-declare a var and use a split assignment so closures could
capture it, as seen in the effects example.
All effect callback types now take *Terminal as their first
parameter. The C trampolines already recovered the *Terminal from
userdata, so they now simply forward it to the Go handler. This
lets callers define callbacks inline in NewTerminal without any
pre-declaration workaround.
Add Go bindings for the upstream key, mouse, and focus encoding
APIs from key/, mouse/, and focus.h headers.
Key encoding provides KeyEvent (action, key, mods, UTF-8 text,
composing state, unshifted codepoint) and KeyEncoder with setopt
methods for cursor key application mode, Kitty keyboard protocol
flags, macOS option-as-alt, and other terminal modes. The encoder
also supports syncing options from a Terminal instance.
Mouse encoding provides MouseEvent (action, button, mods, position)
and MouseEncoder with tracking mode, format, size geometry, and
terminal state syncing. The encoder supports X10, UTF-8, SGR, URxvt,
and SGR-Pixels protocols.
Focus encoding exposes FocusEncode as a standalone function producing
CSI I (gained) or CSI O (lost) sequences.
KittyKeyFlags moves from terminal.go to key_encoder.go since it is
part of the key encoding API and used by both the encoder and the
terminal.
Fixes #6
The root libghostty package previously imported image/png for
SysDecodePng. Because image/png registers itself via an init()
function, the Go linker cannot eliminate it from binaries that
never call SysDecodePng. Every consumer paid the cost.
Move the built-in PNG decoder into sys/png so users opt in
explicitly. The root package no longer imports image or image/png.
The kitty_graphics_test.go file inlines a local test helper to
avoid the import cycle that would result from an internal test
package importing its own subpackage.
Add alloc.go with exported Alloc and Free functions wrapping the
upstream ghostty_alloc() and ghostty_free() from allocator.h. These
use the default (NULL) allocator, matching how the rest of the
bindings pass nil for the allocator parameter.
This is important because it lets us not explicitly depend on any libc
functionality.
Update the pinned ghostty commit to pick up the new _get_multi C
APIs added across all getter types (terminal, render state, row,
cell, screen, kitty graphics image, kitty graphics placement).
The existing Info() methods on KittyGraphicsImage and
KittyGraphicsPlacementIterator previously used sized-struct C
types (GhosttyKittyGraphicsImageInfo, etc.) initialized via
GHOSTTY_INIT_SIZED. These are replaced by get_multi calls that
fetch each field individually through typed pointers, eliminating
struct ABI concerns (padding, alignment, field ordering) at the
cgo boundary. The Go-side convenience structs remain unchanged.
Each type also gains a public GetMulti method that exposes the
raw get_multi API for callers who want to batch arbitrary subsets
of queries into a single cgo crossing.
A shared cValuesArray helper in get_multi.go solves the cgo
pointer-passing rule for void**: the array of output pointers is
allocated in C heap memory, populated from Go, passed to C, then
freed.
Update the pinned upstream commit to 7421b4b which adds three new
convenience APIs that return all metadata or rendering geometry in
a single sized-struct call, avoiding repeated cgo overhead.
KittyGraphicsImage.Info() returns all image metadata (ID, number,
dimensions, format, compression, pixel data) via the new
GHOSTTY_KITTY_IMAGE_DATA_INFO enum and GhosttyKittyGraphicsImageInfo
struct.
KittyGraphicsPlacementIterator.Info() returns all placement metadata
(image ID, placement ID, virtual flag, offsets, source rect, grid
size, z-index) via GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO and
GhosttyKittyGraphicsPlacementInfo.
KittyGraphicsPlacementIterator.RenderInfo() combines pixel size,
grid size, viewport position, and source rectangle into one call
via the new ghostty_kitty_graphics_placement_render_info() function
and GhosttyKittyGraphicsPlacementRenderInfo struct.
Adds an agent skill that reviews Go bindings against upstream
libghostty-vt C headers and produces concrete API improvement
suggestions. The skill applies a checklist of known friction
patterns (multi-call data fetching, ptr/len splits, repeated
parameter triples, two-phase init) and writes findings with
impact ratings and C signature sketches to UPSTREAM.md.
Add complete Go bindings for kitty_graphics.h, covering the full
image storage and placement iteration API.
New types: KittyGraphics, KittyGraphicsImage, and
KittyGraphicsPlacementIterator along with enums for placement
layers, image formats, and compression. Terminal.KittyGraphics()
provides the entry point by querying the active screen storage.
Image handles expose ID, dimensions, format, compression, and
borrowed pixel data. The placement iterator supports z-layer
filtering and provides per-placement getters for image ID,
placement ID, offsets, source rect fields, grid size, and z-index.
Rendering helpers compute pixel size, grid size, viewport position,
source rect, and bounding selection.
Terminal option setters added for SetKittyImageStorageLimit and the
three medium toggles (file, temp file, shared memory).
Also introduces the Selection type wrapping GhosttySelection since
the placement rect API returns one.
Bind the GHOSTTY_SYS_OPT_DECODE_PNG option from ghostty_sys_set(),
which lets embedders supply a PNG-to-RGBA decoder for Kitty Graphics
Protocol support.
SysSetDecodePng installs or clears a Go callback. The C trampoline
allocates the output pixel buffer through the library allocator via
ghostty_alloc so the library can own and free it. The Go callback
returns a SysImage struct; pixel data is copied into the
library-owned buffer before returning to C.
A ready-to-use SysDecodePng function is provided in sys_builtin.go
that uses Go standard library image/png. It returns NRGBA pixels
directly when the decoded image is already in that format and falls
back to a per-pixel conversion for other image types.
Add an agent skill for discovering new or missing C APIs in the
upstream libghostty-vt headers and creating Go bindings for them.
The skill guides the agent through diffing upstream headers against
existing bindings, presenting findings, and writing idiomatic Go
wrappers following project conventions.
Includes a helper script that compares the pinned GIT_TAG in
CMakeLists.txt against the latest upstream main branch commit,
reporting whether an update is available.
Bump the ghostty pin to include the new GHOSTTY_SYS_OPT_LOG API
from ghostty-org/ghostty#12227.
Add Go bindings for the log callback system in sys.go. SysSetLog
installs a Go callback that receives internal library log messages
with a level, scope, and message. SysSetLogStderr installs the
built-in ghostty_sys_log_stderr convenience callback. Passing nil
to SysSetLog clears the callback and silently discards messages.
The Go trampoline converts C types to native Go strings before
dispatching to the user callback. The API is not safe for concurrent
use and should be configured at startup before creating terminals.