use std::io::IsTerminal;
use crate::app::ColorChoice;
#[derive(Debug, Clone, Copy)]
pub(super) struct Style {
enabled: bool,
}
impl Style {
pub(super) fn new(choice: ColorChoice) -> Self {
let enabled = match choice {
ColorChoice::Always => true,
ColorChoice::Never => false,
ColorChoice::Auto => std::io::stdout().is_terminal(),
};
Self { enabled }
}
#[cfg(test)]
pub(super) fn plain() -> Self {
Self { enabled: false }
}
fn wrap(&self, escape: &str, s: &str) -> String {
if self.enabled {
format!("\x1b[{escape}m{s}\x1b[0m")
} else {
s.to_string()
}
}
pub(super) fn bold(&self, s: &str) -> String {
self.wrap("1", s)
}
pub(super) fn dim(&self, s: &str) -> String {
self.wrap("2", s)
}
pub(super) fn bold_cyan(&self, s: &str) -> String {
self.wrap("1;36", s)
}
pub(super) fn bold_green(&self, s: &str) -> String {
self.wrap("1;32", s)
}
pub(super) fn dim_red(&self, s: &str) -> String {
self.wrap("2;31", s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plain_is_identity() {
let s = Style::plain();
assert_eq!(s.bold("x"), "x");
assert_eq!(s.dim("y"), "y");
assert_eq!(s.bold_cyan("z"), "z");
}
#[test]
fn never_disables_even_on_tty() {
let s = Style::new(ColorChoice::Never);
assert_eq!(s.bold("hello"), "hello");
}
#[test]
fn always_emits_escapes() {
let s = Style::new(ColorChoice::Always);
assert_eq!(s.bold("hi"), "\x1b[1mhi\x1b[0m");
assert_eq!(s.dim_red("?"), "\x1b[2;31m?\x1b[0m");
}
}