Documentation
¶
Overview ¶
Package gotermboard draws a self-refreshing terminal board on Bubble Tea v2: a tab per view, folding groups on shared columns, a side panel that follows the cursor, and one action table the keys, the footer and the ? overlay all read.
A view is a read model, as in CQRS. Its reader joins sources into a snapshot, and its renderer turns the snapshot into a Frame this package draws. A failed read never gives up a good value: a Source keeps its last good read and says how old it is.
Index ¶
- Constants
- func Ago(d time.Duration) string
- func Once(board Board, pal gotermstyle.Palette, width, height int) string
- func OnceSize(fallbackWidth, fallbackHeight int) (width, height int)
- func RefreshAll(ctx context.Context, sources ...Refresher)
- type Action
- type Board
- type Cell
- type Column
- type Frame
- type Group
- type Keyed
- type Line
- type Model
- func (m *Model) Cursor() string
- func (m *Model) HalfScreen() int
- func (m *Model) Init() tea.Cmd
- func (m *Model) Rebuild()
- func (m *Model) Restart() tea.Cmd
- func (m *Model) Say(text string)
- func (m *Model) ScrollBy(lines int)
- func (m *Model) Toggle() tea.Cmd
- func (m *Model) ToggleEveryRow() tea.Cmd
- func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *Model) View() tea.View
- type Refresher
- type Row
- type Source
- type Status
- type Tab
- type Tabs
- type TailBoard
Constants ¶
const ( CueGlyph = "•" CueCode = BoldCyan CueFor = 30 * time.Second )
The cue a row or group wears after it changed. It sits in the pointer's column, so no column moves for it.
const ( Red = gotermstyle.CodeRed Yellow = gotermstyle.CodeYellow Green = gotermstyle.CodeGreen Cyan = gotermstyle.CodeCyan Blue = gotermstyle.CodeBlue Magenta = gotermstyle.CodeMagenta White = gotermstyle.CodeWhite Bold = gotermstyle.CodeBold BoldRed = "\033[1;91m" BoldYellow = "\033[1;93m" BoldGreen = "\033[1;92m" BoldCyan = "\033[1;96m" BoldBlue = "\033[1;94m" BoldMagenta = "\033[1;95m" Reverse = "\033[7m" )
The codes a view colors a cell with, all in ANSI 0-15 so they follow the theme.
const ( MarkGlyph = "◆" MarkCode = BoldMagenta )
The mark a Marked row draws.
const PanelFrom = 160
PanelFrom is the narrowest screen that gets the side panel.
Variables ¶
This section is empty.
Functions ¶
func Once ¶
func Once(board Board, pal gotermstyle.Palette, width, height int) string
Once is one frame at a size, drawn from what the board's sources already hold.
func OnceSize ¶
OnceSize is the size one printed frame draws at: COLUMNS by LINES, then the terminal's own size, then the fallback.
func RefreshAll ¶
RefreshAll reads every source once, all at once, and returns when each ended.
Types ¶
type Action ¶
type Action struct {
Keys []string
Label string
Run func(*Model) tea.Cmd
// Applies says whether this view can use the key now. Nil means always.
Applies func(*Model) bool
}
Action is one row of the key table the handler, the footer and the ? overlay all read.
type Board ¶
type Board interface {
Sources() []Refresher
Groupings() []string
Frame(now time.Time, grouping string) Frame
}
Board is one view, as this package draws it: sources to keep fresh, and the frame their last good reads make now.
type Cell ¶
Cell is text and its color. Ticks says the text follows the clock, as an age does, so its changing is no change to the row, though its color changing still is.
type Column ¶
Column is one column of the table. The last is unpadded, so the screen's edge cuts it first. Max caps its width, where one long value must not take the row.
type Group ¶
type Group struct {
Key string
Title Line
// Count is drawn after the title as " · n", where Counted says to.
Count int
Counted bool
// Cells draw on the columns past the first, which holds the title, so a group's
// totals line up with the rows under it.
Cells []Cell
// WrapLast is the last column as Row.WrapLast has it.
WrapLast Line
// Below are lines drawn under the header whether the group is folded or not. The
// cursor moves past them as one node.
Below []Line
// Summary is drawn past the title while the group is folded.
Summary Line
Folded bool
// Gap draws a blank line after the group.
Gap bool
Rows []Row
Groups []Group
Detail []Cell
// contains filtered or unexported fields
}
Group is a header carrying its count, with rows and groups under it.
type Keyed ¶
type Keyed interface {
Actions() []Action
}
Keyed is a Board with keys of its own. They are read ahead of the table's, so a view can add a key or take one over, and the footer and the ? overlay list them.
type Line ¶
type Line []Cell
Line is cells drawn one after another.
func ReadStatus ¶
ReadStatus is the one line a strip says about its reads. While every read is on schedule it says how old the newest is. A failed read is named in red with its reason, a late one in yellow, and a note follows plain, because a read that covered less still read. The screen's edge cuts them in that order.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the Bubble Tea program of one view. Tabs holds one per tab.
func NewModel ¶
func NewModel(board Board, pal gotermstyle.Palette) *Model
NewModel is a model reading board, sized until the terminal says otherwise.
func (*Model) Cursor ¶
Cursor is the key of the group or row the cursor is on, for a board's own keys.
func (*Model) HalfScreen ¶
HalfScreen is half the table's height in lines.
func (*Model) Rebuild ¶
func (m *Model) Rebuild()
Rebuild is for a key that changed what the board shows from what it already holds.
func (*Model) Restart ¶
Restart puts the cursor back at the top and reads every source now, for a board's key that changes what the view shows.
func (*Model) ScrollBy ¶
ScrollBy moves the screen over the table by lines and leaves the cursor, for reading through a row's detail taller than the screen. Moving the cursor ends it.
func (*Model) Toggle ¶
Toggle folds the group under the cursor or opens its row's detail, for a board's key that takes enter and acts only on some rows.
func (*Model) ToggleEveryRow ¶
ToggleEveryRow opens every showing row's detail, or closes them all where every one is open already, so a whole group reads as one document.
type Refresher ¶
type Refresher interface {
// Claim reports whether a read is due at now, and marks one under way.
Claim(now time.Time) bool
Refresh(ctx context.Context)
// Force makes the next Claim true.
Force()
Status() Status
}
Refresher is a Source with its value's type out of the way, for the loop that only starts reads.
type Row ¶
type Row struct {
Key string
Symbol Cell
Cells []Cell
Span Line
// WrapLast is the last column as cells of their own colors. It continues on
// further lines at that column, where a cell in Cells is cut at the screen's edge.
WrapLast Line
// Chevron draws ▸ or ▾ in Symbol's place, for a row whose Detail is the point of it.
Chevron bool
// Under is the row's first line, drawn on a └─ row while those are on.
Under Cell
// Detail is what the side panel shows while the cursor is on the row, and
// what enter opens under the row. Each cell is a paragraph that wraps.
Detail []Cell
// Text is more the filter matches beyond what the row draws.
Text string
// Marked draws MarkGlyph in the row's indent and its first cell in MarkCode. No
// column moves for it.
Marked bool
// contains filtered or unexported fields
}
Row is one line of the table: Cells on the columns, or Span across them.
type Source ¶
type Source[T any] struct { // contains filtered or unexported fields }
Source is one read at its own interval, holding its last good value.
func NewSource ¶
func NewSource[T any](name string, every time.Duration, read func(context.Context) (T, string, error)) *Source[T]
NewSource declares a read. read answers the value, a note on what it could not cover, and a failure, which leaves the last good value in place.
func (*Source[T]) Claim ¶
Claim is Refresher's. A read still under way is never started twice, so a slow source falls behind rather than piling up.
type Status ¶
type Status struct {
Name string `json:"name"`
Every string `json:"every"`
ReadAt time.Time `json:"read_at,omitzero"`
Took string `json:"took,omitempty"`
TriedAt time.Time `json:"tried_at,omitzero"`
// Fault is why the newest try failed, and empty where it read.
Fault string `json:"fault,omitempty"`
// Note is what a read that succeeded could not cover, such as a host asleep.
Note string `json:"note,omitempty"`
// Reading says a read is under way.
Reading bool `json:"reading,omitempty"`
// contains filtered or unexported fields
}
Status is what a view says about one source, on its strip and in its --json.
type Tabs ¶
type Tabs struct {
// contains filtered or unexported fields
}
Tabs is the Bubble Tea program of one Model per tab, the Elm Architecture's composition. Each tab keeps its own cursor, folds and filter. A hidden tab starts no read and builds no frame. On its return it draws its last good read with that read's age, and whatever is due reads at once.
func NewTabs ¶
NewTabs is a program of these tabs, opening on the one named open, or the first where open is empty. A name no tab has is an error naming the ones there are.