app

package
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

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

func New(base Screen, th theme.Theme, tier theme.Tier, themes []theme.Theme) Model

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) Init

func (m Model) Init() tea.Cmd

func (Model) Update

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

func (Model) View

func (m Model) View() tea.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

func (m Model) WithOptions(o Options) Model

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

type ThemeChangedMsg struct {
	Theme theme.Theme
	Tier  theme.Tier
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL