Skip to content

Commit

Permalink
feat: make progressbar could update according to an interval or updat…
Browse files Browse the repository at this point in the history
…e each time render was called.
  • Loading branch information
chengxilo committed Sep 18, 2024
1 parent d773ff3 commit 5ad50c6
Showing 1 changed file with 60 additions and 11 deletions.
71 changes: 60 additions & 11 deletions progressbar.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type state struct {
counterTime time.Time
counterNumSinceLast int64
counterLastTenRates []float64
spinnerIdx int // the index of spinner

maxLineWidth int
currentBytes float64
Expand Down Expand Up @@ -105,6 +106,11 @@ type config struct {
// spinnerTypeOptionUsed remembers if the spinnerType was changed manually
spinnerTypeOptionUsed bool

// spinnerChangeInterval the change interval of spinner
// if set this attribute to 0, the spinner only change when renderProgressBar was called
// for example, each time when Add() was called,which will call renderProgressBar function
spinnerChangeInterval time.Duration

// spinner represents the spinner as a slice of string
spinner []string

Expand Down Expand Up @@ -151,6 +157,18 @@ func OptionSetWidth(s int) Option {
}
}

// OptionSetSpinnerChangeInterval sets the spinner change interval
// the spinner will change according to this value.
// By default, this value is 100 * time.Millisecond
// If you don't want to let this progressbar update by specified time interval
// you can set this value to zero, then the spinner will change each time rendered,
// such as when Add() or Describe() was called
func OptionSetSpinnerChangeInterval(interval time.Duration) Option {
return func(p *ProgressBar) {
p.config.spinnerChangeInterval = interval
}
}

// OptionSpinnerType sets the type of spinner used for indeterminate bars
func OptionSpinnerType(spinnerType int) Option {
return func(p *ProgressBar) {
Expand Down Expand Up @@ -337,16 +355,17 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
counterTime: time.Time{},
},
config: config{
writer: os.Stdout,
theme: defaultTheme,
iterationString: "it",
width: 40,
max: max,
throttleDuration: 0 * time.Nanosecond,
elapsedTime: max == -1,
predictTime: true,
spinnerType: 9,
invisible: false,
writer: os.Stdout,
theme: defaultTheme,
iterationString: "it",
width: 40,
max: max,
throttleDuration: 0 * time.Nanosecond,
elapsedTime: max == -1,
predictTime: true,
spinnerType: 9,
invisible: false,
spinnerChangeInterval: 100 * time.Millisecond,
},
}

Expand Down Expand Up @@ -374,6 +393,27 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
b.RenderBlank()
}

// if the render time interval attribute is set
if b.config.spinnerChangeInterval != 0 {
go func() {
ticker := time.NewTicker(b.config.spinnerChangeInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if b.IsFinished() {
return
}
if b.IsStarted() {
b.lock.Lock()
b.render()
b.lock.Unlock()
}
}
}
}()
}

return &b
}

Expand Down Expand Up @@ -1058,7 +1098,16 @@ func renderProgressBar(c config, s *state) (int, error) {
if len(c.spinner) > 0 {
selectedSpinner = c.spinner
}
spinner := selectedSpinner[int(math.Round(math.Mod(float64(time.Since(s.startTime).Milliseconds()/100), float64(len(selectedSpinner)))))]

var spinner string
if c.spinnerChangeInterval != 0 {
// if the spinner is changed according to an interval, calculate it
spinner = selectedSpinner[int(math.Round(math.Mod(float64(time.Since(s.startTime).Nanoseconds()/c.spinnerChangeInterval.Nanoseconds()), float64(len(selectedSpinner)))))]
} else {
// if the spinner is changed according to the number render was called
spinner = selectedSpinner[s.spinnerIdx]
s.spinnerIdx = (s.spinnerIdx + 1) % len(selectedSpinner)
}
if c.elapsedTime {
if c.showDescriptionAtLineEnd {
str = fmt.Sprintf("\r%s %s [%s] %s ",
Expand Down

0 comments on commit 5ad50c6

Please sign in to comment.