Skip to main content

fallow_core/
progress.rs

1use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
2
3/// Progress reporter for analysis stages.
4pub struct AnalysisProgress {
5    multi: MultiProgress,
6    enabled: bool,
7}
8
9impl AnalysisProgress {
10    /// Create a new progress reporter.
11    pub fn new(enabled: bool) -> Self {
12        Self {
13            multi: MultiProgress::new(),
14            enabled,
15        }
16    }
17
18    /// Create a spinner for a stage.
19    pub fn stage_spinner(&self, message: &str) -> ProgressBar {
20        if !self.enabled {
21            return ProgressBar::hidden();
22        }
23
24        let pb = self.multi.add(ProgressBar::new_spinner());
25        pb.set_style(
26            ProgressStyle::with_template("{spinner:.cyan} {msg}")
27                .unwrap()
28                .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "),
29        );
30        pb.set_message(message.to_string());
31        pb.enable_steady_tick(std::time::Duration::from_millis(80));
32        pb
33    }
34
35    /// Create a progress bar for file processing.
36    pub fn file_progress(&self, total: u64, message: &str) -> ProgressBar {
37        if !self.enabled {
38            return ProgressBar::hidden();
39        }
40
41        let pb = self.multi.add(ProgressBar::new(total));
42        pb.set_style(
43            ProgressStyle::with_template(
44                "{spinner:.cyan} {msg} [{bar:30.cyan/dim}] {pos}/{len} ({eta})",
45            )
46            .unwrap()
47            .progress_chars("━━╸━"),
48        );
49        pb.set_message(message.to_string());
50        pb
51    }
52
53    /// Finish all progress bars.
54    pub fn finish(&self) {
55        self.multi.clear().ok();
56    }
57}
58
59impl Default for AnalysisProgress {
60    fn default() -> Self {
61        Self::new(false)
62    }
63}