Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use strings.Builder for bar string composition #143

Merged
merged 3 commits into from Nov 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 49 additions & 52 deletions progressbar.go
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"os"
"regexp"
Expand Down Expand Up @@ -378,7 +377,7 @@ func DefaultBytesSilent(maxBytes int64, description ...string) *ProgressBar {
return NewOptions64(
maxBytes,
OptionSetDescription(desc),
OptionSetWriter(ioutil.Discard),
OptionSetWriter(io.Discard),
OptionShowBytes(true),
OptionSetWidth(10),
OptionThrottle(65*time.Millisecond),
Expand Down Expand Up @@ -424,7 +423,7 @@ func DefaultSilent(max int64, description ...string) *ProgressBar {
return NewOptions64(
max,
OptionSetDescription(desc),
OptionSetWriter(ioutil.Discard),
OptionSetWriter(io.Discard),
OptionSetWidth(10),
OptionThrottle(65*time.Millisecond),
OptionShowCount(),
Expand Down Expand Up @@ -708,12 +707,7 @@ func getStringWidth(c config, str string, colorize bool) int {
}

func renderProgressBar(c config, s *state) (int, error) {
leftBrac := ""
rightBrac := ""
saucer := ""
saucerHead := ""
bytesString := ""
str := ""
var sb strings.Builder

averageRate := average(s.counterLastTenRates)
if len(s.counterLastTenRates) == 0 || s.finished {
Expand All @@ -728,62 +722,66 @@ func renderProgressBar(c config, s *state) (int, error) {

// show iteration count in "current/total" iterations format
if c.showIterationsCount {
if bytesString == "" {
bytesString += "("
if sb.Len() == 0 {
sb.WriteString("(")
} else {
bytesString += ", "
sb.WriteString(", ")
}
if !c.ignoreLength {
if c.showBytes {
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes)
if currentSuffix == c.maxHumanizedSuffix {
bytesString += fmt.Sprintf("%s/%s%s", currentHumanize, c.maxHumanized, c.maxHumanizedSuffix)
sb.WriteString(fmt.Sprintf("%s/%s%s",
currentHumanize, c.maxHumanized, c.maxHumanizedSuffix))
} else {
bytesString += fmt.Sprintf("%s%s/%s%s", currentHumanize, currentSuffix, c.maxHumanized, c.maxHumanizedSuffix)
sb.WriteString(fmt.Sprintf("%s%s/%s%s",
currentHumanize, currentSuffix, c.maxHumanized, c.maxHumanizedSuffix))
}
} else {
bytesString += fmt.Sprintf("%.0f/%d", s.currentBytes, c.max)
sb.WriteString(fmt.Sprintf("%.0f/%d", s.currentBytes, c.max))
}
} else {
if c.showBytes {
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes)
bytesString += fmt.Sprintf("%s%s", currentHumanize, currentSuffix)
sb.WriteString(fmt.Sprintf("%s%s", currentHumanize, currentSuffix))
} else {
bytesString += fmt.Sprintf("%.0f/%s", s.currentBytes, "-")
sb.WriteString(fmt.Sprintf("%.0f/%s", s.currentBytes, "-"))
}
}
}

// show rolling average rate
if c.showBytes && averageRate > 0 && !math.IsInf(averageRate, 1) {
if bytesString == "" {
bytesString += "("
if sb.Len() == 0 {
sb.WriteString("(")
} else {
bytesString += ", "
sb.WriteString(", ")
}
currentHumanize, currentSuffix := humanizeBytes(averageRate)
bytesString += fmt.Sprintf("%s%s/s", currentHumanize, currentSuffix)
sb.WriteString(fmt.Sprintf("%s%s/s", currentHumanize, currentSuffix))
}

// show iterations rate
if c.showIterationsPerSecond {
if bytesString == "" {
bytesString += "("
if sb.Len() == 0 {
sb.WriteString("(")
} else {
bytesString += ", "
sb.WriteString(", ")
}
if averageRate > 1 {
bytesString += fmt.Sprintf("%0.0f %s/s", averageRate, c.iterationString)
sb.WriteString(fmt.Sprintf("%0.0f %s/s", averageRate, c.iterationString))
} else if averageRate*60 > 1 {
bytesString += fmt.Sprintf("%0.0f %s/min", 60*averageRate, c.iterationString)
sb.WriteString(fmt.Sprintf("%0.0f %s/min", 60*averageRate, c.iterationString))
} else {
bytesString += fmt.Sprintf("%0.0f %s/hr", 3600*averageRate, c.iterationString)
sb.WriteString(fmt.Sprintf("%0.0f %s/hr", 3600*averageRate, c.iterationString))
}
}
if bytesString != "" {
bytesString += ")"
if sb.Len() != 0 {
sb.WriteString(")")
}

leftBrac, rightBrac, saucer, saucerHead := "", "", "", ""

// show time prediction in "current/total" seconds format
switch {
case c.predictTime:
Expand All @@ -806,7 +804,7 @@ func renderProgressBar(c config, s *state) (int, error) {
}
}

c.width = width - getStringWidth(c, c.description, true) - 14 - len(bytesString) - len(leftBrac) - len(rightBrac)
c.width = width - getStringWidth(c, c.description, true) - 14 - sb.Len() - len(leftBrac) - len(rightBrac)
s.currentSaucerSize = int(float64(s.currentPercent) / 100.0 * float64(c.width))
}
if s.currentSaucerSize > 0 {
Expand All @@ -828,7 +826,6 @@ func renderProgressBar(c config, s *state) (int, error) {
saucerHead = c.theme.SaucerHead
s.isAltSaucerHead = true
}
saucer += saucerHead
}

/*
Expand All @@ -838,52 +835,52 @@ func renderProgressBar(c config, s *state) (int, error) {
or if showDescriptionAtLineEnd is enabled
% |------ | (kb/s) (iteration count) (iteration rate) (predict time) Description
*/

repeatAmount := c.width - s.currentSaucerSize
if repeatAmount < 0 {
repeatAmount = 0
}

str := ""

if c.ignoreLength {
spinner := spinners[c.spinnerType][int(math.Round(math.Mod(float64(time.Since(s.startTime).Milliseconds()/100), float64(len(spinners[c.spinnerType])))))]
if c.elapsedTime {
if c.showDescriptionAtLineEnd {
str = fmt.Sprintf("\r%s %s [%s] %s ",
spinner,
bytesString,
sb.String(),
leftBrac,
c.description,
)
c.description)
} else {
str = fmt.Sprintf("\r%s %s %s [%s] ",
spinner,
c.description,
bytesString,
leftBrac,
)
sb.String(),
leftBrac)
}
} else {
if c.showDescriptionAtLineEnd {
str = fmt.Sprintf("\r%s %s %s ",
spinner,
bytesString,
c.description,
)
sb.String(),
c.description)
} else {
str = fmt.Sprintf("\r%s %s %s ",
spinner,
c.description,
bytesString,
)
sb.String())
}
}
} else if rightBrac == "" {
str = fmt.Sprintf("%4d%% %s%s%s%s %s",
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s",
s.currentPercent,
c.theme.BarStart,
saucer,
saucerHead,
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
c.theme.BarEnd,
bytesString,
)
sb.String())

if c.showDescriptionAtLineEnd {
str = fmt.Sprintf("\r%s %s ", str, c.description)
Expand All @@ -892,14 +889,14 @@ func renderProgressBar(c config, s *state) (int, error) {
}
} else {
if s.currentPercent == 100 {
str = fmt.Sprintf("%4d%% %s%s%s%s %s",
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s",
s.currentPercent,
c.theme.BarStart,
saucer,
saucerHead,
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
c.theme.BarEnd,
bytesString,
)
sb.String())
if c.showElapsedTimeOnFinish {
str = fmt.Sprintf("%s [%s]", str, leftBrac)
}
Expand All @@ -910,16 +907,16 @@ func renderProgressBar(c config, s *state) (int, error) {
str = fmt.Sprintf("\r%s%s", c.description, str)
}
} else {
str = fmt.Sprintf("%4d%% %s%s%s%s %s [%s:%s]",
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s [%s:%s]",
s.currentPercent,
c.theme.BarStart,
saucer,
saucerHead,
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
c.theme.BarEnd,
bytesString,
sb.String(),
leftBrac,
rightBrac,
)
rightBrac)

if c.showDescriptionAtLineEnd {
str = fmt.Sprintf("\r%s %s", str, c.description)
Expand Down
11 changes: 5 additions & 6 deletions progressbar_test.go
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
Expand Down Expand Up @@ -331,7 +330,7 @@ func TestBasicSets(t *testing.T) {
OptionSetWidth(888),
OptionSetRenderBlankState(true),

OptionSetWriter(ioutil.Discard), // suppressing output for this test
OptionSetWriter(io.Discard), // suppressing output for this test
)

tc := b.config
Expand Down Expand Up @@ -494,7 +493,7 @@ func TestReaderToFile(t *testing.T) {
assert.Nil(t, err)
defer resp.Body.Close()

f, err := ioutil.TempFile("", "progressbar_testfile")
f, err := os.CreateTemp("", "progressbar_testfile")
if err != nil {
t.Fatal()
}
Expand All @@ -520,7 +519,7 @@ func TestReaderToFile(t *testing.T) {
t.Fatal(err)
}

b, err := ioutil.ReadAll(r)
b, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -548,7 +547,7 @@ func TestReaderToFileUnknownLength(t *testing.T) {
assert.Nil(t, err)
defer resp.Body.Close()

f, err := ioutil.TempFile("", "progressbar_testfile")
f, err := os.CreateTemp("", "progressbar_testfile")
if err != nil {
t.Fatal()
}
Expand All @@ -574,7 +573,7 @@ func TestReaderToFileUnknownLength(t *testing.T) {
t.Fatal(err)
}

b, err := ioutil.ReadAll(r)
b, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
Expand Down