Skip to content

Commit

Permalink
feat(list): ability to SetStatusBarItemName (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
wesleimp committed Jun 16, 2022
1 parent e57fd29 commit 57d79da
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 7 deletions.
35 changes: 28 additions & 7 deletions list/list.go
Expand Up @@ -87,7 +87,7 @@ type Rank struct {
// DefaultFilter uses the sahilm/fuzzy to filter through the list.
// This is set by default.
func DefaultFilter(term string, targets []string) []Rank {
var ranks fuzzy.Matches = fuzzy.Find(term, targets)
var ranks = fuzzy.Find(term, targets)
sort.Stable(ranks)
result := make([]Rank, len(ranks))
for i, r := range ranks {
Expand Down Expand Up @@ -129,6 +129,9 @@ type Model struct {
showHelp bool
filteringEnabled bool

itemNameSingular string
itemNamePlural string

Title string
Styles Styles

Expand Down Expand Up @@ -202,6 +205,8 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model {
showStatusBar: true,
showPagination: true,
showHelp: true,
itemNameSingular: "item",
itemNamePlural: "items",
filteringEnabled: true,
KeyMap: DefaultKeyMap(),
Filter: DefaultFilter,
Expand Down Expand Up @@ -286,6 +291,18 @@ func (m Model) ShowStatusBar() bool {
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
// still be active, it simply won't be displayed.
func (m *Model) SetShowPagination(v bool) {
Expand Down Expand Up @@ -1048,21 +1065,25 @@ func (m Model) statusView() string {
totalItems := len(m.items)
visibleItems := len(m.VisibleItems())

plural := ""
var itemName string
if visibleItems != 1 {
plural = "s"
itemName = m.itemNamePlural
} else {
itemName = m.itemNameSingular
}

itemsDisplay := fmt.Sprintf("%d %s", visibleItems, itemName)

if m.filterState == Filtering {
// Filter results
if visibleItems == 0 {
status = m.Styles.StatusEmpty.Render("Nothing matched")
} else {
status = fmt.Sprintf("%d item%s", visibleItems, plural)
status = itemsDisplay
}
} else if len(m.items) == 0 {
// Not filtering: no items.
status = m.Styles.StatusEmpty.Render("No items")
status = m.Styles.StatusEmpty.Render("No " + m.itemNamePlural)
} else {
// Normal
filtered := m.FilterState() == FilterApplied
Expand All @@ -1073,7 +1094,7 @@ func (m Model) statusView() string {
status += fmt.Sprintf("“%s” ", f)
}

status += fmt.Sprintf("%d item%s", visibleItems, plural)
status += itemsDisplay
}

numFiltered := totalItems - visibleItems
Expand Down Expand Up @@ -1117,7 +1138,7 @@ func (m Model) populatedView() string {
if m.filterState == Filtering {
return ""
}
return m.Styles.NoItems.Render("No items found.")
return m.Styles.NoItems.Render("No " + m.itemNamePlural + " found.")
}

if len(items) > 0 {
Expand Down
74 changes: 74 additions & 0 deletions list/list_test.go
@@ -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)
}
}

0 comments on commit 57d79da

Please sign in to comment.