spinner.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package progress
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. type Spinner struct {
  8. message string
  9. messageWidth int
  10. parts []string
  11. value int
  12. ticker *time.Ticker
  13. started time.Time
  14. stopped time.Time
  15. }
  16. func NewSpinner(message string) *Spinner {
  17. s := &Spinner{
  18. message: message,
  19. parts: []string{
  20. "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏",
  21. },
  22. started: time.Now(),
  23. }
  24. go s.start()
  25. return s
  26. }
  27. func (s *Spinner) String() string {
  28. var sb strings.Builder
  29. if len(s.message) > 0 {
  30. message := strings.TrimSpace(s.message)
  31. if s.messageWidth > 0 && len(message) > s.messageWidth {
  32. message = message[:s.messageWidth]
  33. }
  34. fmt.Fprintf(&sb, "%s", message)
  35. if padding := s.messageWidth - sb.Len(); padding > 0 {
  36. sb.WriteString(strings.Repeat(" ", padding))
  37. }
  38. sb.WriteString(" ")
  39. }
  40. if s.stopped.IsZero() {
  41. spinner := s.parts[s.value]
  42. sb.WriteString(spinner)
  43. sb.WriteString(" ")
  44. }
  45. return sb.String()
  46. }
  47. func (s *Spinner) start() {
  48. s.ticker = time.NewTicker(100 * time.Millisecond)
  49. for range s.ticker.C {
  50. s.value = (s.value + 1) % len(s.parts)
  51. if !s.stopped.IsZero() {
  52. return
  53. }
  54. }
  55. }
  56. func (s *Spinner) Stop() {
  57. if s.stopped.IsZero() {
  58. s.stopped = time.Now()
  59. }
  60. }