internal/pkg/term/progress/spinner.go (66 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package progress
import (
"fmt"
"io"
"os"
"time"
"github.com/briandowns/spinner"
)
// Events display settings.
const (
minCellWidth = 20 // minimum number of characters in a table's cell.
tabWidth = 4 // number of characters in between columns.
cellPaddingWidth = 2 // number of padding characters added by default to a cell.
paddingChar = ' ' // character in between columns.
noAdditionalFormatting = 0
maxCellLength = 70 // Number of characters we want to display at most in a cell before wrapping it to the next line.
)
// startStopper is the interface to interact with the spinner.
type startStopper interface {
Start()
Stop()
}
// Spinner represents an indicator that an asynchronous operation is taking place.
//
// For short operations, less than 4 seconds, display only the spinner with the Start and Stop methods.
// For longer operations, display intermediate progress events using the Events method.
type Spinner struct {
spin startStopper
}
// NewSpinner returns a spinner that outputs to w.
func NewSpinner(w io.Writer) *Spinner {
interval := 125 * time.Millisecond
if os.Getenv("CI") == "true" {
interval = 30 * time.Second
}
s := spinner.New(charset, interval, spinner.WithHiddenCursor(true))
s.Writer = w
return &Spinner{
spin: s,
}
}
// Start starts the spinner suffixed with a label.
func (s *Spinner) Start(label string) {
s.suffix(fmt.Sprintf(" %s", label))
s.spin.Start()
}
// Stop stops the spinner and replaces it with a label.
func (s *Spinner) Stop(label string) {
s.finalMSG(fmt.Sprint(label))
s.spin.Stop()
}
func (s *Spinner) lock() {
if spinner, ok := s.spin.(*spinner.Spinner); ok {
spinner.Lock()
}
}
func (s *Spinner) unlock() {
if spinner, ok := s.spin.(*spinner.Spinner); ok {
spinner.Unlock()
}
}
func (s *Spinner) suffix(label string) {
s.lock()
defer s.unlock()
if spinner, ok := s.spin.(*spinner.Spinner); ok {
spinner.Suffix = label
}
}
func (s *Spinner) finalMSG(label string) {
s.lock()
defer s.unlock()
if spinner, ok := s.spin.(*spinner.Spinner); ok {
spinner.FinalMSG = label
}
}