Skip to content

[FEATURE] RGB-to-ANSI downgrade #48

Description

@AlexanderNZ

Feature Description

Automatic RGB-to-ANSI color downgrade when the terminal doesn't support truecolor.

Problem or Use Case

Ratatui + crossterm doesn't do any terminal color capability detection. When a theme uses Color::Rgb values (which all the built-in themes except Default already do), xleak emits raw RGB escape codes on the assumption the user's terminal is capable of correctly rendering. On terminals that don't support truecolor — macOS Terminal.app is the big one — the result is garbled or blinking text rather than a graceful fallback.

In #47 I added a basic COLORTERM env var check that warns on stderr if truecolor isn't advertised. It's cool to print a warning, it's cooler to gracefully handle the error.

Proposed Solution

When the terminal doesn't advertise truecolor support, map each Color::Rgb(r, g, b) in the active theme to the nearest ANSI-256 color. The math is a Euclidean distance search against the 256-color palette, there's a supports-color crate that handles the detection side across platforms.

The downside is that approximated colors can look noticeably different from the originals. A carefully tuned Dracula theme mapped to 256 colors might look "close enough" or might look muddy. Hard to know without trying it.

Alternatives Considered

  • Warning only (current state): xleak checks COLORTERM at startup and warns if truecolor isn't advertised. This is honest and actionable, but doesn't fix the display.
  • Per-theme fallback colors: Let users specify e.g. header_fg_fallback = "blue" alongside header_fg = "#7aa2f7". Full user control, but doubles the config surface area for a niche use case.
  • Do nothing: The main terminals people use with TUI tools (iTerm2, WezTerm, Alacritty, Kitty, Windows Terminal) all support truecolor. macOS Terminal.app is really the only common holdout. The warning might be good enough.

Additional Context

Implementation Notes

  1. Use supports-color to detect terminal capabilities (truecolor / 256 / 16 / none)
  2. If truecolor isn't available, walk the active ColorScheme and replace each Color::Rgb with the nearest Color::Indexed from the 256-color palette
  3. Do this once at startup, not per-frame
  4. Keep the existing stderr warning as a fallback for edge cases where detection is wrong

That's maybe 50-80 lines plus the new dependency. The existing named-color themes (foreground = "cyan") would be unaffected since they already use ANSI colors.

A couple of questions before I start on this:

  • Are you okay with adding supports-color as a dependency?
  • Should this be opt-in (--force-truecolor to skip downgrade) or opt-out (--no-color-downgrade)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions