5302c4912cb64bc43f2d68a1f43cef62c8d3f665
- Author
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Committer
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/ui/common/utils.go b/ui/common/utils.go
2index 119f1b787d953586d9723a4a38a8f39859015f0f..97d498cb63ca1b77e7565d60dd870b4aff9d7575 100644
3--- a/ui/common/utils.go
4+++ b/ui/common/utils.go
5@@ -16,8 +16,8 @@ func TruncateString(s string, max int) string {
6 return truncate.StringWithTail(s, uint(max), "…")
7 }
8
9-// RepoURL returns the URL of the repository.
10-func RepoURL(publicURL, name string) string {
11+// CloneCmd returns the URL of the repository.
12+func CloneCmd(publicURL, name string) string {
13 name = utils.SanitizeRepo(name) + ".git"
14 url, err := url.Parse(publicURL)
15 if err == nil {
16diff --git a/ui/components/statusbar/statusbar.go b/ui/components/statusbar/statusbar.go
17index 7b960569faf23f4668c2bfc3ddc3792cf73c9ad7..c208c84897731234ba3b5611b7751de2ad930e3c 100644
18--- a/ui/components/statusbar/statusbar.go
19+++ b/ui/components/statusbar/statusbar.go
20@@ -9,16 +9,19 @@ import (
21
22 // StatusBarMsg is a message sent to the status bar.
23 type StatusBarMsg struct {
24- Key string
25- Value string
26- Info string
27- Branch string
28+ Key string
29+ Value string
30+ Info string
31+ Extra string
32 }
33
34 // StatusBar is a status bar model.
35 type StatusBar struct {
36 common common.Common
37- msg StatusBarMsg
38+ key string
39+ value string
40+ info string
41+ extra string
42 }
43
44 // Model is an interface that supports setting the status bar information.
45@@ -50,7 +53,18 @@ func (s *StatusBar) Init() tea.Cmd {
46 func (s *StatusBar) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
47 switch msg := msg.(type) {
48 case StatusBarMsg:
49- s.msg = msg
50+ if msg.Key != "" {
51+ s.key = msg.Key
52+ }
53+ if msg.Value != "" {
54+ s.value = msg.Value
55+ }
56+ if msg.Info != "" {
57+ s.info = msg.Info
58+ }
59+ if msg.Extra != "" {
60+ s.extra = msg.Extra
61+ }
62 }
63 return s, nil
64 }
65@@ -63,14 +77,14 @@ func (s *StatusBar) View() string {
66 "repo-help",
67 st.StatusBarHelp.Render("? Help"),
68 )
69- key := st.StatusBarKey.Render(s.msg.Key)
70+ key := st.StatusBarKey.Render(s.key)
71 info := ""
72- if s.msg.Info != "" {
73- info = st.StatusBarInfo.Render(s.msg.Info)
74+ if s.info != "" {
75+ info = st.StatusBarInfo.Render(s.info)
76 }
77- branch := st.StatusBarBranch.Render(s.msg.Branch)
78+ branch := st.StatusBarBranch.Render(s.extra)
79 maxWidth := s.common.Width - w(key) - w(info) - w(branch) - w(help)
80- v := truncate.StringWithTail(s.msg.Value, uint(maxWidth-st.StatusBarValue.GetHorizontalFrameSize()), "…")
81+ v := truncate.StringWithTail(s.value, uint(maxWidth-st.StatusBarValue.GetHorizontalFrameSize()), "…")
82 value := st.StatusBarValue.
83 Width(maxWidth).
84 Render(v)
85diff --git a/ui/pages/repo/empty.go b/ui/pages/repo/empty.go
86index fe3921d9c66fe1d6619a412a33558b418fa41694..1e62e8f869988c8f2c525b03b2d67e24a384c42f 100644
87--- a/ui/pages/repo/empty.go
88+++ b/ui/pages/repo/empty.go
89@@ -36,5 +36,5 @@ git push -u origin main
90 git remote add origin %[1]s
91 git push -u origin main
92 `+"```"+`
93-`, common.RepoURL(cfg.SSH.PublicURL, repo))
94+`, common.CloneCmd(cfg.SSH.PublicURL, repo))
95 }
96diff --git a/ui/pages/repo/files.go b/ui/pages/repo/files.go
97index edae23f1ff318e1ec2505d16edc809e035de38b7..a281c1e879c932daacae7c8491d9e3966687b4bb 100644
98--- a/ui/pages/repo/files.go
99+++ b/ui/pages/repo/files.go
100@@ -243,7 +243,7 @@ func (f *Files) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
101 case key.Matches(msg, f.common.KeyMap.BackItem):
102 cmds = append(cmds, backCmd)
103 case key.Matches(msg, f.common.KeyMap.Copy):
104- f.common.Copy.Copy(f.currentContent.content)
105+ cmds = append(cmds, copyCmd(f.currentContent.content, "File contents copied to clipboard"))
106 case key.Matches(msg, lineNo):
107 f.lineNumber = !f.lineNumber
108 f.code.SetShowLineNumber(f.lineNumber)
109diff --git a/ui/pages/repo/filesitem.go b/ui/pages/repo/filesitem.go
110index 1d64cb8d13e1ed7ba3262159dfc6686d6bc00ba0..eae17d920f4384bc8de0f65dc5ed9a0e9f575f43 100644
111--- a/ui/pages/repo/filesitem.go
112+++ b/ui/pages/repo/filesitem.go
113@@ -78,7 +78,6 @@ func (d FileItemDelegate) Spacing() int { return 0 }
114
115 // Update implements list.ItemDelegate.
116 func (d FileItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
117- idx := m.Index()
118 item, ok := m.SelectedItem().(FileItem)
119 if !ok {
120 return nil
121@@ -87,8 +86,7 @@ func (d FileItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
122 case tea.KeyMsg:
123 switch {
124 case key.Matches(msg, d.common.KeyMap.Copy):
125- d.common.Copy.Copy(item.Title())
126- return m.SetItem(idx, item)
127+ return copyCmd(item.entry.Name(), fmt.Sprintf("File name %q copied to clipboard", item.entry.Name()))
128 }
129 }
130 return nil
131diff --git a/ui/pages/repo/logitem.go b/ui/pages/repo/logitem.go
132index b30c21d67f4b371c121b0007c5b93073811e078d..06e27ea858d5bccb43fde70f554bdecc3f8b86cd 100644
133--- a/ui/pages/repo/logitem.go
134+++ b/ui/pages/repo/logitem.go
135@@ -18,7 +18,6 @@ import (
136 // LogItem is a item in the log list that displays a git commit.
137 type LogItem struct {
138 *git.Commit
139- copied time.Time
140 }
141
142 // ID implements selector.IdentifiableItem.
143@@ -57,7 +56,6 @@ func (d LogItemDelegate) Spacing() int { return 1 }
144
145 // Update updates the item. Implements list.ItemDelegate.
146 func (d LogItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
147- idx := m.Index()
148 item, ok := m.SelectedItem().(LogItem)
149 if !ok {
150 return nil
151@@ -66,9 +64,7 @@ func (d LogItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
152 case tea.KeyMsg:
153 switch {
154 case key.Matches(msg, d.common.KeyMap.Copy):
155- item.copied = time.Now()
156- d.common.Copy.Copy(item.Hash())
157- return m.SetItem(idx, item)
158+ return copyCmd(item.Hash(), fmt.Sprintf("Commit hash %q copied to clipboard", item.Hash()))
159 }
160 }
161 return nil
162@@ -92,9 +88,6 @@ func (d LogItemDelegate) Render(w io.Writer, m list.Model, index int, listItem l
163 horizontalFrameSize := styles.Base.GetHorizontalFrameSize()
164
165 hash := i.Commit.ID.String()[:7]
166- if !i.copied.IsZero() && i.copied.Add(time.Second).After(time.Now()) {
167- hash = "copied"
168- }
169 title := styles.Title.Render(
170 common.TruncateString(i.Title(),
171 m.Width()-
172diff --git a/ui/pages/repo/refsitem.go b/ui/pages/repo/refsitem.go
173index ec378696f450278914c13eadf51f25b1b458a95e..f7d8a15221d2df03d43df9daa2b401f5cf32dc04 100644
174--- a/ui/pages/repo/refsitem.go
175+++ b/ui/pages/repo/refsitem.go
176@@ -67,7 +67,6 @@ func (d RefItemDelegate) Spacing() int { return 0 }
177
178 // Update implements list.ItemDelegate.
179 func (d RefItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
180- idx := m.Index()
181 item, ok := m.SelectedItem().(RefItem)
182 if !ok {
183 return nil
184@@ -76,8 +75,7 @@ func (d RefItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
185 case tea.KeyMsg:
186 switch {
187 case key.Matches(msg, d.common.KeyMap.Copy):
188- d.common.Copy.Copy(item.Title())
189- return m.SetItem(idx, item)
190+ return copyCmd(item.ID(), fmt.Sprintf("Reference %q copied to clipboard", item.ID()))
191 }
192 }
193 return nil
194diff --git a/ui/pages/repo/repo.go b/ui/pages/repo/repo.go
195index 6be90105feea3b7fd650919882fe99dc618598a3..38119d9d520f74364ec2c5cbafce5b11e61b0263 100644
196--- a/ui/pages/repo/repo.go
197+++ b/ui/pages/repo/repo.go
198@@ -2,7 +2,6 @@ package repo
199
200 import (
201 "fmt"
202- "time"
203
204 "github.com/charmbracelet/bubbles/help"
205 "github.com/charmbracelet/bubbles/key"
206@@ -56,9 +55,6 @@ type EmptyRepoMsg struct{}
207 // CopyURLMsg is a message to copy the URL of the current repository.
208 type CopyURLMsg struct{}
209
210-// ResetURLMsg is a message to reset the URL string.
211-type ResetURLMsg struct{}
212-
213 // UpdateStatusBarMsg updates the status bar.
214 type UpdateStatusBarMsg struct{}
215
216@@ -68,6 +64,12 @@ type RepoMsg backend.Repository
217 // BackMsg is a message to go back to the previous view.
218 type BackMsg struct{}
219
220+// CopyMsg is a message to indicate copied text.
221+type CopyMsg struct {
222+ Text string
223+ Message string
224+}
225+
226 // Repo is a view for a git repository.
227 type Repo struct {
228 common common.Common
229@@ -77,7 +79,6 @@ type Repo struct {
230 statusbar *statusbar.StatusBar
231 panes []common.Component
232 ref *git.Reference
233- copyURL time.Time
234 state state
235 spinner spinner.Model
236 panesReady [lastTab]bool
237@@ -215,8 +216,9 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
238 if r.selectedRepo != nil {
239 cmds = append(cmds, r.updateStatusBarCmd)
240 urlID := fmt.Sprintf("%s-url", r.selectedRepo.Name())
241+ cmd := common.CloneCmd(r.common.Config().SSH.PublicURL, r.selectedRepo.Name())
242 if msg, ok := msg.(tea.MouseMsg); ok && r.common.Zone.Get(urlID).InBounds(msg) {
243- cmds = append(cmds, r.copyURLCmd())
244+ cmds = append(cmds, copyCmd(cmd, "Command copied to clipboard"))
245 }
246 }
247 switch msg := msg.(type) {
248@@ -234,14 +236,16 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
249 }
250 }
251 }
252- case CopyURLMsg:
253+ case CopyMsg:
254+ txt := msg.Text
255 if cfg := r.common.Config(); cfg != nil {
256- r.common.Copy.Copy(
257- common.RepoURL(cfg.SSH.PublicURL, r.selectedRepo.Name()),
258- )
259+ r.common.Copy.Copy(txt)
260 }
261- case ResetURLMsg:
262- r.copyURL = time.Time{}
263+ cmds = append(cmds, func() tea.Msg {
264+ return statusbar.StatusBarMsg{
265+ Value: msg.Message,
266+ }
267+ })
268 case ReadmeMsg, FileItemsMsg, LogCountMsg, LogItemsMsg, RefItemsMsg:
269 cmds = append(cmds, r.updateRepo(msg))
270 // We have two spinners, one is used to when loading the repository and the
271@@ -345,10 +349,7 @@ func (r *Repo) headerView() string {
272 Align(lipgloss.Right)
273 var url string
274 if cfg := r.common.Config(); cfg != nil {
275- url = common.RepoURL(cfg.SSH.PublicURL, r.selectedRepo.Name())
276- }
277- if !r.copyURL.IsZero() && r.copyURL.Add(time.Second).After(time.Now()) {
278- url = "copied!"
279+ url = common.CloneCmd(cfg.SSH.PublicURL, r.selectedRepo.Name())
280 }
281 url = common.TruncateString(url, r.common.Width-lipgloss.Width(desc)-1)
282 url = r.common.Zone.Mark(
283@@ -378,10 +379,10 @@ func (r *Repo) updateStatusBarCmd() tea.Msg {
284 branch += " " + r.ref.Name().Short()
285 }
286 return statusbar.StatusBarMsg{
287- Key: r.selectedRepo.Name(),
288- Value: value,
289- Info: info,
290- Branch: branch,
291+ Key: r.selectedRepo.Name(),
292+ Value: value,
293+ Info: info,
294+ Extra: branch,
295 }
296 }
297
298diff --git a/ui/pages/selection/item.go b/ui/pages/selection/item.go
299index 837ce69d37f5c4ea2c67def336e31d40f2d92a96..7d24d5a6647a899316e25994daef510fd0fb6bf8 100644
300--- a/ui/pages/selection/item.go
301+++ b/ui/pages/selection/item.go
302@@ -51,7 +51,6 @@ type Item struct {
303 repo backend.Repository
304 lastUpdate *time.Time
305 cmd string
306- copied time.Time
307 }
308
309 // New creates a new Item.
310@@ -64,7 +63,7 @@ func NewItem(repo backend.Repository, cfg *config.Config) (Item, error) {
311 return Item{
312 repo: repo,
313 lastUpdate: lastUpdate,
314- cmd: common.RepoURL(cfg.SSH.PublicURL, repo.Name()),
315+ cmd: common.CloneCmd(cfg.SSH.PublicURL, repo.Name()),
316 }, nil
317 }
318
319@@ -98,6 +97,16 @@ func (i Item) Command() string {
320 type ItemDelegate struct {
321 common *common.Common
322 activePane *pane
323+ copiedIdx int
324+}
325+
326+// NewItemDelegate creates a new ItemDelegate.
327+func NewItemDelegate(common *common.Common, activePane *pane) *ItemDelegate {
328+ return &ItemDelegate{
329+ common: common,
330+ activePane: activePane,
331+ copiedIdx: -1,
332+ }
333 }
334
335 // Width returns the item width.
336@@ -107,16 +116,16 @@ func (d ItemDelegate) Width() int {
337 }
338
339 // Height returns the item height. Implements list.ItemDelegate.
340-func (d ItemDelegate) Height() int {
341+func (d *ItemDelegate) Height() int {
342 height := d.common.Styles.MenuItem.GetVerticalFrameSize() + d.common.Styles.MenuItem.GetHeight()
343 return height
344 }
345
346 // Spacing returns the spacing between items. Implements list.ItemDelegate.
347-func (d ItemDelegate) Spacing() int { return 1 }
348+func (d *ItemDelegate) Spacing() int { return 1 }
349
350 // Update implements list.ItemDelegate.
351-func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
352+func (d *ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
353 idx := m.Index()
354 item, ok := m.SelectedItem().(Item)
355 if !ok {
356@@ -126,7 +135,7 @@ func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
357 case tea.KeyMsg:
358 switch {
359 case key.Matches(msg, d.common.KeyMap.Copy):
360- item.copied = time.Now()
361+ d.copiedIdx = idx
362 d.common.Copy.Copy(item.Command())
363 return m.SetItem(idx, item)
364 }
365@@ -135,7 +144,7 @@ func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
366 }
367
368 // Render implements list.ItemDelegate.
369-func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
370+func (d *ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
371 i := listItem.(Item)
372 s := strings.Builder{}
373 var matchedRunes []int
374@@ -192,8 +201,9 @@ func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
375 s.WriteRune('\n')
376 cmd := common.TruncateString(i.Command(), m.Width()-styles.Base.GetHorizontalFrameSize())
377 cmd = styles.Command.Render(cmd)
378- if !i.copied.IsZero() && i.copied.Add(time.Second).After(time.Now()) {
379- cmd = styles.Command.Render("Copied!")
380+ if d.copiedIdx == index {
381+ cmd += " " + styles.Desc.Render("(copied to clipboard)")
382+ d.copiedIdx = -1
383 }
384 s.WriteString(cmd)
385 fmt.Fprint(w,
386diff --git a/ui/pages/selection/selection.go b/ui/pages/selection/selection.go
387index 036b742227d5a030f0a6c2b90374f0b31964475e..2c7957c6aacaae4eb380dbc3447cf95de6b21580 100644
388--- a/ui/pages/selection/selection.go
389+++ b/ui/pages/selection/selection.go
390@@ -71,7 +71,7 @@ func New(c common.Common) *Selection {
391 SetString(defaultNoContent)
392 selector := selector.New(c,
393 []selector.IdentifiableItem{},
394- ItemDelegate{&c, &sel.activePane})
395+ NewItemDelegate(&c, &sel.activePane))
396 selector.SetShowTitle(false)
397 selector.SetShowHelp(false)
398 selector.SetShowStatusBar(false)