status.go 3.2 KB

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