example_test.go

  1package list_test
  2
  3import (
  4	"fmt"
  5
  6	"charm.land/lipgloss/v2"
  7	"github.com/charmbracelet/crush/internal/ui/list"
  8	uv "github.com/charmbracelet/ultraviolet"
  9)
 10
 11// Example demonstrates basic list usage with string items.
 12func Example_basic() {
 13	// Create some items
 14	items := []list.Item{
 15		list.NewStringItem("1", "First item"),
 16		list.NewStringItem("2", "Second item"),
 17		list.NewStringItem("3", "Third item"),
 18	}
 19
 20	// Create a list with options
 21	l := list.New(items...)
 22	l.SetSize(80, 10)
 23	l.SetSelectedIndex(0)
 24	if true {
 25		l.Focus()
 26	}
 27
 28	// Draw to a screen buffer
 29	screen := uv.NewScreenBuffer(80, 10)
 30	area := uv.Rect(0, 0, 80, 10)
 31	l.Draw(&screen, area)
 32
 33	// Render to string
 34	output := screen.Render()
 35	fmt.Println(output)
 36}
 37
 38// BorderedItem demonstrates a focusable item with borders.
 39type BorderedItem struct {
 40	id      string
 41	content string
 42	focused bool
 43	width   int
 44}
 45
 46func NewBorderedItem(id, content string) *BorderedItem {
 47	return &BorderedItem{
 48		id:      id,
 49		content: content,
 50		width:   80,
 51	}
 52}
 53
 54func (b *BorderedItem) ID() string {
 55	return b.id
 56}
 57
 58func (b *BorderedItem) Height(width int) int {
 59	// Account for border (2 lines for top and bottom)
 60	b.width = width // Update width for rendering
 61	return lipgloss.Height(b.render())
 62}
 63
 64func (b *BorderedItem) Draw(scr uv.Screen, area uv.Rectangle) {
 65	rendered := b.render()
 66	styled := uv.NewStyledString(rendered)
 67	styled.Draw(scr, area)
 68}
 69
 70func (b *BorderedItem) render() string {
 71	style := lipgloss.NewStyle().
 72		Width(b.width-4).
 73		Padding(0, 1)
 74
 75	if b.focused {
 76		style = style.
 77			Border(lipgloss.RoundedBorder()).
 78			BorderForeground(lipgloss.Color("205"))
 79	} else {
 80		style = style.
 81			Border(lipgloss.NormalBorder()).
 82			BorderForeground(lipgloss.Color("240"))
 83	}
 84
 85	return style.Render(b.content)
 86}
 87
 88func (b *BorderedItem) Focus() {
 89	b.focused = true
 90}
 91
 92func (b *BorderedItem) Blur() {
 93	b.focused = false
 94}
 95
 96func (b *BorderedItem) IsFocused() bool {
 97	return b.focused
 98}
 99
100// Example demonstrates focusable items with borders.
101func Example_focusable() {
102	// Create focusable items
103	items := []list.Item{
104		NewBorderedItem("1", "Focusable Item 1"),
105		NewBorderedItem("2", "Focusable Item 2"),
106		NewBorderedItem("3", "Focusable Item 3"),
107	}
108
109	// Create list with first item selected and focused
110	l := list.New(items...)
111	l.SetSize(80, 20)
112	l.SetSelectedIndex(0)
113	if true {
114		l.Focus()
115	}
116
117	// Draw to screen
118	screen := uv.NewScreenBuffer(80, 20)
119	area := uv.Rect(0, 0, 80, 20)
120	l.Draw(&screen, area)
121
122	// The first item will have a colored border since it's focused
123	output := screen.Render()
124	fmt.Println(output)
125}
126
127// Example demonstrates dynamic item updates.
128func Example_dynamicUpdates() {
129	items := []list.Item{
130		list.NewStringItem("1", "Item 1"),
131		list.NewStringItem("2", "Item 2"),
132	}
133
134	l := list.New(items...)
135	l.SetSize(80, 10)
136
137	// Draw initial state
138	screen := uv.NewScreenBuffer(80, 10)
139	area := uv.Rect(0, 0, 80, 10)
140	l.Draw(&screen, area)
141
142	// Update an item
143	l.UpdateItem("2", list.NewStringItem("2", "Updated Item 2"))
144
145	// Draw again - only changed item is re-rendered
146	l.Draw(&screen, area)
147
148	// Append a new item
149	l.AppendItem(list.NewStringItem("3", "New Item 3"))
150
151	// Draw again - master buffer grows efficiently
152	l.Draw(&screen, area)
153
154	output := screen.Render()
155	fmt.Println(output)
156}
157
158// Example demonstrates scrolling with a large list.
159func Example_scrolling() {
160	// Create many items
161	items := make([]list.Item, 100)
162	for i := range items {
163		items[i] = list.NewStringItem(
164			fmt.Sprintf("%d", i),
165			fmt.Sprintf("Item %d", i),
166		)
167	}
168
169	// Create list with small viewport
170	l := list.New(items...)
171	l.SetSize(80, 10)
172	l.SetSelectedIndex(0)
173
174	// Draw initial view (shows items 0-9)
175	screen := uv.NewScreenBuffer(80, 10)
176	area := uv.Rect(0, 0, 80, 10)
177	l.Draw(&screen, area)
178
179	// Scroll down
180	l.ScrollBy(5)
181	l.Draw(&screen, area) // Now shows items 5-14
182
183	// Jump to specific item
184	l.ScrollToItem("50")
185	l.Draw(&screen, area) // Now shows item 50 and neighbors
186
187	// Scroll to bottom
188	l.ScrollToBottom()
189	l.Draw(&screen, area) // Now shows last 10 items
190
191	output := screen.Render()
192	fmt.Println(output)
193}
194
195// VariableHeightItem demonstrates items with different heights.
196type VariableHeightItem struct {
197	id    string
198	lines []string
199	width int
200}
201
202func NewVariableHeightItem(id string, lines []string) *VariableHeightItem {
203	return &VariableHeightItem{
204		id:    id,
205		lines: lines,
206		width: 80,
207	}
208}
209
210func (v *VariableHeightItem) ID() string {
211	return v.id
212}
213
214func (v *VariableHeightItem) Height(width int) int {
215	return len(v.lines)
216}
217
218func (v *VariableHeightItem) Draw(scr uv.Screen, area uv.Rectangle) {
219	content := ""
220	for i, line := range v.lines {
221		if i > 0 {
222			content += "\n"
223		}
224		content += line
225	}
226	styled := uv.NewStyledString(content)
227	styled.Draw(scr, area)
228}
229
230// Example demonstrates variable height items.
231func Example_variableHeights() {
232	items := []list.Item{
233		NewVariableHeightItem("1", []string{"Short item"}),
234		NewVariableHeightItem("2", []string{
235			"This is a taller item",
236			"that spans multiple lines",
237			"to demonstrate variable heights",
238		}),
239		NewVariableHeightItem("3", []string{"Another short item"}),
240		NewVariableHeightItem("4", []string{
241			"A medium height item",
242			"with two lines",
243		}),
244	}
245
246	l := list.New(items...)
247	l.SetSize(80, 15)
248
249	screen := uv.NewScreenBuffer(80, 15)
250	area := uv.Rect(0, 0, 80, 15)
251	l.Draw(&screen, area)
252
253	output := screen.Render()
254	fmt.Println(output)
255}
256
257// Example demonstrates markdown items in a list.
258func Example_markdown() {
259	// Create markdown items
260	items := []list.Item{
261		list.NewMarkdownItem("1", "# Welcome\n\nThis is a **markdown** item."),
262		list.NewMarkdownItem("2", "## Features\n\n- Supports **bold**\n- Supports *italic*\n- Supports `code`"),
263		list.NewMarkdownItem("3", "### Code Block\n\n```go\nfunc main() {\n    fmt.Println(\"Hello\")\n}\n```"),
264	}
265
266	// Create list
267	l := list.New(items...)
268	l.SetSize(80, 20)
269
270	screen := uv.NewScreenBuffer(80, 20)
271	area := uv.Rect(0, 0, 80, 20)
272	l.Draw(&screen, area)
273
274	output := screen.Render()
275	fmt.Println(output)
276}