| Bind the terminal backend from the side that renders into it 3cfee15 nandi 17d ago | 1 | # glimmer-tui |
| 2 | |
| 3 | glimmer's **terminal** backend, on the jolt side of the ABI — the namespace |
| 4 | that binds [`libjolttui`](../../crates/jolt-tui) and registers it with |
| 5 | `glimmer.backend`. |
| 6 | |
| 7 | It is [glimmer-vidya](../glimmer-vidya) with a different shared object under |
| 8 | it. The reconciler does not know what it is patching, so the same hiccup that |
| 9 | egui paints as a window paints here as cells: |
| 10 | |
| 11 | ```clojure |
| 12 | (ns myapp |
| 13 | (:require [glimmer.ratom :refer [atom]] |
| 14 | [glimmer.core :as ui] |
| 15 | [glimmer-tui.core])) ; installs this backend |
| 16 | |
| 17 | (defn -main [& _] (ui/run my-app)) |
| 18 | ``` |
| 19 | |
| 20 | ```bash |
| 21 | cargo build --release -p jolt-tui |
| 22 | LD_LIBRARY_PATH=../../target/release jolt -M:counter |
| 23 | ``` |
| 24 | |
| 25 | ## What differs from the window |
| 26 | |
| 27 | Only what a terminal actually forces. |
| 28 | |
| 29 | * **No pictures, no title, no clipboard, no browser.** `glimmer-vidya.core`'s |
| 30 | `frame-rgba!`, `set-title!`, `clipboard-image-png!`, `open-url!` and |
| 31 | `pick-image!` have no answer here and are not defined. |
| 32 | * **Keys instead of a pointer.** `:on-key` is raised on whatever has focus, or |
| 33 | on the window when nothing does — and it is the one event this backend |
| 34 | *bubbles*, because the focused widget is rarely what knows the key's meaning. |
| 35 | `:on-select` and `:on-scroll` join the list; `:on-hover` leaves it. |
| 36 | * **Cells instead of points.** `screen-size` answers columns and rows. |
| 37 | * **A scale for trees written in points.** `:points-per-cell` on `run` divides |
| 38 | the props that are a distance — margins, padding, spacing, width and height |
| 39 | requests — on the way across, so an app laid out for a window is legible in a |
| 40 | terminal without rewriting its numbers. 8 is about right; the default is 1, |
| 41 | for a tree that was written in cells to begin with. |
| 42 | |
| 43 | `after!`, `every!`, `cancel!`, `quit!` and the `dump` family are the same calls |
| 44 | with the same meanings. |
| 45 | |
| 46 | ## Looking at what was painted |
| 47 | |
| 48 | A headless session is a session with the writer taken off the end — same |
| 49 | layout, same painting, same focus ring, no terminal: |
| 50 | |
| 51 | ```clojure |
| 52 | (tui/after! 100 (fn [] (println (tui/screen-str)) (tui/quit!))) |
| 53 | (ui/run my-app :headless [100 34]) |
| 54 | ``` |
| 55 | |
| 56 | `screen-line`, `screen-str` and `screen!` read the grid back; `feed-key!`, |
| 57 | `feed-click!` and `feed-wheel!` drive it. Those are the entry points a real |
| 58 | terminal's input arrives through, so a test types what a person types. |