Codebase list golang-github-vbauerster-mpb / 6442607
BarReverse option Vladimir Bauer 7 years ago
3 changed file(s) with 142 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
0 package main
1
2 import (
3 "fmt"
4 "math/rand"
5 "sync"
6 "time"
7
8 "github.com/vbauerster/mpb/v4"
9 "github.com/vbauerster/mpb/v4/decor"
10 )
11
12 func init() {
13 rand.Seed(time.Now().UnixNano())
14 }
15
16 func main() {
17 var wg sync.WaitGroup
18 // pass &wg (optional), so p will wait for it eventually
19 p := mpb.New(mpb.WithWaitGroup(&wg))
20 total, numBars := 100, 3
21 wg.Add(numBars)
22
23 for i := 0; i < numBars; i++ {
24 name := fmt.Sprintf("Bar#%d:", i)
25 bar := p.AddBar(int64(total),
26 // reverse Bar#1
27 mpb.BarOptOnCond(mpb.BarReverse(), func() bool { return i == 1 }),
28 mpb.PrependDecorators(
29 // simple name decorator
30 decor.Name(name),
31 // decor.DSyncWidth bit enables column width synchronization
32 decor.Percentage(decor.WCSyncSpace),
33 ),
34 mpb.AppendDecorators(
35 // replace ETA decorator with "done" message, OnComplete event
36 decor.OnComplete(
37 // ETA decorator with ewma age of 60
38 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done",
39 ),
40 ),
41 )
42 // simulating some work
43 go func() {
44 defer wg.Done()
45 max := 100 * time.Millisecond
46 for i := 0; i < total; i++ {
47 start := time.Now()
48 time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
49 // ewma based decorators require work duration measurement
50 bar.IncrBy(1, time.Since(start))
51 }
52 }()
53 }
54 // Waiting for passed &wg and for all bars to complete and flush
55 p.Wait()
56 }
00 package mpb
11
22 import (
3 "bytes"
43 "io"
54 "unicode/utf8"
65
1413 rTip
1514 rEmpty
1615 rRight
16 rRevTip
1717 rRefill
1818 )
1919
20 var defaultBarStyle = "[=>-]+"
20 var defaultBarStyle = "[=>-]<+"
2121
2222 type barFiller struct {
23 format [][]byte
24 rup int
23 format [][]byte
24 refillCount int
25 reverse bool
2526 }
2627
2728 func newDefaultBarFiller() Filler {
3435
3536 func (s *barFiller) setStyle(style string) {
3637 if !utf8.ValidString(style) {
37 style = defaultBarStyle
38 return
3839 }
3940 src := make([][]byte, 0, utf8.RuneCountInString(style))
4041 for _, r := range style {
4344 copy(s.format, src)
4445 }
4546
47 func (s *barFiller) setReverse() {
48 s.reverse = true
49 }
50
4651 func (s *barFiller) Fill(w io.Writer, width int, stat *decor.Statistics) {
47
48 b := s.format[rLeft]
4952
5053 // don't count rLeft and rRight [brackets]
5154 width -= 2
52
5355 if width < 2 {
54 return
55 } else if width == 2 {
56 w.Write(append(b, s.format[rRight]...))
5756 return
5857 }
5958
60 cwidth := internal.Percentage(stat.Total, stat.Current, int64(width))
61
62 if s.rup > 0 {
63 rwidth := internal.Percentage(stat.Total, int64(s.rup), int64(width))
64 b = append(b, bytes.Repeat(s.format[rRefill], int(rwidth))...)
65 rest := cwidth - rwidth
66 b = append(b, bytes.Repeat(s.format[rFill], int(rest))...)
67 } else {
68 b = append(b, bytes.Repeat(s.format[rFill], int(cwidth))...)
59 w.Write(s.format[rLeft])
60 if width == 2 {
61 w.Write(s.format[rRight])
62 return
6963 }
7064
71 if cwidth < int64(width) && cwidth > 0 {
72 _, size := utf8.DecodeLastRune(b)
73 b = append(b[:len(b)-size], s.format[rTip]...)
65 bb := make([][]byte, width)
66
67 cwidth := int(internal.Percentage(stat.Total, stat.Current, int64(width)))
68
69 for i := 0; i < cwidth; i++ {
70 bb[i] = s.format[rFill]
7471 }
7572
76 rest := int64(width) - cwidth
77 b = append(b, bytes.Repeat(s.format[rEmpty], int(rest))...)
78 w.Write(append(b, s.format[rRight]...))
73 if s.refillCount > 0 {
74 var rwidth int
75 if s.refillCount > cwidth {
76 rwidth = cwidth
77 } else {
78 rwidth = int(internal.Percentage(stat.Total, int64(s.refillCount), int64(width)))
79 }
80 for i := 0; i < rwidth; i++ {
81 bb[i] = s.format[rRefill]
82 }
83 }
84
85 if cwidth < width && cwidth > 0 {
86 if s.reverse {
87 bb[cwidth-1] = s.format[rRevTip]
88 } else {
89 bb[cwidth-1] = s.format[rTip]
90 }
91 }
92
93 for i := cwidth; i < width; i++ {
94 bb[i] = s.format[rEmpty]
95 }
96
97 if s.reverse {
98 for i, j := 0, len(bb)-1; i < j; i, j = i+1, j-1 {
99 bb[i], bb[j] = bb[j], bb[i]
100 }
101 }
102
103 for i := 0; i < width; i++ {
104 w.Write(bb[i])
105 }
106 w.Write(s.format[rRight])
79107 }
80108
81 func (s *barFiller) SetRefill(upto int) {
82 s.rup = upto
109 func (s *barFiller) SetRefill(count int) {
110 s.refillCount = count
83111 }
102102 }
103103 }
104104
105 // BarStyle sets custom bar style.
106 // Effective when Filler type is bar.
105 // BarStyle sets custom bar style, default one is "[=>-]<+".
106 //
107 // '[' left bracket rune
108 //
109 // '=' fill rune
110 //
111 // '>' tip rune
112 //
113 // '-' empty rune
114 //
115 // ']' right bracket rune
116 //
117 // '<' reverse tip rune, used when BarReverse option is set
118 //
119 // '+' refill rune, used when *Bar.SetRefill(int) is called
120 //
121 // It's ok to provide first five runes only, for example mpb.BarStyle("╢▌▌░╟")
107122 func BarStyle(style string) BarOption {
108123 chk := func(filler Filler) (interface{}, bool) {
109124 if style == "" {
114129 }
115130 cb := func(t interface{}) {
116131 t.(*barFiller).setStyle(style)
132 }
133 return MakeFillerTypeSpecificBarOption(chk, cb)
134 }
135
136 // BarReverse reverse mode, bar will progress from right to left.
137 func BarReverse() BarOption {
138 chk := func(filler Filler) (interface{}, bool) {
139 t, ok := filler.(*barFiller)
140 return t, ok
141 }
142 cb := func(t interface{}) {
143 t.(*barFiller).setReverse()
117144 }
118145 return MakeFillerTypeSpecificBarOption(chk, cb)
119146 }