<div align="center">
<img height="300" alt="loaders thumbnail" src="https://github.com/user-attachments/assets/4ac08707-6144-4037-b339-ef1d97dd5f3c" />
<a href="https://muhammad-fiaz.github.io/loaders/"><img src="https://img.shields.io/badge/docs-muhammad--fiaz.github.io-blue" alt="Documentation"></a>
<a href="https://www.rust-lang.org/"><img src="https://img.shields.io/badge/Rust-Edition%202024-orange.svg?logo=rust" alt="Rust Edition"></a>
<a href="https://github.com/muhammad-fiaz/loaders"><img src="https://img.shields.io/github/stars/muhammad-fiaz/loaders" alt="GitHub stars"></a>
<a href="https://github.com/muhammad-fiaz/loaders/issues"><img src="https://img.shields.io/github/issues/muhammad-fiaz/loaders" alt="GitHub issues"></a>
<a href="https://github.com/muhammad-fiaz/loaders/pulls"><img src="https://img.shields.io/github/issues-pr/muhammad-fiaz/loaders" alt="GitHub pull requests"></a>
<a href="https://github.com/muhammad-fiaz/loaders"><img src="https://img.shields.io/github/last-commit/muhammad-fiaz/loaders" alt="GitHub last commit"></a>
<a href="https://github.com/muhammad-fiaz/loaders"><img src="https://img.shields.io/github/license/muhammad-fiaz/loaders" alt="License"></a>
<a href="https://github.com/muhammad-fiaz/loaders/actions/workflows/ci.yml"><img src="https://github.com/muhammad-fiaz/loaders/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://github.com/muhammad-fiaz/loaders/actions/workflows/docs.yml"><img src="https://github.com/muhammad-fiaz/loaders/actions/workflows/docs.yml/badge.svg" alt="Docs Deploy"></a>
<img src="https://img.shields.io/badge/platforms-linux%20%7C%20windows%20%7C%20macos-blue" alt="Supported Platforms">
<a href="https://github.com/muhammad-fiaz/loaders/releases/latest"><img src="https://img.shields.io/github/v/release/muhammad-fiaz/loaders?label=Latest%20Release&style=flat-square" alt="Latest Release"></a>
<a href="https://pay.muhammadfiaz.com"><img src="https://img.shields.io/badge/Sponsor-pay.muhammadfiaz.com-ff69b4?style=flat&logo=heart" alt="Sponsor"></a>
<a href="https://github.com/sponsors/muhammad-fiaz"><img src="https://img.shields.io/badge/Sponsor-%F0%9F%92%96-pink?style=social&logo=github" alt="GitHub Sponsors"></a>
<a href="https://hits.sh/muhammad-fiaz/loaders/"><img src="https://hits.sh/muhammad-fiaz/loaders.svg?label=Visitors&extraCount=0&color=green" alt="Repo Visitors"></a>
<p><em>A customisable progressbar and loading library for Rust.</em></p>
<b>
<a href="https://muhammad-fiaz.github.io/loaders/">Documentation</a> |
<a href="https://muhammad-fiaz.github.io/loaders/api-reference">API Reference</a> |
<a href="https://muhammad-fiaz.github.io/loaders/getting-started">Quick Start</a> |
<a href="#contributing">Contributing</a>
</b>
</div>
`loaders` is a production-minded, dependency-free terminal progress library for Rust. It
provides progress bars, spinners, multi-progress rendering, iterator adapters, terminal
capability detection, themes, templates, ANSI styling, and test-friendly draw targets using
only the Rust standard library.
**If you love `loaders`, make sure to give it a star ⭐.**
---
<details>
<summary><strong>Table of Contents</strong> (click to expand)</summary>
- [Prerequisites](#prerequisites)
- [Supported Platforms](#supported-platforms)
- [Installation](#installation)
- [Method 1: Cargo Add (Recommended)](#method-1-cargo-add-recommended)
- [Method 2: Manual Cargo.toml Configuration](#method-2-manual-cargotoml-configuration)
- [Quick Start](#quick-start)
- [Usage Examples](#usage-examples)
- [Basic Progress Bar](#basic-progress-bar)
- [Spinner Quick Start](#spinner-quick-start)
- [Iterator Integration](#iterator-integration)
- [MultiProgress with Threads](#multiprogress-with-threads)
- [Custom Styling](#custom-styling)
- [Download-Style Byte Progress](#download-style-byte-progress)
- [Custom Template Keys](#custom-template-keys)
- [Template Variable Reference](#template-variable-reference)
- [Theme Gallery](#theme-gallery)
- [Spinner Presets](#spinner-presets)
- [Configuration](#configuration)
- [Building & Testing](#building--testing)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)
- [Contact](#contact)
- [Links](#links)
</details>
---
<details>
<summary><strong>Features of loaders</strong> (click to expand)</summary>
| **Zero Dependencies** | Built entirely with `std`, with no third-party runtime or feature dependencies. | [Docs](https://muhammad-fiaz.github.io/loaders/) |
| **Progress Bars** | Known-length bars with position, total, percentage, ETA, elapsed time, and rate. | [Docs](https://muhammad-fiaz.github.io/loaders/progress-bar) |
| **Spinners** | Indeterminate loading indicators with manual ticks or background steady ticks. | [Docs](https://muhammad-fiaz.github.io/loaders/spinners) |
| **27 Spinner Presets** | Dots, line, pipe, star, meter, pulse, blocks, arrows, clock, weather, and more. | [Docs](https://muhammad-fiaz.github.io/loaders/spinners) |
| **MultiProgress** | Render multiple bars in a stable shared terminal block for concurrent jobs. | [Docs](https://muhammad-fiaz.github.io/loaders/multi-progress) |
| **Iterator Wrapping** | Add `.progress()`, `.progress_count()`, and custom-style adapters to iterators. | [Docs](https://muhammad-fiaz.github.io/loaders/examples) |
| **Template Engine** | Parse `{bar}`, `{percent}`, `{bytes_per_sec}`, `{eta}`, and custom keys once. | [Docs](https://muhammad-fiaz.github.io/loaders/styling) |
| **Status Templates** | Render `{status}`, `{remaining}`, `{human_remaining}`, `{ratio}`, and `{rate}`. | [Docs](https://muhammad-fiaz.github.io/loaders/styling) |
| **Custom Template Keys** | Register closures for app-specific template variables. | [Docs](https://muhammad-fiaz.github.io/loaders/advanced) |
| **Reusable Bar Characters** | Define custom fill, head, and empty characters with `ProgressChars`. | [Docs](https://muhammad-fiaz.github.io/loaders/styling) |
| **Themes** | Default, Unicode, Braille, Block, Minimal, Colorful, Gradient, Retro, and more. | [Docs](https://muhammad-fiaz.github.io/loaders/themes) |
| **ANSI Colors** | 16-color, 256-color, and RGB ANSI generation with text attributes. | [Docs](https://muhammad-fiaz.github.io/loaders/styling) |
| **NO_COLOR Compliance** | Suppresses ANSI styling when `NO_COLOR` is set. | [Docs](https://muhammad-fiaz.github.io/loaders/advanced) |
| **CI-Aware Output** | Detects common CI environments and avoids unreadable terminal control output. | [Docs](https://muhammad-fiaz.github.io/loaders/advanced) |
| **Custom Draw Targets** | Write to stdout, stderr, hidden targets, or any `Write + Send` target. | [Docs](https://muhammad-fiaz.github.io/loaders/advanced) |
| **Thread Safety** | Clone progress handles across worker threads using shared synchronized state. | [Docs](https://muhammad-fiaz.github.io/loaders/multi-progress) |
| **Draw Throttling** | Limit redraws by position delta and maximum redraws per second. | [Docs](https://muhammad-fiaz.github.io/loaders/progress-bar) |
| **Outcome Helpers** | Stop spinners with success, failure, warning, or info markers. | [Docs](https://muhammad-fiaz.github.io/loaders/spinners) |
</details>
---
<details>
<summary><strong>Prerequisites & Supported Platforms</strong> (click to expand)</summary>
<br>
## Prerequisites
| **Rust** | Stable with Edition 2024 support | The crate uses Rust 2024 edition metadata. |
| **Dependencies** | None | Only the Rust standard library is used. |
| **Terminal** | Optional | Hidden and custom writer targets work without a TTY. |
---
## Supported Platforms
| **Windows** | x86_64, aarch64, x86 | Interactive same-line redraw, Win32 terminal size detection, newline fallback for non-TTY. |
| **Linux** | x86_64, aarch64, riscv64 | Full terminal width and TTY detection support. |
| **macOS** | x86_64, aarch64 (Apple Silicon) | Full terminal width and TTY detection support. |
| **Other Unix** | target-dependent | Uses the same `isatty` + `ioctl` detection path where available. |
</details>
---
## Installation
### Method 1: Cargo Add (Recommended)
Add **loaders** to your Cargo project dynamically:
```bash
cargo add loaders
```
### Method 2: Manual Cargo.toml Configuration
Add this directly to your `Cargo.toml` dependencies block:
```toml
[dependencies]
loaders = "0.0.0"
```
---
## Quick Start
```rust
use loaders::ProgressBar;
use std::thread;
use std::time::Duration;
fn main() {
let pb = ProgressBar::new(100);
for _ in 0..100 {
pb.inc(1);
thread::sleep(Duration::from_millis(10));
}
pb.finish_with_message("done");
}
```
---
## Usage Examples
### Basic Progress Bar
```rust
use loaders::{ProgressBar, Theme};
let pb = ProgressBar::new(100);
pb.set_prefix("build");
pb.set_style(Theme::Unicode.style());
pb.inc(25);
pb.finish_with_message("complete");
```
### Spinner Quick Start
```rust
use loaders::{Spinner, spinner::frames::DOTS};
let spinner = Spinner::with_message(&DOTS, "connecting");
spinner.tick();
spinner.stop_with_symbol("✔", "connected");
```
### Iterator Integration
```rust
use loaders::ProgressIterator;
let sum: u64 = (0..100u64).progress().sum();
println!("{sum}");
```
### MultiProgress with Threads
```rust
use loaders::{MultiProgress, ProgressBar};
use std::thread;
fn main() {
let multi = MultiProgress::new();
let first = multi.add(ProgressBar::new(50));
let second = multi.add(ProgressBar::new(75));
let a = thread::spawn(move || {
for _ in 0..50 {
first.inc(1);
}
first.finish_with_message("first done");
});
let b = thread::spawn(move || {
for _ in 0..75 {
second.inc(1);
}
second.finish_with_message("second done");
});
multi.join();
let _ = a.join();
let _ = b.join();
}
```
### Custom Styling
```rust
use loaders::{Color, ColorSpec, ProgressBar, ProgressChars, ProgressStyle};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let style = ProgressStyle::with_template(
"{prefix} [{bar:40.#/-}] {pos}/{len} ({percent:.1}%) {msg}",
)?
.progress_chars_set(ProgressChars::equals())
.color(ColorSpec::new().set_fg(Color::Cyan).set_bold(true));
let pb = ProgressBar::new(100);
pb.set_style(style);
pb.set_prefix("custom");
pb.inc(40);
pb.finish_with_message("done");
Ok(())
}
```
### Advanced Progress State & Status Templates
```rust
use loaders::{ProgressBar, ProgressStyle};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let style = ProgressStyle::with_template(
"{prefix} [{bar:20}] {percent:.1}% | {human_remaining} left | {status}",
)?;
let pb = ProgressBar::with_style(100, style);
pb.set_prefix("task");
pb.inc(40);
assert_eq!(pb.remaining(), Some(60));
pb.finish_with_symbol("ok", "complete");
Ok(())
}
```
### Download-Style Byte Progress
```rust
use loaders::{ProgressBar, ProgressStyle};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let style = ProgressStyle::with_template(
"{prefix} [{bar:30}] {bytes}/{total_bytes} {bytes_per_sec} ETA {eta}",
)?;
let pb = ProgressBar::builder()
.length(50 * 1024 * 1024)
.style(style)
.prefix("download")
.build();
pb.inc(1024 * 1024);
pb.finish_with_message("saved");
Ok(())
}
```
### Custom Template Keys
```rust
use loaders::{ProgressBar, ProgressStyle};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let style = ProgressStyle::with_template("{phase} [{bar:20}] {msg}")?
.with_key("phase", |state| format!("phase {}", state.pos / 10 + 1));
let pb = ProgressBar::builder().length(30).style(style).build();
pb.inc(10);
pb.finish_with_message("done");
Ok(())
}
```
---
## Template Variable Reference
| `{bar}` | `:40`, `:40.#/-` | Progress bar segment. | `########>-------` |
| `{wide_bar}` | none | Progress bar sized to remaining template width. | `############>...` |
| `{pos}` | none | Current position. | `42` |
| `{count}` | none | Compact current position. | `1.2k` |
| `{human_pos}` | none | Compact current position alias. | `1.2k` |
| `{len}` | none | Total length or `?` when unknown. | `100` |
| `{total_count}` | none | Compact total length. | `1.5M` |
| `{human_len}` | none | Compact total length alias. | `1.5M` |
| `{remaining}` | none | Remaining units. | `58` |
| `{human_remaining}` | none | Compact remaining units. | `58.0k` |
| `{ratio}` | `:.3` | Completion ratio. | `0.420` |
| `{percent}` | `:.2` | Percentage without a percent sign. | `42` or `42.50` |
| `{elapsed}` | none | Human elapsed time. | `3m 14s` |
| `{elapsed_precise}` | none | Precise elapsed time. | `00:03:14` |
| `{elapsed_millis}` | none | Millisecond elapsed time. | `00:03:14.123` |
| `{eta}` | none | Estimated remaining time. | `~12s` |
| `{eta_precise}` | none | Precise ETA. | `00:00:12` |
| `{eta_millis}` | none | Millisecond ETA. | `00:00:12.345` |
| `{per_sec}` | `:.2` | Average units per second. | `120.50` |
| `{rate}` | none | Formatted item rate. | `1.23k items/s` |
| `{bytes}` | none | Current position as bytes. | `1.00 MB` |
| `{total_bytes}` | none | Total length as bytes. | `50.00 MB` |
| `{bytes_per_sec}` | none | Byte throughput. | `1.23 MB/s` |
| `{spinner}` | none | Current spinner frame. | `⠋` |
| `{msg}` | `:20`, `:>20`, `:^20` | Message text with optional padding/truncation. | `downloading` |
| `{prefix}` | `:10`, `:>10`, `:^10` | Prefix text with optional padding/truncation. | `task` |
| `{postfix}` | `:10`, `:>10`, `:^10` | Postfix text with optional padding/truncation. | `ok` |
| `{status}` | `:10`, `:>10`, `:^10` | Running, spinning, finished, or abandoned state. | `running` |
| `{wide_msg}` | none, `:20`, `:>20`, `:^20` | Message padded or truncated to terminal or explicit width. | terminal-width text |
Text width specs use `<` (left), `>` (right), and `^` (center) alignment with fixed width.
---
## Theme Gallery
Approximate 60% previews:
```text
default [##################>-----------]
unicode [━━━━━━━━━━━━━━━━━━╸░░░░░░░░░░░]
braille [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣦]
block [██████████████████▉▒▒▒▒▒▒▒▒▒▒▒]
minimal ==================>...........
colorful [##################>-----------]
gradient [██████████████████▓░░░░░░░░░░░]
retro [==================>-----------]
dots [••••••••••••••••••∘ ]
rounded [●●●●●●●●●●●●●●●●●●○───────────]
shaded [▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▫ ]
arrows [>>>>>>>>>>>>>>>>>>------------]
```
---
## Spinner Presets
| `dots` | `⠋ ⠙ ⠹` |
| `dots2` | `⣾ ⣽ ⣻` |
| `dots3` | `⠋ ⠙ ⠚` |
| `line` | `- \ |` |
| `pipe` | `┤ ┘ ┴` |
| `star` | `✶ ✸ ✹` |
| `bounce` | `⠁ ⠂ ⠄` |
| `arrows` | `← ↖ ↑` |
| `clock` | `🕛 🕐 🕑` |
| `earth` | `🌍 🌎 🌏` |
| `moon` | `🌑 🌒 🌓` |
| `runner` | `🚶 🏃 🚶` |
| `pong` | `▐⠂ ▐ ⠂ ▐ ⠂` |
| `shark` | `▐|\_ ▐_|\_ ▐__|\_` |
| `weather` | `☀️ ⛅ 🌤` |
| `christmas` | `🌲 🎄 🌲` |
| `toggle` | `■ □ ■` |
| `square_corners` | `◰ ◳ ◲` |
| `binary` | `0 1 10` |
| `meter` | `▱▱▱ ▰▱▱ ▰▰▱` |
| `quadrants` | `◐ ◓ ◑` |
| `triangles` | `◢ ◣ ◤` |
| `circle` | `○ ◔ ◐` |
| `box_bounce` | moving block |
| `pulse` | `. .. ...` |
| `heart` | `♡ ♥ ♡` |
| `progress_blocks` | `▁ ▂ ▃` |
---
## Configuration
```rust
use loaders::{DrawTarget, ProgressBar, Theme};
let pb = ProgressBar::builder()
.length(1_000)
.style(Theme::Block.style())
.target(DrawTarget::stderr())
.draw_delta(10)
.draw_rate(20)
.prefix("build")
.message("compiling")
.build();
```
---
## Building & Testing
```bash
# Keep dependencies current in the lockfile
cargo update
# Check formatting
cargo fmt --all -- --check
# Run clippy across all targets
cargo clippy --all-targets -- -D warnings
# Run unit tests and doctests
cargo test --all
# Build every example
cargo build --examples
# Generate crate documentation
cargo doc --no-deps
```
---
## Documentation
### Online Documentation
Full guides and API walkthroughs are available at:
https://muhammad-fiaz.github.io/loaders
### Generating Local Documentation
```bash
cargo doc --no-deps --open
```
---
## Contributing
Contributions are welcome. Please keep the crate dependency-free, include focused tests for
behavioral changes, and run the full verification commands from [Building & Testing](#building--testing)
before opening a pull request.
---
## License
MIT License - see [LICENSE](LICENSE) for details.
---
---
## Links
- **Documentation**: https://muhammad-fiaz.github.io/loaders
- **Repository**: https://github.com/muhammad-fiaz/loaders
- **Issues**: https://github.com/muhammad-fiaz/loaders/issues
- **Pull Requests**: https://github.com/muhammad-fiaz/loaders/pulls