1package status
2
3import (
4 "time"
5
6 "github.com/charmbracelet/bubbles/v2/help"
7 tea "github.com/charmbracelet/bubbletea/v2"
8 "github.com/charmbracelet/crush/internal/logging"
9 "github.com/charmbracelet/crush/internal/pubsub"
10 "github.com/charmbracelet/crush/internal/session"
11 "github.com/charmbracelet/crush/internal/tui/styles"
12 "github.com/charmbracelet/crush/internal/tui/util"
13)
14
15type StatusCmp interface {
16 util.Model
17}
18
19type statusCmp struct {
20 info util.InfoMsg
21 width int
22 messageTTL time.Duration
23 session session.Session
24 help help.Model
25}
26
27// clearMessageCmd is a command that clears status messages after a timeout
28func (m statusCmp) clearMessageCmd(ttl time.Duration) tea.Cmd {
29 return tea.Tick(ttl, func(time.Time) tea.Msg {
30 return util.ClearStatusMsg{}
31 })
32}
33
34func (m statusCmp) Init() tea.Cmd {
35 return nil
36}
37
38func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
39 switch msg := msg.(type) {
40 case tea.WindowSizeMsg:
41 m.width = msg.Width
42 return m, nil
43
44 // Handle status info
45 case util.InfoMsg:
46 m.info = msg
47 ttl := msg.TTL
48 if ttl == 0 {
49 ttl = m.messageTTL
50 }
51 return m, m.clearMessageCmd(ttl)
52 case util.ClearStatusMsg:
53 m.info = util.InfoMsg{}
54
55 // Handle persistent logs
56 case pubsub.Event[logging.LogMessage]:
57 if msg.Payload.Persist {
58 switch msg.Payload.Level {
59 case "error":
60 m.info = util.InfoMsg{
61 Type: util.InfoTypeError,
62 Msg: msg.Payload.Message,
63 TTL: msg.Payload.PersistTime,
64 }
65 case "info":
66 m.info = util.InfoMsg{
67 Type: util.InfoTypeInfo,
68 Msg: msg.Payload.Message,
69 TTL: msg.Payload.PersistTime,
70 }
71 case "warn":
72 m.info = util.InfoMsg{
73 Type: util.InfoTypeWarn,
74 Msg: msg.Payload.Message,
75 TTL: msg.Payload.PersistTime,
76 }
77 default:
78 m.info = util.InfoMsg{
79 Type: util.InfoTypeInfo,
80 Msg: msg.Payload.Message,
81 TTL: msg.Payload.PersistTime,
82 }
83 }
84 }
85 }
86 return m, nil
87}
88
89func (m statusCmp) View() tea.View {
90 t := styles.CurrentTheme()
91 status := t.S().Base.Padding(0, 1, 1, 1).Render(m.help.View(DefaultKeyMap("focus chat")))
92 if m.info.Msg != "" {
93 switch m.info.Type {
94 case util.InfoTypeError:
95 status = t.S().Base.Background(t.Error).Padding(0, 1).Width(m.width).Render(m.info.Msg)
96 case util.InfoTypeWarn:
97 status = t.S().Base.Background(t.Warning).Padding(0, 1).Width(m.width).Render(m.info.Msg)
98 default:
99 status = t.S().Base.Background(t.Info).Padding(0, 1).Width(m.width).Render(m.info.Msg)
100 }
101 }
102 return tea.NewView(status)
103}
104
105func NewStatusCmp() StatusCmp {
106 t := styles.CurrentTheme()
107 help := help.New()
108 help.Styles = t.S().Help
109 return &statusCmp{
110 messageTTL: 10 * time.Second,
111 help: help,
112 }
113}