diff --git a/container_option.go b/container_option.go index da0e9b1..92bddba 100644 --- a/container_option.go +++ b/container_option.go @@ -72,14 +72,11 @@ // will effectively disable auto refresh rate and discard any output, // useful if you want to disable progress bars with little overhead. func WithOutput(w io.Writer) ContainerOption { - var discarded bool if w == nil { w = io.Discard - discarded = true } return func(s *pState) { s.output = w - s.outputDiscarded = discarded } } diff --git a/cwriter/writer.go b/cwriter/writer.go index 35136de..23a72d3 100644 --- a/cwriter/writer.go +++ b/cwriter/writer.go @@ -40,6 +40,11 @@ return w } +// IsTerminal tells whether underlying io.Writer is terminal. +func (w *Writer) IsTerminal() bool { + return w.terminal +} + // GetTermSize returns WxH of underlying terminal. func (w *Writer) GetTermSize() (width, height int, err error) { return w.termSize(w.fd) diff --git a/progress.go b/progress.go index 0782f41..8304023 100644 --- a/progress.go +++ b/progress.go @@ -43,12 +43,10 @@ reqWidth int popPriority int popCompleted bool - outputDiscarded bool disableAutoRefresh bool - ignoreNotTTY bool manualRefresh chan interface{} renderDelay <-chan struct{} - shutdownNotifier chan struct{} + shutdownNotifier chan<- interface{} queueBars map[*Bar]*Bar output io.Writer debugOut io.Writer @@ -90,14 +88,8 @@ operateState: make(chan func(*pState)), interceptIo: make(chan func(io.Writer)), done: make(chan struct{}), + shutdown: make(chan struct{}), cancel: cancel, - } - - if s.shutdownNotifier != nil { - p.shutdown = s.shutdownNotifier - s.shutdownNotifier = nil - } else { - p.shutdown = make(chan struct{}) } go p.serve(s, cwriter.New(s.output)) @@ -233,11 +225,11 @@ <-p.shutdown } -func (p *Progress) newTicker(s *pState) chan time.Time { +func (p *Progress) newTicker(s *pState, isTerminal bool) chan time.Time { ch := make(chan time.Time) go func() { var autoRefresh <-chan time.Time - if !s.disableAutoRefresh && !s.outputDiscarded { + if isTerminal && !s.disableAutoRefresh { if s.renderDelay != nil { <-s.renderDelay } @@ -265,10 +257,13 @@ } func (p *Progress) serve(s *pState, cw *cwriter.Writer) { + render := func() error { + return s.render(cw) + } go s.hm.run() - refreshCh := p.newTicker(s) + refreshCh := p.newTicker(s, cw.IsTerminal()) for { select { @@ -277,26 +272,34 @@ case fn := <-p.interceptIo: fn(cw) case <-refreshCh: - err := s.render(cw) + err := render() if err != nil { - refreshCh = nil _, _ = fmt.Fprintln(s.debugOut, err.Error()) + render = func() error { return nil } p.cancel() // cancel all bars } case <-p.done: - close(s.hm) + if s.shutdownNotifier != nil { + go func() { + s.shutdownNotifier <- s.hm.end() + }() + } else { + close(s.hm) + } close(p.shutdown) return } } } -func (s *pState) render(cw *cwriter.Writer) error { - width, height, err := cw.GetTermSize() - if err != nil { - if !s.ignoreNotTTY { +func (s *pState) render(cw *cwriter.Writer) (err error) { + var width, height int + if cw.IsTerminal() { + width, height, err = cw.GetTermSize() + if err != nil { return err } + } else { width = s.reqWidth height = 100 }