diff --git a/progress.go b/progress.go index 37b8863..0df63b0 100644 --- a/progress.go +++ b/progress.go @@ -9,76 +9,87 @@ "github.com/gosuri/uilive" ) -// Out is the default writer to render progress bars to -// var Out = os.Stdout - -// RefreshInterval in the default time duration to wait for refreshing the output -var RefreshInterval = time.Millisecond * 10 - -// Progress represents the container that renders progress bars -type Progress struct { - // Out is the writer to render progress bars to +// progress represents the container that renders progress bars +type progress struct { + // out is the writer to render progress bars to out io.Writer // Width is the width of the progress bars // Width int - // Bars is the collection of progress bars - // Bars []*Bar + lw *uilive.Writer - // RefreshInterval in the time duration to wait for refreshing the output - // RefreshInterval time.Duration + // new Bars can be added over this channel + bars chan *Bar - lw *uilive.Writer - // stopChan chan struct{} - // mtx *sync.RWMutex - bars chan *Bar - ticker *time.Ticker + // new refresh interval to be send over this channel + interval chan time.Duration } // New returns a new progress bar with defaults -func New() *Progress { - p := &Progress{ - out: os.Stdout, - lw: uilive.New(), - bars: make(chan *Bar), - ticker: time.NewTicker(RefreshInterval), +func New() *progress { + p := &progress{ + out: os.Stdout, + lw: uilive.New(), + bars: make(chan *Bar), + interval: make(chan time.Duration), } go p.server() return p } -// SetOut is the writer to render progress bars to -func (p *Progress) SetOut(w io.Writer) *Progress { +// RefreshInterval overrides default interval value 30 ms +func (p *progress) RefreshInterval(d time.Duration) *progress { + p.interval <- d + return p +} + +// SetOut sets underlying writer of progress +// default is os.Stdout +func (p *progress) SetOut(w io.Writer) *progress { p.out = w return p } // AddBar creates a new progress bar and adds to the container -func (p *Progress) AddBar(total int) *Bar { +func (p *progress) AddBar(total int) *Bar { bar := NewBar(total) // bar.Width = p.Width p.bars <- bar return bar } -// Listen listens for updates and renders the progress bars -func (p *Progress) server() { +// Bypass returns a writer which allows non-buffered data to be written to the underlying output +func (p *progress) Bypass() io.Writer { + return p.lw.Bypass() +} + +// Stop stops listening +func (p *progress) Stop() { + close(p.bars) +} + +// server listens for updates and renders the progress bars +func (p *progress) server() { + t := time.NewTicker(30 * time.Millisecond) bars := make([]*Bar, 0) p.lw.Out = p.out -loop: for { select { case bar, ok := <-p.bars: if !ok { - break loop + t.Stop() + return } bars = append(bars, bar) - case <-p.ticker.C: + case <-t.C: for _, bar := range bars { fmt.Fprintln(p.lw, bar.String()) } p.lw.Flush() + case d := <-p.interval: + t.Stop() + t = time.NewTicker(d) } } }