Indicatif Progress Bar CLI Logging

Render multi-stage CLI progress with indicatif: throttled bars, nested stages, log interception, and clean terminal restoration.

RustCli Tooling

Code

snippet
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
// progress logging: println pauses bar redraw to keep output clean
use std::time::Duration;

fn make_style(template: &str) -> ProgressStyle {
    ProgressStyle::with_template(template)
        .unwrap()
        .progress_chars("=>-")
}

async fn process_stage(
    bar: &ProgressBar,
    total: u64,
    item_ms: u64,
) -> u64 {
    let mut checksum = 0u64;
    for i in 0..total {
        tokio::time::sleep(Duration::from_millis(item_ms)).await;
        checksum = checksum.wrapping_add(i * 31);
        bar.inc(1);
    }
    checksum
}

#[tokio::main]
async fn main() {
    let multi = MultiProgress::new();

    let download = multi.add(ProgressBar::new(40));
    download.set_style(make_style(
        "[{bar:40.cyan/blue}] {pos}/{len} files ({eta})",
    ));

    let verify = multi.add(ProgressBar::new(20));
    verify.set_style(make_style(
        "[{bar:40.green/white}] {pos}/{len} chunks {msg}",
    ));

    // 进度条与日志共存:suspend 暂停渲染打印普通输出
    multi.println("starting pipeline").unwrap();

    let sum1 = process_stage(&download, 40, 10).await;
    download.finish_with_message("download complete");

    verify.set_message("verifying");
    let sum2 = process_stage(&verify, 20, 15).await;

    multi.println(format!("checksums: {sum1} / {sum2}")).unwrap();

    // 短任务用 spinner:避免为毫秒级操作渲染完整进度条
    let spinner = multi.add(ProgressBar::new_spinner());
    spinner.set_style(make_style("{spinner:.magenta} {msg}"));
    spinner.set_message("finalizing");
    tokio::time::sleep(Duration::from_millis(300)).await;
    spinner.finish_with_message("done");

    multi.clear().unwrap();
}