1package repo
 2
 3import (
 4	"fmt"
 5	"io"
 6	"strings"
 7
 8	"github.com/charmbracelet/bubbles/list"
 9	tea "github.com/charmbracelet/bubbletea"
10	"github.com/charmbracelet/soft-serve/git"
11	"github.com/charmbracelet/soft-serve/ui/styles"
12	"github.com/muesli/reflow/truncate"
13)
14
15// LogItem is a item in the log list that displays a git commit.
16type LogItem struct {
17	*git.Commit
18}
19
20// ID implements selector.IdentifiableItem.
21func (i LogItem) ID() string {
22	return i.Commit.ID.String()
23}
24
25// Title returns the item title. Implements list.DefaultItem.
26func (i LogItem) Title() string {
27	if i.Commit != nil {
28		return strings.Split(i.Commit.Message, "\n")[0]
29	}
30	return ""
31}
32
33// Description returns the item description. Implements list.DefaultItem.
34func (i LogItem) Description() string { return "" }
35
36// FilterValue implements list.Item.
37func (i LogItem) FilterValue() string { return i.Title() }
38
39// LogItemDelegate is the delegate for LogItem.
40type LogItemDelegate struct {
41	style *styles.Styles
42}
43
44// Height returns the item height. Implements list.ItemDelegate.
45func (d LogItemDelegate) Height() int { return 1 }
46
47// Spacing returns the item spacing. Implements list.ItemDelegate.
48func (d LogItemDelegate) Spacing() int { return 0 }
49
50// Update updates the item. Implements list.ItemDelegate.
51func (d LogItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
52
53// Render renders the item. Implements list.ItemDelegate.
54func (d LogItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
55	i, ok := listItem.(LogItem)
56	if !ok {
57		return
58	}
59	if i.Commit == nil {
60		return
61	}
62
63	hash := i.Commit.ID.String()
64	leftMargin := d.style.LogItemSelector.GetMarginLeft() +
65		d.style.LogItemSelector.GetWidth() +
66		d.style.LogItemHash.GetMarginLeft() +
67		d.style.LogItemHash.GetWidth() +
68		d.style.LogItemInactive.GetMarginLeft()
69	title := truncateString(i.Title(), m.Width()-leftMargin, "…")
70	if index == m.Index() {
71		fmt.Fprint(w, d.style.LogItemSelector.Render(">")+
72			d.style.LogItemHash.Bold(true).Render(hash[:7])+
73			d.style.LogItemActive.Render(title))
74	} else {
75		fmt.Fprint(w, d.style.LogItemSelector.Render(" ")+
76			d.style.LogItemHash.Render(hash[:7])+
77			d.style.LogItemInactive.Render(title))
78	}
79}
80
81func truncateString(s string, max int, tail string) string {
82	if max < 0 {
83		max = 0
84	}
85	return truncate.StringWithTail(s, uint(max), tail)
86}