1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- package progress
- import (
- "fmt"
- "io"
- "sync"
- "time"
- )
- type State interface {
- String() string
- }
- type Progress struct {
- mu sync.Mutex
- pos int
- w io.Writer
- ticker *time.Ticker
- states []State
- }
- func NewProgress(w io.Writer) *Progress {
- p := &Progress{w: w}
- go p.start()
- return p
- }
- func (p *Progress) Stop() bool {
- for _, state := range p.states {
- if spinner, ok := state.(*Spinner); ok {
- spinner.Stop()
- }
- }
- if p.ticker != nil {
- p.ticker.Stop()
- p.ticker = nil
- p.render()
- return true
- }
- return false
- }
- func (p *Progress) StopAndClear() bool {
- fmt.Fprint(p.w, "\033[?25l")
- defer fmt.Fprint(p.w, "\033[?25h")
- stopped := p.Stop()
- if stopped {
- // clear the progress bar by:
- // 1. for each line in the progress:
- // a. move the cursor up one line
- // b. clear the line
- for i := 0; i < p.pos; i++ {
- fmt.Fprint(p.w, "\033[A\033[2K")
- }
- }
- return stopped
- }
- func (p *Progress) Add(key string, state State) {
- p.mu.Lock()
- defer p.mu.Unlock()
- p.states = append(p.states, state)
- }
- func (p *Progress) render() error {
- p.mu.Lock()
- defer p.mu.Unlock()
- fmt.Fprint(p.w, "\033[?25l")
- defer fmt.Fprint(p.w, "\033[?25h")
- if p.pos > 0 {
- fmt.Fprintf(p.w, "\033[%dA", p.pos)
- }
- for _, state := range p.states {
- fmt.Fprintln(p.w, state.String())
- }
- if len(p.states) > 0 {
- p.pos = len(p.states)
- }
- return nil
- }
- func (p *Progress) start() {
- p.ticker = time.NewTicker(100 * time.Millisecond)
- for range p.ticker.C {
- p.render()
- }
- }
|