| 1 | 1 |
|
| 2 | 2 |
import (
|
| 3 | 3 |
"fmt"
|
|
4 |
"sync"
|
| 4 | 5 |
"time"
|
| 5 | 6 |
)
|
| 6 | 7 |
|
|
| 64 | 65 |
|
| 65 | 66 |
Alpha float64
|
| 66 | 67 |
|
| 67 | |
currentIncrCh chan int
|
|
68 |
incrRequestCh chan *incrRequest
|
| 68 | 69 |
|
| 69 | 70 |
redrawRequestCh chan *redrawRequest
|
| 70 | 71 |
|
| 71 | 72 |
decoratorCh chan *decorator
|
| 72 | 73 |
|
| 73 | 74 |
timePerItemEstimate time.Duration
|
|
75 |
|
|
76 |
flushedCh chan *sync.WaitGroup
|
| 74 | 77 |
}
|
| 75 | 78 |
|
| 76 | 79 |
type Statistics struct {
|
|
| 79 | 82 |
}
|
| 80 | 83 |
|
| 81 | 84 |
type redrawRequest struct {
|
| 82 | |
bufch chan []byte
|
|
85 |
bufCh chan []byte
|
|
86 |
}
|
|
87 |
|
|
88 |
type incrRequest struct {
|
|
89 |
amount int
|
|
90 |
result chan bool
|
| 83 | 91 |
}
|
| 84 | 92 |
|
| 85 | 93 |
// NewBar returns a new progress bar
|
| 86 | |
func NewBar(total int) *Bar {
|
|
94 |
func newBar(total int) *Bar {
|
| 87 | 95 |
b := &Bar{
|
| 88 | 96 |
Alpha: 0.25,
|
| 89 | 97 |
total: total,
|
|
| 93 | 101 |
Head: Head,
|
| 94 | 102 |
Fill: Fill,
|
| 95 | 103 |
Empty: Empty,
|
| 96 | |
currentIncrCh: make(chan int),
|
|
104 |
incrRequestCh: make(chan *incrRequest),
|
| 97 | 105 |
redrawRequestCh: make(chan *redrawRequest),
|
| 98 | 106 |
decoratorCh: make(chan *decorator),
|
|
107 |
flushedCh: make(chan *sync.WaitGroup),
|
| 99 | 108 |
}
|
| 100 | 109 |
go b.server()
|
| 101 | 110 |
return b
|
| 102 | |
}
|
| 103 | |
|
| 104 | |
func (b *Bar) Incr(n int) {
|
| 105 | |
b.currentIncrCh <- n
|
| 106 | 111 |
}
|
| 107 | 112 |
|
| 108 | 113 |
func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
|
|
| 131 | 136 |
return b
|
| 132 | 137 |
}
|
| 133 | 138 |
|
|
139 |
func (b *Bar) PrependPercentage() *Bar {
|
|
140 |
b.PrependFunc(func(s *Statistics) string {
|
|
141 |
completed := int(100 * float64(s.Completed) / float64(s.Total))
|
|
142 |
return fmt.Sprintf("%3d %%", completed)
|
|
143 |
})
|
|
144 |
return b
|
|
145 |
}
|
|
146 |
|
| 134 | 147 |
// String returns the string representation of the bar
|
| 135 | 148 |
func (b *Bar) String() string {
|
| 136 | |
bufch := make(chan []byte)
|
| 137 | |
b.redrawRequestCh <- &redrawRequest{bufch}
|
| 138 | |
return string(<-bufch)
|
|
149 |
bufCh := make(chan []byte)
|
|
150 |
b.redrawRequestCh <- &redrawRequest{bufCh}
|
|
151 |
return string(<-bufCh)
|
|
152 |
}
|
|
153 |
|
|
154 |
// func (b *Bar) bytes() []byte {
|
|
155 |
// bufch := make(chan []byte)
|
|
156 |
// b.redrawRequestCh <- &redrawRequest{bufch}
|
|
157 |
// return <-bufch
|
|
158 |
// }
|
|
159 |
|
|
160 |
func (b *Bar) flushed(wg *sync.WaitGroup) {
|
|
161 |
b.flushedCh <- wg
|
|
162 |
}
|
|
163 |
|
|
164 |
func (b *Bar) Incr(n int) bool {
|
|
165 |
result := make(chan bool)
|
|
166 |
b.incrRequestCh <- &incrRequest{n, result}
|
|
167 |
return <-result
|
| 139 | 168 |
}
|
| 140 | 169 |
|
| 141 | 170 |
func (b *Bar) server() {
|
| 142 | |
var current int
|
|
171 |
var completed int
|
| 143 | 172 |
blockStartTime := time.Now()
|
| 144 | 173 |
buf := make([]byte, b.Width, b.Width+24)
|
| 145 | 174 |
var appendFuncs []DecoratorFunc
|
| 146 | 175 |
var prependFuncs []DecoratorFunc
|
| 147 | 176 |
for {
|
| 148 | 177 |
select {
|
| 149 | |
case i := <-b.currentIncrCh:
|
| 150 | |
n := current + i
|
|
178 |
case r := <-b.incrRequestCh:
|
|
179 |
n := completed + r.amount
|
| 151 | 180 |
if n > b.total {
|
| 152 | |
return
|
|
181 |
completed = b.total
|
|
182 |
r.result <- false
|
|
183 |
break // breaks out of select, not for
|
| 153 | 184 |
}
|
| 154 | |
b.updateTimePerItemEstimate(i, blockStartTime)
|
| 155 | |
current = n
|
|
185 |
b.updateTimePerItemEstimate(r.amount, blockStartTime)
|
|
186 |
completed = n
|
| 156 | 187 |
blockStartTime = time.Now()
|
|
188 |
r.result <- true
|
| 157 | 189 |
case d := <-b.decoratorCh:
|
| 158 | 190 |
switch d.kind {
|
| 159 | 191 |
case decoratorAppend:
|
|
| 162 | 194 |
prependFuncs = append(prependFuncs, d.f)
|
| 163 | 195 |
}
|
| 164 | 196 |
case r := <-b.redrawRequestCh:
|
| 165 | |
r.bufch <- b.draw(buf, current, appendFuncs, prependFuncs)
|
|
197 |
r.bufCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
|
|
198 |
case wg := <-b.flushedCh:
|
|
199 |
if completed == b.total {
|
|
200 |
close(b.incrRequestCh)
|
|
201 |
wg.Done()
|
|
202 |
return
|
|
203 |
}
|
| 166 | 204 |
}
|
| 167 | 205 |
}
|
| 168 | 206 |
}
|