Skip to content

NO_COLOR drops non-color attributes and treats empty value as active #291

Description

@levitte

NO_COLOR drops non-color attributes and treats empty value as active

Summary

console honors NO_COLOR but in two ways that diverge from
no-color.org
(or its source):

  1. It suppresses all styling — bold, italic, underline, dim, reverse,
    blink, hidden, strikethrough — not only color, contrary to the FAQ:

    Q: Should the presence of NO_COLOR disable other styling such as
    bold, underline, and italic?

    A: No. This standard only signals the user's intention regarding
    adding ANSI color to text output.

  2. It treats NO_COLOR="" (present but empty) as active. The spec requires
    present and not an empty string; an empty value disables nothing.

Reproduction

Both bugs are in StyledObject::fmt (src/utils.rs, the impl_fmt! macro):
the entire emit block — fg, bg, and self.style.attrs — sits behind a
single colors_enabled() / colors_enabled_stderr() gate, which flips to
false when env::var("NO_COLOR").is_ok() (src/unix_term.rs,
src/windows_term/mod.rs).

Verified on console 0.16.4 — style("X").fg(Color::Red).attr(Attribute::Bold):

set_colors_enabled(true);  let on = format!("{st}{s}{st:#}");  // "\x1b[31m\x1b[1mX..."
set_colors_enabled(false); let off = format!("{st}{s}{st:#}"); // "X" — bold gone too

off contains neither \x1b[31m (red) nor \x1b[1m (bold). Per the FAQ,
only the color should be gone; bold should survive.

Expected (spec-aligned)

  • Use the right fd when reading unix terminal size #1 scope: When NO_COLOR is active, suppress color only; keep emitting
    self.style.attrs (bold/dim/italic/underline/blink/reverse/hidden/strikethrough).
    Style already separates fg/bg from attrs, so the fix is to move the
    attrs emit outside the colors_enabled() gate.
  • Get terminal size from /dev/tty directly #2 trigger: NO_COLOR="" should disable nothing. Replace
    env::var("NO_COLOR").is_ok() with a non-empty check
    (e.g. env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty())).

Notes

  • crossterm is a working example of color-only NO_COLOR handling — it
    gates fg/bg/underline-color but emits SetAttributes unconditionally.
  • This cascades to dependents using console for styling — dialoguer and
    indicatif — which would inherit the fix.
  • I'm framing this as a bug fix (patch bump), but defer to the project's
    own version policy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions