use {
std::{
io::{
self,
Write,
},
time::Instant,
},
termimad::{
crossterm::{
cursor,
queue,
style::{
style,
Color,
Print,
PrintStyledContent,
Stylize,
},
terminal::{
Clear,
ClearType,
},
},
ProgressBar,
},
};
pub fn print_progress(
label: &str,
done: usize,
total: usize,
post_label: Option<String>,
) -> anyhow::Result<()> {
let width = 12;
let total = total
.max(done) .max(1); let p = ProgressBar::new(done as f32 / (total as f32), width);
let s = format!("{:width$}", p, width = width);
let mut stderr = io::stderr();
queue!(stderr, cursor::SavePosition)?;
queue!(stderr, Clear(ClearType::CurrentLine))?;
queue!(stderr, Print(format!("{:>20} ", label)))?;
queue!(
stderr,
PrintStyledContent(style(s).with(Color::Yellow).on(Color::DarkBlue))
)?;
if let Some(post_label) = post_label {
queue!(stderr, Print(format!(" {}", post_label)))?;
}
queue!(stderr, cursor::RestorePosition)?;
stderr.flush()?;
Ok(())
}
#[allow(dead_code)]
pub fn clear_progress() -> anyhow::Result<()> {
let mut stderr = io::stderr();
queue!(stderr, cursor::SavePosition)?;
queue!(stderr, Clear(ClearType::CurrentLine))?;
queue!(stderr, cursor::RestorePosition)?;
stderr.flush()?;
Ok(())
}
#[derive(Clone)]
pub struct Task {
pub label: String,
pub show: bool,
pub done: usize,
pub total: usize,
pub start: Instant,
}
impl Task {
pub fn new<S: Into<String>>(label: S) -> Self {
let mut task = Self {
label: label.into(),
show: true,
done: 0,
total: 1,
start: Instant::now(),
};
task.update(0, 1);
task
}
pub fn with_total(
mut self,
total: usize,
) -> Self {
self.total = total;
self
}
pub fn update(
&mut self,
done: usize,
total: usize,
) {
if self.show {
self.done = done;
self.total = total;
let _ = print_progress(&self.label, done, total, None);
}
}
pub fn increment(&mut self) {
if self.show {
self.done += 1;
let _ = print_progress(&self.label, self.done, self.total, None);
}
}
pub fn update_with_label<S: Into<String>>(
&self,
done: usize,
total: usize,
post_label: S,
) {
if self.show {
let _ = print_progress(&self.label, done, total, Some(post_label.into()));
}
}
pub fn finish<S: Into<String>>(
&self,
post_label: S,
) {
if self.show {
let post_label = format!(
"{} in {:.1}s",
post_label.into(),
self.start.elapsed().as_secs_f32(),
);
let _ = print_progress(&self.label, 1, 1, Some(post_label));
eprintln!();
}
}
}