From aab1d3db59f33bc2fde975ffb9e7c9209a9ec4e1 Mon Sep 17 00:00:00 2001 From: Max Zhuravsky Date: Thu, 25 Nov 2021 23:37:02 +0300 Subject: [PATCH 1/3] [no-color] - implement NO_COLOR support --- .gitignore | 3 +++ src/options/theme.rs | 11 ++++++++--- src/options/vars.rs | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index ede6ac0..0ae41f6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ parts prime stage *.snap + +# IntelliJ IDEA files +.idea diff --git a/src/options/theme.rs b/src/options/theme.rs index 02309f7..12d24ec 100644 --- a/src/options/theme.rs +++ b/src/options/theme.rs @@ -5,7 +5,7 @@ use crate::theme::{Options, UseColours, ColourScale, Definitions}; impl Options { pub fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { - let use_colours = UseColours::deduce(matches)?; + let use_colours = UseColours::deduce(matches, vars)?; let colour_scale = ColourScale::deduce(matches)?; let definitions = if use_colours == UseColours::Never { @@ -21,10 +21,15 @@ impl Options { impl UseColours { - fn deduce(matches: &MatchedFlags<'_>) -> Result { + fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { + let default_value = match vars.get(vars::NO_COLOR) { + Some(_) => Self::Never, + None => Self::Automatic, + }; + let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? { Some(w) => w, - None => return Ok(Self::Automatic), + None => return Ok(default_value), }; if word == "always" { diff --git a/src/options/vars.rs b/src/options/vars.rs index a8fc40e..9ce6cc5 100644 --- a/src/options/vars.rs +++ b/src/options/vars.rs @@ -15,6 +15,9 @@ pub static COLUMNS: &str = "COLUMNS"; /// Environment variable used to datetime format. pub static TIME_STYLE: &str = "TIME_STYLE"; +/// Environment variable used to disable colors. +/// See: https://no-color.org/ +pub static NO_COLOR: &str = "NO_COLOR"; // exa-specific variables From a371c41711af22235ef258cf545288407475a0c1 Mon Sep 17 00:00:00 2001 From: Max Zhuravsky Date: Fri, 26 Nov 2021 01:45:41 +0300 Subject: [PATCH 2/3] [no-color] - add unit test and doc --- man/exa.1.md | 6 ++++ src/options/theme.rs | 76 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/man/exa.1.md b/man/exa.1.md index bd91a7c..24cec4f 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -224,6 +224,12 @@ Specifies the number of spaces to print between an icon (see the ‘`--icons`’ Different terminals display icons differently, as they usually take up more than one character width on screen, so there’s no “standard” number of spaces that exa can use to separate an icon from text. One space may place the icon too close to the text, and two spaces may place it too far away. So the choice is left up to the user to configure depending on their terminal emulator. +## `NO_COLOR` + +Disables ANSI colour in the output (regardless of its value). Can be overridden by `--color` option. + +See `https://no-color.org/` for details. + ## `LS_COLORS`, `EXA_COLORS` Specifies the colour scheme used to highlight files based on their name and kind, as well as highlighting metadata and parts of the UI. diff --git a/src/options/theme.rs b/src/options/theme.rs index 12d24ec..010de4a 100644 --- a/src/options/theme.rs +++ b/src/options/theme.rs @@ -92,6 +92,16 @@ mod terminal_test { } }; + ($name:ident: $type:ident <- $inputs:expr, $env:expr; $stricts:expr => $result:expr) => { + #[test] + fn $name() { + let env = $env; + for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &env)) { + assert_eq!(result, $result); + } + } + }; + ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => { #[test] fn $name() { @@ -100,11 +110,39 @@ mod terminal_test { } } }; + + ($name:ident: $type:ident <- $inputs:expr, $env:expr; $stricts:expr => err $result:expr) => { + #[test] + fn $name() { + let env = $env; + for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &env)) { + assert_eq!(result.unwrap_err(), $result); + } + } + }; } struct MockVars { ls: &'static str, exa: &'static str, + no_color: &'static str, + } + + impl MockVars { + fn empty() -> MockVars { + return MockVars { + ls: "", + exa: "", + no_color: "", + }; + } + fn with_no_color() -> MockVars { + return MockVars { + ls: "", + exa: "", + no_color: "true", + }; + } } // Test impl that just returns the value it has. @@ -116,6 +154,9 @@ mod terminal_test { else if name == vars::EXA_COLORS && ! self.exa.is_empty() { Some(OsString::from(self.exa.clone())) } + else if name == vars::NO_COLOR && ! self.no_color.is_empty() { + Some(OsString::from(self.no_color.clone())) + } else { None } @@ -125,32 +166,33 @@ mod terminal_test { // Default - test!(empty: UseColours <- []; Both => Ok(UseColours::Automatic)); + test!(empty: UseColours <- [], MockVars::empty(); Both => Ok(UseColours::Automatic)); + test!(empty_with_no_color: UseColours <- [], MockVars::with_no_color(); Both => Ok(UseColours::Never)); // --colour - test!(u_always: UseColours <- ["--colour=always"]; Both => Ok(UseColours::Always)); - test!(u_auto: UseColours <- ["--colour", "auto"]; Both => Ok(UseColours::Automatic)); - test!(u_never: UseColours <- ["--colour=never"]; Both => Ok(UseColours::Never)); + test!(u_always: UseColours <- ["--colour=always"], MockVars::empty(); Both => Ok(UseColours::Always)); + test!(u_auto: UseColours <- ["--colour", "auto"], MockVars::empty(); Both => Ok(UseColours::Automatic)); + test!(u_never: UseColours <- ["--colour=never"], MockVars::empty(); Both => Ok(UseColours::Never)); // --color - test!(no_u_always: UseColours <- ["--color", "always"]; Both => Ok(UseColours::Always)); - test!(no_u_auto: UseColours <- ["--color=auto"]; Both => Ok(UseColours::Automatic)); - test!(no_u_never: UseColours <- ["--color", "never"]; Both => Ok(UseColours::Never)); + test!(no_u_always: UseColours <- ["--color", "always"], MockVars::empty(); Both => Ok(UseColours::Always)); + test!(no_u_auto: UseColours <- ["--color=auto"], MockVars::empty(); Both => Ok(UseColours::Automatic)); + test!(no_u_never: UseColours <- ["--color", "never"], MockVars::empty(); Both => Ok(UseColours::Never)); // Errors - test!(no_u_error: UseColours <- ["--color=upstream"]; Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("upstream"))); // the error is for --color - test!(u_error: UseColours <- ["--colour=lovers"]; Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("lovers"))); // and so is this one! + test!(no_u_error: UseColours <- ["--color=upstream"], MockVars::empty(); Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("upstream"))); // the error is for --color + test!(u_error: UseColours <- ["--colour=lovers"], MockVars::empty(); Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("lovers"))); // and so is this one! // Overriding - test!(overridden_1: UseColours <- ["--colour=auto", "--colour=never"]; Last => Ok(UseColours::Never)); - test!(overridden_2: UseColours <- ["--color=auto", "--colour=never"]; Last => Ok(UseColours::Never)); - test!(overridden_3: UseColours <- ["--colour=auto", "--color=never"]; Last => Ok(UseColours::Never)); - test!(overridden_4: UseColours <- ["--color=auto", "--color=never"]; Last => Ok(UseColours::Never)); + test!(overridden_1: UseColours <- ["--colour=auto", "--colour=never"], MockVars::empty(); Last => Ok(UseColours::Never)); + test!(overridden_2: UseColours <- ["--color=auto", "--colour=never"], MockVars::empty(); Last => Ok(UseColours::Never)); + test!(overridden_3: UseColours <- ["--colour=auto", "--color=never"], MockVars::empty(); Last => Ok(UseColours::Never)); + test!(overridden_4: UseColours <- ["--color=auto", "--color=never"], MockVars::empty(); Last => Ok(UseColours::Never)); - test!(overridden_5: UseColours <- ["--colour=auto", "--colour=never"]; Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("colour"))); - test!(overridden_6: UseColours <- ["--color=auto", "--colour=never"]; Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("colour"))); - test!(overridden_7: UseColours <- ["--colour=auto", "--color=never"]; Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("color"))); - test!(overridden_8: UseColours <- ["--color=auto", "--color=never"]; Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("color"))); + test!(overridden_5: UseColours <- ["--colour=auto", "--colour=never"], MockVars::empty(); Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("colour"))); + test!(overridden_6: UseColours <- ["--color=auto", "--colour=never"], MockVars::empty(); Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("colour"))); + test!(overridden_7: UseColours <- ["--colour=auto", "--color=never"], MockVars::empty(); Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("color"))); + test!(overridden_8: UseColours <- ["--color=auto", "--color=never"], MockVars::empty(); Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("color"))); test!(scale_1: ColourScale <- ["--color-scale", "--colour-scale"]; Last => Ok(ColourScale::Gradient)); test!(scale_2: ColourScale <- ["--color-scale", ]; Last => Ok(ColourScale::Gradient)); From c6874f0b3276b21a8a4ea02e06bef1a20d8af412 Mon Sep 17 00:00:00 2001 From: Max Zhuravsky Date: Mon, 6 Dec 2021 02:03:47 +0300 Subject: [PATCH 3/3] [baseline] - fix docs and remove gitignore --- .gitignore | 3 --- man/exa.1.md | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0ae41f6..ede6ac0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,3 @@ parts prime stage *.snap - -# IntelliJ IDEA files -.idea diff --git a/man/exa.1.md b/man/exa.1.md index 24cec4f..7bafd3f 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -226,7 +226,7 @@ Different terminals display icons differently, as they usually take up more than ## `NO_COLOR` -Disables ANSI colour in the output (regardless of its value). Can be overridden by `--color` option. +Disables colours in the output (regardless of its value). Can be overridden by `--color` option. See `https://no-color.org/` for details.