Documentation
¶
Overview ¶
Package app is the standard TUI shell: a breadcrumb header, a flex body that renders the active screen's layout, and a statusbar footer. It owns the nav stack, cycles themes, and routes global keys (quit, theme swap) around any screen-owned input focus.
Callers provide a root screen and a theme list; the app handles the rest. Screens implement pkg/screen.Screen and return their own layout trees, so each screen can have a different body composition without any shell changes.
Index ¶
- func ClearStatus() tea.Cmd
- func Error(s string) tea.Cmd
- func ErrorDetail(summary, body string) tea.Cmd
- func ErrorOf(err error) tea.Cmd
- func Info(s string) tea.Cmd
- func InfoDetail(summary, body string) tea.Cmd
- func SetTheme(name string) tea.Cmd
- type Model
- type MouseMode
- type Options
- type OutputClosed
- type SetThemeMsg
- type StatusClearMsg
- type StatusErrorMsg
- type StatusInfoMsg
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClearStatus ¶
ClearStatus returns a command that clears any active statusbar message.
func ErrorDetail ¶ added in v0.19.0
ErrorDetail is InfoDetail's error counterpart. See InfoDetail.
func ErrorOf ¶ added in v0.19.0
ErrorOf posts err as an error message: err.Error() paints the statusbar and the unwrapped %w chain goes to the console, one wrap per line.
Without this the chain gets flattened to its outermost message, because hand-formatting it at every call site is work nobody actually does. An error that wraps nothing degrades to a plain Error, so there is no reason to choose between them.
func InfoDetail ¶ added in v0.19.0
InfoDetail posts an info message whose summary paints the statusbar, as Info does, while body goes to the output console as continuation lines beneath it.
This is the channel for output that was never going to fit in a footer — a command's stderr, a multi-line API response. An empty body behaves exactly like Info, so migrating a call site is mechanical.
Types ¶
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the app shell. Instantiate with New and pass to tea.NewProgram.
func New ¶
New constructs an app shell. By default it reorders Themes via theme.Resolve so Themes[0] reflects the user's config file (and ThemeEnvVar, when set) — pass SkipConfig=true to opt out. The root screen's SetTheme is then called with the resulting Themes[0] so the root renders in the initial palette immediately.
func (Model) Init ¶
Init runs the root screen's Init + OnEnter(nil), and turns on mouse reporting when Options.Mouse asks for it.
func (Model) Theme ¶
Theme exposes the app's current palette for screens that need it outside of SetTheme (rare — most screens just cache the theme they were last told about).
type MouseMode ¶ added in v0.18.0
type MouseMode int
MouseMode selects how much mouse input the app shell enables. It is an enum rather than a bool so a hover tier can be added later without breaking callers who already set the field.
const ( // MouseOff disables mouse reporting entirely, leaving the terminal's // native click-drag text selection intact. This is the default: turning // reporting on takes selection away from the user, so it should be a // decision the app makes rather than something it inherits. MouseOff MouseMode = iota // MouseClick enables cell-motion reporting — presses, releases, the // wheel, and motion while a button is held. Bare pointer movement is // not reported, so nothing re-renders while the pointer merely crosses // the screen. MouseClick )
type Options ¶
type Options struct {
// Root is the root screen — the bottom of the nav stack. Required.
Root screen.Screen
// Themes is the list the user cycles through. At least one entry is
// required; Themes[0] is the initial theme.
Themes []theme.Theme
// Version is rendered on the right side of the statusbar.
Version string
// QuitKey quits the program when the stack depth is 1 and no screen
// is capturing keys. Defaults to "q" (and "ctrl+c").
QuitKey key.Binding
// ThemeKey cycles themes. Leave zero to disable cycling (useful when
// the app is pinned to a single theme).
ThemeKey key.Binding
// HelpKey toggles the expanded help panel. The panel appears as a
// multi-row strip above the statusbar showing every binding the
// active screen currently exposes via Help() — useful when the
// inline hints don't all fit in one row. Defaults to "?". Set to an
// empty binding (key.NewBinding()) to disable the panel.
HelpKey key.Binding
// SuspendKey suspends the program (ctrl+z semantics), returning to the
// shell until the user foregrounds it again. Defaults to "ctrl+z"; see
// DisableSuspend to turn it off.
//
// Bubbletea does not bind this itself — it delivers ctrl+z as an
// ordinary key and expects the app to ask for the suspend — so without
// this the key does nothing. Suspending is unsupported on Windows,
// where the request is ignored.
SuspendKey key.Binding
// DisableSuspend turns off the suspend key entirely.
//
// A zero SuspendKey means "unset" and gets the default, so it cannot
// also mean "disabled" — key.Binding has no way to tell an empty
// binding from an absent one. This flag is the explicit off switch,
// matching DisableAutoEscPop.
DisableSuspend bool
// HelpMaxRows caps how many rows the expanded help panel may grow
// to. Defaults to 6. The panel uses only as many rows as needed to
// fit every binding at the current width, up to this cap.
HelpMaxRows int
// OutputKey opens the app-wide output console (pkg/output) and is the
// single switch for the whole feature: leave it zero and no buffer, no
// statusbar badge and no console screen exist.
//
// Opt-in rather than on-by-default, for the same reason ThemeKey is: it
// claims a key permanently, in every app that links the shell, and a
// key the shell takes is a key no component may ever bind. Spending one
// should be a line the app author writes on purpose.
//
// OutputKey: key.NewBinding(key.WithKeys("o"), key.WithHelp("o", "output"))
//
// The console captures every Info/Error, every InfoDetail/ErrorDetail,
// runner.Result exit statuses, and everything runner.Capture streams.
// Capture itself works with this unset — the calling screen still
// receives every line; you lose the console, not the pipeline.
OutputKey key.Binding
// ActionsKey opens the action menu (pkg/action) for the active screen,
// and is the single switch for the whole feature: leave it zero and no
// menu, no right-click handling and no key exist.
//
// Opt-in for the same reason OutputKey is — a key the shell claims is a
// key no component may ever bind, in every app that links the shell.
//
// ActionsKey: key.NewBinding(key.WithKeys("a"), key.WithHelp("a", "actions"))
//
// A screen supplies its verbs by implementing action.Provider. Screens
// that don't have none, and the key stays inert on them — the hint is
// only advertised where the menu would actually open.
ActionsKey key.Binding
// Actions configures the menu. Leave zero for theme.Actions() against
// the current theme; colors come back from the theme on every swap, as
// everywhere else in the library.
Actions action.Options
// Output configures the console. Leave zero for output.OptionsFrom
// against the initial theme. Non-visual fields (MaxRecords, ExportDir,
// SourceWidth, Keys) survive theme swaps; colors come back from the
// theme, as everywhere else in the library.
Output output.Options
// HelpVerbose restores the legacy footer behavior: bindings are
// tight-packed inline in the statusbar's left slot until they
// overflow. The default (zero value) is minimal mode — the footer
// shows only the "? help" affordance and pressing HelpKey opens the
// expanded panel with every binding. Minimal cuts clutter on screens
// with many bindings (a deep component composition can easily
// produce 15+) at the cost of inline discoverability.
HelpVerbose bool
// Mouse selects how much mouse input the shell enables. Defaults to
// MouseOff, so an app gains mouse support only by asking for it — the
// terminal's own click-drag text selection stops working the moment
// mouse reporting is on, and that trade is the app author's to make.
//
// When set to MouseClick the shell enables cell-motion reporting from
// Init, translates each event into a mouse.Msg (resolving double
// clicks), and forwards it to the active screen. Components hit-test it
// against the rect layout gave them; see pkg/geom and pkg/mouse.
Mouse MouseMode
// DoubleClickInterval is the window in which a second press in the same
// cell counts as a double click. Zero falls back to the user's config
// file, then to mouse.DefaultDoubleClickInterval.
DoubleClickInterval time.Duration
// ThemeEnvVar names an environment variable consulted for the initial
// theme during app.New (e.g. "MYAPP_THEME"). When the var is set to a
// theme's Name, that theme becomes Themes[0]. Empty string disables
// env-var lookup but the user config file is still consulted; see
// SkipConfig to disable both.
ThemeEnvVar string
// SkipConfig disables the automatic theme.Resolve call inside app.New.
// By default app.New reorders Themes so Themes[0] reflects the user's
// $XDG_CONFIG_HOME/tuilib/config.yaml `theme:` field (and ThemeEnvVar,
// when set) — set this to true if you've already called theme.Resolve
// yourself, or if you want to pin the app to Themes[0] regardless.
SkipConfig bool
// DisableAutoEscPop turns off automatic esc→pop handling. When false
// (the default) esc pops the stack whenever depth > 1 and the active
// screen is not capturing keys.
DisableAutoEscPop bool
}
Options configures the app shell.
type OutputClosed ¶ added in v0.19.0
OutputClosed is the value the output console pops with, aliased from pkg/output so a screen matching it in OnEnter needs only this import.
A screen whose OnEnter kicks off a fetch should early-return on it — otherwise glancing at the log silently refetches whatever was underneath:
func (s *Screen) OnEnter(result any) tea.Cmd {
if _, ok := result.(app.OutputClosed); ok {
return nil
}
return s.fetch()
}
type SetThemeMsg ¶
type SetThemeMsg struct{ Name string }
SetThemeMsg asks the app to switch to the named theme and rebroadcast it across the stack. Emit via SetTheme(name) from any screen.
type StatusClearMsg ¶
type StatusClearMsg struct{}
StatusClearMsg asks the app to clear any active statusbar message immediately. Useful for screens that want to wipe a stale message on a non-key event (e.g. a fetch result that resolves cleanly).
type StatusErrorMsg ¶
StatusErrorMsg asks the app to show Text as an error message in the statusbar's center slot. Same auto-clear and Body semantics as StatusInfoMsg. Emit via Error(s) or ErrorDetail(summary, body).
type StatusInfoMsg ¶
StatusInfoMsg asks the app to show Text as an info message in the statusbar's center slot. The message auto-clears on the next KeyMsg (matching the statusbar's own Update behavior). Emit via Info(s) from any screen.
Body is the verbose half: it never touches the statusbar, and goes to the output console (when OutputKey is set) as continuation lines under Text. Emit via InfoDetail.