diff --git a/bar.go b/bar.go index 4282907..cdb0942 100644 --- a/bar.go +++ b/bar.go @@ -34,12 +34,13 @@ leftEnd byte rightEnd byte - incrCh chan int - redrawRequestCh chan *redrawRequest - decoratorCh chan *decorator - flushedCh chan struct{} - stopCh chan struct{} - done chan struct{} + incrCh chan int + redrawReqCh chan chan []byte + progressReqCh chan chan int + decoratorCh chan *decorator + flushedCh chan struct{} + stopCh chan struct{} + done chan struct{} timePerItemEstimate time.Duration } @@ -49,26 +50,31 @@ TimePerItemEstimate time.Duration } -type redrawRequest struct { - bufCh chan []byte -} +// type redrawRequest struct { +// respCh chan []byte +// } + +// type progressRequest struct { +// respCh chan int +// } func newBar(total, width int, wg *sync.WaitGroup) *Bar { b := &Bar{ - fill: '=', - empty: '-', - tip: '>', - leftEnd: '[', - rightEnd: ']', - alpha: 0.25, - total: total, - width: width, - incrCh: make(chan int), - redrawRequestCh: make(chan *redrawRequest), - decoratorCh: make(chan *decorator), - flushedCh: make(chan struct{}), - stopCh: make(chan struct{}), - done: make(chan struct{}), + fill: '=', + empty: '-', + tip: '>', + leftEnd: '[', + rightEnd: ']', + alpha: 0.25, + total: total, + width: width, + incrCh: make(chan int), + redrawReqCh: make(chan chan []byte), + progressReqCh: make(chan chan int), + decoratorCh: make(chan *decorator), + flushedCh: make(chan struct{}), + stopCh: make(chan struct{}), + done: make(chan struct{}), } go b.server(wg) return b @@ -128,9 +134,9 @@ // String returns the string representation of the bar func (b *Bar) String() string { - bufCh := make(chan []byte) - b.redrawRequestCh <- &redrawRequest{bufCh} - return string(<-bufCh) + respCh := make(chan []byte) + b.redrawReqCh <- respCh + return string(<-respCh) } func (b *Bar) Incr(n int) { @@ -228,8 +234,10 @@ case decoratorPrepend: prependFuncs = append(prependFuncs, d.f) } - case r := <-b.redrawRequestCh: - r.bufCh <- b.draw(buf, completed, appendFuncs, prependFuncs) + case respCh := <-b.redrawReqCh: + respCh <- b.draw(buf, completed, appendFuncs, prependFuncs) + case respCh := <-b.progressReqCh: + respCh <- int(100 * float64(completed) / float64(b.total)) case <-b.flushedCh: if done && !b.IsCompleted() { // fmt.Fprintln(os.Stderr, "flushedCh: wg.Done") @@ -287,3 +295,17 @@ lastItemEstimate := float64(lastBlockTime) / float64(items) b.timePerItemEstimate = time.Duration((b.alpha * lastItemEstimate) + (1-b.alpha)*float64(b.timePerItemEstimate)) } + +func (b *Bar) progress() int { + respCh := make(chan int) + b.progressReqCh <- respCh + return <-respCh +} + +type SortableBarSlice []*Bar + +func (p SortableBarSlice) Len() int { return len(p) } + +func (p SortableBarSlice) Less(i, j int) bool { return p[i].progress() < p[j].progress() } + +func (p SortableBarSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/progress.go b/progress.go index 6c494be..6e7d90d 100644 --- a/progress.go +++ b/progress.go @@ -4,6 +4,7 @@ "fmt" "io" "os" + "sort" "sync" "time" @@ -13,8 +14,16 @@ type opType uint const ( - barAdd opType = iota - barRemove + opBarAdd opType = iota + opBarRemove +) + +type SortType uint + +const ( + SortNone SortType = iota + SortTop + SortBottom ) const refreshRate = 60 @@ -23,6 +32,7 @@ type Progress struct { out io.Writer width int + sort SortType stopped bool op chan *operation @@ -74,17 +84,22 @@ return p } +func (p *Progress) Sort(sort SortType) *Progress { + p.sort = sort + return p +} + // AddBar creates a new progress bar and adds to the container func (p *Progress) AddBar(total int) *Bar { p.wg.Add(1) bar := newBar(total, p.width, p.wg) - p.op <- &operation{barAdd, bar, nil} + p.op <- &operation{opBarAdd, bar, nil} return bar } func (p *Progress) RemoveBar(b *Bar) bool { result := make(chan bool) - p.op <- &operation{barRemove, b, result} + p.op <- &operation{opBarRemove, b, result} return <-result } @@ -115,9 +130,9 @@ return } switch op.kind { - case barAdd: + case opBarAdd: bars = append(bars, op.bar) - case barRemove: + case opBarRemove: var ok bool for i, b := range bars { if b == op.bar { @@ -130,6 +145,12 @@ op.result <- ok } case <-t.C: + switch p.sort { + case SortTop: + sort.Sort(sort.Reverse(SortableBarSlice(bars))) + case SortBottom: + sort.Sort(SortableBarSlice(bars)) + } for _, b := range bars { // cannot parallel this, because order matters fmt.Fprintln(lw, b)