multiselect package provides an interactive terminal user interface (TUI) component built with Bubble Tea for selecting multiple items from a list. It’s used throughout Pumu for interactive folder selection in sweep and reinstall operations.
Location
internal/ui/multiselect.go
Core Types
Item
Represents a selectable item in the multi-select list.Label- The main display text for the itemDetail- Optional supplementary information displayed alongside the labelSelected- Whether the item is currently selected
Result
Holds the outcome of the multi-select interaction.Items- The complete list of items with their final selection statesCanceled- Indicates whether the user canceled the operation instead of confirming
model
Internal Bubble Tea model (unexported). Implements thetea.Model interface.
title- Header text displayed at the topitems- The list of selectable itemscursor- Current cursor position (0-based index)showHelp- Whether the help menu is currently visibledone- Whether the interaction is completecanceled- Whether the user canceled
Public API
RunMultiSelect
Launches an interactive multi-select prompt and returns the result.title- The header text shown at the top of the selection UIitems- Slice of items to display. Pre-setSelected: truefor default selections
Result- Contains the items with updated selection states and cancellation statuserror- Returns error if the Bubble Tea program fails to run
- All items passed in with
Selected: truewill be pre-selected by default - Blocks until user confirms (Enter) or cancels (q/Esc)
- Returns immediately if an error occurs
Bubble Tea Implementation
Init
nil (no initial commands).
Update
- Keyboard input via
handleKeyMsg() - Returns
tea.Quitcommand when done
View
- Title - Bold, purple header
- Item list - Each item shows:
- Cursor indicator (
▸for current item) - Checkbox (
[✓]for selected,[ ]for unselected) - Label text (highlighted when cursor is on it)
- Detail text in blue (if present)
- Cursor indicator (
- Status bar - Shows
X/Y selectedcount - Help text - Shows
press ? for helpor full keyboard shortcuts when toggled
Keyboard Shortcuts
| Key | Action | Description |
|---|---|---|
↑ / k | Move up | Move cursor to previous item |
↓ / j | Move down | Move cursor to next item |
g | Go to first | Jump to first item in list |
G | Go to last | Jump to last item in list |
space | Toggle item | Toggle selection state of current item |
a | Select all | Select all items in the list |
n | Deselect all | Clear all selections |
i | Invert selection | Toggle selection state of all items |
enter | Confirm | Accept current selections and exit |
q / esc / ctrl+c | Cancel | Exit without saving changes |
? | Toggle help | Show/hide full keyboard shortcuts |
Message Handling
handleKeyMsg
- Navigation keys - Delegates to
handleNavigation() - Selection keys - Delegates to
handleSelection() - Help toggle -
?key toggles help display - Confirm -
entersetsdone = trueand quits - Cancel -
q,esc, orctrl+csets bothcanceledanddone, then quits
handleNavigation
up/k- Decrement cursor (bounded at 0)down/j- Increment cursor (bounded at list length)home/g- Set cursor to 0end/G- Set cursor to last item
handleSelection
space- Toggle current itema- Set all items to selectedn- Clear all selectionsi- Invert all selections
Visual Styling
The component uses Lipgloss for styling:| Element | Color | Style |
|---|---|---|
| Title | Purple #7C3AED | Bold |
| Cursor | Purple #7C3AED | Bold |
| Selected checkbox | Green #22C55E | Bold |
| Unselected checkbox | Gray #6B7280 | Regular |
| Active item label | White #E5E7EB | Regular |
| Inactive item label | Gray #9CA3AF | Regular |
| Detail text | Blue #60A5FA | Regular |
| Status bar | Purple #A78BFA | Regular |
| Help key | Purple #A78BFA | Bold |
| Help description | Gray #9CA3AF | Regular |
Usage Example
Basic Usage (from sweep command)
Reinstall Selection (from sweep —reinstall)
Integration Points
The multi-select component is used in:-
Sweep command (
scanner.SweepDir)- Selecting which folders to delete
- Selecting which projects to reinstall (when
--reinstallis used)
-
Command-line flow
pumu sweep- Interactive folder deletion selectionpumu sweep --reinstall- Two-stage selection (delete + reinstall)pumu sweep --no-select- Bypasses multi-select entirely
Error Handling
Implementation Notes
- Thread-safe - Model is isolated within Bubble Tea’s event loop
- No external state - All state is contained in the model struct
- Keyboard-driven - No mouse support
- Accessible - Uses standard terminal conventions (arrow keys, vi keys, etc.)
- Minimal dependencies - Only requires Bubble Tea and Lipgloss
- Single-use - Each
RunMultiSelect()call creates a fresh program instance
See Also
- Bubble Tea Documentation
- Lipgloss Styling Guide
- Pumu source:
internal/scanner/scanner.go:selectFolders()