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!();
}
}
}