Skip to content

Commit

Permalink
Basically works
Browse files Browse the repository at this point in the history
  • Loading branch information
schollz committed Oct 26, 2017
1 parent 6aba3fb commit fdf19f7
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 115 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<p align="center">
<img
src="logo.png"
width="100%" border="0" alt="progressbar">
<br>
<a href="https://travis-ci.org/schollz/progressbar"><img src="https://travis-ci.org/schollz/progressbar.svg?branch=master" alt="Build Status"></a>
<a href="https://goreportcard.com/report/github.com/schollz/progressbar"><img src="https://goreportcard.com/badge/github.com/schollz/progressbar" alt="Go Report Card"></a>
<a href="https://godoc.org/github.com/schollz/progressbar"><img src="https://godoc.org/github.com/schollz/progressbar?status.svg" alt="GoDoc"></a>
</p>

<p align="center">A very simple progress bar.</p>

See the godocs for more info.
31 changes: 16 additions & 15 deletions examples/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package main

import (
"time"

"github.com/schollz/progressbar"
)

func main() {
bar := progressbar.New(100)
for i := 0; i < 100; i++ {
bar.Add(1)
time.Sleep(10 * time.Millisecond)
}
}
package main

import (
"time"

"github.com/schollz/progressbar"
)

func main() {
bar := progressbar.New(100)
bar.Reset()
for i := 0; i < 100; i++ {
bar.Add(1)
time.Sleep(10 * time.Millisecond)
}
}
201 changes: 110 additions & 91 deletions progressbar.go
Original file line number Diff line number Diff line change
@@ -1,91 +1,110 @@
package progressbar

import (
"fmt"
"io"
"os"
"strings"
"sync"
"time"
)

// ProgressBar is a thread-safe, simple
// progress bar
type ProgressBar struct {
Max int // max number of the counter
Size int // size of the saucer
currentNum int
currentPercent int
lastPercent int
currentSaucerSize int

lastShown time.Time
startTime time.Time
w io.Writer

// symbols
symbolFinished string
symbolLeft string
leftBookend string
rightBookend string
sync.RWMutex
}

// New returns a new ProgressBar
// with the specified maximum
func New(max int) *ProgressBar {
p := new(ProgressBar)
p.Lock()
defer p.Unlock()
p.Max = max
p.Size = 40
p.symbolFinished = "█"
p.symbolLeft = " "
p.leftBookend = "|"
p.rightBookend = "|"
p.w = os.Stdout
p.lastShown = time.Now()
p.startTime = time.Now()
return p
}

// Add a certain amount to the progress bar
func (p *ProgressBar) Add(num int) error {
p.Lock()
p.currentNum += num
percent := float64(p.currentNum) / float64(p.Max)
p.currentSaucerSize = int(percent * float64(p.Size))
p.currentPercent = int(percent * 100)
updateBar := p.currentPercent != p.lastPercent
p.lastPercent = p.currentPercent
p.Unlock()
if updateBar {
return p.Show()
}
return nil
}

// Show will print the current progress bar
func (p *ProgressBar) Show() error {
p.RLock()
defer p.RUnlock()
secondsLeft := time.Since(p.startTime).Seconds() / float64(p.currentNum) * (float64(p.Max) - float64(p.currentNum))
s := fmt.Sprintf("\r%3d%% %s%s%s%s [%s:%s]",
p.currentPercent,
p.leftBookend,
strings.Repeat(p.symbolFinished, p.currentSaucerSize),
strings.Repeat(p.symbolLeft, p.Size-p.currentSaucerSize),
p.rightBookend,
time.Since(p.startTime).Round(time.Second).String(),
(time.Duration(secondsLeft) * time.Second).String(),
)

_, err := io.WriteString(p.w, s)
if err != nil {
return err
}
if f, ok := p.w.(*os.File); ok {
f.Sync()
}
return nil
}
package progressbar

import (
"errors"
"fmt"
"io"
"os"
"strings"
"sync"
"time"
)

// ProgressBar is a thread-safe, simple
// progress bar
type ProgressBar struct {
Max int // max number of the counter
Size int // size of the saucer
currentNum int
currentPercent int
lastPercent int
currentSaucerSize int

lastShown time.Time
startTime time.Time
w io.Writer

// symbols
symbolFinished string
symbolLeft string
leftBookend string
rightBookend string
sync.RWMutex
}

// New returns a new ProgressBar
// with the specified maximum
func New(max int) *ProgressBar {
p := new(ProgressBar)
p.Lock()
defer p.Unlock()
p.Max = max
p.Size = 40
p.symbolFinished = "█"
p.symbolLeft = " "
p.leftBookend = "|"
p.rightBookend = "|"
p.w = os.Stdout
p.lastShown = time.Now()
p.startTime = time.Now()
return p
}

// Reset will reset the clock
func (p *ProgressBar) Reset() {
p.Lock()
defer p.Unlock()
p.lastShown = time.Now()
p.startTime = time.Now()
}

// Set the max of the progress bar
func (p *ProgressBar) Set(num int) {
p.Lock()
defer p.Unlock()
p.Max = num
}

// Add a certain amount to the progress bar
func (p *ProgressBar) Add(num int) error {
p.Lock()
p.currentNum += num
percent := float64(p.currentNum) / float64(p.Max)
p.currentSaucerSize = int(percent * float64(p.Size))
p.currentPercent = int(percent * 100)
updateBar := p.currentPercent != p.lastPercent && p.currentPercent > 0
p.lastPercent = p.currentPercent
p.Unlock()
if updateBar {
return p.Show()
}
return nil
}

// Show will print the current progress bar
func (p *ProgressBar) Show() error {
p.RLock()
defer p.RUnlock()
if p.currentNum > p.Max {
return errors.New("current number exceeds max")
}
secondsLeft := time.Since(p.startTime).Seconds() / float64(p.currentNum) * (float64(p.Max) - float64(p.currentNum))
s := fmt.Sprintf("\r%3d%% %s%s%s%s [%s:%s] ",
p.currentPercent,
p.leftBookend,
strings.Repeat(p.symbolFinished, p.currentSaucerSize),
strings.Repeat(p.symbolLeft, p.Size-p.currentSaucerSize),
p.rightBookend,
time.Since(p.startTime).Round(time.Second).String(),
(time.Duration(secondsLeft) * time.Second).String(),
)

_, err := io.WriteString(p.w, s)
if err != nil {
return err
}
if f, ok := p.w.(*os.File); ok {
f.Sync()
}
return nil
}
18 changes: 9 additions & 9 deletions progressbar_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package progressbar

func ExampleBar() {
bar := New(10)
bar.Add(1)

// Output:
// 10% |████ | [0s:0s]
}
package progressbar

func ExampleBar() {
bar := New(10)
bar.Add(1)

// Output:
// 10% |████ | [0s:0s]
}

0 comments on commit fdf19f7

Please sign in to comment.