Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom status bar title #169

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 26 additions & 5 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 the custom status bar title
wesleimp marked this conversation as resolved.
Show resolved Hide resolved
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,17 +1065,21 @@ 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.
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
68 changes: 68 additions & 0 deletions list/list_test.go
@@ -0,0 +1,68 @@
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)
}
}