The app shell¶
pkg/app is the standard frame for a tuilib program: a breadcrumb on top, the
active screen's layout in the middle, a statusbar at the bottom, and every
app-wide behavior around them.
m := app.New(app.Options{
Root: newRootScreen(),
Themes: theme.All(),
Version: "v1.2.0",
ThemeKey: key.NewBinding(key.WithKeys("t"), key.WithHelp("t", "theme")),
Mouse: app.MouseClick,
})
if _, err := tea.NewProgram(m, tea.WithAltScreen()).Run(); err != nil {
log.Fatal(err)
}
app.New resolves the initial theme, calls the root's SetTheme with it,
and returns a tea.Model. You don't pass mouse options to tea.NewProgram;
the shell enables reporting from Init when Mouse asks for it.
Options¶
| Field | Type | Default | Meaning |
|---|---|---|---|
Root |
screen.Screen |
required | The bottom of the navigation stack. |
Themes |
[]theme.Theme |
required | Themes the user cycles through. Themes[0] is the initial theme after resolution (below). |
Version |
string |
"" |
Drawn on the right of the statusbar. |
QuitKey |
key.Binding |
q, ctrl+c |
Quits when the stack is at the root and no screen is capturing keys. |
ThemeKey |
key.Binding |
unset (off) | Cycles themes. Leave zero to pin the app to one theme. |
HelpKey |
key.Binding |
? |
Opens the key overlay. Pass key.NewBinding() to disable. |
SuspendKey |
key.Binding |
ctrl+z |
Suspends to the shell. Ignored on Windows. |
DisableSuspend |
bool |
false |
Turns the suspend key off entirely. |
OutputKey |
key.Binding |
unset (off) | Opens the output console. Setting it is what turns the console on. |
Output |
output.Options |
output.OptionsFrom(theme) |
Console configuration: record cap, export directory, keys. |
ActionsKey |
key.Binding |
unset (off) | Opens the action menu on screens that implement action.Provider. |
Actions |
action.Options |
theme.Actions() |
Menu configuration. |
HelpVerbose |
bool |
false |
Pack the screen's bindings inline in the footer instead of showing only ? help. |
DisableHelpSearch |
bool |
false |
Remove the / search field from the key overlay. |
Mouse |
app.MouseMode |
MouseOff |
MouseClick enables presses, releases, the wheel and drags. |
DoubleClickInterval |
time.Duration |
config file, then 500ms | Window for a second press to count as a double click. |
ThemeEnvVar |
string |
"" |
Env var naming the initial theme, e.g. MYAPP_THEME. |
SkipConfig |
bool |
false |
Don't reorder Themes from the env var and config file. |
DisableAutoEscPop |
bool |
false |
Stop esc from popping the stack. |
Why some keys are opt-in
A key the shell claims is a key no component in any app built on it may
bind. ThemeKey, OutputKey and ActionsKey therefore default to off, and
turning one on is a line the app author writes on purpose.
Global keys¶
| Key | Default | When it acts |
|---|---|---|
| quit | q, ctrl+c |
stack depth is 1 |
| back | esc |
stack depth > 1 (pops the top screen) |
| theme | opt-in | always |
| help | ? |
toggles the key overlay |
| suspend | ctrl+z |
not on Windows |
| output | opt-in | toggles the output console |
| actions | opt-in | the screen implements action.Provider |
All of them are suppressed while the active screen's IsCapturingKeys()
returns true, so they reach a focused text field as ordinary characters.
Screens should list q and t in their own Help() if they like; the shell
removes duplicates of its own globals from the overlay. Don't handle these
keys in a screen.
Initial theme resolution¶
Unless SkipConfig is set, app.New reorders Themes so the first entry
is, in priority order:
- the theme whose
Namematches the env var named byThemeEnvVar, - the
theme:field of$XDG_CONFIG_HOME/tuilib/config.yaml(default~/.config/tuilib/config.yaml), Themes[0]unchanged.
Unknown names fall through silently. The library never creates or writes the config file. See Theming and state.
Statusbar messages¶
Screens post transient feedback by returning a command; the shell paints the statusbar's center slot:
return s, app.Info("Deployment triggered")
return s, app.Error("API request failed")
return s, app.ClearStatus()
Messages clear on the next keypress. The clear runs before the screen handles that key, so a screen can set a fresh message in response to the same key. See Feedback and the console.
Live theme preview¶
app.SetTheme(name) returns a command that switches to the named theme (if
it's in Themes) and rebroadcasts it across the stack. A theme picker can call
it as its cursor moves.
Subprocesses and suspend¶
The shell re-enables mouse reporting after a runner.Run subprocess and after
resuming from ctrl+z, since Bubble Tea's terminal restore doesn't track mouse
state. If you drive tea.ExecProcess or tea.Suspend without the shell, you
have to do that yourself. See Running subprocesses.
Without the shell¶
You can use every component in a bare tea.Model. You then wire the
breadcrumb, statusbar, resize handling, theme rebuilds and mouse translation
yourself. Mouse support in particular needs something to turn tea.MouseMsg
into mouse.Msg; the shell is what does that. Prefer the shell unless you need
a frame it can't express.