1package list
2
3import (
4 tea "github.com/charmbracelet/bubbletea/v2"
5 "github.com/charmbracelet/crush/internal/csync"
6 "github.com/charmbracelet/crush/internal/tui/components/core/layout"
7 "github.com/charmbracelet/crush/internal/tui/util"
8)
9
10type Group[T Item] struct {
11 Section ItemSection
12 Items []T
13}
14type GroupedList[T Item] interface {
15 util.Model
16 layout.Sizeable
17 Items() []Item
18 Groups() []Group[T]
19 SetGroups([]Group[T]) tea.Cmd
20 MoveUp(int) tea.Cmd
21 MoveDown(int) tea.Cmd
22 GoToTop() tea.Cmd
23 GoToBottom() tea.Cmd
24 SelectItemAbove() tea.Cmd
25 SelectItemBelow() tea.Cmd
26 SetSelected(string) tea.Cmd
27 SelectedItem() *T
28}
29type groupedList[T Item] struct {
30 *list[Item]
31 groups []Group[T]
32}
33
34func NewGroupedList[T Item](groups []Group[T], opts ...ListOption) GroupedList[T] {
35 list := &list[Item]{
36 confOptions: &confOptions{
37 direction: DirectionForward,
38 keyMap: DefaultKeyMap(),
39 focused: true,
40 },
41 items: csync.NewSlice[Item](),
42 indexMap: csync.NewMap[string, int](),
43 renderedItems: csync.NewMap[string, renderedItem](),
44 }
45 for _, opt := range opts {
46 opt(list.confOptions)
47 }
48
49 return &groupedList[T]{
50 list: list,
51 }
52}
53
54func (g *groupedList[T]) Init() tea.Cmd {
55 g.convertItems()
56 return g.render()
57}
58
59func (l *groupedList[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
60 u, cmd := l.list.Update(msg)
61 l.list = u.(*list[Item])
62 return l, cmd
63}
64
65func (g *groupedList[T]) SelectedItem() *T {
66 item := g.list.SelectedItem()
67 if item == nil {
68 return nil
69 }
70 dRef := *item
71 c, ok := any(dRef).(T)
72 if !ok {
73 return nil
74 }
75 return &c
76}
77
78func (g *groupedList[T]) convertItems() {
79 var items []Item
80 for _, g := range g.groups {
81 items = append(items, g.Section)
82 for _, g := range g.Items {
83 items = append(items, g)
84 }
85 }
86 g.items.SetSlice(items)
87}
88
89func (g *groupedList[T]) SetGroups(groups []Group[T]) tea.Cmd {
90 g.groups = groups
91 g.convertItems()
92 return g.SetItems(g.items.Slice())
93}
94
95func (g *groupedList[T]) Groups() []Group[T] {
96 return g.groups
97}
98
99func (g *groupedList[T]) Items() []Item {
100 return g.list.Items()
101}