Documentation
¶
Index ¶
- func RenderQRCode(content string, size int) string
- type List
- func (l *List) ItemAtRow(row int) int
- func (l *List) ScrollBy(n int)
- func (l *List) SelectIndex(i int) bool
- func (l *List) SelectedID() string
- func (l *List) SelectedItem() *ListItem
- func (l *List) SetItems(items []ListItem)
- func (l *List) Update(msg tea.Msg) (selected bool)
- func (l *List) View() string
- type ListItem
- type Spinner
- type SpinnerTickMsg
- type Tabs
- type TextArea
- func (t *TextArea) Backspace()
- func (t *TextArea) DeleteChar()
- func (t *TextArea) DeleteLine()
- func (t *TextArea) DeleteRange(from, to int)
- func (t *TextArea) InsertNewline()
- func (t *TextArea) InsertString(s string)
- func (t *TextArea) KillToLineEnd()
- func (t *TextArea) KillToLineStart()
- func (t *TextArea) KillWordBack()
- func (t *TextArea) Len() int
- func (t *TextArea) LineBounds() (start, end int)
- func (t *TextArea) MoveDown()
- func (t *TextArea) MoveLeft()
- func (t *TextArea) MoveLineEnd()
- func (t *TextArea) MoveLineStart()
- func (t *TextArea) MoveRight()
- func (t *TextArea) MoveUp()
- func (t *TextArea) MoveWordBack()
- func (t *TextArea) MoveWordForward()
- func (t *TextArea) Reset()
- func (t *TextArea) Update(msg tea.Msg) (submitted bool)
- func (t *TextArea) View() string
- func (t *TextArea) WordBackStart() int
- func (t *TextArea) WordForwardStart() int
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RenderQRCode ¶
RenderQRCode generates an ASCII QR code using Unicode block characters. Uses U+2580 (upper half block) and U+2584 (lower half block) to pack two rows of QR modules into one terminal row.
Types ¶
type List ¶
type List struct {
// RenderRow, when set, replaces this widget's own row drawing. It is
// given one item and must return exactly itemHeight lines, each
// already fitted to width. Everything else — cursor, scrolling,
// click-to-row mapping — is unaffected.
//
// This exists so a caller can have a bespoke row without forking the
// scroll machinery, which is where the fiddly arithmetic lives.
RenderRow func(item ListItem, selected, focused bool, width int) []string
Items []ListItem
Cursor int
Offset int
Width int
Height int
Focused bool
StyleNormal lipgloss.Style
StyleActive lipgloss.Style
StyleTitle lipgloss.Style
StyleSub lipgloss.Style
StyleMeta lipgloss.Style
StyleBadge lipgloss.Style
StyleOnline lipgloss.Style
// StyleEmpty draws the "No items" placeholder. Supplied by the caller
// like every other style here — this widget used to reach for a
// hard-coded #565F89, which is how a generic list ended up owning an
// opinion about the application's palette.
StyleEmpty lipgloss.Style
// contains filtered or unexported fields
}
List is a generic scrollable list widget with vim-style navigation.
func (*List) ItemAtRow ¶
ItemAtRow returns the index of the item displayed at the given local row (0-based, relative to the top of the list's visible area), or -1.
func (*List) SelectIndex ¶
SelectIndex moves the cursor to the given item index. Returns false if the index is out of bounds.
func (*List) SelectedID ¶
SelectedID returns the ID of the currently selected item.
func (*List) SelectedItem ¶
SelectedItem returns the currently selected item, or nil.
type ListItem ¶
type ListItem struct {
ID string
Title string
Subtitle string
Badge string
// MetaAt is the instant Meta describes, or 0 when Meta is not a time.
// A relative label goes stale where an absolute one cannot, so the
// owner keeps the fact beside the sentence about it.
MetaAt int32
Meta string
Online bool
Muted bool // chat notifications are muted; render dimmed
// Kind and Saved describe what the item IS, for callers whose rows
// show a type mark. TUI 2.0's chat list uses them for its sigil, which
// replaces the avatar as the identity signal — the widget itself never
// interprets them.
Kind int
Saved bool
}
ListItem represents a single item in a scrollable list.
type Spinner ¶
Spinner is a loading spinner widget.
type Tabs ¶
type Tabs struct {
Labels []string
Active int
Width int
StyleTab lipgloss.Style
StyleTabActive lipgloss.Style
}
Tabs is a tab bar widget for switching between views.
type TextArea ¶
type TextArea struct {
Value string
Cursor int
Width int
Height int
Focused bool
Placeholder string
Style lipgloss.Style
// StylePlaceholder draws the prompt shown while the field is empty and
// unfocused. Supplied by the caller like Style — this widget used to
// reach for a hard-coded #565F89, which is how a generic input ended up
// holding an opinion about the application's palette.
StylePlaceholder lipgloss.Style
// MultiLine makes Value a multi-line buffer: pastes keep their line
// breaks, InsertNewline is meaningful, and View renders one row per
// line inside a vertically scrolling window Height rows tall.
MultiLine bool
// EchoPassword, on the single-line path, renders a bullet per rune
// instead of Value so a 2FA password is not visible on screen. The
// cursor and placeholder (when empty) are unchanged.
EchoPassword bool
}
TextArea is the shared text input widget. It runs in two shapes, selected by MultiLine:
- MultiLine false: a single-line input with a horizontally scrolling view window (the search overlay, chatview's find bar, the auth prompts).
- MultiLine true: a multi-line editor (the composer). Value may contain "\n"; every motion and edit below is line-aware, and the view scrolls vertically to keep the cursor's line on screen.
The shape is a declared property, not something inferred from Height. Height is a layout number: it arrives from a WindowSizeMsg, is zero before the first one, and can be squeezed to 1 on a short terminal. Deriving "is this a multi-line editor" from it meant the composer silently became a single-line widget in exactly those moments — and flattened the newlines out of anything pasted into it.
Key handling is readline/emacs and is unconditional — callers that want vi semantics (the composer) intercept keys before delegating here and drive the exported edit primitives directly.
Bindings are matched on tea.KeyPressMsg.Keystroke(), never on String(). String() returns Key.Text whenever the terminal attached any, so a Kitty-protocol shift+enter (CSI 13;2;13u) reports String() == "\r" while Keystroke() correctly reports "shift+enter" — matching on String() would both miss the binding and insert a stray carriage return. See the keyPress doc comment in internal/app/keymap.go.
func NewTextArea ¶
func NewTextArea() TextArea
func (*TextArea) Backspace ¶
func (t *TextArea) Backspace()
Backspace deletes the rune before the cursor, joining lines when the cursor sits at the start of one.
func (*TextArea) DeleteChar ¶
func (t *TextArea) DeleteChar()
DeleteChar deletes the rune under the cursor (emacs ctrl+d, vi x).
func (*TextArea) DeleteLine ¶
func (t *TextArea) DeleteLine()
DeleteLine removes the whole line under the cursor including its line break (vi dd) and lands the cursor at the start of what is now the current line.
func (*TextArea) DeleteRange ¶
DeleteRange removes the runes in [from, to) and puts the cursor at from.
func (*TextArea) InsertNewline ¶
func (t *TextArea) InsertNewline()
InsertNewline inserts a hard line break. It is deliberately separate from InsertString/key handling: Enter means "submit" to every component that embeds a TextArea, so a line break can only ever arrive through an explicit call (the composer's ctrl+j / shift+enter chords, or vi's o/O).
func (*TextArea) InsertString ¶
InsertString inserts s at the cursor and leaves the cursor after it.
func (*TextArea) KillToLineEnd ¶
func (t *TextArea) KillToLineEnd()
KillToLineEnd removes the rest of the current line (emacs ctrl+k, vi D). On an already-empty line end it swallows the line break, like readline.
func (*TextArea) KillToLineStart ¶
func (t *TextArea) KillToLineStart()
KillToLineStart removes the current line up to the cursor (emacs ctrl+u).
func (*TextArea) KillWordBack ¶
func (t *TextArea) KillWordBack()
KillWordBack deletes from the start of the previous word to the cursor (emacs ctrl+w).
func (*TextArea) LineBounds ¶
LineBounds returns the [start, end) rune range of the line holding the cursor. end excludes the terminating "\n".
func (*TextArea) MoveDown ¶
func (t *TextArea) MoveDown()
MoveDown moves to the next line, keeping the column where possible. It is a no-op on the last line.
func (*TextArea) MoveLineEnd ¶
func (t *TextArea) MoveLineEnd()
func (*TextArea) MoveLineStart ¶
func (t *TextArea) MoveLineStart()
func (*TextArea) MoveUp ¶
func (t *TextArea) MoveUp()
MoveUp moves to the previous line, keeping the column where possible. It is a no-op on the first line (and therefore in single-line mode).
func (*TextArea) MoveWordBack ¶
func (t *TextArea) MoveWordBack()
MoveWordBack moves to the start of the previous word (vi b).
func (*TextArea) MoveWordForward ¶
func (t *TextArea) MoveWordForward()
MoveWordForward moves to the start of the next word (vi w).
func (*TextArea) WordBackStart ¶
WordBackStart returns the offset of the start of the word before the cursor: skip separators, then skip the word itself.
func (*TextArea) WordForwardStart ¶
WordForwardStart returns the offset of the start of the next word: skip the current word, then skip separators.