status.go

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