Something went wrong. Try again.
Go bindings for libghostty-vt. pkg.go.dev/go.mitchellh.com/libghostty
ghostty
Something went wrong. Try again.
go-libghostty render_state_data.go
21 kB · 527 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528package libghostty
// Render state data getters and setters wrapping// ghostty_render_state_get() and ghostty_render_state_set().// Functions are ordered alphabetically.
/*#include <ghostty/vt.h>
// Helper to create a properly initialized GhosttyRenderStateCursor (sized struct).static inline GhosttyRenderStateCursor init_render_state_cursor() { GhosttyRenderStateCursor c = GHOSTTY_INIT_SIZED(GhosttyRenderStateCursor); return c;}
// Helper to create a properly initialized GhosttyRenderStateColors (sized struct).static inline GhosttyRenderStateColors init_render_state_colors() { GhosttyRenderStateColors c = GHOSTTY_INIT_SIZED(GhosttyRenderStateColors); return c;}
// render_state_u64 is a uint64_t value read from a render state, with the// result of reading it.typedef struct { GhosttyResult result; uint64_t value;} render_state_u64;
// render_state_get_u64 reads a uint64_t value from a render state and// returns it by value. Go code could pass C a pointer to a local variable// instead, but cgo would then move that variable to the heap, which costs// an allocation on every call. Renderers read these values every frame, so// the value stays on the C stack instead.static inline render_state_u64 render_state_get_u64( GhosttyRenderState state, GhosttyRenderStateData data) { render_state_u64 out = {0}; out.result = ghostty_render_state_get(state, data, &out.value); return out;}*/import "C"
import ( "errors" "unsafe")
// RenderStateData identifies a data field for render state queries.// C: GhosttyRenderStateDatatype 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, excluding overscan (uint16_t). RenderStateDataRows RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_ROWS
// RenderStateDataOverscan is the number of extra rows captured by the last update // (GhosttyRenderStateOverscan). RenderStateDataOverscan RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_OVERSCAN
// RenderStateDataOverscanRequest is the request used for the next update // (GhosttyRenderStateOverscan). RenderStateDataOverscanRequest RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_OVERSCAN_REQUEST
// 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
// RenderStateDataImageIterator fills an existing image iterator with // the image placements from the last update // (GhosttyRenderStateImageIterator). RenderStateDataImageIterator RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_IMAGE_ITERATOR
// RenderStateDataImagePlacementsGeneration changes whenever an update // changes the images listed by [RenderStateDataImageIterator] // (uint64_t). See [RenderState.ImagePlacementsGeneration]. RenderStateDataImagePlacementsGeneration RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_IMAGE_PLACEMENTS_GENERATION
// 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
// RenderStateDataCursor is all cursor state in one sized struct // (GhosttyRenderStateCursor). RenderStateDataCursor RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_CURSOR
// RenderStateDataColors is all render-state colors in one sized struct // (GhosttyRenderStateColors). RenderStateDataColors RenderStateData = C.GHOSTTY_RENDER_STATE_DATA_COLORS)
// Cols returns the viewport width in cells.func (rs *RenderState) Cols() (uint16, error) { var v C.uint16_t if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLS, unsafe.Pointer(&v))); err != nil { return 0, err } return uint16(v), nil}
// ColorBackground returns the default/current background color.func (rs *RenderState) ColorBackground() (ColorRGB, error) { var v C.GhosttyColorRgb if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLOR_BACKGROUND, unsafe.Pointer(&v))); err != nil { return ColorRGB{}, err } return ColorRGB{R: uint8(v.r), G: uint8(v.g), B: uint8(v.b)}, nil}
// ColorCursor returns the cursor color when explicitly set by terminal// state. Returns nil (without error) when no explicit cursor color is set.func (rs *RenderState) ColorCursor() (*ColorRGB, error) { // Check whether a cursor color is set first. var has C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR_HAS_VALUE, unsafe.Pointer(&has))); err != nil { return nil, err } if !bool(has) { return nil, nil }
var v C.GhosttyColorRgb err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLOR_CURSOR, unsafe.Pointer(&v))) if err != nil { var ge *Error if errors.As(err, &ge) && ge.Result == ResultInvalidValue { return nil, nil } return nil, err } c := ColorRGB{R: uint8(v.r), G: uint8(v.g), B: uint8(v.b)} return &c, nil}
// ColorForeground returns the default/current foreground color.func (rs *RenderState) ColorForeground() (ColorRGB, error) { var v C.GhosttyColorRgb if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLOR_FOREGROUND, unsafe.Pointer(&v))); err != nil { return ColorRGB{}, err } return ColorRGB{R: uint8(v.r), G: uint8(v.g), B: uint8(v.b)}, nil}
// ColorPalette returns the active 256-color palette.func (rs *RenderState) ColorPalette() (*Palette, error) { var cp [PaletteSize]C.GhosttyColorRgb if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLOR_PALETTE, unsafe.Pointer(&cp[0]))); err != nil { return nil, err } var p Palette for i, c := range cp { p[i] = ColorRGB{R: uint8(c.r), G: uint8(c.g), B: uint8(c.b)} } return &p, nil}
// Colors returns all color information from the render state in a// single call using the sized-struct API.func (rs *RenderState) Colors() (*RenderStateColors, error) { cc := C.init_render_state_colors() if err := resultError(C.ghostty_render_state_get( rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_COLORS, unsafe.Pointer(&cc), )); err != nil { return nil, err }
result := &RenderStateColors{ Background: ColorRGB{R: uint8(cc.background.r), G: uint8(cc.background.g), B: uint8(cc.background.b)}, Foreground: ColorRGB{R: uint8(cc.foreground.r), G: uint8(cc.foreground.g), B: uint8(cc.foreground.b)}, Cursor: ColorRGB{R: uint8(cc.cursor.r), G: uint8(cc.cursor.g), B: uint8(cc.cursor.b)}, CursorHasValue: bool(cc.cursor_has_value), }
for i, c := range cc.palette { result.Palette[i] = ColorRGB{R: uint8(c.r), G: uint8(c.g), B: uint8(c.b)} } return result, nil}
// Cursor returns all cursor information from the render state in one call.// This is the preferred cursor read for render loops because it avoids the// separate cgo transition required by each scalar cursor getter.func (rs *RenderState) Cursor() (*RenderStateCursor, error) { cc := C.init_render_state_cursor() if err := resultError(C.ghostty_render_state_get( rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR, unsafe.Pointer(&cc), )); err != nil { return nil, err }
return &RenderStateCursor{ ViewportHasValue: bool(cc.viewport_has_value), ViewportX: uint16(cc.viewport_x), ViewportY: uint16(cc.viewport_y), WideTail: bool(cc.wide_tail), Visible: bool(cc.visible), Blinking: bool(cc.blinking), PasswordInput: bool(cc.password_input), VisualStyle: CursorVisualStyle(cc.visual_style), }, 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).// Use a Go type with the same size as the C type, such as uint32// for uint32_t, bool for bool, and int32 for an enum.//// GetMulti returns an error if keys and values have different lengths// or if a key cannot be read. In the second case, values for the keys// before it may already have been written.//// Example://// var cols, rows uint16// err := rs.GetMulti(// []RenderStateData{RenderStateDataCols, RenderStateDataRows},// []unsafe.Pointer{unsafe.Pointer(&cols), unsafe.Pointer(&rows)},// )//// C: ghostty_render_state_get_multifunc (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 } // Copy the keys and output pointers into C memory. See get_multi.go. var args getMultiArgs cKeys, err := allocWithKeys[C.GhosttyRenderStateData](&args, keys, values) if err != nil { return err } defer args.free() return resultError(C.ghostty_render_state_get_multi( rs.ptr, C.size_t(len(keys)), cKeys, args.values, nil, ))}
// CursorBlinking reports whether the cursor should blink based on// terminal modes.func (rs *RenderState) CursorBlinking() (bool, error) { var v C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_BLINKING, unsafe.Pointer(&v))); err != nil { return false, err } return bool(v), nil}
// CursorPasswordInput reports whether the cursor is at a password// input field.func (rs *RenderState) CursorPasswordInput() (bool, error) { var v C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_PASSWORD_INPUT, unsafe.Pointer(&v))); err != nil { return false, err } return bool(v), nil}
// CursorVisible reports whether the cursor is visible based on// terminal modes.func (rs *RenderState) CursorVisible() (bool, error) { var v C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE, unsafe.Pointer(&v))); err != nil { return false, err } return bool(v), nil}
// CursorVisualStyle returns the visual style of the cursor.func (rs *RenderState) CursorVisualStyle() (CursorVisualStyle, error) { var v C.GhosttyRenderStateCursorVisualStyle if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE, unsafe.Pointer(&v))); err != nil { return 0, err } return CursorVisualStyle(v), nil}
// CursorViewportHasValue reports whether the cursor is visible within// the viewport. If false, the cursor viewport position values are// undefined.func (rs *RenderState) CursorViewportHasValue() (bool, error) { var v C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE, unsafe.Pointer(&v))); err != nil { return false, err } return bool(v), nil}
// CursorViewportWideTail reports whether the cursor is on the tail// of a wide character. Only valid when CursorViewportHasValue// returns true.func (rs *RenderState) CursorViewportWideTail() (bool, error) { var v C.bool if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_WIDE_TAIL, unsafe.Pointer(&v))); err != nil { return false, err } return bool(v), nil}
// CursorViewportX returns the cursor viewport x position in cells.// Only valid when CursorViewportHasValue returns true.func (rs *RenderState) CursorViewportX() (uint16, error) { var v C.uint16_t if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X, unsafe.Pointer(&v))); err != nil { return 0, err } return uint16(v), nil}
// CursorViewportY returns the cursor viewport y position in cells.// Only valid when CursorViewportHasValue returns true.func (rs *RenderState) CursorViewportY() (uint16, error) { var v C.uint16_t if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y, unsafe.Pointer(&v))); err != nil { return 0, err } return uint16(v), nil}
// Dirty returns the current dirty state.func (rs *RenderState) Dirty() (RenderStateDirty, error) { var v C.GhosttyRenderStateDirty if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_DIRTY, unsafe.Pointer(&v))); err != nil { return 0, err } return RenderStateDirty(v), nil}
// ImageIterator fills iter with the images to draw from the last update.// Call [RenderStateImageIterator.Next] to move to the first image before// reading any values.//// The values in iter stay valid until the next call to [RenderState.Update].// After each update, call ImageIterator again before reading iter. The// same iterator can be reused each time. To skip reading the list on// frames where no image changed, use [RenderState.ImagePlacementsGeneration].func (rs *RenderState) ImageIterator(iter *RenderStateImageIterator) error { return resultError(C.ghostty_render_state_get( rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_IMAGE_ITERATOR, unsafe.Pointer(&iter.ptr), ))}
// ImagePlacementsGeneration returns a value that changes whenever an// update changes the images listed by [RenderState.ImageIterator].//// Most frames don't change any image. A renderer can save this value each// time it reads the image list, then skip reading the list on later// frames while the value stays the same. See the example.//// The value changes when an update adds, removes, or moves an image,// changes which part of an image is shown, or changes an image's pixels.// It stays the same when only text changes, unless the rows that changed// held Kitty placeholder cells before or after the change.//// A new value means the list may have changed, not that it did. For// example, the value also changes when a program rewrites a row that holds// placeholder cells, or changes any image while images shown with// placeholder cells are on screen, even if every image stays where it was.//// Compare values only for equality, and only with values from the same// render state. The value wraps around, so a larger value is not// necessarily a newer one. It is always 0 when Kitty graphics are// disabled.//// The value describes the list as a whole. To know when the pixels of one// image changed, use [RenderStateImageInfo.ImageGeneration].//// ImagePlacementsGeneration doesn't allocate, so it is cheap to call// every frame.//// C: GHOSTTY_RENDER_STATE_DATA_IMAGE_PLACEMENTS_GENERATIONfunc (rs *RenderState) ImagePlacementsGeneration() (uint64, error) { v := C.render_state_get_u64(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_IMAGE_PLACEMENTS_GENERATION) if err := resultError(v.result); err != nil { return 0, err } return uint64(v.value), nil}
// RowIterator initializes ri to iterate over the rows from the last update.// Advance it with [RenderStateRowIterator.Next] before reading row data.// Rows are ordered from top to bottom and include any overscan rows. Use// [RenderStateRowIterator.ViewportY] to position each row in the viewport.//// The iterator can be reused by calling RowIterator again. Its data is valid// only until the next call to [RenderState.Update].func (rs *RenderState) RowIterator(ri *RenderStateRowIterator) error { return resultError(C.ghostty_render_state_get( rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR, unsafe.Pointer(&ri.ptr), ))}
// Rows returns the viewport height in cells, excluding overscan.func (rs *RenderState) Rows() (uint16, error) { var v C.uint16_t if err := resultError(C.ghostty_render_state_get(rs.ptr, C.GHOSTTY_RENDER_STATE_DATA_ROWS, unsafe.Pointer(&v))); err != nil { return 0, err } return uint16(v), nil}
// SetDirty sets the dirty state.func (rs *RenderState) SetDirty(dirty RenderStateDirty) error { v := C.GhosttyRenderStateDirty(dirty) return resultError(C.ghostty_render_state_set(rs.ptr, C.GHOSTTY_RENDER_STATE_OPTION_DIRTY, unsafe.Pointer(&v)))}
// SetOverscan sets the number of extra rows to capture above and below the// viewport on subsequent updates. The request remains in effect until changed.// A zero [RenderStateOverscan] captures only the visible viewport.//// Changing the request leaves the current row data valid. The next update// applies the request and marks the entire render state as dirty. Use// [RenderState.Overscan] after that update to find how many rows were available.//// C: GHOSTTY_RENDER_STATE_OPTION_OVERSCANfunc (rs *RenderState) SetOverscan(request RenderStateOverscan) error { v := C.GhosttyRenderStateOverscan{above: C.uint16_t(request.Above), below: C.uint16_t(request.Below)} return resultError(C.ghostty_render_state_set(rs.ptr, C.GHOSTTY_RENDER_STATE_OPTION_OVERSCAN, unsafe.Pointer(&v)))}
// Overscan returns the number of extra rows captured by the last update.// Each count is at most the corresponding count set by [RenderState.SetOverscan].// Fewer rows are captured when the viewport is near the start or end of the// terminal's contents. Below is zero when the viewport is scrolled to the bottom.//// [RenderState.RowIterator] includes these extra rows. Cursor coordinates still// refer to the visible viewport and are available only when the cursor is// inside it.func (rs *RenderState) Overscan() (RenderStateOverscan, error) { return rs.getOverscan(C.GHOSTTY_RENDER_STATE_DATA_OVERSCAN)}
// OverscanRequest returns the counts most recently set by [RenderState.SetOverscan].// Both counts are zero if SetOverscan has not been called. The next update uses// this request. Use [RenderState.Overscan] for the counts from the last update.func (rs *RenderState) OverscanRequest() (RenderStateOverscan, error) { return rs.getOverscan(C.GHOSTTY_RENDER_STATE_DATA_OVERSCAN_REQUEST)}
// getOverscan reads either the requested or captured overscan counts.func (rs *RenderState) getOverscan(data C.GhosttyRenderStateData) (RenderStateOverscan, error) { var v C.GhosttyRenderStateOverscan if err := resultError(C.ghostty_render_state_get(rs.ptr, data, unsafe.Pointer(&v))); err != nil { return RenderStateOverscan{}, err } return RenderStateOverscan{Above: uint16(v.above), Below: uint16(v.below)}, nil}