Quick Start¶
This walks through the shortest path from an empty screen to a styled,
diff-rendered one, then a first look at input decoding. It assumes
cl-tty-kit is already loaded — see Installation.
Render a screen¶
screen is a pure grid of cell objects — no terminal I/O happens until you
explicitly render it. make-screen creates one, screen-write-string lays
out text, and render-screen turns the grid into an ANSI string:
(let ((screen (make-screen 20 4)))
(screen-write-string screen 0 0 "Hi")
(format t "~A~%" (render-screen screen)))
Nothing here touches a TTY — render-screen returns a plain string, so you
can print it, test it, or feed it into any output stream. The full data model
is covered in Screen and Rendering.
Add style¶
make-style builds a normalized style list from modifier keywords and color
entries. screen-put-cell accepts a :style argument per cell:
(let ((screen (make-screen 12 1)))
(screen-put-cell screen 0 0 #\H :style (make-style :bold (style-fg 196)))
(screen-put-cell screen 1 0 #\i :style (make-style (style-fg 33)))
(format t "~A~%" (render-screen screen)))
style-fg/style-bg accept either an indexed color ((style-fg 196), xterm
256-palette) or RGB bytes ((style-bg 17 34 51)). See Color for
the full conversion API.
Render only what changed¶
Real terminal apps redraw many times per second. render-diff compares two
screens of the same dimensions and emits only the changed cells — this is
what examples/screen-update.lisp and examples/styled-render.lisp
demonstrate:
(let ((previous (make-screen 10 2))
(current (make-screen 10 2)))
(screen-put-cell current 0 0 #\H)
(screen-put-cell current 1 0 #\i)
(screen-put-cell current 0 1 #\!)
(format t "~A~%" (render-diff current previous)))
For a real render loop across many frames, reach for the double-buffered
renderer instead of hand-tracking the previous screen yourself — see
Screen and Rendering.
Decode input¶
decode-input turns a raw terminal input string — printable characters,
control bytes, escape sequences, kitty-protocol sequences, bracketed paste
markers — into a list of key-event structures:
(decode-input (concatenate 'string "a" (string (code-char 3)) (string #\Esc) "[A"))
;; => (#S(KEY-EVENT :TYPE :CHARACTER :CODE #\a :MODIFIERS NIL)
;; #S(KEY-EVENT :TYPE :SPECIAL :CODE :CONTROL-C :MODIFIERS NIL)
;; #S(KEY-EVENT :TYPE :SPECIAL :CODE :UP :MODIFIERS NIL))
For a real terminal reading loop, use the streaming decoder instead of
one-shot decode-input, so partial reads at chunk boundaries don't produce
spurious errors — see Input Decoding.
Where to go next¶
- Work through more of
examples/— every file is a small, runnable, documented program. See Examples for the full index. - Read Screen and Rendering, Layout, and Widgets for the rest of the display-side API.
- Read Terminal Session for putting a real terminal into raw mode and the alternate screen safely.
- Check Compatibility before deploying —
cl-tty-kitrequires SBCL.