relay-cli 0.1.2

CLI interface for Relay Agents.
use atty::Stream;
use indicatif::{ProgressBar, ProgressStyle};

use crate::style::{CliStyle, Styles, Symbols};

pub struct Progress {
    silent: bool,
    bar: Option<ProgressBar>,
    symbols: Symbols,
    styles: Styles,
    pending: Option<String>,
}

impl Progress {
    pub fn new(silent: bool) -> Self {
        let style = CliStyle::detect();
        let symbols = Symbols::for_term(&style);
        let styles = Styles::for_term(&style);

        let bar = if !silent && atty::is(Stream::Stdout) {
            let pb = ProgressBar::new_spinner();
            pb.set_style(ProgressStyle::with_template("{spinner:.cyan} {msg}").unwrap());
            pb.enable_steady_tick(std::time::Duration::from_millis(80));
            Some(pb)
        } else {
            None
        };

        Self {
            silent,
            bar,
            symbols,
            styles,
            pending: None,
        }
    }

    pub fn pause(&mut self) {
        if let Some(ref bar) = self.bar {
            bar.finish_and_clear();
        }
    }

    pub fn resume(&mut self) {
        if let Some(ref bar) = self.bar {
            bar.enable_steady_tick(std::time::Duration::from_millis(80));
            if let Some(ref pending_message) = self.pending {
                bar.set_message(format!(
                    "{} {}",
                    self.symbols.arrow,
                    self.styles.dim.apply_to(pending_message)
                ));
            }
        }
    }

    pub fn step(&mut self, message: &str, done: &str) {
        if let Some(ref bar) = self.bar {
            if let Some(ref pending_message) = self.pending {
                bar.println(format!(
                    "{} {}",
                    self.styles.ok.apply_to(self.symbols.ok),
                    self.styles.dim.apply_to(pending_message)
                ));
            }
            bar.set_message(format!(
                "{} {}",
                self.symbols.arrow,
                self.styles.dim.apply_to(message)
            ));
        } else if let Some(ref pending_message) = self.pending
            && !self.silent
        {
            println!(
                "{} {}",
                self.styles.ok.apply_to(self.symbols.ok),
                self.styles.dim.apply_to(pending_message)
            );
        }
        self.pending = Some(done.to_string());
    }

    pub fn commit(&mut self) {
        if let Some(bar) = &self.bar
            && let Some(ref pending_message) = self.pending
        {
            bar.println(format!(
                "{} {}",
                self.styles.ok.apply_to(self.symbols.ok),
                self.styles.dim.apply_to(pending_message)
            ));
            bar.finish_and_clear();
        } else if let Some(ref pending_message) = self.pending
            && !self.silent
        {
            println!(
                "{} {}",
                self.styles.ok.apply_to(self.symbols.ok),
                self.styles.dim.apply_to(pending_message)
            );
        }
        self.pending = None;
    }

    pub fn abort(&mut self, message: &str) -> ! {
        if let Some(ref bar) = self.bar {
            bar.println(format!(
                "{} {}",
                self.styles.err.apply_to(self.symbols.err),
                self.styles.err.apply_to(message),
            ));
            bar.finish_and_clear();
        } else {
            eprintln!("{} {}", self.symbols.err, message);
        }

        std::process::exit(1);
    }

    pub fn error(&self, message: &str) {
        if let Some(ref bar) = self.bar {
            bar.println(format!(
                "{} {}",
                self.styles.err.apply_to(self.symbols.err),
                self.styles.err.apply_to(message)
            ));
        } else if !self.silent {
            eprintln!("{} {}", self.symbols.err, message);
        }
    }

    pub fn warn(&self, message: &str) {
        if let Some(ref bar) = self.bar {
            bar.println(format!(
                "{} {}",
                self.styles.warn.apply_to(self.symbols.warn),
                self.styles.warn.apply_to(message)
            ));
        } else if !self.silent {
            println!("{} {}", self.symbols.warn, message);
        }
    }

    pub fn warn_end(&self, message: &str) {
        if let Some(ref bar) = self.bar {
            bar.println(format!(
                "{} {}",
                self.styles.warn.apply_to(self.symbols.warn),
                self.styles.warn.apply_to(message)
            ));
            bar.finish_and_clear();
        } else if !self.silent {
            println!("{} {}", self.symbols.warn, message);
        }
    }

    pub fn arrow(&self, message: &str) {
        if let Some(ref bar) = self.bar {
            bar.println(format!(
                "{} {}",
                self.symbols.arrow,
                self.styles.ok.apply_to(message)
            ));
        } else if !self.silent {
            println!(
                "{} {}",
                self.symbols.arrow,
                self.styles.ok.apply_to(message)
            );
        }
    }

    pub fn nested_section(&self, level: u32, message: &str) {
        if let Some(ref bar) = self.bar {
            let indent = "  ".repeat(level as usize);
            bar.println(format!(
                "{}{} {}",
                indent,
                self.symbols.arrow,
                self.styles.ok.apply_to(message)
            ));
        } else if !self.silent {
            let indent = "  ".repeat(level as usize);
            println!(
                "{}{} {}",
                indent,
                self.symbols.arrow,
                self.styles.ok.apply_to(message)
            );
        }
    }

    pub fn nested(&self, level: u32, message: &str) {
        if let Some(ref bar) = self.bar {
            let indent = "  ".repeat(level as usize);
            bar.println(format!(
                "{}{} {}",
                indent,
                self.symbols.bullet,
                self.styles.dim.apply_to(message)
            ));
        } else if !self.silent {
            let indent = "  ".repeat(level as usize);
            println!(
                "{}{} {}",
                indent,
                self.symbols.bullet,
                self.styles.dim.apply_to(message)
            );
        }
    }

    pub fn skip_line(&self) {
        if let Some(ref bar) = self.bar {
            bar.println("");
        } else if !self.silent {
            println!();
        }
    }
}