summaryrefslogtreecommitdiffhomepage
path: root/internal/tui/components/core
diff options
context:
space:
mode:
Diffstat (limited to 'internal/tui/components/core')
-rw-r--r--internal/tui/components/core/button.go287
-rw-r--r--internal/tui/components/core/dialog.go117
-rw-r--r--internal/tui/components/core/help.go119
-rw-r--r--internal/tui/components/core/status.go192
4 files changed, 171 insertions, 544 deletions
diff --git a/internal/tui/components/core/button.go b/internal/tui/components/core/button.go
deleted file mode 100644
index 090fbc1ee..000000000
--- a/internal/tui/components/core/button.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package core
-
-import (
- "github.com/charmbracelet/bubbles/key"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
- "github.com/kujtimiihoxha/termai/internal/tui/styles"
-)
-
-// ButtonKeyMap defines key bindings for the button component
-type ButtonKeyMap struct {
- Enter key.Binding
-}
-
-// DefaultButtonKeyMap returns default key bindings for the button
-func DefaultButtonKeyMap() ButtonKeyMap {
- return ButtonKeyMap{
- Enter: key.NewBinding(
- key.WithKeys("enter"),
- key.WithHelp("enter", "select"),
- ),
- }
-}
-
-// ShortHelp returns keybinding help
-func (k ButtonKeyMap) ShortHelp() []key.Binding {
- return []key.Binding{k.Enter}
-}
-
-// FullHelp returns full help info for keybindings
-func (k ButtonKeyMap) FullHelp() [][]key.Binding {
- return [][]key.Binding{
- {k.Enter},
- }
-}
-
-// ButtonState represents the state of a button
-type ButtonState int
-
-const (
- // ButtonNormal is the default state
- ButtonNormal ButtonState = iota
- // ButtonHovered is when the button is focused/hovered
- ButtonHovered
- // ButtonPressed is when the button is being pressed
- ButtonPressed
- // ButtonDisabled is when the button is disabled
- ButtonDisabled
-)
-
-// ButtonVariant defines the visual style variant of a button
-type ButtonVariant int
-
-const (
- // ButtonPrimary uses primary color styling
- ButtonPrimary ButtonVariant = iota
- // ButtonSecondary uses secondary color styling
- ButtonSecondary
- // ButtonDanger uses danger/error color styling
- ButtonDanger
- // ButtonWarning uses warning color styling
- ButtonWarning
- // ButtonNeutral uses neutral color styling
- ButtonNeutral
-)
-
-// ButtonMsg is sent when a button is clicked
-type ButtonMsg struct {
- ID string
- Payload any
-}
-
-// ButtonCmp represents a clickable button component
-type ButtonCmp struct {
- id string
- label string
- width int
- height int
- state ButtonState
- variant ButtonVariant
- keyMap ButtonKeyMap
- payload any
- style lipgloss.Style
- hoverStyle lipgloss.Style
-}
-
-// NewButtonCmp creates a new button component
-func NewButtonCmp(id, label string) *ButtonCmp {
- b := &ButtonCmp{
- id: id,
- label: label,
- state: ButtonNormal,
- variant: ButtonPrimary,
- keyMap: DefaultButtonKeyMap(),
- width: len(label) + 4, // add some padding
- height: 1,
- }
- b.updateStyles()
- return b
-}
-
-// WithVariant sets the button variant
-func (b *ButtonCmp) WithVariant(variant ButtonVariant) *ButtonCmp {
- b.variant = variant
- b.updateStyles()
- return b
-}
-
-// WithPayload sets the payload sent with button events
-func (b *ButtonCmp) WithPayload(payload any) *ButtonCmp {
- b.payload = payload
- return b
-}
-
-// WithWidth sets a custom width
-func (b *ButtonCmp) WithWidth(width int) *ButtonCmp {
- b.width = width
- b.updateStyles()
- return b
-}
-
-// updateStyles recalculates styles based on current state and variant
-func (b *ButtonCmp) updateStyles() {
- // Base styles
- b.style = styles.Regular.
- Padding(0, 1).
- Width(b.width).
- Align(lipgloss.Center).
- BorderStyle(lipgloss.RoundedBorder())
-
- b.hoverStyle = b.style.
- Bold(true)
-
- // Variant-specific styling
- switch b.variant {
- case ButtonPrimary:
- b.style = b.style.
- Foreground(styles.Base).
- Background(styles.Primary).
- BorderForeground(styles.Primary)
-
- b.hoverStyle = b.hoverStyle.
- Foreground(styles.Base).
- Background(styles.Blue).
- BorderForeground(styles.Blue)
-
- case ButtonSecondary:
- b.style = b.style.
- Foreground(styles.Base).
- Background(styles.Secondary).
- BorderForeground(styles.Secondary)
-
- b.hoverStyle = b.hoverStyle.
- Foreground(styles.Base).
- Background(styles.Mauve).
- BorderForeground(styles.Mauve)
-
- case ButtonDanger:
- b.style = b.style.
- Foreground(styles.Base).
- Background(styles.Error).
- BorderForeground(styles.Error)
-
- b.hoverStyle = b.hoverStyle.
- Foreground(styles.Base).
- Background(styles.Red).
- BorderForeground(styles.Red)
-
- case ButtonWarning:
- b.style = b.style.
- Foreground(styles.Text).
- Background(styles.Warning).
- BorderForeground(styles.Warning)
-
- b.hoverStyle = b.hoverStyle.
- Foreground(styles.Text).
- Background(styles.Peach).
- BorderForeground(styles.Peach)
-
- case ButtonNeutral:
- b.style = b.style.
- Foreground(styles.Text).
- Background(styles.Grey).
- BorderForeground(styles.Grey)
-
- b.hoverStyle = b.hoverStyle.
- Foreground(styles.Text).
- Background(styles.DarkGrey).
- BorderForeground(styles.DarkGrey)
- }
-
- // Disabled style override
- if b.state == ButtonDisabled {
- b.style = b.style.
- Foreground(styles.SubText0).
- Background(styles.LightGrey).
- BorderForeground(styles.LightGrey)
- }
-}
-
-// SetSize sets the button size
-func (b *ButtonCmp) SetSize(width, height int) {
- b.width = width
- b.height = height
- b.updateStyles()
-}
-
-// Focus sets the button to focused state
-func (b *ButtonCmp) Focus() tea.Cmd {
- if b.state != ButtonDisabled {
- b.state = ButtonHovered
- }
- return nil
-}
-
-// Blur sets the button to normal state
-func (b *ButtonCmp) Blur() tea.Cmd {
- if b.state != ButtonDisabled {
- b.state = ButtonNormal
- }
- return nil
-}
-
-// Disable sets the button to disabled state
-func (b *ButtonCmp) Disable() {
- b.state = ButtonDisabled
- b.updateStyles()
-}
-
-// Enable enables the button if disabled
-func (b *ButtonCmp) Enable() {
- if b.state == ButtonDisabled {
- b.state = ButtonNormal
- b.updateStyles()
- }
-}
-
-// IsDisabled returns whether the button is disabled
-func (b *ButtonCmp) IsDisabled() bool {
- return b.state == ButtonDisabled
-}
-
-// IsFocused returns whether the button is focused
-func (b *ButtonCmp) IsFocused() bool {
- return b.state == ButtonHovered
-}
-
-// Init initializes the button
-func (b *ButtonCmp) Init() tea.Cmd {
- return nil
-}
-
-// Update handles messages and user input
-func (b *ButtonCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- // Skip updates if disabled
- if b.state == ButtonDisabled {
- return b, nil
- }
-
- switch msg := msg.(type) {
- case tea.KeyMsg:
- // Handle key presses when focused
- if b.state == ButtonHovered {
- switch {
- case key.Matches(msg, b.keyMap.Enter):
- b.state = ButtonPressed
- return b, func() tea.Msg {
- return ButtonMsg{
- ID: b.id,
- Payload: b.payload,
- }
- }
- }
- }
- }
-
- return b, nil
-}
-
-// View renders the button
-func (b *ButtonCmp) View() string {
- if b.state == ButtonHovered || b.state == ButtonPressed {
- return b.hoverStyle.Render(b.label)
- }
- return b.style.Render(b.label)
-}
-
diff --git a/internal/tui/components/core/dialog.go b/internal/tui/components/core/dialog.go
deleted file mode 100644
index a8fef2e86..000000000
--- a/internal/tui/components/core/dialog.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package core
-
-import (
- "github.com/charmbracelet/bubbles/key"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
- "github.com/kujtimiihoxha/termai/internal/tui/layout"
- "github.com/kujtimiihoxha/termai/internal/tui/util"
-)
-
-type SizeableModel interface {
- tea.Model
- layout.Sizeable
-}
-
-type DialogMsg struct {
- Content SizeableModel
- WidthRatio float64
- HeightRatio float64
-
- MinWidth int
- MinHeight int
-}
-
-type DialogCloseMsg struct{}
-
-type KeyBindings struct {
- Return key.Binding
-}
-
-var keys = KeyBindings{
- Return: key.NewBinding(
- key.WithKeys("esc"),
- key.WithHelp("esc", "close"),
- ),
-}
-
-type DialogCmp interface {
- tea.Model
- layout.Bindings
-}
-
-type dialogCmp struct {
- content SizeableModel
- screenWidth int
- screenHeight int
-
- widthRatio float64
- heightRatio float64
-
- minWidth int
- minHeight int
-
- width int
- height int
-}
-
-func (d *dialogCmp) Init() tea.Cmd {
- return nil
-}
-
-func (d *dialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- d.screenWidth = msg.Width
- d.screenHeight = msg.Height
- d.width = max(int(float64(d.screenWidth)*d.widthRatio), d.minWidth)
- d.height = max(int(float64(d.screenHeight)*d.heightRatio), d.minHeight)
- if d.content != nil {
- d.content.SetSize(d.width, d.height)
- }
- return d, nil
- case DialogMsg:
- d.content = msg.Content
- d.widthRatio = msg.WidthRatio
- d.heightRatio = msg.HeightRatio
- d.minWidth = msg.MinWidth
- d.minHeight = msg.MinHeight
- d.width = max(int(float64(d.screenWidth)*d.widthRatio), d.minWidth)
- d.height = max(int(float64(d.screenHeight)*d.heightRatio), d.minHeight)
- if d.content != nil {
- d.content.SetSize(d.width, d.height)
- }
- case DialogCloseMsg:
- d.content = nil
- return d, nil
- case tea.KeyMsg:
- if key.Matches(msg, keys.Return) {
- return d, util.CmdHandler(DialogCloseMsg{})
- }
- }
- if d.content != nil {
- u, cmd := d.content.Update(msg)
- d.content = u.(SizeableModel)
- return d, cmd
- }
- return d, nil
-}
-
-func (d *dialogCmp) BindingKeys() []key.Binding {
- bindings := []key.Binding{keys.Return}
- if d.content == nil {
- return bindings
- }
- if c, ok := d.content.(layout.Bindings); ok {
- return append(bindings, c.BindingKeys()...)
- }
- return bindings
-}
-
-func (d *dialogCmp) View() string {
- return lipgloss.NewStyle().Width(d.width).Height(d.height).Render(d.content.View())
-}
-
-func NewDialogCmp() DialogCmp {
- return &dialogCmp{}
-}
diff --git a/internal/tui/components/core/help.go b/internal/tui/components/core/help.go
deleted file mode 100644
index 4ef857c78..000000000
--- a/internal/tui/components/core/help.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package core
-
-import (
- "strings"
-
- "github.com/charmbracelet/bubbles/key"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
- "github.com/kujtimiihoxha/termai/internal/tui/styles"
-)
-
-type HelpCmp interface {
- tea.Model
- SetBindings(bindings []key.Binding)
- Height() int
-}
-
-const (
- helpWidgetHeight = 12
-)
-
-type helpCmp struct {
- width int
- bindings []key.Binding
-}
-
-func (h *helpCmp) Init() tea.Cmd {
- return nil
-}
-
-func (h *helpCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- h.width = msg.Width
- }
- return h, nil
-}
-
-func (h *helpCmp) View() string {
- helpKeyStyle := styles.Bold.Foreground(styles.Rosewater).Margin(0, 1, 0, 0)
- helpDescStyle := styles.Regular.Foreground(styles.Flamingo)
- // Compile list of bindings to render
- bindings := removeDuplicateBindings(h.bindings)
- // Enumerate through each group of bindings, populating a series of
- // pairs of columns, one for keys, one for descriptions
- var (
- pairs []string
- width int
- rows = helpWidgetHeight - 2
- )
- for i := 0; i < len(bindings); i += rows {
- var (
- keys []string
- descs []string
- )
- for j := i; j < min(i+rows, len(bindings)); j++ {
- keys = append(keys, helpKeyStyle.Render(bindings[j].Help().Key))
- descs = append(descs, helpDescStyle.Render(bindings[j].Help().Desc))
- }
- // Render pair of columns; beyond the first pair, render a three space
- // left margin, in order to visually separate the pairs.
- var cols []string
- if len(pairs) > 0 {
- cols = []string{" "}
- }
- cols = append(cols,
- strings.Join(keys, "\n"),
- strings.Join(descs, "\n"),
- )
-
- pair := lipgloss.JoinHorizontal(lipgloss.Top, cols...)
- // check whether it exceeds the maximum width avail (the width of the
- // terminal, subtracting 2 for the borders).
- width += lipgloss.Width(pair)
- if width > h.width-2 {
- break
- }
- pairs = append(pairs, pair)
- }
-
- // Join pairs of columns and enclose in a border
- content := lipgloss.JoinHorizontal(lipgloss.Top, pairs...)
- return styles.DoubleBorder.Height(rows).PaddingLeft(1).Width(h.width - 2).Render(content)
-}
-
-func removeDuplicateBindings(bindings []key.Binding) []key.Binding {
- seen := make(map[string]struct{})
- result := make([]key.Binding, 0, len(bindings))
-
- // Process bindings in reverse order
- for i := len(bindings) - 1; i >= 0; i-- {
- b := bindings[i]
- k := strings.Join(b.Keys(), " ")
- if _, ok := seen[k]; ok {
- // duplicate, skip
- continue
- }
- seen[k] = struct{}{}
- // Add to the beginning of result to maintain original order
- result = append([]key.Binding{b}, result...)
- }
-
- return result
-}
-
-func (h *helpCmp) SetBindings(bindings []key.Binding) {
- h.bindings = bindings
-}
-
-func (h helpCmp) Height() int {
- return helpWidgetHeight
-}
-
-func NewHelpCmp() HelpCmp {
- return &helpCmp{
- width: 0,
- bindings: make([]key.Binding, 0),
- }
-}
diff --git a/internal/tui/components/core/status.go b/internal/tui/components/core/status.go
index 93ba34507..8bf3e5166 100644
--- a/internal/tui/components/core/status.go
+++ b/internal/tui/components/core/status.go
@@ -1,21 +1,34 @@
package core
import (
+ "fmt"
+ "strings"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/kujtimiihoxha/termai/internal/config"
- "github.com/kujtimiihoxha/termai/internal/llm/models"
- "github.com/kujtimiihoxha/termai/internal/tui/styles"
- "github.com/kujtimiihoxha/termai/internal/tui/util"
- "github.com/kujtimiihoxha/termai/internal/version"
+ "github.com/kujtimiihoxha/opencode/internal/config"
+ "github.com/kujtimiihoxha/opencode/internal/llm/models"
+ "github.com/kujtimiihoxha/opencode/internal/lsp"
+ "github.com/kujtimiihoxha/opencode/internal/lsp/protocol"
+ "github.com/kujtimiihoxha/opencode/internal/pubsub"
+ "github.com/kujtimiihoxha/opencode/internal/session"
+ "github.com/kujtimiihoxha/opencode/internal/tui/components/chat"
+ "github.com/kujtimiihoxha/opencode/internal/tui/styles"
+ "github.com/kujtimiihoxha/opencode/internal/tui/util"
)
+type StatusCmp interface {
+ tea.Model
+ SetHelpMsg(string)
+}
+
type statusCmp struct {
info util.InfoMsg
width int
messageTTL time.Duration
+ lspClients map[string]*lsp.Client
+ session session.Session
}
// clearMessageCmd is a command that clears status messages after a timeout
@@ -34,6 +47,16 @@ func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.WindowSizeMsg:
m.width = msg.Width
return m, nil
+ case chat.SessionSelectedMsg:
+ m.session = msg
+ case chat.SessionClearedMsg:
+ m.session = session.Session{}
+ case pubsub.Event[session.Session]:
+ if msg.Type == pubsub.UpdatedEvent {
+ if m.session.ID == msg.Payload.ID {
+ m.session = msg.Payload
+ }
+ }
case util.InfoMsg:
m.info = msg
ttl := msg.TTL
@@ -47,20 +70,53 @@ func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
-var (
- versionWidget = styles.Padded.Background(styles.DarkGrey).Foreground(styles.Text).Render(version.Version)
- helpWidget = styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
-)
+var helpWidget = styles.Padded.Background(styles.ForgroundMid).Foreground(styles.BackgroundDarker).Bold(true).Render("ctrl+? help")
+
+func formatTokensAndCost(tokens int64, cost float64) string {
+ // Format tokens in human-readable format (e.g., 110K, 1.2M)
+ var formattedTokens string
+ switch {
+ case tokens >= 1_000_000:
+ formattedTokens = fmt.Sprintf("%.1fM", float64(tokens)/1_000_000)
+ case tokens >= 1_000:
+ formattedTokens = fmt.Sprintf("%.1fK", float64(tokens)/1_000)
+ default:
+ formattedTokens = fmt.Sprintf("%d", tokens)
+ }
+
+ // Remove .0 suffix if present
+ if strings.HasSuffix(formattedTokens, ".0K") {
+ formattedTokens = strings.Replace(formattedTokens, ".0K", "K", 1)
+ }
+ if strings.HasSuffix(formattedTokens, ".0M") {
+ formattedTokens = strings.Replace(formattedTokens, ".0M", "M", 1)
+ }
+
+ // Format cost with $ symbol and 2 decimal places
+ formattedCost := fmt.Sprintf("$%.2f", cost)
+
+ return fmt.Sprintf("Tokens: %s, Cost: %s", formattedTokens, formattedCost)
+}
func (m statusCmp) View() string {
- status := styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
+ status := helpWidget
+ if m.session.ID != "" {
+ tokens := formatTokensAndCost(m.session.PromptTokens+m.session.CompletionTokens, m.session.Cost)
+ tokensStyle := styles.Padded.
+ Background(styles.Forground).
+ Foreground(styles.BackgroundDim).
+ Render(tokens)
+ status += tokensStyle
+ }
+
+ diagnostics := styles.Padded.Background(styles.BackgroundDarker).Render(m.projectDiagnostics())
if m.info.Msg != "" {
infoStyle := styles.Padded.
Foreground(styles.Base).
- Width(m.availableFooterMsgWidth())
+ Width(m.availableFooterMsgWidth(diagnostics))
switch m.info.Type {
case util.InfoTypeInfo:
- infoStyle = infoStyle.Background(styles.Blue)
+ infoStyle = infoStyle.Background(styles.BorderColor)
case util.InfoTypeWarn:
infoStyle = infoStyle.Background(styles.Peach)
case util.InfoTypeError:
@@ -68,7 +124,7 @@ func (m statusCmp) View() string {
}
// Truncate message if it's longer than available width
msg := m.info.Msg
- availWidth := m.availableFooterMsgWidth() - 10
+ availWidth := m.availableFooterMsgWidth(diagnostics) - 10
if len(msg) > availWidth && availWidth > 0 {
msg = msg[:availWidth] + "..."
}
@@ -76,27 +132,121 @@ func (m statusCmp) View() string {
} else {
status += styles.Padded.
Foreground(styles.Base).
- Background(styles.LightGrey).
- Width(m.availableFooterMsgWidth()).
+ Background(styles.BackgroundDim).
+ Width(m.availableFooterMsgWidth(diagnostics)).
Render("")
}
+
+ status += diagnostics
status += m.model()
- status += versionWidget
return status
}
-func (m statusCmp) availableFooterMsgWidth() int {
- // -2 to accommodate padding
- return max(0, m.width-lipgloss.Width(helpWidget)-lipgloss.Width(versionWidget)-lipgloss.Width(m.model()))
+func (m *statusCmp) projectDiagnostics() string {
+ // Check if any LSP server is still initializing
+ initializing := false
+ for _, client := range m.lspClients {
+ if client.GetServerState() == lsp.StateStarting {
+ initializing = true
+ break
+ }
+ }
+
+ // If any server is initializing, show that status
+ if initializing {
+ return lipgloss.NewStyle().
+ Background(styles.BackgroundDarker).
+ Foreground(styles.Peach).
+ Render(fmt.Sprintf("%s Initializing LSP...", styles.SpinnerIcon))
+ }
+
+ errorDiagnostics := []protocol.Diagnostic{}
+ warnDiagnostics := []protocol.Diagnostic{}
+ hintDiagnostics := []protocol.Diagnostic{}
+ infoDiagnostics := []protocol.Diagnostic{}
+ for _, client := range m.lspClients {
+ for _, d := range client.GetDiagnostics() {
+ for _, diag := range d {
+ switch diag.Severity {
+ case protocol.SeverityError:
+ errorDiagnostics = append(errorDiagnostics, diag)
+ case protocol.SeverityWarning:
+ warnDiagnostics = append(warnDiagnostics, diag)
+ case protocol.SeverityHint:
+ hintDiagnostics = append(hintDiagnostics, diag)
+ case protocol.SeverityInformation:
+ infoDiagnostics = append(infoDiagnostics, diag)
+ }
+ }
+ }
+ }
+
+ if len(errorDiagnostics) == 0 && len(warnDiagnostics) == 0 && len(hintDiagnostics) == 0 && len(infoDiagnostics) == 0 {
+ return "No diagnostics"
+ }
+
+ diagnostics := []string{}
+
+ if len(errorDiagnostics) > 0 {
+ errStr := lipgloss.NewStyle().
+ Background(styles.BackgroundDarker).
+ Foreground(styles.Error).
+ Render(fmt.Sprintf("%s %d", styles.ErrorIcon, len(errorDiagnostics)))
+ diagnostics = append(diagnostics, errStr)
+ }
+ if len(warnDiagnostics) > 0 {
+ warnStr := lipgloss.NewStyle().
+ Background(styles.BackgroundDarker).
+ Foreground(styles.Warning).
+ Render(fmt.Sprintf("%s %d", styles.WarningIcon, len(warnDiagnostics)))
+ diagnostics = append(diagnostics, warnStr)
+ }
+ if len(hintDiagnostics) > 0 {
+ hintStr := lipgloss.NewStyle().
+ Background(styles.BackgroundDarker).
+ Foreground(styles.Text).
+ Render(fmt.Sprintf("%s %d", styles.HintIcon, len(hintDiagnostics)))
+ diagnostics = append(diagnostics, hintStr)
+ }
+ if len(infoDiagnostics) > 0 {
+ infoStr := lipgloss.NewStyle().
+ Background(styles.BackgroundDarker).
+ Foreground(styles.Peach).
+ Render(fmt.Sprintf("%s %d", styles.InfoIcon, len(infoDiagnostics)))
+ diagnostics = append(diagnostics, infoStr)
+ }
+
+ return strings.Join(diagnostics, " ")
+}
+
+func (m statusCmp) availableFooterMsgWidth(diagnostics string) int {
+ tokens := ""
+ tokensWidth := 0
+ if m.session.ID != "" {
+ tokens = formatTokensAndCost(m.session.PromptTokens+m.session.CompletionTokens, m.session.Cost)
+ tokensWidth = lipgloss.Width(tokens) + 2
+ }
+ return max(0, m.width-lipgloss.Width(helpWidget)-lipgloss.Width(m.model())-lipgloss.Width(diagnostics)-tokensWidth)
}
func (m statusCmp) model() string {
- model := models.SupportedModels[config.Get().Model.Coder]
+ cfg := config.Get()
+
+ coder, ok := cfg.Agents[config.AgentCoder]
+ if !ok {
+ return "Unknown"
+ }
+ model := models.SupportedModels[coder.Model]
return styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render(model.Name)
}
-func NewStatusCmp() tea.Model {
+func (m statusCmp) SetHelpMsg(s string) {
+ helpWidget = styles.Padded.Background(styles.Forground).Foreground(styles.BackgroundDarker).Bold(true).Render(s)
+}
+
+func NewStatusCmp(lspClients map[string]*lsp.Client) StatusCmp {
return &statusCmp{
messageTTL: 10 * time.Second,
+ lspClients: lspClients,
}
}