D.A.B.Tv0.0.17 Tutorial API DABT Tools ↗ GitHub ↗

Markup: pages, cache & validation

lib/markup/tui_markup.sh, lib/markup/tui_cache.sh, lib/markup/tui_validate.sh - the XML page loader, its record/replay cache, and the validator that checks pages before an app starts. Guide: ../guide/markup.md. ← API index for the full module list and a task-oriented tour with examples.

Functions return 0 unless their entry says otherwise.

Pages

Function Summary
tui.load Parses a markup page and builds its panes and widgets through tui.* calls. Nothing is drawn.
tui.goto Switches to another page: clears the current UI, loads FILE (from the page cache when valid) and repaints in one frame.
tui.reset_ui Clears the whole UI and leaves an empty full-screen root pane. tui.goto calls it.
tui.load_cached Like tui.load, but replays the page from its recorded call log when it is cached and unchanged, and records it otherwise.

tui.load

tui.load FILE

Parses a markup page and builds its panes and widgets through tui.* calls. Nothing is drawn.

Returns: 1 and a message on stderr when FILE can’t be read.

Notes

  • Loads the framework’s default theme first, then the page’s <theme> files.
  • Does not validate. tui.start validates before loading; call tui.validate.files yourself when loading pages another way.
  • Does not use the page cache and does not reset the current UI; use tui.goto to switch pages.

tui.goto

tui.goto FILE

Switches to another page: clears the current UI, loads FILE (from the page cache when valid) and repaints in one frame.

Parameters

  • FILE: relative paths resolve against the current page’s folder.

Notes

  • Everything page-scoped is dropped: panes, widgets, timers, watches, tui.exec instances, the modal, the footer, --page bindings. Tick listeners from tui.tick.add and overlays are kept.
  • The previous page is pushed onto the history for tui.action.back (up to 30 entries).
  • Reloading the same page keeps the focused widget and cursor when that widget still exists.
  • The page’s on_visit function runs on every visit, also when the page is replayed from the cache.
  • Fires the page hook with the resolved path.

Example

open_settings() { tui.goto settings.xml; }

tui.reset_ui

tui.reset_ui

Clears the whole UI and leaves an empty full-screen root pane. tui.goto calls it.

Notes

  • Removes panes, widgets, pane output, styles, timers, watches, tui.exec instances, the modal, dialogs, the footer and page-scoped bindings.
  • Keeps tick listeners, overlays, toasts, the theme class table, app-wide bindings and settings.
  • Clears the screen immediately.

tui.load_cached

tui.load_cached FILE

Like tui.load, but replays the page from its recorded call log when it is cached and unchanged, and records it otherwise.

Notes

  • “Unchanged” means the page and every <include> have the mtimes they had when recorded. Callback scripts are re-sourced on every load, so edits to them apply without invalidating the cache.
  • on_visit is never recorded: it runs fresh every time.

Page cache

A loaded page is recorded as the list of tui.* calls it made and replayed on later visits, as long as the page and its includes keep their mtimes. Why and how: ../design/write-ahead-logging-and-replay.md. Cache keys are absolute, normalized paths.

Function Summary
tui.cache.valid Returns 0 when FILE has a recorded page and neither it nor any of its includes changed since, else 1.
tui.cache.record Loads FILE with recording on and stores the call log and a signature of its files.
tui.cache.replay Rebuilds a page by replaying its recorded call log. Returns 1 when nothing is recorded for FILE.
tui.cache.signature Prints path=mtime; for every file, sorted by path, as one line without a newline. Used as the cache validity key.
tui.cache.deps_of Appends FILE and every file it includes, recursively, to the array named ARRAY_NAME, as absolute paths.
tui.cache.dump_dir Writes every recorded page to DIR, three files per page (.key, .cache, .sig).
tui.cache.load_dir Reads pages written by tui.cache.dump_dir and drops every entry that is no longer valid.
tui.cache.disk_dir Prints the folder of the persistent page cache, $TUI_HOME/cache/pages, without a newline.
tui.cache.warm_with_spinner Records pages into the cache in a background worker while showing the D.A.B.T logo and a progress bar.
tui.cache.init Wraps the builder functions so page loads can be recorded. Called once when tui.sh is sourced; never call it again.
tui.cache.cleanup Removes the temporary stylesheet stamp folder. Called on exit.

tui.cache.valid

tui.cache.valid FILE

Returns 0 when FILE has a recorded page and neither it nor any of its includes changed since, else 1.

Notes

  • FILE must be the absolute, normalized path used as the cache key.
  • Runs one stat per dependency file.

tui.cache.record

tui.cache.record FILE

Loads FILE with recording on and stores the call log and a signature of its files.

Notes

  • Builds the page as a side effect, exactly like tui.load.

tui.cache.replay

tui.cache.replay FILE

Rebuilds a page by replaying its recorded call log. Returns 1 when nothing is recorded for FILE.

Notes

  • Does not check whether the recording is still valid; call tui.cache.valid first.

tui.cache.signature

tui.cache.signature FILE...

Prints path=mtime; for every file, sorted by path, as one line without a newline. Used as the cache validity key.

tui.cache.deps_of

tui.cache.deps_of FILE ARRAY_NAME

Appends FILE and every file it includes, recursively, to the array named ARRAY_NAME, as absolute paths.

Notes

  • Unreadable files and files already in the array are skipped.

Example

local -a deps=()
tui.cache.deps_of "$page" deps

tui.cache.dump_dir

tui.cache.dump_dir DIR

Writes every recorded page to DIR, three files per page (.key, .cache, .sig).

Notes

  • Creates DIR. Existing files for other pages are left alone.

tui.cache.load_dir

tui.cache.load_dir DIR

Reads pages written by tui.cache.dump_dir and drops every entry that is no longer valid.

Notes

  • A missing DIR is not an error.

tui.cache.disk_dir

tui.cache.disk_dir

Prints the folder of the persistent page cache, $TUI_HOME/cache/pages, without a newline.

Notes

  • dabt clear-cache deletes it.

tui.cache.warm_with_spinner

tui.cache.warm_with_spinner PAGE...

Records pages into the cache in a background worker while showing the D.A.B.T logo and a progress bar.

Notes

  • Used by tui.start_cached before the app starts. The worker runs with its output discarded; its stderr goes to a temporary folder.
  • Loads the recorded pages into this process when done.

tui.cache.init

tui.cache.init

Wraps the builder functions so page loads can be recorded. Called once when tui.sh is sourced; never call it again.

tui.cache.cleanup

tui.cache.cleanup

Removes the temporary stylesheet stamp folder. Called on exit.

Validation

tui.start and tui.start_cached validate every page before the terminal is taken over. Errors abort the start (dabt --ignore-invalid-xml or TUI_IGNORE_INVALID_XML=1 starts anyway and shows a notification); warnings are only logged. TUI_VALIDATE=0 skips validation. A clean result is remembered in $TUI_HOME/cache/validated, so only the first start after a change pays for the check.

The default rules live in lib/markup/tui_validate_rules.sh and use the same registration functions an app can call to add its own.

Function Summary
tui.validate.files Validates pages and their includes, replacing any earlier findings.
tui.validate.page Validates one page, adding to the current findings. Ids are checked per page.
tui.validate.report Prints every finding, then a N error(s), M warning(s) summary. Prints nothing when there are no findings.
tui.validate.log Writes every finding to the app log (tui.log) with level error or warn.
tui.validate.messages Formats every finding into the array _TV_LINES, one sentence each, in the order found.

tui.validate.files

tui.validate.files PAGE...

Validates pages and their includes, replacing any earlier findings.

Returns: 1 when any error was found, else 0 (warnings don’t count).

Sets: TUI_V_ERRORS, TUI_V_WARNINGS.

Notes

  • Reports unknown tags, unclosed or mismatched tags, missing and invalid attributes, conflicting attributes, duplicate ids, widgets in missing or split panes, grid cells out of bounds, and missing script/theme/include/page files, each with file, line and column.
  • tui.start and tui.start_cached run it automatically before the terminal is taken over.

Example

tui.validate.files config/*.xml || { tui.validate.report >&2; exit 1; }

See also: tui.validate.report

tui.validate.page

tui.validate.page FILE

Validates one page, adding to the current findings. Ids are checked per page.

Notes

tui.validate.report

tui.validate.report

Prints every finding, then a N error(s), M warning(s) summary. Prints nothing when there are no findings.

Output: one line per finding, e.g. erroneous configuration in config/home.xml line 12 col 5: <button> needs a pane. Warnings start with questionable configuration. Errors are red and warnings yellow when stderr is a terminal.

Notes

  • Writes to stdout; redirect to stderr yourself: tui.validate.report >&2.

tui.validate.log

tui.validate.log

Writes every finding to the app log (tui.log) with level error or warn.

tui.validate.messages

tui.validate.messages

Formats every finding into the array _TV_LINES, one sentence each, in the order found.

Notes

  • The formatter behind tui.validate.report and tui.validate.log.

Writing rules

Function Summary
tui.validate.tag Declares tags the loader understands. Any other tag is reported as unknown.
tui.validate.container Declares tags that may have children (<tag>…</tag>). Implies tui.validate.tag.
tui.validate.widget Declares widget tags. Their id and pane are recorded for the cross-reference checks (duplicate ids, missing panes).
tui.validate.self_closing Declares tags that must be written self-closing: <tag … />.
tui.validate.require Declares attributes that must be present and non-empty on TAG. Repeated calls add to the list.
tui.validate.enum Restricts an attribute to a list of values. * applies it to every tag.
tui.validate.int Requires an attribute to be a whole number of at least MIN (which may be negative). * applies it to every tag.
tui.validate.conflict Reports an error when both attributes are given on TAG. WHY is added to the message.
tui.validate.needs Declares that ATTR only has an effect when OTHER="VALUE"; using it otherwise is reported.
tui.validate.parent Restricts which tags may enclose TAG. - stands for the top level of the page.
tui.validate.parent_split Declares that ATTR only has an effect inside a <pane split="SPLIT">.
tui.validate.rule Registers a custom check.
tui.validate.attr Inside an element rule: stores the value of attribute NAME in REPLY. Returns 1 when the attribute is absent.
tui.validate.here Inside an element rule: stores the location of the current element (or of ATTR on it) in REPLY as file\|line\|col.
tui.validate.error Inside an element rule: reports an error at the current element, or at attribute ATTR.
tui.validate.warn Inside an element rule: reports a warning at the current element, or at attribute ATTR. Warnings are logged but never stop a start.
tui.validate.error_at Reports an error at LOC (file\|line\|col; col may be empty). For end rules, which have no current element.
tui.validate.warn_at Reports a warning at LOC (file\|line\|col).

tui.validate.tag

tui.validate.tag TAG...

Declares tags the loader understands. Any other tag is reported as unknown.

tui.validate.container

tui.validate.container TAG...

Declares tags that may have children (<tag>…</tag>). Implies tui.validate.tag.

tui.validate.widget

tui.validate.widget TAG...

Declares widget tags. Their id and pane are recorded for the cross-reference checks (duplicate ids, missing panes).

tui.validate.self_closing

tui.validate.self_closing TAG...

Declares tags that must be written self-closing: <tag … />.

tui.validate.require

tui.validate.require TAG ATTR...

Declares attributes that must be present and non-empty on TAG. Repeated calls add to the list.

tui.validate.enum

tui.validate.enum TAG|* ATTR "a|b|c"

Restricts an attribute to a list of values. * applies it to every tag.

Example

tui.validate.enum pane border "none|single|double|heavy"

tui.validate.int

tui.validate.int TAG|* ATTR MIN

Requires an attribute to be a whole number of at least MIN (which may be negative). * applies it to every tag.

tui.validate.conflict

tui.validate.conflict TAG ATTR_A ATTR_B [WHY]

Reports an error when both attributes are given on TAG. WHY is added to the message.

tui.validate.needs

tui.validate.needs TAG ATTR OTHER VALUE

Declares that ATTR only has an effect when OTHER="VALUE"; using it otherwise is reported.

tui.validate.parent

tui.validate.parent TAG PARENT...

Restricts which tags may enclose TAG. - stands for the top level of the page.

tui.validate.parent_split

tui.validate.parent_split TAG ATTR SPLIT

Declares that ATTR only has an effect inside a <pane split="SPLIT">.

tui.validate.rule

tui.validate.rule page|element|end FN

Registers a custom check.

Parameters

  • page: FN runs once before a page is walked.
  • element: FN runs for every element, with TUI_V_FILE, TUI_V_LINE, TUI_V_COL, TUI_V_TAG, TUI_V_RAW, TUI_V_SELFCLOSE, TUI_V_DEPTH, TUI_V_PARENT_TAG, TUI_V_PARENT_ID, TUI_V_PARENT_SPLIT, TUI_V_GRANDPARENT_SPLIT set. Read attributes with tui.validate.attr.
  • end: FN runs after the walk, with TUI_V_PAGE and the maps TUI_V_PANES, TUI_V_PANE_SPLIT, TUI_V_WIDGETS, TUI_V_WIDGET_PANE, TUI_V_WIDGET_PANE_AT (locations are file|line|col).

Returns: 1 for another kind.

Notes

  • Report with tui.validate.error / tui.validate.warn.
  • Register rules after sourcing tui.sh and before tui.start.
  • A clean validation is remembered per page set and file mtimes. After adding a rule, pages that already passed are not checked again until a page or include changes; delete $TUI_HOME/cache/validated (or run dabt clear-cache) to force it.

Example

no_empty_title() {
    [[ "$TUI_V_TAG" == pane ]] || return 0
    tui.validate.attr title && [[ -z "$REPLY" ]] && tui.validate.warn "empty title" title
    return 0
}
tui.validate.rule element no_empty_title

tui.validate.attr

tui.validate.attr NAME

Inside an element rule: stores the value of attribute NAME in REPLY. Returns 1 when the attribute is absent.

tui.validate.here

tui.validate.here [ATTR]

Inside an element rule: stores the location of the current element (or of ATTR on it) in REPLY as file|line|col.

tui.validate.error

tui.validate.error MSG [ATTR]

Inside an element rule: reports an error at the current element, or at attribute ATTR.

tui.validate.warn

tui.validate.warn MSG [ATTR]

Inside an element rule: reports a warning at the current element, or at attribute ATTR. Warnings are logged but never stop a start.

tui.validate.error_at

tui.validate.error_at LOC MSG

Reports an error at LOC (file|line|col; col may be empty). For end rules, which have no current element.

tui.validate.warn_at

tui.validate.warn_at LOC MSG

Reports a warning at LOC (file|line|col).