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("First item"),
 16		list.NewStringItem("Second item"),
 17		list.NewStringItem("Third item"),
 18	}
 19
 20	// Create a list with options
 21	l := list.New(items...)
 22	l.SetSize(80, 10)
 23	l.SetSelected(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.SetSelected(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("Item 1"),
131		list.NewStringItem("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("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("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("Item %d", i),
165		)
166	}
167
168	// Create list with small viewport
169	l := list.New(items...)
170	l.SetSize(80, 10)
171	l.SetSelected(0)
172
173	// Draw initial view (shows items 0-9)
174	screen := uv.NewScreenBuffer(80, 10)
175	area := uv.Rect(0, 0, 80, 10)
176	l.Draw(&screen, area)
177
178	// Scroll down
179	l.ScrollBy(5)
180	l.Draw(&screen, area) // Now shows items 5-14
181
182	// Jump to specific item
183	l.ScrollToItem(50)
184	l.Draw(&screen, area) // Now shows item 50 and neighbors
185
186	// Scroll to bottom
187	l.ScrollToBottom()
188	l.Draw(&screen, area) // Now shows last 10 items
189
190	output := screen.Render()
191	fmt.Println(output)
192}
193
194// VariableHeightItem demonstrates items with different heights.
195type VariableHeightItem struct {
196	id    string
197	lines []string
198	width int
199}
200
201func NewVariableHeightItem(id string, lines []string) *VariableHeightItem {
202	return &VariableHeightItem{
203		id:    id,
204		lines: lines,
205		width: 80,
206	}
207}
208
209func (v *VariableHeightItem) ID() string {
210	return v.id
211}
212
213func (v *VariableHeightItem) Height(width int) int {
214	return len(v.lines)
215}
216
217func (v *VariableHeightItem) Draw(scr uv.Screen, area uv.Rectangle) {
218	content := ""
219	for i, line := range v.lines {
220		if i > 0 {
221			content += "\n"
222		}
223		content += line
224	}
225	styled := uv.NewStyledString(content)
226	styled.Draw(scr, area)
227}
228
229// Example demonstrates variable height items.
230func Example_variableHeights() {
231	items := []list.Item{
232		NewVariableHeightItem("1", []string{"Short item"}),
233		NewVariableHeightItem("2", []string{
234			"This is a taller item",
235			"that spans multiple lines",
236			"to demonstrate variable heights",
237		}),
238		NewVariableHeightItem("3", []string{"Another short item"}),
239		NewVariableHeightItem("4", []string{
240			"A medium height item",
241			"with two lines",
242		}),
243	}
244
245	l := list.New(items...)
246	l.SetSize(80, 15)
247
248	screen := uv.NewScreenBuffer(80, 15)
249	area := uv.Rect(0, 0, 80, 15)
250	l.Draw(&screen, area)
251
252	output := screen.Render()
253	fmt.Println(output)
254}
255
256// Example demonstrates markdown items in a list.
257func Example_markdown() {
258	// Create markdown items
259	items := []list.Item{
260		list.NewMarkdownItem("# Welcome\n\nThis is a **markdown** item."),
261		list.NewMarkdownItem("## Features\n\n- Supports **bold**\n- Supports *italic*\n- Supports `code`"),
262		list.NewMarkdownItem("### Code Block\n\n```go\nfunc main() {\n    fmt.Println(\"Hello\")\n}\n```"),
263	}
264
265	// Create list
266	l := list.New(items...)
267	l.SetSize(80, 20)
268
269	screen := uv.NewScreenBuffer(80, 20)
270	area := uv.Rect(0, 0, 80, 20)
271	l.Draw(&screen, area)
272
273	output := screen.Render()
274	fmt.Println(output)
275}