mirror of
https://github.com/charmbracelet/gum.git
synced 2024-10-26 07:10:39 +03:00
113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
// Package choose provides an interface to choose one option from a given list
|
|
// of options. The options can be provided as (new-line separated) stdin or a
|
|
// list of arguments.
|
|
//
|
|
// It is different from the filter command as it does not provide a fuzzy
|
|
// finding input, so it is best used for smaller lists of options.
|
|
//
|
|
// Let's pick from a list of gum flavors:
|
|
//
|
|
// $ gum choose "Strawberry" "Banana" "Cherry"
|
|
//
|
|
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
|
|
}
|