Skip to content

Commit

Permalink
improve detection of terminals over SSH
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
sunshowers committed Aug 30, 2024
1 parent d5c906d commit 6b56291
Showing 1 changed file with 22 additions and 12 deletions.
34 changes: 22 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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 {
Expand Down

0 comments on commit 6b56291

Please sign in to comment.