| Crates.io | termprofile |
| lib.rs | termprofile |
| version | 0.2.0 |
| created_at | 2025-10-03 06:44:49.312835+00 |
| updated_at | 2025-12-26 15:34:19.120287+00 |
| description | A library to detect and handle terminal color/styling support |
| homepage | https://github.com/aschey/termprofile |
| repository | https://github.com/aschey/termprofile |
| max_upload_size | |
| id | 1866257 |
| size | 178,881 |
A library to detect and handle terminal color/styling support.
Terminal environments can have several levels of color support:
All features are disabled by default.
terminfo - Enables checking against the terminfo database for color support.
See terminfo.
query-detect - Enables querying for true color support via
DECRQSS. See
querying the terminal.
windows-version - Enables additional checks for color support based on the
current version of Windows. See windows.
convert - Enables converting incompatible colors based on the color support
level. See conversions.
color-cache - Adds an optional LRU cache for color conversion operations.
See caching.
ratatui - Enables direct conversion to
Ratatui style and color objects. See
Ratatui conversions.
ratatui-underline-color - Enables Ratatui's underline-color feature and
includes underline colors in Ratatui style conversions.
use std::io::stdout;
use termprofile::{TermProfile, DetectorSettings};
let profile = TermProfile::detect(&stdout(), DetectorSettings::default());
println!("Detected profile: {profile:?}");
Variables can be overridden before detecting the color profile.
use std::io::stdout;
use termprofile::{TermProfile, TermVars, DetectorSettings};
let mut vars = TermVars::from_env(&stdout(), DetectorSettings::default());
vars.overrides.force_color = "1".into();
let profile = TermProfile::detect_with_vars(vars);
println!("Profile with override: {profile:?}");
Environment variables can be sourced from an in-memory map instead of reading directly from the environment.
use std::collections::HashMap;
use std::io::stdout;
use termprofile::{TermProfile, TermVars, DetectorSettings};
let source = HashMap::from_iter([("TERM", "xterm-256color"), ("COLORTERM", "1")]);
let vars = TermVars::from_source(&source, &stdout(), DetectorSettings::default());
let profile = TermProfile::detect_with_vars(vars);
println!("Profile: {profile:?}");
Colors and styles can be automatically adapted based on the current profile.
use termprofile::TermProfile;
use std::io::stdout;
use anstyle::{Color, RgbColor, Ansi256Color};
let profile = TermProfile::Ansi256;
let rgb_color: Color = RgbColor(209, 234, 213).into();
let adapted_color = profile.adapt_color(rgb_color);
assert_eq!(adapted_color, Some(Ansi256Color(253).into()));
Automatic color conversion doesn't always produce optimal results. Use
ProfileColor to have more control over the conversion.
use termprofile::{TermProfile, ProfileColor};
use anstyle::{Color, RgbColor, Ansi256Color, AnsiColor};
let profile = TermProfile::Ansi256;
let color = ProfileColor::new(Color::Rgb(RgbColor(209, 234, 213)), profile)
.ansi_256(240)
.ansi_16(AnsiColor::White);
assert_eq!(color.adapt(), Some(Ansi256Color(240).into()));
Text modifiers will be removed if the profile is set to NoTTY.
use termprofile::TermProfile;
use std::io::stdout;
use anstyle::{Color, RgbColor, AnsiColor, Style};
let profile = TermProfile::Ansi16;
let fg = RgbColor(106, 132, 92).into();
let bg = RgbColor(4, 35, 212).into();
let style = Style::new().fg_color(Some(fg)).bg_color(Some(bg));
let adapted_style = profile.adapt_style(style);
assert_eq!(
adapted_style,
Style::new()
.fg_color(Some(AnsiColor::Cyan.into()))
.bg_color(Some(AnsiColor::BrightBlue.into()))
);
anstyle is used for color conversions due to its compatibility with other
terminal color crates, but it does not have support for a Color::Reset
variant, which can be important for TUI apps. If the ratatui feature is
enabled, all of the above conversions work with Ratatui types, allowing for full
compatibility without requiring anstyle as an intermediate layer.
use termprofile::TermProfile;
use std::io::stdout;
use ratatui::style::Color;
let profile = TermProfile::Ansi256;
let rgb_color = Color::Rgb(209, 234, 213);
let adapted_color = profile.adapt_color(rgb_color);
assert_eq!(adapted_color, Some(Color::Indexed(253)));
Color conversion can be somewhat expensive if you're rendering at a high frame
rate. The color-cache feature enables an opt-in LRU cache that can be used to
cache a certain amount of calculations.
use termprofile::{set_color_cache_enabled, set_color_cache_size};
set_color_cache_enabled(true);
set_color_cache_size(256.try_into().expect("non-zero size"));
See examples.
Sadly, there is no standard way to accurately detect color support in terminals. Instead, we must rely on a number of environment variables and other methods that have organically emerged as a pseudo-standard over time.
The most reliable way to detect true color support is to query for it. This is preferable over environment variables because it works over SSH and is not susceptible to ambiguity caused by terminal multiplexers. Unfortunately, this method isn't supported in many terminals yet.
COLORTERM -
the terminal supports true color if this is set to 24bit or truecolorTERM - the most common variable supplied by a terminal, this denotes the
name of the terminal program. We maintain a list of terminals that are known
to have true color support as well as some fuzzy matching logic for common
suffixes (e.g. -256color for ANSI 256 support).TERM_PROGRAM - less common than TERM, but can report more granular
information for a few terminals.TERM_PROGRAM_VERSION - used sparingly, but some terminals only gain true
color support after a certain version.Several variables can be set manually by users in order to override the color detection behavior.
CLICOLOR_FORCE /
FORCE_COLOR - two competing standards that seem
to do the same thing. When either of these is set to a truthy value, the color
support level will be at least ANSI 16, with other variables used to decide if
further support is available.
In addition to true/false values,
chalk supports
using numerical values to set a specific color level. Unfortunately, this
creates ambiguity with
FORCE_COLOR=1 which could be interpreted to mean either "color level 1" or
"true". Instead, we support semantic values to force a specific color value.
no_color - disables all colorsansi or ansi16 - forces ANSI 16 coloransi256 - forces ANSI 256 colorstruecolor, true_color, or 24bit - forces true colorexample: CLICOLOR_FORCE="ansi256"
This can be useful for testing how your program works with a specific color support level.
CLICOLOR - Will enable colors if TERM is
unset and the output is a terminal.
NO_COLOR - When set to a truthy value, this
forces colors to be disabled.
TTY_FORCE -
this can be set to a truthy value to treat the terminal like a TTY even if the
call to
is_terminal
returns false. May be useful when running a subprocess or in some nonstandard
platforms such as webassembly.
If the terminfo feature is enabled, the
terminfo database is queried for
available properties:
colors - returns the number of available colors. Due to limitations with
terminfo, true color terminals generally only report 256 colors with this
property. TERM values ending in -direct (kitty-direct or
alacritty-direct, for example) are the exception and may report color values
> 256 here.RGB and Tc - nonstandard extensions to terminfo, this is a boolean that
may be set in some newer terminals to indicate true color support.If the windows-version feature is enabled, additional checks will be performed
to detect support for ANSI colors based on the active version of Windows. You
may want to enable this if support for older versions of Windows 10 (prior to
build
#14931,
released in 2016) is important to you.
Since CI platforms will render build output in an environment that's not a true TTY, color support detection likely won't work automatically. We try to account for some variables supplied by common CI providers, but we can't account for all of them.
If your CI provider isn't supported, you can use FORCE_COLOR or
CLICOLOR_FORCE to force color output.
Terminal multiplexers like GNU Screen and tmux affect the color support of the terminal. We attempt to detect these cases properly, but it's difficult to do so perfectly since they obscure some information from the host terminal.
Newer versions of Screen support true color, but there doesn't seem to be a way to see if it's enabled, so we cannot accurately detect this case.
Environment variables may not be passed into your SSH session depending on your
configuration, which can cause color support to be detected incorrectly. For
best results, enable the query-detect feature and use a terminal that supports
querying.
The MSRV is currently 1.88.0. Since Cargo's V3 resolver supports MSRV-aware dependencies, we do not treat an MSRV bump as a breaking change.
This library takes inspiration from many other implementations: