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 sys.go
9.9 kB · 322 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323package libghostty
// System-level configuration wrapping ghostty_sys_set().// These are process-global settings that must be configured at startup.
/*#include <ghostty/vt.h>#include <ghostty/vt/sys.h>
// Forward declaration for the Go log trampoline so we can take its// address on the C side. Uses compatible types (no const, int for enum)// to match what cgo generates for the //export function.extern void goSysLogTrampoline( void* userdata, int level, uint8_t* scope, size_t scope_len, uint8_t* message, size_t message_len);
// Forward declaration for the Go decode-PNG trampoline.// Uses compatible types (no const) to match what cgo generates for// the //export function.extern _Bool goSysDecodePngTrampoline( void* userdata, GhosttyAllocator* allocator, uint8_t* data, size_t data_len, GhosttySysImage* out);
// Forward declaration for the Go secure-random trampoline.extern _Bool goSysRandomSecureTrampoline( void* userdata, uint8_t* buf, size_t len);
// Helper to install the Go log trampoline via ghostty_sys_set.// We need this because cgo cannot take the address of a Go-exported// function directly as a C function pointer.static inline GhosttyResult sys_set_log_go(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_LOG, (const void*)goSysLogTrampoline);}
// Helper to install the built-in stderr log callback.static inline GhosttyResult sys_set_log_stderr(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_LOG, (const void*)ghostty_sys_log_stderr);}
// Helper to clear the log callback.static inline GhosttyResult sys_clear_log(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_LOG, NULL);}
// Helper to install the Go decode-PNG trampoline via ghostty_sys_set.static inline GhosttyResult sys_set_decode_png_go(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, (const void*)goSysDecodePngTrampoline);}
// Helper to clear the decode-PNG callback.static inline GhosttyResult sys_clear_decode_png(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, NULL);}
// Helper to install the Go secure-random trampoline via ghostty_sys_set.static inline GhosttyResult sys_set_random_secure_go(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_RANDOM_SECURE, (const void*)goSysRandomSecureTrampoline);}
// Helper to restore the platform secure-random implementation.static inline GhosttyResult sys_clear_random_secure(void) { return ghostty_sys_set(GHOSTTY_SYS_OPT_RANDOM_SECURE, NULL);}*/import "C"
import "unsafe"
// SysImage is a decoded image, returned by a [SysDecodePngFn].//// C: GhosttySysImagetype SysImage struct { // Width is the image width in pixels. Width uint32
// Height is the image height in pixels. Height uint32
// Data holds the pixels as 8-bit RGBA, four bytes per pixel. Rows // are stored in order starting from the top-left corner, with no // padding between them, so a complete image is Width*Height*4 bytes. Data []byte}
// SysDecodePngFn decodes the PNG image in data and returns its pixels.// Return a non-nil error if the image cannot be decoded. The image is then// rejected.//// data is only valid until the function returns, so copy it if you need// it later. The pixels in the returned [SysImage] are copied into memory// owned by libghostty, so the function does not need to keep them alive.//// C: GhosttySysDecodePngFntype SysDecodePngFn func(data []byte) (*SysImage, error)
// sysDecodePngFn is the currently installed Go decode-PNG callback.var sysDecodePngFn SysDecodePngFn
// SysRandomSecureFn fills data with cryptographically secure random bytes.// Implementations must use a real CSPRNG because libghostty uses this output// for secrets such as Kitty clipboard protocol one-time passwords. Return a// non-nil error when secure entropy is unavailable.//// C: GhosttySysRandomSecureFntype SysRandomSecureFn func(data []byte) error
// sysRandomSecureFn is the currently installed Go secure-random callback.var sysRandomSecureFn SysRandomSecureFn
// SysSetDecodePng installs a Go callback that decodes PNG image data// into RGBA pixels. This enables PNG support in the Kitty Graphics// Protocol. Pass nil to clear the callback and disable PNG decoding.//// This function is not safe for concurrent use. Callers must ensure// that decode configuration is not modified while terminals may// process image data (e.g. configure at startup before creating// terminals).func SysSetDecodePng(fn SysDecodePngFn) error { sysDecodePngFn = fn if fn == nil { return resultError(C.sys_clear_decode_png()) } return resultError(C.sys_set_decode_png_go())}
// SysSetRandomSecure overrides libghostty's platform secure-random source.// Pass nil to restore the platform default. Targets without a platform source,// such as wasm32-freestanding, require an override for operations that mint// secrets.//// This function is not safe for concurrent use. Configure it at startup before// terminals can perform operations that require secure entropy.func SysSetRandomSecure(fn SysRandomSecureFn) error { sysRandomSecureFn = fn if fn == nil { return resultError(C.sys_clear_random_secure()) } return resultError(C.sys_set_random_secure_go())}
// SysLogLevel represents the severity level of a log message from the// library. Maps directly to the C enum values.// C: GhosttySysLogLeveltype SysLogLevel int
const ( // SysLogLevelError is the error log level. SysLogLevelError SysLogLevel = C.GHOSTTY_SYS_LOG_LEVEL_ERROR
// SysLogLevelWarning is the warning log level. SysLogLevelWarning SysLogLevel = C.GHOSTTY_SYS_LOG_LEVEL_WARNING
// SysLogLevelInfo is the info log level. SysLogLevelInfo SysLogLevel = C.GHOSTTY_SYS_LOG_LEVEL_INFO
// SysLogLevelDebug is the debug log level. SysLogLevelDebug SysLogLevel = C.GHOSTTY_SYS_LOG_LEVEL_DEBUG)
// String returns a human-readable name for the log level.func (l SysLogLevel) String() string { switch l { case SysLogLevelError: return "error" case SysLogLevelWarning: return "warning" case SysLogLevelInfo: return "info" case SysLogLevelDebug: return "debug" default: return "unknown" }}
// SysLogFn is the Go callback type for log messages from the library.// The scope identifies the subsystem (e.g. "osc", "kitty"); it is// empty for unscoped (default) log messages. The message and scope// are only valid for the duration of the call.// C: GhosttySysLogFntype SysLogFn func(level SysLogLevel, scope string, message string)
// sysLogFn is the currently installed Go log callback.var sysLogFn SysLogFn
// SysSetLog installs a Go callback that receives internal library log// messages. Pass nil to clear the callback and discard log messages.//// Which log levels are emitted depends on the build mode of the// library. Debug builds emit all levels; release builds emit info// and above.//// This function is not safe for concurrent use. Callers must ensure// that log configuration is not modified while log messages may be// delivered (e.g. configure at startup before creating terminals).func SysSetLog(fn SysLogFn) error { sysLogFn = fn if fn == nil { return resultError(C.sys_clear_log()) } return resultError(C.sys_set_log_go())}
// SysSetLogStderr installs the built-in stderr log callback provided// by libghostty. Each message is formatted as "[level](scope): message\n"// and written to stderr in a thread-safe manner.//// This function is not safe for concurrent use. See [SysSetLog].func SysSetLogStderr() error { sysLogFn = nil return resultError(C.sys_set_log_stderr())}
//export goSysLogTrampolinefunc goSysLogTrampoline( _ unsafe.Pointer, level C.int, scopePtr *C.uint8_t, scopeLen C.size_t, messagePtr *C.uint8_t, messageLen C.size_t,) { fn := sysLogFn if fn == nil { return }
var scope string if scopeLen > 0 { scope = C.GoStringN((*C.char)(unsafe.Pointer(scopePtr)), C.int(scopeLen)) }
var message string if messageLen > 0 { message = C.GoStringN((*C.char)(unsafe.Pointer(messagePtr)), C.int(messageLen)) }
fn(SysLogLevel(level), scope, message)}
//export goSysDecodePngTrampolinefunc goSysDecodePngTrampoline( _ unsafe.Pointer, allocator *C.GhosttyAllocator, dataPtr *C.uint8_t, dataLen C.size_t, out *C.GhosttySysImage,) C.bool { fn := sysDecodePngFn if fn == nil { return false }
// Build a Go slice over the input PNG data without copying. data := unsafe.Slice((*byte)(unsafe.Pointer(dataPtr)), int(dataLen))
img, err := fn(data) if err != nil || img == nil { return false }
// Allocate output pixel buffer through the library's allocator so // the library can free it later. pixelLen := C.size_t(len(img.Data)) buf := C.ghostty_alloc(allocator, pixelLen) if buf == nil { return false }
// Copy decoded pixels into the library-owned buffer. copy(unsafe.Slice((*byte)(unsafe.Pointer(buf)), int(pixelLen)), img.Data)
// out.data is a pointer, and Go may only store a pointer into C // memory that is already zeroed (see allocZeroed). libghostty zeroes // out before calling us, so the fields can be set directly. out.width = C.uint32_t(img.Width) out.height = C.uint32_t(img.Height) out.data = buf out.data_len = pixelLen
return true}
//export goSysRandomSecureTrampolinefunc goSysRandomSecureTrampoline( _ unsafe.Pointer, buf *C.uint8_t, length C.size_t,) (ok C.bool) { fn := sysRandomSecureFn if fn == nil { return C.bool(false) }
// A panic must never unwind across the C boundary. A failed random source // is represented by false, which makes the originating operation fail with // GHOSTTY_IO_ERROR. defer func() { if recover() != nil { ok = C.bool(false) } }()
count, valid := ghosttySizeToInt(length) if !valid || (count > 0 && buf == nil) { return C.bool(false) } data := unsafe.Slice((*byte)(unsafe.Pointer(buf)), count) if err := fn(data); err != nil { return C.bool(false) } return C.bool(true)}