status.go

  1package model
  2
  3import (
  4	"strings"
  5	"time"
  6
  7	"charm.land/bubbles/v2/help"
  8	tea "charm.land/bubbletea/v2"
  9	"charm.land/lipgloss/v2"
 10	"github.com/charmbracelet/crush/internal/ui/common"
 11	"github.com/charmbracelet/crush/internal/ui/util"
 12	uv "github.com/charmbracelet/ultraviolet"
 13	"github.com/charmbracelet/x/ansi"
 14)
 15
 16// DefaultStatusTTL is the default time-to-live for status messages.
 17const DefaultStatusTTL = 5 * time.Second
 18
 19// Status is the status bar and help model.
 20type Status struct {
 21	com      *common.Common
 22	hideHelp bool
 23	help     help.Model
 24	helpKm   help.KeyMap
 25	msg      util.InfoMsg
 26}
 27
 28// NewStatus creates a new status bar and help model.
 29func NewStatus(com *common.Common, km help.KeyMap) *Status {
 30	s := new(Status)
 31	s.com = com
 32	s.help = help.New()
 33	s.help.Styles = com.Styles.Help
 34	s.helpKm = km
 35	return s
 36}
 37
 38// SetInfoMsg sets the status info message.
 39func (s *Status) SetInfoMsg(msg util.InfoMsg) {
 40	s.msg = msg
 41}
 42
 43// ClearInfoMsg clears the status info message.
 44func (s *Status) ClearInfoMsg() {
 45	s.msg = util.InfoMsg{}
 46}
 47
 48// SetWidth sets the width of the status bar and help view.
 49func (s *Status) SetWidth(width int) {
 50	helpStyle := s.com.Styles.Status.Help
 51	horizontalPadding := helpStyle.GetPaddingLeft() + helpStyle.GetPaddingRight()
 52	s.help.SetWidth(width - horizontalPadding)
 53}
 54
 55// ShowingAll returns whether the full help view is shown.
 56func (s *Status) ShowingAll() bool {
 57	return s.help.ShowAll
 58}
 59
 60// ToggleHelp toggles the full help view.
 61func (s *Status) ToggleHelp() {
 62	s.help.ShowAll = !s.help.ShowAll
 63}
 64
 65// SetHideHelp sets whether the app is on the onboarding flow.
 66func (s *Status) SetHideHelp(hideHelp bool) {
 67	s.hideHelp = hideHelp
 68}
 69
 70// Draw draws the status bar onto the screen.
 71func (s *Status) Draw(scr uv.Screen, area uv.Rectangle) {
 72	if !s.hideHelp {
 73		helpView := s.com.Styles.Status.Help.Render(s.help.View(s.helpKm))
 74		uv.NewStyledString(helpView).Draw(scr, area)
 75	}
 76
 77	// Render notifications
 78	if s.msg.IsEmpty() {
 79		return
 80	}
 81
 82	var indStyle lipgloss.Style
 83	var msgStyle lipgloss.Style
 84	switch s.msg.Type {
 85	case util.InfoTypeError:
 86		indStyle = s.com.Styles.Status.ErrorIndicator
 87		msgStyle = s.com.Styles.Status.ErrorMessage
 88	case util.InfoTypeWarn:
 89		indStyle = s.com.Styles.Status.WarnIndicator
 90		msgStyle = s.com.Styles.Status.WarnMessage
 91	case util.InfoTypeUpdate:
 92		indStyle = s.com.Styles.Status.UpdateIndicator
 93		msgStyle = s.com.Styles.Status.UpdateMessage
 94	case util.InfoTypeInfo:
 95		indStyle = s.com.Styles.Status.InfoIndicator
 96		msgStyle = s.com.Styles.Status.InfoMessage
 97	case util.InfoTypeSuccess:
 98		indStyle = s.com.Styles.Status.SuccessIndicator
 99		msgStyle = s.com.Styles.Status.SuccessMessage
100	}
101
102	ind := indStyle.String()
103	indWidth := lipgloss.Width(ind)
104	msg := strings.Join(strings.Split(s.msg.Msg, "\n"), " ")
105	msgWidth := lipgloss.Width(msg)
106	msg = ansi.Truncate(msg, area.Dx()-indWidth-msgWidth, "…")
107	padWidth := max(0, area.Dx()-indWidth-msgWidth)
108	msg += strings.Repeat(" ", padWidth)
109	info := msgStyle.Render(msg)
110
111	// Draw the info message over the help view
112	uv.NewStyledString(ind+info).Draw(scr, area)
113}
114
115// clearInfoMsgCmd returns a command that clears the info message after the
116// given TTL.
117func clearInfoMsgCmd(ttl time.Duration) tea.Cmd {
118	return tea.Tick(ttl, func(time.Time) tea.Msg {
119		return util.ClearStatusMsg{}
120	})
121}