Files
clojure-tui/docs/api-reference.md
2026-01-22 10:50:26 -05:00

666 lines
13 KiB
Markdown

# API Reference
Complete API documentation for Clojure TUI.
## Table of Contents
- [tui.core](#tuicore) - Main runtime
- [tui.render](#tuirender) - Hiccup rendering
- [tui.input](#tuiinput) - Key input parsing
- [tui.terminal](#tuiterminal) - Terminal control
- [tui.ansi](#tuiansi) - ANSI escape codes
---
## tui.core
Main runtime using core.async. Provides timers, async commands, background operations, and responsive layout support.
### run
```clojure
(run options)
```
Run a TUI application synchronously (blocks until quit).
**Parameters:**
| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `:init` | any | Yes | Initial model value |
| `:update` | function | Yes | `(fn [model msg] [new-model cmd])` |
| `:view` | function | Yes | `(fn [model size] hiccup)` where size is `{:width w :height h}` |
| `:init-cmd` | command | No | Initial command to execute |
| `:fps` | integer | No | Frames per second (default: 60) |
| `:alt-screen` | boolean | No | Use alternate screen (default: true) |
**Returns:** Final model value after quit
**Example:**
```clojure
(require '[tui.core :as tui])
(tui/run {:init {:count 0}
:update (fn [model msg]
(if (tui/key= msg "q")
[model tui/quit]
[model nil]))
:view (fn [{:keys [count]} _size]
[:text (str "Count: " count)])
:fps 30
:alt-screen true})
```
### quit
```clojure
quit
```
Constant value returned as a command to exit the application.
**Example:**
```clojure
(defn update-fn [model msg]
(if (tui/key= msg "q")
[model tui/quit]
[model nil]))
```
### tick
```clojure
(tick ms)
```
Create a command that sends `:tick` message after a delay.
**Parameters:**
- `ms` - Delay in milliseconds
**Returns:** A tick command
**Example:**
```clojure
;; Start a 1-second timer
(defn update-fn [model msg]
(case msg
:tick [(update model :seconds inc) (tui/tick 1000)]
[model nil]))
;; Initial tick
(tui/run {:init {:seconds 0}
:update update-fn
:view view
:init-cmd (tui/tick 1000)})
```
### batch
```clojure
(batch & cmds)
```
Create a command that executes multiple commands in parallel.
**Parameters:**
- `cmds` - Variable number of commands
**Returns:** A batch command
**Example:**
```clojure
;; Execute two async operations in parallel
(defn update-fn [model msg]
(if (= msg :start)
[model (tui/batch
(fn [] (fetch-user))
(fn [] (fetch-settings)))]
[model nil]))
```
### sequentially
```clojure
(sequentially & cmds)
```
Create a command that executes commands one after another.
**Parameters:**
- `cmds` - Variable number of commands
**Returns:** A sequential command
**Example:**
```clojure
;; First save, then notify
(defn update-fn [model msg]
(if (= msg :save)
[model (tui/sequentially
(fn [] (save-data model))
(fn [] {:type :saved}))]
[model nil]))
```
### send-msg
```clojure
(send-msg msg)
```
Create a command that immediately sends a message.
**Parameters:**
- `msg` - Message to send
**Returns:** A send-msg command
**Example:**
```clojure
(defn update-fn [model msg]
(if (tui/key= msg "r")
[{:status :resetting} (tui/send-msg :do-reset)]
[model nil]))
```
### key=
```clojure
(key= msg pattern)
```
Check if a key message matches a pattern.
**Parameters:**
- `msg` - The message to check
- `pattern` - Pattern to match (see below)
**Returns:** `true` if matches, `false` otherwise
**Pattern types:**
| Pattern | Matches |
|---------|---------|
| `"q"` | Character 'q' |
| `:enter` | Enter key |
| `:up` | Arrow up |
| `[:ctrl \c]` | Ctrl+C |
| `[:alt \x]` | Alt+X |
**Example:**
```clojure
(defn update-fn [model msg]
(cond
(tui/key= msg "q") [model tui/quit]
(tui/key= msg :up) [(update model :y dec) nil]
(tui/key= msg [:ctrl \c]) [model tui/quit]
:else [model nil]))
```
### key-str
```clojure
(key-str msg)
```
Convert a key message to a human-readable string.
**Parameters:**
- `msg` - Key message
**Returns:** String representation
**Example:**
```clojure
(tui/key-str [:key {:char \a}]) ;; => "a"
(tui/key-str [:key :up]) ;; => "up"
(tui/key-str [:key {:ctrl true :char \c}]) ;; => "ctrl+c"
```
### render
```clojure
(render hiccup)
```
Re-exported from `tui.render`. Render hiccup to ANSI string.
---
## tui.render
Converts hiccup data structures to ANSI-formatted strings.
### render
```clojure
(render hiccup)
(render hiccup ctx)
```
Render hiccup to ANSI string.
**Parameters:**
- `hiccup` - Hiccup data structure
- `ctx` - Optional context map (for internal use)
**Returns:** String with ANSI escape codes
**Example:**
```clojure
(require '[tui.render :as r])
(r/render [:text {:fg :red :bold true} "Error!"])
;; => "\e[31m\e[1mError!\e[0m"
(r/render [:col
[:text "Line 1"]
[:text "Line 2"]])
;; => "Line 1\nLine 2"
(r/render [:box {:border :rounded} "Content"])
;; => "╭─────────╮\n│Content │\n╰─────────╯"
```
### text
```clojure
(text & args)
```
Helper function to create `:text` elements.
**Example:**
```clojure
(text "Hello") ;; => [:text "Hello"]
(text {:fg :red} "Error") ;; => [:text {:fg :red} "Error"]
```
### row
```clojure
(row & args)
```
Helper function to create `:row` elements.
**Example:**
```clojure
(row "A" "B" "C") ;; => [:row "A" "B" "C"]
(row {:gap 2} "A" "B") ;; => [:row {:gap 2} "A" "B"]
```
### col
```clojure
(col & args)
```
Helper function to create `:col` elements.
**Example:**
```clojure
(col "Line 1" "Line 2") ;; => [:col "Line 1" "Line 2"]
(col {:gap 1} "A" "B") ;; => [:col {:gap 1} "A" "B"]
```
### box
```clojure
(box & args)
```
Helper function to create `:box` elements.
**Example:**
```clojure
(box "Content") ;; => [:box "Content"]
(box {:title "Info"} "Content") ;; => [:box {:title "Info"} "Content"]
```
---
## tui.input
Parses raw terminal input into structured key messages.
### read-key
```clojure
(read-key)
```
Read a single key event from the terminal.
**Returns:** Key message vector `[:key ...]`
**Key message formats:**
```clojure
;; Regular character
[:key {:char \a}]
;; Special key
[:key :enter]
[:key :up]
[:key :f1]
;; Control combination
[:key {:ctrl true :char \c}]
;; Alt combination
[:key {:alt true :char \x}]
;; Unknown sequence
[:key :unknown "\e[xyz"]
```
### Special Key Keywords
| Keyword | Key |
|---------|-----|
| `:up` | Arrow Up |
| `:down` | Arrow Down |
| `:left` | Arrow Left |
| `:right` | Arrow Right |
| `:home` | Home |
| `:end` | End |
| `:page-up` | Page Up |
| `:page-down` | Page Down |
| `:insert` | Insert |
| `:delete` | Delete |
| `:escape` | Escape |
| `:tab` | Tab |
| `:shift-tab` | Shift+Tab |
| `:enter` | Enter |
| `:backspace` | Backspace |
| `:f1` - `:f12` | Function keys |
### key-match?
```clojure
(key-match? msg pattern)
```
Internal function used by `key=` to match patterns.
### key->str
```clojure
(key->str msg)
```
Convert key message to string representation.
**Example:**
```clojure
(key->str [:key {:char \a}]) ;; => "a"
(key->str [:key :enter]) ;; => "enter"
(key->str [:key {:ctrl true :char \c}]) ;; => "ctrl+c"
(key->str [:key {:alt true :char \x}]) ;; => "alt+x"
```
---
## tui.terminal
Low-level terminal control functions.
### get-terminal-size
```clojure
(get-terminal-size)
```
Get the terminal dimensions.
**Returns:** Map with `:width` and `:height` keys
**Example:**
```clojure
(require '[tui.terminal :as term])
(term/get-terminal-size)
;; => {:width 120 :height 40}
```
### raw-mode!
```clojure
(raw-mode!)
```
Enter raw terminal mode. Disables echo and line buffering.
### restore!
```clojure
(restore!)
```
Restore terminal to original state.
### alt-screen!
```clojure
(alt-screen!)
```
Enter the alternate screen buffer.
### exit-alt-screen!
```clojure
(exit-alt-screen!)
```
Exit the alternate screen buffer.
### clear!
```clojure
(clear!)
```
Clear the screen and move cursor to home position.
### render!
```clojure
(render! s)
```
Render a string to the terminal.
**Parameters:**
- `s` - String to render (typically from `tui.render/render`)
### Input Functions
```clojure
(init-input!) ;; Initialize input reader
(close-input!) ;; Close input reader
(input-ready?) ;; Check if input available (non-blocking)
(read-char) ;; Read single character (blocking)
(read-available) ;; Read all available characters
(read-char-timeout ms) ;; Read with timeout
```
---
## tui.ansi
ANSI escape codes and text styling utilities.
### style
```clojure
(style text & {:keys [fg bg bold dim italic underline inverse strike]})
```
Apply multiple styles to text.
**Parameters:**
- `text` - String to style
- `:fg` - Foreground color
- `:bg` - Background color
- `:bold` - Boolean
- `:dim` - Boolean
- `:italic` - Boolean
- `:underline` - Boolean
- `:inverse` - Boolean
- `:strike` - Boolean
**Example:**
```clojure
(require '[tui.ansi :as ansi])
(ansi/style "Error" :fg :red :bold true)
(ansi/style "Warning" :fg :yellow :bg :black :underline true)
```
### Color Functions
```clojure
(fg color text) ;; Set foreground color
(bg color text) ;; Set background color
(fg-256 n text) ;; 256-color foreground (0-255)
(bg-256 n text) ;; 256-color background (0-255)
(fg-rgb r g b text) ;; True color foreground (24-bit)
(bg-rgb r g b text) ;; True color background (24-bit)
```
**Example:**
```clojure
(ansi/fg :red "Error")
(ansi/bg :yellow "Highlighted")
(ansi/fg-256 208 "Orange")
(ansi/fg-rgb 255 128 0 "True color orange")
```
### String Utilities
```clojure
(visible-length s) ;; Get visible length (excludes ANSI codes)
(pad-right s width) ;; Pad with spaces on right
(pad-left s width) ;; Pad with spaces on left
(pad-center s width) ;; Center within width
(truncate s max-width) ;; Truncate with ellipsis
```
**Example:**
```clojure
(ansi/visible-length "\e[31mRed\e[0m") ;; => 3
(ansi/pad-right "Hi" 10) ;; => "Hi "
(ansi/pad-center "Hi" 10) ;; => " Hi "
(ansi/truncate "Hello World" 8) ;; => "Hello..."
```
### Cursor Control
```clojure
(cursor-to row col) ;; Move cursor to position (1-indexed)
(cursor-up n) ;; Move cursor up n lines
(cursor-down n) ;; Move cursor down n lines
(cursor-forward n) ;; Move cursor right n columns
(cursor-back n) ;; Move cursor left n columns
```
### Constants
```clojure
clear-screen ;; Clear entire screen
clear-line ;; Clear current line
clear-to-end ;; Clear from cursor to end of screen
cursor-home ;; Move cursor to home (1,1)
hide-cursor ;; Hide cursor
show-cursor ;; Show cursor
enter-alt-screen ;; Enter alternate screen buffer
exit-alt-screen ;; Exit alternate screen buffer
cursor-save ;; Save cursor position
cursor-restore ;; Restore cursor position
reset ;; Reset all attributes
```
### Box Drawing Characters
```clojure
ansi/box-chars
;; => {:rounded {:tl "╭" :tr "╮" :bl "╰" :br "╯" :h "─" :v "│"}
;; :single {:tl "┌" :tr "┐" :bl "└" :br "┘" :h "─" :v "│"}
;; :double {:tl "╔" :tr "╗" :bl "╚" :br "╝" :h "═" :v "║"}
;; :heavy {:tl "┏" :tr "┓" :bl "┗" :br "┛" :h "━" :v "┃"}
;; :ascii {:tl "+" :tr "+" :bl "+" :br "+" :h "-" :v "|"}}
```
### Color Maps
```clojure
ansi/fg-colors ;; Map of color keywords to ANSI codes
ansi/bg-colors ;; Map of color keywords to ANSI codes
ansi/attrs ;; Map of attribute keywords to ANSI codes
```
---
## Custom Async Commands
In `tui.core`, you can create custom async commands by returning functions:
```clojure
;; Custom command that fetches data
(defn fetch-data-cmd []
(fn []
;; This runs asynchronously
(let [result (http/get "https://api.example.com/data")]
{:type :data-loaded :data (:body result)})))
(defn update-fn [model msg]
(cond
(tui/key= msg "f")
[{:loading true} (fetch-data-cmd)]
(= (:type msg) :data-loaded)
[{:loading false :data (:data msg)} nil]
:else
[model nil]))
```
The function must:
1. Take no arguments
2. Return a message (any Clojure value)
3. The returned message will be passed to your update function
---
## Summary
| Namespace | Purpose |
|-----------|---------|
| `tui.core` | Main runtime with Elm architecture and async commands |
| `tui.render` | Hiccup to ANSI rendering |
| `tui.input` | Key input parsing |
| `tui.terminal` | Low-level terminal control |
| `tui.ansi` | ANSI codes and text utilities |