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/server/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	item, ok := m.SelectedItem().(RefItem)
 71	if !ok {
 72		return nil
 73	}
 74	switch msg := msg.(type) {
 75	case tea.KeyMsg:
 76		switch {
 77		case key.Matches(msg, d.common.KeyMap.Copy):
 78			return copyCmd(item.ID(), fmt.Sprintf("Reference %q copied to clipboard", item.ID()))
 79		}
 80	}
 81	return nil
 82}
 83
 84// Render implements list.ItemDelegate.
 85func (d RefItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
 86	s := d.common.Styles.Ref
 87	i, ok := listItem.(RefItem)
 88	if !ok {
 89		return
 90	}
 91
 92	var st lipgloss.Style
 93	var selector string
 94
 95	isTag := i.Reference.IsTag()
 96	isActive := index == m.Index()
 97
 98	if isTag && isActive {
 99		st = s.Active.ItemTag
100	} else if isTag {
101		st = s.Normal.ItemTag
102	} else if isActive {
103		st = s.Active.Item
104	} else {
105		st = s.Normal.Item
106	}
107
108	if isActive {
109		selector = s.ItemSelector.String()
110	} else {
111		selector = "  "
112	}
113
114	ref := i.Short()
115	ref = s.ItemBranch.Render(ref)
116	refMaxWidth := m.Width() -
117		s.ItemSelector.GetMarginLeft() -
118		s.ItemSelector.GetWidth() -
119		s.Normal.Item.GetMarginLeft()
120	ref = common.TruncateString(ref, refMaxWidth)
121	ref = st.Render(ref)
122	fmt.Fprint(w,
123		d.common.Zone.Mark(
124			i.ID(),
125			fmt.Sprint(selector, ref),
126		),
127	)
128}