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