From 6b5629144a3a324526f096537c8ca2e3ce821c8e Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 29 Aug 2024 19:50:41 -0700 Subject: [PATCH] improve detection of terminals over SSH A recurring issue with terminals over SSH is that while TERM is passed in, COLORTERM is not by default. This means that programs running on the server only have access to TERM. If TERM is something like `xterm-256color` or `konsole-direct` this works fine, but if it is something like `wezterm` or `alacritty` it doesn't, so auto detection falls back to assuming colors aren't supported at all. This creates a pretty bad experience. I had a look at what some other crates do and it looks like anstyle (which is used by Cargo itself) just checks that the terminal isn't `dumb` (or `cygwin` on Windows). However I believe the latest version of anstyle also has a bug, that it thinks that if TERM isn't set on Windows then ANSI colors aren't supported. (That is fine for anstream, I believe, since that knows how to fall back to Windows console calls.) --- src/lib.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 935a0ea..b06495f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,8 +107,7 @@ fn supports_color(stream: Stream) -> usize { { 2 } else if env::var("COLORTERM").is_ok() - || env::var("TERM").map(|term| check_ansi_color(&term)) == Ok(true) - || env::consts::OS == "windows" + || check_ansi_color(env::var("TERM").ok().as_deref()) || env::var("CLICOLOR").map_or(false, |v| v != "0") || is_ci::uncached() { @@ -118,16 +117,27 @@ fn supports_color(stream: Stream) -> usize { } } -fn check_ansi_color(term: &str) -> bool { - term.starts_with("screen") - || term.starts_with("xterm") - || term.starts_with("vt100") - || term.starts_with("vt220") - || term.starts_with("rxvt") - || term.contains("color") - || term.contains("ansi") - || term.contains("cygwin") - || term.contains("linux") +#[cfg(windows)] +fn check_ansi_color(term: Option<&str>) -> bool { + if let Some(term) = term { + // cygwin doesn't seem to support ANSI escape sequences and instead has its own variety. + term != "dumb" && term != "cygwin" + } else { + // TERM is generally not set on Windows. It's reasonable to assume that all Windows + // terminals support ANSI escape sequences (since Windows 10 version 1511). + true + } +} + +#[cfg(not(windows))] +fn check_ansi_color(term: Option<&str>) -> bool { + if let Some(term) = term { + // dumb terminals don't support ANSI escape sequences. + term != "dumb" + } else { + // TERM is not set, which is really weird on Unix systems. + false + } } fn check_colorterm_16m(colorterm: &str) -> bool {