diff --git a/bar.go b/bar.go index aef1ca0..f2bccee 100644 --- a/bar.go +++ b/bar.go @@ -321,7 +321,6 @@ frame = io.MultiReader(frame, s.bufE) } - // b.toDrop = s.dropOnComplete b.toShutdown = s.toComplete && !s.completeFlushed s.completeFlushed = s.toComplete @@ -411,13 +410,6 @@ } } -// func (b *Bar) dropOnComplete() { -// select { -// case b.operateState <- func(s *bState) { s.dropOnComplete = true }: -// case <-b.done: -// } -// } - func newStatistics(s *bState) *decor.Statistics { return &decor.Statistics{ ID: s.id, diff --git a/bar_option.go b/bar_option.go index 7b60520..65e517d 100644 --- a/bar_option.go +++ b/bar_option.go @@ -74,20 +74,17 @@ } } -// BarReplaceOnComplete is deprecated. Refer to BarParkTo option. +// BarReplaceOnComplete is deprecated. Use BarParkTo instead. func BarReplaceOnComplete(runningBar *Bar) BarOption { return BarParkTo(runningBar) } // BarParkTo parks constructed bar into the runningBar. In other words, -// constructed bar will start only after runningBar has been completed. -// Parked bar inherits priority of the runningBar, if no BarPriority -// option is set. Parked bar will replace runningBar eventually. +// constructed bar will replace runningBar after it has been completed. func BarParkTo(runningBar *Bar) BarOption { if runningBar == nil { return nil } - runningBar.dropOnComplete() return func(s *bState) { s.runningBar = runningBar } diff --git a/options.go b/options.go index 1d84706..26c67cd 100644 --- a/options.go +++ b/options.go @@ -79,6 +79,13 @@ } } +// PopCompletedMode will pop and stop rendering completed bars. +func PopCompletedMode() ContainerOption { + return func(s *pState) { + s.popCompleted = true + } +} + // ContainerOptOnCond returns option when condition evaluates to true. func ContainerOptOnCond(option ContainerOption, condition func() bool) ContainerOption { if condition() { diff --git a/priority_queue.go b/priority_queue.go index 4fffb2e..29d9bd5 100644 --- a/priority_queue.go +++ b/priority_queue.go @@ -1,6 +1,4 @@ package mpb - -import "container/heap" // A priorityQueue implements heap.Interface type priorityQueue []*Bar @@ -32,9 +30,3 @@ bar.index = -1 // for safety return bar } - -// update modifies the priority of a Bar in the queue. -func (pq *priorityQueue) update(bar *Bar, priority int) { - bar.priority = priority - heap.Fix(pq, bar.index) -} diff --git a/progress.go b/progress.go index 1cbb2ae..e732edc 100644 --- a/progress.go +++ b/progress.go @@ -39,10 +39,12 @@ pMatrix map[int][]chan int aMatrix map[int][]chan int barShutdownQueue []*Bar + barPopQueue []*Bar // following are provided/overrided by user idCount int width int + popCompleted bool rr time.Duration uwg *sync.WaitGroup manualRefreshCh <-chan time.Time @@ -132,9 +134,6 @@ } bar := newBar(p, bs) if bs.runningBar != nil { - if bar.priority == ps.idCount { - bar.priority = bs.runningBar.priority - } ps.parkedBars[bs.runningBar] = bar } else { heap.Push(&ps.bHeap, bar) @@ -163,16 +162,22 @@ } } -// UpdateBarPriority is deprecated. Please use *Bar.SetOrder. +func (p *Progress) setBarPriority(b *Bar, priority int) { + select { + case p.operateState <- func(s *pState) { + if b.index < 0 { + return + } + b.priority = priority + heap.Fix(&s.bHeap, b.index) + }: + case <-p.done: + } +} + +// UpdateBarPriority same as *Bar.SetPriority. func (p *Progress) UpdateBarPriority(b *Bar, priority int) { p.setBarPriority(b, priority) -} - -func (p *Progress) setBarPriority(b *Bar, priority int) { - select { - case p.operateState <- func(s *pState) { s.bHeap.update(b, priority) }: - case <-p.done: - } } // BarCount returns bars count @@ -255,52 +260,56 @@ } func (s *pState) flush(cw *cwriter.Writer) error { - var rpop bool var lineCount int hlen := s.bHeap.Len() - tmp := make([]*Bar, hlen) + bb := make([]*Bar, hlen) for i := 0; i < hlen; i++ { - bar := heap.Pop(&s.bHeap).(*Bar) + b := heap.Pop(&s.bHeap).(*Bar) defer func() { - if bar.toShutdown { + if b.toShutdown { // shutdown at next flush, in other words decrement underlying WaitGroup // only after the bar with completed state has been flushed. this // ensures no bar ends up with less than 100% rendered. - s.barShutdownQueue = append(s.barShutdownQueue, bar) - // if parkedBar := s.parkedBars[bar]; parkedBar != nil { - // heap.Push(&s.bHeap, parkedBar) - // s.heapUpdated = true - // delete(s.parkedBars, bar) - // } - // if bar.toDrop { - // s.heapUpdated = true - // return - // } - // bar.priority = 0 + s.barShutdownQueue = append(s.barShutdownQueue, b) + if s.popCompleted && s.parkedBars[b] == nil { + b.priority = -1 + } } }() - cw.ReadFrom(<-bar.frameCh) - lineCount += bar.extendedLines + 1 - tmp[i] = bar - } - - for _, b := range tmp { + cw.ReadFrom(<-b.frameCh) + lineCount += b.extendedLines + 1 + bb[i] = b + } + + for _, b := range bb { heap.Push(&s.bHeap, b) } for _, b := range s.barShutdownQueue { if parkedBar := s.parkedBars[b]; parkedBar != nil { - heap.Remove(&s.bHeap, b.index) + parkedBar.priority = b.priority heap.Push(&s.bHeap, parkedBar) delete(s.parkedBars, b) - s.heapUpdated = true - } else if b.toDrop { + b.toDrop = true + } + if b.toDrop { heap.Remove(&s.bHeap, b.index) s.heapUpdated = true + } else if s.popCompleted { + defer func() { + s.barPopQueue = append(s.barPopQueue, b) + }() } b.cancel() } s.barShutdownQueue = s.barShutdownQueue[0:0] + + for _, b := range s.barPopQueue { + heap.Remove(&s.bHeap, b.index) + s.heapUpdated = true + lineCount -= b.extendedLines + 1 + } + s.barPopQueue = s.barPopQueue[0:0] return cw.Flush(lineCount) }