diff --git a/bar.go b/bar.go index 3499aab..9b0de15 100644 --- a/bar.go +++ b/bar.go @@ -51,32 +51,34 @@ etaAlpha float64 total int64 current int64 + dropRatio int64 trimLeftSpace bool trimRightSpace bool completed bool aborted bool + dynamic bool startTime time.Time timeElapsed time.Duration blockStartTime time.Time timePerItem time.Duration appendFuncs []decor.DecoratorFunc prependFuncs []decor.DecoratorFunc - simpleSpinner func() byte refill *refill bufP, bufB, bufA *bytes.Buffer } ) func newBar(ID int, total int64, wg *sync.WaitGroup, cancel <-chan struct{}, options ...BarOption) *Bar { + if total <= 0 { + total = time.Now().Unix() + } + s := state{ - id: ID, - total: total, - etaAlpha: etaAlpha, - } - - // if total <= 0 { - // s.simpleSpinner = getSpinner() - // } + id: ID, + total: total, + etaAlpha: etaAlpha, + dropRatio: 10, + } for _, opt := range options { opt(&s) @@ -103,7 +105,6 @@ s.prependFuncs = nil }: case <-b.quit: - return } } @@ -114,7 +115,6 @@ s.appendFuncs = nil }: case <-b.quit: - return } } @@ -143,15 +143,18 @@ s.timeElapsed = time.Since(s.startTime) s.updateTimePerItemEstimate(n) if s.total > 0 && sum >= s.total { - s.current = s.total - s.completed = true + if s.dynamic { + sum -= sum * s.dropRatio / 100 + } else { + s.current = s.total + s.completed = true + } return } s.current = sum s.blockStartTime = time.Now() }: case <-b.quit: - return } } @@ -166,7 +169,6 @@ s.refill = &refill{r, till} }: case <-b.quit: - return } } @@ -218,6 +220,19 @@ return <-result case <-b.done: return b.cacheState.total + } +} + +// SetTotal sets total dynamically. The final param indicates the very last set, +// in other words you should set it to true when total is determined. +// Also you may consider providing your drop ratio via BarDropRatio BarOption func. +func (b *Bar) SetTotal(total int64, final bool) { + select { + case b.ops <- func(s *state) { + s.total = total + s.dynamic = !final + }: + case <-b.quit: } } @@ -311,13 +326,6 @@ return ch } -func (s *state) updateFormat(format string) { - for i, n := 0, 0; len(format) > 0; i++ { - s.format[i], n = utf8.DecodeRuneInString(format) - format = format[n:] - } -} - func (s *state) updateTimePerItemEstimate(amount int) { lastBlockTime := time.Since(s.blockStartTime) // shorthand for time.Now().Sub(t) lastItemEstimate := float64(lastBlockTime) / float64(amount) @@ -402,13 +410,6 @@ } s.bufB.WriteRune(s.format[rRight]) -} - -func concatenateBlocks(buf []byte, blocks ...[]byte) []byte { - for _, block := range blocks { - buf = append(buf, block...) - } - return buf } func newStatistics(s *state) *decor.Statistics { @@ -424,15 +425,16 @@ } } -func getSpinner() func() byte { - chars := []byte(`-\|/`) - repeat := len(chars) - 1 - index := repeat - return func() byte { - if index == repeat { - index = -1 - } - index++ - return chars[index] - } -} +func concatenateBlocks(buf []byte, blocks ...[]byte) []byte { + for _, block := range blocks { + buf = append(buf, block...) + } + return buf +} + +func (s *state) updateFormat(format string) { + for i, n := 0, 0; len(format) > 0; i++ { + s.format[i], n = utf8.DecodeRuneInString(format) + format = format[n:] + } +} diff --git a/bar_option.go b/bar_option.go index 416168a..b5b8eff 100644 --- a/bar_option.go +++ b/bar_option.go @@ -6,30 +6,35 @@ // if passed to p.AddBar(int64, ...BarOption) type BarOption func(*state) +// AppendDecorators let you inject decorators to the bar's right side func AppendDecorators(appenders ...decor.DecoratorFunc) BarOption { return func(bs *state) { bs.appendFuncs = append(bs.appendFuncs, appenders...) } } +// PrependDecorators let you inject decorators to the bar's left side func PrependDecorators(prependers ...decor.DecoratorFunc) BarOption { return func(bs *state) { bs.prependFuncs = append(bs.prependFuncs, prependers...) } } +// BarTrimLeft trims left side space of the bar func BarTrimLeft() BarOption { return func(bs *state) { bs.trimLeftSpace = true } } +// BarTrimRight trims right space of the bar func BarTrimRight() BarOption { return func(bs *state) { bs.trimRightSpace = true } } +// BarTirm trims both left and right spaces of the bar func BarTrim() BarOption { return func(bs *state) { bs.trimLeftSpace = true @@ -37,6 +42,7 @@ } } +// BarID overwrites internal bar id func BarID(id int) BarOption { return func(bs *state) { bs.id = id @@ -52,6 +58,15 @@ } } +// BarDropRatio sets drop ratio, default is 10. Effective when total is dynamic. +// If progress tip reaches total, but total is not final value yet, tip will be +// dropped by specified ratio. +func BarDropRatio(ratio int64) BarOption { + return func(bs *state) { + bs.dropRatio = ratio + } +} + func barWidth(w int) BarOption { return func(bs *state) { bs.width = w