1package repo
2
3import (
4 "sort"
5 "strings"
6
7 "github.com/charmbracelet/bubbles/key"
8 tea "github.com/charmbracelet/bubbletea"
9 ggit "github.com/charmbracelet/soft-serve/git"
10 "github.com/charmbracelet/soft-serve/ui/common"
11 "github.com/charmbracelet/soft-serve/ui/components/selector"
12 "github.com/charmbracelet/soft-serve/ui/components/tabs"
13 "github.com/charmbracelet/soft-serve/ui/git"
14)
15
16// RefItemsMsg is a message that contains a list of RefItem.
17type RefItemsMsg struct {
18 prefix string
19 items []selector.IdentifiableItem
20}
21
22// Refs is a component that displays a list of references.
23type Refs struct {
24 common common.Common
25 selector *selector.Selector
26 repo git.GitRepo
27 ref *ggit.Reference
28 activeRef *ggit.Reference
29 refPrefix string
30}
31
32// NewRefs creates a new Refs component.
33func NewRefs(common common.Common, refPrefix string) *Refs {
34 r := &Refs{
35 common: common,
36 refPrefix: refPrefix,
37 }
38 s := selector.New(common, []selector.IdentifiableItem{}, RefItemDelegate{common.Styles})
39 s.SetShowFilter(false)
40 s.SetShowHelp(false)
41 s.SetShowPagination(true)
42 s.SetShowStatusBar(false)
43 s.SetShowTitle(false)
44 s.SetFilteringEnabled(false)
45 s.DisableQuitKeybindings()
46 r.selector = s
47 return r
48}
49
50// SetSize implements common.Component.
51func (r *Refs) SetSize(width, height int) {
52 r.common.SetSize(width, height)
53 r.selector.SetSize(width, height)
54}
55
56// ShortHelp implements help.KeyMap.
57func (r *Refs) ShortHelp() []key.Binding {
58 k := r.selector.KeyMap
59 return []key.Binding{
60 r.common.KeyMap.SelectItem,
61 k.CursorUp,
62 k.CursorDown,
63 }
64}
65
66// FullHelp implements help.KeyMap.
67func (r *Refs) FullHelp() [][]key.Binding {
68 k := r.selector.KeyMap
69 return [][]key.Binding{
70 {r.common.KeyMap.SelectItem},
71 {
72 k.CursorUp,
73 k.CursorDown,
74 },
75 {
76 k.NextPage,
77 k.PrevPage,
78 },
79 {
80 k.GoToStart,
81 k.GoToEnd,
82 },
83 }
84}
85
86// Init implements tea.Model.
87func (r *Refs) Init() tea.Cmd {
88 return r.updateItemsCmd
89}
90
91// Update implements tea.Model.
92func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
93 cmds := make([]tea.Cmd, 0)
94 switch msg := msg.(type) {
95 case RepoMsg:
96 r.selector.Select(0)
97 r.repo = git.GitRepo(msg)
98 cmds = append(cmds, r.Init())
99 case RefMsg:
100 r.ref = msg
101 cmds = append(cmds, r.Init())
102 case RefItemsMsg:
103 cmds = append(cmds, r.selector.SetItems(msg.items))
104 i := r.selector.SelectedItem()
105 if i != nil {
106 r.activeRef = i.(RefItem).Reference
107 }
108 case selector.ActiveMsg:
109 switch sel := msg.IdentifiableItem.(type) {
110 case RefItem:
111 r.activeRef = sel.Reference
112 }
113 cmds = append(cmds, updateStatusBarCmd)
114 case selector.SelectMsg:
115 switch i := msg.IdentifiableItem.(type) {
116 case RefItem:
117 cmds = append(cmds,
118 switchRefCmd(i.Reference),
119 tabs.SelectTabCmd(int(filesTab)),
120 )
121 }
122 case tea.KeyMsg:
123 switch msg.String() {
124 case "l", "right":
125 cmds = append(cmds, r.selector.SelectItem)
126 }
127 }
128 m, cmd := r.selector.Update(msg)
129 r.selector = m.(*selector.Selector)
130 if cmd != nil {
131 cmds = append(cmds, cmd)
132 }
133 return r, tea.Batch(cmds...)
134}
135
136// View implements tea.Model.
137func (r *Refs) View() string {
138 return r.selector.View()
139}
140
141// StausBarValue implements statusbar.StatusBar.
142func (r *Refs) StatusBarValue() string {
143 if r.activeRef == nil {
144 return ""
145 }
146 return r.activeRef.Name().String()
147}
148
149// StatusBarInfo implements statusbar.StatusBar.
150func (r *Refs) StatusBarInfo() string {
151 return ""
152}
153
154func (r *Refs) updateItemsCmd() tea.Msg {
155 its := make(RefItems, 0)
156 refs, err := r.repo.References()
157 if err != nil {
158 return common.ErrorMsg(err)
159 }
160 for _, ref := range refs {
161 if strings.HasPrefix(ref.Name().String(), r.refPrefix) {
162 its = append(its, RefItem{ref})
163 }
164 }
165 sort.Sort(its)
166 items := make([]selector.IdentifiableItem, len(its))
167 for i, it := range its {
168 items[i] = it
169 }
170 return RefItemsMsg{
171 items: items,
172 prefix: r.refPrefix,
173 }
174}
175
176func switchRefCmd(ref *ggit.Reference) tea.Cmd {
177 return func() tea.Msg {
178 return RefMsg(ref)
179 }
180}