Documentation
¶
Overview ¶
Package help renders key-binding hints in two shapes:
- Model — the one-line footer the app shell paints into the statusbar's left slot. In minimal mode (the default) it is just the "? help" affordance; in verbose mode bindings are tight-packed inline until they overflow, and the affordance is appended when they do. The affordance is the source of truth for whether the help key does anything: when it isn't drawn, the key is inert.
- Overlay — the modal reference the affordance opens: a bordered, scrollable, searchable list of every binding the active screen exposes, grouped into Sections. See overlay.go.
The split is deliberate. A footer answers "what can I press right now" in the space of one line, and stops being able to answer it somewhere around a dozen bindings; the overlay answers "what can I press at all", which needs grouping and room to scroll. Trying to make one shape do both is what the expanded footer panel was, and it inherited the footer's flat binding list — the part that doesn't scale.
Components that want to contribute their own bindings can implement the Provider interface; the parent collects bindings from the focused child and passes them in via SetBindings before rendering.
Index ¶
- Constants
- func Compile(groups ...[]key.Binding) []key.Binding
- func Flatten(secs []Section) []key.Binding
- type ClosedMsg
- type Model
- func (m Model) AffordanceSpan(width int) (start, w int, ok bool)
- func (m Model) Count() int
- func (m Model) Minimal() bool
- func (m Model) Open() bool
- func (m *Model) SetBindings(b []key.Binding)
- func (m *Model) SetMinimal(b bool)
- func (m *Model) SetOpen(b bool)
- func (m Model) ShortView() string
- func (m Model) ShortViewBudget(width int) (line string, consumed int, overflow bool)
- type Options
- type Overlay
- func (o *Overlay) BlurFilter()
- func (o Overlay) Bounds() geom.Rect
- func (o *Overlay) FocusFilter() tea.Cmd
- func (o Overlay) Help() []key.Binding
- func (o Overlay) Init() tea.Cmd
- func (o Overlay) IsCapturingKeys() bool
- func (o Overlay) Query() string
- func (o Overlay) Rect() geom.Rect
- func (o Overlay) Sections() []Section
- func (o *Overlay) SetRect(r geom.Rect)
- func (o *Overlay) SetSections(secs []Section)
- func (o *Overlay) SetTitle(s string)
- func (o Overlay) Update(msg tea.Msg) (Overlay, tea.Cmd)
- func (o Overlay) View() string
- type OverlayKeys
- type OverlayOptions
- type Provider
- type Section
- func CompileSections(secs []Section) []Section
- func Group(title string, bindings ...key.Binding) Section
- func Qualify(owner string, secs []Section) []Section
- func Sections(secs ...Section) []Section
- func SectionsOf(parts ...any) []Section
- func Suppress(claimed []key.Binding, secs []Section) []Section
- type Sectioned
Constants ¶
const ( SectionNavigate = "Navigate" // SectionScroll is the horizontal axis, which is the pane's (rule 25). SectionScroll = "Scroll" // SectionFilter narrows what is displayed; SectionSearch finds within // it. Components that do one call it that; logview and tree do both // and keep the distinction. SectionFilter = "Filter" SectionSearch = "Search" // SectionSelect is marking (rule 32) — the keys and the click that // build a selection. SectionSelect = "Select" // SectionSort is column sorting. SectionSort = "Sort" // SectionExpand is opening and closing branches in a tree or inspector. SectionExpand = "Expand" // SectionView changes how content is rendered rather than which part of // it is on screen — wrap, follow. SectionView = "View" // SectionEdit is typing into a field or flipping a toggle. SectionEdit = "Edit" // SectionSubmit is committing or abandoning — a form, a confirm modal. SectionSubmit = "Submit" // SectionTabs is switching between tabbed bodies. SectionTabs = "Tabs" )
The section vocabulary. Groups are named by what the keys *do*, not by what holds them — a heading naming the owner ends up over every binding that owner has, which is how "Multi-select" came to sit above a table's scroll keys. Owners are a qualifier instead (see Qualify), applied only when more than one of them is on screen.
Components share these names so a group means the same thing wherever it appears: "Navigate" is cursor movement in a list, a table and a tree, and a user who has read it once has read it everywhere.
const OwnerWidth = 20
OwnerWidth is the widest an owner prefix may be before it is truncated. A qualifier repeats on every one of that owner's headings, so it has to stay short enough not to become the widest thing in the column.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ClosedMsg ¶ added in v0.25.0
type ClosedMsg struct{}
ClosedMsg is emitted when the overlay asks to be dismissed — its Close key, or a press outside its bounds. The host clears its own "overlay is up" flag on receipt; the overlay holds no visibility state of its own, matching pkg/confirm and pkg/alert.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model renders the footer strip. Call SetBindings whenever the active binding set changes; both render methods read from the same compiled list. Whether the overlay is open is the host's state, mirrored here via SetOpen so the affordance can say "close".
func (Model) AffordanceSpan ¶ added in v0.18.0
AffordanceSpan reports where the "? help" / "? close" affordance sits within the footer line rendered at width: its start offset in cells and its width. ok is false when no affordance is drawn. The app shell uses it to route a click there to the same toggle the help key drives.
The offset is not simply "the end of the line": minimal mode renders the affordance first and pads after it, while the verbose flow appends it last. Getting this from one place keeps a click landing on the glyph the user sees.
func (*Model) SetBindings ¶
SetBindings replaces the footer's binding list, deduped by keys.
func (*Model) SetMinimal ¶
SetMinimal flips minimal-footer mode at runtime. See Options.Minimal.
func (*Model) SetOpen ¶ added in v0.25.0
SetOpen tells the footer whether the overlay is up, which is all the affordance needs to know to say "close" instead of "help".
func (Model) ShortView ¶
ShortView renders the current bindings as a single inline line — "key desc <sep> key desc <sep> ..." — using KeyStyle and DescStyle.
The separator and the space between each key and its description are rendered through DescStyle so that any background color set on DescStyle extends across the whole line with no gaps. When embedding in a colored status bar, give KeyStyle and DescStyle the same Background as the bar.
func (Model) ShortViewBudget ¶
ShortViewBudget renders the footer line fitting within width visible cells. In minimal mode the line is the affordance alone. Otherwise bindings are tight-packed inline until the next one would not fit, and the affordance is appended on overflow.
consumed reports how many bindings were placed on the line. overflow reports whether any were dropped — in minimal mode, whether there are any at all, since none of them are shown. Width 0 or less skips budgeting and falls back to ShortView.
type Options ¶
type Options struct {
// KeyStyle is applied to the key column (left side of each pair).
KeyStyle lipgloss.Style
// DescStyle is applied to the description column.
DescStyle lipgloss.Style
// ShortSeparator is placed between bindings in ShortView. Defaults to
// " • ".
ShortSeparator string
// Minimal collapses the footer to just the "? help" / "? close"
// affordance regardless of how many bindings the model holds — the
// inline strip is hidden and pressing the help key is the only way
// to see hints. Set via SetMinimal at runtime.
Minimal bool
}
Options configures the footer. Zero-value fields fall back to defaults.
type Overlay ¶ added in v0.25.0
type Overlay struct {
// contains filtered or unexported fields
}
Overlay is the expanded key-binding reference: a bordered, scrollable, optionally searchable modal listing every binding the active screen exposes, grouped into sections.
It sizes itself to its content and centers inside whatever rect it is given, so a host composes it with layout.Sized alone — no layout.Center wrapper, the same shape pkg/alert uses in autosize mode:
layout.ZStack(base, layout.Sized(&s.keys))
Under pkg/app none of that is the screen's problem: the shell owns the overlay, opens it on HelpKey, and routes every key and mouse event to it while it is up.
func NewOverlay ¶ added in v0.25.0
func NewOverlay(opts OverlayOptions) Overlay
NewOverlay constructs the modal. Call SetSections to give it content and SetRect to place it.
func (*Overlay) BlurFilter ¶ added in v0.25.0
func (o *Overlay) BlurFilter()
BlurFilter returns input from the search field to the body.
func (Overlay) Bounds ¶ added in v0.25.0
Bounds returns the rect the modal actually occupies, which is what a host tests a click against to decide it landed outside.
func (*Overlay) FocusFilter ¶ added in v0.25.0
FocusFilter moves input to the search field.
func (Overlay) Help ¶ added in v0.25.0
Help returns the bindings the overlay itself responds to, for the footer beneath it. The close binding comes first: it is the one key a user who opened this by accident needs.
func (Overlay) Init ¶ added in v0.25.0
Init satisfies the component shape; the overlay starts nothing.
func (Overlay) IsCapturingKeys ¶ added in v0.25.0
IsCapturingKeys reports whether the search field is swallowing keys.
func (Overlay) Rect ¶ added in v0.25.0
Rect returns the bounds the overlay was last given (not the smaller rect it centered itself into — see Bounds).
func (Overlay) Sections ¶ added in v0.25.0
Sections returns the compiled groups the overlay is showing.
func (*Overlay) SetRect ¶ added in v0.25.0
SetRect treats r as the outer bounds — typically the body area the shell hands the overlay — measures the content, and centers itself inside them.
func (*Overlay) SetSections ¶ added in v0.25.0
SetSections replaces the binding groups and resets scroll to the top. Empty sections and bindings with no help text are dropped, and a key already listed in an earlier section is not repeated — the same dedupe-by-keys rule Compile applies within one group, extended across them so a screen restating a global doesn't print it twice.
type OverlayKeys ¶ added in v0.25.0
type OverlayKeys struct {
Search key.Binding
Top, Bottom key.Binding
Close key.Binding
Pane pane.Keys
}
OverlayKeys is the overlay's keymap. Vertical scroll comes from the embedded pane and its viewport (rule 25); the overlay itself binds only search, the top/bottom jumps and close.
func DefaultOverlayKeys ¶ added in v0.25.0
func DefaultOverlayKeys() OverlayKeys
DefaultOverlayKeys returns the overlay's stock keymap.
func (*OverlayKeys) FillDefaults ¶ added in v0.25.0
func (k *OverlayKeys) FillDefaults()
FillDefaults fills any zero-valued binding with its DefaultOverlayKeys counterpart, so partial overrides work without restating every field.
type OverlayOptions ¶ added in v0.25.0
type OverlayOptions struct {
// Title sits on the pane's top-left border slot. Defaults to "keys".
Title string
// Searchable embeds a filter on the pane's first inner row. Typing
// reduces the list to matching bindings — on a thirty-binding screen
// "mark" is a faster route to the four marking keys than reading.
Searchable bool
// KeyStyle is applied to the key column, DescStyle to the
// description, SectionStyle to each section heading.
KeyStyle lipgloss.Style
DescStyle lipgloss.Style
SectionStyle lipgloss.Style
// EmptyStyle is applied to the "no matching keys" line.
EmptyStyle lipgloss.Style
// Pane pass-throughs. See pkg/pane.Options for defaults.
ActiveColor lipgloss.TerminalColor
InactiveColor lipgloss.TerminalColor
ActiveBorder lipgloss.Border
InactiveBorder lipgloss.Border
Glyphs glyph.Set
SlotBrackets pane.SlotBracketStyle
// FilterRule styles the line separating the inline filter row from the
// content — an inline filter has no border of its own to light up, so
// the rule carries the "input goes here" signal (rule 27).
FilterRuleActive lipgloss.Style
FilterRuleInactive lipgloss.Style
// Filter configures the embedded filter. Ignored when Searchable=false.
Filter filter.Options
// Keys is the overlay's keymap. Leave zero to use DefaultOverlayKeys.
Keys OverlayKeys
}
OverlayOptions configures the modal. Zero-value fields fall back to defaults; start from theme.HelpOverlay() to fill in the color tokens.
type Provider ¶
Provider is implemented by components that want to surface extra key bindings in the help overlay when focused.
type Section ¶ added in v0.25.0
Section is a named group of bindings. Grouping is the whole reason the overlay exists: a screen composed of an app shell, a focus.Group and three components can easily reach thirty bindings, and thirty bindings in one flat list is a wall of text whether it is drawn in a footer or a modal. Sections say where each key comes from — "Global", "Results", "Filter" — which is the question a user reading the list actually has.
func CompileSections ¶ added in v0.25.0
CompileSections drops empty groups and bindings with no help text, and removes a binding repeated *within* one group.
Deduping stops at the group boundary on purpose. Two panes on one screen bind ↑/k to "up" in each of them, and those are not duplicates — they are the same verb aimed at different components, and dropping the second leaves a pane looking as though it cannot be scrolled. The one genuine overlap, a screen restating the shell's globals, is handled by Suppress, which the host applies with the bindings it actually owns.
func Group ¶ added in v0.25.0
Group builds a section list, dropping any group whose bindings are all empty. Components build their sections with it so an unconfigured feature — a list that isn't markable, a table with no sortable column — contributes no heading rather than an empty one.
func Qualify ¶ added in v0.25.0
Qualify prefixes each section title with an owner — "files · Navigate".
Only worth doing when more than one owner is on screen: with a single component the owner is not in question, and repeating it on every heading is noise. focus.Group applies this rule for the screens it holds.
The owner is normalized first, because the natural source for it is a pane's title and a pane title is often "name · hint" ("files · / to filter"). The hint is an affordance for the pane, not part of its name, and carrying it into every heading is what turns a qualifier into a paragraph — so everything from the first "·" on is dropped, and what survives is truncated to OwnerWidth.
func Sections ¶ added in v0.25.0
Sections assembles a component's groups, discarding the empty ones.
func SectionsOf ¶ added in v0.25.0
SectionsOf collects sections from a mixed list of parts, in order. A part may be a Sectioned (contributes its own groups), anything with a Help() []key.Binding (contributes one unnamed group), a Section, or a []Section. Anything else is skipped.
This is how a screen composes: the same shape as building Help() from its components, with the grouping kept.
func (s *Screen) HelpSections() []help.Section {
return help.SectionsOf(&s.table, help.Group("Deployments", s.verbs()...))
}
func Suppress ¶ added in v0.25.0
Suppress removes from secs any binding whose keys are already claimed elsewhere, and drops the groups that empties.
The app shell applies it with its own globals: screens list q and t in their Help() by convention, and a shell that prepends a Global group would otherwise print them twice under two headings. It takes the claimed bindings explicitly rather than assuming the first group owns everything — only keys that really are app-wide should silence a component's.
type Sectioned ¶ added in v0.25.0
type Sectioned interface {
HelpSections() []Section
}
Sectioned is the interface a component, a composite (focus.Group) or a screen implements to describe its bindings as groups rather than as one flat list. Anything that doesn't implement it still works: the host wraps its Help() in a single unnamed Section.