Skip to main content

voirs_cli/
progress.rs

1//! Progress indication utilities.
2
3use indicatif::{ProgressBar, ProgressFinish, ProgressState, ProgressStyle};
4use std::fmt::Write;
5use std::time::Duration;
6
7/// Progress tracker for synthesis operations
8pub struct SynthesisProgress {
9    bar: ProgressBar,
10}
11
12impl SynthesisProgress {
13    /// Create a new synthesis progress bar
14    pub fn new(total_items: u64) -> Self {
15        let bar = ProgressBar::new(total_items);
16        bar.set_style(
17            ProgressStyle::with_template(
18                "{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {pos}/{len} {msg}",
19            )
20            .unwrap()
21            .with_key("eta", |state: &ProgressState, w: &mut dyn Write| {
22                write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()
23            })
24            .progress_chars("#>-"),
25        );
26        bar.set_message("Synthesizing...");
27
28        Self { bar }
29    }
30
31    /// Update progress with message
32    pub fn update(&self, pos: u64, msg: &str) {
33        self.bar.set_position(pos);
34        self.bar.set_message(msg.to_string());
35    }
36
37    /// Increment progress by 1
38    pub fn inc(&self, msg: &str) {
39        self.bar.inc(1);
40        self.bar.set_message(msg.to_string());
41    }
42
43    /// Finish progress bar
44    pub fn finish(&self, msg: &str) {
45        self.bar.finish_with_message(msg.to_string());
46    }
47}
48
49/// Progress tracker for download operations
50pub struct DownloadProgress {
51    bar: ProgressBar,
52}
53
54impl DownloadProgress {
55    /// Create a new download progress bar
56    pub fn new(total_bytes: u64, filename: &str) -> Self {
57        let bar = ProgressBar::new(total_bytes);
58        bar.set_style(
59            ProgressStyle::with_template(
60                "{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta}) {msg}"
61            )
62            .unwrap()
63            .progress_chars("#>-")
64        );
65        bar.set_message(format!("Downloading {}", filename));
66
67        Self { bar }
68    }
69
70    /// Update download progress
71    pub fn update(&self, downloaded_bytes: u64) {
72        self.bar.set_position(downloaded_bytes);
73    }
74
75    /// Finish download
76    pub fn finish(&self, msg: &str) {
77        self.bar.finish_with_message(msg.to_string());
78    }
79}
80
81/// Progress tracker for batch operations
82pub struct BatchProgress {
83    bar: ProgressBar,
84    start_time: std::time::Instant,
85}
86
87impl BatchProgress {
88    /// Create a new batch progress bar
89    pub fn new(total_items: u64, operation: &str) -> Self {
90        let bar = ProgressBar::new(total_items);
91        bar.set_style(
92            ProgressStyle::with_template(
93                "{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {pos}/{len} ({per_sec}) {msg}"
94            )
95            .unwrap()
96            .progress_chars("#>-")
97        );
98        bar.set_message(format!("Processing {} items...", operation));
99
100        Self {
101            bar,
102            start_time: std::time::Instant::now(),
103        }
104    }
105
106    /// Update batch progress
107    pub fn update(&self, pos: u64, current_item: &str) {
108        self.bar.set_position(pos);
109        self.bar
110            .set_message(format!("Processing: {}", current_item));
111    }
112
113    /// Increment batch progress
114    pub fn inc(&self, current_item: &str) {
115        self.bar.inc(1);
116        self.bar
117            .set_message(format!("Processing: {}", current_item));
118    }
119
120    /// Finish batch processing
121    pub fn finish(&self, msg: &str) {
122        let elapsed = self.start_time.elapsed();
123        self.bar.finish_with_message(format!(
124            "{} (completed in {:.2}s)",
125            msg,
126            elapsed.as_secs_f64()
127        ));
128    }
129
130    /// Get elapsed time
131    pub fn elapsed(&self) -> Duration {
132        self.start_time.elapsed()
133    }
134}
135
136/// Simple spinner for indeterminate operations
137pub struct Spinner {
138    bar: ProgressBar,
139}
140
141impl Spinner {
142    /// Create a new spinner
143    pub fn new(msg: &str) -> Self {
144        let bar = ProgressBar::new_spinner();
145        bar.enable_steady_tick(Duration::from_millis(120));
146        bar.set_style(
147            ProgressStyle::with_template("{spinner:.blue} {msg}")
148                .unwrap()
149                .tick_strings(&[
150                    "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁",
151                ]),
152        );
153        bar.set_message(msg.to_string());
154
155        Self { bar }
156    }
157
158    /// Update spinner message
159    pub fn update(&self, msg: &str) {
160        self.bar.set_message(msg.to_string());
161    }
162
163    /// Finish spinner
164    pub fn finish(&self, msg: &str) {
165        self.bar.finish_with_message(msg.to_string());
166    }
167}
168
169/// Create a simple progress bar for file operations
170pub fn create_file_progress(total_files: usize, operation: &str) -> ProgressBar {
171    let bar = ProgressBar::new(total_files as u64);
172    bar.set_style(
173        ProgressStyle::with_template(&format!(
174            "{{spinner:.green}} {} [{{bar:.cyan/blue}}] {{pos}}/{{len}} {{msg}}",
175            operation
176        ))
177        .unwrap()
178        .progress_chars("#>-"),
179    );
180    bar
181}
182
183/// Create a progress bar with custom style
184pub fn create_custom_progress(total: u64, template: &str) -> ProgressBar {
185    let bar = ProgressBar::new(total);
186    if let Ok(style) = ProgressStyle::with_template(template) {
187        bar.set_style(style.progress_chars("#>-"));
188    }
189    bar
190}