English | 简体中文
🌙 MoonProgress - A clean and practical command-line progress bar library designed for MoonBit
- 🎯 Clean & Practical - Focus on core functionality with 5 curated styles, zero bloat
- ⚡ High Performance - Optimized rendering algorithm with minimal performance overhead
- 🔧 Flexible Configuration - Chainable configuration API with customizable display parameters
- 📊 Smart Display - ETA estimation, rate display, counters, and percentages
- 🌐 Universal Compatibility - Pure ASCII/Unicode characters, works in all terminals
- 🎯 Easy Integration - Clean API design, zero dependencies, ready to use
- ⏱️ Smart Time Tracking - Real-time rate calculation, accurate ETA estimation, smooth updates
- 📏 Dynamic Width Adaptation - Auto-detect terminal width, intelligently adjust progress bar length
- 🔗 Nested Progress Bars - Support multi-level progress bar management for complex tasks
- Add Dependency: Add to your project's
moon.pkg.json:
{
"import": [
"CGaaaaaa/MoonProgress/src"
]
}- Import and Use: In your MoonBit code:
// Create progress bar
let pb = @CGaaaaaa/MoonProgress.new(100)
let result = pb.update(50).render()
println(result)// Create progress bar with total 100, current progress 50
let pb = @CGaaaaaa/MoonProgress.new(100).update(50)
println(pb.render())
// Output: 50%|[█████████████████████████ ]// Custom prefix and suffix
let pb = @CGaaaaaa/MoonProgress.new(100)
.set_prefix("Processing: ")
.set_suffix(" Complete")
.update(75)
println(pb.render())
// Output: Processing: 75%|[█████████████████████████████████████▌ ] Complete// Show percentage + count
let pb1 = @CGaaaaaa/MoonProgress.new(100).set_show_percent(true).set_show_count(true).update(45)
println(pb1.render())
// Output: 45% (45/100)|[██████████████████████▌ ]
// Show ETA + processing rate
let pb2 = @CGaaaaaa/MoonProgress.new(1000).set_show_eta(true).set_show_rate(true).update(350)
println(pb2.render())
// Output: 35%|[█████████████████▌ ] ETA: 2m15s 150.5/s
// Show elapsed time + custom unit
let pb3 = @CGaaaaaa/MoonProgress.new(500).set_show_elapsed(true).set_unit("MB").update(200)
println(pb3.render())
// Output: 40%|[████████████████████ ] 200MB Elapsed: 1m30s
// Dynamic width adaptation
let pb4 = @CGaaaaaa/MoonProgress.new(100).set_dynamic_width(true).update(75)
println(pb4.render())
// Output: 75%|[████████████████████████████████████████████████████████████▌ ] (auto-adapts to terminal width)
// Full feature display
let pb5 = @CGaaaaaa/MoonProgress.new(2000)
.set_show_percent(true)
.set_show_count(true)
.set_show_eta(true)
.set_show_rate(true)
.set_unit("items/s")
.update(800)
println(pb5.render())
// Output: 40% (800/2000)|[████████████████████ ] ETA: 4m20s 92.3items/s// Simulate file processing
fn process_files(total: Int) {
let pb = @CGaaaaaa/MoonProgress.new(total)
.set_prefix("Processing files: ")
.set_show_eta(true)
.set_show_rate(true)
for i = 0; i < total; i = i + 1 {
// Simulate processing time
// Thread.sleep(100) // if available
pb.update(i + 1)
print("\r" + pb.render())
// Clear line and move cursor
if i == total - 1 {
println("")
}
}
}
process_files(50)Create a new progress bar with specified total count.
Update current progress and return self for chaining.
Render the progress bar as a string.
.set_style(style: ProgressStyle) -> ProgressBar
.set_fill(char: Char) -> ProgressBar
.set_empty(char: Char) -> ProgressBar
.set_width(width: Int) -> ProgressBar.set_prefix(text: String) -> ProgressBar
.set_suffix(text: String) -> ProgressBar
.set_show_percent(show: Bool) -> ProgressBar
.set_show_count(show: Bool) -> ProgressBar
.set_show_eta(show: Bool) -> ProgressBar
.set_show_rate(show: Bool) -> ProgressBar.set_dynamic_width(enable: Bool) -> ProgressBar
.set_smooth(enable: Bool) -> ProgressBar
.set_unit(unit: String) -> ProgressBar
.set_desc(desc: String) -> ProgressBar- Classic:
█filled,empty - Traditional solid blocks - Modern:
●filled,○empty - Modern rounded style - Minimal:
=filled,-empty - Clean minimalist design - ASCII:
#filled,.empty - Pure ASCII compatibility - Dots:
•filled,·empty - Elegant dot pattern
// Basic display (default configuration)
let basic = @CGaaaaaa/MoonProgress.new(100).update(60)
println(basic.render())
// Output: 60%|[██████████████████████████████ ]
// Enable count display
let with_count = @CGaaaaaa/MoonProgress.new(100).set_show_count(true).update(60)
println(with_count.render())
// Output: 60% (60/100)|[██████████████████████████████ ]
// Enable rate and ETA
let with_stats = @CGaaaaaa/MoonProgress.new(100)
.set_show_rate(true)
.set_show_eta(true)
.update(60)
println(with_stats.render())
// Output: 60%|[██████████████████████████████ ] ETA: 45s 2.3/s
// Full feature showcase
let full_featured = @CGaaaaaa/MoonProgress.new(100)
.set_prefix("Processing: ")
.set_suffix(" Complete")
.set_show_count(true)
.set_show_rate(true)
.set_show_eta(true)
.set_unit("items")
.update(60)
println(full_featured.render())
// Output: Processing: 60% (60/100)|[██████████████████████████████ ] ETA: 45s 2.3items/s Complete// File download scenario
let download = @CGaaaaaa/MoonProgress.new(1024)
.set_prefix("Download: ")
.set_show_rate(true)
.set_show_eta(true)
.set_unit("MB/s")
.update(512)
println(download.render())
// Output: Download: 50%|[█████████████████████████ ] ETA: 2m30s 8.5MB/s
// Data processing scenario
let processing = @CGaaaaaa/MoonProgress.new(10000)
.set_prefix("Analyzing: ")
.set_show_count(true)
.set_show_rate(true)
.set_unit("items/s")
.update(4500)
println(processing.render())
// Output: Analyzing: 45% (4500/10000)|[██████████████████████▌ ] 125.6items/s
// Long-running task scenario
let long_task = @CGaaaaaa/MoonProgress.new(500)
.set_show_elapsed(true)
.set_show_eta(true)
.set_smooth(true)
.update(200)
println(long_task.render())
// Output: 40%|[████████████████████ ] Elapsed: 15m30s ETA: 23m15sfn download_file(filename: String, size_mb: Int) {
let pb = @CGaaaaaa/MoonProgress.new(size_mb)
.set_prefix("Downloading " + filename + ": ")
.set_suffix(" MB")
.set_show_eta(true)
.set_show_rate(true)
.set_unit("MB")
.set_style(@CGaaaaaa/MoonProgress.Modern)
for i = 0; i <= size_mb; i = i + 1 {
pb.update(i)
print("\r" + pb.render())
// Simulate download delay
}
println("\nDownload complete!")
}fn process_data(records: Array[String]) {
let total = records.length()
let pb = @CGaaaaaa/MoonProgress.new(total)
.set_prefix("Processing records: ")
.set_show_count(true)
.set_show_rate(true)
.set_unit("rec/s")
.set_style(@CGaaaaaa/MoonProgress.Classic)
for i = 0; i < total; i = i + 1 {
// Process record
let record = records[i]
// ... processing logic ...
pb.update(i + 1)
print("\r" + pb.render())
}
println("\nProcessing complete!")
}fn multi_stage_task() {
// Stage 1: Initialization
let init_pb = @CGaaaaaa/MoonProgress.new(10)
.set_prefix("Initializing: ")
.set_style(@CGaaaaaa/MoonProgress.Minimal)
for i = 0; i <= 10; i = i + 1 {
init_pb.update(i)
print("\r" + init_pb.render())
}
println("\nInitialization complete!")
// Stage 2: Processing
let proc_pb = @CGaaaaaa/MoonProgress.new(50)
.set_prefix("Processing: ")
.set_show_eta(true)
.set_style(@CGaaaaaa/MoonProgress.Modern)
for i = 0; i <= 50; i = i + 1 {
proc_pb.update(i)
print("\r" + proc_pb.render())
}
println("\nProcessing complete!")
}- Percentage: Show completion percentage (default: true)
- Count: Show current/total counts (default: false)
- ETA: Show estimated time remaining (default: true)
- Rate: Show processing rate (default: true)
- Elapsed: Show elapsed time (default: false)
- Width: Progress bar width in characters (default: 50)
- Fill Character: Character for completed portion (default: '█')
- Empty Character: Character for remaining portion (default: ' ')
- Prefix/Suffix: Custom text before/after progress bar
- Dynamic Width: Auto-adjust to terminal width (default: false)
- Smooth Updates: Smooth progress transitions (default: true)
- Leave: Keep progress bar after completion (default: true)
// For file operations - use Classic
let file_pb = pb.set_style(@CGaaaaaa/MoonProgress.Classic)
// For network operations - use Modern
let net_pb = pb.set_style(@CGaaaaaa/MoonProgress.Modern)
// For simple tasks - use Minimal
let simple_pb = pb.set_style(@CGaaaaaa/MoonProgress.Minimal)// Good: Specific and informative
let pb = @CGaaaaaa/MoonProgress.new(1000)
.set_prefix("Analyzing log files: ")
.set_suffix(" entries processed")
// Avoid: Generic or unclear
let pb = @CGaaaaaa/MoonProgress.new(1000)
.set_prefix("Working: ")// For fast operations: batch updates
if i % 10 == 0 {
pb.update(i)
print("\r" + pb.render())
}
// For slow operations: update each iteration
pb.update(i)
print("\r" + pb.render())MoonProgress is optimized for minimal overhead:
- Memory: ~1KB per progress bar instance
- CPU: <0.1ms per render call on modern hardware
- Terminal: Efficient cursor control, minimal flickering
- Updates: Smart rate limiting prevents excessive redraws
We welcome contributions! Please feel free to:
- Report bugs and issues
- Suggest new features
- Submit pull requests
- Improve documentation
This project is licensed under the Apache-2.0 License - see the LICENSE file for details.
Inspired by excellent progress bar libraries:
- Python's tqdm
- Rust's indicatif
- Go's progressbar