Created
January 2, 2022 02:18
-
-
Save lox/2e33c4dfbd3bb524c3dca42fa69b615f to your computer and use it in GitHub Desktop.
Thinking on an API for spinner/progress bar library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Spinners and Progress bars are the same thing. | |
// They are assembled with a go template with some built in functions or templated strings | |
// for things like messages before and after. | |
// Render a spinner that looks like: | |
// ⡀ Loading blah... [3s] | |
spinner := indicate.New(context.Background(), | |
`{{ spinner "⠁⠂⠄⡀⢀⠠⠐⠈ " }} {{ template "message" }} [{{ elapsed }}]`). | |
WithDefaults(indicate.SpinnerDefaults). | |
Start() | |
for i := 0 ; i < 100; i++ { | |
spinner.Update("message", "Loading...") | |
spinner.Increment() | |
} | |
spinner.FinishAndClear() | |
// Render a progress bar that looks like | |
// Crawling... 45m [########> ] 3s | |
progress := indicate.New(context.Background(), | |
`{{ template "prefix" }} {{ elapsed }} {{ progress "[#> ]" }} {{ eta }}`). | |
WithTotal(100). | |
WithTemplateFunc("prefix", func(state indicate.State) string { | |
return fmt.Sprintf("[%d/%d]", state.Current, state.Total) | |
}). | |
Start() | |
for i := 0 ; i < 100; i++ { | |
progress.Update("prefix", "Crawling... ") | |
progress.Increment() | |
} | |
progress.FinishAndClear() | |
// Printing and re-rendering the indicator after the output | |
progress.Println("blah") |
How APT renders its progress bar: https://mdk.fr/blog/how-apt-does-its-fancy-progress-bar.html
https://news.ycombinator.com/item?id=28850036
Ooooh this is neat: https://github.com/jdxcode/smooth-progress
Using Block Elements: https://en.wikipedia.org/wiki/Block_Elements
package main
import (
"fmt"
"log"
"time"
"golang.org/x/term"
)
// For the record here's what's used (\033 is ESC):
//
// `ESC 7` is DECSC (Save Cursor)
// `ESC 8` is DECRC (Restore Cursor)
// `ESC [ Pn ; Pn r` is DECSTBM (Set Top and Bottom Margins)
// `ESC [ Pn A` is CUU (Cursor Up)
// `ESC [ Pn ; Pn f` is HVP (Horizontal and Vertical Position)
// `ESC [ Ps K` is EL (Erase In Line)
func main() {
var height int
var err error
_, height, err = term.GetSize(0)
if err != nil {
log.Fatal(err)
}
// go func() {
// // SIGWINCH syscall to react on window size changes.
// c := make(chan os.Signal, 1)
// signal.Notify(c, syscall.SIGWINCH)
// for range c {
// var err error
// _, height, err = term.GetSize(0)
// if err != nil {
// panic(err)
// }
// fmt.Printf("resize detected, new height is %d", height)
// }
// }()
fmt.Print("\033[?25l") // Turn off cursor
fmt.Println() // Ensure the last line is available.
fmt.Print("\0337") // Save cursor position
fmt.Printf("\033[0;%dr\n", height-1) // Reserve the bottom line
fmt.Printf("\033[%d;0f", height) // Move cursor to the bottom margin
fmt.Print("\033[1A") // Move up one line
var bar Bar
bar.NewOption(0, 100)
for i := 0; i <= 100; i++ {
fmt.Println("Hello!")
time.Sleep(100 * time.Millisecond)
fmt.Print("\0337") // Save cursor position
fmt.Printf("\033[%d;0f", height) // Move cursor to the bottom margin
fmt.Print("\033[2K") // Clear line
bar.Draw(int64(i))
fmt.Print("\0338") // Restore cursor position
}
bar.Finish()
}
func monitorResize() {
}
type Bar struct {
Percent int64 // percentage
Cur int64 // current progress location
Total int64 // total progress
Rate string // progress bar
Graph string // display symbols
}
func (b *Bar) NewOption(start, total int64) {
b.Cur = start
b.Total = total
if b.Graph == "" {
b.Graph = "█"
}
b.Percent = b.CalculatePercent()
for i := 0; i < int(b.Percent); i += 2 {
b.Rate += b.Graph // initialize the progress bar position
}
}
func (b *Bar) CalculatePercent() int64 {
return int64(float32(b.Cur) / float32(b.Total) * 100)
}
func (b *Bar) Draw(cur int64) {
b.Cur = cur
last := b.Percent
b.Percent = b.CalculatePercent()
if b.Percent != last && b.Percent%2 == 0 {
b.Rate += b.Graph
}
fmt.Printf("[%-50s]%3d%% %8d/%d", b.Rate, b.Percent, b.Cur, b.Total)
}
func (b *Bar) Finish() {
fmt.Println()
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Existing libraries:
https://github.com/vbauerster/mpb
https://github.com/gosuri/uiprogress
https://github.com/schollz/progressbar
https://github.com/cheggaaa/pb
https://github.com/sethgrid/multibar