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 CursorBoard
- type Document
- 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) Read(title string, document Document)
- func (m *Model) Rebuild()
- func (m *Model) Restart() tea.Cmd
- func (m *Model) Reveal()
- func (m *Model) Say(text string)
- func (m *Model) ScrollBy(lines int)
- func (m *Model) Tall(document Document) bool
- 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 MovingBoard
- type Reader
- type Refresher
- type Row
- type RuleWeight
- 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.
const ReadingWidth = 100
ReadingWidth is the widest a reader lays text out, because a longer line is hard to follow back to its start. A wider screen keeps the rest as margin. A view that lays the same text out in its table reads this, so the two wrap alike.
const RuleCode = "\033[0;90m"
RuleCode is the gray a rule draws in, which the terminal palette's theme sets.
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 ¶
type Cell struct {
Text string
Code string
Ticks bool
// Section says this cell starts the words of a heading, where a Reader's [ and ] land, and
// how deep the heading sits: 1 is outermost, and 0 is no heading. A heading closes every
// open one at its depth or deeper, which is the path a Reader's top line draws.
Section int
// contains filtered or unexported fields
}
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 ¶
type Column struct {
Title string
// Min holds the column at least this wide, for what a group's Beside fits into.
Min int
Max int
Right bool
}
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 CursorBoard ¶ added in v0.3.0
type CursorBoard interface {
CursorOn(key string)
}
CursorBoard is a Board told which key the cursor is on, for a read that follows it.
type Document ¶ added in v0.4.0
Document is text that lays itself out at a width, for what only the draw can place: hanging bullets, tables and boxes of code. Its lines are drawn as they come.
type Frame ¶
type Frame struct {
Strip []Line
Columns []Column
Groups []Group
// StartAt is the key the cursor starts on, where that key is showing. Without one it
// starts on the first line holding cells, or the last on a TailBoard, past any group with
// no panel text. With no such line it starts on the first line with text to read.
StartAt string
}
Frame is one screen of a view, before it is laid out to a size.
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
// Span draws whole past the title on the header's line, wrapping under itself, so a
// long value never sets the first column's width. The cells then take a line of their
// own beneath it, and Beside sits ahead of them in the first column.
Span Line
// Beside is what the first column holds on a Span group's line of cells, under the
// Span's start. An Items line there is cut to fit.
Beside Line
// Under is the group's summary, wrapping on a └─ row under Below while those are on.
Under Cell
// Document draws under Below whether the group is folded or not, so a view can open
// a group's text in place. The cursor moves past it too.
Document Document
// 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
// Rule draws a thin line after the group, in place of Gap's blank one.
Rule bool
// Tone is the code the group's overline and underline draw in, where not the rule gray.
Tone string
// Overline draws a line across the table above the header.
Overline RuleWeight
// Underline draws a line across the table under the header, ahead of Below.
Underline RuleWeight
// Still keeps the header open with no fold mark, and the cursor passes over it. At
// the top of a frame it stays on screen with the column titles while the table scrolls.
Still bool
// Heading says the title only labels what sits under it, so the filter looks past it.
Heading bool
// FilterOnly keeps the group out of the table until a filter is typed, so a search
// reaches past what a view shows.
FilterOnly bool
Rows []Row
Groups []Group
Detail []Cell
// Panel is what the side panel shows in Detail's place, as Row.Panel has it.
Panel Document
// Text is more the filter matches beyond what the group draws.
Text string
// 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 Items ¶ added in v0.3.0
Items is a line of a Group's Below that the draw cuts to the items that fit, ending in +N for the rest, rather than letting the screen's edge cut one in half. The width it has moves with the side panel, so only the draw knows it. The filter and the change cue read every item, shown or not.
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) Read ¶ added in v0.6.0
Read opens document on a full-screen Reader over the board, until esc or space closes it. The reader's top line names the groups holding the cursor's line, then title.
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) Reveal ¶ added in v0.3.0
func (m *Model) Reveal()
Reveal scrolls the cursor's row and what opens under it into view, for a board's key that opens text under a row.
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) Tall ¶ added in v0.6.0
Tall says document runs past the screen, so enter reads it on a Reader.
func (*Model) Toggle ¶
Toggle is what enter does, for a board's key that takes enter and acts only on some rows: a row's Document that runs past the screen opens on a Reader, open in place or not, and anything else folds or opens in place. Bind it to enter alone and leave space to the table, which folds in place however tall the text. A row open in place that turns tall closes only on that space.
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 MovingBoard ¶ added in v0.12.0
type MovingBoard interface {
// MoveEvery is how long the strip holds each drawing. Zero or less holds it still, and the
// next tick asks again, so a board with nothing moving spends nothing.
MoveEvery() time.Duration
// StripAt is the whole strip at now. It stands in for Frame.Strip on every draw, so a line
// holding still is returned as it is. A strip that changes its height redraws the table.
StripAt(now time.Time) []Line
}
MovingBoard is a Board whose strip moves between its frames, as a diagram of work in motion does. Only the strip redraws at this pace, so the table and its change cue wait for their frame. Only the tab showing runs it, and a reader over the board holds it.
type Reader ¶ added in v0.6.0
type Reader struct {
// CopyText is what y copies. Nil copies the text as drawn.
CopyText func() string
// EditFile is the file e opens in the editor, after which the text is laid out again.
// Empty leaves e unbound.
EditFile string
// contains filtered or unexported fields
}
Reader is a full screen over one Document. It lays out every row at the width and draws the window that fits, because Bubble Tea keeps only the last lines of a taller view. It runs as a program of its own, or a Model opens one with Read.
func NewReader ¶ added in v0.6.0
func NewReader(title string, document Document, pal gotermstyle.Palette) *Reader
NewReader is a Reader over document, sized until the terminal says otherwise.
func (*Reader) Once ¶ added in v0.6.0
Once is the whole document at width, for output nobody scrolls.
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
// Under is the row's summary, 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 opens
// under the row. Each cell is a paragraph that wraps. A row holding Detail or a
// Document draws a chevron in its indent.
Detail []Cell
// Document is what opens under the row and the side panel shows, in Detail's place.
Document Document
// StartsOpen shows the row's Detail or Document under it until a key closes it, so a
// view can draw its newest entry whole and still fold it to its first line.
StartsOpen bool
// Panel is what the side panel shows in place of both, each line wrapping at spaces
// with its cells' own colors.
Panel Document
// 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 RuleWeight ¶ added in v0.8.0
type RuleWeight int
RuleWeight is how heavy a line across the table is drawn.
const ( RuleNone RuleWeight = iota RuleThin RuleDouble )
The weights a rule takes.
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, builds no frame and moves no strip. 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.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
read-markdown
command
read-markdown draws a markdown file, or what is piped to it, on a full-screen reader.
|
read-markdown draws a markdown file, or what is piped to it, on a full-screen reader. |
|
Package markdown lays markdown out as a board's lines at a given width, in colors that follow the terminal's theme.
|
Package markdown lays markdown out as a board's lines at a given width, in colors that follow the terminal's theme. |