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