1package core
2
3import (
4 "time"
5
6 tea "github.com/charmbracelet/bubbletea"
7 "github.com/charmbracelet/lipgloss"
8 "github.com/kujtimiihoxha/termai/internal/config"
9 "github.com/kujtimiihoxha/termai/internal/llm/models"
10 "github.com/kujtimiihoxha/termai/internal/tui/styles"
11 "github.com/kujtimiihoxha/termai/internal/tui/util"
12 "github.com/kujtimiihoxha/termai/internal/version"
13)
14
15type statusCmp struct {
16 err error
17 info string
18 width int
19 messageTTL time.Duration
20}
21
22// clearMessageCmd is a command that clears status messages after a timeout
23func (m statusCmp) clearMessageCmd() tea.Cmd {
24 return tea.Tick(m.messageTTL, func(time.Time) tea.Msg {
25 return util.ClearStatusMsg{}
26 })
27}
28
29func (m statusCmp) Init() tea.Cmd {
30 return nil
31}
32
33func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
34 switch msg := msg.(type) {
35 case tea.WindowSizeMsg:
36 m.width = msg.Width
37 case util.ErrorMsg:
38 m.err = msg
39 m.info = ""
40 return m, m.clearMessageCmd()
41 case util.InfoMsg:
42 m.info = string(msg)
43 m.err = nil
44 return m, m.clearMessageCmd()
45 case util.ClearStatusMsg:
46 m.info = ""
47 m.err = nil
48 }
49 return m, nil
50}
51
52var (
53 versionWidget = styles.Padded.Background(styles.DarkGrey).Foreground(styles.Text).Render(version.Version)
54 helpWidget = styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
55)
56
57func (m statusCmp) View() string {
58 status := styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
59
60 if m.err != nil {
61 status += styles.Regular.Padding(0, 1).
62 Background(styles.Red).
63 Foreground(styles.Text).
64 Width(m.availableFooterMsgWidth()).
65 Render(m.err.Error())
66 } else if m.info != "" {
67 status += styles.Padded.
68 Foreground(styles.Base).
69 Background(styles.Green).
70 Width(m.availableFooterMsgWidth()).
71 Render(m.info)
72 } else {
73 status += styles.Padded.
74 Foreground(styles.Base).
75 Background(styles.LightGrey).
76 Width(m.availableFooterMsgWidth()).
77 Render(m.info)
78 }
79 status += m.model()
80 status += versionWidget
81 return status
82}
83
84func (m statusCmp) availableFooterMsgWidth() int {
85 // -2 to accommodate padding
86 return max(0, m.width-lipgloss.Width(helpWidget)-lipgloss.Width(versionWidget)-lipgloss.Width(m.model()))
87}
88
89func (m statusCmp) model() string {
90 model := models.SupportedModels[config.Get().Model.Coder]
91 return styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render(model.Name)
92}
93
94func NewStatusCmp() tea.Model {
95 return &statusCmp{
96 messageTTL: 5 * time.Second,
97 }
98}