Update vendor

This commit is contained in:
Ettore Di Giacinto
2021-02-17 10:46:13 +01:00
parent b3e3abec8f
commit 49d7efa9ea
5 changed files with 138 additions and 113 deletions

View File

@@ -14,13 +14,13 @@
package spinner
import (
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
"unicode/utf8"
@@ -161,7 +161,7 @@ var colorAttributeMap = map[string]color.Attribute{
"bgHiWhite": color.BgHiWhite,
}
// validColor will make sure the given color is actually allowed
// validColor will make sure the given color is actually allowed.
func validColor(c string) bool {
if validColors[c] {
return true
@@ -169,8 +169,9 @@ func validColor(c string) bool {
return false
}
// Spinner struct to hold the provided options
// Spinner struct to hold the provided options.
type Spinner struct {
mu *sync.RWMutex //
Delay time.Duration // Delay is the speed of the indicator
chars []string // chars holds the chosen character set
Prefix string // Prefix is the text preppended to the indicator
@@ -178,20 +179,21 @@ type Spinner struct {
FinalMSG string // string displayed after Stop() is called
lastOutput string // last character(set) written
color func(a ...interface{}) string // default color is white
lock *sync.RWMutex //
Writer io.Writer // to make testing better, exported so users have access
Writer io.Writer // to make testing better, exported so users have access. Use `WithWriter` to update after initialization.
active bool // active holds the state of the spinner
stopChan chan struct{} // stopChan is a channel used to stop the indicator
HideCursor bool // hideCursor determines if the cursor is visible
PreUpdate func(s *Spinner) // will be triggered before every spinner update
PostUpdate func(s *Spinner) // will be triggered after every spinner update
}
// New provides a pointer to an instance of Spinner with the supplied options
// New provides a pointer to an instance of Spinner with the supplied options.
func New(cs []string, d time.Duration, options ...Option) *Spinner {
s := &Spinner{
Delay: d,
chars: cs,
color: color.New(color.FgWhite).SprintFunc(),
lock: &sync.RWMutex{},
mu: &sync.RWMutex{},
Writer: color.Output,
active: false,
stopChan: make(chan struct{}, 1),
@@ -204,10 +206,10 @@ func New(cs []string, d time.Duration, options ...Option) *Spinner {
}
// Option is a function that takes a spinner and applies
// a given configuration
// a given configuration.
type Option func(*Spinner)
// Options contains fields to configure the spinner
// Options contains fields to configure the spinner.
type Options struct {
Color string
Suffix string
@@ -215,7 +217,7 @@ type Options struct {
HideCursor bool
}
// WithColor adds the given color to the spinner
// WithColor adds the given color to the spinner.
func WithColor(color string) Option {
return func(s *Spinner) {
s.Color(color)
@@ -223,7 +225,7 @@ func WithColor(color string) Option {
}
// WithSuffix adds the given string to the spinner
// as the suffix
// as the suffix.
func WithSuffix(suffix string) Option {
return func(s *Spinner) {
s.Suffix = suffix
@@ -231,7 +233,7 @@ func WithSuffix(suffix string) Option {
}
// WithFinalMSG adds the given string ot the spinner
// as the final message to be written
// as the final message to be written.
func WithFinalMSG(finalMsg string) Option {
return func(s *Spinner) {
s.FinalMSG = finalMsg
@@ -239,31 +241,42 @@ func WithFinalMSG(finalMsg string) Option {
}
// WithHiddenCursor hides the cursor
// if hideCursor = true given
// if hideCursor = true given.
func WithHiddenCursor(hideCursor bool) Option {
return func(s *Spinner) {
s.HideCursor = hideCursor
}
}
// Active will return whether or not the spinner is currently active
// WithWriter adds the given writer to the spinner. This
// function should be favored over directly assigning to
// the struct value.
func WithWriter(w io.Writer) Option {
return func(s *Spinner) {
s.mu.Lock()
s.Writer = w
s.mu.Unlock()
}
}
// Active will return whether or not the spinner is currently active.
func (s *Spinner) Active() bool {
return s.active
}
// Start will start the indicator
// Start will start the indicator.
func (s *Spinner) Start() {
s.lock.Lock()
s.mu.Lock()
if s.active {
s.lock.Unlock()
s.mu.Unlock()
return
}
if s.HideCursor && runtime.GOOS != "windows" {
// hides the cursor
fmt.Print("\033[?25l")
fmt.Fprint(s.Writer, "\033[?25l")
}
s.active = true
s.lock.Unlock()
s.mu.Unlock()
go func() {
for {
@@ -272,8 +285,17 @@ func (s *Spinner) Start() {
case <-s.stopChan:
return
default:
s.lock.Lock()
s.mu.Lock()
if !s.active {
s.mu.Unlock()
return
}
s.erase()
if s.PreUpdate != nil {
s.PreUpdate(s)
}
var outColor string
if runtime.GOOS == "windows" {
if s.Writer == os.Stderr {
@@ -282,14 +304,18 @@ func (s *Spinner) Start() {
outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
}
} else {
outColor = fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
}
outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
outPlain := fmt.Sprintf("\r%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
fmt.Fprint(s.Writer, outColor)
s.lastOutput = outPlain
delay := s.Delay
s.lock.Unlock()
if s.PostUpdate != nil {
s.PostUpdate(s)
}
s.mu.Unlock()
time.Sleep(delay)
}
}
@@ -297,40 +323,41 @@ func (s *Spinner) Start() {
}()
}
// Stop stops the indicator
// Stop stops the indicator.
func (s *Spinner) Stop() {
s.lock.Lock()
defer s.lock.Unlock()
s.mu.Lock()
defer s.mu.Unlock()
if s.active {
s.active = false
if s.HideCursor && runtime.GOOS != "windows" {
// makes the cursor visible
fmt.Print("\033[?25h")
fmt.Fprint(s.Writer, "\033[?25h")
}
s.erase()
if s.FinalMSG != "" {
fmt.Fprintf(s.Writer, s.FinalMSG)
fmt.Fprint(s.Writer, s.FinalMSG)
}
s.stopChan <- struct{}{}
}
}
// Restart will stop and start the indicator
// Restart will stop and start the indicator.
func (s *Spinner) Restart() {
s.Stop()
s.Start()
}
// Reverse will reverse the order of the slice assigned to the indicator
// Reverse will reverse the order of the slice assigned to the indicator.
func (s *Spinner) Reverse() {
s.lock.Lock()
defer s.lock.Unlock()
s.mu.Lock()
defer s.mu.Unlock()
for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
}
}
// Color will set the struct field for the given color to be used
// Color will set the struct field for the given color to be used. The spinner
// will need to be explicitly restarted.
func (s *Spinner) Color(colors ...string) error {
colorAttributes := make([]color.Attribute, len(colors))
@@ -342,63 +369,55 @@ func (s *Spinner) Color(colors ...string) error {
colorAttributes[index] = colorAttributeMap[c]
}
s.lock.Lock()
s.mu.Lock()
s.color = color.New(colorAttributes...).SprintFunc()
s.lock.Unlock()
s.Restart()
s.mu.Unlock()
return nil
}
// UpdateSpeed will set the indicator delay to the given value
// UpdateSpeed will set the indicator delay to the given value.
func (s *Spinner) UpdateSpeed(d time.Duration) {
s.lock.Lock()
defer s.lock.Unlock()
s.mu.Lock()
defer s.mu.Unlock()
s.Delay = d
}
// UpdateCharSet will change the current character set to the given one
// UpdateCharSet will change the current character set to the given one.
func (s *Spinner) UpdateCharSet(cs []string) {
s.lock.Lock()
defer s.lock.Unlock()
s.mu.Lock()
defer s.mu.Unlock()
s.chars = cs
}
// erase deletes written characters
//
// erase deletes written characters.
// Caller must already hold s.lock.
func (s *Spinner) erase() {
n := utf8.RuneCountInString(s.lastOutput)
if runtime.GOOS == "windows" {
var clearString string
for i := 0; i < n; i++ {
clearString += " "
}
clearString += "\r"
fmt.Fprintf(s.Writer, clearString)
clearString := "\r" + strings.Repeat(" ", n) + "\r"
fmt.Fprint(s.Writer, clearString)
s.lastOutput = ""
return
}
del, _ := hex.DecodeString("7f")
for _, c := range []string{"\b", string(del), "\b", "\033[K"} { // "\033[K" for macOS Terminal
for i := 0; i < n; i++ {
fmt.Fprintf(s.Writer, c)
}
for _, c := range []string{"\b", "\127", "\b", "\033[K"} { // "\033[K" for macOS Terminal
fmt.Fprint(s.Writer, strings.Repeat(c, n))
}
fmt.Fprintf(s.Writer, "\r\033[K") // erases to end of line
s.lastOutput = ""
}
// Lock allows for manual control to lock the spinner
// Lock allows for manual control to lock the spinner.
func (s *Spinner) Lock() {
s.lock.Lock()
s.mu.Lock()
}
// Unlock allows for manual control to unlock the spinner
// Unlock allows for manual control to unlock the spinner.
func (s *Spinner) Unlock() {
s.lock.Unlock()
s.mu.Unlock()
}
// GenerateNumberSequence will generate a slice of integers at the
// provided length and convert them each to a string
// provided length and convert them each to a string.
func GenerateNumberSequence(length int) []string {
numSeq := make([]string, length)
for i := 0; i < length; i++ {