charmbracelet / charmbracelet/bubbles

List: Unnecessary/Undesirable ellipsis on full width title

Open
#737 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
8.9k
Forks
457
Avg merge
1d 18h
Merged PRs (30d)
5

Description

**Describe the bug**
When the list title occupies the full width of the item, unnecessary ellipsis is appended. The logic which appends the status message appends two spaces regardless of whether a status message is set.

**Setup**
Please complete the following information along with version numbers, if applicable.
- OS agnostic
- Shell agnostic
- Terminal Emulator: n/a
- Terminal Multiplexer: n/a
- Locale en_US.UTF-8

**To Reproduce**
Steps to reproduce the behavior:
1. Create a list with a title set to the maximum width (but no wider)
``` dl := list.New(listItems, itemDelegate, 0, 10)
dl.SetShowHelp(false)
dl.Title = "List Title ABCDEFG"
dl.Styles.Title = list.DefaultStyles().Title.Padding(0)
```

2. Set the list width to title width + 2 (in the example above 18 + 2 = 20)

3. Render the list

**Source Code**
```package main

import (
"fmt"

"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

type someListModel struct {
demoList list.Model
}

type someListItem struct {
text string
}

func (s someListItem) FilterValue() string {
return s.text
}

func (s someListItem) Description() string {
return ""
}

var listItemStyle = lipgloss.NewStyle().Width(18).Background(lipgloss.Color("17")).Foreground(lipgloss.Color("15")).Align(lipgloss.Left)

func (s someListItem) Title() string {
return listItemStyle.Render(s.text)
}

func NewList(items []string) *someListModel {
listItems := make([]list.Item, len(items))
for i, item := range items {
listItems[i] = someListItem{text: item}
}
itemDelegate := list.NewDefaultDelegate()
itemDelegate.SetHeight(1)
itemDelegate.SetSpacing(0)
itemDelegate.ShowDescription = false

dl := list.New(listItems, itemDelegate, 0, 10)
dl.SetShowHelp(false)
dl.Title = "List Title ABCDEFG"
dl.Styles.Title = list.DefaultStyles().Title.Padding(0)
return &someListModel{demoList: dl}
}

func (s *someListModel) Init() tea.Cmd {
return nil
}

func (s *someListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
s.demoList.SetWidth(min(20, msg.Width-2))
case tea.KeyMsg:
if s.demoList.FilteringEnabled() {
break
}
if msg.String() == "q" {
return s, tea.Quit
}
}
var cmd tea.Cmd
s.demoList, cmd = s.demoList.Update(msg)
return s, cmd
}

func (s *someListModel) View() string {
return lipgloss.NewStyle().Border(lipgloss.NormalBorder()).Render(s.demoList.View())
}

func main() {
s := NewList([]string{"one", "two", "three"})
p := tea.NewProgram(s, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
fmt.Printf("Error starting program: %v", err)
return
}
}
```

**Expected behavior**
Given the title itself doesn't overflow the width of the list, I would not expect an ellipsis to be appended to the title.

**Screenshots**
![Image](https://github.com/user-attachments/assets/dcfb17c2-012d-4dfb-9bec-9213cd2751c2)

**Additional context**
The origin of the problem is the unconditional appending of two spaces to the title (assuming filtering is not active)
``` // Status message
if m.filterState != Filtering {
view += " " + m.statusMessage
view = ansi.Truncate(view, m.width-spinnerWidth, ellipsis)
}```

If the spaces were only appended for non-empty statusMessage, this would only result in the ellipsis in the valid situation where there is further content beyond the base title.
``` // Status message
if m.filterState != Filtering {
if m.statusMessage != "" {
view += " " + m.statusMessage
}
view = ansi.Truncate(view, m.width-spinnerWidth, ellipsis)
}
```

This yields the title without the ellipsis.

![Image](https://github.com/user-attachments/assets/ecb4f955-a6d0-4771-b90f-d85a1f9e481b)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.