Improve color detection across platforms (#885)
Fixes #882 by improving `style::available_color_count()`: - Checks ANSI support on Windows. - Uses the COLORTERM environment variable and falls back to the TERM environment variable. - Supports "xterm-24bit" and "truecolor" values which return `u16::MAX`.
This commit is contained in:
parent
fe440284bf
commit
080f06494a
@ -96,6 +96,7 @@ futures-timer = "3.0"
|
||||
async-std = "1.12"
|
||||
serde_json = "1.0"
|
||||
serial_test = "2.0.0"
|
||||
temp-env = "0.3.6"
|
||||
|
||||
#
|
||||
# Examples
|
||||
|
106
src/style.rs
106
src/style.rs
@ -161,9 +161,23 @@ pub fn style<D: Display>(val: D) -> StyledContent<D> {
|
||||
///
|
||||
/// This does not always provide a good result.
|
||||
pub fn available_color_count() -> u16 {
|
||||
env::var("TERM")
|
||||
.map(|x| if x.contains("256color") { 256 } else { 8 })
|
||||
.unwrap_or(8)
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// Check if we're running in a pseudo TTY, which supports true color.
|
||||
// Fall back to env vars otherwise for other terminals on Windows.
|
||||
if crate::ansi_support::supports_ansi() {
|
||||
return u16::MAX;
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT: u16 = 8;
|
||||
env::var("COLORTERM")
|
||||
.or_else(|_| env::var("TERM"))
|
||||
.map_or(DEFAULT, |x| match x {
|
||||
_ if x.contains("24bit") || x.contains("truecolor") => u16::MAX,
|
||||
_ if x.contains("256") => 256,
|
||||
_ => DEFAULT,
|
||||
})
|
||||
}
|
||||
|
||||
/// Forces colored output on or off globally, overriding NO_COLOR.
|
||||
@ -519,3 +533,89 @@ impl_display!(for ResetColor);
|
||||
fn parse_next_u8<'a>(iter: &mut impl Iterator<Item = &'a str>) -> Option<u8> {
|
||||
iter.next().and_then(|s| s.parse().ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// On Windows many env var tests will fail so we need to conditionally check for ANSI support.
|
||||
// This allows other terminals on Windows to still assert env var support.
|
||||
macro_rules! skip_windows_ansi_supported {
|
||||
() => {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if crate::ansi_support::supports_ansi() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg_attr(windows, test)]
|
||||
#[cfg(windows)]
|
||||
fn windows_always_truecolor() {
|
||||
// This should always be true on supported Windows 10+,
|
||||
// but downlevel Windows clients and other terminals may fail `cargo test` otherwise.
|
||||
if crate::ansi_support::supports_ansi() {
|
||||
assert_eq!(u16::MAX, available_color_count());
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colorterm_overrides_term() {
|
||||
skip_windows_ansi_supported!();
|
||||
temp_env::with_vars(
|
||||
[
|
||||
("COLORTERM", Some("truecolor")),
|
||||
("TERM", Some("xterm-256color")),
|
||||
],
|
||||
|| {
|
||||
assert_eq!(u16::MAX, available_color_count());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn term_24bits() {
|
||||
skip_windows_ansi_supported!();
|
||||
temp_env::with_vars(
|
||||
[("COLORTERM", None), ("TERM", Some("xterm-24bits"))],
|
||||
|| {
|
||||
assert_eq!(u16::MAX, available_color_count());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn term_256color() {
|
||||
skip_windows_ansi_supported!();
|
||||
temp_env::with_vars(
|
||||
[("COLORTERM", None), ("TERM", Some("xterm-256color"))],
|
||||
|| {
|
||||
assert_eq!(256u16, available_color_count());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_color_count() {
|
||||
skip_windows_ansi_supported!();
|
||||
temp_env::with_vars([("COLORTERM", None::<&str>), ("TERM", None)], || {
|
||||
assert_eq!(8, available_color_count());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_term_colorterm_values() {
|
||||
skip_windows_ansi_supported!();
|
||||
temp_env::with_vars(
|
||||
[
|
||||
("COLORTERM", Some("gibberish")),
|
||||
("TERM", Some("gibberish")),
|
||||
],
|
||||
|| {
|
||||
assert_eq!(8u16, available_color_count());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user