diff --git a/pkg/ui/components/tabs/tabs.go b/pkg/ui/components/tabs/tabs.go index 36f0a19e8..54589917a 100644 --- a/pkg/ui/components/tabs/tabs.go +++ b/pkg/ui/components/tabs/tabs.go @@ -14,10 +14,22 @@ type SelectTabMsg int // ActiveTabMsg is a message that contains the index of the current active tab. type ActiveTabMsg int +// IdentifiableTab is a struct that encapsulates a tabs shown value with an id. +type IdentifiableTab struct { + ID string + Value string +} + +// SetTabValueMsg is a message that sets a tabs shown value. +type SetTabValueMsg struct { + ID string + Value string +} + // Tabs is bubbletea component that displays a list of tabs. type Tabs struct { common common.Common - tabs []string + tabs []IdentifiableTab activeTab int TabSeparator lipgloss.Style TabInactive lipgloss.Style @@ -28,9 +40,16 @@ type Tabs struct { // New creates a new Tabs component. func New(c common.Common, tabs []string) *Tabs { + ts := make([]IdentifiableTab, 0) + for _, t := range tabs { + ts = append(ts, IdentifiableTab{ + ID: t, + Value: t, + }) + } r := &Tabs{ common: c, - tabs: tabs, + tabs: ts, activeTab: 0, TabSeparator: c.Styles.TabSeparator, TabInactive: c.Styles.TabInactive, @@ -67,12 +86,19 @@ func (t *Tabs) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.Button { case tea.MouseLeft: for i, tab := range t.tabs { - if t.common.Zone.Get(tab).InBounds(msg) { + if t.common.Zone.Get(tab.ID).InBounds(msg) { t.activeTab = i cmds = append(cmds, t.activeTabCmd) } } } + case SetTabValueMsg: + for i, tab := range t.tabs { + if tab.ID == msg.ID { + t.tabs[i].Value = msg.Value + break + } + } case SelectTabMsg: tab := int(msg) if tab >= 0 && tab < len(t.tabs) { @@ -82,6 +108,13 @@ func (t *Tabs) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return t, tea.Batch(cmds...) } +// ResetTabNames resets all tab names to their IDs. +func (t *Tabs) ResetTabNames() { + for i := range t.tabs { + t.tabs[i].Value = t.tabs[i].ID + } +} + // View implements tea.Model. func (t *Tabs) View() string { s := strings.Builder{} @@ -98,8 +131,8 @@ func (t *Tabs) View() string { } s.WriteString( t.common.Zone.Mark( - tab, - style.Render(tab), + tab.ID, + style.Render(tab.Value), ), ) if i != len(t.tabs)-1 { diff --git a/pkg/ui/pages/repo/repo.go b/pkg/ui/pages/repo/repo.go index e9e5535ee..47c863521 100644 --- a/pkg/ui/pages/repo/repo.go +++ b/pkg/ui/pages/repo/repo.go @@ -139,6 +139,9 @@ func (r *Repo) FullHelp() [][]key.Binding { func (r *Repo) Init() tea.Cmd { r.state = loadingState r.activeTab = 0 + // Reset the tab names on every init so that we do not + // briefly show incorrect counts when navigating between repos + r.tabs.ResetTabNames() return tea.Batch( r.tabs.Init(), r.statusbar.Init(), @@ -217,9 +220,25 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case FileItemsMsg, FileContentMsg: cmds = append(cmds, r.updateTabComponent(&Files{}, msg)) case LogItemsMsg, LogDiffMsg, LogCountMsg: - cmds = append(cmds, r.updateTabComponent(&Log{}, msg)) + log := &Log{} + if lim, ok := msg.(LogItemsMsg); ok { + msg := tabs.SetTabValueMsg{ID: log.TabName(), Value: fmt.Sprintf("Commits (%d)", len(lim))} + t, cmd := r.tabs.Update(msg) + r.tabs = t.(*tabs.Tabs) + if cmd != nil { + cmds = append(cmds, cmd) + } + } + cmds = append(cmds, r.updateTabComponent(log, msg)) case RefItemsMsg: - cmds = append(cmds, r.updateTabComponent(&Refs{refPrefix: msg.prefix}, msg)) + refs := &Refs{refPrefix: msg.prefix} + tabMsg := tabs.SetTabValueMsg{ID: refs.TabName(), Value: fmt.Sprintf("%s (%d)", refs.TabName(), len(msg.items))} + t, cmd := r.tabs.Update(tabMsg) + r.tabs = t.(*tabs.Tabs) + if cmd != nil { + cmds = append(cmds, cmd) + } + cmds = append(cmds, r.updateTabComponent(refs, msg)) case StashListMsg, StashPatchMsg: cmds = append(cmds, r.updateTabComponent(&Stash{}, msg)) // We have two spinners, one is used to when loading the repository and the