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/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}