diff --git a/_examples/spinnerDecorator/main.go b/_examples/spinnerDecorator/main.go new file mode 100644 index 0000000..0b67239 --- /dev/null +++ b/_examples/spinnerDecorator/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "math/rand" + "sync" + "time" + + "github.com/vbauerster/mpb/v4" + "github.com/vbauerster/mpb/v4/decor" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + var wg sync.WaitGroup + // pass &wg (optional), so p will wait for it eventually + p := mpb.New(mpb.WithWaitGroup(&wg), mpb.WithWidth(64)) + total, numBars := 100, 3 + wg.Add(numBars) + + for i := 0; i < numBars; i++ { + name := fmt.Sprintf("Bar#%d:", i) + bar := p.AddBar(int64(total), + mpb.PrependDecorators( + // simple name decorator + decor.Name(name), + decor.OnComplete( + // spinner decorator with default style + decor.Spinner(nil, decor.WCSyncSpace), "done", + ), + ), + mpb.AppendDecorators( + // decor.DSyncWidth bit enables column width synchronization + decor.Percentage(decor.WCSyncWidth), + ), + ) + // simulating some work + go func() { + defer wg.Done() + max := 100 * time.Millisecond + for i := 0; i < total; i++ { + start := time.Now() + time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) + // ewma based decorators require work duration measurement + bar.IncrBy(1, time.Since(start)) + } + }() + } + // Waiting for passed &wg and for all bars to complete and flush + p.Wait() +} diff --git a/decor/spinner.go b/decor/spinner.go new file mode 100644 index 0000000..1eff1a0 --- /dev/null +++ b/decor/spinner.go @@ -0,0 +1,42 @@ +package decor + +var defaultSpinnerStyle = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} + +// Spinner returns spinner decorator. +// +// `frames` spinner frames, if nil or len==0, default is used +// +// `wcc` optional WC config +func Spinner(frames []string, wcc ...WC) Decorator { + var wc WC + for _, widthConf := range wcc { + wc = widthConf + } + wc.Init() + if len(frames) == 0 { + frames = defaultSpinnerStyle + } + d := &spinnerDecorator{ + WC: wc, + frames: frames, + } + return d +} + +type spinnerDecorator struct { + WC + frames []string + complete *string +} + +func (d *spinnerDecorator) Decor(st *Statistics) string { + if st.Completed && d.complete != nil { + return d.FormatMsg(*d.complete) + } + frame := d.frames[st.Current%int64(len(d.frames))] + return d.FormatMsg(frame) +} + +func (d *spinnerDecorator) OnCompleteMessage(msg string) { + d.complete = &msg +}