use crate::color::{Stream, decide_color};
use crate::output::{Env, OutputMode};
use anstyle::{AnsiColor, Color, Effects, Style};
#[derive(Debug, Clone, Copy, Default)]
pub struct Palette {
pub error: Style,
pub success: Style,
pub warn: Style,
pub dim: Style,
pub tag: Style,
}
impl Palette {
pub(crate) fn for_stream(
stream: Stream,
mode: OutputMode,
env: &dyn Env,
is_terminal: bool,
) -> Self {
if !decide_color(stream, mode, env, is_terminal) {
return Self::default();
}
Self {
error: Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::Red)))
.effects(Effects::BOLD),
success: Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::Green)))
.effects(Effects::BOLD),
warn: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Yellow))),
dim: Style::new().effects(Effects::DIMMED),
tag: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Cyan))),
}
}
}
pub fn stderr_error_palette() -> Palette {
use crate::output::RealEnv;
use std::io::IsTerminal;
Palette::for_stream(
Stream::Stderr,
OutputMode::Human,
&RealEnv,
std::io::stderr().is_terminal(),
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[derive(Debug, Default)]
struct FakeEnv {
vars: HashMap<String, String>,
}
impl FakeEnv {
fn with(mut self, k: &str, v: &str) -> Self {
self.vars.insert(k.into(), v.into());
self
}
}
impl Env for FakeEnv {
fn var(&self, name: &str) -> Option<String> {
self.vars.get(name).cloned()
}
fn stdout_is_terminal(&self) -> bool {
true
}
}
#[test]
fn json_stdout_yields_empty_palette() {
let env = FakeEnv::default().with("FORCE_COLOR", "1");
let p = Palette::for_stream(Stream::Stdout, OutputMode::Json, &env, true);
assert_eq!(p.error, Style::new());
assert_eq!(p.success, Style::new());
assert_eq!(p.warn, Style::new());
assert_eq!(p.dim, Style::new());
assert_eq!(p.tag, Style::new());
}
#[test]
fn default_palette_is_all_noop() {
let p = Palette::default();
assert_eq!(p.error, Style::new());
}
#[test]
fn human_tty_palette_is_populated() {
let env = FakeEnv::default();
let p = Palette::for_stream(Stream::Stderr, OutputMode::Human, &env, true);
assert_ne!(p.error, Style::new());
assert_ne!(p.success, Style::new());
}
#[test]
fn no_color_collapses() {
let env = FakeEnv::default().with("NO_COLOR", "1");
let p = Palette::for_stream(Stream::Stderr, OutputMode::Human, &env, true);
assert_eq!(p.error, Style::new());
}
}