Codebase list golang-github-vbauerster-mpb / 7bd7f5e
AppendFunc Vladimir Bauer 9 years ago
2 changed file(s) with 68 addition(s) and 63 deletion(s). Raw diff Collapse all Expand all
00 package uiprogress
1
2 import (
3 "fmt"
4 "time"
5 )
16
27 var (
38 // Fill is the default character representing completed progress
1722
1823 // Width is the default width of the progress bar
1924 Width = 70
20
21 // ErrMaxCurrentReached is error when trying to set current value that exceeds the total value
22 // ErrMaxCurrentReached = errors.New("errors: current value is greater total value")
2325 )
2426
2527 // Bar represents a progress bar
4547 // Width is the width of the progress bar
4648 Width int
4749
48 currentUpdateCh chan int
50 Alpha float64
51
52 currentIncrCh chan int
4953
5054 redrawRequestCh chan *redrawRequest
5155
52 // appendFuncs []DecoratorFunc
53 // prependFuncs []DecoratorFunc
56 decoratorFuncCh chan DecoratorFunc
57
58 timePerItemEstimate time.Duration
5459 }
5560
5661 // DecoratorFunc is a function that can be prepended and appended to the progress bar
57 type DecoratorFunc func(b *Bar) string
62 type DecoratorFunc func(s *Statistics) string
63
64 type Statistics struct {
65 Total, Completed int
66 TimePerItemEstimate time.Duration
67 }
68
69 type redrawRequest struct {
70 bufch chan []byte
71 }
5872
5973 // NewBar returns a new progress bar
6074 func NewBar(total int) *Bar {
6175 b := &Bar{
76 Alpha: 0.25,
6277 total: total,
6378 Width: Width,
6479 LeftEnd: LeftEnd,
6681 Head: Head,
6782 Fill: Fill,
6883 Empty: Empty,
69 currentUpdateCh: make(chan int),
84 currentIncrCh: make(chan int),
7085 redrawRequestCh: make(chan *redrawRequest),
86 decoratorFuncCh: make(chan DecoratorFunc),
7187 }
7288 go b.server()
7389 return b
7490 }
7591
76 type redrawRequest struct {
77 bufch chan []byte
92 func (b *Bar) Incr(n int) {
93 b.currentIncrCh <- n
7894 }
7995
80 func (b *Bar) Update(n int) {
81 b.currentUpdateCh <- n
96 func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
97 b.decoratorFuncCh <- f
98 return b
99 }
100
101 func (b *Bar) AppendETA() *Bar {
102 b.AppendFunc(func(s *Statistics) string {
103 eta := time.Duration(s.Total-s.Completed) * s.TimePerItemEstimate
104 return fmt.Sprint(time.Duration(eta.Seconds()) * time.Second)
105 })
106 return b
82107 }
83108
84109 // String returns the string representation of the bar
90115
91116 func (b *Bar) server() {
92117 var current int
93 // blockStartTime := time.Now()
94 // timePerItemEstimate time.Duration
95 // remainingTime time.Duration
118 blockStartTime := time.Now()
96119 buf := make([]byte, b.Width)
120 var appendFuncs []DecoratorFunc
121 // var prependFuncs []DecoratorFunc
97122 for {
98123 select {
99 case n := <-b.currentUpdateCh:
124 case i := <-b.currentIncrCh:
125 n := current + i
100126 if n > b.total {
101127 return
102128 }
129 b.updateTimePerItemEstimate(i, blockStartTime)
103130 current = n
104 // fmt.Printf("current = %+v\n", current)
105 // blockStartTime = time.Now()
131 blockStartTime = time.Now()
132 case f := <-b.decoratorFuncCh:
133 appendFuncs = append(appendFuncs, f)
106134 case r := <-b.redrawRequestCh:
107 r.bufch <- b.draw(buf, current)
135 r.bufch <- b.draw(buf, current, appendFuncs)
108136 }
109137 }
110138 }
111139
112 func (b *Bar) draw(buf []byte, current int) []byte {
140 func (b *Bar) draw(buf []byte, current int, appendFuncs []DecoratorFunc) []byte {
141 // eta := time.Duration(b.total-current) * b.timePerItemEstimate
113142 completedWidth := current * b.Width / b.total
114143
115144 for i := 0; i < completedWidth; i++ {
126155 // set left and right ends bits
127156 buf[0], buf[len(buf)-1] = b.LeftEnd, b.RightEnd
128157
158 s := &Statistics{b.total, current, b.timePerItemEstimate}
159
129160 // render append functions to the right of the bar
130 // for _, f := range b.appendFuncs {
131 // pb = append(pb, ' ')
132 // pb = append(pb, []byte(f(b))...)
133 // }
161 for _, f := range appendFuncs {
162 buf = append(buf, ' ')
163 buf = append(buf, []byte(f(s))...)
164 }
134165
135166 // render prepend functions to the left of the bar
136167 // for _, f := range b.prependFuncs {
141172 return buf
142173 }
143174
144 // CompletedPercent return the percent completed
145 // func (b *Bar) CompletedPercent() int {
146 // return int(100 * float64(b.current) / float64(b.Total))
175 func (b *Bar) updateTimePerItemEstimate(items int, blockStartTime time.Time) {
176 lastBlockTime := time.Since(blockStartTime)
177 lastItemEstimate := float64(lastBlockTime) / float64(items)
178 b.timePerItemEstimate = time.Duration((b.Alpha * lastItemEstimate) + (1-b.Alpha)*float64(b.timePerItemEstimate))
179 }
180
181 // func nextTimePerItemEstimate(d time.Duration, blockStartTime time.Time, alpha float64, items int) time.Duration {
182 // lastBlockTime := time.Since(blockStartTime)
183 // lastItemEstimate := float64(lastBlockTime) / float64(items)
184 // return time.Duration((alpha * lastItemEstimate) + (1-alpha)*float64(d))
147185 // }
148
149 // AppendFunc runs the decorator function and renders the output on the right of the progress bar
150 // func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
151 // b.appendFuncs = append(b.appendFuncs, f)
152 // return b
153 // }
154
155 // PrependFunc runs decorator function and render the output left the progress bar
156 // func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
157 // b.prependFuncs = append(b.prependFuncs, f)
158 // return b
159 // }
160
161 // AppendCompleted appends the completion percent to the progress bar
162 // func (b *Bar) AppendCompleted() *Bar {
163 // b.AppendFunc(func(b *Bar) string {
164 // return b.CompletedPercentString()
165 // })
166 // return b
167 // }
168
169 // CompletedPercentString returns the formatted string representation of the completed percent
170 // func (b *Bar) CompletedPercentString() string {
171 // return fmt.Sprintf("%3d%%", b.CompletedPercent())
172 // }
173
174 // PrependElapsed prepends the time elapsed to the begining of the bar
175 // func (b *Bar) PrependElapsed() *Bar {
176 // b.PrependFunc(func(b *Bar) string {
177 // return strutil.PadLeft(b.TimeElapsedString(), 5, ' ')
178 // })
179 // return b
180 // }
1717 bar := p.AddBar(totalItem) // Add a new bar
1818
1919 // optionally, append and prepend completion and elapsed time
20 // bar.AppendCompleted()
20 bar.AppendETA()
2121 // bar.PrependElapsed()
2222
2323 blockSize := rand.Intn(maxBlockSize) + 1
24 for i := 0; i < totalItem; i += blockSize {
24 for i := 1; i <= totalItem; i += blockSize {
2525 time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond)))))
26 bar.Update(i)
26 bar.Incr(blockSize)
2727 blockSize = rand.Intn(maxBlockSize) + 1
2828 }
2929