A really basic thread-safe progress bar for Golang applications

progressbar

travis go report card coverage godocs

A very simple thread-safe progress bar which should work on every OS without problems. I needed a progressbar for croc and everything I tried had problems, so I made another one. In order to be OS agnostic I do not plan to support multi-line outputs.

Install

go get -u github.com/schollz/progressbar/v3

Usage

Basic usage

bar := progressbar.Default(100)
for i := 0; i < 100; i++ {
    bar.Add(1)
    time.Sleep(40 * time.Millisecond)
}

which looks like:

Example of basic bar

I/O operations

The progressbar implements an io.Writer so it can automatically detect the number of bytes written to a stream, so you can use it as a progressbar for an io.Reader.

req, _ := http.NewRequest("GET", "https://dl.google.com/go/go1.14.2.src.tar.gz", nil)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

f, _ := os.OpenFile("go1.14.2.src.tar.gz", os.O_CREATE|os.O_WRONLY, 0644)
defer f.Close()

bar := progressbar.DefaultBytes(
    resp.ContentLength,
    "downloading",
)
io.Copy(io.MultiWriter(f, bar), resp.Body)

which looks like:

Example of download bar

Progress bar with unknown length

A progressbar with unknown length is a spinner. Any bar with -1 length will automatically convert it to a spinner with a customizable spinner type. For example, the above code can be run and set the resp.ContentLength to -1.

which looks like:

Example of download bar with unknown length

Customization

There is a lot of customization that you can do - change the writer, the color, the width, description, theme, etc. See all the options.

bar := progressbar.NewOptions(1000,
    progressbar.OptionSetWriter(ansi.NewAnsiStdout()),
    progressbar.OptionEnableColorCodes(true),
    progressbar.OptionShowBytes(true),
    progressbar.OptionSetWidth(15),
    progressbar.OptionSetDescription("[cyan][1/3][reset] Writing moshable file..."),
    progressbar.OptionSetTheme(progressbar.Theme{
        Saucer:        "[green]=[reset]",
        SaucerHead:    "[green]>[reset]",
        SaucerPadding: " ",
        BarStart:      "[",
        BarEnd:        "]",
    }))
for i := 0; i < 1000; i++ {
    bar.Add(1)
    time.Sleep(5 * time.Millisecond)
}

which looks like:

Example of customized bar

Contributing

Pull requests are welcome. Feel free to...

  • Revise documentation
  • Add new features
  • Fix bugs
  • Suggest improvements

Thanks

Thanks @Dynom for massive improvements in version 2.0!

Thanks @CrushedPixel for adding descriptions and color code support!

Thanks @MrMe42 for adding some minor features!

Thanks @tehstun for some great PRs!

Thanks @Benzammour and @haseth for helping create v3!

Thanks @briandowns for compiling the list of spinners.

License

MIT

Comments
  • OptionShowCount incorrectly renders with items below 1%

    OptionShowCount incorrectly renders with items below 1%

    Currently, if a bar is created with maximum number of items X and then updated (.Add(i)) with i that is significantly lower than 1% of X (e.g. 0.1%), then the item count shown to the right of the bar ((n/X)) will only update when it has accumulated to a whole percentage value (e.g. 1%, 2%) and so on. When you have a lot of items in between, it looks really weird.

    It is possible to introduce fractional percentage (which i guess will by default fix this behaviour), or somehow re-render the item count text on Add?

  • Refactor to functional options

    Refactor to functional options

    TL;DR

    The title is a bit misleading but currently this PR:

    • ✅ Introduces a "default value render" where it can render a 0% progress (instead when .Add(n) is called
    • ✅ Removes the instance setters and replace 'm with construction time Functional Options
    • ✅ Introduces a setting to change the initial rendering behaviour
    • ❎ Obliterates backward compatibility
    • ❎ Depends on Go 1.10 to run the tests (uses strings.Builder)

    The details

    This PR removes any of the "setters" and is more in line with the immutability concept. I'm not sure what the typical use-case is, but I don't expect people changing the options frequently once the bar is configured. This design supports that philosophy by having this moment a bit "sooner". Once the constructor is called, it's ready to be used and doesn't support any "configuration" changes.

    This way we can also render a blank bar on the get-go and voids the need to call bar.RenderBlank(). However I've tinkered with it and I don't think I personally like the implicit behaviour. So I've made it optional (disabled by default) and we can pick and choose.

    New API

    I think the API speaks for itself, but now it'll work like:

    bar := progressbar.NewOptions(100, OptionSetSize(10))
    bar.RenderBlank()
    bar.Add(5)
    
    • SetSize() has been removed and renamed to it's Width equivalent OptionSetWidth()
    • OptionSetRenderBlankState() is introduced to define the rendering behaviour of a blank progress bar

    Pending considerations

    • I've left progressbar.New(max) in, but I can just as easily replace it with what's now called progressbar.NewOptions().
    • ~~Decide if we want to set the maximum bar units using FO or as a straight-up parameter.~~

    Should resolve https://github.com/schollz/progressbar/issues/12

  • #79 breaks rendering on bars in GoLand terminal Windows 10

    #79 breaks rendering on bars in GoLand terminal Windows 10

    This error happens every 9 out of 10 times, all renders error out with: golang.org/x/sys/windows.ERROR_INVALID_HANDLE (6). I am using the default GoLand configuration, so it's a Command Prompt terminal.

    Ref: #79

  • Cannot get newline to print properly

    Cannot get newline to print properly

    Issue pictured image Code:

    	bar := progressbar.NewOptions(-1,
    		progressbar.OptionSetDescription("downloading emojis "+count),
    		progressbar.OptionSpinnerType(4),
    		progressbar.OptionShowCount(),
    		progressbar.OptionShowBytes(true),
    		progressbar.OptionOnCompletion(func() {
    			fmt.Fprint(os.Stderr, "\n")
    		}),
    	)
    

    I can't get the bar to properly add a newline afterwards for whatever reason.

  • Create String and Silent funcs

    Create String and Silent funcs

    This PR adds the ProgressBar.String() method that returns the rendered version of the progress bar as a string. This is useful for environments where one doesn't want to output to stdout, but use the progess bar somewhere else. Personally I'm using it in Amfora, which is a TUI application.

    This PR also adds the DefaultSilent and DefaultBytesSilent funcs, which create a ProgressBar that doesn't output anywhere, and doesn't have

    OptionOnCompletion(func() {
    	fmt.Fprint(os.Stderr, "\n")
    })
    
  • added infinite scrolling option

    added infinite scrolling option

    Here are the following changes made in code:

    1. Added ignoreLength flag.
    2. config.currentByte takes care of the number of bytes progressed.
    3. Able to show infinite progress bar withiteration/sec.
    4. Added showByte Option to toggle the speed rate display.
    5. Added test cases.
    6. Removed option to update max value through ChangeMax() function.

    Resolves #27

  • screen scrolling

    screen scrolling

    my progressbar init:

            max := 10000
    	writer := os.Stdout
    	bar := progressbar.NewOptions(max,
    		progressbar.OptionSetDescription(""),
    		progressbar.OptionSetWriter(writer),
    		progressbar.OptionSetWidth(50),
    		progressbar.OptionThrottle(65*time.Millisecond),
    		progressbar.OptionShowCount(),
    		progressbar.OptionShowIts(),
    		progressbar.OptionOnCompletion(func() {
    			fmt.Fprint(writer, "\n")
    		}),
    		progressbar.OptionSpinnerType(14),
    		progressbar.OptionFullWidth(),
    	)
    	_ = bar.RenderBlank()
    
    	for i := 0; i <= max; i++ {
    		bar.Add(1)
    		time.Sleep(time.Millisecond * 50)
    	}
    

    2020-07-07 16 30 27 it starts scrolling.so what i can do?

  • Feature request: unknown length (e.g. network io)

    Feature request: unknown length (e.g. network io)

    most IO progress implementations seem to only allow for a known fixed length denominator. in the case where the operation is for instance an HTTP POST, the total length/duration is not known and there doesn't seem to be a way to easily tie into the network layer to do a 'better' job. to satisfy this use case it would be great to have the progress bar simply ping back and forth, ping pong style, until progress bar Finish or Reset is called. Passing -1 perhaps to OptionSetWidth could be an approach to indicate unknown length.

  • int64 for maxbytes

    int64 for maxbytes

    Anything against having int64 for maxBytes, currentNum and so on? If we're processing a file, and we're using a progressbar, it's likely it's a huge file :)

    int will do in 64bit OS, but not in 32bit one (such as raspbian)

  • [Bug] Console output after progress bar doesn't start with new line

    [Bug] Console output after progress bar doesn't start with new line

    Affected version

    3.9.0

    Steps To Reproduce

    Create the following code example

    package main
    
    import (
    	"fmt"
    	"github.com/schollz/progressbar/v3"
    	"time"
    )
    
    func main() {
    	count := 10
    	progressBar := progressbar.NewOptions(
    		count,
    		progressbar.OptionFullWidth(),
    		progressbar.OptionSetRenderBlankState(true),
    		progressbar.OptionShowCount(),
    		progressbar.OptionSetVisibility(true),
    		progressbar.OptionSetPredictTime(false),
    		progressbar.OptionClearOnFinish(),
    	)
    
    	for i := 0; i < count; i++ {
    		time.Sleep(time.Millisecond * 100)
    		_ = progressBar.Add(1)
    	}
    
    	fmt.Println("hello")
    }
    

    Run

    go get github.com/schollz/progressbar/[email protected]
    

    Then run the example.

    The result is

    > go run .
    hello
    

    Then run

    go get github.com/schollz/progressbar/[email protected]
    

    And run the example again.

    The result is

    > go run .
                                                                                                                                               hello
    

    Notice number of spaces before the hello word.

    See the playground https://go.dev/play/p/Tpiz7wA-E2g?v=goprev

  • Adding the option to render the bar, before calling Add()

    Adding the option to render the bar, before calling Add()

    I've introduced a new function to call to render the blank bar. I've refrained from adding it as an option, since the current API doesn't easily allow for setting options. I've also refrained from adding it by default as I didn't wanted to introduce a backwards incompatible change.

    
    b := progressbar.New(10)
    b.RenderBlank()
    ticker := time.NewTicker(1 * time.Second)
    now := time.Now()
    for t := range ticker.C {
    	b.Add(1)
    	if t.Sub(now).Seconds() >= 10 {
    		break
    	}
    }
    
    ticker.Stop()
    
  • feature/allow-custom-spinners

    feature/allow-custom-spinners

    Description

    This PR makes the spinner type custom so that you can use one of the 76 preset spinners or any custom animation. To do this, the OptionSpinnerType now accepts a []string instead of an int, so any animation can be passed. If you want to use one of the presets, just use the new func GetPresetSpinner(spinnerType int) which gives you access to the previous standard animations.

  • docker logs -f does not show progress bar

    docker logs -f does not show progress bar

    When trying to follow docker container logs with "docker logs container -f" the progress bar is not showing even though by default it's following StdOut and the progress bar is writing to os.Stdout

    main.go

    package main
    
    import (
    	"time"
    
    	"github.com/schollz/progressbar/v3"
    )
    
    func main() {
    	bar := progressbar.Default(100)
    
    	for i := 0; i < 100; i++ {
    		bar.Add(1)
    		time.Sleep(1 * time.Second)
    	}
    }
    

    Dockerfile

    FROM golang:1.18-alpine
    WORKDIR /app
    COPY go.mod ./
    COPY go.sum ./
    RUN go mod download
    COPY *.go ./
    RUN go build -o /application
    CMD [ "/application" ]
    

    Building:

    docker build -t app . Running:

    docker run -d -t app Follow logs:

    docker logs 0b26e53d7321 -f

  • ChangeMax not working

    ChangeMax not working

    I start my progress bar as indeterminate for the first query that retrieves the count.
    Then I set the count as the new max, my log line does show the correct number.
    The progress bar never changes from indeterminate to an actual progress bar.

    Here is my setup.

    bar := progressbar.NewOptions(
    	-1,
    	progressbar.OptionSetDescription("Fetching messages from API"),
    	progressbar.OptionSetWriter(os.Stderr),
    	progressbar.OptionFullWidth(),
    	progressbar.OptionEnableColorCodes(true),
    	progressbar.OptionSetPredictTime(true),
    	progressbar.OptionShowCount(),
    	progressbar.OptionShowIts(),
    	progressbar.OptionShowElapsedTimeOnFinish(),
    	progressbar.OptionSetItsString("Msgs"),
    	progressbar.OptionSpinnerType(14),
    	progressbar.OptionSetRenderBlankState(true),
    )
    
    // This is just the initial query
    folderMessages := f.getMessages(client, log.Named("Messages"), queryLimit)
    msgCount := *folderMessages.GetOdataCount()
    log.With(zap.Int64("Count", msgCount)).Info("Message Count")
    bar.ChangeMax64(msgCount)
    
    // Proceeds to the processing loop
    

    And inside my loop.

    if err := bar.Add(1); err != nil {
    	log.With(zap.Error(err)).Error("Failed to increment progress bar!")
    }
    
  • How to display all steps in spinner

    How to display all steps in spinner

    I'm trying this code:

    func main() {
    	bar := progressbar.NewOptions(-1,
    		progressbar.OptionSetDescription("spinnertest"),
    		progressbar.OptionShowIts(),
    		progressbar.OptionShowCount(),
    		progressbar.OptionSpinnerType(7),
    	)
    
    	for i:=0; i < 100; i++ {
    		bar.Add(1)
    		time.Sleep(1 * time.Second)
    	}
    }
    

    And I'm expecting that each time it updates, it would move 1 step in the spinner, instead it just flops back and forth between 2 values. If I use spinners with more steps, 1 second intervals also seem to skip steps.

    If I change the delay to be time.Sleep(500 * time.Millisecond) it does work and I see all 4 steps, but my proposed usage would be at 1 second intervals. On the other hand, if I go to time.Sleep(2 * time.Second) I get no change in the spinner, although in all situations the count increments correctly.

    Is there somewhere I need to set the "total time lapse" of a spinner rotation?

  • feat!: Add ability to use custom style for bytes showing

    feat!: Add ability to use custom style for bytes showing

    I have added ability to customize way of bytes show by adding an option.

    func ExampleOptionUseCustomBytesShowWithMax() {
    	bar := NewOptions(100,
    		OptionSetWidth(10),
    		OptionShowIts(),
    		OptionShowCount(),
    		OptionSetElapsedTime(false), OptionUseCustomBytesShow(func(f float64, i int64) string {
    			return fmt.Sprintf("%.0f of %d items", f, i)
    		}))
    	bar.Reset()
    	time.Sleep(1 * time.Second)
    	bar.Add(5)
    
    	// Output:
    	// -  (5 of 100 items, 5 it/s)
    }
    

    closes #138

A go library to render progress bars in terminal applications
A go library to render progress bars in terminal applications

uiprogress A Go library to render progress bars in terminal applications. It provides a set of flexible features with a customizable API. Progress bar

Dec 29, 2022
Golang ultimate ANSI-colors that supports Printf/Sprintf methods
Golang ultimate ANSI-colors that supports Printf/Sprintf methods

Aurora Ultimate ANSI colors for Golang. The package supports Printf/Sprintf etc. TOC Installation Usage Simple Printf aurora.Sprintf Enable/Disable co

Dec 29, 2022
go-isatty - isatty for golang.

go-isatty isatty for golang Usage package main import ( "fmt" "github.com/mattn/go-isatty" "os" ) func main() { if isatty.IsTerminal(os.Stdout.F

Jan 7, 2023
A tiny library for super simple Golang tables

Tabby A tiny library for super simple Golang tables Get Tabby go get github.com/cheynewallace/tabby Import Tabby import "github.com/cheynewallace/tabb

Nov 23, 2022
Golang terminal dashboard
Golang terminal dashboard

termui termui is a cross-platform and fully-customizable terminal dashboard and widget library built on top of termbox-go. It is inspired by blessed-c

Dec 27, 2022
A really basic thread-safe progress bar for Golang applications
A really basic thread-safe progress bar for Golang applications

progressbar A very simple thread-safe progress bar which should work on every OS without problems. I needed a progressbar for croc and everything I tr

Jan 1, 2023
Go concurrent-safe, goroutine-safe, thread-safe queue
Go concurrent-safe, goroutine-safe, thread-safe queue

goconcurrentqueue - Concurrent safe queues The package goconcurrentqueue offers a public interface Queue with methods for a queue. It comes with multi

Dec 31, 2022
multi progress bar for Go cli applications

Multi Progress Bar mpb is a Go lib for rendering progress bars in terminal applications. Features Multiple Bars: Multiple progress bars are supported

Dec 30, 2022
multi progress bar for Go cli applications

Multi Progress Bar mpb is a Go lib for rendering progress bars in terminal applications. Features Multiple Bars: Multiple progress bars are supported

Dec 28, 2022
Console progress bar for Golang

Terminal progress bar for Go Installation go get github.com/cheggaaa/pb/v3 Documentation for v1 bar available here Quick start package main import (

Jan 9, 2023
progress_bar creates a single customizable progress bar for Linux terminal.
progress_bar creates a single customizable progress bar for Linux terminal.

progress_bar Go Progress Bar Features progress_bar creates a single customizable progress bar for Linux terminal. Installation go get -u github.com/er

Aug 12, 2022
Go simple progress bar writing to output
Go simple progress bar writing to output

?? progress-go Go simple progress bar writing to output ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free to send pull requests! Have

Oct 30, 2022
Routines was a fixed number thread pool to process the user task, and it would respawn a corresponding new thread when panic

Routines Routines was a fixed number thread pool to process the user task, and it would respawn a corresponding new thread when panic. It supports the

Dec 16, 2021
A Golang lock-free thread-safe HashMap optimized for fastest read access.

hashmap Overview A Golang lock-free thread-safe HashMap optimized for fastest read access. Usage Set a value for a key in the map: m := &HashMap{} m.S

Dec 30, 2022
Lightweight, Simple, Quick, Thread-Safe Golang Stack Implementation

stack Lightweight, Simple, Quick, Thread-Safe Golang Stack Implementation Purpose Provide a fast, thread safe, and generic Golang Stack API with minim

May 3, 2022
Light weight thread safe cache for golang

go-cache Light weight thread safe LRU cache Getting started import( "fmt" "github.com/tak1827/go-cache/lru" ) func main() { size := 2 cache := l

Dec 12, 2021
ZenQ - A low-latency thread-safe queue in golang implemented using a lock-free ringbuffer

ZenQ A low-latency thread-safe queue in golang implemented using a lock-free ringbuffer Features Much faster than native channels in both SPSC (single

Jan 8, 2023
Package ring provides a high performance and thread safe Go implementation of a bloom filter.

ring - high performance bloom filter Package ring provides a high performance and thread safe Go implementation of a bloom filter. Usage Please see th

Nov 20, 2022
A thread safe map which has expiring key-value pairs

~ timedmap ~ A map which has expiring key-value pairs. go get github.com/zekroTJA/timedmap Intro This package allows to set values to a map which will

Dec 29, 2022
go.fifo provides a simple fifo thread-safe queue for the Go programming language

go.fifo Description go.fifo provides a simple FIFO thread-safe queue. *fifo.Queue supports pushing an item at the end with Add(), and popping an item

Aug 29, 2022