go.modgo.summodules.txt
vendor
dario.cat
github.com
ProtonMail
go-crypto
ocb
openpgp
armor
canonical_text.goecdh
ed25519
ed448
errors
internal
key_generation.gokeys.gopacket
aead_crypter.gocompressed.goconfig.goconfig_v5.goencrypted_key.goliteral.gomarker.goone_pass_signature.goopaque.gopacket.gopacket_sequence.gopacket_unsupported.gopadding.goprivate_key.gopublic_key.goreader.gorecipient.gosignature.gosymmetric_key_encrypted.gosymmetrically_encrypted.gosymmetrically_encrypted_aead.gosymmetrically_encrypted_mdc.gouserattribute.gouserid.go
read.goread_write_test_data.gos2k
write.gox25519
x448
charmbracelet
lipgloss
x
ansi
cloudflare
containerd
containerd
cyphar
filepath-securejoin
docker
cli
docker
go-git
go-billy
go-viper
mapstructure
grpc-ecosystem
grpc-gateway
klauspost
compress
mattn
go-runewidth
moby
sys
prometheus
schollz
progressbar
skeema
knownhosts
stretchr
go.opentelemetry.io
contrib
instrumentation
net
http
otelhttp
otel
.gitignore.golangci.ymlCHANGELOG.mdCODEOWNERSCONTRIBUTING.mdMakefileREADME.mdRELEASING.md
attribute
baggage
codes
doc.goexporters
otlp
otlpmetric
otlpmetricgrpc
otlptrace
internal
metric
renovate.jsonsdk
instrumentation
metric
config.godoc.goexemplar.gomanual_reader.gometer.goperiodic_reader.gopipeline.goprovider.goreader.goversion.goview.go
exemplar
README.mddoc.goexemplar.gofilter.gofixed_size_reservoir.gohistogram_reservoir.goreservoir.gostorage.govalue.go
instrument.gointernal
aggregate
aggregate.godrop.goexemplar.goexponential_histogram.gofiltered_reservoir.gohistogram.golastvalue.gosum.go
exemplar
x
resource
trace
version.gosemconv
trace
verify_examples.shverify_released_changelog.shversion.goversions.yamlgolang.org
x
crypto
exp
net
LICENSE
http2
sync
sys
LICENSE
cpu
asm_darwin_x86_gc.scpu.gocpu_arm64.gocpu_darwin_x86.gocpu_gc_x86.gocpu_gc_x86.scpu_gccgo_x86.gocpu_linux_arm64.gocpu_linux_noinit.gocpu_linux_riscv64.gocpu_other_x86.gocpu_riscv64.gocpu_x86.gosyscall_darwin_x86_gc.go
unix
README.mdioctl_linux.gomkerrors.shsyscall_aix.gosyscall_darwin.gosyscall_hurd.gosyscall_linux.gosyscall_linux_arm64.gosyscall_linux_loong64.gosyscall_linux_riscv64.gosyscall_openbsd.gosyscall_zos_s390x.govgetrandom_linux.govgetrandom_unsupported.gozerrors_darwin_amd64.gozerrors_darwin_arm64.gozerrors_linux.gozerrors_linux_386.gozerrors_linux_amd64.gozerrors_linux_arm.gozerrors_linux_arm64.gozerrors_linux_loong64.gozerrors_linux_mips.gozerrors_linux_mips64.gozerrors_linux_mips64le.gozerrors_linux_mipsle.gozerrors_linux_ppc.gozerrors_linux_ppc64.gozerrors_linux_ppc64le.gozerrors_linux_riscv64.gozerrors_linux_s390x.gozerrors_linux_sparc64.gozerrors_zos_s390x.gozsyscall_darwin_amd64.gozsyscall_darwin_amd64.szsyscall_darwin_arm64.gozsyscall_darwin_arm64.szsyscall_linux.gozsyscall_openbsd_386.gozsyscall_openbsd_386.szsyscall_openbsd_amd64.gozsyscall_openbsd_amd64.szsyscall_openbsd_arm.gozsyscall_openbsd_arm.szsyscall_openbsd_arm64.gozsyscall_openbsd_arm64.szsyscall_openbsd_mips64.gozsyscall_openbsd_mips64.szsyscall_openbsd_ppc64.gozsyscall_openbsd_ppc64.szsyscall_openbsd_riscv64.gozsyscall_openbsd_riscv64.szsysnum_linux_386.gozsysnum_linux_amd64.gozsysnum_linux_arm.gozsysnum_linux_arm64.gozsysnum_linux_loong64.gozsysnum_linux_mips.gozsysnum_linux_mips64.gozsysnum_linux_mips64le.gozsysnum_linux_mipsle.gozsysnum_linux_ppc.gozsysnum_linux_ppc64.gozsysnum_linux_ppc64le.gozsysnum_linux_riscv64.gozsysnum_linux_s390x.gozsysnum_linux_sparc64.goztypes_darwin_amd64.goztypes_darwin_arm64.goztypes_freebsd_386.goztypes_freebsd_amd64.goztypes_freebsd_arm.goztypes_freebsd_arm64.goztypes_freebsd_riscv64.goztypes_linux.goztypes_linux_riscv64.goztypes_zos_s390x.go
windows
term
text
time
google.golang.org
grpc
CONTRIBUTING.mdMAINTAINERS.mdSECURITY.mdclientconn.gocodec.go
backoff
balancer
balancer_wrapper.gobinarylog
grpc_binarylog_v1
credentials
dialoptions.godoc.goencoding
experimental
grpclog
health
grpc_health_v1
internal
balancer
gracefulswitch
binarylog
channelz
envconfig
experimental.gogrpclog
grpcsync
grpcutil
idle
internal.goresolver
stats
status
syscall
tcp_keepalive_unix.gotcp_keepalive_windows.gotransport
keepalive
mem
metadata
preloader.goregenerate.shresolver_wrapper.gorpc_util.goserver.goshared_buffer_pool.gostats
stream.gostream_interfaces.goversion.goprotobuf
encoding
internal
descopts
editiondefaults
filedesc
genid
impl
codec_extension.gocodec_field.gocodec_message.gocodec_reflect.gocodec_unsafe.goconvert.goencode.goequal.golegacy_extension.gomessage.gopointer_reflect.gopointer_unsafe.go
strs
version
proto
reflect
runtime
protoiface
types
known
anypb
durationpb
fieldmaskpb
structpb
timestamppb
wrapperspb
361
vendor/github.com/schollz/progressbar/v3/progressbar.go
generated
vendored
361
vendor/github.com/schollz/progressbar/v3/progressbar.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package progressbar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -44,17 +45,20 @@ type state struct {
|
||||
isAltSaucerHead bool
|
||||
|
||||
lastShown time.Time
|
||||
startTime time.Time
|
||||
startTime time.Time // time when the progress bar start working
|
||||
|
||||
counterTime time.Time
|
||||
counterNumSinceLast int64
|
||||
counterLastTenRates []float64
|
||||
spinnerIdx int // the index of spinner
|
||||
|
||||
maxLineWidth int
|
||||
currentBytes float64
|
||||
finished bool
|
||||
exit bool // Progress bar exit halfway
|
||||
|
||||
details []string // details to show,only used when detail row is set to more than 0
|
||||
|
||||
rendered string
|
||||
}
|
||||
|
||||
@ -79,6 +83,9 @@ type config struct {
|
||||
showIterationsPerSecond bool
|
||||
showIterationsCount bool
|
||||
|
||||
// whether the progress bar should show the total bytes (e.g. 23/24 or 23/-, vs. just 23).
|
||||
showTotalBytes bool
|
||||
|
||||
// whether the progress bar should show elapsed time.
|
||||
// always enabled if predictTime is true.
|
||||
elapsedTime bool
|
||||
@ -102,6 +109,11 @@ type config struct {
|
||||
// spinnerTypeOptionUsed remembers if the spinnerType was changed manually
|
||||
spinnerTypeOptionUsed bool
|
||||
|
||||
// spinnerChangeInterval the change interval of spinner
|
||||
// if set this attribute to 0, the spinner only change when renderProgressBar was called
|
||||
// for example, each time when Add() was called,which will call renderProgressBar function
|
||||
spinnerChangeInterval time.Duration
|
||||
|
||||
// spinner represents the spinner as a slice of string
|
||||
spinner []string
|
||||
|
||||
@ -121,6 +133,11 @@ type config struct {
|
||||
|
||||
// showDescriptionAtLineEnd specifies whether description should be written at line end instead of line start
|
||||
showDescriptionAtLineEnd bool
|
||||
|
||||
// specifies how many rows of details to show,default value is 0 and no details will be shown
|
||||
maxDetailRow int
|
||||
|
||||
stdBuffer bytes.Buffer
|
||||
}
|
||||
|
||||
// Theme defines the elements of the bar
|
||||
@ -131,8 +148,46 @@ type Theme struct {
|
||||
SaucerPadding string
|
||||
BarStart string
|
||||
BarEnd string
|
||||
|
||||
// BarStartFilled is used after the Bar starts filling, if set. Otherwise, it defaults to BarStart.
|
||||
BarStartFilled string
|
||||
|
||||
// BarEndFilled is used once the Bar finishes, if set. Otherwise, it defaults to BarEnd.
|
||||
BarEndFilled string
|
||||
}
|
||||
|
||||
var (
|
||||
// ThemeDefault is given by default (if not changed with OptionSetTheme), and it looks like "|████ |".
|
||||
ThemeDefault = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}
|
||||
|
||||
// ThemeASCII is a predefined Theme that uses ASCII symbols. It looks like "[===>...]".
|
||||
// Configure it with OptionSetTheme(ThemeASCII).
|
||||
ThemeASCII = Theme{
|
||||
Saucer: "=",
|
||||
SaucerHead: ">",
|
||||
SaucerPadding: ".",
|
||||
BarStart: "[",
|
||||
BarEnd: "]",
|
||||
}
|
||||
|
||||
// ThemeUnicode is a predefined Theme that uses Unicode characters, displaying a graphic bar.
|
||||
// It looks like "" (rendering will depend on font being used).
|
||||
// It requires special symbols usually found in "nerd fonts" [2], or in Fira Code [1], and other sources.
|
||||
// Configure it with OptionSetTheme(ThemeUnicode).
|
||||
//
|
||||
// [1] https://github.com/tonsky/FiraCode
|
||||
// [2] https://www.nerdfonts.com/
|
||||
ThemeUnicode = Theme{
|
||||
Saucer: "\uEE04", //
|
||||
SaucerHead: "\uEE04", //
|
||||
SaucerPadding: "\uEE01", //
|
||||
BarStart: "\uEE00", //
|
||||
BarStartFilled: "\uEE03", //
|
||||
BarEnd: "\uEE02", //
|
||||
BarEndFilled: "\uEE05", //
|
||||
}
|
||||
)
|
||||
|
||||
// Option is the type all options need to adhere to
|
||||
type Option func(p *ProgressBar)
|
||||
|
||||
@ -143,6 +198,18 @@ func OptionSetWidth(s int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetSpinnerChangeInterval sets the spinner change interval
|
||||
// the spinner will change according to this value.
|
||||
// By default, this value is 100 * time.Millisecond
|
||||
// If you don't want to let this progressbar update by specified time interval
|
||||
// you can set this value to zero, then the spinner will change each time rendered,
|
||||
// such as when Add() or Describe() was called
|
||||
func OptionSetSpinnerChangeInterval(interval time.Duration) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.spinnerChangeInterval = interval
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSpinnerType sets the type of spinner used for indeterminate bars
|
||||
func OptionSpinnerType(spinnerType int) Option {
|
||||
return func(p *ProgressBar) {
|
||||
@ -159,7 +226,8 @@ func OptionSpinnerCustom(spinner []string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetTheme sets the elements the bar is constructed of
|
||||
// OptionSetTheme sets the elements the bar is constructed with.
|
||||
// There are two pre-defined themes you can use: ThemeASCII and ThemeUnicode.
|
||||
func OptionSetTheme(t Theme) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.theme = t
|
||||
@ -237,13 +305,20 @@ func OptionShowIts() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// OptionShowElapsedOnFinish will keep the display of elapsed time on finish
|
||||
// OptionShowElapsedTimeOnFinish will keep the display of elapsed time on finish.
|
||||
func OptionShowElapsedTimeOnFinish() Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.showElapsedTimeOnFinish = true
|
||||
}
|
||||
}
|
||||
|
||||
// OptionShowTotalBytes will keep the display of total bytes.
|
||||
func OptionShowTotalBytes(flag bool) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.showTotalBytes = flag
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetItsString sets what's displayed for iterations a second. The default is "it" which would display: "it/s"
|
||||
func OptionSetItsString(iterationString string) Option {
|
||||
return func(p *ProgressBar) {
|
||||
@ -259,7 +334,7 @@ func OptionThrottle(duration time.Duration) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// OptionClearOnFinish will clear the bar once its finished
|
||||
// OptionClearOnFinish will clear the bar once its finished.
|
||||
func OptionClearOnFinish() Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.clearOnFinish = true
|
||||
@ -305,7 +380,13 @@ func OptionShowDescriptionAtLineEnd() Option {
|
||||
}
|
||||
}
|
||||
|
||||
var defaultTheme = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}
|
||||
// OptionSetMaxDetailRow sets the max row of details
|
||||
// the row count should be less than the terminal height, otherwise it will not give you the output you want
|
||||
func OptionSetMaxDetailRow(row int) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.maxDetailRow = row
|
||||
}
|
||||
}
|
||||
|
||||
// NewOptions constructs a new instance of ProgressBar, with any options you specify
|
||||
func NewOptions(max int, options ...Option) *ProgressBar {
|
||||
@ -315,18 +396,24 @@ func NewOptions(max int, options ...Option) *ProgressBar {
|
||||
// NewOptions64 constructs a new instance of ProgressBar, with any options you specify
|
||||
func NewOptions64(max int64, options ...Option) *ProgressBar {
|
||||
b := ProgressBar{
|
||||
state: getBasicState(),
|
||||
state: state{
|
||||
startTime: time.Time{},
|
||||
lastShown: time.Time{},
|
||||
counterTime: time.Time{},
|
||||
},
|
||||
config: config{
|
||||
writer: os.Stdout,
|
||||
theme: defaultTheme,
|
||||
iterationString: "it",
|
||||
width: 40,
|
||||
max: max,
|
||||
throttleDuration: 0 * time.Nanosecond,
|
||||
elapsedTime: max == -1,
|
||||
predictTime: true,
|
||||
spinnerType: 9,
|
||||
invisible: false,
|
||||
writer: os.Stdout,
|
||||
theme: ThemeDefault,
|
||||
iterationString: "it",
|
||||
width: 40,
|
||||
max: max,
|
||||
throttleDuration: 0 * time.Nanosecond,
|
||||
elapsedTime: max == -1,
|
||||
predictTime: true,
|
||||
spinnerType: 9,
|
||||
invisible: false,
|
||||
spinnerChangeInterval: 100 * time.Millisecond,
|
||||
showTotalBytes: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -338,11 +425,13 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
|
||||
panic("invalid spinner type, must be between 0 and 75")
|
||||
}
|
||||
|
||||
if b.config.maxDetailRow < 0 {
|
||||
panic("invalid max detail row, must be greater than 0")
|
||||
}
|
||||
|
||||
// ignoreLength if max bytes not known
|
||||
if b.config.max == -1 {
|
||||
b.config.ignoreLength = true
|
||||
b.config.max = int64(b.config.width)
|
||||
b.config.predictTime = false
|
||||
b.lengthUnknown()
|
||||
}
|
||||
|
||||
b.config.maxHumanized, b.config.maxHumanizedSuffix = humanizeBytes(float64(b.config.max),
|
||||
@ -352,6 +441,27 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
|
||||
b.RenderBlank()
|
||||
}
|
||||
|
||||
// if the render time interval attribute is set
|
||||
if b.config.spinnerChangeInterval != 0 && !b.config.invisible && b.config.ignoreLength {
|
||||
go func() {
|
||||
ticker := time.NewTicker(b.config.spinnerChangeInterval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if b.IsFinished() {
|
||||
return
|
||||
}
|
||||
if b.IsStarted() {
|
||||
b.lock.Lock()
|
||||
b.render()
|
||||
b.lock.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return &b
|
||||
}
|
||||
|
||||
@ -383,6 +493,7 @@ func DefaultBytes(maxBytes int64, description ...string) *ProgressBar {
|
||||
OptionSetDescription(desc),
|
||||
OptionSetWriter(os.Stderr),
|
||||
OptionShowBytes(true),
|
||||
OptionShowTotalBytes(true),
|
||||
OptionSetWidth(10),
|
||||
OptionThrottle(65*time.Millisecond),
|
||||
OptionShowCount(),
|
||||
@ -409,6 +520,7 @@ func DefaultBytesSilent(maxBytes int64, description ...string) *ProgressBar {
|
||||
OptionSetDescription(desc),
|
||||
OptionSetWriter(io.Discard),
|
||||
OptionShowBytes(true),
|
||||
OptionShowTotalBytes(true),
|
||||
OptionSetWidth(10),
|
||||
OptionThrottle(65*time.Millisecond),
|
||||
OptionShowCount(),
|
||||
@ -429,6 +541,7 @@ func Default(max int64, description ...string) *ProgressBar {
|
||||
OptionSetDescription(desc),
|
||||
OptionSetWriter(os.Stderr),
|
||||
OptionSetWidth(10),
|
||||
OptionShowTotalBytes(true),
|
||||
OptionThrottle(65*time.Millisecond),
|
||||
OptionShowCount(),
|
||||
OptionShowIts(),
|
||||
@ -455,6 +568,7 @@ func DefaultSilent(max int64, description ...string) *ProgressBar {
|
||||
OptionSetDescription(desc),
|
||||
OptionSetWriter(io.Discard),
|
||||
OptionSetWidth(10),
|
||||
OptionShowTotalBytes(true),
|
||||
OptionThrottle(65*time.Millisecond),
|
||||
OptionShowCount(),
|
||||
OptionShowIts(),
|
||||
@ -483,6 +597,24 @@ func (p *ProgressBar) RenderBlank() error {
|
||||
return p.render()
|
||||
}
|
||||
|
||||
// StartWithoutRender will start the progress bar without rendering it
|
||||
// this method is created for the use case where you want to start the progress
|
||||
// but don't want to render it immediately.
|
||||
// If you want to start the progress and render it immediately, use RenderBlank instead,
|
||||
// or maybe you can use Add to start it automatically, but it will make the time calculation less precise.
|
||||
func (p *ProgressBar) StartWithoutRender() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if p.IsStarted() {
|
||||
return
|
||||
}
|
||||
|
||||
p.state.startTime = time.Now()
|
||||
// the counterTime should be set to the current time
|
||||
p.state.counterTime = time.Now()
|
||||
}
|
||||
|
||||
// Reset will reset the clock that is used
|
||||
// to calculate current time and the time left.
|
||||
func (p *ProgressBar) Reset() {
|
||||
@ -564,6 +696,10 @@ func (p *ProgressBar) Add64(num int64) error {
|
||||
|
||||
p.state.currentBytes += float64(num)
|
||||
|
||||
if p.state.counterTime.IsZero() {
|
||||
p.state.counterTime = time.Now()
|
||||
}
|
||||
|
||||
// reset the countdown timer every second to take rolling average
|
||||
p.state.counterNumSinceLast += num
|
||||
if time.Since(p.state.counterTime).Seconds() > 0.5 {
|
||||
@ -593,6 +729,66 @@ func (p *ProgressBar) Add64(num int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDetail adds a detail to the progress bar. Only used when maxDetailRow is set to a value greater than 0
|
||||
func (p *ProgressBar) AddDetail(detail string) error {
|
||||
if p.config.maxDetailRow == 0 {
|
||||
return errors.New("maxDetailRow is set to 0, cannot add detail")
|
||||
}
|
||||
if p.IsFinished() {
|
||||
return errors.New("cannot add detail to a finished progress bar")
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
if p.state.details == nil {
|
||||
// if we add a detail before the first add, it will be weird that we have detail but don't have the progress bar in the top.
|
||||
// so when we add the first detail, we will render the progress bar first.
|
||||
if err := p.render(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
p.state.details = append(p.state.details, detail)
|
||||
if len(p.state.details) > p.config.maxDetailRow {
|
||||
p.state.details = p.state.details[1:]
|
||||
}
|
||||
if err := p.renderDetails(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderDetails renders the details of the progress bar
|
||||
func (p *ProgressBar) renderDetails() error {
|
||||
if p.config.invisible {
|
||||
return nil
|
||||
}
|
||||
if p.state.finished {
|
||||
return nil
|
||||
}
|
||||
if p.config.maxDetailRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
b := strings.Builder{}
|
||||
b.WriteString("\n")
|
||||
|
||||
// render the details row
|
||||
for _, detail := range p.state.details {
|
||||
b.WriteString(fmt.Sprintf("\u001B[K\r%s\n", detail))
|
||||
}
|
||||
// add empty lines to fill the maxDetailRow
|
||||
for i := len(p.state.details); i < p.config.maxDetailRow; i++ {
|
||||
b.WriteString("\u001B[K\n")
|
||||
}
|
||||
|
||||
// move the cursor up to the start of the details row
|
||||
b.WriteString(fmt.Sprintf("\u001B[%dF", p.config.maxDetailRow+1))
|
||||
|
||||
writeString(p.config, b.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clear erases the progress bar from the current line
|
||||
func (p *ProgressBar) Clear() error {
|
||||
return clearProgressBar(p.config, p.state)
|
||||
@ -653,6 +849,11 @@ func (p *ProgressBar) ChangeMax64(newMax int64) {
|
||||
p.config.useIECUnits)
|
||||
}
|
||||
|
||||
if newMax == -1 {
|
||||
p.lengthUnknown()
|
||||
} else {
|
||||
p.lengthKnown(newMax)
|
||||
}
|
||||
p.lock.Unlock() // so p.Add can lock
|
||||
|
||||
p.Add(0) // re-render
|
||||
@ -666,22 +867,31 @@ func (p *ProgressBar) IsFinished() bool {
|
||||
return p.state.finished
|
||||
}
|
||||
|
||||
// IsStarted returns true if progress bar is started
|
||||
func (p *ProgressBar) IsStarted() bool {
|
||||
return !p.state.startTime.IsZero()
|
||||
}
|
||||
|
||||
// render renders the progress bar, updating the maximum
|
||||
// rendered line width. this function is not thread-safe,
|
||||
// so it must be called with an acquired lock.
|
||||
func (p *ProgressBar) render() error {
|
||||
// make sure that the rendering is not happening too quickly
|
||||
// but always show if the currentNum reaches the max
|
||||
if time.Since(p.state.lastShown).Nanoseconds() < p.config.throttleDuration.Nanoseconds() &&
|
||||
if !p.IsStarted() {
|
||||
p.state.startTime = time.Now()
|
||||
} else if time.Since(p.state.lastShown).Nanoseconds() < p.config.throttleDuration.Nanoseconds() &&
|
||||
p.state.currentNum < p.config.max {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.config.useANSICodes {
|
||||
// first, clear the existing progress bar
|
||||
err := clearProgressBar(p.config, p.state)
|
||||
if err != nil {
|
||||
return err
|
||||
// first, clear the existing progress bar, if not yet finished.
|
||||
if !p.state.finished {
|
||||
err := clearProgressBar(p.config, p.state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,8 +899,14 @@ func (p *ProgressBar) render() error {
|
||||
if !p.state.finished && p.state.currentNum >= p.config.max {
|
||||
p.state.finished = true
|
||||
if !p.config.clearOnFinish {
|
||||
io.Copy(p.config.writer, &p.config.stdBuffer)
|
||||
renderProgressBar(p.config, &p.state)
|
||||
}
|
||||
if p.config.maxDetailRow > 0 {
|
||||
p.renderDetails()
|
||||
// put the cursor back to the last line of the details
|
||||
writeString(p.config, fmt.Sprintf("\u001B[%dB\r\u001B[%dC", p.config.maxDetailRow, len(p.state.details[len(p.state.details)-1])))
|
||||
}
|
||||
if p.config.onCompletion != nil {
|
||||
p.config.onCompletion()
|
||||
}
|
||||
@ -707,6 +923,7 @@ func (p *ProgressBar) render() error {
|
||||
}
|
||||
|
||||
// then, re-render the current progress bar
|
||||
io.Copy(p.config.writer, &p.config.stdBuffer)
|
||||
w, err := renderProgressBar(p.config, &p.state)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -721,6 +938,20 @@ func (p *ProgressBar) render() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// lengthUnknown sets the progress bar to ignore the length
|
||||
func (p *ProgressBar) lengthUnknown() {
|
||||
p.config.ignoreLength = true
|
||||
p.config.max = int64(p.config.width)
|
||||
p.config.predictTime = false
|
||||
}
|
||||
|
||||
// lengthKnown sets the progress bar to do not ignore the length
|
||||
func (p *ProgressBar) lengthKnown(max int64) {
|
||||
p.config.ignoreLength = false
|
||||
p.config.max = max
|
||||
p.config.predictTime = true
|
||||
}
|
||||
|
||||
// State returns the current state
|
||||
func (p *ProgressBar) State() State {
|
||||
p.lock.Lock()
|
||||
@ -733,7 +964,12 @@ func (p *ProgressBar) State() State {
|
||||
}
|
||||
s.CurrentPercent = float64(p.state.currentNum) / float64(p.config.max)
|
||||
s.CurrentBytes = p.state.currentBytes
|
||||
s.SecondsSince = time.Since(p.state.startTime).Seconds()
|
||||
if p.IsStarted() {
|
||||
s.SecondsSince = time.Since(p.state.startTime).Seconds()
|
||||
} else {
|
||||
s.SecondsSince = 0
|
||||
}
|
||||
|
||||
if p.state.currentNum > 0 {
|
||||
s.SecondsLeft = s.SecondsSince / float64(p.state.currentNum) * (float64(p.config.max) - float64(p.state.currentNum))
|
||||
}
|
||||
@ -793,21 +1029,32 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
if c.showBytes {
|
||||
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits)
|
||||
if currentSuffix == c.maxHumanizedSuffix {
|
||||
sb.WriteString(fmt.Sprintf("%s/%s%s",
|
||||
currentHumanize, c.maxHumanized, c.maxHumanizedSuffix))
|
||||
} else {
|
||||
if c.showTotalBytes {
|
||||
sb.WriteString(fmt.Sprintf("%s/%s%s",
|
||||
currentHumanize, c.maxHumanized, c.maxHumanizedSuffix))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%s%s",
|
||||
currentHumanize, c.maxHumanizedSuffix))
|
||||
}
|
||||
} else if c.showTotalBytes {
|
||||
sb.WriteString(fmt.Sprintf("%s%s/%s%s",
|
||||
currentHumanize, currentSuffix, c.maxHumanized, c.maxHumanizedSuffix))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%s%s", currentHumanize, currentSuffix))
|
||||
}
|
||||
} else {
|
||||
} else if c.showTotalBytes {
|
||||
sb.WriteString(fmt.Sprintf("%.0f/%d", s.currentBytes, c.max))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%.0f", s.currentBytes))
|
||||
}
|
||||
} else {
|
||||
if c.showBytes {
|
||||
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits)
|
||||
sb.WriteString(fmt.Sprintf("%s%s", currentHumanize, currentSuffix))
|
||||
} else {
|
||||
} else if c.showTotalBytes {
|
||||
sb.WriteString(fmt.Sprintf("%.0f/%s", s.currentBytes, "-"))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%.0f", s.currentBytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -843,6 +1090,10 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
}
|
||||
|
||||
leftBrac, rightBrac, saucer, saucerHead := "", "", "", ""
|
||||
barStart, barEnd := c.theme.BarStart, c.theme.BarEnd
|
||||
if s.finished && c.theme.BarEndFilled != "" {
|
||||
barEnd = c.theme.BarEndFilled
|
||||
}
|
||||
|
||||
// show time prediction in "current/total" seconds format
|
||||
switch {
|
||||
@ -879,6 +1130,9 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
c.width = width - getStringWidth(c, c.description, true) - 10 - amend - sb.Len() - len(leftBrac) - len(rightBrac)
|
||||
s.currentSaucerSize = int(float64(s.currentPercent) / 100.0 * float64(c.width))
|
||||
}
|
||||
if (s.currentSaucerSize > 0 || s.currentPercent > 0) && c.theme.BarStartFilled != "" {
|
||||
barStart = c.theme.BarStartFilled
|
||||
}
|
||||
if s.currentSaucerSize > 0 {
|
||||
if c.ignoreLength {
|
||||
saucer = strings.Repeat(c.theme.SaucerPadding, s.currentSaucerSize-1)
|
||||
@ -920,7 +1174,16 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
if len(c.spinner) > 0 {
|
||||
selectedSpinner = c.spinner
|
||||
}
|
||||
spinner := selectedSpinner[int(math.Round(math.Mod(float64(time.Since(s.startTime).Milliseconds()/100), float64(len(selectedSpinner)))))]
|
||||
|
||||
var spinner string
|
||||
if c.spinnerChangeInterval != 0 {
|
||||
// if the spinner is changed according to an interval, calculate it
|
||||
spinner = selectedSpinner[int(math.Round(math.Mod(float64(time.Since(s.startTime).Nanoseconds()/c.spinnerChangeInterval.Nanoseconds()), float64(len(selectedSpinner)))))]
|
||||
} else {
|
||||
// if the spinner is changed according to the number render was called
|
||||
spinner = selectedSpinner[s.spinnerIdx]
|
||||
s.spinnerIdx = (s.spinnerIdx + 1) % len(selectedSpinner)
|
||||
}
|
||||
if c.elapsedTime {
|
||||
if c.showDescriptionAtLineEnd {
|
||||
str = fmt.Sprintf("\r%s %s [%s] %s ",
|
||||
@ -951,11 +1214,11 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
} else if rightBrac == "" {
|
||||
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s",
|
||||
s.currentPercent,
|
||||
c.theme.BarStart,
|
||||
barStart,
|
||||
saucer,
|
||||
saucerHead,
|
||||
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
|
||||
c.theme.BarEnd,
|
||||
barEnd,
|
||||
sb.String())
|
||||
if (s.currentPercent == 100 && c.showElapsedTimeOnFinish) || c.elapsedTime {
|
||||
str = fmt.Sprintf("%s [%s]", str, leftBrac)
|
||||
@ -970,11 +1233,11 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
if s.currentPercent == 100 {
|
||||
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s",
|
||||
s.currentPercent,
|
||||
c.theme.BarStart,
|
||||
barStart,
|
||||
saucer,
|
||||
saucerHead,
|
||||
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
|
||||
c.theme.BarEnd,
|
||||
barEnd,
|
||||
sb.String())
|
||||
|
||||
if c.showElapsedTimeOnFinish {
|
||||
@ -989,11 +1252,11 @@ func renderProgressBar(c config, s *state) (int, error) {
|
||||
} else {
|
||||
str = fmt.Sprintf("%4d%% %s%s%s%s%s %s [%s:%s]",
|
||||
s.currentPercent,
|
||||
c.theme.BarStart,
|
||||
barStart,
|
||||
saucer,
|
||||
saucerHead,
|
||||
strings.Repeat(c.theme.SaucerPadding, repeatAmount),
|
||||
c.theme.BarEnd,
|
||||
barEnd,
|
||||
sb.String(),
|
||||
leftBrac,
|
||||
rightBrac)
|
||||
@ -1142,3 +1405,27 @@ var termWidth = func() (width int, err error) {
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func shouldCacheOutput(pb *ProgressBar) bool {
|
||||
return !pb.state.finished && !pb.state.exit && !pb.config.invisible
|
||||
}
|
||||
|
||||
func Bprintln(pb *ProgressBar, a ...interface{}) (int, error) {
|
||||
pb.lock.Lock()
|
||||
defer pb.lock.Unlock()
|
||||
if !shouldCacheOutput(pb) {
|
||||
return fmt.Fprintln(pb.config.writer, a...)
|
||||
} else {
|
||||
return fmt.Fprintln(&pb.config.stdBuffer, a...)
|
||||
}
|
||||
}
|
||||
|
||||
func Bprintf(pb *ProgressBar, format string, a ...interface{}) (int, error) {
|
||||
pb.lock.Lock()
|
||||
defer pb.lock.Unlock()
|
||||
if !shouldCacheOutput(pb) {
|
||||
return fmt.Fprintf(pb.config.writer, format, a...)
|
||||
} else {
|
||||
return fmt.Fprintf(&pb.config.stdBuffer, format, a...)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user