widgets

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package widgets is the component kit of tuigoff. Its components follow the Elm architecture of Bubble Tea: a component is a model with Update(tea.Msg) (T, tea.Cmd) and View() string, its state lives in the model, and what happens in it is reported to the parent as messages.

Conventions

Every component follows the same shape as the models in charm.land/bubbles:

  • a constructor returns a value: NewList(id, items);
  • setters have pointer receivers (SetSize, SetItems, Focus, Blur), and Update has a value receiver and returns the updated model;
  • the parent gives the component its size with SetSize, or by forwarding a tea.WindowSizeMsg to Update; View returns exactly that many lines of that many columns;
  • a component ignores key presses until Focus is called, and mouse events are given in coordinates relative to its top-left cell;
  • keys are key.Binding values collected in a KeyMap field, so an application can rebind them and a help bar can list them (each KeyMap implements help.KeyMap);
  • colours come from the active theme (package theme) when View runs.

Messages instead of callbacks

A component never calls back into its parent. It returns a command that delivers a message, and the parent handles the message in its own Update:

list, cmd = list.Update(msg)
...
case widgets.ItemSelectedMsg:
	if msg.ID == "projects" { return m, openProject(msg.Item) }

Each message carries the ID the component was created with, so a screen with two lists can tell them apart. Asynchronous work is a tea.Cmd that returns a result message; components never start goroutines.

The catalogue of messages:

List         ItemHighlightedMsg, ItemSelectedMsg
Tree         NodeHighlightedMsg, NodeSelectedMsg
Form         FieldChangedMsg, SubmitMsg, CancelMsg, ButtonPressedMsg
Tabs         TabChangedMsg, TabCloseMsg
Modal        ModalDoneMsg
Breadcrumbs  CrumbSelectedMsg

Focus movement

A screen that wants the shell (package nav) to move focus with the arrow keys implements Boundary: the shell asks AtEdge before it turns Up at the top of a list into "go to the breadcrumbs". Components that edit text implement Editor, which suspends application-wide key bindings while a cursor is active.

Framing and layout

Frame draws the bordered, titled box every panel sits in, with the focus colour on its border; Split divides a length into fixed and proportional parts; Fit, Overlay and Center are the string helpers behind them. All are pure functions of their arguments.

Index

Constants

This section is empty.

Variables

View Source
var (
	// UnderlineTabsStyle underlines the inactive tabs.
	UnderlineTabsStyle = TabsStyle{Underscore: true}
	// RadioTabsStyle marks the active tab with a filled circle.
	RadioTabsStyle = TabsStyle{Radio: true}
)

Predefined tab strip styles.

Functions

func AlignIn

func AlignIn(s string, width int, align Align) string

AlignIn fits s into exactly width columns: wider text is truncated with an ellipsis, narrower text is padded according to align.

func Blank

func Blank(width, height int) string

Blank returns a width x height block of spaces.

func Center

func Center(base, top string, width, height int) string

Center overlays top in the middle of a width x height base.

func DefaultListKeyMap

func DefaultListKeyMap() list.KeyMap

DefaultListKeyMap returns the key bindings of a List: bubbles' own map with j, k, h, l, g, G, u, d, b, f and the quit and help keys taken away, because letters belong to item shortcuts and Left and Right belong to the shell.

func Emit

func Emit(msg tea.Msg) tea.Cmd

Emit returns a command that delivers msg to Update. Components report what happened with messages, and Emit is how they send them.

func Fit

func Fit(s string, width, height int) string

Fit reshapes s into exactly height lines of exactly width columns, padding short lines and blank rows and truncating what does not fit.

func Overlay

func Overlay(base, top string, x, y int) string

Overlay draws top over base with its top-left corner at column x, row y. Both may carry ANSI styling. Parts of top that fall outside base are clipped.

func PadRight

func PadRight(s string, width int) string

PadRight pads s with spaces on the right to width columns, or truncates it (with an ellipsis) when it is wider.

func Split

func Split(total int, parts ...Size) []int

Split divides total cells among parts. Fixed parts are served first, in order, and are cut short when they do not fit; the rest is shared among Fill parts in proportion to their weights, the last of them taking the rounding remainder. A Fill part with weight zero gets nothing.

Types

type Align

type Align int

Align positions text inside a cell or a line.

const (
	AlignLeft Align = iota
	AlignCenter
	AlignRight
)

Alignments.

type Boundary

type Boundary interface {
	AtEdge(dir Direction) bool
}

Boundary is implemented by components that can tell whether the selection sits at an edge. The shell asks the focused screen before it turns an arrow key into a focus move: Up at the top edge goes to the breadcrumbs, Left at the left edge goes to the menu, and so on. A component that is not a Boundary keeps all arrow keys for itself.

AtEdge is a pure query of the model state, so it is as testable as View.

type Breadcrumbs struct {
	// KeyMap holds the key bindings.
	KeyMap BreadcrumbsKeyMap
	// contains filtered or unexported fields
}

Breadcrumbs is a one-line navigation trail. Left and Right move the selection along the trail and Enter activates the selected crumb, which is reported with a CrumbSelectedMsg.

The selection rests on the last crumb. When the trail receives focus the selection jumps to the crumb before it, the parent step, so that Enter goes one step back. The trail is a Boundary: Left is at the edge on the first crumb and Right on the last.

func NewBreadcrumbs

func NewBreadcrumbs(id string, crumbs ...Crumb) Breadcrumbs

NewBreadcrumbs creates a trail. id identifies it in CrumbSelectedMsg.

func (b Breadcrumbs) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (b *Breadcrumbs) Blur()

Blur returns the selection to the last crumb.

func (b Breadcrumbs) Crumbs() []Crumb

Crumbs returns a copy of the trail.

func (b *Breadcrumbs) Focus()

Focus moves the selection to the parent crumb.

func (b Breadcrumbs) Focused() bool

Focused reports whether the trail holds focus.

func (b Breadcrumbs) Selected() int

Selected returns the index of the selected crumb.

func (b *Breadcrumbs) SetCrumbs(crumbs []Crumb)

SetCrumbs replaces the trail and rests the selection on its last crumb.

func (b *Breadcrumbs) SetSeparator(separator string)

SetSeparator sets the text drawn between crumbs; the default is " > ".

func (b *Breadcrumbs) SetSeparatorStart(i int)

SetSeparatorStart suppresses the separators before crumb i, for trails whose first crumbs form one visual unit.

func (b *Breadcrumbs) SetSize(width, _ int)

SetSize gives the trail its width; the height is always one row.

func (b Breadcrumbs) Update(msg tea.Msg) (Breadcrumbs, tea.Cmd)

Update handles key presses while focused, clicks, and size messages.

func (b Breadcrumbs) View() string

View renders the trail on one row of the given width.

type BreadcrumbsKeyMap struct {
	Prev     key.Binding
	Next     key.Binding
	Activate key.Binding
}

BreadcrumbsKeyMap holds the key bindings of Breadcrumbs.

func DefaultBreadcrumbsKeyMap

func DefaultBreadcrumbsKeyMap() BreadcrumbsKeyMap

DefaultBreadcrumbsKeyMap returns the default key bindings.

func (k BreadcrumbsKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (k BreadcrumbsKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type Button

type Button struct {
	// Label is the caption.
	Label string
	// Shortcut, when not zero, is shown before the label.
	Shortcut rune
	// Focused draws the button highlighted.
	Focused bool
	// Disabled draws the button dimmed.
	Disabled bool
	// Background and Foreground override the colours of an unfocused button.
	Background color.Color
	Foreground color.Color
}

Button is the look of a push button: a label with an optional shortcut hint in front of it, "(l) Login". It is a plain value; components that contain buttons keep the state (which one is focused) and render them with View.

func (Button) Text

func (b Button) Text() string

Text is the plain caption: the shortcut hint, when there is one, and the label.

func (Button) View

func (b Button) View(width int) string

View renders the caption centred in exactly width columns.

func (Button) Width

func (b Button) Width() int

Width is the width that fits the caption with one column of padding each side.

type ButtonPressedMsg

type ButtonPressedMsg struct {
	ID       string
	ButtonID string
	Values   map[string]string
}

ButtonPressedMsg reports that an ActionRole button was pressed.

type ButtonRole

type ButtonRole int

ButtonRole says what pressing a FormButton reports.

const (
	// SubmitRole buttons report SubmitMsg.
	SubmitRole ButtonRole = iota
	// CancelRole buttons report CancelMsg.
	CancelRole
	// ActionRole buttons report ButtonPressedMsg.
	ActionRole
)

Button roles.

type CancelMsg

type CancelMsg struct {
	ID       string
	ButtonID string
}

CancelMsg reports that a CancelRole button was pressed, or Esc was, in which case ButtonID is empty.

type Crumb

type Crumb struct {
	// Title is the text of the step.
	Title string
	// Color colours the step; the theme's hotkey colour is used when nil.
	Color color.Color
}

Crumb is one step of a navigation trail.

type CrumbSelectedMsg

type CrumbSelectedMsg struct {
	ID    string
	Index int
	Crumb Crumb
}

CrumbSelectedMsg reports that a crumb was activated with the keyboard or the mouse. Index is its position in the trail, 0 being the root.

type Direction

type Direction int

Direction is a direction of navigation.

const (
	Up Direction = iota
	Down
	Left
	Right
)

Directions.

type Editor

type Editor interface {
	Editing() bool
}

Editor is implemented by components that may currently own a text cursor. While Editing reports true the shell keeps application-wide key bindings out of the way so that text-editing keys keep their meaning.

type Field

type Field struct {
	// ID identifies the field in Value, SetValue and the messages; it must be
	// unique in the form.
	ID string
	// Label is the caption in front of the control.
	Label string
	// Kind selects the control.
	Kind FieldKind
	// Value is the initial text, or for a SelectField the initially chosen
	// option (empty or unknown: nothing chosen).
	Value string
	// Placeholder is shown in an empty text field.
	Placeholder string
	// Width is the width of the control in columns; zero fills the row (text) or
	// fits the value (select).
	Width int
	// Options are the choices of a SelectField.
	Options []string
	// Text is the content of a StaticField; it may carry ANSI styling.
	Text string
	// Accept filters typed and pasted text. It receives the text the field would
	// hold after an insertion and the inserted rune; returning false drops the
	// insertion. It is the one function a Field holds: a pure input filter, that
	// is validation data and not behaviour, so it must not have side effects.
	Accept func(text string, last rune) bool
}

Field describes one labelled row of a Form.

type FieldChangedMsg

type FieldChangedMsg struct {
	ID      string
	FieldID string
	Value   string
}

FieldChangedMsg reports that the user changed the value of a field by typing, deleting, pasting or choosing an option. SetValue does not send it.

type FieldKind

type FieldKind int

FieldKind is the kind of a form field.

const (
	// TextField is a single-line text input.
	TextField FieldKind = iota
	// PasswordField is a text input that hides what is typed.
	PasswordField
	// SelectField is a single choice among Options.
	SelectField
	// StaticField is a read-only line of text that focus skips.
	StaticField
)

Field kinds.

type Form

type Form struct {
	// KeyMap holds the key bindings.
	KeyMap FormKeyMap
	// contains filtered or unexported fields
}

Form is a vertical form of labelled fields above a row of buttons. Fields sit one per row with labels right-aligned to the widest one, then a blank row and the buttons, aligned left. When the height is too small the form scrolls so the focused row stays visible.

Text and password fields wrap charm.land/bubbles/v2/textinput (virtual cursor on, blinking off, so no timer messages). Select fields and layout are own code: bubbles has no select, and a form needs the option list to take rows from the layout while it is open (capped at eight, scrolling inside).

Messages: FieldChangedMsg when Update changes a value, SubmitMsg, CancelMsg and ButtonPressedMsg for buttons, and CancelMsg with an empty ButtonID for Esc.

Keys (FormKeyMap): Tab and Down move to the next control, Shift+Tab and Up to the previous one; Enter on a field moves on and on a button presses it; Left and Right move between buttons; Esc cancels. On a closed select Enter, Space and Down open the option list, Up and Down move in it, Enter picks and Esc closes it, and Left and Right step through the options. Ctrl+Q and Ctrl+C are never consumed. Clicks focus a field or press a button.

Boundary: AtEdge(Up) is true on the first control, Down on the buttons (or the last field when there are none), Left when the text cursor is at the start, on the first button, or on a select at its first option, and Right when the cursor is at the end, on the last button, or on a select at its last option. While a select list is open no edge is reached. Form is an Editor while a text or password field is focused.

func NewForm

func NewForm(id string, fields []Field, buttons []FormButton) Form

NewForm creates a form. id identifies it in messages. It starts blurred, with the first field (or button) as the control that receives focus.

func (Form) AtEdge

func (f Form) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (*Form) Blur

func (f *Form) Blur()

Blur takes the keyboard away and closes an open select list.

func (Form) Editing

func (f Form) Editing() bool

Editing implements Editor: a text or password field holds the cursor.

func (*Form) Focus

func (f *Form) Focus()

Focus gives the form the keyboard.

func (*Form) FocusField

func (f *Form) FocusField(id string) bool

FocusField moves the focus to the field id and reports whether it exists and can take focus.

func (Form) Focused

func (f Form) Focused() bool

Focused reports whether the form holds focus.

func (*Form) SetButtons

func (f *Form) SetButtons(buttons []FormButton)

SetButtons replaces the buttons, keeping the focus when its control survives.

func (*Form) SetFields

func (f *Form) SetFields(fields []Field)

SetFields replaces the fields. Typed values of fields whose ID and kind survive are kept, and so is the focus when its control survives.

func (*Form) SetSize

func (f *Form) SetSize(width, height int)

SetSize sets the size of the view.

func (*Form) SetValue

func (f *Form) SetValue(id, value string)

SetValue sets the value of the field id without sending a message. A value that is not one of a select's options clears the choice.

func (Form) Update

func (f Form) Update(msg tea.Msg) (Form, tea.Cmd)

Update handles key presses while focused, clicks, the wheel, pastes and size messages.

func (Form) Value

func (f Form) Value(id string) string

Value returns the value of the field id: the text, or the chosen option of a select. Unknown and static fields have none.

func (Form) Values

func (f Form) Values() map[string]string

Values returns the value of every text, password and select field by ID.

func (Form) View

func (f Form) View() string

View renders exactly height rows of width columns, scrolled so the focused row is visible.

type FormButton

type FormButton struct {
	// ID identifies the button in the messages.
	ID string
	// Label is the caption.
	Label string
	// Role selects the message a press reports.
	Role ButtonRole
}

FormButton is a push button below the fields of a Form.

type FormKeyMap

type FormKeyMap struct {
	Next   key.Binding
	Prev   key.Binding
	Submit key.Binding
	Cancel key.Binding
	Left   key.Binding
	Right  key.Binding
	// Open opens a closed select.
	Open key.Binding
	// Press presses the focused button.
	Press key.Binding
}

FormKeyMap holds the key bindings of Form.

func DefaultFormKeyMap

func DefaultFormKeyMap() FormKeyMap

DefaultFormKeyMap returns the default key bindings.

func (FormKeyMap) FullHelp

func (k FormKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (FormKeyMap) ShortHelp

func (k FormKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type Frame

type Frame struct {
	// Title is drawn in the top border.
	Title string
	// Focused selects the focused border colour.
	Focused bool
	// Borders draws the border; without it the content fills the whole rectangle.
	Borders bool
	// Padding is the space between the border and the content.
	Padding Padding
	// TitleAlign positions the title along the top border.
	TitleAlign Align
}

Frame is the bordered, titled box a panel is drawn in. The border takes the theme's focused colour while Focused is true and its blurred colour otherwise. Frame is a plain value: With... methods return a modified copy, and Render is a pure function of the frame and its arguments.

frame := widgets.NewFrame().WithTitle("Projects").WithFocus(true)
out := frame.Render(list.View(), 40, 12)

func NewFrame

func NewFrame() Frame

NewFrame returns a bordered frame without padding and with a centred title.

func (Frame) Inner

func (f Frame) Inner(width, height int) (w, h int)

Inner returns the size of the content area of a frame drawn into width x height; a dimension is never negative.

func (Frame) Origin

func (f Frame) Origin() (x, y int)

Origin is the position of the content's top-left cell inside the frame.

func (Frame) Render

func (f Frame) Render(content string, width, height int) string

Render draws content, which should be Inner(width, height) cells, inside the frame and returns exactly height lines of width columns.

func (Frame) WithFocus

func (f Frame) WithFocus(focused bool) Frame

WithFocus sets whether the frame is drawn as focused.

func (Frame) WithPadding

func (f Frame) WithPadding(top, right, bottom, left int) Frame

WithPadding sets the padding between the border and the content.

func (Frame) WithTitle

func (f Frame) WithTitle(title string) Frame

WithTitle sets the title.

func (Frame) WithTitleAlign

func (f Frame) WithTitleAlign(align Align) Frame

WithTitleAlign positions the title along the top border.

func (Frame) WithoutBorders

func (f Frame) WithoutBorders() Frame

WithoutBorders removes the border.

type ItemHighlightedMsg

type ItemHighlightedMsg struct {
	ID    string
	Index int
	Item  list.Item
}

ItemHighlightedMsg reports that the highlighted item of a List changed because of a message passed to Update. Index is the position among the visible items (those matching the filter, when there is one).

type ItemSelectedMsg

type ItemSelectedMsg struct {
	ID    string
	Index int
	Item  list.Item
}

ItemSelectedMsg reports that the highlighted item of a List was chosen with Enter, with its shortcut key, or by a click on the already highlighted row.

type List

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

List is a compact vertical menu built on bubbles' list.Model, which supplies the cursor movement, paging and optional filtering. The wrapper turns off the title, status bar, help and pagination dots, draws its own theme-coloured rows, and reports what happens with messages.

Rows are one line high, or two when some item has a detail. The highlighted row is drawn across the full width in the theme's selected style. bubbles pages the list instead of scrolling it: moving past the last row of a page shows the next page.

Messages, returned as commands by Update:

  • ItemHighlightedMsg when a key, a click or the wheel changes the highlighted item; SetItems and Select are setters and never emit
  • ItemSelectedMsg on Enter, on the shortcut key of a MenuItem (after an ItemHighlightedMsg when that moved the highlight), and on a left click on the row that is already highlighted; a click on another row only highlights it

Keys, while focused: up, down, home, end, pgup and pgdown, all without wrapping around, and Enter. Letters are free for shortcuts. Unfocused, keys are ignored. Mouse clicks and the wheel work regardless of focus, with coordinates relative to the top-left cell; the wheel moves the highlight one row per notch.

Filtering is off until SetFilteringEnabled(true); then "/" starts it, and while the filter input is active the list is an Editor: Editing reports true and every key goes to bubbles unmodified. The parent must pass all messages, not only keys, to Update while filtering, because bubbles delivers the matches asynchronously. Enabling filtering costs one row for the filter input.

List is a Boundary: Up is at the edge when the first item is highlighted (or there are no items), Down when the last one is, and Left and Right always.

func NewList

func NewList(id string, items ...list.Item) List

NewList creates a list. id identifies it in its messages.

func (List) AtEdge

func (l List) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (*List) Blur

func (l *List) Blur()

Blur stops the list handling keys and dims the highlight.

func (List) Editing

func (l List) Editing() bool

Editing implements Editor: true while the filter input is being typed into.

func (List) FilteringEnabled

func (l List) FilteringEnabled() bool

FilteringEnabled reports whether the filter is available.

func (*List) Focus

func (l *List) Focus()

Focus makes the list handle keys and draws the highlight in the focused style.

func (List) Focused

func (l List) Focused() bool

Focused reports whether the list holds focus.

func (List) FullHelp

func (l List) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (List) Index

func (l List) Index() int

Index returns the position of the highlighted item among the visible items.

func (List) Items

func (l List) Items() []list.Item

Items returns the items, ignoring any filter.

func (List) KeyMap

func (l List) KeyMap() list.KeyMap

KeyMap returns the key bindings of the underlying list model.

func (*List) Select

func (l *List) Select(index int)

Select highlights the item at index among the visible items, clamped to the list. It emits no message.

func (List) SelectedItem

func (l List) SelectedItem() list.Item

SelectedItem returns the highlighted item, or nil when there is none.

func (*List) SetFilteringEnabled

func (l *List) SetFilteringEnabled(enabled bool)

SetFilteringEnabled turns the "/" filter on or off; it is off by default.

func (*List) SetItems

func (l *List) SetItems(items ...list.Item)

SetItems replaces the items, ending any filter and keeping the highlight at the same position, or on the last item when there are fewer. It emits no message.

func (*List) SetKeyMap

func (l *List) SetKeyMap(km list.KeyMap)

SetKeyMap replaces the key bindings. The quit bindings stay disabled.

func (*List) SetSize

func (l *List) SetSize(width, height int)

SetSize sets the size of the list in cells.

func (List) ShortHelp

func (l List) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

func (List) Update

func (l List) Update(msg tea.Msg) (List, tea.Cmd)

Update handles keys while focused, mouse clicks and wheel notches, size messages, and passes everything else (bubbles' asynchronous filter results and cursor blinks) to the underlying model.

func (List) View

func (l List) View() string

View renders the list in exactly the size given to SetSize.

type MenuItem struct {
	// ID identifies the item for the parent.
	ID string
	// Label is the first line of the item.
	Label string
	// Detail, when not empty, is shown muted on a second line.
	Detail string
	// Shortcut, when not zero, is drawn as "(x) " before the label and selects
	// the item when the key is typed.
	Shortcut rune
	// Ref is any value the parent wants to get back with the item.
	Ref any
}

MenuItem is a ready-made list item: a label, an optional second line of detail, an optional shortcut key and an opaque reference the parent can use to find out what the item stands for.

func (i MenuItem) Description() string

Description implements list.DefaultItem.

func (i MenuItem) FilterValue() string

FilterValue implements list.Item.

func (i MenuItem) Title() string

Title implements list.DefaultItem.

type Modal struct {
	// KeyMap holds the key bindings.
	KeyMap ModalKeyMap
	// contains filtered or unexported fields
}

Modal is a dialog: a bordered box with a title in its border, wrapped text and a row of buttons drawn with Button. View returns the box only, at its natural size; the shell overlays it on the screen with Center, so the modal need not know what is behind it. bubbles has no dialog, and Frame draws neither a background nor a custom border colour, so the box is drawn here.

A modal owns the input, so it is always focused and has no Focus or Blur: Left, Right, Tab and Shift+Tab move between the buttons (wrapping around), Enter presses the focused button, Esc answers with index -1, and every other key press is swallowed. Only Ctrl+C and Ctrl+Q are left alone, Update returning the model and no command, so that the shell can quit. A left click on a button presses it and every other click is swallowed. Mouse coordinates are relative to the top-left corner of the box, which is where the shell puts the box's top-left cell.

Messages: ModalDoneMsg. A tea.WindowSizeMsg sets the space the box must fit in, like SetMaxSize. Modal is neither a Boundary nor an Editor.

func NewModal

func NewModal(id string) Modal

NewModal creates a modal without text or buttons. id identifies it in ModalDoneMsg.

func (Modal) Active

func (m Modal) Active() int

Active returns the index of the focused button.

func (Modal) FullHelp

func (m Modal) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (*Modal) SetButtons

func (m *Modal) SetButtons(labels ...string)

SetButtons replaces the buttons and focuses the first one.

func (*Modal) SetColors

func (m *Modal) SetColors(colors ModalColors)

SetColors overrides the theme's colours; nil fields keep the theme's.

func (*Modal) SetMaxSize

func (m *Modal) SetMaxSize(maxWidth, maxHeight int)

SetMaxSize sets the space the box must fit in. The text is wrapped at the smaller of maxWidth-4 and 60 columns, and text rows that do not fit the height are dropped. Zero or less means unlimited, which still wraps at 60 columns.

func (*Modal) SetText

func (m *Modal) SetText(text string)

SetText sets the message; Size and View wrap it.

func (*Modal) SetTitle

func (m *Modal) SetTitle(title string)

SetTitle sets the title drawn in the top border.

func (Modal) ShortHelp

func (m Modal) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

func (Modal) Size

func (m Modal) Size() (w, h int)

Size returns the natural size of the box.

func (Modal) Update

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

Update handles key presses, left clicks and size messages. See Modal for which keys are swallowed.

func (Modal) View

func (m Modal) View() string

View renders the box at its natural size: every line has the same width.

type ModalColors

type ModalColors struct {
	Background       color.Color
	Text             color.Color
	Border           color.Color
	ButtonBackground color.Color
	ButtonText       color.Color
}

ModalColors overrides the colours of a Modal. A nil colour uses the theme's: the focus colour for the border, the text colour for the text, no background, and the default look for unfocused buttons.

type ModalDoneMsg

type ModalDoneMsg struct {
	ID    string
	Index int
	Label string
}

ModalDoneMsg reports that the modal was answered: a button was pressed with Enter or a click, or Esc was pressed, in which case Index is -1 and Label is empty. The parent removes the modal when it receives it.

type ModalKeyMap

type ModalKeyMap struct {
	Prev    key.Binding
	Next    key.Binding
	Confirm key.Binding
	Cancel  key.Binding
}

ModalKeyMap holds the key bindings of Modal.

func DefaultModalKeyMap

func DefaultModalKeyMap() ModalKeyMap

DefaultModalKeyMap returns the default key bindings.

func (ModalKeyMap) FullHelp

func (k ModalKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (ModalKeyMap) ShortHelp

func (k ModalKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type NodeHighlightedMsg

type NodeHighlightedMsg struct {
	ID   string
	Node TreeNode
}

NodeHighlightedMsg reports that the cursor moved to a node because of a key or a click. It is not sent for changes made with Select, SetRoots or SetChildren.

type NodeSelectedMsg

type NodeSelectedMsg struct {
	ID   string
	Node TreeNode
}

NodeSelectedMsg reports that a node was activated: Enter on the cursor node, or a click on the node that already holds the cursor. The node is never changed by the message itself; Enter afterwards toggles a node that has children.

type Padding

type Padding struct{ Top, Right, Bottom, Left int }

Padding is a space in rows and columns.

type Size

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

Size is the share of a length one part of a layout takes: a fixed number of cells, or a weight in what remains.

func Fill

func Fill(weight int) Size

Fill is a part that takes a share of the space left after the fixed parts, proportional to weight.

func Fixed

func Fixed(n int) Size

Fixed is a part of exactly n cells.

type SubmitMsg

type SubmitMsg struct {
	ID       string
	ButtonID string
	Values   map[string]string
}

SubmitMsg reports that a SubmitRole button was pressed.

type Tab

type Tab struct {
	// ID identifies the tab for the parent.
	ID string
	// Title is the text shown in the strip.
	Title string
	// Closable adds a close mark to the tab.
	Closable bool
}

Tab is one entry of the tab strip.

type TabChangedMsg

type TabChangedMsg struct {
	ID    string
	Index int
	Tab   Tab
}

TabChangedMsg reports that the active tab changed because of a key press or a click. Index is the position of the new active tab.

type TabCloseMsg

type TabCloseMsg struct {
	ID    string
	Index int
	Tab   Tab
}

TabCloseMsg reports a click on the close mark of a closable tab. The parent decides whether to call RemoveTab.

type Tabs

type Tabs struct {
	// KeyMap holds the key bindings.
	KeyMap TabsKeyMap
	// contains filtered or unexported fields
}

Tabs is a one-row strip of tab titles, optionally preceded by a label. It draws the strip only: the parent keeps the pages and shows the content of the active tab itself, following TabChangedMsg. bubbles has no tab strip, so the rendering is our own.

Left and Right switch tabs (no wrapping) and Alt+1 to Alt+9 jump to a tab, while focused. A click on a tab activates it, and a click on the close mark of a closable tab reports it. The active tab is drawn in the theme's selected style when the strip is focused and bold when it is not; inactive tabs are muted, and underlined in the Underscore style. When the strip is wider than the space it is scrolled so that the active tab is visible.

Messages: TabChangedMsg when the active tab changes through Update (never for SetActive, AddTab or RemoveTab, which are setters), and TabCloseMsg on a click on a close mark. Mouse clicks work regardless of focus, with the x coordinate relative to the left edge of the strip and y 0.

Tabs is a Boundary: Left is at the edge when the first tab is active, Right when the last one is, and Up and Down always. It is not an Editor.

func NewTabs

func NewTabs(id string, style TabsStyle, tabs ...Tab) Tabs

NewTabs creates a strip. id identifies it in its messages. The first tab is active.

func (Tabs) Active

func (t Tabs) Active() int

Active returns the index of the active tab, or -1 without tabs.

func (*Tabs) AddTab

func (t *Tabs) AddTab(tab Tab)

AddTab appends a tab. The first tab added becomes active.

func (Tabs) AtEdge

func (t Tabs) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (*Tabs) Blur

func (t *Tabs) Blur()

Blur stops the strip handling keys.

func (*Tabs) Focus

func (t *Tabs) Focus()

Focus makes the strip handle keys.

func (Tabs) Focused

func (t Tabs) Focused() bool

Focused reports whether the strip holds focus.

func (Tabs) FullHelp

func (t Tabs) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (*Tabs) RemoveTab

func (t *Tabs) RemoveTab(index int)

RemoveTab removes the tab at index, ignoring an index outside the strip. Removing the active tab activates its neighbour. It emits no message.

func (*Tabs) SetActive

func (t *Tabs) SetActive(index int)

SetActive activates the tab at index, ignoring an index outside the strip. It emits no message.

func (*Tabs) SetLabel

func (t *Tabs) SetLabel(label string)

SetLabel sets the text drawn before the strip; it may carry ANSI styling.

func (*Tabs) SetSize

func (t *Tabs) SetSize(width, _ int)

SetSize gives the strip its width; the height is always one row.

func (Tabs) ShortHelp

func (t Tabs) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

func (Tabs) Tabs

func (t Tabs) Tabs() []Tab

Tabs returns a copy of the tabs.

func (Tabs) Update

func (t Tabs) Update(msg tea.Msg) (Tabs, tea.Cmd)

Update handles key presses while focused, left clicks, and size messages.

func (Tabs) View

func (t Tabs) View() string

View renders the strip on one row of the width given to SetSize.

type TabsKeyMap

type TabsKeyMap struct {
	Prev key.Binding
	Next key.Binding
	// Jump activates tab n with alt+n, for n from 1 to 9.
	Jump key.Binding
}

TabsKeyMap holds the key bindings of Tabs.

func DefaultTabsKeyMap

func DefaultTabsKeyMap() TabsKeyMap

DefaultTabsKeyMap returns the default key bindings.

func (TabsKeyMap) FullHelp

func (k TabsKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (TabsKeyMap) ShortHelp

func (k TabsKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type TabsStyle

type TabsStyle struct {
	// Radio prefixes each tab with a filled circle when active, an empty one
	// otherwise.
	Radio bool
	// Underscore underlines the inactive tabs.
	Underscore bool
}

TabsStyle selects how the tab strip is drawn; the theme supplies colours.

type TextPane

type TextPane struct {
	// KeyMap holds the key bindings.
	KeyMap TextPaneKeyMap
	// contains filtered or unexported fields
}

TextPane shows scrollable, optionally wrapped text and is built on bubbles' viewport, which does the scrolling, the soft wrapping and the horizontal cropping. The wrapper adds the key map (arrows, page keys, home and end; letters are not bound), a default text colour, the Boundary queries, and the exact-size View.

The content may carry ANSI styling (lipgloss output, theme.RedText, highlight output). Styling survives soft wrapping because the viewport cuts every wrapped row out of the styled line with ansi.Cut, which re-opens the styles that are active at the start of the row and closes them at its end (the tests verify this). A style that stays open across a line break, which the viewport would otherwise lose on the next line, is closed at the end of the line and re-opened at the start of the next by carryStyles when the content is set.

Wrapping is on by default and breaks lines at exactly the width (the viewport does not break at word boundaries). With SetWrap(false), Left and Right scroll horizontally. The wheel scrolls three lines. The vertical position is kept when the pane is resized and clamped to the text; SetContent scrolls to the top and AppendContent keeps the position.

TextPane sends no messages. It is a Boundary: Up is at the edge when scrolled to the top, Down at the bottom, Left when scrolled fully left (always while wrapping) and Right when scrolled fully right (always while wrapping). It is not an Editor.

func NewTextPane

func NewTextPane(id string) TextPane

NewTextPane creates an empty pane that wraps long lines.

func (*TextPane) AppendContent

func (t *TextPane) AppendContent(s string)

AppendContent adds s to the end of the text without moving the scroll position; call GotoBottom afterwards to follow a stream.

func (TextPane) AtEdge

func (t TextPane) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (*TextPane) Blur

func (t *TextPane) Blur()

Blur stops the pane handling keys.

func (TextPane) Content

func (t TextPane) Content() string

Content returns the text as it was given.

func (*TextPane) Focus

func (t *TextPane) Focus()

Focus makes the pane handle keys.

func (TextPane) Focused

func (t TextPane) Focused() bool

Focused reports whether the pane holds focus.

func (TextPane) FullHelp

func (t TextPane) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (*TextPane) GotoBottom

func (t *TextPane) GotoBottom()

GotoBottom scrolls so that the last line is visible.

func (*TextPane) GotoTop

func (t *TextPane) GotoTop()

GotoTop scrolls to the first line.

func (TextPane) ID

func (t TextPane) ID() string

ID returns the id the pane was created with.

func (TextPane) LineCount

func (t TextPane) LineCount() int

LineCount returns the number of lines at the current width, wrapped lines counted separately.

func (*TextPane) ScrollTo

func (t *TextPane) ScrollTo(y, x int)

ScrollTo scrolls so that line y and column x are the first visible ones, clamped to the text.

func (*TextPane) SetContent

func (t *TextPane) SetContent(s string)

SetContent replaces the text and scrolls to the top.

func (*TextPane) SetSize

func (t *TextPane) SetSize(width, height int)

SetSize sets the size of the pane; the scroll position is kept and clamped.

func (*TextPane) SetTextColor

func (t *TextPane) SetTextColor(c color.Color)

SetTextColor sets the foreground colour of text that has no colour of its own.

func (*TextPane) SetWrap

func (t *TextPane) SetWrap(wrap bool)

SetWrap turns soft wrapping on (the default) or off, which enables horizontal scrolling.

func (TextPane) ShortHelp

func (t TextPane) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

func (TextPane) Update

func (t TextPane) Update(msg tea.Msg) (TextPane, tea.Cmd)

Update handles key presses while focused, the mouse wheel, and size messages.

func (TextPane) View

func (t TextPane) View() string

View renders the visible text in exactly the size given to SetSize.

func (TextPane) XOffset

func (t TextPane) XOffset() int

XOffset returns the first visible column; it is 0 while wrapping.

func (TextPane) YOffset

func (t TextPane) YOffset() int

YOffset returns the first visible line, counting wrapped lines.

type TextPaneKeyMap

type TextPaneKeyMap struct {
	Up       key.Binding
	Down     key.Binding
	PageUp   key.Binding
	PageDown key.Binding
	Top      key.Binding
	Bottom   key.Binding
	Left     key.Binding
	Right    key.Binding
}

TextPaneKeyMap holds the key bindings of TextPane. Letters are not bound.

func DefaultTextPaneKeyMap

func DefaultTextPaneKeyMap() TextPaneKeyMap

DefaultTextPaneKeyMap returns the default key bindings.

func (TextPaneKeyMap) FullHelp

func (k TextPaneKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (TextPaneKeyMap) ShortHelp

func (k TextPaneKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type Tree

type Tree struct {
	// KeyMap holds the key bindings.
	KeyMap TreeKeyMap
	// contains filtered or unexported fields
}

Tree is a scrollable, data-driven hierarchy of TreeNode values. Several roots give the "hidden root" layout: they are drawn at the left edge.

Keys: Up, Down, PageUp, PageDown, Home and End move the cursor between visible selectable nodes. Right expands a collapsed node, or moves to the first selectable child of an expanded one. Left collapses an expanded node below the top level, or moves to its selectable parent; on a top-level node it does nothing. Enter reports NodeSelectedMsg and then toggles a node that has children, Space only toggles. A click selects the row (NodeSelectedMsg when it already held the cursor) and a click on the expand marker toggles it; the wheel scrolls without moving the cursor. Cursor moves made by Update are reported with NodeHighlightedMsg.

Boundary: AtEdge(Up) is true on the first selectable visible node, Down on the last, Left when Left would do nothing (a top-level node, or a node whose parent is a group header and that cannot collapse) and Right when Right would do nothing (a leaf, or an expanded node without a selectable child). Tree is not an Editor.

Why it does not wrap charm.land/bubbles/v2/tree: that component is built on a mutable *Node graph whose Open and Close mutate shared nodes, has no unselectable nodes, keys expansion by pointer rather than by ID, has no per-node colour, and renders the whole tree into a viewport on every move instead of exactly width x height rows. Tree needs all of those, so it draws the rows itself (with the guides and markers below) and reuses only key and help from bubbles.

func NewTree

func NewTree(id string, roots ...TreeNode) Tree

NewTree creates a tree. id identifies it in messages. The first selectable node holds the cursor; nothing is expanded.

func (Tree) AtEdge

func (t Tree) AtEdge(dir Direction) bool

AtEdge implements Boundary.

func (*Tree) Blur

func (t *Tree) Blur()

Blur takes the keyboard away.

func (*Tree) Collapse

func (t *Tree) Collapse(id string)

Collapse closes the node id.

func (*Tree) CollapseAll

func (t *Tree) CollapseAll()

CollapseAll closes every node.

func (Tree) Current

func (t Tree) Current() (TreeNode, bool)

Current returns the node under the cursor, with its children.

func (*Tree) Expand

func (t *Tree) Expand(id string)

Expand opens the node id.

func (*Tree) ExpandAll

func (t *Tree) ExpandAll()

ExpandAll opens every node that has children.

func (Tree) Expanded

func (t Tree) Expanded(id string) bool

Expanded reports whether the node id is open.

func (*Tree) Focus

func (t *Tree) Focus()

Focus gives the tree the keyboard.

func (Tree) Focused

func (t Tree) Focused() bool

Focused reports whether the tree holds focus.

func (Tree) Roots

func (t Tree) Roots() []TreeNode

Roots returns a copy of the top-level nodes.

func (*Tree) Select

func (t *Tree) Select(id string) bool

Select moves the cursor to the node id, opening its ancestors so it is visible, without sending a message. It reports false when the node does not exist or is unselectable.

func (*Tree) SetChildren

func (t *Tree) SetChildren(id string, children []TreeNode) bool

SetChildren replaces the children of the node id, for lazy loading, and keeps the cursor. It reports whether the node exists.

func (*Tree) SetExpanded

func (t *Tree) SetExpanded(id string, open bool) bool

SetExpanded opens or closes the node id. It reports whether the node exists.

func (*Tree) SetRoots

func (t *Tree) SetRoots(roots ...TreeNode)

SetRoots replaces the data. Expansion is kept by ID, and so is the cursor when its node still exists; otherwise the first selectable node takes it.

func (*Tree) SetSize

func (t *Tree) SetSize(width, height int)

SetSize sets the size of the view.

func (Tree) Update

func (t Tree) Update(msg tea.Msg) (Tree, tea.Cmd)

Update handles key presses while focused, clicks, the wheel, and size messages.

func (Tree) View

func (t Tree) View() string

View renders exactly height rows of width columns, scrolled to the offset.

type TreeKeyMap

type TreeKeyMap struct {
	Up       key.Binding
	Down     key.Binding
	PageUp   key.Binding
	PageDown key.Binding
	Home     key.Binding
	End      key.Binding
	Expand   key.Binding
	Collapse key.Binding
	Activate key.Binding
	Toggle   key.Binding
}

TreeKeyMap holds the key bindings of Tree.

func DefaultTreeKeyMap

func DefaultTreeKeyMap() TreeKeyMap

DefaultTreeKeyMap returns the default key bindings.

func (TreeKeyMap) FullHelp

func (k TreeKeyMap) FullHelp() [][]key.Binding

FullHelp implements help.KeyMap.

func (TreeKeyMap) ShortHelp

func (k TreeKeyMap) ShortHelp() []key.Binding

ShortHelp implements help.KeyMap.

type TreeNode

type TreeNode struct {
	// ID identifies the node and must be unique in the tree.
	ID string
	// Text is the caption; it may carry ANSI styling and emoji.
	Text string
	// Ref is an arbitrary value the application attaches to the node.
	Ref any
	// Color colours the caption when the node is not the selected row; nil keeps
	// the terminal default.
	Color color.Color
	// Children are the nodes below this one.
	Children []TreeNode
	// Unselectable marks a group header: it is drawn (and can be expanded with
	// SetExpanded, ExpandAll or a click on its marker) but the cursor never rests
	// on it.
	Unselectable bool
}

TreeNode is one node of a Tree. Nodes are plain data: the tree keeps no pointers into them, and expansion and the cursor are tracked by ID.

Jump to

Keyboard shortcuts

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