Plugins & hooks
lib/plugin/tui_plugin.sh, lib/tui_home.sh - discovering, installing, enabling/disabling and reloading plugins, the hook system they use to extend the framework, and the per-app metadata file. Guide: ../guide/plugins.md. ← API index for the full module list and a task-oriented tour with examples.
Files live under ~/.config/DABT/ (TUI_HOME): plugins/ (TUI_PLUGINS_DIR) and apps/<TUI_APP_NAME>/ (TUI_APP_CONF: dabt.conf, keybinds.xml, settings.conf, app.meta, logs/). A plugin is a NAME.plugin.sh file or a NAME/plugin.sh folder; it defines plugin.NAME.on_enable, and optionally on_disable and on_remove. Plugins are trusted code: they run in the app’s shell with its permissions. Functions return 0 unless their entry says otherwise.
Plugins
| Function | Summary |
|---|---|
tui.plugin.scan |
Discovers plugins (NAME.plugin.sh files and NAME/plugin.sh folders) and registers them, disabled. |
tui.plugin.dir_add |
Adds a folder for tui.plugin.scan to search. Adding a folder twice is a no-op. |
tui.plugin.add |
Registers one plugin file or folder, disabled. |
tui.plugin.install |
Security-scans a plugin, copies it into ~/.config/DABT/plugins and registers it, disabled. |
tui.plugin.remove |
Disables a plugin, runs its plugin.NAME.on_remove, unregisters it and forgets its saved state. |
tui.plugin.enable |
Enables a plugin: enables its requirements first, sources its file and runs plugin.NAME.on_enable. |
tui.plugin.disable |
Disables a plugin: disables plugins that require it first, runs plugin.NAME.on_disable, then undoes everything it registered, newest first. |
tui.plugin.toggle |
Disables an enabled plugin, or enables any other. The choice is saved. |
tui.plugin.reload |
Re-reads a plugin after its file changed: disables it, drops its plugin.NAME.* functions, re-reads the metadata, and enables it again if it was enabled. Returns 1 for an unknown plugin. |
tui.plugin.startup |
Scans for plugins (once) and enables each one whose saved state, or # default: when never set, is on. Called by tui.init. |
tui.plugin.list |
Prints every registered plugin in discovery order. |
tui.plugin.info |
Prints a readable description: title, version, description, id, state (with the error), source, file, author and requirements. Returns 1 for an unknown plugin. |
tui.plugin.get |
Prints one field of a plugin: title, version, description, author, requires, state, source, file or error. Returns 1 for any other field. |
tui.plugin.enabled |
Returns 0 when the plugin is enabled, else 1. |
tui.plugin.root |
Prints the plugin folder for a folder plugin, or the file for a single-file plugin. Returns 1 for an unknown plugin. |
tui.plugin.dir |
Prints the folder that contains the plugin file. Use it to find assets shipped next to the plugin. Returns 1 for an unknown plugin. |
tui.plugin.files |
Prints every file of the plugin, one per line (recursive for a folder plugin). Returns 1 for an unknown plugin. |
tui.plugin.stats |
Prints size figures and what the plugin currently has registered. |
tui.plugin.config |
Reads or writes a plugin’s own saved setting, stored as plugin.NAME.KEY in dabt.conf. |
tui.plugin.own |
Adds something to what disabling the current plugin undoes. Only has an effect while a plugin is being enabled. |
tui.plugin.scan
tui.plugin.scan
Discovers plugins (NAME.plugin.sh files and NAME/plugin.sh folders) and registers them, disabled.
Notes
- Folders, in order:
~/.config/DABT/plugins(TUI_PLUGINS_DIR), the app’splugins/,share/plugins(when DABT is not installed), then each folder inTUI_PLUGIN_DIRS(colon-separated). Add more withtui.plugin.dir_addfirst. - When two folders hold a plugin of the same name, the first one wins; the other fails to register.
tui.initruns it throughtui.plugin.startup.
tui.plugin.dir_add
tui.plugin.dir_add DIR
Adds a folder for tui.plugin.scan to search. Adding a folder twice is a no-op.
Notes
- Adding a folder before the first scan replaces the default folder list; add the defaults yourself if you still want them.
tui.plugin.add
tui.plugin.add PATH [SOURCE]
Registers one plugin file or folder, disabled.
Parameters
PATH: aNAME.plugin.shfile or a folder containingplugin.sh.SOURCE:builtin,apporuser(default), shown in lists.
Returns: 1 when the file can’t be read or another plugin already has the name.
Sets: TUI_PLUGIN_NAME on success, TUI_PLUGIN_ERROR on failure.
Notes
- Reads only the metadata comments in the first 40 lines (
# plugin:,# title:,# version:,# description:,# author:,# requires:,# default: on|off). The file is sourced only when enabled. - The name is lowercased, with characters other than
a-z 0-9 _turned into_.
tui.plugin.install
tui.plugin.install PATH [--force] [--strict] [--no-scan]
Security-scans a plugin, copies it into ~/.config/DABT/plugins and registers it, disabled.
Options
--force: replace an installed plugin of the same name; with--strict, install despite high-risk findings.--strict: refuse when the scan finds high-risk issues.--no-scan: skip the scan.
Returns: 1 on failure, with the reason in TUI_PLUGIN_ERROR.
Sets: TUI_PLUGIN_WARNING to a one-line scan summary when there were findings; the full report is in TUI_SCAN_REPORT.
Notes
- Plugins run in the app’s shell with its permissions. The scan flags risky patterns; it is not a sandbox.
See also: tui.scan.run
tui.plugin.remove
tui.plugin.remove NAME
Disables a plugin, runs its plugin.NAME.on_remove, unregisters it and forgets its saved state.
Returns: 1 for an unknown plugin.
Notes
- Files are deleted only for user plugins inside
~/.config/DABT/plugins. Built-in and app plugins are only unregistered and come back on the next scan.
tui.plugin.enable
tui.plugin.enable NAME [--no-save]
Enables a plugin: enables its requirements first, sources its file and runs plugin.NAME.on_enable.
Returns: 1 when the plugin is unknown, a requirement fails, the requirements are circular, or sourcing or on_enable fails. The reason is in TUI_PLUGIN_ERROR.
Notes
- Commands, bindings, hooks, timers, tick listeners, overlays and palette providers registered while it loads are recorded, so disabling undoes them.
- The state is saved as config
plugin.NAME.enabled=1unless--no-saveis given. - Fires the
plugin_enabledhook. - On failure, what the plugin registered so far is undone and its state becomes
error.
tui.plugin.disable
tui.plugin.disable NAME [--no-save]
Disables a plugin: disables plugins that require it first, runs plugin.NAME.on_disable, then undoes everything it registered, newest first.
Returns: 1 for an unknown plugin.
Notes
- The state is saved as
plugin.NAME.enabled=0unless--no-saveis given. - Its functions stay defined until it is removed or reloaded.
- Fires the
plugin_disabledhook.
tui.plugin.toggle
tui.plugin.toggle NAME
Disables an enabled plugin, or enables any other. The choice is saved.
tui.plugin.reload
tui.plugin.reload NAME
Re-reads a plugin after its file changed: disables it, drops its plugin.NAME.* functions, re-reads the metadata, and enables it again if it was enabled. Returns 1 for an unknown plugin.
Notes
- The saved state is not changed.
tui.plugin.startup
tui.plugin.startup
Scans for plugins (once) and enables each one whose saved state, or # default: when never set, is on. Called by tui.init.
Notes
- Set
TUI_NO_PLUGINS=1to skip plugins entirely. - A plugin that fails prints
plugin NAME: REASONon stderr and stays disabled.
tui.plugin.list
tui.plugin.list
Prints every registered plugin in discovery order.
Output: NAME<TAB>STATE<TAB>VERSION<TAB>SOURCE<TAB>TITLE. STATE is enabled, disabled or error; SOURCE is builtin, app or user.
tui.plugin.info
tui.plugin.info NAME
Prints a readable description: title, version, description, id, state (with the error), source, file, author and requirements. Returns 1 for an unknown plugin.
tui.plugin.get
tui.plugin.get NAME FIELD
Prints one field of a plugin: title, version, description, author, requires, state, source, file or error. Returns 1 for any other field.
tui.plugin.enabled
tui.plugin.enabled NAME
Returns 0 when the plugin is enabled, else 1.
tui.plugin.root
tui.plugin.root NAME
Prints the plugin folder for a folder plugin, or the file for a single-file plugin. Returns 1 for an unknown plugin.
tui.plugin.dir
tui.plugin.dir NAME
Prints the folder that contains the plugin file. Use it to find assets shipped next to the plugin. Returns 1 for an unknown plugin.
tui.plugin.files
tui.plugin.files NAME
Prints every file of the plugin, one per line (recursive for a folder plugin). Returns 1 for an unknown plugin.
tui.plugin.stats
tui.plugin.stats NAME
Prints size figures and what the plugin currently has registered.
Output: key=value lines: files, dirs, bytes, lines, functions, commands, binds, hooks, timers, ticks, overlays, providers.
Returns: 1 for an unknown plugin.
tui.plugin.config
tui.plugin.config NAME KEY [VALUE]
Reads or writes a plugin’s own saved setting, stored as plugin.NAME.KEY in dabt.conf.
Notes
- With
VALUE: saves it. Without: prints the stored value (no newline). - To read with a default, use
tui.config.get plugin.NAME.KEY DEFAULT; the third argument here always means “set”.
Example
interval=$(tui.plugin.config clock interval); interval=${interval:-5}
tui.plugin.config clock interval 10
tui.plugin.own
tui.plugin.own TYPE VALUE
Adds something to what disabling the current plugin undoes. Only has an effect while a plugin is being enabled.
Parameters
TYPE:cmd(command id),bind(key spec, plus--pane ID),hook(EVENT FN),every(timer id),tick(function),overlay(draw function),provider(function), orrun(shell code that isevaled on disable).
Notes
- Registrations made through the regular
tui.*calls are recorded automatically; use this for things they don’t cover.
Example
plugin.myplug.on_enable() {
stty -ixon
tui.plugin.own run "stty ixon"
}
Hooks
| Function | Summary |
|---|---|
tui.hook.on |
Registers FN to run when the framework fires EVENT. |
tui.hook.off |
Removes a hook handler. |
tui.hook.fire |
Calls every handler of EVENT with the arguments. Returns 0 when at least one handler returned 0, else 1. |
tui.hook.on
tui.hook.on EVENT FN
Registers FN to run when the framework fires EVENT.
Events
init(aftertui.init),ready(before the first frame),page FILE(after every page switch),resize ROWS COLS,quit(tui.stop),exit(terminal being restored: give back terminal settings and files here),plugin_enabled NAME,plugin_disabled NAME.key NAME: before bindings; a handler that returns0consumes the key.
Notes
- Adding the same
FNtwice for one event is a no-op. Handlers run in registration order. - Available to apps too, not only plugins.
Example
on_page() { tui.log "visited $1"; }
tui.hook.on page on_page
tui.hook.off
tui.hook.off EVENT FN
Removes a hook handler.
tui.hook.fire
tui.hook.fire EVENT [ARG...]
Calls every handler of EVENT with the arguments. Returns 0 when at least one handler returned 0, else 1.
Notes
- Handlers whose function no longer exists are skipped.
- Apps may fire their own events for their plugins.
App metadata
| Function | Summary |
|---|---|
tui.app.meta_get |
Prints a value from the app’s app.meta (no newline), or DEFAULT. |
tui.app.meta_set |
Stores a key in the app’s app.meta and writes the file. |
tui.app.dir |
Prints the app’s config folder, TUI_APP_CONF (~/.config/DABT/apps/<TUI_APP_NAME>). |
tui.app.meta_get
tui.app.meta_get KEY [DEFAULT]
Prints a value from the app’s app.meta (no newline), or DEFAULT.
Notes
- Keys written by
tui.init:name,title,description,dabt_version,app_dir,entry,first_run,last_run,runs.
tui.app.meta_set
tui.app.meta_set KEY VALUE
Stores a key in the app’s app.meta and writes the file.
tui.app.dir
tui.app.dir
Prints the app’s config folder, TUI_APP_CONF (~/.config/DABT/apps/<TUI_APP_NAME>).
