luv

Workshop wiki

screen.lisp

ghostty/screen.lisp

system luv/ghostty · 49 definitions · on GitHub

Styled screen snapshots through libghostty-vt's render-state API.

terminal-text gives plain trimmed text. terminal-screen gives one dense per-cell snapshot: the base character, resolved foreground/background colours, bold/inverse flags, the default palette colours, and the cursor.

in-package#:luv.ghostty

Render-state C ABI. Enum values follow include/ghostty/vt/render.h.

cffi:defcstructcolor-rgb
r:uint8
g:uint8
b:uint8
cffi:defcunionstyle-color-value
palette:uint8
padding:uint64
cffi:defcstructstyle-color
tag:int
cffi:defcstructstyle
size:size
fg-color
bg-color
underline-color
bold:bool
italic:bool
faint:bool
blink:bool
inverse:bool
invisible:bool
strikethrough:bool
overline:bool
underline:int
cffi:defcfun
"ghostty_render_state_new"%render-state-new
ghostty-result
allocator:pointer
state:pointer
cffi:defcfun
"ghostty_render_state_free"%render-state-free
:void
state:pointer
cffi:defcfun
"ghostty_render_state_update"%render-state-update
ghostty-result
state:pointer
terminal:pointer
cffi:defcfun
"ghostty_render_state_get"%render-state-get
ghostty-result
state:pointer
data:int
output:pointer
cffi:defcfun
"ghostty_render_state_row_iterator_new"%render-state-row-iterator-new
ghostty-result
allocator:pointer
iterator:pointer
cffi:defcfun
"ghostty_render_state_row_iterator_free"%render-state-row-iterator-free
:void
iterator:pointer
cffi:defcfun
"ghostty_render_state_row_iterator_next"%render-state-row-iterator-next
:bool
iterator:pointer
cffi:defcfun
"ghostty_render_state_row_get"%render-state-row-get
ghostty-result
iterator:pointer
data:int
output:pointer
cffi:defcfun
"ghostty_render_state_row_cells_new"%render-state-row-cells-new
ghostty-result
allocator:pointer
cells:pointer
cffi:defcfun
"ghostty_render_state_row_cells_free"%render-state-row-cells-free
:void
cells:pointer
cffi:defcfun
"ghostty_render_state_row_cells_next"%render-state-row-cells-next
:bool
cells:pointer
cffi:defcfun
"ghostty_render_state_row_cells_get"%render-state-row-cells-get
ghostty-result
cells:pointer
data:int
output:pointer

The snapshot.

defstruct
terminal-screen
:constructor%make-terminal-screen

One dense styled snapshot of a terminal viewport.

CHARACTERS holds the base character of each cell in row-major order, #\Space where the cell is empty. FOREGROUND and BACKGROUND hold packed #xRRGGBB colours per cell, or -1 where the cell has no explicit colour and the DEFAULT-FOREGROUND / DEFAULT-BACKGROUND applies. FLAGS holds bit 0 = bold, bit 1 = inverse, bit 2 = faint, bit 3 = invisible.

columns0:typefixnum
rows0:typefixnum
characters"":typesimple-string
foregroundnil:type
simple-arrayfixnum
backgroundnil:type
simple-arrayfixnum
flagsnil:type
simple-array
unsigned-byte8
default-foreground#xFFFFFF:typefixnum
default-background#x000000:typefixnum
cursor-visible-pnil
cursor-column0:typefixnum
cursor-row0:typefixnum
defconstant+screen-flag-bold+1
defunterminal-screen-offset
screencolumnrow
+column
*row
terminal-screen-columnsscreen
defunterminal-screen-character
screencolumnrow
schar
terminal-screen-charactersscreen
terminal-screen-offsetscreencolumnrow
defunterminal-screen-bold-p
screencolumnrow
logtest+screen-flag-bold+
aref
terminal-screen-flagsscreen
terminal-screen-offsetscreencolumnrow
defunterminal-screen-inverse-p
screencolumnrow
logtest+screen-flag-inverse+
aref
terminal-screen-flagsscreen
terminal-screen-offsetscreencolumnrow
defunterminal-screen-cell-colors
screencolumnrow

Return the effective foreground and background #xRRGGBB of one cell.

Inverse video and the cursor cell swap the two; the second value is NIL when the cell paints no background of its own.

let*
offset
terminal-screen-offsetscreencolumnrow
flags
aref
terminal-screen-flagsscreen
offset
fg
aref
terminal-screen-foregroundscreen
offset
bg
aref
terminal-screen-backgroundscreen
offset
fg-set-p
>=fg0
bg-set-p
>=bg0
fg
iffg-set-pfg
terminal-screen-default-foregroundscreen
bg
ifbg-set-pbg
terminal-screen-default-backgroundscreen
cursor-p
and
terminal-screen-cursor-visible-pscreen
=column
terminal-screen-cursor-columnscreen
=row
terminal-screen-cursor-rowscreen
cond
and
notcursor-p
valuesbgfg
cursor-p

Draw the cursor as a block of the current foreground colour.

values
iffgbg
fg
t
valuesfg
andbg-set-pbg
defunterminal-screen-text
screen

The snapshot's rows as one newline-separated, right-trimmed string.

with-output-to-string
stream
dotimes
row
terminal-screen-rowsscreen
unless
zeroprow
terpristream
write-string
string-right-trim" "
subseq
terminal-screen-charactersscreen
stream
defunread-color-rgb
pointer
logior
ash
cffi:foreign-slot-valuepointer'
:structcolor-rgb
'r
16
ash
cffi:foreign-slot-valuepointer'
:structcolor-rgb
'g
8
cffi:foreign-slot-valuepointer'
:structcolor-rgb
'b
defunrender-state-color
statedata
cffi:with-foreign-object
color'
:structcolor-rgb
check-result
%render-state-getstatedatacolor
'terminal-screen
defunrender-state-bool
statedata
cffi:with-foreign-object
value:bool
setf
cffi:mem-refvalue:bool
nil
check-result
%render-state-getstatedatavalue
'terminal-screen
cffi:mem-refvalue:bool
defunrender-state-uint16
statedata
cffi:with-foreign-object
value:uint16
setf
cffi:mem-refvalue:uint16
0
check-result
%render-state-getstatedatavalue
'terminal-screen
cffi:mem-refvalue:uint16
defuncell-optional-color
cellsdata

A resolved cell colour, or -1 when the cell has none.

cffi:with-foreign-object
color'
:structcolor-rgb
let
result
%render-state-row-cells-getcellsdatacolor
caseresult
:success
:invalid-value-1
defunread-screen-cells
cellsscreenrowstylecodepoints

Copy one row of cells into screen's dense lanes.

let
columns
terminal-screen-columnsscreen
characters
terminal-screen-charactersscreen
foreground
terminal-screen-foregroundscreen
background
terminal-screen-backgroundscreen
flags
terminal-screen-flagsscreen
loopforcolumnfrom0while
and
<columncolumns
%render-state-row-cells-nextcells
do
let
offset
terminal-screen-offsetscreencolumnrow
cffi:with-foreign-object
count:uint32
setf
cffi:mem-refcount:uint32
0
check-result
%render-state-row-cells-getcells+render-state-row-cells-data-graphemes-len+count
'graphemes-len
let
count
cffi:mem-refcount:uint32
when
pluspcount

Only the base codepoint is placed on the wall grid. Combining marks stay in Ghostty's model for now.

check-result
%render-state-row-cells-getcells+render-state-row-cells-data-graphemes-buf+codepoints
'graphemes-buf
let
code
cffi:mem-arefcodepoints:uint320
when
and
pluspcode
<codechar-code-limit
setf
scharcharactersoffset
code-charcode
setf
cffi:foreign-slot-valuestyle'
:structstyle
'size
cffi:foreign-type-size'
:structstyle
flet
flag
slotbit
if
cffi:foreign-slot-valuestyle'
:structstyle
slot
bit0
setf
arefflagsoffset
defunterminal-screen

Snapshot terminal's active viewport as a styled terminal-screen.

let
state
cffi:null-pointer
iterator
cffi:null-pointer
cells
cffi:null-pointer
unwind-protect
cffi:with-foreign-objects
output:pointer
cells-output:pointer
style'
:structstyle
codepoints:uint3264
setf
cffi:mem-refoutput:pointer
cffi:null-pointer
check-result
%render-state-new
cffi:null-pointer
output
'state-new
setfstate
cffi:mem-refoutput:pointer
check-result
%render-state-updatestate
terminal-pointerterminal
'state-update
setf
cffi:mem-refoutput:pointer
cffi:null-pointer
check-result
%render-state-row-iterator-new
cffi:null-pointer
output
'iterator-new
setfiterator
cffi:mem-refoutput:pointer
setf
cffi:mem-refoutput:pointer
cffi:null-pointer
check-result
%render-state-row-cells-new
cffi:null-pointer
output
'cells-new
setfcells
cffi:mem-refoutput:pointer
let*
count
*columnsrows
screen
%make-terminal-screen:columnscolumns:rowsrows:characters
make-stringcount:initial-element#\Space
:foreground
make-arraycount:element-type'fixnum:initial-element-1
:background
make-arraycount:element-type'fixnum:initial-element-1
:flags
make-arraycount:element-type'
unsigned-byte8
:initial-element0
:default-foreground:default-background

These out-parameters point at the pre-allocated handles.

setf
cffi:mem-refoutput:pointer
iterator
check-result
%render-state-getstate+render-state-data-row-iterator+output
'row-iterator
loopforrowfrom0while
and
<rowrows
%render-state-row-iterator-nextiterator
do
setf
cffi:mem-refcells-output:pointer
cells
check-result
%render-state-row-getiterator+render-state-row-data-cells+cells-output
'row-cells
read-screen-cellscellsscreenrowstylecodepoints
screen
unless
cffi:null-pointer-pcells
%render-state-row-cells-freecells
unless
cffi:null-pointer-piterator
%render-state-row-iterator-freeiterator
unless
cffi:null-pointer-pstate
%render-state-freestate