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}