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 EditorCommand(path string) *exec.Cmd
- func FooterHints[H any](actions []KeyAction[H]) []string
- func LastLine(out []byte, err error) string
- func Once(board Board, pal gotermstyle.Palette, width, height int) string
- func OnceSize(fallbackWidth, fallbackHeight int) (width, height int)
- func OpenClaudeSession(session ClaudeSession) tea.Cmd
- func OpenWindow(name, dir string, argv []string, needs ...string) error
- func OpenWindowBehind(name, dir string, argv []string, needs ...string) error
- func RefreshAll(ctx context.Context, sources ...Refresher)
- func RunKey[H any](host H, actions []KeyAction[H], key string) (tea.Cmd, bool)
- func SpinnerAt(now time.Time) string
- func TableKeys() []string
- type Action
- type Board
- type BusyBoard
- type Cell
- type Choice
- type ClaudeSession
- type ClaudeSessionOutcome
- type Column
- type CursorBoard
- type Document
- type EntityBoard
- type EntityRef
- type Frame
- type Group
- type HandedBack
- type Host
- type KeyAction
- type KeySection
- type Keyed
- type LastRowBoard
- type Line
- type Look
- type LookBoard
- type Model
- func (m *Model) Ask(q Question)
- func (m *Model) CloseInPlace() bool
- func (m *Model) Cursor() string
- func (m *Model) CursorEntities() []EntityRef
- func (m *Model) Follow(title string, document Document, closed func())
- func (m *Model) HalfScreen() int
- func (m *Model) HandOver(cmd *exec.Cmd, then func(m *Model, err error, stderr []byte) tea.Cmd) tea.Cmd
- func (m *Model) Init() tea.Cmd
- func (m *Model) MoveCursorTo(key string) bool
- 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 Outside
- type Question
- type Reader
- type ReceivingBoard
- type Refresher
- type Row
- type RuleWeight
- type Source
- type Status
- type Tab
- type Tabs
- type TailBoard
- type TwoLineBoard
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 ( LockGlyph = "●" LockCode = BoldCyan )
The mark a row naming what the tabs are locked to draws in MarkGlyph's cell, in its place.
const ( SectionMoving = "Moving" SectionOpening = "Opening" SectionEverywhere = "Everywhere" )
Sections UniversalActions files its rows under.
const JumpKey = "t"
JumpKey goes to what the cursor's row names, where another tab or a program outside shows it.
const LockKey = "*"
LockKey locks every tab to what the cursor's row names, and lifts the lock from any tab. It is cross-filtering, as Tableau's brushing and linking or Grafana's ad hoc filters are.
const PageKey = "i"
PageKey opens the entity page on what the cursor's row names, from any tab, the page's own included.
const PanelFrom = 160
PanelFrom is the narrowest width inside a board's Look margin that gets the side panel. On a board with no Look, that is the screen's width.
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.
const SpinEvery = 100 * time.Millisecond
SpinEvery is how long a spinner holds each drawing: the footer's beside work under way, and one a board turns on its own clock.
Variables ¶
This section is empty.
Functions ¶
func EditorCommand ¶ added in v0.22.0
EditorCommand is the user's editor on path: $VISUAL, then $EDITOR, then vi, split on spaces, so EDITOR="code --wait" works. A board's key hands it the terminal with Model.HandOver, as the Reader's e does with tea.ExecProcess.
func FooterHints ¶ added in v0.43.0
FooterHints is the footer's words for actions in their order, leaving out each row that leaves its key to the ? overlay.
func LastLine ¶ added in v0.30.0
LastLine is the last line a failed command wrote, or how it ended where it wrote nothing.
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. It is printedframe.Size.
func OpenClaudeSession ¶ added in v0.43.0
func OpenClaudeSession(session ClaudeSession) tea.Cmd
OpenClaudeSession is C: a Claude session on a record, in session.Dir. Inside tmux it opens in a window of its own, so the board stays usable while the session works. tmux answers once the window exists, before claude starts, so the outcome says only that the window opened. Outside tmux it holds the terminal until it ends, and a failure says the last line it wrote to stderr. The command ends in a ClaudeSessionOutcome either way, so a Model and a host that draws its own screen open it alike.
func OpenWindow ¶ added in v0.30.0
OpenWindow runs argv in a new tmux window named name, in dir where dir is not empty. tmux makes the window current, and the board keeps running in its own. tmux runs several arguments with no shell, so none needs quoting, and runs a lone one through its default-shell.
tmux opens the window whether or not its program starts, and in another directory where dir is gone, so tmux, argv[0] and every program in needs are looked for on PATH first, and dir is looked for too. A lone argument holding a space is a shell command rather than a program, so needs names what it runs. Outside tmux it opens nothing, because tmux would open the window in whichever session it last used.
func OpenWindowBehind ¶ added in v0.42.0
OpenWindowBehind is OpenWindow with the board's window left current: tmux opens the new one behind it, for a command that runs on its own while the board stays in front.
func RefreshAll ¶
RefreshAll reads every source once, all at once, and returns when each ended.
func RunKey ¶ added in v0.43.0
RunKey runs the first of actions bound to key on host, and says whether one was.
Types ¶
type Action ¶
Action is one row of a Model's key table. A board's key hides the table's action for it even while Applies is false.
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 BusyBoard ¶ added in v0.21.0
type BusyBoard interface {
UnderWay() string
}
BusyBoard is a Board with work under way, such as a command its key started. The footer names it after a spinner, above what the last key did, until UnderWay is empty again. A key never clears it.
type Cell ¶
type Cell struct {
Text string
Code string
// Role is the TUI theme role the cell draws in, such as syntax.keyword, with Code's
// attributes over it. A board, its tabs and a Reader resolve it in their live theme wherever
// they draw the cell, so a reload recolors it. Line.Paint resolves it in the built-in theme.
Role 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 Choice ¶ added in v0.42.0
type Choice struct {
// Key is the key that picks it, as Bubble Tea names a press, such as "n" or "N".
Key string
// Label says what picking it does, drawn after the key and cut at the screen's edge.
Label string
}
Choice is one answer of a Question's menu.
type ClaudeSession ¶ added in v0.43.0
type ClaudeSession struct {
// On names the record as its handle on the command line, such as an issue's number. The tmux
// window is named "claude <On>", and every sentence about the session names it.
On string
// Dir is where the session runs: the record's checkout, or else the board's own directory.
Dir string
// Fallback is why Dir is not the record's checkout, as a bare clause completing "because",
// such as "12 names no one repo". It is empty where Dir is the record's checkout.
Fallback string
// Brief says what the record is and the command that prints it whole, and asks nothing.
// OpenClaudeSession adds the ask after it, and with a Fallback where the session runs and
// why, because that directory may hold another repo's code.
Brief string
// Env is KEY=value pairs the session starts with on top of the program's environment. Inside
// tmux they go ahead of claude through env, because a window takes its environment from the
// tmux server.
Env []string
}
ClaudeSession is a Claude session a board's C opens on one record.
type ClaudeSessionOutcome ¶ added in v0.43.0
type ClaudeSessionOutcome struct {
Session ClaudeSession
// Said is the sentence saying what came of it.
Said string
// Err is why no session opened, or how one that held the terminal failed. It is nil where a
// window opened, or the session ended 0.
Err error
// HeldTerminal says the session held the terminal and has ended, so what it changed is there
// to read again.
HeldTerminal bool
// Stderr is the end of what a session that held the terminal wrote to stderr.
Stderr []byte
}
ClaudeSessionOutcome is what came of OpenClaudeSession. A Model says Said on its footer while it shows, then hands the outcome to its ReceivingBoard. The tab showing is the tab whose key opened the session, because a session holding the terminal leaves no key to change tabs with, and tmux makes the window it opens current. A host draws Said where it says what a key did.
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
// contains filtered or unexported fields
}
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 EntityBoard ¶ added in v0.40.0
type EntityBoard interface {
// EntityKinds is the kinds a jump lands on here.
EntityKinds() []string
// ShowEntity is told the entity a jump came for, before its tab shows, so the board can
// change what it reads. It says whether the board now shows the entity whole, as a page
// given to one thing does. Where it does not, the cursor goes to the first group or row
// naming the entity once the reads land. Either way the tab starts at its top and reads
// every source at once, as Model.Restart does.
ShowEntity(ref EntityRef) (whole bool)
}
EntityBoard is a Board that shows some kinds of entity, so a row in another tab naming one can jump here.
type EntityRef ¶ added in v0.40.0
EntityRef names one thing a row or a group is about, by a kind and an id every view agrees on, as a Backstage entity reference or a Kubernetes object reference does. The package gives no kind a meaning, so a caller names its own.
type Frame ¶
type Frame struct {
Strip []Line
// Charts is drawn under the strip at the screen's width, for what has to be laid out at the
// width it gets, as a chart is. It is handed the screen's height too, so a board can keep it to
// a share of a short screen. A moving strip leaves it as the frame drew it.
Charts func(width, height int) []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
// BlankAboveRule draws a blank line between the group's last line and its Rule.
BlankAboveRule bool
// BetweenRows draws a blank line and then a rule of this weight between each two of the
// group's rows, so rows of more than one line read as blocks.
BetweenRows RuleWeight
// 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
// Entities is what the group is about, as Row.Entities has it.
Entities []EntityRef
// contains filtered or unexported fields
}
Group is a header carrying its count, with rows and groups under it.
type HandedBack ¶ added in v0.30.0
type HandedBack struct {
// Err is how the program ended, nil where it exited 0.
Err error
// Stderr is the end of what the program wrote to stderr, empty where the caller set
// cmd.Stderr.
Stderr []byte
// contains filtered or unexported fields
}
HandedBack is what a program Model.HandOver gave the terminal to sends once it exits. Only the model that handed it over takes it, so among Tabs the tab whose key started it runs its then, hidden or not, and no other tab does. That model's board receives it first through ReceivingBoard, to read again what the program may have changed.
type Host ¶ added in v0.43.0
type Host interface {
// MoveBy moves the cursor by rows, stopping on the first and the last. g and G move by 1<<30
// rows, so the cursor plus rows stays inside an int on a 32-bit build.
MoveBy(rows int) tea.Cmd
// HalfScreen is half the list's height in lines.
HalfScreen() int
// ScrollBy moves the text open under the cursor's row by lines, and leaves the cursor on it.
ScrollBy(lines int)
// OnOpenText says the cursor's row shows text open under it, which the half-screen keys and
// J and K then read through.
OnOpenText() bool
// JumpGroup goes to the next group at the cursor's depth or shallower, or the previous where
// direction is negative, as Vim's ]] and [[ move by section.
JumpGroup(direction int)
// HasGroups says the screen has groups for [ and ] to jump between.
HasGroups() bool
// Toggles says enter and space would change something on the cursor's line.
Toggles() bool
// Open is enter: it opens the row's text full screen where it runs past the screen, or a
// side panel already shows it, and otherwise does what ToggleInPlace does.
Open() tea.Cmd
// ToggleInPlace is space: it folds or opens the cursor's group, or opens or closes its row's
// text in place however tall.
ToggleInPlace() tea.Cmd
// ShowKeys opens the ? overlay.
ShowKeys()
// Quit ends the program.
Quit() tea.Cmd
}
Host is a screen of rows that UniversalActions act on: a host that draws its own screen, or a Model. It gains no method, because each host's build would break on the release that added one. A universal key needing more of a host asks for it through an interface of its own, and binds only on a host that implements it.
type KeyAction ¶ added in v0.43.0
type KeyAction[H any] struct { Keys []string // Section heads the row's group in a ? overlay that groups its rows. A Model's overlay lists // its rows in one run. Section string Label string // Footer is the footer's words for the key, or empty to leave it to the ? overlay. Run func(H) tea.Cmd // Applies says whether the screen can use the key now. Nil means always. Applies func(H) bool }
KeyAction is one row of a key table, for a screen of type H. The key handler, the footer and the ? overlay all read the same rows, so a key bound in one shows in the other two. A Model's rows are Action, and a Reader's are KeyAction[*Reader]. A host that draws its own screen builds its table from UniversalActions and rows of its own, reads what applies now through ActionsNow, and reads those rows through RunKey, FooterHints and BySection.
func ActionsNow ¶ added in v0.43.0
ActionsNow is every key host can use now from layers of rows: each layer's rows that apply, less the keys a layer before it took. A host's key handler, footer and ? overlay all read it, so a key the screen cannot use is in none of them. A host's own rows go in a layer ahead of UniversalActions, so its key wins where it applies, and the universal row acts everywhere else. The rows are in the footer's order, which splits a section where layers share it, so an overlay that heads each section reads BySection(ActionsNow(...)).
func UniversalActions ¶ added in v0.43.0
UniversalActions is the keys every board binds, and a host's table starts from, acting on a Host: moving by rows, to either end and by half a screen, scrolling the open text, jumping between groups, opening a row, the ? overlay and quitting. Each binds where its Applies holds. esc stays the host's, because what it backs out of is the host's. They are in the order a footer names them, with the way to the other keys and the way out ahead of what a narrow footer cuts.
type KeySection ¶ added in v0.43.0
KeySection is one section of a ? overlay: its heading and its rows.
func BySection ¶ added in v0.43.0
func BySection[H any](actions []KeyAction[H]) []KeySection[H]
BySection is actions under their sections, each section where its first row stands and its rows in their order.
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 LastRowBoard ¶ added in v0.44.0
type LastRowBoard interface {
CursorOnLastRow(on bool)
}
LastRowBoard is a Board told whether the cursor sits on the last row the table shows, once each time that changes. The filter and the folds decide which row that is, so a board holding back rows that land while the reader is scrolled back, as less +F stops following once the reader scrolls, lets them in when the reader is back at the end of what shows. A table with no row to sit on counts as on its last, because nothing in it is scrolled back from.
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.
func TallyBar ¶ added in v0.14.0
TallyBar is one cell per unit counted: done ▰ in green, under way ▱ in yellow, blocked ▱ in red and the rest ▱ plain. Its length shows how many there are, and one blocked unit among sixty still shows, where a fixed width would round it away. Without color only done is filled, so no unfinished unit reads as done. In a WrapLast it keeps every cell however narrow the row.
type Look ¶ added in v0.35.0
type Look struct {
// Sides is the blank columns at each side of the screen, and Ends the blank lines above
// and below it. A screen too small for them keeps a column and a line to draw in.
Sides, Ends int
// Spread fills the table's width with its columns at their own widths, dealing what they
// leave out between them from the left, rather than the last column taking it. A column
// with no title continues the one before it and takes none of the spread. A table whose
// rows or groups set WrapLast keeps the slack in its last column, where the text wraps.
Spread bool
// Rules puts the column titles on a line of their own with a rule under it, and a rule
// above the footer.
Rules bool
// BoldCursor draws the cursor's row bold over the theme's selection, as it is where there
// is none.
BoldCursor bool
// NoRowChevrons leaves a row's chevron cell blank, for a board whose every row opens, where
// a chevron tells no row apart. A group's chevron still draws, and no column moves.
NoRowChevrons bool
}
Look is how a board's screen is laid out where it does not take the default.
type LookBoard ¶ added in v0.35.0
type LookBoard interface {
// Look is how the board draws on a screen this wide, read again as the screen changes size.
Look(width int) Look
}
LookBoard is a Board drawn in a Look of its own rather than the default, whose zero Look draws nothing differently.
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. It draws in the TUI theme file gotermstyle's tuitheme finds, and reads it again on SIGUSR2 while it runs as the program. A file that will not load at start leaves ANSI 0-15, and on a reload keeps the colors on screen. The footer says why.
func (*Model) Ask ¶ added in v0.17.0
Ask puts q on the footer's lines. Until enter or esc every key and paste goes to it, so q and ? type themselves and tab changes no tab.
func (*Model) CloseInPlace ¶ added in v0.28.0
CloseInPlace closes the text open under the cursor's row, as the table's space does, and says whether any was open. A board that binds space to a row verb, such as a mark, calls it first, so space still closes a row open in place.
func (*Model) Cursor ¶
Cursor is the key of the group or row the cursor is on, for a board's own keys.
func (*Model) CursorEntities ¶ added in v0.40.0
CursorEntities is what the group or row under the cursor names.
func (*Model) Follow ¶ added in v0.37.0
Follow opens document on a full-screen Reader over the board at its last line, and keeps it there as the document grows, as tail -f and less +F do, until esc or space closes it. Scrolling up holds the reader where it is, and G follows again. Lines a board's command streams into the document show as each message the board receives lands. closed runs as esc or space closes the reader, so the board can stop what feeds it.
func (*Model) HalfScreen ¶
HalfScreen is half the table's height in lines.
func (*Model) HandOver ¶ added in v0.30.0
func (m *Model) HandOver(cmd *exec.Cmd, then func(m *Model, err error, stderr []byte) tea.Cmd) tea.Cmd
HandOver gives the terminal to cmd until it exits, then runs then with how it ended and the end of what it wrote to stderr. LastLine(stderr, err) is the sentence a failure says.
To keep stderr, the program's fd 2 is a pipe whose bytes reach the terminal as they come, so a program that asks whether stderr is a terminal hears no. A caller handing over such a program sets cmd.Stderr, such as to os.Stderr, and keeps nothing.
func (*Model) MoveCursorTo ¶ added in v0.28.0
MoveCursorTo puts the cursor on the group or row keyed key, for a board's key that acts on the cursor's row and moves on, and says whether key shows. A row in a folded group, or one the filter hides, does not. A key that changed what the board holds calls Rebuild first.
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 Outside ¶ added in v0.40.0
type Outside struct {
Kind string
// Name names it among the places a row goes, as a tab's name does.
Name string
// Command is the program opened on one entity's id, which the caller's own runner starts,
// or nil where it cannot open that id. It ends as Model.HandOver's program does: the end
// of its stderr is kept, the board whose row it left receives the HandedBack, and a
// failure says its last line.
Command func(id string) tea.ExecCommand
}
Outside is a program that shows one kind of entity whole, such as a pull request tool opened on one pull request. A jump to it hands it the terminal and pushes nothing, because quitting it comes back to the row the jump left.
type Question ¶ added in v0.17.0
type Question struct {
// Listing draws above Text, a line each, for a question about several things that names
// each one. Each line is cut at the screen's edge. While the question is open the table
// keeps one line, and a listing longer than the rest of the screen ends on how many more
// it held.
Listing []Line
// Text draws in bold as written, so its own punctuation ends it.
Text string
// Typed takes one line typed under the question as the answer. Without it enter alone
// answers, for an act that takes no text, and Answer is handed an empty string.
Typed bool
// Choices are the answers a single key picks, drawn under Text a line each, as a menu. A key
// naming one closes the question and hands Answer that Key, and every other key but esc and
// ctrl+c does nothing, enter included. Typed is ignored where Choices are set.
Choices []Choice
// Answer runs on enter with what was typed, trimmed, or on a choice's key with that key. The
// question has closed by then, so it can Say what it did, ask another question, or return a
// command such as an editor.
Answer func(typed string) tea.Cmd
// Cancel, where set, runs on esc or ctrl+c, so a board can say that nothing was done.
Cancel func() tea.Cmd
}
Question is what a key asks on the footer's lines, until enter or a choice's key answers it or esc takes it away.
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. It draws in the TUI theme file gotermstyle's tuitheme finds, and reads it again on SIGUSR2 while it runs as the program.
func (*Reader) ClosesWith ¶ added in v0.31.0
func (r *Reader) ClosesWith(back func())
ClosesWith is for a program drawing the reader inside a screen of its own, as Model.Read does over a board: esc and space call back once nothing is left to clear, where on a reader running as the program they do nothing.
func (*Reader) Once ¶ added in v0.6.0
Once is the whole document at width, for output nobody scrolls.
type ReceivingBoard ¶ added in v0.21.0
ReceivingBoard is a Board handed every message the model does not handle itself, such as the one a command its key started sends when it ends. Receive runs with the model, so it can Say what came of the command, Rebuild, or return the next command. Tabs hands such a message to every tab, because the tab whose key started the command may be hidden by the time it ends, so a board ignores a message of a type it does not own. A message whose type names where it goes is the exception: a HandedBack reaches only the board whose model handed the terminal over, and a ClaudeSessionOutcome only the board of the tab showing.
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
// Second is a line the row draws under its first, always. Its first cell sits in the first
// column under the row's first cell, and the rest draw one after another from the second
// column, cut at the table's edge. The cursor's row wears its look across both lines. A
// row's Under draws after it.
Second Line
// UnderWhereCut draws Under only where the last column is too narrow for the row's cell
// there, for a summary that repeats that cell. Only the draw knows the column's width.
UnderWhereCut bool
// 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
// ReaderTitle heads the Reader enter opens on a tall Document, and the side panel where
// it draws the Document. Empty, the row's own words head the Reader.
ReaderTitle string
// 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. A row whose
// Document the side panel draws starts folded while the panel shows, since the panel
// draws it whole beside the table.
StartsOpen bool
// Panel is what the side panel shows in place of both, each line wrapping at spaces
// with its cells' own colors. Without one, the panel draws the Document.
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
// Entities is what the row is about, which JumpKey lists and a jump's cursor looks for.
Entities []EntityRef
// 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 RuleDotted )
The weights a rule takes. RuleDotted is the lightest, for between rows.
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 moves no strip, and builds a frame only where its board's Receive rebuilds it. 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. Every tab draws in the one TUI theme file gotermstyle's tuitheme finds, read again on SIGUSR2.
func (*Tabs) EntityPage ¶ added in v0.45.0
EntityPage names the tab that shows any one entity whole, as Backstage gives each entity one page. Its board is an EntityBoard. PageKey goes there, and JumpKey leaves it out of its list, because a row naming three things would otherwise list each twice. A lock marks the lines on the page naming what is locked and hides none, because the page already shows one thing whole.
func (*Tabs) Keys ¶ added in v0.40.0
Keys is every key Tabs binds beside the table's, each where it has something to do, which a board's own key would hide. A board taking keys from its own config asks this and TableKeys which ones it would take.
func (*Tabs) OpenPage ¶ added in v0.45.0
OpenPage opens the program on the entity page showing ref, as PageKey would from a row naming it, so esc from the page opened on another thing comes back to ref. It is for before the program starts, after EntityPage.
func (*Tabs) OpensOutside ¶ added in v0.40.0
OpensOutside adds programs that a row's entity can jump to, after the tabs that show its kind.
type TailBoard ¶
type TailBoard interface {
Tails() bool
}
TailBoard is a Board read from its newest row, as a log is. Its cursor starts on the last row, and stays on the last row as rows land while it is there.
type TwoLineBoard ¶ added in v0.26.0
type TwoLineBoard interface {
TwoLines() bool
}
TwoLineBoard is a Board whose rows' Under summaries start shown. f still hides them.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package breadcrumb fits a path of names, such as "uv › add › Options", on one line.
|
Package breadcrumb fits a path of names, such as "uv › add › Options", on one line. |
|
Package chart draws plain series as lines of cells for a board.
|
Package chart draws plain series as lines of cells for a board. |
|
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, naming a TUI theme role for each cell, such as markdown.heading.2 or syntax.keyword.
|
Package markdown lays markdown out as a board's lines at a given width, naming a TUI theme role for each cell, such as markdown.heading.2 or syntax.keyword. |
|
Package printedframe picks the size one printed frame draws at, as a TUI's --once prints it.
|
Package printedframe picks the size one printed frame draws at, as a TUI's --once prints it. |