diff --git a/progressbar.go b/progressbar.go index 1e2866a..1cd3f37 100644 --- a/progressbar.go +++ b/progressbar.go @@ -113,6 +113,9 @@ type config struct { // whether the render function should make use of ANSI codes to reduce console I/O useANSICodes bool + // whether to use the IEC units (e.g. MiB) instead of the default SI units (e.g. MB) + useIECUnits bool + // showDescriptionAtLineEnd specifies whether description should be written at line end instead of line start showDescriptionAtLineEnd bool } @@ -284,6 +287,14 @@ func OptionUseANSICodes(val bool) Option { } } +// OptionUseIECUnits will enable IEC units (e.g. MiB) instead of the default +// SI units (e.g. MB). +func OptionUseIECUnits(val bool) Option { + return func(p *ProgressBar) { + p.config.useIECUnits = val + } +} + // OptionShowDescriptionAtLineEnd defines whether description should be written at line end instead of line start func OptionShowDescriptionAtLineEnd() Option { return func(p *ProgressBar) { @@ -331,7 +342,8 @@ func NewOptions64(max int64, options ...Option) *ProgressBar { b.config.predictTime = false } - b.config.maxHumanized, b.config.maxHumanizedSuffix = humanizeBytes(float64(b.config.max)) + b.config.maxHumanized, b.config.maxHumanizedSuffix = humanizeBytes(float64(b.config.max), + b.config.useIECUnits) if b.config.renderWithBlankState { b.RenderBlank() @@ -620,7 +632,8 @@ func (p *ProgressBar) ChangeMax64(newMax int64) { p.config.max = newMax if p.config.showBytes { - p.config.maxHumanized, p.config.maxHumanizedSuffix = humanizeBytes(float64(p.config.max)) + p.config.maxHumanized, p.config.maxHumanizedSuffix = humanizeBytes(float64(p.config.max), + p.config.useIECUnits) } p.Add(0) // re-render @@ -750,7 +763,7 @@ func renderProgressBar(c config, s *state) (int, error) { } if !c.ignoreLength { if c.showBytes { - currentHumanize, currentSuffix := humanizeBytes(s.currentBytes) + currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits) if currentSuffix == c.maxHumanizedSuffix { sb.WriteString(fmt.Sprintf("%s/%s%s", currentHumanize, c.maxHumanized, c.maxHumanizedSuffix)) @@ -763,7 +776,7 @@ func renderProgressBar(c config, s *state) (int, error) { } } else { if c.showBytes { - currentHumanize, currentSuffix := humanizeBytes(s.currentBytes) + currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits) sb.WriteString(fmt.Sprintf("%s%s", currentHumanize, currentSuffix)) } else { sb.WriteString(fmt.Sprintf("%.0f/%s", s.currentBytes, "-")) @@ -778,7 +791,7 @@ func renderProgressBar(c config, s *state) (int, error) { } else { sb.WriteString(", ") } - currentHumanize, currentSuffix := humanizeBytes(averageRate) + currentHumanize, currentSuffix := humanizeBytes(averageRate, c.useIECUnits) sb.WriteString(fmt.Sprintf("%s%s/s", currentHumanize, currentSuffix)) } @@ -1065,9 +1078,15 @@ func average(xs []float64) float64 { return total / float64(len(xs)) } -func humanizeBytes(s float64) (string, string) { +func humanizeBytes(s float64, iec bool) (string, string) { sizes := []string{" B", " kB", " MB", " GB", " TB", " PB", " EB"} - base := 1024.0 + base := 1000.0 + + if iec { + sizes = []string{" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"} + base = 1024.0 + } + if s < 10 { return fmt.Sprintf("%2.0f", s), sizes[0] } diff --git a/progressbar_test.go b/progressbar_test.go index ff073a7..88acd78 100644 --- a/progressbar_test.go +++ b/progressbar_test.go @@ -323,14 +323,14 @@ func TestBarSmallBytes(t *testing.T) { time.Sleep(100 * time.Millisecond) bar.Add(1000) } - if !strings.Contains(buf.String(), "8.8 kB/95 MB") { + if !strings.Contains(buf.String(), "9.0 kB/100 MB") { t.Errorf("wrong string: %s", buf.String()) } for i := 1; i < 10; i++ { time.Sleep(10 * time.Millisecond) bar.Add(1000000) } - if !strings.Contains(buf.String(), "8.6/95 MB") { + if !strings.Contains(buf.String(), "9.0/100 MB") { t.Errorf("wrong string: %s", buf.String()) } } @@ -823,3 +823,19 @@ func TestOptionFullWidth(t *testing.T) { }) } } + +func TestHumanizeBytesSI(t *testing.T) { + amount, suffix := humanizeBytes(float64(12.34)*1000*1000, false) + assert.Equal(t, "12 MB", fmt.Sprintf("%s%s", amount, suffix)) + + amount, suffix = humanizeBytes(float64(56.78)*1000*1000*1000, false) + assert.Equal(t, "57 GB", fmt.Sprintf("%s%s", amount, suffix)) +} + +func TestHumanizeBytesIEC(t *testing.T) { + amount, suffix := humanizeBytes(float64(12.34)*1024*1024, true) + assert.Equal(t, "12 MiB", fmt.Sprintf("%s%s", amount, suffix)) + + amount, suffix = humanizeBytes(float64(56.78)*1024*1024*1024, true) + assert.Equal(t, "57 GiB", fmt.Sprintf("%s%s", amount, suffix)) +}