Cross-Platform, Concurrent-Safe Multi-Progress Bar Library for Go
Go’s strong concurrency model makes it ideal for I/O-bound tasks, where real-time progress feedback is often needed. While simple carriage-return (\r) tricks suffice for basic single-bar use cases, they fall short in production-grade scenarios:
- Managing multiple concurrent progress bars requires precise synchronization and terminal state management.
- ANSI escape sequences behave inconsistently across platforms—especial in Windows PowerShell—leading to misaligned or corrupted output.
- Dynamic terminal resizing, mixed-width Unicode characters (e.g., CJK glyphs), and variable-length labels complicate line-length tracking and overwriting logic.
- Advanced UX needs—like hiding the cursor, disabling input during updates, or preserving layout across resize events—are unsupported by naive implementations.
Overview
progress is a Go library designed for robust, cross-platform, concurrent-safe progress visualization in terminal environments. It supports simultaneous rendering of heterogeneous progress indicators with full Unicode compatibility—including East Asian scripts—and provides fine-grained control over appearance, behavior, and lifecycle.
Key features include:
- Platform-agnostic ANSI handling via
single-line-printfoundation. - Event-driven rendering (not timer-polling), minimizing I/O pressure and ensuring stability under high bar counts.
- Configurable bar styles: standard, inline, text-only, and animated loading indicators.
- Rich customization: spacing, width, color, float precision, visibility flags, and emoji support.
- Automatic terminal adaptation: dynamic width detection, cursor visibility control, and input blocking.
Installation
go get github.com/lianggaoqiang/progress
Basic Usage
package main
import (
"github.com/lianggaoqiang/progress"
"time"
)
func main() {
p := progress.Start()
bar := progress.NewBar()
p.AddBar(bar)
for i := 0; i <= 100; i++ {
bar.Inc()
time.Sleep(10 * time.Millisecond)
}
}
This renders a default horizontal bar updating from 0% to 100%.
Custom Styling
Use Custom() to define visual elements:
b := progress.NewBar().Custom(progress.BarSetting{
StartText: "[",
EndText: "]",
PassedText: "-",
FirstPassedText: ">",
NotPassedText: "=",
})
BarSetting fields include:
LeftSpace,RightSpace: padding strings.Total: number of fill characters inside the bar.Hidden,HidePercent,UseFloat: display toggles and precision control.StartText,EndText: delimiters.PassedText,NotPassedText,FirstPassedText: fill glyphs.PercentColor: ANSI color index (e.g.,progress.Green).
Colorization
Apply ANSI colors using helper functions:
b := progress.NewBar().Custom(progress.BarSetting{
NotPassedText: progress.WhiteText("▇"),
PassedText: progress.ColorText("▇", progress.Green),
})
Supported color constants: Black, Red, Green, Yellow, Blue, Purple, Cyan, White.
Alternative Indicators
TextBar
For static status messages:
tb := progress.NewTextBar(progress.GreenText("Ready!"))
p.AddBar(tb)
LoadingBar
For indeterminate activity:
lb := progress.NewLoadingBar(
300,
"Loading",
"Loading.",
"Loading..",
"Loading...",
)
lb.SetColor(progress.Red)
p.AddBar(lb)
The first argument is the frame interval in milliseconds. Subsequent strings rotate as frames. To reuse previous text, use - as shorthand (e.g., "-.", "-.", "-..."). For literal -, escape as -- or wrap as -(--).
LoadingBarSetting adds FixedWidth, which locks width to the longest frame.
Composing Multiple Bars
Bars render in insertion order, enabling complex layouts:
p := progress.Start()
b1 := progress.NewBar().Custom(progress.BarSetting{
Total: 50, StartText: "[", EndText: "]",
PassedText: "-", FirstPassedText: ">", NotPassedText: "=",
})
b2 := progress.NewBar().Custom(progress.BarSetting{
UseFloat: true, Inline: true,
StartText: "|", EndText: "|",
FirstPassedText: ">", PassedText: "=", NotPassedText: " ",
})
b3 := progress.NewBar().Custom(progress.BarSetting{
LeftSpace: 10, Total: 10,
StartText: "|", EndText: "|",
PassedText: "⚡", NotPassedText: " ",
})
p.AddBar(b2)
p.AddBar(b3)
p.AddBar(b1)
for i := 0; i <= 100; i++ {
b1.Inc()
b2.Add(1.4)
b3.Percent(float64(i))
time.Sleep(40 * time.Millisecond)
}
Configuration Flags
Initialize with StartWithFlag() for advanced behavior:
HideCursor: hides terminal cursor during rendering.DisableInput: blocks keyboard input while active.ResizeReactively: rechecks terminal width before each render.PercentOverflow: allows values >100%, disabling auto-stop.AutoStop: stops automatically when all bars reach 100% and loader are inactive.
Example:
p := progress.StartWithFlag(
progress.HideCursor |
progress.DisableInput |
progress.AutoStop,
)
Note: AutoStop is enabled by default unless overridden.