| 106 |
106 |
|
impl Fidelity {
|
| 107 |
107 |
|
/// Read the terminal's own claim, from `COLORTERM` then `TERM`.
|
| 108 |
108 |
|
///
|
| 109 |
|
- |
/// Deliberately credulous. A terminal that understates itself costs a
|
| 110 |
|
- |
/// slightly heavier frame; one that overstates itself was going to render
|
| 111 |
|
- |
/// wrongly regardless of what this crate assumed.
|
|
109 |
+ |
/// Deliberately credulous, and the fall-through is where that is decided.
|
|
110 |
+ |
/// An unrecognised `TERM` is assumed capable, because the two wrong answers
|
|
111 |
+ |
/// do not cost the same: guessing [`TrueColor`](Self::TrueColor) on a
|
|
112 |
+ |
/// limited terminal costs some fidelity, and guessing
|
|
113 |
+ |
/// [`Ansi16`](Self::Ansi16) on a capable one throws away colour the user
|
|
114 |
+ |
/// paid for — and, for a caller that quantises its palette off this answer,
|
|
115 |
+ |
/// throws away the whole theme. `COLORTERM` is routinely stripped by ssh
|
|
116 |
+ |
/// and by multiplexers, so an unrecognised name is the common case rather
|
|
117 |
+ |
/// than the exotic one: `foot`, `xterm` and `screen` all land here.
|
|
118 |
+ |
///
|
|
119 |
+ |
/// So sixteen colours is reached by naming the terminals that really have
|
|
120 |
+ |
/// them. The list is short and it does not grow: these are the fixed
|
|
121 |
+ |
/// consoles, and `TERM=linux` is the case this exists for — the Linux
|
|
122 |
+ |
/// virtual console, which is what an installer and a machine with no
|
|
123 |
+ |
/// desktop draw on.
|
| 112 |
124 |
|
#[must_use]
|
| 113 |
125 |
|
pub fn detect() -> Self {
|
| 114 |
|
- |
let colorterm = std::env::var("COLORTERM").unwrap_or_default();
|
|
126 |
+ |
Self::from_env(
|
|
127 |
+ |
&std::env::var("COLORTERM").unwrap_or_default(),
|
|
128 |
+ |
&std::env::var("TERM").unwrap_or_default(),
|
|
129 |
+ |
)
|
|
130 |
+ |
}
|
|
131 |
+ |
|
|
132 |
+ |
/// [`detect`](Self::detect) with the environment passed in, so the decision
|
|
133 |
+ |
/// can be tested without mutating a process-wide variable from a parallel
|
|
134 |
+ |
/// test.
|
|
135 |
+ |
#[must_use]
|
|
136 |
+ |
pub fn from_env(colorterm: &str, term: &str) -> Self {
|
| 115 |
137 |
|
if colorterm.contains("truecolor") || colorterm.contains("24bit") {
|
| 116 |
138 |
|
return Self::TrueColor;
|
| 117 |
139 |
|
}
|
| 118 |
|
- |
let term = std::env::var("TERM").unwrap_or_default();
|
| 119 |
|
- |
if term.contains("256color") || term.contains("direct") {
|
| 120 |
|
- |
return Self::Ansi256;
|
|
140 |
+ |
match term {
|
|
141 |
+ |
"linux" | "vt100" | "vt220" | "ansi" | "dumb" => Self::Ansi16,
|
|
142 |
+ |
_ if term.contains("256color") || term.contains("direct") => Self::Ansi256,
|
|
143 |
+ |
_ => Self::TrueColor,
|
| 121 |
144 |
|
}
|
| 122 |
|
- |
if term.is_empty() {
|
| 123 |
|
- |
return Self::TrueColor;
|
| 124 |
|
- |
}
|
| 125 |
|
- |
Self::Ansi16
|
| 126 |
145 |
|
}
|
| 127 |
146 |
|
|
| 128 |
147 |
|
/// Whether colour alone can tell a raised surface from a well here.
|
| 642 |
661 |
|
assert!(!Fidelity::Ansi16.separates_depth());
|
| 643 |
662 |
|
}
|
| 644 |
663 |
|
|
|
664 |
+ |
// Sixteen colours is reached by naming a console, never by failing to
|
|
665 |
+ |
// recognise a terminal. `COLORTERM` is stripped by ssh and by every
|
|
666 |
+ |
// multiplexer, so an unrecognised name carries no evidence at all, and a
|
|
667 |
+ |
// caller quantising its palette off this answer would flatten a whole theme
|
|
668 |
+ |
// on the strength of it.
|
|
669 |
+ |
#[test]
|
|
670 |
+ |
fn an_unrecognised_terminal_is_assumed_capable() {
|
|
671 |
+ |
let f = Fidelity::from_env;
|
|
672 |
+ |
assert_eq!(f("", "foot"), Fidelity::TrueColor);
|
|
673 |
+ |
assert_eq!(f("", "xterm"), Fidelity::TrueColor);
|
|
674 |
+ |
assert_eq!(f("", "screen"), Fidelity::TrueColor);
|
|
675 |
+ |
assert_eq!(f("", ""), Fidelity::TrueColor);
|
|
676 |
+ |
}
|
|
677 |
+ |
|
|
678 |
+ |
#[test]
|
|
679 |
+ |
fn a_console_that_really_has_sixteen_colours_is_named() {
|
|
680 |
+ |
let f = Fidelity::from_env;
|
|
681 |
+ |
assert_eq!(f("", "linux"), Fidelity::Ansi16);
|
|
682 |
+ |
assert_eq!(f("", "vt100"), Fidelity::Ansi16);
|
|
683 |
+ |
assert_eq!(f("", "dumb"), Fidelity::Ansi16);
|
|
684 |
+ |
}
|
|
685 |
+ |
|
|
686 |
+ |
#[test]
|
|
687 |
+ |
fn a_terminal_naming_its_depth_is_taken_at_its_word() {
|
|
688 |
+ |
let f = Fidelity::from_env;
|
|
689 |
+ |
assert_eq!(f("", "xterm-256color"), Fidelity::Ansi256);
|
|
690 |
+ |
assert_eq!(f("", "screen-256color"), Fidelity::Ansi256);
|
|
691 |
+ |
assert_eq!(f("", "xterm-direct"), Fidelity::Ansi256);
|
|
692 |
+ |
// And a claim of 24-bit beats the name, which is only ever a floor.
|
|
693 |
+ |
assert_eq!(f("truecolor", "xterm-256color"), Fidelity::TrueColor);
|
|
694 |
+ |
assert_eq!(f("24bit", "linux"), Fidelity::TrueColor);
|
|
695 |
+ |
}
|
|
696 |
+ |
|
| 645 |
697 |
|
#[test]
|
| 646 |
698 |
|
fn a_region_too_small_for_an_edge_is_left_alone() {
|
| 647 |
699 |
|
let p = palette(None);
|