From c51bb711e629777d78a5ad3ab96ce581f6b583e3 Mon Sep 17 00:00:00 2001 From: Prashant Rahul Date: Wed, 11 Mar 2026 12:55:42 +0530 Subject: [PATCH 1/4] feat: Dont use colors when NO_COLOR env is present This enables the ability to disable colors in output by defining `NO_COLOR` environment variable Signed-off-by: Prashant Rahul --- bin/src/traits.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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() From 57ad76c682287976555665da28215bd8369a0ab0 Mon Sep 17 00:00:00 2001 From: Prashant Rahul Date: Wed, 11 Mar 2026 13:01:55 +0530 Subject: [PATCH 2/4] docs: Add color toggle ability via NO_COLOR env to readme Signed-off-by: Prashant Rahul --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) 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. From a48f0928cc8e5989b051005966fd34957b660537 Mon Sep 17 00:00:00 2001 From: Prashant Rahul Date: Thu, 12 Mar 2026 12:14:48 +0530 Subject: [PATCH 3/4] feat(test): Ability to disable stripping ansi escape, and pass env vars Signed-off-by: Prashant Rahul --- bin/tests/_utils.rs | 23 ++++++++++++++++++++--- macros/src/test.rs | 5 ++++- 2 files changed, 24 insertions(+), 4 deletions(-) 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/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); From a8b3e027a37b1723548a57ff639b994183e13c02 Mon Sep 17 00:00:00 2001 From: Prashant Rahul Date: Thu, 19 Mar 2026 10:43:02 +0530 Subject: [PATCH 4/4] feat(test): introduce no_color tests with snapshots Signed-off-by: Prashant Rahul --- bin/tests/no_color.rs | 36 +++++++++++++++++++ ..._color__output_with_color_ansi_escape.snap | 12 +++++++ ...lor__output_without_color_ansi_escape.snap | 12 +++++++ 3 files changed, 60 insertions(+) create mode 100644 bin/tests/no_color.rs create mode 100644 bin/tests/snapshots/no_color__output_with_color_ansi_escape.snap create mode 100644 bin/tests/snapshots/no_color__output_without_color_ansi_escape.snap 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 +โ”€โ”€โ”€โ•ฏ