Documentation
¶
Overview ¶
Package build constructs live tuilib components and a layout.Node tree from the YAML config. The output is owned by the screen, which holds the component pointers for state preservation across theme swaps.
Index ¶
- func ApplyData(c *Component, data any, th theme.Theme)
- func ApplyStreamLine(c *Component, line string, th theme.Theme)
- func Substitute(s string, sel Selection) string
- func SubstituteAll(argv []string, sel Selection, prompts map[string]string) []string
- func SubstituteCursor(s string, cursor Selection) string
- func SubstituteScreen(s *cfg.Screen, components map[string]*cfg.Component, ...) (*cfg.Screen, map[string]*cfg.Component, map[string]*cfg.Source, error)
- type Component
- type Kind
- type Selection
- type Tree
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyData ¶
ApplyData maps a data source response onto a bound component. Component shape and binding fields decide how the response is consumed:
- list Cfg.Item (dot-path to display string)
- table Column.Value (dot-path per column)
- inspector field.Path (dot-path per field; static Value preserved when Path is empty)
The iterable root is selected via Cfg.Source's root path (already applied in screen.Model before this is called) so data is the already-rooted value. All three updates happen in place; tuilib's SetItems/SetRows/SetFields preserve cursor + filter + InitialDepth pre-expansion across refreshes.
func ApplyStreamLine ¶
ApplyStreamLine handles one line from a streaming source bound to a non-logview component. Logview-bound streams are handled directly in screen.handleStream (just Append the line); this function exists for the cases that need parsing + projection.
Two table modes, decided by whether Cfg.RowKey is set:
- Ring buffer (no RowKey): prepend each event as a new row, trimmed to Cfg.MaxRows. The live-tape pattern — chat, log overlays, recent-trades feeds.
- Keyed upsert (RowKey set): each event identifies the row it updates via Cfg.RowKey. Matching key → update in place; unseen key → append. The L1 order-book / status-grid pattern.
In both modes, lines that don't parse as JSON or that project to all-empty cells are skipped silently — that's how diagnostic / handshake frames ("(connecting to …)", an empty subscription_succeeded confirmation) drop out of the live data view. Color rules apply per cell exactly as they do on a fetch-driven table.
func Substitute ¶
Substitute resolves ${selection.*} and ${env.*} tokens in s against the given Selection. Used by push-site `bind:` resolution to turn a template like `${selection.Namespace}` into the focused row's actual namespace value before that value is passed into a destination source's parameter binder.
func SubstituteAll ¶
SubstituteAll runs ${selection.*}/${env.*}/${prompt.*} substitution on every entry in argv and returns a new slice. Used by action dispatch — the run argv references the focused row's selection AND any prompt values entered moments before dispatch. Pass nil for prompts when there were none.
func SubstituteCursor ¶
SubstituteCursor resolves both ${cursor.*} (against the live cursor Selection) AND every other namespace (env, prompt-less) so a cursor bind template like `${cursor.Name}-${env.CLUSTER}` composes cleanly. Selection tokens pass through as literals — this is the runtime path, not the push-time one, and no push-site sel is in scope.
func SubstituteScreen ¶
func SubstituteScreen(s *cfg.Screen, components map[string]*cfg.Component, sources map[string]*cfg.Source, sel Selection, params map[string]string) (*cfg.Screen, map[string]*cfg.Component, map[string]*cfg.Source, error)
SubstituteScreen returns deep-copied Screen + Components + Entries with every ${selection*} token replaced from sel. Original config is left untouched, so each push can re-substitute against a fresh selection. Leaf-kind entries go through the same substitution so a child's URL / headers / body can reference the parent row.
When params is non-nil, every cloned leaf entry that declares `parameters:` ALSO has BindLeafParams called against the subset of params it actually declares. This is how the explicit push-site bind: block feeds into the destination screen's parameterized sources. Missing required params surface as an error so the caller (tryPush) can pop an alert instead of building a broken screen.
Operator entries (filter, sort, …) are cloned without substitution — they don't carry templated string fields and the expression language is bind-time, not screen-time.
Pass nil for params to skip parameter binding (single-screen New and initial multi-screen construction — no push site context). Parameterized sources in that path will be left with unresolved ${params.*} templates and will fail at fetch with a clear URL.
Types ¶
type Component ¶
type Component struct {
Cfg *cfg.Component
Kind Kind
// Exactly one of these is non-nil based on Kind.
List *list.Model
Table *table.Model
Logview *logview.Model
Tree *tree.Model
Inspector *inspector.Model
Textview *textview.Model
// StreamRows is the ring buffer used by KTable components bound to
// a streaming source. Newest events first; trimmed to Cfg.MaxRows
// (defaulted to 100 for streaming bindings) on every append. nil
// for non-streaming tables and non-table kinds.
StreamRows []any
}
Component is a live, themed component pointer plus the originating config — kept so SetTheme can rebuild the same component against a new theme.
func NewComponent ¶
NewComponent builds a Component from a config leaf and the active theme.
type Selection ¶
type Selection struct {
// String is the primary representation: a list's selected item, or a
// table's first cell. Drives bare ${selection}.
String string
// Cells are the full row of cells for a table source. Drives
// ${selection.N} (1-based) and ${selection.COLNAME}.
Cells []string
// Columns are the parallel column titles for Cells. Used to resolve
// ${selection.COLNAME} to the right cell.
Columns []string
}
Selection is the data captured from a source component (list or table) when an on_enter binding fires. It seeds the ${selection} token in the pushed screen's config.
type Tree ¶
type Tree struct {
Root *cfg.Node
Components map[string]*Component
Order []string // names, in the order encountered while walking Root
}
Tree owns the live components and the layout config they're wired into. Components are keyed by the name used in the layout's `component:` refs; Order keeps an iteration order for fanout (Update/SetTheme/Help/etc.).
func Build ¶
Build instantiates every component defined in the config (lazily — only names referenced by the layout are built) and wires the layout tree.
func (*Tree) RenderNode ¶
RenderNode walks the config tree producing a live layout.Node tree. Component leaves are resolved by name through Tree.Components.