diff --git a/bin/src/traits.rs b/bin/src/traits.rs index 284adf4b..aebebd1e 100644 --- a/bin/src/traits.rs +++ b/bin/src/traits.rs @@ -1,4 +1,5 @@ use std::{ + env, io::{self, Write}, str, }; @@ -46,6 +47,7 @@ fn write_stderr( lint_result: &LintResult, vfs: &ReadOnlyVfs, ) -> io::Result<()> { + let no_color = env::var("NO_COLOR").is_ok(); let file_id = lint_result.file_id; let src = str::from_utf8(vfs.get(file_id)).unwrap(); let path = vfs.file_path(file_id); @@ -70,6 +72,7 @@ fn write_stderr( CliReport::build(report_kind, src_id, offset) .with_config( CliConfig::default() + .with_color(!no_color) .with_cross_gap(true) .with_multiline_arrows(false) .with_label_attach(LabelAttach::Middle) @@ -78,11 +81,16 @@ fn write_stderr( .with_message(report.note) .with_code(report.code), |cli_report, diagnostic| { - cli_report.with_label( - Label::new((src_id, range(diagnostic.at))) + let mut label = Label::new((src_id, range(diagnostic.at))); + if no_color { + label = + label.with_message(diagnostic.message.split('`').collect::()); + } else { + label = label .with_message(colorize(&diagnostic.message)) - .with_color(Color::Magenta), - ) + .with_color(Color::Magenta); + } + cli_report.with_label(label) }, ) .finish() diff --git a/bin/tests/_utils.rs b/bin/tests/_utils.rs index 6dcc2a7f..d4d8cbc0 100644 --- a/bin/tests/_utils.rs +++ b/bin/tests/_utils.rs @@ -1,8 +1,15 @@ -use std::{io::Write, process::Command}; +use std::{collections::HashMap, io::Write, process::Command}; use tempfile::NamedTempFile; -pub fn test_cli(expression: &str, args: &[&str]) -> anyhow::Result { +pub fn test_cli( + expression: &str, + args: &[&str], + envs: HashMap<&str, &str>, + output_processing: OutputProcessing, +) -> anyhow::Result +where +{ let mut fixture = NamedTempFile::with_suffix(".nix")?; fixture.write_all(expression.as_bytes())?; fixture.write_all(b"\n")?; // otherwise diff says there's no newline at end of file @@ -12,11 +19,21 @@ pub fn test_cli(expression: &str, args: &[&str]) -> anyhow::Result { .arg("--") .args(args) .arg(fixture.path()) + .envs(envs) .output()?; - let stdout = strip_ansi_escapes::strip(output.stdout)?; + let stdout = match output_processing { + OutputProcessing::Unchanged => output.stdout, + OutputProcessing::StripAnsi => strip_ansi_escapes::strip(output.stdout)?, + }; let stdout = String::from_utf8(stdout)?; let stdout = stdout.replace(fixture.path().to_str().unwrap(), ""); Ok(stdout) } + +#[allow(unused)] +pub enum OutputProcessing { + Unchanged, + StripAnsi, +} diff --git a/bin/tests/no_color.rs b/bin/tests/no_color.rs new file mode 100644 index 00000000..892f2859 --- /dev/null +++ b/bin/tests/no_color.rs @@ -0,0 +1,36 @@ +mod _utils; + +use crate::_utils::OutputProcessing; +use std::collections::HashMap; + +const EXPR: &'static str = "let in null"; + +#[test] +fn test_output_with_color_ansi_escape() { + let stdout = _utils::test_cli( + EXPR, + &["check"], + HashMap::new(), + OutputProcessing::Unchanged, + ) + .unwrap(); + let snapshot = format!("{EXPR}\n---\n{stdout}"); + insta::with_settings!({omit_expression => true}, { + insta::assert_snapshot!("output_with_color_ansi_escape", snapshot); + }); +} + +#[test] +fn test_output_without_color_ansi_escape() { + let stdout = _utils::test_cli( + EXPR, + &["check"], + HashMap::from([("NO_COLOR", "1")]), + OutputProcessing::Unchanged, + ) + .unwrap(); + let snapshot = format!("{EXPR}\n---\n{stdout}"); + insta::with_settings!({omit_expression => true}, { + insta::assert_snapshot!("output_without_color_ansi_escape", snapshot); + }); +} diff --git a/bin/tests/snapshots/no_color__output_with_color_ansi_escape.snap b/bin/tests/snapshots/no_color__output_with_color_ansi_escape.snap new file mode 100644 index 00000000..8a113589 --- /dev/null +++ b/bin/tests/snapshots/no_color__output_with_color_ansi_escape.snap @@ -0,0 +1,12 @@ +--- +source: bin/tests/no_color.rs +--- +let in null +--- +[W02] Warning: Useless let-in expression + โ•ญโ”€[:1:1] + โ”‚ + 1 โ”‚ let in null +  ยท โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€ +  ยท โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€ This let-in expression has no entries +โ”€โ”€โ”€โ•ฏ diff --git a/bin/tests/snapshots/no_color__output_without_color_ansi_escape.snap b/bin/tests/snapshots/no_color__output_without_color_ansi_escape.snap new file mode 100644 index 00000000..93cc4890 --- /dev/null +++ b/bin/tests/snapshots/no_color__output_without_color_ansi_escape.snap @@ -0,0 +1,12 @@ +--- +source: bin/tests/no_color.rs +--- +let in null +--- +[W02] Warning: Useless let-in expression + โ•ญโ”€[:1:1] + โ”‚ + 1 โ”‚ let in null + ยท โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€ This let-in expression has no entries +โ”€โ”€โ”€โ•ฏ diff --git a/macros/src/test.rs b/macros/src/test.rs index 1afd0a14..e7b8dee2 100644 --- a/macros/src/test.rs +++ b/macros/src/test.rs @@ -95,8 +95,11 @@ fn make_test(rule: &Ident, kind: TestKind, nix_expression: &Expr) -> proc_macro2 quote! { #[test] fn #test_ident() { + use std::collections::HashMap; + use crate::_utils::OutputProcessing; + let expression = #nix_expression; - let stdout = _utils::test_cli(expression, #args).unwrap(); + let stdout = _utils::test_cli(expression, #args, HashMap::new(), OutputProcessing::StripAnsi).unwrap(); let snapshot = format!("{expression}\n---\n{stdout}"); insta::with_settings!({omit_expression => true}, { insta::assert_snapshot!(#snap_name, snapshot); diff --git a/readme.md b/readme.md index fc0c2623..1318634b 100644 --- a/readme.md +++ b/readme.md @@ -152,3 +152,8 @@ useless_has_attr All lints are enabled by default. Generate a minimal config with `statix dump > statix.toml`. + +### Color + +Reports contain ANSI color escape codes unless the +[`NO_COLOR`](https://no-color.org/) environment variable is present.