func (s *SpinnerFactory) Start(format ...string) {
	if s.active {
		return
	}
	s.active = true
	s.prepare(format)
	go func() {
		for {
			select {
			case <-s.stopCh:
				return
			default:
				s.lock.Lock()
				fmt.Print("\x0D\x1B[2K")
				color.Printf(s.Format, s.Builder())
				s.lock.Unlock()
				time.Sleep(s.Speed)
			}
		}
	}()
}
Start run spinner
package progress
import (
	"fmt"
	"strings"
	"sync"
	"time"
	"github.com/gookit/color"
)
type BuilderFunc func() string
type SpinnerFactory struct {
	Speed time.Duration
	Format string
	Builder BuilderFunc
	lock *sync.RWMutex
	active bool
	stopCh chan struct{}
}
func Spinner(speed time.Duration) *SpinnerFactory {
	return &SpinnerFactory{
		Speed:  speed,
		Format: "%s",
		lock: &sync.RWMutex{},
		stopCh: make(chan struct{}, 1),
	}
}
func RoundTripLoading(char rune, speed time.Duration, charNumAndBoxWidth ...int) *SpinnerFactory {
	return RoundTripSpinner(char, speed, charNumAndBoxWidth...)
}
func RoundTripSpinner(char rune, speed time.Duration, charNumAndBoxWidth ...int) *SpinnerFactory {
	charNum := 4
	boxWidth := 12
	if ln := len(charNumAndBoxWidth); ln > 0 {
		charNum = charNumAndBoxWidth[0]
		if ln > 1 {
			boxWidth = charNumAndBoxWidth[1]
		}
	}
	return Spinner(speed).WithBuilder(roundTripTextBuilder(char, charNum, boxWidth))
}
func LoadingSpinner(chars []rune, speed time.Duration) *SpinnerFactory {
	return Spinner(speed).WithBuilder(loadingCharBuilder(chars))
}
func (s *SpinnerFactory) WithBuilder(builder BuilderFunc) *SpinnerFactory {
	s.Builder = builder
	return s
}
func (s *SpinnerFactory) prepare(format []string) {
	if s.Builder == nil {
		panic("spinner: field SpinnerFactory.Builder must be setting")
	}
	if len(format) > 0 {
		s.Format = format[0]
	}
	if s.Format != "" && !strings.Contains(s.Format, "%s") {
		s.Format = "%s " + s.Format
	}
	if s.Speed == 0 {
		s.Speed = 100 * time.Millisecond
	}
}