items.go

  1package list
  2
  3import (
  4	"io"
  5
  6	"charm.land/lipgloss/v2"
  7	"github.com/charmbracelet/crush/internal/ui/common"
  8	"github.com/charmbracelet/glamour/v2"
  9	"github.com/charmbracelet/glamour/v2/ansi"
 10)
 11
 12// Item represents a rendered item in the [List] component.
 13type Item interface {
 14	// Content is the rendered content of the item.
 15	Content() string
 16	// Height returns the height of the item based on its content.
 17	Height() int
 18}
 19
 20// Gap is [GapItem] to be used as a vertical gap in the list.
 21var Gap = GapItem{}
 22
 23// GapItem represents a vertical gap in the list.
 24type GapItem struct{}
 25
 26// Content returns the content of the gap item.
 27func (g GapItem) Content() string {
 28	return ""
 29}
 30
 31// Height returns the height of the gap item.
 32func (g GapItem) Height() int {
 33	return 1
 34}
 35
 36// StringItem represents a simple string item in the list.
 37type StringItem struct {
 38	content string
 39}
 40
 41// NewStringItem creates a new [StringItem] with the given id and content.
 42func NewStringItem(content string) StringItem {
 43	return StringItem{
 44		content: content,
 45	}
 46}
 47
 48// Content returns the content of the string item.
 49func (s StringItem) Content() string {
 50	return s.content
 51}
 52
 53// Height returns the height of the string item based on its content.
 54func (s StringItem) Height() int {
 55	return lipgloss.Height(s.content)
 56}
 57
 58// MarkdownItem represents a markdown item in the list.
 59type MarkdownItem struct {
 60	StringItem
 61}
 62
 63// NewMarkdownItem creates a new [MarkdownItem] with the given id and content.
 64func NewMarkdownItem(id, content string) MarkdownItem {
 65	return MarkdownItem{
 66		StringItem: StringItem{
 67			content: content,
 68		},
 69	}
 70}
 71
 72// Content returns the content of the markdown item.
 73func (m MarkdownItem) Content() string {
 74	return m.StringItem.Content()
 75}
 76
 77// Height returns the height of the markdown item based on its content.
 78func (m MarkdownItem) Height() int {
 79	return m.StringItem.Height()
 80}
 81
 82// MarkdownItemMaxWidth is the maximum width for rendering markdown items.
 83const MarkdownItemMaxWidth = 120
 84
 85// MarkdownItemRenderer renders [MarkdownItem]s in a [List].
 86type MarkdownItemRenderer struct {
 87	Styles *ansi.StyleConfig
 88}
 89
 90// Render implements [ItemRenderer].
 91func (m *MarkdownItemRenderer) Render(w io.Writer, list *List, index int, item Item) {
 92	width := min(list.Width(), MarkdownItemMaxWidth)
 93	var r *glamour.TermRenderer
 94	if m.Styles != nil {
 95		r = common.MarkdownRenderer(*m.Styles, width)
 96	} else {
 97		r = common.PlainMarkdownRenderer(width)
 98	}
 99
100	rendered, _ := r.Render(item.Content())
101	_, _ = io.WriteString(w, rendered)
102}