Documentation
¶
Overview ¶
Package app is the root Bubble Tea model: a Screen router (a stack, not nullable dialog pointers - build spec section 4.5) plus the global keymap. It owns no rendering of its own beyond delegating to the top of the stack and the app-wide theme, which every Screen renders with but only this package mutates.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Model ¶
type Model struct {
Theme theme.Theme
Tier theme.Tier
Opts Options
// Width and Height are the live terminal size. Bubble Tea sends a
// WindowSizeMsg on startup and on every resize, so these are the one
// source of truth for layout; nothing in the tree may assume 80x24.
Width int
Height int
// contains filtered or unexported fields
}
Model is the root tea.Model: current theme/tier, terminal size, the screen stack, and the app-wide Options.
func New ¶
New returns a router with base as the only (non-poppable) screen. themes is the full candidate set ThemeSelectedMsg resolves against; pass nil if nothing in this Program ever offers a theme picker.
Options.Mouse starts false here; the launcher sets it from config ([tui] mouse, default true) with the MIVIA_MOUSE environment override, and MouseCaptureMsg changes it live afterwards.
func (Model) View ¶
View renders the top of the stack.
The cockpit holds the alternate screen, which is the only interactive renderer. v2 declares this on the View rather than as a Program option, so the mode is part of the frame and cannot drift from what was drawn. The top screen can hand the surface back (rule 6.3) by reporting ViewFlags.AltScreen = false.
MouseModeCellMotion, not AllMotion: cell motion reports clicks, drags and the wheel, which is everything the transcript needs. AllMotion adds an event for every cursor movement over the surface, and that traffic buys nothing here. Capture is off entirely while the surface is handed back - the terminal's own selection must reach the transcript in scrollback - and when Options.Mouse is off (rule 7.1). The live-drag highlight is painted by each selectable component in its own View (internal/ui/select), so the router adds no overlay.
func (Model) WithOptions ¶
WithOptions sets the app-wide terminal modes and returns the router.
type MouseCaptureMsg ¶ added in v0.1.2
type MouseCaptureMsg struct{ On bool }
MouseCaptureMsg flips the app-wide mouse capture live. The settings screen's "mouse capture" row sends it (bridged through the program); the router applies it and the next View declares the new MouseMode, which the renderer writes as ?1002/?1006 on or off. Turning capture off hands the mouse back to the terminal - native selection and scroll return; turning it on restores in-app drag-select and wheel.
type Options ¶
type Options struct {
// Mouse reports whether the cockpit captures the mouse. Rule 6.5
// makes capture opt-out: mouse capture is the most common friction
// point over SSH and inside tmux, because it kills copy-on-select.
Mouse bool
// FullRepaint forces a complete redraw on resize. Windows Terminal
// and ConPTY coalesce positioned writes wrongly and leave stale
// cells (cockpit-research.md section 4), and a full redraw is the
// recovery. The effect on a real terminal cannot be tested here;
// the decision function and the ClearScreen Cmd are.
FullRepaint bool
}
Options are the app-wide terminal modes. They come from flags and startup probes, not from any Screen, so they live on the router and apply to every frame.
type OwnsQuit ¶
type OwnsQuit interface {
OwnsQuit() bool
}
OwnsQuit is implemented by a pushed screen that manages its own ctrl+c double-press quit guard (UX Rule 1.3) instead of the router's default "a pushed screen quits on the first ctrl+c" behavior. The default fits a quick pick-one-and-go dialog (the theme picker, the session picker), where there is nothing to lose. A screen with real in-flight state - the settings modal's cursor position, filters, and pending saves - should implement this and show its own "press again to quit" warning, the same way the base screen's statusRow does, so a stray ctrl+c cannot discard that state with no warning.
type PopScreenMsg ¶
type PopScreenMsg struct{}
PopScreenMsg asks the router to pop the top screen off the stack. A pop on a one-screen stack (the base screen) is a no-op: the base screen is never dismissed this way.
type PushScreenMsg ¶
type PushScreenMsg struct{ Screen Screen }
PushScreenMsg asks the router to push a new modal screen onto the stack. Emit it as the Msg a Cmd returns; the router applies it and calls the new screen's Init.
type Screen ¶
type Screen interface {
Init() tea.Cmd
Update(tea.Msg) (Screen, tea.Cmd)
View() string
// ViewFlags reports the terminal modes this screen needs on the ONE
// tea.View the router assembles. A Screen cannot return a tea.View,
// so the modes it depends on - today, whether the alternate screen
// is held - travel through this method instead.
ViewFlags() ViewFlags
}
Screen is one pushable unit of the UI: a full base screen (the conversation) or a modal (the theme picker, the transcript pager). Its Init/Update/View mirror tea.Model; Screen is not tea.Model itself so a Screen can be constructed and tested without a running Program.
type ScreenResumedMsg ¶
type ScreenResumedMsg struct{}
ScreenResumedMsg is sent by the router to the newly exposed top screen after a pushed modal screen is popped from the stack.
type ThemeChangedMsg ¶
ThemeChangedMsg is sent by the router to every Screen on the stack after it adopts a new theme, so each Screen (and the components it owns) can update its own copy. Theme/Tier are plain value fields on Model, Screen, and every component - there is no shared pointer - so nothing re-renders with the new theme without this broadcast.
type ThemeSelectedMsg ¶
type ThemeSelectedMsg struct{ Name string }
ThemeSelectedMsg asks the router to adopt a new app-wide theme by name and pop the screen that offered the choice (the theme picker). Theme identity is app-level state no Screen owns, so the message - not a direct field mutation - is how a screen changes it.
type ViewFlags ¶
type ViewFlags struct {
// AltScreen reports whether the screen holds the terminal's whole
// drawing surface. The transcript pager clears it while the
// conversation is handed back to native scrollback
// (cockpit-research.md rule 6.3): one key writes the transcript into
// the scrollback and the terminal must be able to show it.
AltScreen bool
}
ViewFlags are the per-screen terminal mode requests the router honors.