appshell

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package appshell composes a common interactive-CLI-tool layout — a header, a full-width input, a scrollable content area, and an optional key-hints footer — out of existing widgets, without introducing any new rendering primitive of its own.

Stability: experimental. Its API may change in any minor release.

Example

An appshell frames content with a title, a scrolling area and an input line.

package main

import (
	"fmt"
	"strings"

	"github.com/ows4444/tui/ansi"
	"github.com/ows4444/tui/appshell"
)

func main() {
	m := appshell.New("my app", 40, 5)
	fmt.Println(strings.Contains(ansi.StripANSI(m.View()), "my app"))
}
Output:
true

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Child

type Child interface {
	Update(tui.Msg) (Child, tui.Cmd)
	View() string
}

Child is what a Router holds: anything that can take a message and render. Build one from a widget with Wrap. A Child that also has SetTheme(theme.Theme) Child receives the Router's theme, and one with Bindings() []keymap.Binding lends its bindings to the Router's own.

func Wrap

func Wrap[T interface {
	Update(tui.Msg) (T, tui.Cmd)
	View() string
}](v T) Child

Wrap adapts a widget type T (any value with Update(tui.Msg) (T, tui.Cmd) and View() string) to a Child. If T has SetTheme(theme.Theme) T (see tui.ThemeSetter) or is a tui.Themeable whose SetTheme returns a T, the Router's theme reaches it; if T has Bindings() []keymap.Binding the Router reports them while the child is focused.

type Model

type Model struct {
	Title   string
	Input   textinput.Model
	Content viewport.Model
	Hints   []widgets.Hint
	Theme   theme.Theme
	// contains filtered or unexported fields
}

Model is a composed application shell: a title rendered via widgets.Header, a single-line Input, a scrollable Content viewport, and an optional row of Hints rendered via widgets.KeyHints.

v1 scope: AppShell composes exactly one input field, and that field is always treated as focused — Update always forwards keys to Input (after handling Enter itself), so there's no separate focus-tracking state.

func New

func New(title string, width, contentHeight int) Model

New returns a Model with an Input and a Content viewport sized to width (content height contentHeight), and the Input focused and ready to type into.

func (Model) LayoutNode

func (m Model) LayoutNode() layout.Node

LayoutNode adapts the shell to a layout.Node: the title, the input (which scrolls to fit) and the key hints keep their natural height, and the content fills the space between them. The Model is not changed.

func (Model) Linearize

func (m Model) Linearize() string

Linearize renders the shell as plain text for accessible output (see tui.Linearizer): the title, the input's line, the content's lines, and each key hint as "Key: <key>, <action>".

func (Model) SetTheme

func (m Model) SetTheme(t theme.Theme) Model

SetTheme returns m with t applied to the shell and forwarded to its children: the header reads m.Theme, and the Input's text and placeholder styles are rebuilt from t's Text and Muted roles. The Content viewport renders the caller's own text and has no theme of its own. It makes Model a tui.ThemeSetter, so tui.WithTheme reaches the shell without app code forwarding the theme.

func (Model) Tokens

func (m Model) Tokens() theme.Tokens

Tokens returns the colour tokens the widget renders with: its theme's roles, overridden by any theme.WithTokens(theme.ComponentAppShell, ...) and then by WithTokens.

func (Model) Update

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

Update handles a message. On Enter it emits a SubmitMsg carrying the Input's current value via a Cmd and clears the Input; any other key is forwarded to Input.Update.

func (Model) View

func (m Model) View() string

View renders the shell: Header, Input, Content, and — only when Hints is non-empty — a footer built from widgets.KeyHints, stacked with a layout.Column. With no Hints, the footer row is omitted entirely rather than rendered as a stray empty line.

func (Model) WithTokens

func (m Model) WithTokens(tok theme.Tokens) Model

WithTokens returns m with tok as its per-instance colour override. Nil fields inherit from the theme, so only the roles tok names change; the theme and every other widget are untouched. A second call replaces the first.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is an opt-in composition router for a screen of several children registered by id. It is a value: every method returns the next Router.

Routing rules, see Update: keys go to the focused child only; mouse events go to the child under the pointer (see SetBounds, SetLayout); every other message, ResizeMsg included, is broadcast to all children. The theme is delivered with SetTheme, to each themeable child once.

func NewRouter

func NewRouter() Router

NewRouter returns an empty Router. The first child added has focus.

func (Router) Add

func (r Router) Add(id string, c Child) Router

Add registers c under id, after the children already added. A repeated id replaces that child in place. If SetTheme was called before, c receives the theme now.

func (Router) Bindings

func (r Router) Bindings() []keymap.Binding

Bindings returns the focused child's bindings when it has them, so a help screen follows focus. It makes Router a tui.BindingsProvider.

func (Router) Focus

func (r Router) Focus(id string) Router

Focus gives focus to the child registered as id. An unknown id changes nothing.

func (Router) FocusNext

func (r Router) FocusNext() Router

FocusNext moves focus to the next child, wrapping at the end.

func (Router) FocusPrev

func (r Router) FocusPrev() Router

FocusPrev moves focus to the previous child, wrapping at the start.

func (Router) Focused

func (r Router) Focused() string

Focused returns the id of the focused child, or "" for an empty Router.

func (Router) SetBounds

func (r Router) SetBounds(id string, rect layout.Rect) Router

SetBounds records the rectangle child id occupies, in the same coordinates as the mouse events the Router receives. Unknown ids are recorded too and take effect once a child with that id is added.

func (Router) SetLayout

func (r Router) SetLayout(root layout.Node, size layout.Size) Router

SetLayout takes every child's rectangle from root laid out at size: the node named with the child's id (layout.Named) gives its rectangle. Children with no such node lose their bounds. The rectangles are relative to root's top-left, so the mouse coordinates must be too.

func (Router) SetTheme

func (r Router) SetTheme(t theme.Theme) Router

SetTheme delivers t to every child that takes a theme, once each, and to children added later when they are added. Other children are untouched. It makes Router a tui.ThemeSetter[Router].

func (Router) Update

func (r Router) Update(msg tui.Msg) (Router, tui.Cmd)

Update routes msg. A Tab or Shift+Tab moves focus when WithTabCycle is on. Any other tui.Key goes to the focused child only. A tui.MouseEvent is routed by position (see SetBounds). Everything else, ResizeMsg and ticks included, is broadcast to every child in order; the Cmds are batched.

func (Router) View

func (r Router) View(id string) string

View returns the View of the child registered as id, or "" if unknown. The Router does not lay children out itself; compose the views with package layout.

func (Router) WithTabCycle

func (r Router) WithTabCycle(on bool) Router

WithTabCycle opts in to Tab and Shift+Tab moving focus to the next and previous child (wrapping). Off by default, when Tab goes to the focused child like any other key.

type SubmitMsg

type SubmitMsg struct {
	Value string
}

SubmitMsg is emitted when Enter is pressed, carrying the Input's value at the moment of submission. The Input is cleared as part of handling the key that produced it.

Jump to

Keyboard shortcuts

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