App, screens and layout¶
A config has four top-level blocks. data: is the data layer, read by
both wrangl and tui-builder. tui: is the presentation layer, read
only by tui-builder. actions: is the write side, kept apart from
data: so nothing that re-fetches can ever re-run a mutation.
app:
title: Pods
data:
sources:
pods: {type: http, url: http://localhost:8001/api/v1/pods, root: items, refresh: 5s}
tui:
components:
pods_table:
type: table
source: pods
columns:
- {title: Name, value: metadata.name}
- {title: Phase, value: status.phase}
screen:
layout: {component: pods_table}
actions:
delete_pod:
run: [kubectl, delete, pod, "${inputs.name}"]
inputs: {name: {required: true}}
Top level¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
app |
map | — | — | App shell settings. See app. |
data |
map | — | — | The data layer. Holds sources:, the single map of every leaf source and operator. See data. |
tui |
map | — | — | Components and screens. See tui. Ignored by wrangl. |
actions |
map of action | — | — | Named units of work, bound to keys by screens. See actions.md. |
data¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
sources |
map of source | — | — | Every data entry, keyed by name. Each entry's type: picks a leaf kind (sources.md) or an operator (pipelines.md). Components and wrangl address entries by these names. |
app¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
title |
string | — | — | The terminal window's title, set when the app starts. The breadcrumb shows each screen's own title:. |
version |
string | — | — | Shown on the right of the statusbar. |
theme |
string | first built-in | — | The starting palette. The TUI_BUILDER_THEME environment variable overrides it for one run; when neither is set, the theme: in your own $XDG_CONFIG_HOME/tuilib/config.yaml is used. An unknown name falls through to the next of those, then to the first theme. Names: dark, accent, light, solarized, nord, dracula, gruvbox, catppuccin-mocha, catppuccin-latte, tokyo-night, rose-pine, rose-pine-dawn, one-dark, monokai, everforest-dark, base16-ocean, base16-eighties, base16-railscasts, base16-tomorrow-night. |
glyphs |
map | — | — | Overrides the single-character marks components draw. See app.glyphs. |
borders |
map | — | — | Border shapes and how a pane title meets its border. See app.borders. |
actions_key |
string | a |
— | Opens the action menu. - turns the menu off, which also turns off right-click targeting and menu shortcuts. No action may bind this key. |
theme_key |
string | t |
— | Cycles through every built-in palette, live. - pins the app to theme:. No action may bind this key. |
output_key |
string | o |
— | Opens the output console: every statusbar message and everything a subprocess streams, with a badge counting events and a picker for killing running work. - disables it. No action may bind this key. |
quit_key |
string | q |
— | Quits from the root screen. ctrl+c always quits too. Can be rebound but not turned off. |
suspend_key |
string | ctrl+z |
— | Suspends the app to the shell. - turns suspending off. |
help_key |
string | ? |
— | Opens the key overlay. Can be rebound but not turned off. |
mouse |
string | click |
— | click makes components clickable; off leaves the mouse to the terminal, so click-drag selects text without holding shift. |
double_click |
duration | your tuilib config's double_click_ms, else tuilib's |
— | How quickly a second click must follow to count as a double click. |
esc_pops |
bool | true |
— | esc goes back one screen. false leaves going back to actions. |
output |
map | — | — | The output console's scrollback cap and export directory. See app.output. |
actions_title |
string | Actions |
— | The action menu's title. |
form_spacing |
int | 0 |
— | Blank lines between fields in action-input forms and boot prompts. |
keys |
map | — | — | Remaps navigation keys in every list, table and tree. See app.keys. |
prompts |
list | — | — | A form shown at boot, before any screen renders. See app.prompts. |
env |
list | — | — | Environment variables the config depends on, checked at load. See app.env. |
glyphs: and borders: apply to every palette, not just the one
theme: names: cycling themes changes color, never vocabulary.
app.glyphs¶
Every field is optional; an unset one keeps tuilib's default.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
cursor |
string | tuilib's | — | Marks the focused row in list, logview and the action menu. |
mark |
string | tuilib's | — | Marks a selected row where markable: is on. |
expand_open |
string | tuilib's | — | Disclosure arrow for an open node in tree and inspector. |
expand_closed |
string | tuilib's | — | Disclosure arrow for a closed node. |
rule |
string | tuilib's | — | The horizontal line under an inline filter. |
scroll_thumb |
string | tuilib's | — | Vertical scrollbar thumb. |
scroll_track |
string | tuilib's | — | Vertical scrollbar track. |
h_scroll_thumb |
string | tuilib's | — | Horizontal scrollbar thumb. |
h_scroll_track |
string | tuilib's | — | Horizontal scrollbar track. |
sort_asc |
string | tuilib's | — | Follows the sorted column's title, ascending. |
sort_desc |
string | tuilib's | — | Follows the sorted column's title, descending. |
column_sep |
string | tuilib's | — | Divides table columns. |
placeholder |
string | tuilib's | — | Fills a row a windowed table hasn't received yet. |
mask |
string | tuilib's | — | Drawn for each typed character in a masked input or prompt. |
activity_ok |
string | tuilib's | — | Shown when a row's work finished. |
activity_fail |
string | tuilib's | — | Shown when a row's work failed. |
activity_changed |
string | tuilib's | — | Shown when a row's work finished and changed it. |
Validation: each value must be exactly one character. A wider glyph shifts every row it's drawn on, so it's rejected.
app.borders¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
active |
string | normal |
— | Border shape of the focused component. |
inactive |
string | normal |
— | Border shape of unfocused components. Focus is signalled by color, so set this differently from active only if you want panes to change weight on focus. |
overlay |
string | thick |
— | Border shape of what floats over a screen: the key overlay, confirm and alert dialogs, the action menu. |
slot_brackets |
string | none |
— | How a pane's title meets the border line: none (── title ──), corners (┐ title ┌, reads as a tab), tees (─┤ title ├─). |
Validation: shapes are one of normal, rounded, thick,
double, hidden, block, ascii; slot_brackets is one of none,
corners, tees.
app:
glyphs: {cursor: ">", mark: "*"}
borders: {active: rounded, inactive: rounded, overlay: double, slot_brackets: corners}
app.output¶
The console's colors come from the theme; these are its other settings.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
max_records |
int | tuilib's | — | How many entries the console keeps before dropping the oldest. |
export_dir |
string | tuilib's | — | Where the console writes an exported log. |
app.keys¶
Remaps navigation keys in every list, table and tree, by binding name. Each value is one key or a list of keys, and replaces that binding's default keys. There are no per-component keymaps: a remap is a habit, not a per-pane choice.
| Binding | Default | On |
|---|---|---|
up, down |
↑/k, ↓/j |
list, table, tree |
top, bottom |
g, G |
list, table, tree |
half_up, half_down |
ctrl+u, ctrl+d |
list, table |
filter |
/ |
list, table; on a tree, its / search |
mark, mark_all, clear_marks, mark_range |
x, A, D, X |
list, table, tree with markable: |
sort_prev, sort_next, sort_dir |
[, ], s |
table |
col_prev, col_next |
shift+left, shift+right |
table |
app:
keys:
up: [k, up]
down: [j, down]
filter: /
Validation: names must be from the table; each needs at least one
key; a key can't be one the shell or the screen already owns (the
quit, suspend, help, console, theme and menu keys, ctrl+c, esc,
tab, shift+tab, r).
Shell keys¶
Validation: quit_key and help_key can't be -. Two shell
features can't share a key, and none can be esc, tab, shift+tab or
r. mouse is click or off; double_click is a positive duration;
form_spacing and output.max_records can't be negative.
app.prompts¶
An ordered list of fields collected in a form before the first screen
renders. Each value is written to the environment variable named by
key, so the rest of the config reads it as ${env.KEY}. If that
variable is already set, the field starts with its value. Cancelling the
form exits the program.
A prompt is a key plus the same field vocabulary an action input uses
(see actions.md).
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
key |
string | — | required | The environment variable the value is written to. |
type |
string | string |
— | The data type: string, int, bool or duration. It also picks the widget: bool is a yes/no toggle, anything else a text input, unless options: makes it a select. |
label |
string | the key | — | The field's caption. |
default |
string | — | not with required |
The starting value. For bool, "true" / "false"; with options:, one of the options. |
required |
bool | false |
not with default |
The form won't submit while the field is empty. On a select, nothing starts highlighted, so the answer is picked on purpose. |
description |
string | — | — | One-line summary, shown by wrangl --describe. |
placeholder |
string | — | text inputs | Hint shown inside an empty text input. |
options |
list of string | — | not with mask |
Turns the field into a select over these values. |
mask |
bool | false |
not with options |
Shows typed characters as bullets. Display only: the value is still the real string everywhere else. |
order |
int | 0 |
— | Sort position in the form. Ties break alphabetically. |
validate |
expr | — | — | An expression over value, true when the answer is acceptable; the form won't submit until it is. See action inputs. |
invalid |
string | not accepted |
validate |
The message shown when validate is false. |
Validation: key is required; type must be one of the four data
types; required and default are mutually exclusive; mask and
options conflict; validate must compile, and invalid needs it.
app:
prompts:
- {key: GH_USER, label: GitHub user, required: true}
- {key: SORT, options: [updated, stars], default: updated}
- {key: GH_TOKEN, mask: true}
app.env¶
Declares environment variables the config reads with ${env.NAME}, so a
missing one fails at load with a clear message instead of a 401 or a
double-slash URL at first fetch. Applies to wrangl too.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
name |
string | — | required | The variable name, e.g. AWX_TOKEN. |
required |
bool | false |
not with default |
Load fails if the variable is unset. Every missing variable is reported in one message. |
default |
string | — | not with required |
Set into the environment when the variable is unset. |
description |
string | — | — | Shown in the missing-variable error, so the user knows what to set. |
A ${env.X} that is referenced, unset and not declared (here or as a
prompt key) prints a warning at load, not an error: an empty value is
legitimate for optional headers and flags.
app:
env:
- {name: AWX_HOST, required: true, description: "Tower base URL, e.g. https://awx.example.com"}
- {name: DEBUG, default: "0"}
tui¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
components |
map of component | — | — | Every component, keyed by name. Layouts place them by name. See components.md. |
screen |
screen | — | not with screens |
Single-screen mode: the one screen the app shows. |
screens |
map of screen | — | not with screen; needs initial |
Multi-screen mode: screens keyed by name, reached by push actions. |
initial |
string | — | required with screens |
The name of the root screen in screens:. |
Validation: exactly one of screen: and screens: is set;
initial: names a defined screen.
Screens¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
title |
template | — | — | Shown in the breadcrumb. On a pushed screen it can use ${selection…} from the row that opened it. |
layout |
node | — | one of layout / tabs |
The root of the screen's layout tree. |
actions |
list of binding | — | not with tabs |
Action bindings: which actions this screen offers, on which keys, fed by which component's selection. See actions.md. |
tabs |
list | — | one of layout / tabs |
Makes this a tabbed screen. See tabs. |
Validation: each component may be placed at most once per screen (per tab, on a tabbed screen).
A pushed screen's sources can take values from the row that opened it,
either by ${selection…} tokens in their URL, argv or body, or through
the push binding's bind:, which fills their parameters:. See
actions.md.
tui:
initial: users
screens:
users:
title: Users
layout: {component: users_list}
actions:
- {key: enter, action: open_repos, from: users_list, bind: {user: "${selection}"}}
repos:
title: "${selection}'s repos"
layout: {component: repos_table}
Tabs¶
A screen can hold tabs instead of one layout. Each tab is a small screen of its own, with a label, a layout and actions, shown one at a time under a strip.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
label |
string | — | required | The tab's name in the strip. Unique within the screen. |
layout |
node | — | required | The tab's layout tree. |
actions |
list of binding | — | — | The tab's own bindings; from: names a component in this tab. |
The strip is set on the screen, beside tabs::
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
strip_pos |
string | top |
tabs |
top or bottom. |
initial |
string | the first tab | tabs |
The label of the tab the screen opens on. |
prev_key |
string | shift+left |
tabs |
Switches to the previous tab. - turns it off. |
next_key |
string | shift+right |
tabs |
Switches to the next tab. - turns it off. |
number_keys |
bool | true |
tabs |
1–9 jump straight to a tab. |
Keys and clicks go to the active tab; tab / shift+tab move focus
within it. A tab first fetches when it's first opened, then keeps
polling while hidden, and switching back doesn't refetch. Each tab keeps
its own sources, so a source bound in two tabs is fetched twice, as on
two pushed screens; put a cache operator in front to share one fetch.
The breadcrumb shows the screen's title:, since switching tabs isn't
moving between screens. A push from inside a tab keeps the tabs
underneath it.
tui:
screen:
title: Cluster
initial: Services
tabs:
- label: Pods
layout: {component: pods_table}
actions:
- {key: enter, action: describe_pod, from: pods_table, bind: {name: "${selection}"}}
- label: Services
layout: {component: services_table}
Validation: tabs: and layout: are exclusive, and a tabbed screen
has no actions: of its own. Each tab needs a unique label and a
layout. initial must be a label, strip_pos is top or bottom, and
a switch key can't be one the shell or the screen already owns. The
strip fields are errors without tabs:. The same component may appear in
two tabs; each builds its own copy.
Layout nodes¶
A node is exactly one of a vertical stack, a horizontal stack, an overlay, or a component.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
vstack |
list of item | — | exactly one per node | Children stacked top to bottom. |
hstack |
list of item | — | exactly one per node | Children side by side, left to right. |
zstack |
map | — | exactly one per node | Draws overlay on top of base; both fill the node. |
component |
string | — | exactly one per node | A component name from tui.components. |
Stack items¶
An item is a node plus a sizing hint.
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
flex |
int | 1 |
set one of flex / fixed |
Share of the space left after fixed items. Used when neither is set. |
fixed |
int | — | set one of flex / fixed |
Exact size in rows (vstack) or columns (hstack). An input or toggle in a vstack is always 3 rows. |
Validation: setting both flex and fixed on one item is an error.
zstack¶
| Field | Type | Default | Valid on/with | What it does |
|---|---|---|---|---|
base |
node | — | required | The node underneath. |
overlay |
node | — | required | The node drawn on top. |
layout:
vstack:
- fixed: 10
component: summary
- flex: 1
hstack:
- {flex: 2, component: pods_table}
- {flex: 1, component: pod_logs}