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