list.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package list
  2. import (
  3. "github.com/charmbracelet/bubbles/key"
  4. "github.com/charmbracelet/bubbles/list"
  5. tea "github.com/charmbracelet/bubbletea"
  6. "github.com/charmbracelet/lipgloss"
  7. )
  8. var (
  9. appStyle = lipgloss.NewStyle().Padding(1, 2)
  10. titleStyle = lipgloss.NewStyle().
  11. Foreground(lipgloss.Color("#FFFDF5")).
  12. Background(lipgloss.Color("#25A065")).
  13. Padding(0, 1)
  14. statusMessageStyle = lipgloss.NewStyle().
  15. Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).
  16. Render
  17. )
  18. type Item struct {
  19. title string
  20. description string
  21. }
  22. func NewItem(title string, description string) Item {
  23. return Item{title, description}
  24. }
  25. func (i Item) Title() string { return i.title }
  26. func (i Item) Description() string { return i.description }
  27. func (i Item) FilterValue() string { return i.title }
  28. type listKeyMap struct {
  29. toggleSpinner key.Binding
  30. toggleTitleBar key.Binding
  31. toggleStatusBar key.Binding
  32. togglePagination key.Binding
  33. toggleHelpMenu key.Binding
  34. }
  35. func newListKeyMap() *listKeyMap {
  36. return &listKeyMap{
  37. toggleSpinner: key.NewBinding(
  38. key.WithKeys("s"),
  39. key.WithHelp("s", "toggle spinner"),
  40. ),
  41. toggleTitleBar: key.NewBinding(
  42. key.WithKeys("T"),
  43. key.WithHelp("T", "toggle title"),
  44. ),
  45. toggleStatusBar: key.NewBinding(
  46. key.WithKeys("S"),
  47. key.WithHelp("S", "toggle status"),
  48. ),
  49. togglePagination: key.NewBinding(
  50. key.WithKeys("P"),
  51. key.WithHelp("P", "toggle pagination"),
  52. ),
  53. toggleHelpMenu: key.NewBinding(
  54. key.WithKeys("H"),
  55. key.WithHelp("H", "toggle help"),
  56. ),
  57. }
  58. }
  59. type model struct {
  60. list list.Model
  61. keys *listKeyMap
  62. delegateKeys *delegateKeyMap
  63. }
  64. func NewList(title string, items []list.Item) model {
  65. var (
  66. delegateKeys = newDelegateKeyMap()
  67. listKeys = newListKeyMap()
  68. )
  69. // Setup list
  70. delegate := newItemDelegate(delegateKeys)
  71. groceryList := list.New(items, delegate, 0, 0)
  72. groceryList.Title = title
  73. groceryList.Styles.Title = titleStyle
  74. groceryList.AdditionalFullHelpKeys = func() []key.Binding {
  75. return []key.Binding{
  76. listKeys.toggleSpinner,
  77. listKeys.toggleTitleBar,
  78. listKeys.toggleStatusBar,
  79. listKeys.togglePagination,
  80. listKeys.toggleHelpMenu,
  81. }
  82. }
  83. return model{
  84. list: groceryList,
  85. keys: listKeys,
  86. delegateKeys: delegateKeys,
  87. }
  88. }
  89. func (m model) Init() tea.Cmd {
  90. return tea.EnterAltScreen
  91. }
  92. func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  93. var cmds []tea.Cmd
  94. switch msg := msg.(type) {
  95. case tea.WindowSizeMsg:
  96. h, v := appStyle.GetFrameSize()
  97. m.list.SetSize(msg.Width-h, msg.Height-v)
  98. case tea.KeyMsg:
  99. // Don't match any of the keys below if we're actively filtering.
  100. if m.list.FilterState() == list.Filtering {
  101. break
  102. }
  103. switch {
  104. case key.Matches(msg, m.keys.toggleSpinner):
  105. cmd := m.list.ToggleSpinner()
  106. return m, cmd
  107. case key.Matches(msg, m.keys.toggleTitleBar):
  108. v := !m.list.ShowTitle()
  109. m.list.SetShowTitle(v)
  110. m.list.SetShowFilter(v)
  111. m.list.SetFilteringEnabled(v)
  112. return m, nil
  113. case key.Matches(msg, m.keys.toggleStatusBar):
  114. m.list.SetShowStatusBar(!m.list.ShowStatusBar())
  115. return m, nil
  116. case key.Matches(msg, m.keys.togglePagination):
  117. m.list.SetShowPagination(!m.list.ShowPagination())
  118. return m, nil
  119. case key.Matches(msg, m.keys.toggleHelpMenu):
  120. m.list.SetShowHelp(!m.list.ShowHelp())
  121. return m, nil
  122. }
  123. }
  124. // This will also call our delegate's update function.
  125. newListModel, cmd := m.list.Update(msg)
  126. m.list = newListModel
  127. cmds = append(cmds, cmd)
  128. return m, tea.Batch(cmds...)
  129. }
  130. func (m model) View() string {
  131. return appStyle.Render(m.list.View())
  132. }