mirror of
https://github.com/Maks1mS/bubbles.git
synced 2024-12-23 22:32:59 +03:00
feat(list): ability to SetStatusBarItemName
(#169)
This commit is contained in:
parent
e57fd292cc
commit
57d79daf4d
35
list/list.go
35
list/list.go
@ -87,7 +87,7 @@ type Rank struct {
|
|||||||
// DefaultFilter uses the sahilm/fuzzy to filter through the list.
|
// DefaultFilter uses the sahilm/fuzzy to filter through the list.
|
||||||
// This is set by default.
|
// This is set by default.
|
||||||
func DefaultFilter(term string, targets []string) []Rank {
|
func DefaultFilter(term string, targets []string) []Rank {
|
||||||
var ranks fuzzy.Matches = fuzzy.Find(term, targets)
|
var ranks = fuzzy.Find(term, targets)
|
||||||
sort.Stable(ranks)
|
sort.Stable(ranks)
|
||||||
result := make([]Rank, len(ranks))
|
result := make([]Rank, len(ranks))
|
||||||
for i, r := range ranks {
|
for i, r := range ranks {
|
||||||
@ -129,6 +129,9 @@ type Model struct {
|
|||||||
showHelp bool
|
showHelp bool
|
||||||
filteringEnabled bool
|
filteringEnabled bool
|
||||||
|
|
||||||
|
itemNameSingular string
|
||||||
|
itemNamePlural string
|
||||||
|
|
||||||
Title string
|
Title string
|
||||||
Styles Styles
|
Styles Styles
|
||||||
|
|
||||||
@ -202,6 +205,8 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model {
|
|||||||
showStatusBar: true,
|
showStatusBar: true,
|
||||||
showPagination: true,
|
showPagination: true,
|
||||||
showHelp: true,
|
showHelp: true,
|
||||||
|
itemNameSingular: "item",
|
||||||
|
itemNamePlural: "items",
|
||||||
filteringEnabled: true,
|
filteringEnabled: true,
|
||||||
KeyMap: DefaultKeyMap(),
|
KeyMap: DefaultKeyMap(),
|
||||||
Filter: DefaultFilter,
|
Filter: DefaultFilter,
|
||||||
@ -286,6 +291,18 @@ func (m Model) ShowStatusBar() bool {
|
|||||||
return m.showStatusBar
|
return m.showStatusBar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetStatusBarItemName defines a replacement for the items identifier. Defaults
|
||||||
|
// to item/items
|
||||||
|
func (m *Model) SetStatusBarItemName(singular, plural string) {
|
||||||
|
m.itemNameSingular = singular
|
||||||
|
m.itemNamePlural = plural
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusBarItemName returns singular and plural status bar item names
|
||||||
|
func (m Model) StatusBarItemName() (string, string) {
|
||||||
|
return m.itemNameSingular, m.itemNamePlural
|
||||||
|
}
|
||||||
|
|
||||||
// ShowingPagination hides or shoes the paginator. Note that pagination will
|
// ShowingPagination hides or shoes the paginator. Note that pagination will
|
||||||
// still be active, it simply won't be displayed.
|
// still be active, it simply won't be displayed.
|
||||||
func (m *Model) SetShowPagination(v bool) {
|
func (m *Model) SetShowPagination(v bool) {
|
||||||
@ -1048,21 +1065,25 @@ func (m Model) statusView() string {
|
|||||||
totalItems := len(m.items)
|
totalItems := len(m.items)
|
||||||
visibleItems := len(m.VisibleItems())
|
visibleItems := len(m.VisibleItems())
|
||||||
|
|
||||||
plural := ""
|
var itemName string
|
||||||
if visibleItems != 1 {
|
if visibleItems != 1 {
|
||||||
plural = "s"
|
itemName = m.itemNamePlural
|
||||||
|
} else {
|
||||||
|
itemName = m.itemNameSingular
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemsDisplay := fmt.Sprintf("%d %s", visibleItems, itemName)
|
||||||
|
|
||||||
if m.filterState == Filtering {
|
if m.filterState == Filtering {
|
||||||
// Filter results
|
// Filter results
|
||||||
if visibleItems == 0 {
|
if visibleItems == 0 {
|
||||||
status = m.Styles.StatusEmpty.Render("Nothing matched")
|
status = m.Styles.StatusEmpty.Render("Nothing matched")
|
||||||
} else {
|
} else {
|
||||||
status = fmt.Sprintf("%d item%s", visibleItems, plural)
|
status = itemsDisplay
|
||||||
}
|
}
|
||||||
} else if len(m.items) == 0 {
|
} else if len(m.items) == 0 {
|
||||||
// Not filtering: no items.
|
// Not filtering: no items.
|
||||||
status = m.Styles.StatusEmpty.Render("No items")
|
status = m.Styles.StatusEmpty.Render("No " + m.itemNamePlural)
|
||||||
} else {
|
} else {
|
||||||
// Normal
|
// Normal
|
||||||
filtered := m.FilterState() == FilterApplied
|
filtered := m.FilterState() == FilterApplied
|
||||||
@ -1073,7 +1094,7 @@ func (m Model) statusView() string {
|
|||||||
status += fmt.Sprintf("“%s” ", f)
|
status += fmt.Sprintf("“%s” ", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
status += fmt.Sprintf("%d item%s", visibleItems, plural)
|
status += itemsDisplay
|
||||||
}
|
}
|
||||||
|
|
||||||
numFiltered := totalItems - visibleItems
|
numFiltered := totalItems - visibleItems
|
||||||
@ -1117,7 +1138,7 @@ func (m Model) populatedView() string {
|
|||||||
if m.filterState == Filtering {
|
if m.filterState == Filtering {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return m.Styles.NoItems.Render("No items found.")
|
return m.Styles.NoItems.Render("No " + m.itemNamePlural + " found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(items) > 0 {
|
if len(items) > 0 {
|
||||||
|
74
list/list_test.go
Normal file
74
list/list_test.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package list
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
)
|
||||||
|
|
||||||
|
type item string
|
||||||
|
|
||||||
|
func (i item) FilterValue() string { return "" }
|
||||||
|
|
||||||
|
type itemDelegate struct{}
|
||||||
|
|
||||||
|
func (d itemDelegate) Height() int { return 1 }
|
||||||
|
func (d itemDelegate) Spacing() int { return 0 }
|
||||||
|
func (d itemDelegate) Update(msg tea.Msg, m *Model) tea.Cmd { return nil }
|
||||||
|
func (d itemDelegate) Render(w io.Writer, m Model, index int, listItem Item) {
|
||||||
|
i, ok := listItem.(item)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
str := fmt.Sprintf("%d. %s", index+1, i)
|
||||||
|
fmt.Fprint(w, m.Styles.TitleBar.Render(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusBarItemName(t *testing.T) {
|
||||||
|
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10)
|
||||||
|
expected := "2 items"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
list.SetItems([]Item{item("foo")})
|
||||||
|
expected = "1 item"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusBarWithoutItems(t *testing.T) {
|
||||||
|
list := New([]Item{}, itemDelegate{}, 10, 10)
|
||||||
|
|
||||||
|
expected := "No items"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomStatusBarItemName(t *testing.T) {
|
||||||
|
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10)
|
||||||
|
list.SetStatusBarItemName("connection", "connections")
|
||||||
|
|
||||||
|
expected := "2 connections"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
list.SetItems([]Item{item("foo")})
|
||||||
|
expected = "1 connection"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
list.SetItems([]Item{})
|
||||||
|
expected = "No connections"
|
||||||
|
if !strings.Contains(list.statusView(), expected) {
|
||||||
|
t.Fatalf("Error: expected view to contain %s", expected)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user