filesitem.go

  1package repo
  2
  3import (
  4	"fmt"
  5	"io"
  6	"io/fs"
  7
  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/ui/styles"
 13	"github.com/dustin/go-humanize"
 14)
 15
 16// FileItem is a list item for a file.
 17type FileItem struct {
 18	entry *git.TreeEntry
 19}
 20
 21// ID returns the ID of the file item.
 22func (i FileItem) ID() string {
 23	return i.entry.Name()
 24}
 25
 26// Title returns the title of the file item.
 27func (i FileItem) Title() string {
 28	return i.entry.Name()
 29}
 30
 31// Description returns the description of the file item.
 32func (i FileItem) Description() string {
 33	return ""
 34}
 35
 36// Mode returns the mode of the file item.
 37func (i FileItem) Mode() fs.FileMode {
 38	return i.entry.Mode()
 39}
 40
 41// FilterValue implements list.Item.
 42func (i FileItem) FilterValue() string { return i.Title() }
 43
 44// FileItems is a list of file items.
 45type FileItems []FileItem
 46
 47// Len implements sort.Interface.
 48func (cl FileItems) Len() int { return len(cl) }
 49
 50// Swap implements sort.Interface.
 51func (cl FileItems) Swap(i, j int) { cl[i], cl[j] = cl[j], cl[i] }
 52
 53// Less implements sort.Interface.
 54func (cl FileItems) Less(i, j int) bool {
 55	if cl[i].entry.IsTree() && cl[j].entry.IsTree() {
 56		return cl[i].Title() < cl[j].Title()
 57	} else if cl[i].entry.IsTree() {
 58		return true
 59	} else if cl[j].entry.IsTree() {
 60		return false
 61	} else {
 62		return cl[i].Title() < cl[j].Title()
 63	}
 64}
 65
 66// FileItemDelegate is the delegate for the file item list.
 67type FileItemDelegate struct {
 68	style *styles.Styles
 69}
 70
 71// Height returns the height of the file item list. Implements list.ItemDelegate.
 72func (d FileItemDelegate) Height() int { return 1 }
 73
 74// Spacing returns the spacing of the file item list. Implements list.ItemDelegate.
 75func (d FileItemDelegate) Spacing() int { return 0 }
 76
 77// Update implements list.ItemDelegate.
 78func (d FileItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
 79
 80// Render implements list.ItemDelegate.
 81func (d FileItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
 82	s := d.style
 83	i, ok := listItem.(FileItem)
 84	if !ok {
 85		return
 86	}
 87
 88	name := i.Title()
 89	size := humanize.Bytes(uint64(i.entry.Size()))
 90	if i.entry.IsTree() {
 91		size = ""
 92		name = s.TreeFileDir.Render(name)
 93	}
 94	var cs lipgloss.Style
 95	mode := i.Mode()
 96	if index == m.Index() {
 97		cs = s.TreeItemActive
 98		fmt.Fprint(w, s.TreeItemSelector.Render(">"))
 99	} else {
100		cs = s.TreeItemInactive
101		fmt.Fprint(w, s.TreeItemSelector.Render(" "))
102	}
103	leftMargin := s.TreeItemSelector.GetMarginLeft() +
104		s.TreeItemSelector.GetWidth() +
105		s.TreeFileMode.GetMarginLeft() +
106		s.TreeFileMode.GetWidth() +
107		cs.GetMarginLeft()
108	rightMargin := s.TreeFileSize.GetMarginLeft() + lipgloss.Width(size)
109	name = truncateString(name, m.Width()-leftMargin-rightMargin, "…")
110	sizeStyle := s.TreeFileSize.Copy().
111		Width(m.Width() -
112			leftMargin -
113			s.TreeFileSize.GetMarginLeft() -
114			lipgloss.Width(name)).
115		Align(lipgloss.Right)
116	fmt.Fprint(w, s.TreeFileMode.Render(mode.String())+
117		cs.Render(name)+
118		sizeStyle.Render(size))
119}