use super::lines::Line as OutputLine;
use console::Term;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use std::time::Duration;
pub struct Printer {
pub use_color: bool,
pub is_ci: bool,
}
impl Printer {
#[must_use]
pub fn new() -> Self {
let is_ci = std::env::var("CI").is_ok();
let is_tty = Term::stdout().is_term();
let no_color = std::env::var("NO_COLOR").is_ok();
let use_color = is_tty && !no_color && !is_ci;
Self { use_color, is_ci }
}
#[must_use]
pub fn spinner(&self, message: &str) -> Option<ProgressBar> {
if self.is_ci || !Term::stderr().is_term() {
return None;
}
let pb = ProgressBar::with_draw_target(None, ProgressDrawTarget::stderr());
pb.set_style(
ProgressStyle::default_spinner()
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
.template("{spinner} {msg}")
.unwrap_or_else(|_| ProgressStyle::default_spinner()),
);
pb.enable_steady_tick(Duration::from_millis(80));
pb.set_message(message.to_owned());
Some(pb)
}
pub fn print_lines(&self, lines: &[OutputLine]) {
use std::io::Write as _;
let stdout = std::io::stdout();
let mut handle = stdout.lock();
for line in lines {
drop(writeln!(handle, "{}", line.format_line(self.use_color)));
}
}
}
impl Default for Printer {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn printer_new_respects_ci_env() {
let printer = Printer::new();
if std::env::var("CI").is_ok() {
assert!(!printer.use_color);
assert!(printer.is_ci);
}
}
#[test]
fn printer_new_respects_no_color() {
let printer = Printer {
use_color: false,
is_ci: false,
};
assert!(!printer.use_color);
}
#[test]
fn printer_spinner_returns_none_in_ci() {
let printer = Printer {
use_color: false,
is_ci: true,
};
let spinner = printer.spinner("test");
assert!(spinner.is_none());
}
}