Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Cross-Platform, Concurrent-Safe Multi-Progress Bar Library for Go

Tech 2

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-print foundation.
  • 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.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.