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}