]> git.proxmox.com Git - rustc.git/blob - vendor/termion/src/color.rs
New upstream version 1.32.0~beta.2+dfsg1
[rustc.git] / vendor / termion / src / color.rs
1 //! Color managemement.
2 //!
3 //! # Example
4 //!
5 //! ```rust
6 //! use termion::color;
7 //!
8 //! fn main() {
9 //! println!("{}Red", color::Fg(color::Red));
10 //! println!("{}Blue", color::Fg(color::Blue));
11 //! println!("{}Back again", color::Fg(color::Reset));
12 //! }
13 //! ```
14
15 use std::fmt;
16 use raw::CONTROL_SEQUENCE_TIMEOUT;
17 use std::io::{self, Write, Read};
18 use std::time::{SystemTime, Duration};
19 use async::async_stdin;
20 use std::env;
21
22 /// A terminal color.
23 pub trait Color {
24 /// Write the foreground version of this color.
25 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
26 /// Write the background version of this color.
27 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
28 }
29
30 macro_rules! derive_color {
31 ($doc:expr, $name:ident, $value:expr) => {
32 #[doc = $doc]
33 #[derive(Copy, Clone, Debug)]
34 pub struct $name;
35
36 impl Color for $name {
37 #[inline]
38 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 write!(f, csi!("38;5;", $value, "m"))
40 }
41
42 #[inline]
43 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 write!(f, csi!("48;5;", $value, "m"))
45 }
46 }
47 };
48 }
49
50 derive_color!("Black.", Black, "0");
51 derive_color!("Red.", Red, "1");
52 derive_color!("Green.", Green, "2");
53 derive_color!("Yellow.", Yellow, "3");
54 derive_color!("Blue.", Blue, "4");
55 derive_color!("Magenta.", Magenta, "5");
56 derive_color!("Cyan.", Cyan, "6");
57 derive_color!("White.", White, "7");
58 derive_color!("High-intensity light black.", LightBlack, "8");
59 derive_color!("High-intensity light red.", LightRed, "9");
60 derive_color!("High-intensity light green.", LightGreen, "10");
61 derive_color!("High-intensity light yellow.", LightYellow, "11");
62 derive_color!("High-intensity light blue.", LightBlue, "12");
63 derive_color!("High-intensity light magenta.", LightMagenta, "13");
64 derive_color!("High-intensity light cyan.", LightCyan, "14");
65 derive_color!("High-intensity light white.", LightWhite, "15");
66
67 impl<'a> Color for &'a Color {
68 #[inline]
69 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 (*self).write_fg(f)
71 }
72
73 #[inline]
74 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 (*self).write_bg(f)
76 }
77 }
78
79 /// An arbitrary ANSI color value.
80 #[derive(Clone, Copy, Debug)]
81 pub struct AnsiValue(pub u8);
82
83 impl AnsiValue {
84 /// 216-color (r, g, b ≤ 5) RGB.
85 pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
86 debug_assert!(r <= 5,
87 "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.",
88 r);
89 debug_assert!(g <= 5,
90 "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.",
91 g);
92 debug_assert!(b <= 5,
93 "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.",
94 b);
95
96 AnsiValue(16 + 36 * r + 6 * g + b)
97 }
98
99 /// Grayscale color.
100 ///
101 /// There are 24 shades of gray.
102 pub fn grayscale(shade: u8) -> AnsiValue {
103 // Unfortunately, there are a little less than fifty shades.
104 debug_assert!(shade < 24,
105 "Grayscale out of bound (shade = {}). There are only 24 shades of \
106 gray.",
107 shade);
108
109 AnsiValue(0xE8 + shade)
110 }
111 }
112
113 impl Color for AnsiValue {
114 #[inline]
115 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 write!(f, csi!("38;5;{}m"), self.0)
117 }
118
119 #[inline]
120 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 write!(f, csi!("48;5;{}m"), self.0)
122 }
123 }
124
125 /// A truecolor RGB.
126 #[derive(Debug, Clone, Copy, PartialEq)]
127 pub struct Rgb(pub u8, pub u8, pub u8);
128
129 impl Color for Rgb {
130 #[inline]
131 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2)
133 }
134
135 #[inline]
136 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2)
138 }
139 }
140
141 /// Reset colors to defaults.
142 #[derive(Debug, Clone, Copy)]
143 pub struct Reset;
144
145 impl Color for Reset {
146 #[inline]
147 fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 write!(f, csi!("39m"))
149 }
150
151 #[inline]
152 fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 write!(f, csi!("49m"))
154 }
155 }
156
157 /// A foreground color.
158 #[derive(Debug, Clone, Copy)]
159 pub struct Fg<C: Color>(pub C);
160
161 impl<C: Color> fmt::Display for Fg<C> {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 self.0.write_fg(f)
164 }
165 }
166
167 /// A background color.
168 #[derive(Debug, Clone, Copy)]
169 pub struct Bg<C: Color>(pub C);
170
171 impl<C: Color> fmt::Display for Bg<C> {
172 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173 self.0.write_bg(f)
174 }
175 }
176
177 /// Types that allow detection of the colors they support.
178 pub trait DetectColors {
179 /// How many ANSI colors are supported (from 8 to 256)?
180 ///
181 /// Beware: the information given isn't authoritative, it's infered through escape codes or the
182 /// value of `TERM`, more colors may be available.
183 fn available_colors(&mut self) -> io::Result<u16>;
184 }
185
186 impl<W: Write> DetectColors for W {
187 fn available_colors(&mut self) -> io::Result<u16> {
188 let mut stdin = async_stdin();
189
190 if detect_color(self, &mut stdin, 0)? {
191 // OSC 4 is supported, detect how many colors there are.
192 // Do a binary search of the last supported color.
193 let mut min = 8;
194 let mut max = 256;
195 let mut i;
196 while min + 1 < max {
197 i = (min + max) / 2;
198 if detect_color(self, &mut stdin, i)? {
199 min = i
200 } else {
201 max = i
202 }
203 }
204 Ok(max)
205 } else {
206 // OSC 4 is not supported, trust TERM contents.
207 Ok(match env::var_os("TERM") {
208 Some(val) => {
209 if val.to_str().unwrap_or("").contains("256color") {
210 256
211 } else {
212 8
213 }
214 }
215 None => 8,
216 })
217 }
218 }
219 }
220
221 /// Detect a color using OSC 4.
222 fn detect_color(stdout: &mut Write, stdin: &mut Read, color: u16) -> io::Result<bool> {
223 // Is the color available?
224 // Use `ESC ] 4 ; color ; ? BEL`.
225 write!(stdout, "\x1B]4;{};?\x07", color)?;
226 stdout.flush()?;
227
228 let mut buf: [u8; 1] = [0];
229 let mut total_read = 0;
230
231 let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
232 let now = SystemTime::now();
233 let bell = 7u8;
234
235 // Either consume all data up to bell or wait for a timeout.
236 while buf[0] != bell && now.elapsed().unwrap() < timeout {
237 total_read += stdin.read(&mut buf)?;
238 }
239
240 // If there was a response, the color is supported.
241 Ok(total_read > 0)
242 }