Documentation
¶
Overview ¶
Package multiselect demonstrates marking — the multi-selection a user builds with space — on a table.Model, and the action.Set that acts on it.
Press space to mark the cursor row (it toggles both ways), X to extend the selection from the last-marked row down to the cursor, A to mark every row the filter currently shows, D to drop the selection, or click the ✓ gutter. Then press "a" or right-click to open the menu: it is titled with what it will act on ("3 items"), and every verb that did not declare Multi is dimmed with a reason.
X spans either direction from the anchor, which stays put — so ranging again from the same anchor grows or shrinks one span rather than walking it along. Shift+click does the same thing with the mouse. Both are additive, so a range extends a selection rather than replacing it.
Marking is keyed, or it is wrong ¶
Marks are held by the row's Key, not its index, which is why this screen populates the table with SetKeyedRows. On anonymous rows (SetRows) every mark operation is a deliberate no-op: an inert feature is recoverable, and a selection that has silently drifted onto its neighbours is not. That drift is not hypothetical — it is what an index-held mark does the moment a polled refresh reorders the set between the user marking rows and picking a verb.
Two things worth doing to this screen ¶
Mark a row, then filter it out of sight. The count in the title does not move, because a key does not care whether its row is currently visible — so the marked row is still in the selection, and the menu still says "2 items" while one of them is off screen. Correct, and a genuine surprise, which is why the menu's title is the disclosure rather than a decoration.
Then cycle the theme with "t". The marks survive, because SetTheme carries them across the rebuild with SetMarks the same way it carries the cursor and the filter (rule 4). Forgetting that line is invisible until a user loses a twelve-row selection to a keypress that was supposed to change the colours.
Selection() is the accessor to reach for ¶
Not Marks(). Selection() is "the marked keys, or the cursor's key when nothing is marked", which is the branch every caller would otherwise write by hand and some would forget — and whose failure mode is a verb quietly acting on one row when the user had marked six.
Index ¶
- func New(t theme.Theme) screen.Screen
- type Screen
- func (s *Screen) Actions() action.Set
- func (s *Screen) Help() []key.Binding
- func (s *Screen) Init() tea.Cmd
- func (s *Screen) IsCapturingKeys() bool
- func (s *Screen) Layout() layout.Node
- func (s *Screen) OnEnter(any) tea.Cmd
- func (s *Screen) SetTheme(t theme.Theme)
- func (s *Screen) Title() string
- func (s *Screen) Update(msg tea.Msg) (screen.Screen, tea.Cmd)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Screen ¶
type Screen struct {
// contains filtered or unexported fields
}
Screen is an ordinary table screen. Marking is one Options field; acting on the marks is the Actions method at the bottom.
func (*Screen) Actions ¶
Actions satisfies action.Provider. It is rebuilt per call, so it reports on whatever is selected right now.
Every verb reads Selection() identically whether the user marked six rows or marked nothing and left the cursor on one. The arity difference lives in the Multi field, and the menu — not this code — is what enforces it.
func (*Screen) Help ¶
Help leans on the table, which already advertises x, X, A and D because Markable is set — the bindings and the hints come from the same Keys struct (rule 26), so nothing here restates them. The verbs are absent on purpose: moving discovery off the footer and into the menu is most of the point.