status.go

  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/tui/styles"
  9	"github.com/charmbracelet/crush/internal/tui/util"
 10	"github.com/charmbracelet/x/ansi"
 11)
 12
 13type StatusCmp interface {
 14	util.Model
 15	ToggleFullHelp()
 16	SetKeyMap(keyMap help.KeyMap)
 17}
 18
 19type statusCmp struct {
 20	info       util.InfoMsg
 21	width      int
 22	messageTTL time.Duration
 23	help       help.Model
 24	keyMap     help.KeyMap
 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		m.help.Width = msg.Width - 2
 43		return m, nil
 44
 45	// Handle status info
 46	case util.InfoMsg:
 47		m.info = msg
 48		ttl := msg.TTL
 49		if ttl == 0 {
 50			ttl = m.messageTTL
 51		}
 52		return m, m.clearMessageCmd(ttl)
 53	case util.ClearStatusMsg:
 54		m.info = util.InfoMsg{}
 55	}
 56	return m, nil
 57}
 58
 59func (m *statusCmp) View() string {
 60	t := styles.CurrentTheme()
 61	status := t.S().Base.Padding(0, 1, 1, 1).Render(m.help.View(m.keyMap))
 62	if m.info.Msg != "" {
 63		status = m.infoMsg()
 64	}
 65	return status
 66}
 67
 68func (m *statusCmp) infoMsg() string {
 69	t := styles.CurrentTheme()
 70	message := ""
 71	infoType := ""
 72	switch m.info.Type {
 73	case util.InfoTypeError:
 74		infoType = t.S().Base.Background(t.Red).Padding(0, 1).Render("ERROR")
 75		message = t.S().Base.Background(t.Error).Foreground(t.White).Padding(0, 1).Render(m.info.Msg)
 76	case util.InfoTypeWarn:
 77		infoType = t.S().Base.Foreground(t.BgOverlay).Background(t.Yellow).Padding(0, 1).Render("WARNING")
 78		message = t.S().Base.Foreground(t.BgOverlay).Background(t.Warning).Padding(0, 1).Render(m.info.Msg)
 79	default:
 80		infoType = t.S().Base.Foreground(t.BgOverlay).Background(t.Green).Padding(0, 1).Render("OKAY!")
 81		message = t.S().Base.Background(t.Success).Foreground(t.White).Padding(0, 1).Render(m.info.Msg)
 82	}
 83	return ansi.Truncate(infoType+message, m.width, "…")
 84}
 85
 86func (m *statusCmp) ToggleFullHelp() {
 87	m.help.ShowAll = !m.help.ShowAll
 88}
 89
 90func (m *statusCmp) SetKeyMap(keyMap help.KeyMap) {
 91	m.keyMap = keyMap
 92}
 93
 94func NewStatusCmp() StatusCmp {
 95	t := styles.CurrentTheme()
 96	help := help.New()
 97	help.Styles = t.S().Help
 98	return &statusCmp{
 99		messageTTL: 5 * time.Second,
100		help:       help,
101	}
102}