New BarOptions, BarReplaceOnComplete and BarClearOnComplete
Vladimir Bauer
8 years ago
| 30 | 30 | type Bar struct { |
| 31 | 31 | priority int |
| 32 | 32 | index int |
| 33 | ||
| 34 | // pointer to running bar, which this bar should replace | |
| 35 | waitBar *Bar | |
| 33 | 36 | |
| 34 | 37 | // completed is set from master Progress goroutine only |
| 35 | 38 | completed bool |
| 59 | 62 | trimRightSpace bool |
| 60 | 63 | toComplete bool |
| 61 | 64 | dynamic bool |
| 65 | noBarOnComplete bool | |
| 62 | 66 | startTime time.Time |
| 63 | 67 | timeElapsed time.Duration |
| 64 | 68 | blockStartTime time.Time |
| 72 | 76 | // following options are assigned to the *Bar |
| 73 | 77 | priority int |
| 74 | 78 | removeOnComplete bool |
| 79 | waitBar *Bar | |
| 75 | 80 | } |
| 76 | 81 | refill struct { |
| 77 | 82 | char rune |
| 109 | 114 | b := &Bar{ |
| 110 | 115 | priority: s.priority, |
| 111 | 116 | removeOnComplete: s.removeOnComplete, |
| 117 | waitBar: s.waitBar, | |
| 112 | 118 | operateState: make(chan func(*bState)), |
| 113 | 119 | done: make(chan struct{}), |
| 114 | 120 | shutdown: make(chan struct{}), |
| 121 | } | |
| 122 | ||
| 123 | if b.waitBar != nil { | |
| 124 | b.priority = b.waitBar.priority | |
| 115 | 125 | } |
| 116 | 126 | |
| 117 | 127 | go b.serve(wg, s, cancel) |
| 321 | 331 | } |
| 322 | 332 | |
| 323 | 333 | func (s *bState) draw(termWidth int, pSyncer, aSyncer *widthSyncer) io.Reader { |
| 334 | defer s.bufA.WriteByte('\n') | |
| 335 | ||
| 324 | 336 | if termWidth <= 0 { |
| 325 | 337 | termWidth = s.width |
| 326 | 338 | } |
| 332 | 344 | s.bufP.WriteString(f(stat, pSyncer.Accumulator[i], pSyncer.Distributor[i])) |
| 333 | 345 | } |
| 334 | 346 | |
| 335 | if !s.trimLeftSpace { | |
| 336 | s.bufP.WriteByte(' ') | |
| 337 | } | |
| 338 | ||
| 339 | // render append functions to the right of the bar | |
| 340 | if !s.trimRightSpace { | |
| 341 | s.bufA.WriteByte(' ') | |
| 342 | } | |
| 343 | ||
| 344 | 347 | for i, f := range s.aDecorators { |
| 345 | 348 | s.bufA.WriteString(f(stat, aSyncer.Accumulator[i], aSyncer.Distributor[i])) |
| 346 | 349 | } |
| 347 | 350 | |
| 348 | 351 | prependCount := utf8.RuneCount(s.bufP.Bytes()) |
| 349 | 352 | appendCount := utf8.RuneCount(s.bufA.Bytes()) |
| 353 | ||
| 354 | if s.toComplete && s.noBarOnComplete { | |
| 355 | return io.MultiReader(s.bufP, s.bufA) | |
| 356 | } | |
| 350 | 357 | |
| 351 | 358 | s.fillBar(s.width) |
| 352 | 359 | barCount := utf8.RuneCount(s.bufB.Bytes()) |
| 355 | 362 | s.fillBar(termWidth - prependCount - appendCount) |
| 356 | 363 | } |
| 357 | 364 | |
| 358 | s.bufA.WriteByte('\n') | |
| 359 | 365 | return io.MultiReader(s.bufP, s.bufB, s.bufA) |
| 360 | 366 | } |
| 361 | 367 | |
| 362 | 368 | func (s *bState) fillBar(width int) { |
| 369 | defer func() { | |
| 370 | if !s.trimRightSpace { | |
| 371 | s.bufB.WriteByte(' ') | |
| 372 | } | |
| 373 | }() | |
| 363 | 374 | s.bufB.Reset() |
| 375 | if !s.trimLeftSpace { | |
| 376 | s.bufB.WriteByte(' ') | |
| 377 | } | |
| 364 | 378 | s.bufB.WriteRune(s.runes[rLeft]) |
| 365 | 379 | if width <= 2 { |
| 366 | 380 | s.bufB.WriteRune(s.runes[rRight]) |
| 0 | 0 | package mpb |
| 1 | 1 | |
| 2 | import "github.com/vbauerster/mpb/decor" | |
| 2 | import ( | |
| 3 | "github.com/vbauerster/mpb/decor" | |
| 4 | ) | |
| 3 | 5 | |
| 4 | 6 | // BarOption is a function option which changes the default behavior of a bar, |
| 5 | 7 | // if passed to p.AddBar(int64, ...BarOption) |
| 74 | 76 | } |
| 75 | 77 | } |
| 76 | 78 | |
| 77 | // BarRemoveOnComplete is a flag, which tells whether the intention is to remove the bar after completion. | |
| 79 | // BarRemoveOnComplete is a flag, which will trigger bar auto remove on completion event. | |
| 78 | 80 | func BarRemoveOnComplete() BarOption { |
| 79 | 81 | return func(s *bState) { |
| 80 | 82 | s.removeOnComplete = true |
| 83 | 85 | |
| 84 | 86 | // BarPriority sets bar's priority. |
| 85 | 87 | // Zero is highest priority, i.e. bar will be on top. |
| 88 | // If `BarReplaceOnComplete` option is supplied, this option is ignored. | |
| 86 | 89 | func BarPriority(priority int) BarOption { |
| 87 | 90 | return func(s *bState) { |
| 88 | 91 | s.priority = priority |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | // BarReplaceOnComplete provided `b` is usually already running bar which this bar should replace. | |
| 96 | func BarReplaceOnComplete(b *Bar) BarOption { | |
| 97 | return func(s *bState) { | |
| 98 | s.waitBar = b | |
| 99 | } | |
| 100 | } | |
| 101 | ||
| 102 | // BarClearOnComplete clears the bar section on complete event. | |
| 103 | func BarClearOnComplete() BarOption { | |
| 104 | return func(s *bState) { | |
| 105 | s.noBarOnComplete = true | |
| 89 | 106 | } |
| 90 | 107 | } |
| 91 | 108 | |
| 45 | 45 | cancel <-chan struct{} |
| 46 | 46 | shutdownNotifier chan struct{} |
| 47 | 47 | interceptors []func(io.Writer) |
| 48 | waitBars map[*Bar]*Bar | |
| 48 | 49 | } |
| 49 | 50 | widthSyncer struct { |
| 50 | 51 | // Public for easy testing |
| 59 | 60 | pq := make(priorityQueue, 0) |
| 60 | 61 | heap.Init(&pq) |
| 61 | 62 | s := &pState{ |
| 62 | bHeap: &pq, | |
| 63 | width: pwidth, | |
| 64 | format: pformat, | |
| 65 | cw: cwriter.New(os.Stdout), | |
| 66 | rr: prr, | |
| 67 | ticker: time.NewTicker(prr), | |
| 63 | bHeap: &pq, | |
| 64 | width: pwidth, | |
| 65 | format: pformat, | |
| 66 | cw: cwriter.New(os.Stdout), | |
| 67 | rr: prr, | |
| 68 | ticker: time.NewTicker(prr), | |
| 69 | waitBars: make(map[*Bar]*Bar), | |
| 68 | 70 | } |
| 69 | 71 | |
| 70 | 72 | for _, opt := range options { |
| 91 | 93 | case p.operateState <- func(s *pState) { |
| 92 | 94 | options = append(options, barWidth(s.width), barFormat(s.format)) |
| 93 | 95 | b := newBar(p.wg, s.idCounter, total, s.cancel, options...) |
| 94 | heap.Push(s.bHeap, b) | |
| 95 | s.heapUpdated = true | |
| 96 | if b.waitBar != nil { | |
| 97 | s.waitBars[b.waitBar] = b | |
| 98 | } else { | |
| 99 | heap.Push(s.bHeap, b) | |
| 100 | s.heapUpdated = true | |
| 101 | } | |
| 96 | 102 | s.idCounter++ |
| 97 | 103 | result <- b |
| 98 | 104 | }: |
| 207 | 213 | if rs.bar.removeOnComplete { |
| 208 | 214 | s.heapUpdated = heap.Remove(s.bHeap, rs.bar.index) != nil |
| 209 | 215 | } |
| 216 | if replacementBar, ok := s.waitBars[rs.bar]; ok { | |
| 217 | heap.Push(s.bHeap, replacementBar) | |
| 218 | s.heapUpdated = true | |
| 219 | delete(s.waitBars, rs.bar) | |
| 220 | } | |
| 210 | 221 | defer func() { |
| 211 | 222 | s.shutdownPending = append(s.shutdownPending, rs.bar) |
| 212 | 223 | }() |