mirror of
https://github.com/taigrr/bubbletea.git
synced 2026-04-02 02:59:09 -07:00
Add list examples
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,6 +4,9 @@
|
||||
examples/fullscreen/fullscreen
|
||||
examples/help/help
|
||||
examples/http/http
|
||||
examples/list-default/list-default
|
||||
examples/list-fancy/list-fancy
|
||||
examples/list-simple/list-simple
|
||||
examples/mouse/mouse
|
||||
examples/pager/pager
|
||||
examples/simple/simple
|
||||
|
||||
@@ -29,6 +29,7 @@ github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k
|
||||
github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 h1:VRIbnDWRmAh5yBdz+J6yFMF5vso1It6vn+WmM/5l7MA=
|
||||
github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776/go.mod h1:9wvnDu3YOfxzWM9Cst40msBF1C2UdQgDv962oTxSuMs=
|
||||
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
@@ -63,6 +64,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
|
||||
87
examples/list-default/main.go
Normal file
87
examples/list-default/main.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var docStyle = lipgloss.NewStyle().Margin(1, 2)
|
||||
|
||||
type item struct {
|
||||
title, desc string
|
||||
}
|
||||
|
||||
func (i item) Title() string { return i.title }
|
||||
func (i item) Description() string { return i.desc }
|
||||
func (i item) FilterValue() string { return i.title }
|
||||
|
||||
type model struct {
|
||||
list list.Model
|
||||
}
|
||||
|
||||
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.KeyMsg:
|
||||
if msg.String() == "ctrl+c" {
|
||||
return m, nil
|
||||
}
|
||||
case tea.WindowSizeMsg:
|
||||
top, right, bottom, left := docStyle.GetMargin()
|
||||
m.list.SetSize(msg.Width-left-right, msg.Height-top-bottom)
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
return docStyle.Render(m.list.View())
|
||||
}
|
||||
|
||||
func main() {
|
||||
items := []list.Item{
|
||||
item{title: "Raspberry Pi’s", desc: "I have ’em all over my house"},
|
||||
item{title: "Nutella", desc: "It's good on toast"},
|
||||
item{title: "Bitter melon", desc: "It cools you down"},
|
||||
item{title: "Nice socks", desc: "And by that I mean socks without holes"},
|
||||
item{title: "Eight hours of sleep", desc: "I had this once"},
|
||||
item{title: "Cats", desc: "Usually"},
|
||||
item{title: "Plantasia, the album", desc: "My plants love it too"},
|
||||
item{title: "Pour over coffee", desc: "It takes forever to make though"},
|
||||
item{title: "VR", desc: "Virtual reality...what is there to say?"},
|
||||
item{title: "Noguchi Lamps", desc: "Such pleasing organic forms"},
|
||||
item{title: "Linux", desc: "Pretty much the best OS"},
|
||||
item{title: "Business school", desc: "Just kidding"},
|
||||
item{title: "Pottery", desc: "Wet clay is a great feeling"},
|
||||
item{title: "Shampoo", desc: "Nothing like clean hair"},
|
||||
item{title: "Table tennis", desc: "It’s surprisingly exhausting"},
|
||||
item{title: "Milk crates", desc: "Great for packing in your extra stuff"},
|
||||
item{title: "Afternoon tea", desc: "Especially the tea sandwich part"},
|
||||
item{title: "Stickers", desc: "The thicker the vinyl the better"},
|
||||
item{title: "20° Weather", desc: "Celsius, not Fahrenheit"},
|
||||
item{title: "Warm light", desc: "Like around 2700 Kelvin"},
|
||||
item{title: "The vernal equinox", desc: "The autumnal equinox is pretty good too"},
|
||||
item{title: "Gaffer’s tape", desc: "Basically sticky fabric"},
|
||||
item{title: "Terrycloth", desc: "In other words, towel fabric"},
|
||||
}
|
||||
|
||||
m := model{list: list.NewModel(items, list.NewDefaultDelegate(), 0, 0)}
|
||||
m.list.Title = "My Fave Things"
|
||||
|
||||
p := tea.NewProgram(m)
|
||||
p.EnterAltScreen()
|
||||
|
||||
if err := p.Start(); err != nil {
|
||||
fmt.Println("Error running program:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
89
examples/list-fancy/delegate.go
Normal file
89
examples/list-fancy/delegate.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func newItemDelegate(keys *delegateKeyMap) list.DefaultDelegate {
|
||||
d := list.NewDefaultDelegate()
|
||||
|
||||
d.UpdateFunc = func(msg tea.Msg, m *list.Model) tea.Cmd {
|
||||
var title string
|
||||
|
||||
if i, ok := m.SelectedItem().(item); ok {
|
||||
title = i.Title()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
case key.Matches(msg, keys.choose):
|
||||
return m.NewStatusMessage(statusMessageStyle("You chose " + title))
|
||||
|
||||
case key.Matches(msg, keys.remove):
|
||||
index := m.Index()
|
||||
m.RemoveItem(index)
|
||||
if len(m.Items()) == 0 {
|
||||
keys.remove.SetEnabled(false)
|
||||
}
|
||||
return m.NewStatusMessage(statusMessageStyle("Deleted " + title))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
help := []key.Binding{keys.choose, keys.remove}
|
||||
|
||||
d.ShortHelpFunc = func() []key.Binding {
|
||||
return help
|
||||
}
|
||||
|
||||
d.FullHelpFunc = func() [][]key.Binding {
|
||||
return [][]key.Binding{help}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
type delegateKeyMap struct {
|
||||
choose key.Binding
|
||||
remove key.Binding
|
||||
}
|
||||
|
||||
// Additional short help entries. This satisfies the help.KeyMap interface and
|
||||
// is entirely optional.
|
||||
func (d delegateKeyMap) ShortHelp() []key.Binding {
|
||||
return []key.Binding{
|
||||
d.choose,
|
||||
d.remove,
|
||||
}
|
||||
}
|
||||
|
||||
// Additional full help entries. This satisfies the help.KeyMap interface and
|
||||
// is entirely optional.
|
||||
func (d delegateKeyMap) FullHelp() [][]key.Binding {
|
||||
return [][]key.Binding{
|
||||
{
|
||||
d.choose,
|
||||
d.remove,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newDelegateKeyMap() *delegateKeyMap {
|
||||
return &delegateKeyMap{
|
||||
choose: key.NewBinding(
|
||||
key.WithKeys("enter"),
|
||||
key.WithHelp("enter", "choose"),
|
||||
),
|
||||
remove: key.NewBinding(
|
||||
key.WithKeys("x", "backspace"),
|
||||
key.WithHelp("x", "delete"),
|
||||
),
|
||||
}
|
||||
}
|
||||
190
examples/list-fancy/main.go
Normal file
190
examples/list-fancy/main.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var (
|
||||
appStyle = lipgloss.NewStyle().Padding(1, 2)
|
||||
|
||||
titleStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#FFFDF5")).
|
||||
Background(lipgloss.Color("#25A065")).
|
||||
Padding(0, 1)
|
||||
|
||||
statusMessageStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).
|
||||
Render
|
||||
)
|
||||
|
||||
type item struct {
|
||||
title string
|
||||
description string
|
||||
}
|
||||
|
||||
func (i item) Title() string { return i.title }
|
||||
func (i item) Description() string { return i.description }
|
||||
func (i item) FilterValue() string { return i.title }
|
||||
|
||||
type listKeyMap struct {
|
||||
toggleSpinner key.Binding
|
||||
toggleTitleBar key.Binding
|
||||
toggleStatusBar key.Binding
|
||||
togglePagination key.Binding
|
||||
toggleHelpMenu key.Binding
|
||||
insertItem key.Binding
|
||||
}
|
||||
|
||||
func newListKeyMap() *listKeyMap {
|
||||
return &listKeyMap{
|
||||
insertItem: key.NewBinding(
|
||||
key.WithKeys("a"),
|
||||
key.WithHelp("a", "add item"),
|
||||
),
|
||||
toggleSpinner: key.NewBinding(
|
||||
key.WithKeys("s"),
|
||||
key.WithHelp("s", "toggle spinner"),
|
||||
),
|
||||
toggleTitleBar: key.NewBinding(
|
||||
key.WithKeys("T"),
|
||||
key.WithHelp("T", "toggle title"),
|
||||
),
|
||||
toggleStatusBar: key.NewBinding(
|
||||
key.WithKeys("S"),
|
||||
key.WithHelp("S", "toggle status"),
|
||||
),
|
||||
togglePagination: key.NewBinding(
|
||||
key.WithKeys("P"),
|
||||
key.WithHelp("P", "toggle pagination"),
|
||||
),
|
||||
toggleHelpMenu: key.NewBinding(
|
||||
key.WithKeys("H"),
|
||||
key.WithHelp("H", "toggle help"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type model struct {
|
||||
list list.Model
|
||||
itemGenerator *randomItemGenerator
|
||||
keys *listKeyMap
|
||||
delegateKeys *delegateKeyMap
|
||||
}
|
||||
|
||||
func newModel() model {
|
||||
var (
|
||||
itemGenerator randomItemGenerator
|
||||
delegateKeys = newDelegateKeyMap()
|
||||
listKeys = newListKeyMap()
|
||||
)
|
||||
|
||||
// Make initial list of items
|
||||
const numItems = 24
|
||||
items := make([]list.Item, numItems)
|
||||
for i := 0; i < numItems; i++ {
|
||||
items[i] = itemGenerator.next()
|
||||
}
|
||||
|
||||
// Setup list
|
||||
delegate := newItemDelegate(delegateKeys)
|
||||
groceryList := list.NewModel(items, delegate, 0, 0)
|
||||
groceryList.Title = "Groceries"
|
||||
groceryList.Styles.Title = titleStyle
|
||||
groceryList.AdditionalFullHelpKeys = func() []key.Binding {
|
||||
return []key.Binding{
|
||||
listKeys.toggleSpinner,
|
||||
listKeys.insertItem,
|
||||
listKeys.toggleTitleBar,
|
||||
listKeys.toggleStatusBar,
|
||||
listKeys.togglePagination,
|
||||
listKeys.toggleHelpMenu,
|
||||
}
|
||||
}
|
||||
|
||||
return model{
|
||||
list: groceryList,
|
||||
keys: listKeys,
|
||||
delegateKeys: delegateKeys,
|
||||
itemGenerator: &itemGenerator,
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return tea.EnterAltScreen
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
topGap, rightGap, bottomGap, leftGap := appStyle.GetPadding()
|
||||
m.list.SetSize(msg.Width-leftGap-rightGap, msg.Height-topGap-bottomGap)
|
||||
|
||||
case tea.KeyMsg:
|
||||
// Don't match any of the keys below if we're actively filtering.
|
||||
if m.list.FilterState() == list.Filtering {
|
||||
break
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.toggleSpinner):
|
||||
cmd := m.list.ToggleSpinner()
|
||||
return m, cmd
|
||||
|
||||
case key.Matches(msg, m.keys.toggleTitleBar):
|
||||
v := !m.list.ShowTitle()
|
||||
m.list.SetShowTitle(v)
|
||||
m.list.SetShowFilter(v)
|
||||
m.list.SetFilteringEnabled(v)
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.toggleStatusBar):
|
||||
m.list.SetShowStatusBar(!m.list.ShowStatusBar())
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.togglePagination):
|
||||
m.list.SetShowPagination(!m.list.ShowPagination())
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.toggleHelpMenu):
|
||||
m.list.SetShowHelp(!m.list.ShowHelp())
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.insertItem):
|
||||
m.delegateKeys.remove.SetEnabled(true)
|
||||
newItem := m.itemGenerator.next()
|
||||
insCmd := m.list.InsertItem(0, newItem)
|
||||
statusCmd := m.list.NewStatusMessage(statusMessageStyle("Added " + newItem.Title()))
|
||||
return m, tea.Batch(insCmd, statusCmd)
|
||||
}
|
||||
}
|
||||
|
||||
// This will also call our delegate's update function.
|
||||
newListModel, cmd := m.list.Update(msg)
|
||||
m.list = newListModel
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
return appStyle.Render(m.list.View())
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
|
||||
if err := tea.NewProgram(newModel()).Start(); err != nil {
|
||||
fmt.Println("Error running program:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
164
examples/list-fancy/randomitems.go
Normal file
164
examples/list-fancy/randomitems.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type randomItemGenerator struct {
|
||||
titles []string
|
||||
descs []string
|
||||
titleIndex int
|
||||
descIndex int
|
||||
mtx *sync.Mutex
|
||||
shuffle *sync.Once
|
||||
}
|
||||
|
||||
func (r *randomItemGenerator) reset() {
|
||||
r.mtx = &sync.Mutex{}
|
||||
r.shuffle = &sync.Once{}
|
||||
|
||||
r.titles = []string{
|
||||
"Artichoke",
|
||||
"Baking Flour",
|
||||
"Bananas",
|
||||
"Barley",
|
||||
"Bean Sprouts",
|
||||
"Bitter Melon",
|
||||
"Black Cod",
|
||||
"Blood Orange",
|
||||
"Brown Sugar",
|
||||
"Cashew Apple",
|
||||
"Cashews",
|
||||
"Cat Food",
|
||||
"Coconut Milk",
|
||||
"Cucumber",
|
||||
"Curry Paste",
|
||||
"Currywurst",
|
||||
"Dill",
|
||||
"Dragonfruit",
|
||||
"Dried Shrimp",
|
||||
"Eggs",
|
||||
"Fish Cake",
|
||||
"Furikake",
|
||||
"Garlic",
|
||||
"Gherkin",
|
||||
"Ginger",
|
||||
"Granulated Sugar",
|
||||
"Grapefruit",
|
||||
"Green Onion",
|
||||
"Hazelnuts",
|
||||
"Heavy whipping cream",
|
||||
"Honey Dew",
|
||||
"Horseradish",
|
||||
"Jicama",
|
||||
"Kohlrabi",
|
||||
"Leeks",
|
||||
"Lentils",
|
||||
"Licorice Root",
|
||||
"Meyer Lemons",
|
||||
"Milk",
|
||||
"Molasses",
|
||||
"Muesli",
|
||||
"Nectarine",
|
||||
"Niagamo Root",
|
||||
"Nopal",
|
||||
"Nutella",
|
||||
"Oat Milk",
|
||||
"Oatmeal",
|
||||
"Olives",
|
||||
"Papaya",
|
||||
"Party Gherkin",
|
||||
"Peppers",
|
||||
"Persian Lemons",
|
||||
"Pickle",
|
||||
"Pineapple",
|
||||
"Plantains",
|
||||
"Pocky",
|
||||
"Powdered Sugar",
|
||||
"Quince",
|
||||
"Radish",
|
||||
"Ramps",
|
||||
"Star Anise",
|
||||
"Sweet Potato",
|
||||
"Tamarind",
|
||||
"Unsalted Butter",
|
||||
"Watermelon",
|
||||
"Weißwurst",
|
||||
"Yams",
|
||||
"Yeast",
|
||||
"Yuzu",
|
||||
"Snow Peas",
|
||||
}
|
||||
|
||||
r.descs = []string{
|
||||
"A little weird",
|
||||
"Bold flavor",
|
||||
"Can’t get enough",
|
||||
"Delectable",
|
||||
"Expensive",
|
||||
"Expired",
|
||||
"Exquisite",
|
||||
"Fresh",
|
||||
"Gimme",
|
||||
"In season",
|
||||
"Kind of spicy",
|
||||
"Looks fresh",
|
||||
"Looks good to me",
|
||||
"Maybe not",
|
||||
"My favorite",
|
||||
"Oh my",
|
||||
"On sale",
|
||||
"Organic",
|
||||
"Questionable",
|
||||
"Really fresh",
|
||||
"Refreshing",
|
||||
"Salty",
|
||||
"Scrumptious",
|
||||
"Delectable",
|
||||
"Slightly sweet",
|
||||
"Smells great",
|
||||
"Tasty",
|
||||
"Too ripe",
|
||||
"At last",
|
||||
"What?",
|
||||
"Wow",
|
||||
"Yum",
|
||||
"Maybe",
|
||||
"Sure, why not?",
|
||||
}
|
||||
|
||||
r.shuffle.Do(func() {
|
||||
shuf := func(x []string) {
|
||||
rand.Shuffle(len(x), func(i, j int) { x[i], x[j] = x[j], x[i] })
|
||||
}
|
||||
shuf(r.titles)
|
||||
shuf(r.descs)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *randomItemGenerator) next() item {
|
||||
if r.mtx == nil {
|
||||
r.reset()
|
||||
}
|
||||
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
|
||||
i := item{
|
||||
title: r.titles[r.titleIndex],
|
||||
description: r.descs[r.descIndex],
|
||||
}
|
||||
|
||||
r.titleIndex++
|
||||
if r.titleIndex >= len(r.titles) {
|
||||
r.titleIndex = 0
|
||||
}
|
||||
|
||||
r.descIndex++
|
||||
if r.descIndex >= len(r.descs) {
|
||||
r.descIndex = 0
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
137
examples/list-simple/main.go
Normal file
137
examples/list-simple/main.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
const listHeight = 14
|
||||
|
||||
var (
|
||||
titleStyle = lipgloss.NewStyle().MarginLeft(2)
|
||||
itemStyle = lipgloss.NewStyle().PaddingLeft(4)
|
||||
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
|
||||
paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
|
||||
helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
|
||||
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
||||
)
|
||||
|
||||
type item string
|
||||
|
||||
func (i item) FilterValue() string { return string(i) }
|
||||
|
||||
type itemDelegate struct{}
|
||||
|
||||
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("%d. %s", index+1, i)
|
||||
|
||||
fn := itemStyle.Render
|
||||
if index == m.Index() {
|
||||
fn = func(s string) string {
|
||||
return selectedItemStyle.Render("> " + s)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, fn(str))
|
||||
}
|
||||
|
||||
type model struct {
|
||||
list list.Model
|
||||
items []item
|
||||
choice string
|
||||
quitting bool
|
||||
}
|
||||
|
||||
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":
|
||||
i, ok := m.list.SelectedItem().(item)
|
||||
if ok {
|
||||
m.choice = string(i)
|
||||
}
|
||||
return m, tea.Quit
|
||||
|
||||
default:
|
||||
if !m.list.SettingFilter() && (keypress == "q" || keypress == "esc") {
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
default:
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
if m.choice != "" {
|
||||
return quitTextStyle.Render(fmt.Sprintf("%s? Sounds good to me.", m.choice))
|
||||
}
|
||||
if m.quitting {
|
||||
return quitTextStyle.Render("Not hungry? That’s cool.")
|
||||
}
|
||||
return "\n" + m.list.View()
|
||||
}
|
||||
|
||||
func main() {
|
||||
items := []list.Item{
|
||||
item("Ramen"),
|
||||
item("Tomato Soup"),
|
||||
item("Hamburgers"),
|
||||
item("Cheeseburgers"),
|
||||
item("Currywurst"),
|
||||
item("Okonomiyaki"),
|
||||
item("Pasta"),
|
||||
item("Fillet Mignon"),
|
||||
item("Caviar"),
|
||||
item("Just Wine"),
|
||||
}
|
||||
|
||||
const defaultWidth = 20
|
||||
|
||||
l := list.NewModel(items, itemDelegate{}, defaultWidth, listHeight)
|
||||
l.Title = "What do you want for dinner?"
|
||||
l.SetShowStatusBar(false)
|
||||
l.SetFilteringEnabled(false)
|
||||
l.Styles.Title = titleStyle
|
||||
l.Styles.PaginationStyle = paginationStyle
|
||||
l.Styles.HelpStyle = helpStyle
|
||||
|
||||
m := model{list: l}
|
||||
|
||||
if err := tea.NewProgram(m).Start(); err != nil {
|
||||
fmt.Println("Error running program:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user