Expand description

A progress bar library with a focus on ergonomics.

Usage

use headway::ProgressBarIterable;

for _ in (0..100).progress() {
    sleep(Duration::from_millis(20));
}

Multiple bars

Multiple bars are transparently supported. Just create more of them and they will automatically be placed so that they do not overlap.

use headway::ProgressBarIterable;

let mut handles = vec![];
for i in 0..5 {
    handles.push(thread::spawn(move || {
        for _ in (0..100).progress() {
            sleep(Duration::from_millis(20 + i * 20));
        }
    }));
}
for handle in handles {
    handle.join().unwrap();
}

Splitting bars

You can split bars into smaller bars if you have a task that consists of several sub-tasks.

use headway::{ProgressBar, ProgressBarIterable};

let mut p = ProgressBar::new().split_weighted();
let first_half = p.take(0.5).with_message("First part");
let second_half = p.take(0.5).with_message("Second part");
for _ in (0..50).progress_with(first_half) {
    sleep(Duration::from_millis(20));
}
for _ in (0..50).progress_with(second_half) {
    sleep(Duration::from_millis(30));
}

You can also split in other ways, not just using fractions.

use headway::ProgressBar;

// Split the bar into bars taking up a fixed fraction of the parent
let mut p = ProgressBar::new().split_weighted();
let first_quarter = p.take(0.25);
let last_three_quarters = p.take(0.75);

// Split the bar into fixed size nested bars
let p = ProgressBar::new();
p.set_length(50);
let mut p = p.split_sized();
let first_10 = p.take(10);
let another_30 = p.take(30);
let last_10 = p.remaining();

// Split the bar and display it by summing the progress from each child
let p = ProgressBar::new().split_summed();
let first = p.take();
let second = p.take();

// Split into several bars, each representing one item of the iterator
let items = &["a", "b", "c", "d"];
for (nested_bar, letter) in ProgressBar::new().split_each(items.iter()) {}

Printing while a progress bar is visible

Most progress bar libraries have their output messed up in some way if you try to e.g. call println while a progress bar is visible. Either the progress bar gets clobbered, or your printed text gets overwritten, or both!

This library interacts properly with stdout so you can freely use println while a progress bar (or multiple) is visible.

use headway::ProgressBarIterable;

for i in (0..100).progress() {
    if i % 10 == 0 {
        println!("{}", i);
    }
    sleep(Duration::from_millis(20));
}

Caveats

Printing to stderr has the potential to mess things up. However, if you flush stdout before you print to stderr then things should work properly. If a child process prints to stdout, this also has the potential to mess things up.

Abandoning bars

If you abandon a bar without finishing it (for example because a worker thread crashed), then the bar will draw angry red marks to draw your attention. You can also explicitly abandon a bar using ProgressBar::abandon.

use headway::ProgressBarIterable;

for i in (0..100).progress() {
    if i == 20 {
        panic!("Something went wrong!");
    }
    sleep(Duration::from_millis(50));
}

Indeterminate bars

If the progress bar doesn’t have a known length, the bar will show an animation instead.

use headway::ProgressBarIterable;

for i in (0..).progress() {
    if i == 100 {
        break;
    }
    sleep(Duration::from_millis(50));
}

Styling

It is currently not possible to style bars in any way.

Alternative crates

  • Indicatif - A crate which supports progress bars and spinners and lots of styling. However it is less ergonomic, especially when working with multiple progress bars. It also interacts poorly with simultaneous printing to stdout.

Structs

A convenient progress bar.
A progress bar that wraps an iterator.
Helper for spliting progress bars
Helper for spliting progress bars
Helper for spliting progress bars

Traits