status.go

 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}