1package repo
  2
  3import (
  4	"fmt"
  5	"io"
  6
  7	"github.com/charmbracelet/bubbles/key"
  8	"github.com/charmbracelet/bubbles/list"
  9	tea "github.com/charmbracelet/bubbletea"
 10	"github.com/charmbracelet/lipgloss"
 11	"github.com/charmbracelet/soft-serve/git"
 12	"github.com/charmbracelet/soft-serve/ui/common"
 13)
 14
 15// RefItem is a git reference item.
 16type RefItem struct {
 17	*git.Reference
 18}
 19
 20// ID implements selector.IdentifiableItem.
 21func (i RefItem) ID() string {
 22	return i.Reference.Name().String()
 23}
 24
 25// Title implements list.DefaultItem.
 26func (i RefItem) Title() string {
 27	return i.Reference.Name().Short()
 28}
 29
 30// Description implements list.DefaultItem.
 31func (i RefItem) Description() string {
 32	return ""
 33}
 34
 35// Short returns the short name of the reference.
 36func (i RefItem) Short() string {
 37	return i.Reference.Name().Short()
 38}
 39
 40// FilterValue implements list.Item.
 41func (i RefItem) FilterValue() string { return i.Short() }
 42
 43// RefItems is a list of git references.
 44type RefItems []RefItem
 45
 46// Len implements sort.Interface.
 47func (cl RefItems) Len() int { return len(cl) }
 48
 49// Swap implements sort.Interface.
 50func (cl RefItems) Swap(i, j int) { cl[i], cl[j] = cl[j], cl[i] }
 51
 52// Less implements sort.Interface.
 53func (cl RefItems) Less(i, j int) bool {
 54	return cl[i].Short() < cl[j].Short()
 55}
 56
 57// RefItemDelegate is the delegate for the ref item.
 58type RefItemDelegate struct {
 59	common *common.Common
 60}
 61
 62// Height implements list.ItemDelegate.
 63func (d RefItemDelegate) Height() int { return 1 }
 64
 65// Spacing implements list.ItemDelegate.
 66func (d RefItemDelegate) Spacing() int { return 0 }
 67
 68// Update implements list.ItemDelegate.
 69func (d RefItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
 70	idx := m.Index()
 71	item, ok := m.SelectedItem().(RefItem)
 72	if !ok {
 73		return nil
 74	}
 75	switch msg := msg.(type) {
 76	case tea.KeyMsg:
 77		switch {
 78		case key.Matches(msg, d.common.KeyMap.Copy):
 79			d.common.Copy.Copy(item.Title())
 80			return m.SetItem(idx, item)
 81		}
 82	}
 83	return nil
 84}
 85
 86// Render implements list.ItemDelegate.
 87func (d RefItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
 88	s := d.common.Styles.Ref
 89	i, ok := listItem.(RefItem)
 90	if !ok {
 91		return
 92	}
 93
 94	var st lipgloss.Style
 95	var selector string
 96
 97	isTag := i.Reference.IsTag()
 98	isActive := index == m.Index()
 99
100	if isTag && isActive {
101		st = s.Active.ItemTag
102	} else if isTag {
103		st = s.Normal.ItemTag
104	} else if isActive {
105		st = s.Active.Item
106	} else {
107		st = s.Normal.Item
108	}
109
110	if isActive {
111		selector = s.ItemSelector.String()
112	} else {
113		selector = "  "
114	}
115
116	ref := i.Short()
117	ref = s.ItemBranch.Render(ref)
118	refMaxWidth := m.Width() -
119		s.ItemSelector.GetMarginLeft() -
120		s.ItemSelector.GetWidth() -
121		s.Normal.Item.GetMarginLeft()
122	ref = common.TruncateString(ref, refMaxWidth)
123	ref = st.Render(ref)
124	fmt.Fprint(w, selector, ref)
125}