grouped.go

  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}