mirror of
				https://github.com/Maks1mS/bubbles.git
				synced 2025-10-31 05:42:01 +03:00 
			
		
		
		
	feat(list): ability to SetStatusBarItemName (#169)
				
					
				
			This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						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. | ||||
| // 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 { | ||||
| @@ -129,6 +129,9 @@ type Model struct { | ||||
| 	showHelp         bool | ||||
| 	filteringEnabled bool | ||||
|  | ||||
| 	itemNameSingular string | ||||
| 	itemNamePlural   string | ||||
|  | ||||
| 	Title  string | ||||
| 	Styles Styles | ||||
|  | ||||
| @@ -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, | ||||
| @@ -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) { | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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 { | ||||
|   | ||||
							
								
								
									
										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) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user