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	info       *util.InfoMsg
17	width      int
18	messageTTL time.Duration
19}
20
21// clearMessageCmd is a command that clears status messages after a timeout
22func (m statusCmp) clearMessageCmd() tea.Cmd {
23	return tea.Tick(m.messageTTL, func(time.Time) tea.Msg {
24		return util.ClearStatusMsg{}
25	})
26}
27
28func (m statusCmp) Init() tea.Cmd {
29	return nil
30}
31
32func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
33	switch msg := msg.(type) {
34	case tea.WindowSizeMsg:
35		m.width = msg.Width
36		return m, m.clearMessageCmd()
37	case util.InfoMsg:
38		m.info = &msg
39		return m, m.clearMessageCmd()
40	case util.ClearStatusMsg:
41		m.info = nil
42	}
43	return m, nil
44}
45
46var (
47	versionWidget = styles.Padded.Background(styles.DarkGrey).Foreground(styles.Text).Render(version.Version)
48	helpWidget    = styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
49)
50
51func (m statusCmp) View() string {
52	status := styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render("? help")
53	if m.info != nil {
54		infoStyle := styles.Padded.
55			Foreground(styles.Base).
56			Width(m.availableFooterMsgWidth())
57		switch m.info.Type {
58		case util.InfoTypeInfo:
59			infoStyle = infoStyle.Background(styles.Blue)
60		case util.InfoTypeWarn:
61			infoStyle = infoStyle.Background(styles.Peach)
62		case util.InfoTypeError:
63			infoStyle = infoStyle.Background(styles.Red)
64		}
65		status += infoStyle.Render(m.info.Msg)
66	} else {
67		status += styles.Padded.
68			Foreground(styles.Base).
69			Background(styles.LightGrey).
70			Width(m.availableFooterMsgWidth()).
71			Render("")
72	}
73	status += m.model()
74	status += versionWidget
75	return status
76}
77
78func (m statusCmp) availableFooterMsgWidth() int {
79	// -2 to accommodate padding
80	return max(0, m.width-lipgloss.Width(helpWidget)-lipgloss.Width(versionWidget)-lipgloss.Width(m.model()))
81}
82
83func (m statusCmp) model() string {
84	model := models.SupportedModels[config.Get().Model.Coder]
85	return styles.Padded.Background(styles.Grey).Foreground(styles.Text).Render(model.Name)
86}
87
88func NewStatusCmp() tea.Model {
89	return &statusCmp{
90		messageTTL: 5 * time.Second,
91	}
92}