From 5d67d01e6331275fe97fef59619c697b50958d50 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 11 Apr 2026 13:00:58 -0700 Subject: [PATCH] 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. --- CMakeLists.txt | 2 +- get_multi.go | 25 +++ kitty_graphics.go | 362 +++++++++++++++++++++++++++++++++++++------ render_state_cell.go | 74 +++++++++ render_state_data.go | 114 ++++++++++++++ render_state_row.go | 65 +++++++- screen.go | 172 +++++++++++++++++++- terminal_data.go | 162 +++++++++++++++++++ 8 files changed, 922 insertions(+), 54 deletions(-) create mode 100644 get_multi.go diff --git a/CMakeLists.txt b/CMakeLists.txt index 46255d1..9d6103a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,6 @@ project(go-libghostty LANGUAGES C) include(FetchContent) FetchContent_Declare(ghostty GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git - GIT_TAG 7421b4b13f87e101d4bbcedd4da84886ceae4e7b + GIT_TAG c36b458ad57a95869745e405c9d8d45104a97773 ) FetchContent_MakeAvailable(ghostty) diff --git a/get_multi.go b/get_multi.go new file mode 100644 index 0000000..d85323b --- /dev/null +++ b/get_multi.go @@ -0,0 +1,25 @@ +package libghostty + +// Shared helpers for the get_multi pattern used by multiple types. +// These helpers solve the cgo pointer-passing rule: Go cannot pass +// a Go-allocated void** (array of pointers to Go memory) directly +// to C. Instead, we allocate the void** array in C heap memory, +// copy the Go pointer values in, call the C function, then free. + +/* +#include +*/ +import "C" + +import "unsafe" + +// cValuesArray allocates a C-heap array of void* pointers, copies the +// Go unsafe.Pointer values into it, and returns the C array pointer. +// The caller must free the returned pointer with C.free when done. +func cValuesArray(values []unsafe.Pointer) *unsafe.Pointer { + n := len(values) + cArr := (*unsafe.Pointer)(C.malloc(C.size_t(n) * C.size_t(unsafe.Sizeof(unsafe.Pointer(nil))))) + dst := unsafe.Slice(cArr, n) + copy(dst, values) + return cArr +} diff --git a/kitty_graphics.go b/kitty_graphics.go index 001576d..94e622d 100644 --- a/kitty_graphics.go +++ b/kitty_graphics.go @@ -5,6 +5,7 @@ package libghostty // protocol. /* +#include #include // Helper to create a properly initialized GhosttySelection (sized struct). @@ -13,18 +14,6 @@ static inline GhosttySelection init_selection() { return s; } -// Helper to create a properly initialized GhosttyKittyGraphicsImageInfo (sized struct). -static inline GhosttyKittyGraphicsImageInfo init_kitty_image_info() { - GhosttyKittyGraphicsImageInfo info = GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsImageInfo); - return info; -} - -// Helper to create a properly initialized GhosttyKittyGraphicsPlacementInfo (sized struct). -static inline GhosttyKittyGraphicsPlacementInfo init_kitty_placement_info() { - GhosttyKittyGraphicsPlacementInfo info = GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementInfo); - return info; -} - // Helper to create a properly initialized GhosttyKittyGraphicsPlacementRenderInfo (sized struct). static inline GhosttyKittyGraphicsPlacementRenderInfo init_kitty_placement_render_info() { GhosttyKittyGraphicsPlacementRenderInfo info = GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementRenderInfo); @@ -33,7 +22,105 @@ static inline GhosttyKittyGraphicsPlacementRenderInfo init_kitty_placement_rende */ import "C" -import "unsafe" +import ( + "errors" + "unsafe" +) + +// KittyGraphicsImageData identifies a data field for Kitty graphics +// image queries. +// C: GhosttyKittyGraphicsImageData +type KittyGraphicsImageData int + +const ( + // KittyGraphicsImageDataInvalid is an invalid / sentinel value. + KittyGraphicsImageDataInvalid KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_INVALID + + // KittyGraphicsImageDataID is the image ID (uint32_t). + KittyGraphicsImageDataID KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_ID + + // KittyGraphicsImageDataNumber is the image number (uint32_t). + KittyGraphicsImageDataNumber KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_NUMBER + + // KittyGraphicsImageDataWidth is the image width in pixels (uint32_t). + KittyGraphicsImageDataWidth KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_WIDTH + + // KittyGraphicsImageDataHeight is the image height in pixels (uint32_t). + KittyGraphicsImageDataHeight KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_HEIGHT + + // KittyGraphicsImageDataFormat is the pixel format of the image + // (GhosttyKittyImageFormat). + KittyGraphicsImageDataFormat KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_FORMAT + + // KittyGraphicsImageDataCompression is the compression of the image + // (GhosttyKittyImageCompression). + KittyGraphicsImageDataCompression KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION + + // KittyGraphicsImageDataDataPtr is a borrowed pointer to the raw pixel + // data (const uint8_t **). + KittyGraphicsImageDataDataPtr KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_DATA_PTR + + // KittyGraphicsImageDataDataLen is the length of the raw pixel data + // in bytes (size_t). + KittyGraphicsImageDataDataLen KittyGraphicsImageData = C.GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN +) + +// KittyGraphicsPlacementData identifies a data field for Kitty graphics +// placement queries. +// C: GhosttyKittyGraphicsPlacementData +type KittyGraphicsPlacementData int + +const ( + // KittyGraphicsPlacementDataInvalid is an invalid / sentinel value. + KittyGraphicsPlacementDataInvalid KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INVALID + + // KittyGraphicsPlacementDataImageID is the image ID this placement + // belongs to (uint32_t). + KittyGraphicsPlacementDataImageID KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID + + // KittyGraphicsPlacementDataPlacementID is the placement ID (uint32_t). + KittyGraphicsPlacementDataPlacementID KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID + + // KittyGraphicsPlacementDataIsVirtual indicates whether this is a + // virtual placement (bool). + KittyGraphicsPlacementDataIsVirtual KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL + + // KittyGraphicsPlacementDataXOffset is the pixel offset from the left + // edge of the cell (uint32_t). + KittyGraphicsPlacementDataXOffset KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET + + // KittyGraphicsPlacementDataYOffset is the pixel offset from the top + // edge of the cell (uint32_t). + KittyGraphicsPlacementDataYOffset KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET + + // KittyGraphicsPlacementDataSourceX is the source rectangle x origin + // in pixels (uint32_t). + KittyGraphicsPlacementDataSourceX KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X + + // KittyGraphicsPlacementDataSourceY is the source rectangle y origin + // in pixels (uint32_t). + KittyGraphicsPlacementDataSourceY KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y + + // KittyGraphicsPlacementDataSourceWidth is the source rectangle width + // in pixels (uint32_t). + KittyGraphicsPlacementDataSourceWidth KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH + + // KittyGraphicsPlacementDataSourceHeight is the source rectangle height + // in pixels (uint32_t). + KittyGraphicsPlacementDataSourceHeight KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT + + // KittyGraphicsPlacementDataColumns is the number of columns this + // placement occupies (uint32_t). + KittyGraphicsPlacementDataColumns KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS + + // KittyGraphicsPlacementDataRows is the number of rows this placement + // occupies (uint32_t). + KittyGraphicsPlacementDataRows KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_ROWS + + // KittyGraphicsPlacementDataZ is the z-index for this placement + // (int32_t). + KittyGraphicsPlacementDataZ KittyGraphicsPlacementData = C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z +) // KittyGraphics is a handle to the Kitty graphics image storage // associated with a terminal's active screen. It is borrowed from @@ -146,10 +233,8 @@ func selectionFromC(cs C.GhosttySelection) Selection { } // KittyGraphicsImageInfo contains all image metadata in a single struct. -// This is more efficient than querying each field individually since it -// requires only one cgo call. -// -// C: GhosttyKittyGraphicsImageInfo +// This is a Go-only convenience type; it has no corresponding C struct. +// Populated via get_multi in a single cgo call. type KittyGraphicsImageInfo struct { // ID is the image ID. ID uint32 @@ -175,10 +260,8 @@ type KittyGraphicsImageInfo struct { } // KittyGraphicsPlacementInfo contains all placement metadata in a single -// struct. This is more efficient than querying each field individually -// since it requires only one cgo call. -// -// C: GhosttyKittyGraphicsPlacementInfo +// struct. This is a Go-only convenience type; it has no corresponding +// C struct. Populated via get_multi in a single cgo call. type KittyGraphicsPlacementInfo struct { // ImageID is the image ID this placement belongs to. ImageID uint32 @@ -334,6 +417,46 @@ func (img *KittyGraphicsImage) Height() (uint32, error) { return uint32(v), nil } +// GetMulti queries multiple image data fields in a single cgo call. +// This is a low-level function; prefer the typed getters (ID, Width, +// Height, Format, etc.) or Info() for normal use. GetMulti is useful +// when you need a custom subset of fields and want to avoid per-field +// cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/kitty_graphics.h, GhosttyKittyGraphicsImageData +// enum). +// +// Example: +// +// var w, h C.uint32_t +// err := img.GetMulti( +// []KittyGraphicsImageData{KittyGraphicsImageDataWidth, KittyGraphicsImageDataHeight}, +// []unsafe.Pointer{unsafe.Pointer(&w), unsafe.Pointer(&h)}, +// ) +// +// C: ghostty_kitty_graphics_image_get_multi +func (img *KittyGraphicsImage) GetMulti(keys []KittyGraphicsImageData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_kitty_graphics_image_get_multi( + img.ptr, + C.size_t(len(keys)), + (*C.GhosttyKittyGraphicsImageData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // Format returns the pixel format of the image. func (img *KittyGraphicsImage) Format() (KittyImageFormat, error) { var v C.GhosttyKittyImageFormat @@ -362,28 +485,71 @@ func (img *KittyGraphicsImage) Compression() (KittyImageCompression, error) { // Info returns all image metadata in a single call. This is more // efficient than calling ID, Number, Width, Height, Format, -// Compression, and Data individually. +// Compression, and Data individually. Uses the get_multi C API +// to fetch all fields in one cgo round-trip. func (img *KittyGraphicsImage) Info() (*KittyGraphicsImageInfo, error) { - ci := C.init_kitty_image_info() - if err := resultError(C.ghostty_kitty_graphics_image_get( + // Output variables — one per field, typed to match the C API. + var ( + id C.uint32_t + number C.uint32_t + width C.uint32_t + height C.uint32_t + format C.GhosttyKittyImageFormat + compression C.GhosttyKittyImageCompression + dataPtr *C.uint8_t + dataLen C.size_t + ) + + // Keys identify which fields to fetch; order must match values. + keys := [...]C.GhosttyKittyGraphicsImageData{ + C.GHOSTTY_KITTY_IMAGE_DATA_ID, + C.GHOSTTY_KITTY_IMAGE_DATA_NUMBER, + C.GHOSTTY_KITTY_IMAGE_DATA_WIDTH, + C.GHOSTTY_KITTY_IMAGE_DATA_HEIGHT, + C.GHOSTTY_KITTY_IMAGE_DATA_FORMAT, + C.GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION, + C.GHOSTTY_KITTY_IMAGE_DATA_DATA_PTR, + C.GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN, + } + + // Each value pointer receives the corresponding field from C. + // We must allocate the void** array in C memory to satisfy cgo + // pointer-passing rules (Go cannot pass a Go pointer containing + // other Go pointers to C). + values := [...]unsafe.Pointer{ + unsafe.Pointer(&id), + unsafe.Pointer(&number), + unsafe.Pointer(&width), + unsafe.Pointer(&height), + unsafe.Pointer(&format), + unsafe.Pointer(&compression), + unsafe.Pointer(&dataPtr), + unsafe.Pointer(&dataLen), + } + cVals := cValuesArray(values[:]) + defer C.free(unsafe.Pointer(cVals)) + + if err := resultError(C.ghostty_kitty_graphics_image_get_multi( img.ptr, - C.GHOSTTY_KITTY_IMAGE_DATA_INFO, - unsafe.Pointer(&ci), + C.size_t(len(keys)), + &keys[0], + cVals, + nil, )); err != nil { return nil, err } info := &KittyGraphicsImageInfo{ - ID: uint32(ci.id), - Number: uint32(ci.number), - Width: uint32(ci.width), - Height: uint32(ci.height), - Format: KittyImageFormat(ci.format), - Compression: KittyImageCompression(ci.compression), + ID: uint32(id), + Number: uint32(number), + Width: uint32(width), + Height: uint32(height), + Format: KittyImageFormat(format), + Compression: KittyImageCompression(compression), } - if ci.data_ptr != nil && ci.data_len > 0 { - info.Data = unsafe.Slice((*byte)(unsafe.Pointer(ci.data_ptr)), int(ci.data_len)) + if dataPtr != nil && dataLen > 0 { + info.Data = unsafe.Slice((*byte)(unsafe.Pointer(dataPtr)), int(dataLen)) } return info, nil @@ -453,6 +619,47 @@ func (it *KittyGraphicsPlacementIterator) Next() bool { return bool(C.ghostty_kitty_graphics_placement_next(it.ptr)) } +// GetMulti queries multiple placement data fields in a single cgo +// call. This is a low-level function; prefer the typed getters +// (ImageID, PlacementID, Z, etc.) or Info() for normal use. GetMulti +// is useful when you need a custom subset of fields and want to avoid +// per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/kitty_graphics.h, +// GhosttyKittyGraphicsPlacementData enum). +// +// Example: +// +// var imageID C.uint32_t +// var z C.int32_t +// err := it.GetMulti( +// []KittyGraphicsPlacementData{KittyGraphicsPlacementDataImageID, KittyGraphicsPlacementDataZ}, +// []unsafe.Pointer{unsafe.Pointer(&imageID), unsafe.Pointer(&z)}, +// ) +// +// C: ghostty_kitty_graphics_placement_get_multi +func (it *KittyGraphicsPlacementIterator) GetMulti(keys []KittyGraphicsPlacementData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_kitty_graphics_placement_get_multi( + it.ptr, + C.size_t(len(keys)), + (*C.GhosttyKittyGraphicsPlacementData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // ImageID returns the image ID of the current placement. func (it *KittyGraphicsPlacementIterator) ImageID() (uint32, error) { var v C.uint32_t @@ -615,30 +822,83 @@ func (it *KittyGraphicsPlacementIterator) Z() (int32, error) { // Info returns all placement metadata in a single call. This is more // efficient than calling ImageID, PlacementID, IsVirtual, XOffset, // YOffset, SourceX, SourceY, SourceWidth, SourceHeight, Columns, -// Rows, and Z individually. +// Rows, and Z individually. Uses the get_multi C API to fetch all +// fields in one cgo round-trip. func (it *KittyGraphicsPlacementIterator) Info() (*KittyGraphicsPlacementInfo, error) { - ci := C.init_kitty_placement_info() - if err := resultError(C.ghostty_kitty_graphics_placement_get( + // Output variables — one per field, typed to match the C API. + var ( + imageID C.uint32_t + placementID C.uint32_t + isVirtual C.bool + xOffset C.uint32_t + yOffset C.uint32_t + sourceX C.uint32_t + sourceY C.uint32_t + sourceWidth C.uint32_t + sourceHeight C.uint32_t + columns C.uint32_t + rows C.uint32_t + z C.int32_t + ) + + // Keys identify which fields to fetch; order must match values. + keys := [...]C.GhosttyKittyGraphicsPlacementData{ + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_ROWS, + C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z, + } + + // Each value pointer receives the corresponding field from C. + // Allocated in C memory to satisfy cgo pointer-passing rules. + values := [...]unsafe.Pointer{ + unsafe.Pointer(&imageID), + unsafe.Pointer(&placementID), + unsafe.Pointer(&isVirtual), + unsafe.Pointer(&xOffset), + unsafe.Pointer(&yOffset), + unsafe.Pointer(&sourceX), + unsafe.Pointer(&sourceY), + unsafe.Pointer(&sourceWidth), + unsafe.Pointer(&sourceHeight), + unsafe.Pointer(&columns), + unsafe.Pointer(&rows), + unsafe.Pointer(&z), + } + cVals := cValuesArray(values[:]) + defer C.free(unsafe.Pointer(cVals)) + + if err := resultError(C.ghostty_kitty_graphics_placement_get_multi( it.ptr, - C.GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO, - unsafe.Pointer(&ci), + C.size_t(len(keys)), + &keys[0], + cVals, + nil, )); err != nil { return nil, err } return &KittyGraphicsPlacementInfo{ - ImageID: uint32(ci.image_id), - PlacementID: uint32(ci.placement_id), - IsVirtual: bool(ci.is_virtual), - XOffset: uint32(ci.x_offset), - YOffset: uint32(ci.y_offset), - SourceX: uint32(ci.source_x), - SourceY: uint32(ci.source_y), - SourceWidth: uint32(ci.source_width), - SourceHeight: uint32(ci.source_height), - Columns: uint32(ci.columns), - Rows: uint32(ci.rows), - Z: int32(ci.z), + ImageID: uint32(imageID), + PlacementID: uint32(placementID), + IsVirtual: bool(isVirtual), + XOffset: uint32(xOffset), + YOffset: uint32(yOffset), + SourceX: uint32(sourceX), + SourceY: uint32(sourceY), + SourceWidth: uint32(sourceWidth), + SourceHeight: uint32(sourceHeight), + Columns: uint32(columns), + Rows: uint32(rows), + Z: int32(z), }, nil } diff --git a/render_state_cell.go b/render_state_cell.go index 5b22c1a..f399201 100644 --- a/render_state_cell.go +++ b/render_state_cell.go @@ -4,6 +4,7 @@ package libghostty // GhosttyRenderStateRowCells C APIs. /* +#include #include */ import "C" @@ -13,6 +14,39 @@ import ( "unsafe" ) +// RenderStateRowCellsData identifies a data field for render state cell +// queries. +// C: GhosttyRenderStateRowCellsData +type RenderStateRowCellsData int + +const ( + // RenderStateRowCellsDataInvalid is an invalid / sentinel value. + RenderStateRowCellsDataInvalid RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_INVALID + + // RenderStateRowCellsDataRaw is the raw cell value (GhosttyCell). + RenderStateRowCellsDataRaw RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_RAW + + // RenderStateRowCellsDataStyle is the style for the current cell + // (GhosttyStyle). + RenderStateRowCellsDataStyle RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_STYLE + + // RenderStateRowCellsDataGraphemesLen is the total number of grapheme + // codepoints including the base codepoint (uint32_t). + RenderStateRowCellsDataGraphemesLen RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN + + // RenderStateRowCellsDataGraphemesBuf writes grapheme codepoints into + // a caller-provided buffer (uint32_t*). + RenderStateRowCellsDataGraphemesBuf RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF + + // RenderStateRowCellsDataBgColor is the resolved background color of + // the cell (GhosttyColorRgb). + RenderStateRowCellsDataBgColor RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_BG_COLOR + + // RenderStateRowCellsDataFgColor is the resolved foreground color of + // the cell (GhosttyColorRgb). + RenderStateRowCellsDataFgColor RenderStateRowCellsData = C.GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_FG_COLOR +) + // RenderStateRowCells iterates over cells in a render-state row. // Create one with NewRenderStateRowCells, populate it via // RenderStateRowIterator.Cells, then advance with Next (or jump @@ -56,6 +90,46 @@ func (rc *RenderStateRowCells) Select(x uint16) error { return resultError(C.ghostty_render_state_row_cells_select(rc.ptr, C.uint16_t(x))) } +// GetMulti queries multiple render-state cell data fields in a single +// cgo call. This is a low-level function; prefer the typed getters +// (Raw, Style, Graphemes, BgColor, FgColor) for normal use. GetMulti +// is useful when you need many fields at once and want to avoid +// per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/render.h, GhosttyRenderStateRowCellsData enum). +// +// Example: +// +// var raw C.GhosttyCell +// var graphemesLen C.uint32_t +// err := rc.GetMulti( +// []RenderStateRowCellsData{RenderStateRowCellsDataRaw, RenderStateRowCellsDataGraphemesLen}, +// []unsafe.Pointer{unsafe.Pointer(&raw), unsafe.Pointer(&graphemesLen)}, +// ) +// +// C: ghostty_render_state_row_cells_get_multi +func (rc *RenderStateRowCells) GetMulti(keys []RenderStateRowCellsData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_render_state_row_cells_get_multi( + rc.ptr, + C.size_t(len(keys)), + (*C.GhosttyRenderStateRowCellsData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // Raw returns the raw Cell value for the current iterator position. // The returned Cell can be used with the same getter methods as cells // obtained from GridRef. diff --git a/render_state_data.go b/render_state_data.go index 737b2ec..4baa320 100644 --- a/render_state_data.go +++ b/render_state_data.go @@ -5,6 +5,7 @@ package libghostty // Functions are ordered alphabetically. /* +#include #include // Helper to create a properly initialized GhosttyRenderStateColors (sized struct). @@ -20,6 +21,81 @@ import ( "unsafe" ) +// RenderStateData identifies a data field for render state queries. +// C: GhosttyRenderStateData +type RenderStateData int + +const ( + // RenderStateDataInvalid is an invalid / sentinel value. + RenderStateDataInvalid RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_INVALID + + // RenderStateDataCols is the viewport width in cells (uint16_t). + RenderStateDataCols RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLS + + // RenderStateDataRows is the viewport height in cells (uint16_t). + RenderStateDataRows RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_ROWS + + // RenderStateDataDirty is the current dirty state + // (GhosttyRenderStateDirty). + RenderStateDataDirty RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_DIRTY + + // RenderStateDataRowIterator populates a pre-allocated row iterator + // (GhosttyRenderStateRowIterator). + RenderStateDataRowIterator RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR + + // RenderStateDataColorBackground is the default/current background + // color (GhosttyColorRgb). + RenderStateDataColorBackground RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLOR_BACKGROUND + + // RenderStateDataColorForeground is the default/current foreground + // color (GhosttyColorRgb). + RenderStateDataColorForeground RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLOR_FOREGROUND + + // RenderStateDataColorCursor is the cursor color when explicitly set + // (GhosttyColorRgb). + RenderStateDataColorCursor RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR + + // RenderStateDataColorCursorHasValue indicates whether an explicit + // cursor color is set (bool). + RenderStateDataColorCursorHasValue RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR_HAS_VALUE + + // RenderStateDataColorPalette is the active 256-color palette + // (GhosttyColorRgb[256]). + RenderStateDataColorPalette RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLOR_PALETTE + + // RenderStateDataCursorVisualStyle is the visual style of the cursor + // (GhosttyRenderStateCursorVisualStyle). + RenderStateDataCursorVisualStyle RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE + + // RenderStateDataCursorVisible indicates whether the cursor is visible + // based on terminal modes (bool). + RenderStateDataCursorVisible RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE + + // RenderStateDataCursorBlinking indicates whether the cursor should + // blink based on terminal modes (bool). + RenderStateDataCursorBlinking RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING + + // RenderStateDataCursorPasswordInput indicates whether the cursor is + // at a password input field (bool). + RenderStateDataCursorPasswordInput RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_PASSWORD_INPUT + + // RenderStateDataCursorViewportHasValue indicates whether the cursor + // is visible within the viewport (bool). + RenderStateDataCursorViewportHasValue RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE + + // RenderStateDataCursorViewportX is the cursor viewport x position + // in cells (uint16_t). + RenderStateDataCursorViewportX RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X + + // RenderStateDataCursorViewportY is the cursor viewport y position + // in cells (uint16_t). + RenderStateDataCursorViewportY RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y + + // RenderStateDataCursorViewportWideTail indicates whether the cursor + // is on the tail of a wide character (bool). + RenderStateDataCursorViewportWideTail RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_WIDE_TAIL +) + // Cols returns the viewport width in cells. func (rs *RenderState) Cols() (uint16, error) { var v C.uint16_t @@ -106,6 +182,44 @@ func (rs *RenderState) Colors() (*RenderStateColors, error) { return result, nil } +// GetMulti queries multiple render state data fields in a single cgo +// call. This is a low-level function; prefer the typed getters (Cols, +// Rows, CursorVisible, etc.) for normal use. GetMulti is useful when +// you need many fields at once and want to avoid per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/render.h, GhosttyRenderStateData enum). +// +// Example: +// +// var cols, rows C.uint16_t +// err := rs.GetMulti( +// []RenderStateData{RenderStateDataCols, RenderStateDataRows}, +// []unsafe.Pointer{unsafe.Pointer(&cols), unsafe.Pointer(&rows)}, +// ) +// +// C: ghostty_render_state_get_multi +func (rs *RenderState) GetMulti(keys []RenderStateData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_render_state_get_multi( + rs.ptr, + C.size_t(len(keys)), + (*C.GhosttyRenderStateData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // CursorBlinking reports whether the cursor should blink based on // terminal modes. func (rs *RenderState) CursorBlinking() (bool, error) { diff --git a/render_state_row.go b/render_state_row.go index d4caa18..261643c 100644 --- a/render_state_row.go +++ b/render_state_row.go @@ -4,11 +4,35 @@ package libghostty // GhosttyRenderStateRowIterator C APIs. /* +#include #include */ import "C" -import "unsafe" +import ( + "errors" + "unsafe" +) + +// RenderStateRowData identifies a data field for render state row queries. +// C: GhosttyRenderStateRowData +type RenderStateRowData int + +const ( + // RenderStateRowDataInvalid is an invalid / sentinel value. + RenderStateRowDataInvalid RenderStateRowData = C.GHOSTTY_RENDER_STATE_ROW_DATA_INVALID + + // RenderStateRowDataDirty indicates whether the current row is dirty + // (bool). + RenderStateRowDataDirty RenderStateRowData = C.GHOSTTY_RENDER_STATE_ROW_DATA_DIRTY + + // RenderStateRowDataRaw is the raw row value (GhosttyRow). + RenderStateRowDataRaw RenderStateRowData = C.GHOSTTY_RENDER_STATE_ROW_DATA_RAW + + // RenderStateRowDataCells populates a pre-allocated row cells instance + // (GhosttyRenderStateRowCells). + RenderStateRowDataCells RenderStateRowData = C.GHOSTTY_RENDER_STATE_ROW_DATA_CELLS +) // RenderStateRowIterator iterates over rows in a render state. // Create one with NewRenderStateRowIterator, populate it via @@ -47,6 +71,45 @@ func (ri *RenderStateRowIterator) Next() bool { return bool(C.ghostty_render_state_row_iterator_next(ri.ptr)) } +// GetMulti queries multiple render-state row data fields in a single +// cgo call. This is a low-level function; prefer the typed getters +// (Dirty, Raw, Cells) for normal use. GetMulti is useful when you +// need many fields at once and want to avoid per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/render.h, GhosttyRenderStateRowData enum). +// +// Example: +// +// var dirty C.bool +// var raw C.GhosttyRow +// err := ri.GetMulti( +// []RenderStateRowData{RenderStateRowDataDirty, RenderStateRowDataRaw}, +// []unsafe.Pointer{unsafe.Pointer(&dirty), unsafe.Pointer(&raw)}, +// ) +// +// C: ghostty_render_state_row_get_multi +func (ri *RenderStateRowIterator) GetMulti(keys []RenderStateRowData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_render_state_row_get_multi( + ri.ptr, + C.size_t(len(keys)), + (*C.GhosttyRenderStateRowData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // Dirty reports whether the current row is dirty and requires a // redraw. func (ri *RenderStateRowIterator) Dirty() (bool, error) { diff --git a/screen.go b/screen.go index c47dd33..ee7f188 100644 --- a/screen.go +++ b/screen.go @@ -1,11 +1,103 @@ package libghostty /* +#include #include */ import "C" -import "unsafe" +import ( + "errors" + "unsafe" +) + +// CellData identifies a data field for cell queries. +// C: GhosttyCellData +type CellData int + +const ( + // CellDataInvalid is an invalid data type. + CellDataInvalid CellData = C.GHOSTTY_CELL_DATA_INVALID + + // CellDataCodepoint is the codepoint of the cell (uint32_t). + CellDataCodepoint CellData = C.GHOSTTY_CELL_DATA_CODEPOINT + + // CellDataContentTag is the content tag describing what kind of + // content is in the cell (GhosttyCellContentTag). + CellDataContentTag CellData = C.GHOSTTY_CELL_DATA_CONTENT_TAG + + // CellDataWide is the wide property of the cell (GhosttyCellWide). + CellDataWide CellData = C.GHOSTTY_CELL_DATA_WIDE + + // CellDataHasText indicates whether the cell has text to render (bool). + CellDataHasText CellData = C.GHOSTTY_CELL_DATA_HAS_TEXT + + // CellDataHasStyling indicates whether the cell has non-default + // styling (bool). + CellDataHasStyling CellData = C.GHOSTTY_CELL_DATA_HAS_STYLING + + // CellDataStyleID is the style ID for the cell (uint16_t). + CellDataStyleID CellData = C.GHOSTTY_CELL_DATA_STYLE_ID + + // CellDataHasHyperlink indicates whether the cell has a hyperlink + // (bool). + CellDataHasHyperlink CellData = C.GHOSTTY_CELL_DATA_HAS_HYPERLINK + + // CellDataProtected indicates whether the cell is protected (bool). + CellDataProtected CellData = C.GHOSTTY_CELL_DATA_PROTECTED + + // CellDataSemanticContent is the semantic content type of the cell + // (GhosttyCellSemanticContent). + CellDataSemanticContent CellData = C.GHOSTTY_CELL_DATA_SEMANTIC_CONTENT + + // CellDataColorPalette is the palette index for the cell's background + // color (GhosttyColorPaletteIndex). + CellDataColorPalette CellData = C.GHOSTTY_CELL_DATA_COLOR_PALETTE + + // CellDataColorRGBValue is the RGB value for the cell's background + // color (GhosttyColorRgb). + CellDataColorRGBValue CellData = C.GHOSTTY_CELL_DATA_COLOR_RGB +) + +// RowData identifies a data field for row queries. +// C: GhosttyRowData +type RowData int + +const ( + // RowDataInvalid is an invalid data type. + RowDataInvalid RowData = C.GHOSTTY_ROW_DATA_INVALID + + // RowDataWrap indicates whether the row is soft-wrapped (bool). + RowDataWrap RowData = C.GHOSTTY_ROW_DATA_WRAP + + // RowDataWrapContinuation indicates whether the row is a continuation + // of a soft-wrapped row (bool). + RowDataWrapContinuation RowData = C.GHOSTTY_ROW_DATA_WRAP_CONTINUATION + + // RowDataGrapheme indicates whether any cells in the row have grapheme + // clusters (bool). + RowDataGrapheme RowData = C.GHOSTTY_ROW_DATA_GRAPHEME + + // RowDataStyled indicates whether any cells in the row have styling + // (bool). + RowDataStyled RowData = C.GHOSTTY_ROW_DATA_STYLED + + // RowDataHyperlink indicates whether any cells in the row have + // hyperlinks (bool). + RowDataHyperlink RowData = C.GHOSTTY_ROW_DATA_HYPERLINK + + // RowDataSemanticPrompt is the semantic prompt state of the row + // (GhosttyRowSemanticPrompt). + RowDataSemanticPrompt RowData = C.GHOSTTY_ROW_DATA_SEMANTIC_PROMPT + + // RowDataKittyVirtualPlaceholder indicates whether the row contains + // a Kitty virtual placeholder (bool). + RowDataKittyVirtualPlaceholder RowData = C.GHOSTTY_ROW_DATA_KITTY_VIRTUAL_PLACEHOLDER + + // RowDataDirty indicates whether the row is dirty and requires a + // redraw (bool). + RowDataDirty RowData = C.GHOSTTY_ROW_DATA_DIRTY +) // Cell is a wrapper around an opaque terminal grid cell value. // Use getter methods to extract data from it. @@ -93,6 +185,45 @@ const ( RowSemanticPromptContinuation RowSemanticPrompt = C.GHOSTTY_ROW_SEMANTIC_PROMPT_CONTINUATION ) +// GetMulti queries multiple cell data fields in a single cgo call. +// This is a low-level function; prefer the typed getters (Codepoint, +// Wide, HasText, etc.) for normal use. GetMulti is useful when you +// need many fields at once and want to avoid per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/screen.h, GhosttyCellData enum). +// +// Example: +// +// var cp C.uint32_t +// var wide C.GhosttyCellWide +// err := cell.GetMulti( +// []CellData{CellDataCodepoint, CellDataWide}, +// []unsafe.Pointer{unsafe.Pointer(&cp), unsafe.Pointer(&wide)}, +// ) +// +// C: ghostty_cell_get_multi +func (c *Cell) GetMulti(keys []CellData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_cell_get_multi( + c.c, + C.size_t(len(keys)), + (*C.GhosttyCellData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // Codepoint returns the codepoint of the cell (0 if empty). func (c *Cell) Codepoint() (uint32, error) { var v C.uint32_t @@ -195,6 +326,45 @@ func (c *Cell) ColorRGB() (ColorRGB, error) { return ColorRGB{R: uint8(v.r), G: uint8(v.g), B: uint8(v.b)}, nil } +// GetMulti queries multiple row data fields in a single cgo call. +// This is a low-level function; prefer the typed getters (Wrap, +// Grapheme, Styled, Semantic, etc.) for normal use. GetMulti is +// useful when you need many fields at once and want to avoid +// per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/screen.h, GhosttyRowData enum). +// +// Example: +// +// var wrap, styled C.bool +// err := row.GetMulti( +// []RowData{RowDataWrap, RowDataStyled}, +// []unsafe.Pointer{unsafe.Pointer(&wrap), unsafe.Pointer(&styled)}, +// ) +// +// C: ghostty_row_get_multi +func (r *Row) GetMulti(keys []RowData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_row_get_multi( + r.c, + C.size_t(len(keys)), + (*C.GhosttyRowData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // Wrap reports whether the row is soft-wrapped. func (r *Row) Wrap() (bool, error) { var v C.bool diff --git a/terminal_data.go b/terminal_data.go index a72771c..11b54d3 100644 --- a/terminal_data.go +++ b/terminal_data.go @@ -4,6 +4,7 @@ package libghostty // Functions are ordered alphabetically. /* +#include #include */ import "C" @@ -13,6 +14,129 @@ import ( "unsafe" ) +// TerminalData identifies a data field for terminal queries. +// C: GhosttyTerminalData +type TerminalData int + +const ( + // TerminalDataInvalid is an invalid / sentinel value. + TerminalDataInvalid TerminalData = C.GHOSTTY_TERMINAL_DATA_INVALID + + // TerminalDataCols is the terminal width in cells (uint16_t). + TerminalDataCols TerminalData = C.GHOSTTY_TERMINAL_DATA_COLS + + // TerminalDataRows is the terminal height in cells (uint16_t). + TerminalDataRows TerminalData = C.GHOSTTY_TERMINAL_DATA_ROWS + + // TerminalDataCursorX is the cursor column position, 0-indexed (uint16_t). + TerminalDataCursorX TerminalData = C.GHOSTTY_TERMINAL_DATA_CURSOR_X + + // TerminalDataCursorY is the cursor row position within the active area, + // 0-indexed (uint16_t). + TerminalDataCursorY TerminalData = C.GHOSTTY_TERMINAL_DATA_CURSOR_Y + + // TerminalDataCursorPendingWrap indicates whether the cursor has a + // pending wrap (bool). + TerminalDataCursorPendingWrap TerminalData = C.GHOSTTY_TERMINAL_DATA_CURSOR_PENDING_WRAP + + // TerminalDataActiveScreen is the currently active screen + // (GhosttyTerminalScreen). + TerminalDataActiveScreen TerminalData = C.GHOSTTY_TERMINAL_DATA_ACTIVE_SCREEN + + // TerminalDataCursorVisible indicates whether the cursor is visible, + // DEC mode 25 (bool). + TerminalDataCursorVisible TerminalData = C.GHOSTTY_TERMINAL_DATA_CURSOR_VISIBLE + + // TerminalDataKittyKeyboardFlags is the current Kitty keyboard protocol + // flags (uint8_t). + TerminalDataKittyKeyboardFlags TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_KEYBOARD_FLAGS + + // TerminalDataScrollbar is the scrollbar state for the terminal viewport + // (GhosttyTerminalScrollbar). + TerminalDataScrollbar TerminalData = C.GHOSTTY_TERMINAL_DATA_SCROLLBAR + + // TerminalDataCursorStyle is the current SGR style of the cursor + // (GhosttyStyle). + TerminalDataCursorStyle TerminalData = C.GHOSTTY_TERMINAL_DATA_CURSOR_STYLE + + // TerminalDataMouseTracking indicates whether any mouse tracking mode + // is active (bool). + TerminalDataMouseTracking TerminalData = C.GHOSTTY_TERMINAL_DATA_MOUSE_TRACKING + + // TerminalDataTitle is the terminal title as set by escape sequences + // (GhosttyString). + TerminalDataTitle TerminalData = C.GHOSTTY_TERMINAL_DATA_TITLE + + // TerminalDataPwd is the terminal's current working directory as set + // by escape sequences (GhosttyString). + TerminalDataPwd TerminalData = C.GHOSTTY_TERMINAL_DATA_PWD + + // TerminalDataTotalRows is the total number of rows in the active screen + // including scrollback (size_t). + TerminalDataTotalRows TerminalData = C.GHOSTTY_TERMINAL_DATA_TOTAL_ROWS + + // TerminalDataScrollbackRows is the number of scrollback rows (size_t). + TerminalDataScrollbackRows TerminalData = C.GHOSTTY_TERMINAL_DATA_SCROLLBACK_ROWS + + // TerminalDataWidthPx is the total terminal width in pixels (uint32_t). + TerminalDataWidthPx TerminalData = C.GHOSTTY_TERMINAL_DATA_WIDTH_PX + + // TerminalDataHeightPx is the total terminal height in pixels (uint32_t). + TerminalDataHeightPx TerminalData = C.GHOSTTY_TERMINAL_DATA_HEIGHT_PX + + // TerminalDataColorForeground is the effective foreground color + // (GhosttyColorRgb). + TerminalDataColorForeground TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND + + // TerminalDataColorBackground is the effective background color + // (GhosttyColorRgb). + TerminalDataColorBackground TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND + + // TerminalDataColorCursor is the effective cursor color + // (GhosttyColorRgb). + TerminalDataColorCursor TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_CURSOR + + // TerminalDataColorPalette is the current 256-color palette + // (GhosttyColorRgb[256]). + TerminalDataColorPalette TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_PALETTE + + // TerminalDataColorForegroundDefault is the default foreground color, + // ignoring OSC overrides (GhosttyColorRgb). + TerminalDataColorForegroundDefault TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND_DEFAULT + + // TerminalDataColorBackgroundDefault is the default background color, + // ignoring OSC overrides (GhosttyColorRgb). + TerminalDataColorBackgroundDefault TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND_DEFAULT + + // TerminalDataColorCursorDefault is the default cursor color, + // ignoring OSC overrides (GhosttyColorRgb). + TerminalDataColorCursorDefault TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_CURSOR_DEFAULT + + // TerminalDataColorPaletteDefault is the default 256-color palette, + // ignoring OSC overrides (GhosttyColorRgb[256]). + TerminalDataColorPaletteDefault TerminalData = C.GHOSTTY_TERMINAL_DATA_COLOR_PALETTE_DEFAULT + + // TerminalDataKittyImageStorageLimit is the Kitty image storage limit + // in bytes for the active screen (uint64_t). + TerminalDataKittyImageStorageLimit TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_STORAGE_LIMIT + + // TerminalDataKittyImageMediumFile indicates whether the file medium + // is enabled for Kitty image loading (bool). + TerminalDataKittyImageMediumFile TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_FILE + + // TerminalDataKittyImageMediumTempFile indicates whether the temporary + // file medium is enabled for Kitty image loading (bool). + TerminalDataKittyImageMediumTempFile TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_TEMP_FILE + + // TerminalDataKittyImageMediumSharedMem indicates whether the shared + // memory medium is enabled for Kitty image loading (bool). + TerminalDataKittyImageMediumSharedMem TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_SHARED_MEM + + // TerminalDataKittyGraphics is the Kitty graphics image storage for + // the active screen (GhosttyKittyGraphics). + TerminalDataKittyGraphics TerminalData = C.GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS +) + // ActiveScreen returns which screen buffer is currently active. func (t *Terminal) ActiveScreen() (TerminalScreen, error) { var v C.GhosttyTerminalScreen @@ -79,6 +203,44 @@ func (t *Terminal) ColorPaletteDefault() (*Palette, error) { return t.getPalette(C.GHOSTTY_TERMINAL_DATA_COLOR_PALETTE_DEFAULT) } +// GetMulti queries multiple terminal data fields in a single cgo call. +// This is a low-level function; prefer the typed getters (Cols, Rows, +// CursorX, etc.) for normal use. GetMulti is useful when you need many +// fields at once and want to avoid per-field cgo overhead. +// +// Each element in keys specifies a data kind, and the corresponding +// element in values must be an unsafe.Pointer to a variable whose type +// matches the "Output type" documented for that key in the upstream C +// header (ghostty/vt/terminal.h, GhosttyTerminalData enum). +// +// Example: +// +// var cols, rows C.uint16_t +// err := t.GetMulti( +// []TerminalData{TerminalDataCols, TerminalDataRows}, +// []unsafe.Pointer{unsafe.Pointer(&cols), unsafe.Pointer(&rows)}, +// ) +// +// C: ghostty_terminal_get_multi +func (t *Terminal) GetMulti(keys []TerminalData, values []unsafe.Pointer) error { + if len(keys) != len(values) { + return errors.New("libghostty: keys and values must have the same length") + } + if len(keys) == 0 { + return nil + } + // Allocate the void** array in C memory to satisfy cgo pointer-passing rules. + cVals := cValuesArray(values) + defer C.free(unsafe.Pointer(cVals)) + return resultError(C.ghostty_terminal_get_multi( + t.ptr, + C.size_t(len(keys)), + (*C.GhosttyTerminalData)(unsafe.Pointer(&keys[0])), + cVals, + nil, + )) +} + // CursorPendingWrap reports whether the cursor has a pending wrap // (the next printed character will soft-wrap to the next line). func (t *Terminal) CursorPendingWrap() (bool, error) { -- 2.51.2