init
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
# Clojure TUI
|
||||
|
||||
A Clojure TUI (Terminal User Interface) framework inspired by [Bubbletea](https://github.com/charmbracelet/bubbletea), using the Elm Architecture with Hiccup for views.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Hiccup DSL (view returns hiccup) │ ← User-facing API
|
||||
├─────────────────────────────────────┤
|
||||
│ Layout Engine (calculates sizes) │ ← Constraint solving
|
||||
├─────────────────────────────────────┤
|
||||
│ Render (hiccup → ANSI string) │ ← Colors, styles
|
||||
├─────────────────────────────────────┤
|
||||
│ Terminal (raw mode, input, output) │ ← Platform abstraction
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The Elm Architecture
|
||||
|
||||
Every app has three parts:
|
||||
|
||||
```clojure
|
||||
;; Model - your application state
|
||||
(def initial-model {:count 0})
|
||||
|
||||
;; Update - handle messages, return [new-model command]
|
||||
(defn update-model [model msg]
|
||||
(cond
|
||||
(tui/key= msg "q") [model tui/quit]
|
||||
(tui/key= msg :up) [(update model :count inc) nil]
|
||||
:else [model nil]))
|
||||
|
||||
;; View - render model as hiccup
|
||||
(defn view [{:keys [count]}]
|
||||
[:col
|
||||
[:text {:bold true} "Counter"]
|
||||
[:text (str "Count: " count)]
|
||||
[:text {:fg :gray} "Press up to increment, q to quit"]])
|
||||
```
|
||||
|
||||
## Hiccup Elements
|
||||
|
||||
| Element | Description | Attributes |
|
||||
|---------|-------------|------------|
|
||||
| `:text` | Styled text | `:fg` `:bg` `:bold` `:dim` `:italic` `:underline` `:inverse` |
|
||||
| `:row` | Horizontal layout | `:gap` |
|
||||
| `:col` | Vertical layout | `:gap` |
|
||||
| `:box` | Bordered container | `:border` `:title` `:padding` |
|
||||
| `:space` | Empty space | `:width` `:height` |
|
||||
|
||||
### Colors
|
||||
|
||||
`:fg` and `:bg` accept: `:black` `:red` `:green` `:yellow` `:blue` `:magenta` `:cyan` `:white` `:gray` and bright variants.
|
||||
|
||||
### Borders
|
||||
|
||||
`:border` accepts: `:rounded` `:single` `:double` `:heavy` `:ascii`
|
||||
|
||||
### Padding
|
||||
|
||||
`:padding` accepts: `n` (all sides), `[v h]` (vertical, horizontal), or `[top right bottom left]`
|
||||
|
||||
## Running Examples
|
||||
|
||||
### With Clojure CLI
|
||||
|
||||
```bash
|
||||
# Counter - basic Elm architecture
|
||||
clojure -A:dev -M -m examples.counter
|
||||
|
||||
# Timer - async commands (tick)
|
||||
clojure -A:dev -M -m examples.timer
|
||||
|
||||
# List selection - cursor navigation, multi-select
|
||||
clojure -A:dev -M -m examples.list-selection
|
||||
|
||||
# Spinner - animated loading
|
||||
clojure -A:dev -M -m examples.spinner
|
||||
|
||||
# Views - multi-screen state machine
|
||||
clojure -A:dev -M -m examples.views
|
||||
|
||||
# HTTP - async HTTP requests
|
||||
clojure -A:dev -M -m examples.http
|
||||
```
|
||||
|
||||
### With Babashka (limited)
|
||||
|
||||
The full async runtime requires `core.async`. For Babashka, use `tui.simple`:
|
||||
|
||||
```clojure
|
||||
(require '[tui.simple :as tui])
|
||||
|
||||
;; Same API, but no async commands (tick, http, etc.)
|
||||
(tui/run {:init initial-model
|
||||
:update update-model
|
||||
:view view})
|
||||
```
|
||||
|
||||
## Built-in Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `tui/quit` | Exit the program |
|
||||
| `(tui/tick ms)` | Send `:tick` message after ms |
|
||||
| `(tui/batch cmd1 cmd2)` | Run commands in parallel |
|
||||
| `(tui/sequentially cmd1 cmd2)` | Run commands in sequence |
|
||||
| `(fn [] msg)` | Custom async command |
|
||||
|
||||
## Key Matching
|
||||
|
||||
```clojure
|
||||
(tui/key= msg "q") ;; Character
|
||||
(tui/key= msg :enter) ;; Special key
|
||||
(tui/key= msg :up) ;; Arrow
|
||||
(tui/key= msg [:ctrl \c]) ;; Control combo
|
||||
(tui/key= msg [:alt \x]) ;; Alt combo
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
tui/
|
||||
core.clj # Full async runtime (core.async)
|
||||
simple.clj # Simple sync runtime (Babashka-compatible)
|
||||
render.clj # Hiccup → ANSI
|
||||
terminal.clj # Raw mode, input/output
|
||||
input.clj # Key parsing
|
||||
ansi.clj # ANSI codes, colors
|
||||
examples/
|
||||
counter.clj
|
||||
timer.clj
|
||||
list_selection.clj
|
||||
spinner.clj
|
||||
views.clj
|
||||
http.clj
|
||||
```
|
||||
|
||||
## Differences from Bubbletea
|
||||
|
||||
| Bubbletea (Go) | Clojure TUI |
|
||||
|----------------|-------------|
|
||||
| String views | Hiccup views |
|
||||
| Lipgloss styling | Inline `:fg` `:bold` attrs |
|
||||
| `tea.Cmd` functions | Vector commands `[:tick 100]` |
|
||||
| Imperative builder | Declarative data |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user