logitem.go

  1package repo
  2
  3import (
  4	"fmt"
  5	"io"
  6	"strings"
  7	"time"
  8
  9	"github.com/charmbracelet/bubbles/list"
 10	tea "github.com/charmbracelet/bubbletea"
 11	"github.com/charmbracelet/lipgloss"
 12	"github.com/charmbracelet/soft-serve/git"
 13	"github.com/charmbracelet/soft-serve/ui/styles"
 14	"github.com/muesli/reflow/truncate"
 15)
 16
 17// LogItem is a item in the log list that displays a git commit.
 18type LogItem struct {
 19	*git.Commit
 20}
 21
 22// ID implements selector.IdentifiableItem.
 23func (i LogItem) ID() string {
 24	return i.Commit.ID.String()
 25}
 26
 27// Title returns the item title. Implements list.DefaultItem.
 28func (i LogItem) Title() string {
 29	if i.Commit != nil {
 30		return strings.Split(i.Commit.Message, "\n")[0]
 31	}
 32	return ""
 33}
 34
 35// Description returns the item description. Implements list.DefaultItem.
 36func (i LogItem) Description() string { return "" }
 37
 38// FilterValue implements list.Item.
 39func (i LogItem) FilterValue() string { return i.Title() }
 40
 41// LogItemDelegate is the delegate for LogItem.
 42type LogItemDelegate struct {
 43	style *styles.Styles
 44}
 45
 46// Height returns the item height. Implements list.ItemDelegate.
 47func (d LogItemDelegate) Height() int { return 2 }
 48
 49// Spacing returns the item spacing. Implements list.ItemDelegate.
 50func (d LogItemDelegate) Spacing() int { return 1 }
 51
 52// Update updates the item. Implements list.ItemDelegate.
 53func (d LogItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
 54
 55// Render renders the item. Implements list.ItemDelegate.
 56func (d LogItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
 57	i, ok := listItem.(LogItem)
 58	if !ok {
 59		return
 60	}
 61	if i.Commit == nil {
 62		return
 63	}
 64
 65	width := lipgloss.Width
 66	titleStyle := d.style.LogItemTitle.Copy()
 67	style := d.style.LogItemInactive
 68	if index == m.Index() {
 69		titleStyle.Bold(true)
 70		style = d.style.LogItemActive
 71	}
 72	hash := " " + i.Commit.ID.String()[:7]
 73	title := titleStyle.Render(
 74		truncateString(i.Title(), m.Width()-style.GetHorizontalFrameSize()-width(hash)-2, "…"),
 75	)
 76	hash = d.style.LogItemHash.Copy().
 77		Align(lipgloss.Right).
 78		Width(m.Width() -
 79			style.GetHorizontalFrameSize() -
 80			width(title) -
 81			// FIXME where this "1" is coming from?
 82			1).
 83		Render(hash)
 84	author := i.Author.Name
 85	commiter := i.Committer.Name
 86	who := ""
 87	if author != "" && commiter != "" {
 88		who = fmt.Sprintf("%s committed", commiter)
 89		if author != commiter {
 90			who = fmt.Sprintf("%s authored and %s", author, who)
 91		}
 92		who += " "
 93	}
 94	date := fmt.Sprintf("on %s", i.Committer.When.Format("Feb 02"))
 95	if i.Committer.When.Year() != time.Now().Year() {
 96		date += fmt.Sprintf(" %d", i.Committer.When.Year())
 97	}
 98	who += date
 99	who = truncateString(who, m.Width()-style.GetHorizontalFrameSize(), "…")
100	fmt.Fprint(w,
101		style.Render(
102			lipgloss.JoinVertical(lipgloss.Top,
103				lipgloss.JoinHorizontal(lipgloss.Left,
104					title,
105					hash,
106				),
107				who,
108			),
109		),
110	)
111
112	// leftMargin := d.style.LogItemSelector.GetMarginLeft() +
113	// 	d.style.LogItemSelector.GetWidth() +
114	// 	d.style.LogItemHash.GetMarginLeft() +
115	// 	d.style.LogItemHash.GetWidth() +
116	// 	d.style.LogItemInactive.GetMarginLeft()
117	// title := truncateString(i.Title(), m.Width()-leftMargin, "…")
118	// if index == m.Index() {
119	// 	fmt.Fprint(w, d.style.LogItemSelector.Render(">")+
120	// 		d.style.LogItemHash.Bold(true).Render(hash[:7])+
121	// 		d.style.LogItemActive.Render(title))
122	// } else {
123	// 	fmt.Fprint(w, d.style.LogItemSelector.Render(" ")+
124	// 		d.style.LogItemHash.Render(hash[:7])+
125	// 		d.style.LogItemInactive.Render(title))
126	// }
127	// fmt.Fprintln(w)
128}
129
130func truncateString(s string, max int, tail string) string {
131	if max < 0 {
132		max = 0
133	}
134	return truncate.StringWithTail(s, uint(max), tail)
135}