Support NO_COLOR. (#782)

This commit is contained in:
Kevin Vigor 2023-06-12 11:06:11 -06:00 committed by GitHub
parent dfc67e54c8
commit 2c534fc69e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,4 +1,6 @@
use parking_lot::Once;
use std::fmt::{self, Formatter}; use std::fmt::{self, Formatter};
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,6 +23,9 @@ pub enum Colored {
UnderlineColor(Color), UnderlineColor(Color),
} }
static ANSI_COLOR_DISABLED: AtomicBool = AtomicBool::new(false);
static INITIALIZER: Once = Once::new();
impl Colored { impl Colored {
/// Parse an ANSI foreground or background color. /// Parse an ANSI foreground or background color.
/// This is the string that would appear within an `ESC [ <str> m` escape sequence, as found in /// This is the string that would appear within an `ESC [ <str> m` escape sequence, as found in
@ -64,12 +69,39 @@ impl Colored {
Some(output) Some(output)
} }
/// Checks whether ansi color sequences are disabled by setting of NO_COLOR
/// in environment as per https://no-color.org/
pub fn ansi_color_disabled() -> bool {
!std::env::var("NO_COLOR")
.unwrap_or("".to_string())
.is_empty()
}
pub fn ansi_color_disabled_memoized() -> bool {
INITIALIZER.call_once(|| {
ANSI_COLOR_DISABLED.store(Self::ansi_color_disabled(), Ordering::SeqCst);
});
ANSI_COLOR_DISABLED.load(Ordering::SeqCst)
}
#[cfg(test)]
pub fn set_ansi_color_disabled(val: bool) {
// Force the one-time initializer to run.
_ = Self::ansi_color_disabled_memoized();
ANSI_COLOR_DISABLED.store(val, Ordering::SeqCst);
}
} }
impl fmt::Display for Colored { impl fmt::Display for Colored {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let color; let color;
if Self::ansi_color_disabled_memoized() {
return Ok(());
}
match *self { match *self {
Colored::ForegroundColor(new_color) => { Colored::ForegroundColor(new_color) => {
if new_color == Color::Reset { if new_color == Color::Reset {
@ -125,40 +157,47 @@ impl fmt::Display for Colored {
mod tests { mod tests {
use crate::style::{Color, Colored}; use crate::style::{Color, Colored};
fn check_format_color(colored: Colored, expected: &str) {
Colored::set_ansi_color_disabled(true);
assert_eq!(colored.to_string(), "");
Colored::set_ansi_color_disabled(false);
assert_eq!(colored.to_string(), expected);
}
#[test] #[test]
fn test_format_fg_color() { fn test_format_fg_color() {
let colored = Colored::ForegroundColor(Color::Red); let colored = Colored::ForegroundColor(Color::Red);
assert_eq!(colored.to_string(), "38;5;9"); check_format_color(colored, "38;5;9");
} }
#[test] #[test]
fn test_format_bg_color() { fn test_format_bg_color() {
let colored = Colored::BackgroundColor(Color::Red); let colored = Colored::BackgroundColor(Color::Red);
assert_eq!(colored.to_string(), "48;5;9"); check_format_color(colored, "48;5;9");
} }
#[test] #[test]
fn test_format_reset_fg_color() { fn test_format_reset_fg_color() {
let colored = Colored::ForegroundColor(Color::Reset); let colored = Colored::ForegroundColor(Color::Reset);
assert_eq!(colored.to_string(), "39"); check_format_color(colored, "39");
} }
#[test] #[test]
fn test_format_reset_bg_color() { fn test_format_reset_bg_color() {
let colored = Colored::BackgroundColor(Color::Reset); let colored = Colored::BackgroundColor(Color::Reset);
assert_eq!(colored.to_string(), "49"); check_format_color(colored, "49");
} }
#[test] #[test]
fn test_format_fg_rgb_color() { fn test_format_fg_rgb_color() {
let colored = Colored::BackgroundColor(Color::Rgb { r: 1, g: 2, b: 3 }); let colored = Colored::BackgroundColor(Color::Rgb { r: 1, g: 2, b: 3 });
assert_eq!(colored.to_string(), "48;2;1;2;3"); check_format_color(colored, "48;2;1;2;3");
} }
#[test] #[test]
fn test_format_fg_ansi_color() { fn test_format_fg_ansi_color() {
let colored = Colored::ForegroundColor(Color::AnsiValue(255)); let colored = Colored::ForegroundColor(Color::AnsiValue(255));
assert_eq!(colored.to_string(), "38;5;255"); check_format_color(colored, "38;5;255");
} }
#[test] #[test]
@ -267,4 +306,16 @@ mod tests {
test("48;2;0;2;25;"); test("48;2;0;2;25;");
test("48;2;0;2;25;3"); test("48;2;0;2;25;3");
} }
#[test]
fn test_no_color() {
std::env::set_var("NO_COLOR", "1");
assert!(Colored::ansi_color_disabled());
std::env::set_var("NO_COLOR", "XXX");
assert!(Colored::ansi_color_disabled());
std::env::set_var("NO_COLOR", "");
assert!(!Colored::ansi_color_disabled());
std::env::remove_var("NO_COLOR");
assert!(!Colored::ansi_color_disabled());
}
} }