diff --git a/src/unix_term.rs b/src/unix_term.rs
index 815d976a..154af2c7 100644
--- a/src/unix_term.rs
+++ b/src/unix_term.rs
@@ -27,7 +27,7 @@ pub(crate) fn is_a_color_terminal(out: &Term) -> bool {
return false;
}
- if env::var("NO_COLOR").is_ok() {
+ if env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty()) {
return false;
}
diff --git a/src/utils.rs b/src/utils.rs
index 3a48628e..e4537e4f 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -823,6 +823,16 @@ macro_rules! impl_fmt {
write!(f, "{}", self.style.attrs)?;
reset = true;
}
+ } else {
+ // NO_COLOR and similar controls disable color, but per
+ // text attributes (bold, italic,
+ // underline, etc.) are not "color" and should remain
+ // visible. Emit them outside the colors_enabled gate so
+ // they survive when colors are suppressed.
+ if !self.style.attrs.is_empty() {
+ write!(f, "{}", self.style.attrs)?;
+ reset = true;
+ }
}
fmt::$name::fmt(&self.val, f)?;
if reset {
@@ -1227,3 +1237,46 @@ fn test_style_from_non_ascii_bg() {
// silently ignores non-ascii
assert_eq!(parsed_style, Style::default());
}
+
+#[test]
+fn test_attrs_survive_colors_disabled() {
+ // Regression test for :
+ // per , `NO_COLOR` suppresses *color*, not text
+ // attributes. When color output is otherwise disabled, attributes such as
+ // bold/italic/underline should still be emitted (with a trailing reset).
+ let prev = colors_enabled();
+ set_colors_enabled(false);
+
+ let bold = style("foo").bold().to_string();
+ assert!(
+ bold.contains("\x1b[1m"),
+ "bold escape sequence missing when colors are disabled: {bold:?}"
+ );
+ assert!(
+ bold.ends_with("\x1b[0m"),
+ "reset escape sequence missing after bold: {bold:?}"
+ );
+
+ let italic = style("bar").italic().to_string();
+ assert!(
+ italic.contains("\x1b[3m"),
+ "italic escape sequence missing when colors are disabled: {italic:?}"
+ );
+ assert!(
+ italic.ends_with("\x1b[0m"),
+ "reset escape sequence missing after italic: {italic:?}"
+ );
+
+ // Foreground color is *still* suppressed when colors are disabled.
+ let colored = style("baz").red().to_string();
+ assert!(
+ !colored.contains("\x1b[31m"),
+ "foreground color escape sequence should be suppressed when colors are disabled: {colored:?}"
+ );
+ assert!(
+ !colored.contains("\x1b[0m"),
+ "reset escape sequence should not be emitted when nothing is styled: {colored:?}"
+ );
+
+ set_colors_enabled(prev);
+}
diff --git a/src/windows_term/mod.rs b/src/windows_term/mod.rs
index 8d8a7803..a967c094 100644
--- a/src/windows_term/mod.rs
+++ b/src/windows_term/mod.rs
@@ -63,7 +63,7 @@ pub(crate) fn is_a_color_terminal(out: &Term) -> bool {
if !is_a_terminal(out) {
return false;
}
- if env::var("NO_COLOR").is_ok() {
+ if env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty()) {
return false;
}
if msys_tty_on(out) {