progress.go 905 B

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. package progress
  2. import (
  3. "fmt"
  4. "io"
  5. "sync"
  6. "time"
  7. )
  8. type State interface {
  9. String() string
  10. }
  11. type Progress struct {
  12. mu sync.Mutex
  13. pos int
  14. w io.Writer
  15. ticker *time.Ticker
  16. states []State
  17. }
  18. func NewProgress(w io.Writer) *Progress {
  19. p := &Progress{pos: -1, w: w}
  20. go p.start()
  21. return p
  22. }
  23. func (p *Progress) Stop() {
  24. if p.ticker != nil {
  25. p.ticker.Stop()
  26. p.ticker = nil
  27. p.render()
  28. }
  29. }
  30. func (p *Progress) Add(key string, state State) {
  31. p.mu.Lock()
  32. defer p.mu.Unlock()
  33. p.states = append(p.states, state)
  34. }
  35. func (p *Progress) render() error {
  36. p.mu.Lock()
  37. defer p.mu.Unlock()
  38. fmt.Fprintf(p.w, "\033[%dA", p.pos)
  39. for _, state := range p.states {
  40. fmt.Fprintln(p.w, state.String())
  41. }
  42. if len(p.states) > 0 {
  43. p.pos = len(p.states)
  44. }
  45. return nil
  46. }
  47. func (p *Progress) start() {
  48. p.ticker = time.NewTicker(100 * time.Millisecond)
  49. for range p.ticker.C {
  50. p.render()
  51. }
  52. }