@@ -11,6 +11,9 @@ import (
1111"github.com/kujtimiihoxha/opencode/internal/llm/models"
1212"github.com/kujtimiihoxha/opencode/internal/lsp"
1313"github.com/kujtimiihoxha/opencode/internal/lsp/protocol"
14+ "github.com/kujtimiihoxha/opencode/internal/pubsub"
15+ "github.com/kujtimiihoxha/opencode/internal/session"
16+ "github.com/kujtimiihoxha/opencode/internal/tui/components/chat"
1417"github.com/kujtimiihoxha/opencode/internal/tui/styles"
1518"github.com/kujtimiihoxha/opencode/internal/tui/util"
1619)
@@ -20,6 +23,7 @@ type statusCmp struct {
2023width int
2124messageTTL time.Duration
2225lspClients map [string ]* lsp.Client
26+ session session.Session
2327}
2428
2529// clearMessageCmd is a command that clears status messages after a timeout
@@ -38,6 +42,16 @@ func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
3842case tea.WindowSizeMsg :
3943m .width = msg .Width
4044return m , nil
45+ case chat.SessionSelectedMsg :
46+ m .session = msg
47+ case chat.SessionClearedMsg :
48+ m .session = session.Session {}
49+ case pubsub.Event [session.Session ]:
50+ if msg .Type == pubsub .UpdatedEvent {
51+ if m .session .ID == msg .Payload .ID {
52+ m .session = msg .Payload
53+ }
54+ }
4155case util.InfoMsg :
4256m .info = msg
4357ttl := msg .TTL
@@ -53,8 +67,43 @@ func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5367
5468var helpWidget = styles .Padded .Background (styles .ForgroundMid ).Foreground (styles .BackgroundDarker ).Bold (true ).Render ("ctrl+? help" )
5569
70+ func formatTokensAndCost (tokens int64 , cost float64 ) string {
71+ // Format tokens in human-readable format (e.g., 110K, 1.2M)
72+ var formattedTokens string
73+ switch {
74+ case tokens >= 1_000_000 :
75+ formattedTokens = fmt .Sprintf ("%.1fM" , float64 (tokens )/ 1_000_000 )
76+ case tokens >= 1_000 :
77+ formattedTokens = fmt .Sprintf ("%.1fK" , float64 (tokens )/ 1_000 )
78+ default :
79+ formattedTokens = fmt .Sprintf ("%d" , tokens )
80+ }
81+
82+ // Remove .0 suffix if present
83+ if strings .HasSuffix (formattedTokens , ".0K" ) {
84+ formattedTokens = strings .Replace (formattedTokens , ".0K" , "K" , 1 )
85+ }
86+ if strings .HasSuffix (formattedTokens , ".0M" ) {
87+ formattedTokens = strings .Replace (formattedTokens , ".0M" , "M" , 1 )
88+ }
89+
90+ // Format cost with $ symbol and 2 decimal places
91+ formattedCost := fmt .Sprintf ("$%.2f" , cost )
92+
93+ return fmt .Sprintf ("Tokens: %s, Cost: %s" , formattedTokens , formattedCost )
94+ }
95+
5696func (m statusCmp ) View () string {
5797status := helpWidget
98+ if m .session .ID != "" {
99+ tokens := formatTokensAndCost (m .session .PromptTokens + m .session .CompletionTokens , m .session .Cost )
100+ tokensStyle := styles .Padded .
101+ Background (styles .Forground ).
102+ Foreground (styles .BackgroundDim ).
103+ Render (tokens )
104+ status += tokensStyle
105+ }
106+
58107diagnostics := styles .Padded .Background (styles .BackgroundDarker ).Render (m .projectDiagnostics ())
59108if m .info .Msg != "" {
60109infoStyle := styles .Padded .
@@ -82,6 +131,7 @@ func (m statusCmp) View() string {
82131Width (m .availableFooterMsgWidth (diagnostics )).
83132Render ("" )
84133}
134+
85135status += diagnostics
86136status += m .model ()
87137return status
@@ -136,7 +186,11 @@ func (m *statusCmp) projectDiagnostics() string {
136186}
137187
138188func (m statusCmp ) availableFooterMsgWidth (diagnostics string ) int {
139- return max (0 , m .width - lipgloss .Width (helpWidget )- lipgloss .Width (m .model ())- lipgloss .Width (diagnostics ))
189+ tokens := ""
190+ if m .session .ID != "" {
191+ tokens = formatTokensAndCost (m .session .PromptTokens + m .session .CompletionTokens , m .session .Cost )
192+ }
193+ return max (0 , m .width - lipgloss .Width (helpWidget )- lipgloss .Width (m .model ())- lipgloss .Width (diagnostics )- lipgloss .Width (tokens ))
140194}
141195
142196func (m statusCmp ) model () string {
0 commit comments