mago_feedback/
progress.rs

1#![allow(unknown_lints)]
2#![allow(clippy::literal_string_with_formatting_args)]
3
4use std::sync::LazyLock;
5
6use indicatif::MultiProgress;
7use indicatif::ProgressBar;
8use indicatif::ProgressStyle;
9
10/// A global multi-progress bar that allows managing multiple progress bars concurrently.
11pub static GLOBAL_PROGRESS_MANAGER: LazyLock<MultiProgress> = LazyLock::new(MultiProgress::new);
12
13/// Creates a new progress bar with the specified length and theme.
14///
15/// # Arguments
16///
17/// * `length` - The total length of the progress bar, representing the total units of work.
18/// * `theme` - The theme of the progress bar.
19///
20/// # Returns
21///
22/// A `ProgressBar` that is styled and ready to use.
23pub fn create_progress_bar(length: usize, prefix: &'static str, theme: ProgressBarTheme) -> ProgressBar {
24    let pb = GLOBAL_PROGRESS_MANAGER.add(ProgressBar::new(length as u64));
25    pb.set_style(
26        ProgressStyle::with_template(theme.template())
27            .unwrap()
28            .progress_chars(theme.progress_chars())
29            .tick_chars(theme.tick_chars()),
30    );
31
32    pb.set_prefix(prefix);
33
34    pb
35}
36
37/// Removes the specified progress bar from the global multi-progress manager.
38///
39/// # Arguments
40///
41/// * `progress_bar` - The progress bar to remove.
42pub fn remove_progress_bar(progress_bar: ProgressBar) {
43    progress_bar.finish_and_clear();
44
45    GLOBAL_PROGRESS_MANAGER.remove(&progress_bar);
46}
47
48/// Represents different visual themes for the progress bar.
49#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub enum ProgressBarTheme {
51    Red,
52    Yellow,
53    Green,
54    Blue,
55    Magenta,
56    Cyan,
57}
58
59impl ProgressBarTheme {
60    /// Returns the template string for the selected theme, defining the layout and appearance of the progress bar.
61    pub fn template(&self) -> &'static str {
62        match self {
63            Self::Red => "{spinner} {prefix:<16.bold}▕{wide_bar:.red}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
64            Self::Yellow => "{spinner} {prefix:<16.bold}▕{wide_bar:.yellow}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
65            Self::Green => "{spinner} {prefix:<16.bold}▕{wide_bar:.green}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
66            Self::Blue => "{spinner} {prefix:<16.bold}▕{wide_bar:.blue}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
67            Self::Magenta => "{spinner} {prefix:<16.bold}▕{wide_bar:.magenta}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
68            Self::Cyan => "{spinner} {prefix:<16.bold}▕{wide_bar:.cyan}▏{pos:>6}/{len}▕  {percent:>3}%▕  ETA: {eta_precise}▕  Elapsed: {elapsed_precise}",
69        }
70    }
71
72    /// Returns the characters used to represent the progress of the bar.
73    pub fn progress_chars(&self) -> &'static str {
74        match self {
75            ProgressBarTheme::Red => "█░ ",
76            ProgressBarTheme::Yellow => "█▉▊▋▌▍▎▏░ ",
77            ProgressBarTheme::Green => "█▇▆▅▄▃▂▁░ ",
78            ProgressBarTheme::Blue => "█▓▒░░ ",
79            ProgressBarTheme::Magenta => "█▛▌▖░ ",
80            ProgressBarTheme::Cyan => "█▉▊▋▌▍▎▏░ ",
81        }
82    }
83
84    /// Returns the characters used to animate the spinner/ticker in the progress bar.
85    pub fn tick_chars(&self) -> &'static str {
86        match self {
87            ProgressBarTheme::Red => "⠁⠂⠄⡀⢀⠠⠐⠈ ",
88            ProgressBarTheme::Yellow => "⢀⠠⠐⠈⠁⠂⠄⡀ ",
89            ProgressBarTheme::Green => "⠄⡀⢀⠠⠐⠈⠁⠂ ",
90            ProgressBarTheme::Blue => "⡀⢀⠠⠐⠈⠁⠂⠄ ",
91            ProgressBarTheme::Magenta => "⠐⠈⠁⠂⠄⡀⢀⠠ ",
92            ProgressBarTheme::Cyan => "⠠⠐⠈⠁⠂⠄⡀⢀ ",
93        }
94    }
95}