gum/choose/choose.go
Maas Lalani 46ddc28ae5
feat: gum choose, pick from a list of choices
gum choose allows the user to be prompted for a choice from a list of choices.

For example, let's ask the user to pick a card from a deck.
gum choose --height 15 {Ace,King,Queen,Jack,Ten,Nine,Eight,Seven,Six,Five,Four,Three,Two}" of "{Spades,Hearts,Clubs,Diamonds}
2022-07-11 16:26:23 -04:00

102 lines
2 KiB
Go

package choose
import (
"fmt"
"io"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type model struct {
choice string
height int
indicator string
indicatorStyle lipgloss.Style
itemStyle lipgloss.Style
items []item
list list.Model
options []string
quitting bool
selectedItemStyle lipgloss.Style
}
type item string
func (i item) FilterValue() string { return "" }
type itemDelegate struct {
indicator string
indicatorStyle lipgloss.Style
itemStyle lipgloss.Style
selectedItemStyle lipgloss.Style
}
func (d itemDelegate) Height() int { return 1 }
func (d itemDelegate) Spacing() int { return 0 }
func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i, ok := listItem.(item)
if !ok {
return
}
str := fmt.Sprintf("%s", i)
fn := d.itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return d.indicatorStyle.Render(d.indicator) + d.selectedItemStyle.Render(s)
}
}
fmt.Fprintf(w, fn(str))
}
func (m model) Init() tea.Cmd { return nil }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.list.SetWidth(msg.Width)
return m, nil
case tea.KeyMsg:
switch keypress := msg.String(); keypress {
case "ctrl+c":
m.quitting = true
return m, tea.Quit
case "enter":
m.quitting = true
i, ok := m.list.SelectedItem().(item)
if ok {
m.choice = string(i)
}
return m, tea.Quit
}
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
return m, cmd
}
func (m model) View() string {
if m.quitting {
return ""
}
return m.list.View()
}
func clamp(min, max, val int) int {
if val < min {
return min
}
if val > max {
return max
}
return val
}