diff --git a/progress.go b/progress.go index 1182d7e..97c6180 100644 --- a/progress.go +++ b/progress.go @@ -244,6 +244,78 @@ } } +func (s *pState) render(cw *cwriter.Writer) error { + if s.heapUpdated { + s.updateSyncMatrix() + s.heapUpdated = false + } + syncWidth(s.pMatrix) + syncWidth(s.aMatrix) + + tw, err := cw.GetWidth() + if err != nil { + tw = s.reqWidth + } + for i := 0; i < s.bHeap.Len(); i++ { + bar := s.bHeap[i] + go bar.render(tw) + } + + return s.flush(cw) +} + +func (s *pState) flush(cw *cwriter.Writer) error { + var totalLines int + bm := make(map[*Bar]*frame, s.bHeap.Len()) + for s.bHeap.Len() > 0 { + b := heap.Pop(&s.bHeap).(*Bar) + frame := <-b.frameCh + _, err := cw.ReadFrom(frame.reader) + if err != nil { + return err + } + if frame.complete { + // shutdown at next flush + // this ensures no bar ends up with less than 100% rendered + defer func() { + s.barShutdownQueue = append(s.barShutdownQueue, b) + }() + } else if frame.abort { + s.barShutdownQueue = append(s.barShutdownQueue, b) + } + totalLines += frame.lines + bm[b] = frame + } + + for _, b := range s.barShutdownQueue { + b.cancel() + <-b.done // waiting for b.done, so it's safe to read b.bs + var toDrop bool + if qb, ok := s.queueBars[b]; ok { + delete(s.queueBars, b) + qb.bar.priority = b.priority + heap.Push(&s.bHeap, qb.bar) + go qb.serve() + toDrop = true + } else if s.popCompleted && !b.bs.noPop { + frame := bm[b] + totalLines -= frame.lines + toDrop = true + } + if toDrop || b.bs.dropOnComplete { + delete(bm, b) + s.heapUpdated = true + } + } + s.barShutdownQueue = s.barShutdownQueue[0:0] + + for b := range bm { + heap.Push(&s.bHeap, b) + } + + return cw.Flush(totalLines) +} + func (s *pState) newTicker(done <-chan struct{}) chan time.Time { ch := make(chan time.Time) if s.shutdownNotifier == nil { @@ -282,78 +354,6 @@ return ch } -func (s *pState) render(cw *cwriter.Writer) error { - if s.heapUpdated { - s.updateSyncMatrix() - s.heapUpdated = false - } - syncWidth(s.pMatrix) - syncWidth(s.aMatrix) - - tw, err := cw.GetWidth() - if err != nil { - tw = s.reqWidth - } - for i := 0; i < s.bHeap.Len(); i++ { - bar := s.bHeap[i] - go bar.render(tw) - } - - return s.flush(cw) -} - -func (s *pState) flush(cw *cwriter.Writer) error { - var totalLines int - bm := make(map[*Bar]*frame, s.bHeap.Len()) - for s.bHeap.Len() > 0 { - b := heap.Pop(&s.bHeap).(*Bar) - frame := <-b.frameCh - _, err := cw.ReadFrom(frame.reader) - if err != nil { - return err - } - if frame.complete { - // shutdown at next flush - // this ensures no bar ends up with less than 100% rendered - defer func() { - s.barShutdownQueue = append(s.barShutdownQueue, b) - }() - } else if frame.abort { - s.barShutdownQueue = append(s.barShutdownQueue, b) - } - totalLines += frame.lines - bm[b] = frame - } - - for _, b := range s.barShutdownQueue { - b.cancel() - <-b.done // waiting for b.done, so it's safe to read b.bs - var toDrop bool - if qb, ok := s.queueBars[b]; ok { - delete(s.queueBars, b) - qb.bar.priority = b.priority - heap.Push(&s.bHeap, qb.bar) - go qb.serve() - toDrop = true - } else if s.popCompleted && !b.bs.noPop { - frame := bm[b] - totalLines -= frame.lines - toDrop = true - } - if toDrop || b.bs.dropOnComplete { - delete(bm, b) - s.heapUpdated = true - } - } - s.barShutdownQueue = s.barShutdownQueue[0:0] - - for b := range bm { - heap.Push(&s.bHeap, b) - } - - return cw.Flush(totalLines) -} - func (s *pState) updateSyncMatrix() { s.pMatrix = make(map[int][]chan int) s.aMatrix = make(map[int][]chan int)