on main help sign in
feat(ui): list: expose filterable items source type and return values for selection methods
c0be798Ayman Bagabas
internal/ui/list/filterable.go+8−4
@@ -70,13 +70,17 @@ func (f *FilterableList) SetFilter(q string) {
70 f.query = q
70 f.query = q
71}
71}
72
72
73+// FilterableItemsSource is a type that implements [fuzzy.Source] for filtering
74+// [FilterableItem]s.
73−type filterableItems []FilterableItem
75+type FilterableItemsSource []FilterableItem
74
76
75−func (f filterableItems) Len() int {
77+// Len returns the length of the source.
78+func (f FilterableItemsSource) Len() int {
76 return len(f)
79 return len(f)
77}
80}
78
81
82+// String returns the string representation of the item at index i.
79−func (f filterableItems) String(i int) string {
83+func (f FilterableItemsSource) String(i int) string {
80 return f[i].Filter()
84 return f[i].Filter()
81}
85}
82
86
@@ -94,7 +98,7 @@ func (f *FilterableList) VisibleItems() []Item {
94 return items
98 return items
95 }
99 }
96
100
97− items := filterableItems(f.items)
101+ items := FilterableItemsSource(f.items)
98 matches := fuzzy.FindFrom(f.query, items)
102 matches := fuzzy.FindFrom(f.query, items)
99 matchedItems := []Item{}
103 matchedItems := []Item{}
100 resultSize := len(matches)
104 resultSize := len(matches)
internal/ui/list/item.go+19
@@ -1,6 +1,8 @@
1package list
1package list
2
2
3import (
3import (
4+ "strings"
5+
4 "github.com/charmbracelet/x/ansi"
6 "github.com/charmbracelet/x/ansi"
5)
7)
6
8
@@ -30,3 +32,20 @@ type MouseClickable interface {
30 // It returns true if the event was handled, false otherwise.
32 // It returns true if the event was handled, false otherwise.
31 HandleMouseClick(btn ansi.MouseButton, x, y int) bool
33 HandleMouseClick(btn ansi.MouseButton, x, y int) bool
32}
34}
35+
36+// SpacerItem is a spacer item that adds vertical space in the list.
37+type SpacerItem struct {
38+ Height int
39+}
40+
41+// NewSpacerItem creates a new [SpacerItem] with the specified height.
42+func NewSpacerItem(height int) *SpacerItem {
43+ return &SpacerItem{
44+ Height: max(0, height-1),
45+ }
46+}
47+
48+// Render implements the Item interface for [SpacerItem].
49+func (s *SpacerItem) Render(width int) string {
50+ return strings.Repeat("\n", s.Height)
51+}
internal/ui/list/list.go+17−4
@@ -390,6 +390,7 @@ func (l *List) SelectedItemInView() bool {
390}
390}
391
391
392// SetSelected sets the selected item index in the list.
392// SetSelected sets the selected item index in the list.
393+// It returns -1 if the index is out of bounds.
393func (l *List) SetSelected(index int) {
394func (l *List) SetSelected(index int) {
394 if index < 0 || index >= len(l.items) {
395 if index < 0 || index >= len(l.items) {
395 l.selectedIdx = -1
396 l.selectedIdx = -1
@@ -415,31 +416,43 @@ func (l *List) IsSelectedLast() bool {
415}
416}
416
417
417// SelectPrev selects the previous item in the list.
418// SelectPrev selects the previous item in the list.
419+// It returns whether the selection changed.
418−func (l *List) SelectPrev() {
420+func (l *List) SelectPrev() bool {
419 if l.selectedIdx > 0 {
421 if l.selectedIdx > 0 {
420 l.selectedIdx--
422 l.selectedIdx--
423+ return true
421 }
424 }
425+ return false
422}
426}
423
427
424// SelectNext selects the next item in the list.
428// SelectNext selects the next item in the list.
429+// It returns whether the selection changed.
425−func (l *List) SelectNext() {
430+func (l *List) SelectNext() bool {
426 if l.selectedIdx < len(l.items)-1 {
431 if l.selectedIdx < len(l.items)-1 {
427 l.selectedIdx++
432 l.selectedIdx++
433+ return true
428 }
434 }
435+ return false
429}
436}
430
437
431// SelectFirst selects the first item in the list.
438// SelectFirst selects the first item in the list.
439+// It returns whether the selection changed.
432−func (l *List) SelectFirst() {
440+func (l *List) SelectFirst() bool {
433 if len(l.items) > 0 {
441 if len(l.items) > 0 {
434 l.selectedIdx = 0
442 l.selectedIdx = 0
443+ return true
435 }
444 }
445+ return false
436}
446}
437
447
438// SelectLast selects the last item in the list.
448// SelectLast selects the last item in the list.
449+// It returns whether the selection changed.
439−func (l *List) SelectLast() {
450+func (l *List) SelectLast() bool {
440 if len(l.items) > 0 {
451 if len(l.items) > 0 {
441 l.selectedIdx = len(l.items) - 1
452 l.selectedIdx = len(l.items) - 1
453+ return true
442 }
454 }
455+ return false
443}
456}
444
457
445// SelectedItem returns the currently selected item. It may be nil if no item
458// SelectedItem returns the currently selected item. It may be nil if no item