|
package progress |
|
|
|
import ( |
|
"fmt" |
|
"strings" |
|
"time" |
|
) |
|
|
|
type Spinner struct { |
|
message string |
|
messageWidth int |
|
|
|
parts []string |
|
|
|
value int |
|
|
|
ticker *time.Ticker |
|
started time.Time |
|
stopped time.Time |
|
} |
|
|
|
func NewSpinner(message string) *Spinner { |
|
s := &Spinner{ |
|
message: message, |
|
parts: []string{ |
|
"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", |
|
}, |
|
started: time.Now(), |
|
} |
|
go s.start() |
|
return s |
|
} |
|
|
|
func (s *Spinner) String() string { |
|
var sb strings.Builder |
|
if len(s.message) > 0 { |
|
message := strings.TrimSpace(s.message) |
|
if s.messageWidth > 0 && len(message) > s.messageWidth { |
|
message = message[:s.messageWidth] |
|
} |
|
|
|
fmt.Fprintf(&sb, "%s", message) |
|
if padding := s.messageWidth - sb.Len(); padding > 0 { |
|
sb.WriteString(strings.Repeat(" ", padding)) |
|
} |
|
|
|
sb.WriteString(" ") |
|
} |
|
|
|
if s.stopped.IsZero() { |
|
spinner := s.parts[s.value] |
|
sb.WriteString(spinner) |
|
sb.WriteString(" ") |
|
} |
|
|
|
return sb.String() |
|
} |
|
|
|
func (s *Spinner) start() { |
|
s.ticker = time.NewTicker(100 * time.Millisecond) |
|
for range s.ticker.C { |
|
s.value = (s.value + 1) % len(s.parts) |
|
if !s.stopped.IsZero() { |
|
return |
|
} |
|
} |
|
} |
|
|
|
func (s *Spinner) Stop() { |
|
if s.stopped.IsZero() { |
|
s.stopped = time.Now() |
|
} |
|
} |
|
|