package progress import ( "fmt" "os" "strings" "time" "gitlab.com/rhogenson/vecdeque" "golang.org/x/term" ) const measurements = 20 type measurement struct { t time.Time i int } type Bar struct { max int measurements vecdeque.DQ[measurement] cols int } func New(max int) *Bar { b := &Bar{max: max} b.measurements.Grow(measurements) return b } func (b *Bar) Set(i int) { if b.measurements.Len() == measurements { b.measurements.PopFront() } b.measurements.PushBack(measurement{time.Now(), i}) } func (b *Bar) Print() { first := b.measurements.Get(0) last := b.measurements.Get(b.measurements.Len() - 1) deltaT := last.t.Sub(first.t) delta := last.i - first.i eta := time.Duration(-1) if delta != 0 { eta = time.Duration(float64(b.max-last.i) / float64(delta) * float64(deltaT)) } if b.cols == 0 { var err error if b.cols, _, err = term.GetSize(int(os.Stderr.Fd())); err != nil { fmt.Fprintf(os.Stderr, "Warning: unable to determine terminal size: %s\n", err) } } else { p := last.i * b.cols / b.max fmt.Fprintf(os.Stderr, "\033[2F\033[J%s>\n", strings.Repeat("=", max(p-1, 0))) } if eta < 0 { fmt.Fprintln(os.Stderr, "ETA: calculating...") } else { fmt.Fprintf(os.Stderr, "ETA: %s\n", eta.Round(time.Second)) } }