use indicatif::{ProgressBar, ProgressFinish, ProgressState, ProgressStyle};
use std::fmt::Write;
use std::time::Duration;
pub struct SynthesisProgress {
bar: ProgressBar,
}
impl SynthesisProgress {
pub fn new(total_items: u64) -> Self {
let bar = ProgressBar::new(total_items);
bar.set_style(
ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {pos}/{len} {msg}",
)
.expect("progress template is valid")
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| {
let _ = write!(w, "{:.1}s", state.eta().as_secs_f64());
})
.progress_chars("#>-"),
);
bar.set_message("Synthesizing...");
Self { bar }
}
pub fn update(&self, pos: u64, msg: &str) {
self.bar.set_position(pos);
self.bar.set_message(msg.to_string());
}
pub fn inc(&self, msg: &str) {
self.bar.inc(1);
self.bar.set_message(msg.to_string());
}
pub fn finish(&self, msg: &str) {
self.bar.finish_with_message(msg.to_string());
}
}
pub struct DownloadProgress {
bar: ProgressBar,
}
impl DownloadProgress {
pub fn new(total_bytes: u64, filename: &str) -> Self {
let bar = ProgressBar::new(total_bytes);
bar.set_style(
ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta}) {msg}"
)
.expect("progress template is valid")
.progress_chars("#>-")
);
bar.set_message(format!("Downloading {}", filename));
Self { bar }
}
pub fn update(&self, downloaded_bytes: u64) {
self.bar.set_position(downloaded_bytes);
}
pub fn finish(&self, msg: &str) {
self.bar.finish_with_message(msg.to_string());
}
}
pub struct BatchProgress {
bar: ProgressBar,
start_time: std::time::Instant,
}
impl BatchProgress {
pub fn new(total_items: u64, operation: &str) -> Self {
let bar = ProgressBar::new(total_items);
bar.set_style(
ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {pos}/{len} ({per_sec}) {msg}"
)
.expect("progress template is valid")
.progress_chars("#>-")
);
bar.set_message(format!("Processing {} items...", operation));
Self {
bar,
start_time: std::time::Instant::now(),
}
}
pub fn update(&self, pos: u64, current_item: &str) {
self.bar.set_position(pos);
self.bar
.set_message(format!("Processing: {}", current_item));
}
pub fn inc(&self, current_item: &str) {
self.bar.inc(1);
self.bar
.set_message(format!("Processing: {}", current_item));
}
pub fn finish(&self, msg: &str) {
let elapsed = self.start_time.elapsed();
self.bar.finish_with_message(format!(
"{} (completed in {:.2}s)",
msg,
elapsed.as_secs_f64()
));
}
pub fn elapsed(&self) -> Duration {
self.start_time.elapsed()
}
}
pub struct Spinner {
bar: ProgressBar,
}
impl Spinner {
pub fn new(msg: &str) -> Self {
let bar = ProgressBar::new_spinner();
bar.enable_steady_tick(Duration::from_millis(120));
bar.set_style(
ProgressStyle::with_template("{spinner:.blue} {msg}")
.expect("progress template is valid")
.tick_strings(&[
"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁",
]),
);
bar.set_message(msg.to_string());
Self { bar }
}
pub fn update(&self, msg: &str) {
self.bar.set_message(msg.to_string());
}
pub fn finish(&self, msg: &str) {
self.bar.finish_with_message(msg.to_string());
}
}
pub fn create_file_progress(total_files: usize, operation: &str) -> ProgressBar {
let bar = ProgressBar::new(total_files as u64);
bar.set_style(
ProgressStyle::with_template(&format!(
"{{spinner:.green}} {} [{{bar:.cyan/blue}}] {{pos}}/{{len}} {{msg}}",
operation
))
.expect("progress template is valid")
.progress_chars("#>-"),
);
bar
}
pub fn create_custom_progress(total: u64, template: &str) -> ProgressBar {
let bar = ProgressBar::new(total);
if let Ok(style) = ProgressStyle::with_template(template) {
bar.set_style(style.progress_chars("#>-"));
}
bar
}