diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-04-05 13:45:16 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-04-05 13:45:16 -0700 |
| commit | 3f578882a651f74d4e701d8682e6c76752da76b5 (patch) | |
| tree | 5df45d42b57127e088d3d71576938ad091669ea8 /progress.go | |
| parent | Initial commit (diff) | |
| download | progress-bar-3f578882a651f74d4e701d8682e6c76752da76b5.tar.zst | |
Refactor into reusable libraries
Diffstat (limited to 'progress.go')
| -rw-r--r-- | progress.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/progress.go b/progress.go new file mode 100644 index 0000000..7660605 --- /dev/null +++ b/progress.go @@ -0,0 +1,63 @@ +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)) + } +} |
