tui: Terminal UI for Racket
| (require tui) | package: racket-tui |
A small terminal UI library for Linux: raw-mode terminal control, mouse and true-color support, bracketed paste, and window-resize events.
Linux only. This library binds directly to Linux termios, signalfd and ioctl. Loading tui on other operating systems raises an error, because the FFI symbols do not exist. Only xterm / qterminal have been tested.
1 Installation
Install from the package index:
raco pkg install tui |
or directly from GitHub:
raco pkg install https://github.com/lu96-wow/racket-tui.git |
2 Quick Start
(require tui) (with-tui (λ () (screen-clear) (cursor-hide) (put-rgb-fg 255 100 0 "Hello TUI!") (put-at 5 10 "Direct output") (sleep 2)))
3 API Conventions
The whole API follows two naming tables (prefix, suffix) and three rules (put/format symmetry, argument order, three color tiers). Once these are known, most function names and signatures can be derived without looking them up.
3.1 Prefix: behavior
Prefix |
| Meaning |
| Example |
put- |
| Immediate terminal output (flushes by default) |
| |
format- |
| Return bytes without outputting; batch with @racket[put-bytes] |
| |
cursor- screen- line- buffer- |
| Cursor / screen / line / alt-buffer operations (immediate) |
| |
clr- |
| 16-color foreground constructor (shorthand for @racket[(color-fg n)]) |
| clr-red |
bclr- |
| 16-color background constructor |
| bclr-blue |
attr- |
| SGR attribute constructor (thunk that emits the escape sequence) |
| |
color- color256- color-rgb- |
| Color constructors (thunks, for @racket[style-define!]) |
| |
style- |
| Style system |
| |
event- |
| Input-event predicates and accessors |
| |
current- |
| Parameters or tracked cursor variables |
|
3.2 Suffix: side effects
Suffix |
| Meaning |
| Example |
! |
| Side effects: updates the tracked cursor / terminal mode |
| |
? |
| Predicate, returns boolean |
| |
-at |
| Positioned (@racket[row] @racket[col] first); DECSC/DECRC so the tracked cursor is untouched |
| |
-at! |
| Positioned and updates the tracked cursor |
| |
-base |
| Escape sequence only: no content, no reset |
|
3.3 Rule 1: put / format symmetry
Almost every capability has both a put- form (immediate output) and a format- form (returns bytes), with identical arguments:
(put-fg 1 "x") (put-rgb-fg-at 1 1 255 0 0 "x") (put-cursor-save)
Exceptions (by design):
put-at corresponds to format-content-at (the -at name is the content form).
format-styled* exists only in the format- form, for batching where one trailing format-reset is appended.
Output entry points such as put and put-bytes have no format- twin; format-content does the conversion.
3.4 Rule 2: argument order
The content v (string / bytes / char / number) is always the last argument.
Positioned functions take row col first.
Color arguments come in the middle: n for 16/256 colors; r g b for RGB; fr fg fb br bg bb (foreground then background) for foreground+background.
(put-rgb-fg-bg-at row col fr fg fb br bg bb v)
3.5 Rule 3: three color tiers are isomorphic
The 16-color, 256-color and RGB tiers are same-named and same-shaped; only the color argument differs (n / n / r g b):
(put-fg n v) (put-256-fg n v) (put-rgb-fg r g b v) (put-fg-at r c n v) (put-256-fg-at r c n v) (put-rgb-fg-at r c r g b v) (put-fg-base n) (put-256-fg-base n) (put-rgb-fg-base r g b)
Knowing any one tier, the other two can be derived.
3.6 Standard API categories
Category |
| Representative functions |
Lifecycle |
| |
Basic output |
| |
Positioned output |
| |
Cursor |
| |
Screen / line / buffer |
| |
Colors |
| |
Styles |
| |
Format (returns bytes) |
| |
Input |
| |
Terminal |
| |
Cursor tracking |
| |
Config constants |
|
4 Lifecycle
All three with-tui entry points are plain functions taking a thunk. They use dynamic-wind internally, so the terminal is always restored whether the body returns normally or raises an exception. Exceptions from the body propagate outward; they are never swallowed.
procedure
(with-tui body) → any
body : (-> any)
procedure
(with-tui-nobuffer body) → any
body : (-> any)
procedure
(with-tui-nobuffer-echo body) → any
body : (-> any)
procedure
(tui-init) → void?
procedure
(tui-exit) → void?
procedure
(tui-init-no-buffer) → void?
procedure
(tui-exit-no-buffer) → void?
procedure
(tui-init-no-buffer-echo) → void?
procedure
(tui-exit-no-buffer-echo) → void?
procedure
(enable-mouse!) → void?
procedure
(disable-mouse!) → void?
procedure
(enable-bracketed-paste!) → void?
procedure
(disable-bracketed-paste!) → void?
Do not call (exit) inside a with-tui body: it terminates the process without running cleanup, leaving the terminal in raw mode. Use a running? flag plus loop-input/stop instead.
5 Output
All put- functions write to the current output port immediately (one flush per call) by default; use set-buffered-mode! to batch.
procedure
(put v) → void?
v : any/c
procedure
(put-string s) → void?
s : string?
procedure
(put-bytes bs) → void?
bs : bytes?
procedure
(put-byte b) → void?
b : byte?
procedure
(put-char c) → void?
c : char?
procedure
(put-newline) → void?
procedure
(put-format-bytes part ...) → void?
part : bytes?
procedure
(format-newline) → bytes?
procedure
(put-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
5.1 Cursor
procedure
(cursor-up n) → void?
n : exact-nonnegative-integer?
procedure
(cursor-down n) → void?
n : exact-nonnegative-integer?
procedure
(cursor-left n) → void?
n : exact-nonnegative-integer?
procedure
(cursor-right n) → void?
n : exact-nonnegative-integer?
procedure
(cursor-move row col) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer?
procedure
(cursor-col n) → void?
n : exact-nonnegative-integer?
procedure
(cursor-home) → void?
procedure
(cursor-hide) → void?
procedure
(cursor-show) → void?
procedure
(put-cursor-save) → void?
procedure
(put-cursor-restore) → void?
5.2 Screen and lines
procedure
(screen-clear) → void?
procedure
(screen-clear-below) → void?
procedure
(screen-clear-above) → void?
procedure
(line-clear) → void?
procedure
(line-clear-right) → void?
procedure
(line-clear-left) → void?
procedure
(buffer-alt-enable) → void?
procedure
(buffer-alt-disable) → void?
5.3 Flush mode
procedure
(set-immediate-mode!) → void?
procedure
(set-buffered-mode!) → void?
procedure
(flush!) → void?
6 Colors
Colors come in three flavors: 16-color ANSI, 256-color, and true color (RGB). The put- variants print content in that color and reset after.
procedure
(put-fg n v) → void?
n : (integer-in 0 15) v : any/c
procedure
(put-bg n v) → void?
n : (integer-in 0 15) v : any/c
procedure
(put-rgb-fg r g b v) → void?
r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-bg r g b v) → void?
r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-fg-bg fr fg fb br bg bb v) → void?
fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte? v : any/c
procedure
(put-256-fg n v) → void?
n : (integer-in 0 255) v : any/c
procedure
(put-256-bg n v) → void?
n : (integer-in 0 255) v : any/c
procedure
(put-reset) → void?
6.1 Positioned colors
The -at variants print in color at a fixed position. Like put-at, they use DECSC/DECRC so the tracked cursor is untouched; the -at! variants update the tracked cursor position instead.
procedure
(put-fg-at row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(put-fg-at! row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(put-bg-at row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(put-bg-at! row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(put-rgb-fg-at row col r g b v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-fg-at! row col r g b v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-bg-at row col r g b v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-bg-at! row col r g b v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(put-rgb-fg-bg-at row col fr fg fb br bg bb v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte? v : any/c
procedure
(put-rgb-fg-bg-at! row col fr fg fb br bg bb v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte? v : any/c
procedure
(put-256-fg-at row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(put-256-fg-at! row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(put-256-bg-at row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(put-256-bg-at! row col n v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
6.2 Escape-only variants
The -base variants emit only the escape sequence, without content or reset; the attribute variants emit the corresponding SGR sequence:
procedure
(put-fg-base n) → void?
n : (integer-in 0 15)
procedure
(put-bg-base n) → void?
n : (integer-in 0 15)
procedure
(put-rgb-fg-base r g b) → void?
r : byte? g : byte? b : byte?
procedure
(put-rgb-bg-base r g b) → void?
r : byte? g : byte? b : byte?
procedure
(put-rgb-fg-bg-base fr fg fb br bg bb) → void?
fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte?
procedure
(put-256-fg-base n) → void?
n : (integer-in 0 255)
procedure
(put-256-bg-base n) → void?
n : (integer-in 0 255)
procedure
(put-bold) → void?
procedure
(put-dim) → void?
procedure
(put-italic) → void?
procedure
(put-underline) → void?
procedure
(put-blink) → void?
procedure
(put-reverse) → void?
7 Styles
Styles are named bundles of color and attribute thunks. Define them once, then apply by name. style-define! registers every style in both a 256-color and a 16-color registry; the active registry is selected by current-registry (see use-color-auto!).
7.1 Usage
(style-define! 'fancy clr-yellow bclr-blue attr-bold attr-underline) (put-styled 'fancy "Combined style") (put-styled-at 5 10 'fancy "fixed") (put-styled-at! 5 10 'fancy "cursor") (put-format-bytes (format-styled 'title "Title") (format-styled 'info "body text"))
The two registries give automatic 256/16-color fallback: plain color-fg/attr-bold register the same value in both, while color-fg* and color-bg* take separate values for each:
(style-define! 'status (color-fg* 46 2) attr-bold)
style->bytes returns the precomputed escape bytes for a style; it is what format-styled uses internally. An undefined style name is a no-op: it produces empty bytes without raising an error.
procedure
(style-define! name spec ...) → void?
name : symbol? spec : procedure?
procedure
(style-apply! name) → void?
name : symbol?
procedure
(style-reset) → void?
procedure
(style->bytes name) → bytes?
name : symbol?
procedure
(put-styled name v) → void?
name : symbol? v : any/c
procedure
(put-styled-at row col name v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? name : symbol? v : any/c
procedure
(put-styled-at! row col name v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? name : symbol? v : any/c
procedure
(put-styled-bold v) → void?
v : any/c
procedure
(put-styled-bold-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-bold-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-dim v) → void?
v : any/c
procedure
(put-styled-dim-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-dim-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-italic v) → void?
v : any/c
procedure
(put-styled-italic-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-italic-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-underline v) → void?
v : any/c
procedure
(put-styled-underline-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-underline-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-blink v) → void?
v : any/c
procedure
(put-styled-blink-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-blink-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-reverse v) → void?
v : any/c
procedure
(put-styled-reverse-at row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(put-styled-reverse-at! row col v) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
7.2 Color and attribute constructors
procedure
(color-fg n) → procedure?
n : (integer-in 0 15)
procedure
(color-bg n) → procedure?
n : (integer-in 0 15)
procedure
(color256-fg n) → procedure?
n : (integer-in 0 255)
procedure
(color256-bg n) → procedure?
n : (integer-in 0 255)
procedure
(color-rgb-fg r g b) → procedure?
r : byte? g : byte? b : byte?
procedure
(color-rgb-bg r g b) → procedure?
r : byte? g : byte? b : byte?
procedure
(color-fg* c256 c16) → color-thunk?
c256 : (integer-in 0 255) c16 : (integer-in 0 15)
procedure
(color-bg* c256 c16) → color-thunk?
c256 : (integer-in 0 255) c16 : (integer-in 0 15)
procedure
(attr-bold) → void?
procedure
(attr-dim) → void?
procedure
(attr-italic) → void?
procedure
(attr-underline) → void?
procedure
(attr-blink) → void?
procedure
(attr-reverse) → void?
7.3 Color mode
procedure
(use-256color!) → void?
procedure
(use-16color!) → void?
procedure
(use-color-auto!) → void?
7.4 Built-in styles
The following styles are pre-registered by the library:
Basic: 'red 'green 'blue 'yellow 'cyan 'magenta 'white
Levels: 'error 'warning 'info 'success
Text: 'title 'subtitle 'heading 'border 'border-bold
Widgets: 'button 'button-hover 'button-pressed 'button-disabled
Menus: 'menu-item 'menu-selected 'menu-key 'menu-shortcut
Lists: 'list-item 'list-selected 'list-alternate
Dialogs: 'dialog-title 'dialog-body 'dialog-button 'dialog-highlight
Status: 'status-bar 'status-good 'status-warning 'status-bad
Input: 'input-normal 'input-focus 'input-error
Misc: 'cursor 'selection 'scroll-track 'scroll-thumb
8 Format functions
The format- functions return byte strings without writing anything. They are meant to be collected and written in one batch with put-format-bytes or put-bytes. Each value-taking variant appends content and a style reset, so format-reset is only needed once at the end of a batch.
procedure
(format-cursor-move row col) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer?
procedure
(format-cursor-up n) → bytes?
n : exact-nonnegative-integer?
procedure
(format-cursor-down n) → bytes?
n : exact-nonnegative-integer?
procedure
(format-cursor-left n) → bytes?
n : exact-nonnegative-integer?
procedure
(format-cursor-right n) → bytes?
n : exact-nonnegative-integer?
procedure
(format-cursor-col n) → bytes?
n : exact-nonnegative-integer?
procedure
(format-cursor-home) → bytes?
procedure
(format-cursor-hide) → bytes?
procedure
(format-cursor-show) → bytes?
procedure
(format-cursor-save) → bytes?
procedure
(format-cursor-restore) → bytes?
procedure
(format-screen-clear) → bytes?
procedure
(format-screen-clear-below) → bytes?
procedure
(format-screen-clear-above) → bytes?
procedure
(format-line-clear) → bytes?
procedure
(format-line-clear-right) → bytes?
procedure
(format-line-clear-left) → bytes?
procedure
(format-buffer-alt-enable) → bytes?
procedure
(format-buffer-alt-disable) → bytes?
procedure
(format-reset) → bytes?
procedure
(format-bold) → bytes?
procedure
(format-dim) → bytes?
procedure
(format-italic) → bytes?
procedure
(format-underline) → bytes?
procedure
(format-blink) → bytes?
procedure
(format-reverse) → bytes?
procedure
(format-content v) → bytes?
v : any/c
procedure
(format-fg n v) → bytes?
n : (integer-in 0 15) v : any/c
procedure
(format-bg n v) → bytes?
n : (integer-in 0 15) v : any/c
procedure
(format-rgb-fg r g b v) → bytes?
r : byte? g : byte? b : byte? v : any/c
procedure
(format-rgb-bg r g b v) → bytes?
r : byte? g : byte? b : byte? v : any/c
procedure
(format-rgb-fg-bg fr fg fb br bg bb v) → bytes?
fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte? v : any/c
procedure
(format-256-fg n v) → bytes?
n : (integer-in 0 255) v : any/c
procedure
(format-256-bg n v) → bytes?
n : (integer-in 0 255) v : any/c
procedure
(format-fg-base n) → bytes?
n : (integer-in 0 15)
procedure
(format-bg-base n) → bytes?
n : (integer-in 0 15)
procedure
(format-rgb-fg-base r g b) → bytes?
r : byte? g : byte? b : byte?
procedure
(format-rgb-bg-base r g b) → bytes?
r : byte? g : byte? b : byte?
procedure
(format-rgb-fg-bg-base fr fg fb br bg bb) → bytes?
fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte?
procedure
(format-256-fg-base n) → bytes?
n : (integer-in 0 255)
procedure
(format-256-bg-base n) → bytes?
n : (integer-in 0 255)
procedure
(format-styled name v) → bytes?
name : symbol? v : any/c
procedure
(format-styled* name v) → bytes?
name : symbol? v : any/c
procedure
(format-styled-at row col name v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? name : symbol? v : any/c
procedure
(format-styled-at! row col name v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? name : symbol? v : any/c
procedure
(format-styled-bold v) → bytes?
v : any/c
procedure
(format-styled-bold-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-bold-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-dim v) → bytes?
v : any/c
procedure
(format-styled-dim-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-dim-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-italic v) → bytes?
v : any/c
procedure
(format-styled-italic-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-italic-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-underline v) → bytes?
v : any/c
procedure
(format-styled-underline-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-underline-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-blink v) → bytes?
v : any/c
procedure
(format-styled-blink-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-blink-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-reverse v) → bytes?
v : any/c
procedure
(format-styled-reverse-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-styled-reverse-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-content-at row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-content-at! row col v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? v : any/c
procedure
(format-fg-at row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(format-fg-at! row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(format-bg-at row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(format-bg-at! row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 15) v : any/c
procedure
(format-rgb-fg-at row col r g b v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(format-rgb-fg-at! row col r g b v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(format-rgb-bg-at row col r g b v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(format-rgb-bg-at! row col r g b v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? r : byte? g : byte? b : byte? v : any/c
procedure
(format-256-fg-at row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(format-256-fg-at! row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(format-256-bg-at row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(format-256-bg-at! row col n v) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? n : (integer-in 0 255) v : any/c
procedure
(format-rgb-fg-bg-at row col fr fg fb br bg bb) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte?
procedure
(format-rgb-fg-bg-at! row col fr fg fb br bg bb) → bytes?
row : exact-nonnegative-integer? col : exact-nonnegative-integer? fr : byte? fg : byte? fb : byte? br : byte? bg : byte? bb : byte?
9 Input
9.1 High-level: build-input and event loops
procedure
(build-input [ #:char on-char #:utf-char on-utf-char #:ctrl on-ctrl #:alt on-alt #:mod-char on-mod-char #:mod-key on-mod-key #:tab on-tab #:backtab on-backtab #:space on-space #:enter on-enter #:backspace on-backspace #:escape on-escape #:up on-up #:down on-down #:left on-left #:right on-right #:delete on-delete #:insert on-insert #:home on-home #:end on-end #:pageup on-pageup #:pagedown on-pagedown #:mouse-press on-mouse-press #:mouse-release on-mouse-release #:mouse-move on-mouse-move #:mouse-scroll on-mouse-scroll #:paste on-paste #:resize on-resize #:null on-null #:any on-any]) → (-> symbol? bytes? (or/c #f (list/c boolean? boolean? boolean?)) any) on-char : (or/c (-> integer? any) #f) = #f on-utf-char : (or/c (-> string? any) #f) = #f on-ctrl : (or/c (-> char? any) #f) = #f on-alt : (or/c (-> char? any) #f) = #f
on-mod-char : (or/c (-> char? boolean? boolean? boolean? any) #f) = #f
on-mod-key : (or/c (-> symbol? boolean? boolean? boolean? any) #f) = #f on-tab : (or/c (-> any) #f) = #f on-backtab : (or/c (-> any) #f) = #f on-space : (or/c (-> any) #f) = #f on-enter : (or/c (-> any) #f) = #f on-backspace : (or/c (-> any) #f) = #f on-escape : (or/c (-> any) #f) = #f on-up : (or/c (-> any) #f) = #f on-down : (or/c (-> any) #f) = #f on-left : (or/c (-> any) #f) = #f on-right : (or/c (-> any) #f) = #f on-delete : (or/c (-> any) #f) = #f on-insert : (or/c (-> any) #f) = #f on-home : (or/c (-> any) #f) = #f on-end : (or/c (-> any) #f) = #f on-pageup : (or/c (-> any) #f) = #f on-pagedown : (or/c (-> any) #f) = #f
on-mouse-press : (or/c (-> symbol? exact-nonnegative-integer? exact-nonnegative-integer? (list/c boolean? boolean? boolean?) any) #f) = #f
on-mouse-release : (or/c (-> symbol? exact-nonnegative-integer? exact-nonnegative-integer? (list/c boolean? boolean? boolean?) any) #f) = #f
on-mouse-move : (or/c (-> exact-nonnegative-integer? exact-nonnegative-integer? (list/c boolean? boolean? boolean?) any) #f) = #f
on-mouse-scroll : (or/c (-> symbol? exact-nonnegative-integer? exact-nonnegative-integer? (list/c boolean? boolean? boolean?) any) #f) = #f on-paste : (or/c (-> bytes? any) #f) = #f
on-resize : (or/c (-> exact-positive-integer? exact-positive-integer? any) #f) = #f on-null : (or/c (-> any) #f) = #f
on-any : (or/c (-> symbol? bytes? (or/c #f (list/c boolean? boolean? boolean?)) any) #f) = #f
Event dispatch priority (built in): null > resize > paste > mouse > tab/backtab/space/enter/backspace/escape > arrows > function keys > ctrl > alt > mod-seq > utf8 > char > any.
Modified characters (e.g. Ctrl+Alt+x, encoded as ESC [ 27;7;120~) go to #:mod-char with the character.
Modified navigation keys (e.g. Ctrl+Up, encoded as ESC [ 1;5A) go to #:mod-key with a key symbol such as 'up or 'home. If #:mod-key is not provided they fall back to #:mod-char.
9.1.1 Callback arguments
All keywords are optional; an event without a matching callback falls through to #:any, or is ignored if #:any is absent. Callback argument types:
Keyword |
| Callback |
| Argument types |
#:char |
| (ch) |
| ch — |
#:utf-char |
| (str) |
| str — |
#:ctrl |
| (ch) |
| ch — |
#:alt |
| (ch) |
| ch — |
#:mod-char |
| (ch ctrl? alt? shift?) |
| ch — |
#:mod-key |
| (key ctrl? alt? shift?) |
| key — |
#:tab |
| () |
| No arguments |
#:backtab |
| () |
| Shift+Tab, no arguments |
#:space |
| () |
| No arguments |
#:enter |
| () |
| No arguments |
#:backspace |
| () |
| No arguments |
#:escape |
| () |
| No arguments |
#:up |
| () |
| Arrow up, no arguments |
#:down |
| () |
| No arguments |
#:left |
| () |
| No arguments |
#:right |
| () |
| No arguments |
#:delete |
| () |
| No arguments |
#:insert |
| () |
| No arguments |
#:home |
| () |
| No arguments |
#:end |
| () |
| No arguments |
#:pageup |
| () |
| No arguments |
#:pagedown |
| () |
| No arguments |
#:mouse-press |
| (button x y mods) |
| button — |
#:mouse-release |
| (button x y mods) |
| Same as #:mouse-press |
#:mouse-move |
| (x y mods) |
| x y — |
#:mouse-scroll |
| (dir x y mods) |
| dir — |
#:paste |
| (data) |
| data — |
#:resize |
| (rows cols) |
| rows cols — |
#:null |
| () |
| No input available (noblock loop) |
#:any |
| (type data mods) |
| type — |
9.1.2 Example
(define handler (build-input #:char (lambda (ch) (printf "key '~a'\n" (integer->char ch))) #:ctrl (lambda (ch) (printf "Ctrl+~a\n" ch)) #:mod-char (lambda (ch ctrl? alt? shift?) (printf "~a~a~a~a\n" (if ctrl? "Ctrl+" "") (if alt? "Alt+" "") (if shift? "Shift+" "") ch)) #:mod-key (lambda (key ctrl? alt? shift?) (printf "~a~a~a~a\n" (if ctrl? "Ctrl+" "") (if alt? "Alt+" "") (if shift? "Shift+" "") key)) #:mouse-press (lambda (button x y mods) (printf "~a ~a (~a,~a)\n" (car mods) button x y)) #:paste (lambda (data) (printf "pasted ~a bytes\n" (bytes-length data))) #:resize (lambda (rows cols) (printf "~ax~a\n" rows cols))))
syntax
(loop-input handler ...)
syntax
(loop-input-noblock handler ...)
syntax
(loop-input/stop stop-expr handler ...)
syntax
(loop-input-noblock/stop stop-expr handler ...)
9.2 Low-level: read-event
procedure
(read-event) →
symbol? bytes? (or/c #f (list/c boolean? boolean? boolean?))
type —
a symbol (see the predicates below). data —
event payload: key byte, UTF-8 bytes, mouse detail list, paste bytes, or (rows . cols) for resize. mods —
#f (no modifiers) or (list ctrl? alt? shift?) for modified keys and mouse events.
procedure
→
symbol? bytes? (or/c #f (list/c boolean? boolean? boolean?))
procedure
(event-null? type) → boolean?
type : symbol?
procedure
(event-key? type) → boolean?
type : symbol?
procedure
(event-utf8? type) → boolean?
type : symbol?
procedure
(event-seq? type) → boolean?
type : symbol?
procedure
(event-ctrl? type) → boolean?
type : symbol?
procedure
(event-alt? type) → boolean?
type : symbol?
procedure
(event-mod-seq? type) → boolean?
type : symbol?
procedure
(event-resize? type) → boolean?
type : symbol?
procedure
(event-up? type) → boolean?
type : symbol?
procedure
(event-down? type) → boolean?
type : symbol?
procedure
(event-left? type) → boolean?
type : symbol?
procedure
(event-right? type) → boolean?
type : symbol?
procedure
(event-del? type) → boolean?
type : symbol?
procedure
(event-insert? type) → boolean?
type : symbol?
procedure
(event-home? type) → boolean?
type : symbol?
procedure
(event-end? type) → boolean?
type : symbol?
procedure
(event-pageup? type) → boolean?
type : symbol?
procedure
(event-pagedown? type) → boolean?
type : symbol?
procedure
(event-backtab? type) → boolean?
type : symbol?
procedure
(event-touch? type) → boolean?
type : symbol?
procedure
(event-mouse? type) → boolean?
type : symbol?
procedure
(event-paste? type) → boolean?
type : symbol?
procedure
(event-tab? type data) → boolean?
type : symbol? data : bytes?
procedure
(event-space? type data) → boolean?
type : symbol? data : bytes?
procedure
(event-backspace? type data) → boolean?
type : symbol? data : bytes?
procedure
(event-enter? type data) → boolean?
type : symbol? data : bytes?
procedure
(event-escape? type data) → boolean?
type : symbol? data : bytes?
procedure
(ctrl->char data) → (or/c char? #f)
data : bytes?
procedure
(alt->char data) → (or/c char? #f)
data : bytes?
procedure
(mod-seq->char data) → (or/c char? #f)
data : bytes?
procedure
(event->string data) → string?
data : bytes?
procedure
(event->byte data) → byte?
data : bytes?
9.3 Mouse
procedure
(mouse-press? detail) → boolean?
detail : list?
procedure
(mouse-release? detail) → boolean?
detail : list?
procedure
(mouse-move? detail) → boolean?
detail : list?
procedure
(mouse-scroll? detail) → boolean?
detail : list?
procedure
(mouse-left? detail) → boolean?
detail : list?
procedure
(mouse-middle? detail) → boolean?
detail : list?
procedure
(mouse-right? detail) → boolean?
detail : list?
procedure
(scroll-up? detail) → boolean?
detail : list?
procedure
(scroll-down? detail) → boolean?
detail : list?
procedure
(mouse-x detail) → exact-nonnegative-integer?
detail : list?
procedure
(mouse-y detail) → exact-nonnegative-integer?
detail : list?
procedure
(get-mouse-pos detail) →
exact-nonnegative-integer? exact-nonnegative-integer? detail : list?
procedure
(mouse-modifiers detail) → (listof symbol?)
detail : list?
9.4 Resize
procedure
(get-resize-rows data) → exact-positive-integer?
data : (cons/c exact-positive-integer? exact-positive-integer?)
procedure
(get-resize-cols data) → exact-positive-integer?
data : (cons/c exact-positive-integer? exact-positive-integer?)
procedure
(get-resize-size data) →
exact-positive-integer? exact-positive-integer? data : (cons/c exact-positive-integer? exact-positive-integer?)
10 Terminal
procedure
(terminal?) → boolean?
procedure
(enter-raw-mode!) → void?
procedure
(exit-raw-mode!) → void?
procedure
(enter-raw-mode-keep-echo!) → void?
procedure
(call-with-terminal-reply thunk) → any
thunk : (-> any)
procedure
(make-stdin-evt) → evt?
procedure
(get-window-size [fd]) →
(or/c exact-positive-integer? #f) (or/c exact-positive-integer? #f) fd : exact-integer? = 1
procedure
(resize-monitor-start) → void?
procedure
(resize-monitor-stop) → void?
procedure
(make-resize-evt) → evt?
11 Cursor state
The library tracks the cursor position in two parameters; -at functions update it.
value
current-cursor-row : exact-nonnegative-integer?
value
current-cursor-col : exact-nonnegative-integer?
procedure
(set-cursor! row col) → void?
row : exact-nonnegative-integer? col : exact-nonnegative-integer?
procedure
(get-cursor) →
exact-nonnegative-integer? exact-nonnegative-integer?
procedure
(update-cursor!) →
exact-nonnegative-integer? exact-nonnegative-integer?
12 Configuration constants
value
ESCDELAY : real?
value
CSI-MAX-BYTES : exact-positive-integer?
value
PASTE-MAX-BYTES : exact-positive-integer?
value
UTF8-READ-TIMEOUT : real?
value
PASTE-READ-TIMEOUT : real?
13 Complete example
(require tui) (define (draw-ui) (define buffer (bytes-append format-screen-clear (format-cursor-move 0 0) (format-rgb-fg 255 255 0) #"=== TUI Demo ===" format-reset (format-cursor-move 2 0) (format-rgb-fg 0 255 0) #"Press 'q' to quit" format-reset (format-cursor-move 4 0) (format-rgb-fg 255 0 0) #"Hello, TUI!" format-reset (format-cursor-move 6 0) (format-256-fg 46 "UTF-8 support: 你好世界") format-reset)) (put-bytes buffer)) (with-tui (λ () (cursor-hide) (define running? #t) (define handler (build-input #:char (lambda (ch) (when (= ch (char->integer #\q)) (set! running? #f))))) (define (render-and-handle type data mods) (handler type data mods) (draw-ui)) (loop-input/stop (not running?) render-and-handle)))
14 Implementation notes
The termios struct layout and flag constants in base/terminal/base.rkt are hardcoded (previously generated by compiling a C program). The values come from the kernel’s asm-generic/termbits.h and are identical across mainstream Linux architectures (x86, arm, aarch64, riscv, ppc, mips, sparc). TERMIOS-SIZE is fixed at 60, which is safe for both glibc and musl. The only exception is the alpha architecture, which is not supported.