diff --git a/bar.go b/bar.go index fd9852c..a8cf446 100644 --- a/bar.go +++ b/bar.go @@ -73,7 +73,7 @@ trimRightCh: make(chan bool), stateReqCh: make(chan chan state, 1), decoratorCh: make(chan *decorator), - flushedCh: make(chan struct{}), + flushedCh: make(chan struct{}, 1), removeReqCh: make(chan struct{}), done: make(chan struct{}), } @@ -92,17 +92,19 @@ // TrimLeftSpace removes space befor LeftEnd charater func (b *Bar) TrimLeftSpace() *Bar { - if !b.isDone() { - b.trimLeftCh <- true - } + if IsClosed(b.done) { + return b + } + b.trimLeftCh <- true return b } // TrimRightSpace removes space after RightEnd charater func (b *Bar) TrimRightSpace() *Bar { - if !b.isDone() { - b.trimRightCh <- true - } + if IsClosed(b.done) { + return b + } + b.trimRightCh <- true return b } @@ -156,7 +158,10 @@ // Incr increments progress bar func (b *Bar) Incr(n int) { - if n > 0 && !b.isDone() { + if IsClosed(b.done) { + return + } + if n > 0 { b.incrCh <- int64(n) } } @@ -171,7 +176,7 @@ // Current returns the actual current. func (b *Bar) Current() int64 { - if b.isDone() { + if IsClosed(b.done) { return b.lastState.current } ch := make(chan state, 1) @@ -183,42 +188,48 @@ // InProgress returns true, while progress is running // Can be used as condition in for loop func (b *Bar) InProgress() bool { - return !b.isDone() + return !IsClosed(b.done) } // PrependFunc prepends DecoratorFunc func (b *Bar) PrependFunc(f DecoratorFunc) *Bar { - if !b.isDone() { - b.decoratorCh <- &decorator{decPrepend, f} - } - return b -} - + if IsClosed(b.done) { + return b + } + b.decoratorCh <- &decorator{decPrepend, f} + return b +} + +// RemoveAllPrependers removes all prepend functions func (b *Bar) RemoveAllPrependers() { - if !b.isDone() { - b.decoratorCh <- &decorator{decPrependZero, nil} - } + if IsClosed(b.done) { + return + } + b.decoratorCh <- &decorator{decPrependZero, nil} } // AppendFunc appends DecoratorFunc func (b *Bar) AppendFunc(f DecoratorFunc) *Bar { - if !b.isDone() { - b.decoratorCh <- &decorator{decAppend, f} - } - return b -} - + if IsClosed(b.done) { + return b + } + b.decoratorCh <- &decorator{decAppend, f} + return b +} + +// RemoveAllAppenders removes all append functions func (b *Bar) RemoveAllAppenders() { - if !b.isDone() { - b.decoratorCh <- &decorator{decAppendZero, nil} - } + if IsClosed(b.done) { + return + } + b.decoratorCh <- &decorator{decAppendZero, nil} } func (b *Bar) bytes(width int) []byte { if width <= 0 { width = b.width } - if b.isDone() { + if IsClosed(b.done) { return b.draw(b.lastState, width) } ch := make(chan state, 1) @@ -284,16 +295,18 @@ close(b.done) } -func (b *Bar) flushDone() { - if !b.isDone() { - b.flushedCh <- struct{}{} - } +func (b *Bar) flushed() { + if IsClosed(b.done) { + return + } + b.flushedCh <- struct{}{} } func (b *Bar) remove() { - if !b.isDone() { - b.removeReqCh <- struct{}{} - } + if IsClosed(b.done) { + return + } + b.removeReqCh <- struct{}{} } func (b *Bar) draw(s state, termWidth int) []byte { @@ -385,18 +398,9 @@ return buf } -func (b *Bar) isDone() bool { - select { - case <-b.done: - return true - default: - return false - } -} - func (b *Bar) status() int { var total, current int64 - if b.isDone() { + if IsClosed(b.done) { total = b.lastState.total current = b.lastState.current } else { diff --git a/progress.go b/progress.go index 0032067..c78f70b 100644 --- a/progress.go +++ b/progress.go @@ -104,7 +104,7 @@ // SetOut sets underlying writer of progress. Default is os.Stdout // pancis, if called on stopped Progress instance, i.e after Stop() func (p *Progress) SetOut(w io.Writer) *Progress { - if p.isDone() { + if IsClosed(p.done) { panic(ErrCallAfterStop) } if w == nil { @@ -117,7 +117,7 @@ // RefreshRate overrides default (30ms) refreshRate value // pancis, if called on stopped Progress instance, i.e after Stop() func (p *Progress) RefreshRate(d time.Duration) *Progress { - if p.isDone() { + if IsClosed(p.done) { panic(ErrCallAfterStop) } p.rrChangeReqCh <- d @@ -133,7 +133,7 @@ // AddBar creates a new progress bar and adds to the container // pancis, if called on stopped Progress instance, i.e after Stop() func (p *Progress) AddBar(total int64) *Bar { - if p.isDone() { + if IsClosed(p.done) { panic(ErrCallAfterStop) } result := make(chan bool) @@ -148,7 +148,7 @@ // RemoveBar removes bar at any time // pancis, if called on stopped Progress instance, i.e after Stop() func (p *Progress) RemoveBar(b *Bar) bool { - if p.isDone() { + if IsClosed(p.done) { panic(ErrCallAfterStop) } result := make(chan bool) @@ -159,7 +159,7 @@ // BarCount returns bars count in the container. // Pancis if called on stopped Progress instance, i.e after Stop() func (p *Progress) BarCount() int { - if p.isDone() { + if IsClosed(p.done) { panic(ErrCallAfterStop) } respCh := make(chan int) @@ -170,18 +170,10 @@ // Stop waits for bars to finish rendering and stops the rendering goroutine func (p *Progress) Stop() { p.wg.Wait() - if !p.isDone() { - close(p.operationCh) - } -} - -func (p *Progress) isDone() bool { - select { - case <-p.done: - return true - default: - return false - } + if IsClosed(p.done) { + return + } + close(p.operationCh) } // server monitors underlying channels and renders any progress bars @@ -254,9 +246,7 @@ cw.Flush() for _, b := range bars { - go func(b *Bar) { - b.flushDone() - }(b) + b.flushed() } case d := <-p.rrChangeReqCh: t.Stop() @@ -285,3 +275,14 @@ }() return ibars } + +// IsClosed check if ch closed +// caution see: http://www.tapirgames.com/blog/golang-channel-closing +func IsClosed(ch <-chan struct{}) bool { + select { + case <-ch: + return true + default: + return false + } +}