Closed pombadev closed 11 months ago
@chris-laplante any ideas?
@chris-laplante any ideas?
Yes, I think we can handle this like how tqdm handles it: https://github.com/tqdm/tqdm/issues/918. Basically, just like how we autodetect terminal width we should also look at terminal height and only try to draw as many progress bars as will fit on the screen.
I was playing around with async and I think I have the same problem with the code below.
It looks quite a bit more weird (in the error case). Also I use multiple progress bars for tasks and one main progress bar at the bottom to track overall progress.
Just change the "ITEMS" variable to a lower or higher value.
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use rand::prelude::*;
use std::convert::TryInto;
use tokio::task::JoinSet;
use tokio::time::{sleep, Duration};
use uuid::Uuid;
#[tokio::main]
async fn main() {
const ITEMS: usize = 30;
let uuids: Vec<(Uuid, usize)> = (0..ITEMS)
.into_iter()
// generate new uuid and an index
.map(|x| (Uuid::new_v4(), x))
.collect();
let multi_pb = MultiProgress::new();
let items_u64: u64 = ITEMS.try_into().unwrap();
let main_pb = multi_pb.add(ProgressBar::new(items_u64));
main_pb.set_style(
ProgressStyle::with_template(
"[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}",
)
.unwrap()
.progress_chars("##-"),
);
main_pb.set_message("total ");
// Make the main progress bar render immediately rather than waiting for the
// first task to finish.
main_pb.tick();
let mut set = JoinSet::new();
for (uuid, index) in uuids {
let steps = 100;
let task_pb = multi_pb.insert_before(&main_pb, ProgressBar::new(steps));
task_pb.set_style(
ProgressStyle::with_template(
"[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}",
)
.unwrap()
.progress_chars("##-"),
);
set.spawn(do_stuff(uuid, index, steps, task_pb));
}
let mut seen = [false; ITEMS];
while let Some(res) = set.join_next().await {
let idx = res.unwrap();
seen[idx] = true;
main_pb.inc(1);
}
main_pb.finish();
}
async fn do_stuff(uuid: Uuid, index: usize, steps: u64, task_pb: ProgressBar) -> usize {
let msg = format!("app #{} with id:{}", index, uuid);
task_pb.set_message(msg.clone());
// calculate "tick size" for progress bar to use with sleep (millisecs / steps)
let num = rand::thread_rng().gen_range(steps..=10000);
let tick = num / steps;
for _ in 0..steps {
sleep(Duration::from_millis(tick)).await;
task_pb.inc(1);
}
let msg = format!("DONE {}", &msg);
task_pb.finish_with_message(msg);
index
}
Similar to #144 , if progress bars exceeds terminal's height i.e if there are more progress bars than it is able fit in visible at once, newlines are created. Fix provided in #144 doesn't help either.
Reproduction steps:
Use this code and run it
Example