]> git.proxmox.com Git - rustc.git/blob - vendor/ansi_term-0.11.0/src/ansi.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / vendor / ansi_term-0.11.0 / src / ansi.rs
1 use style::{Colour, Style};
2
3 use std::fmt;
4
5 use write::AnyWrite;
6
7
8 // ---- generating ANSI codes ----
9
10 impl Style {
11
12 /// Write any ANSI codes that go *before* a piece of text. These should be
13 /// the codes to set the terminal to a different colour or font style.
14 fn write_prefix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
15
16 // If there are actually no styles here, then don’t write *any* codes
17 // as the prefix. An empty ANSI code may not affect the terminal
18 // output at all, but a user may just want a code-free string.
19 if self.is_plain() {
20 return Ok(());
21 }
22
23 // Write the codes’ prefix, then write numbers, separated by
24 // semicolons, for each text style we want to apply.
25 write!(f, "\x1B[")?;
26 let mut written_anything = false;
27
28 {
29 let mut write_char = |c| {
30 if written_anything { write!(f, ";")?; }
31 written_anything = true;
32 write!(f, "{}", c)?;
33 Ok(())
34 };
35
36 if self.is_bold { write_char('1')? }
37 if self.is_dimmed { write_char('2')? }
38 if self.is_italic { write_char('3')? }
39 if self.is_underline { write_char('4')? }
40 if self.is_blink { write_char('5')? }
41 if self.is_reverse { write_char('7')? }
42 if self.is_hidden { write_char('8')? }
43 if self.is_strikethrough { write_char('9')? }
44 }
45
46 // The foreground and background colours, if specified, need to be
47 // handled specially because the number codes are more complicated.
48 // (see `write_background_code` and `write_foreground_code`)
49 if let Some(bg) = self.background {
50 if written_anything { write!(f, ";")?; }
51 written_anything = true;
52 bg.write_background_code(f)?;
53 }
54
55 if let Some(fg) = self.foreground {
56 if written_anything { write!(f, ";")?; }
57 fg.write_foreground_code(f)?;
58 }
59
60 // All the codes end with an `m`, because reasons.
61 write!(f, "m")?;
62
63 Ok(())
64 }
65
66 /// Write any ANSI codes that go *after* a piece of text. These should be
67 /// the codes to *reset* the terminal back to its normal colour and style.
68 fn write_suffix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
69 if self.is_plain() {
70 Ok(())
71 }
72 else {
73 write!(f, "{}", RESET)
74 }
75 }
76 }
77
78
79 /// The code to send to reset all styles and return to `Style::default()`.
80 pub static RESET: &str = "\x1B[0m";
81
82
83
84 impl Colour {
85 fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
86 match *self {
87 Colour::Black => write!(f, "30"),
88 Colour::Red => write!(f, "31"),
89 Colour::Green => write!(f, "32"),
90 Colour::Yellow => write!(f, "33"),
91 Colour::Blue => write!(f, "34"),
92 Colour::Purple => write!(f, "35"),
93 Colour::Cyan => write!(f, "36"),
94 Colour::White => write!(f, "37"),
95 Colour::Fixed(num) => write!(f, "38;5;{}", &num),
96 Colour::RGB(r,g,b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
97 }
98 }
99
100 fn write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
101 match *self {
102 Colour::Black => write!(f, "40"),
103 Colour::Red => write!(f, "41"),
104 Colour::Green => write!(f, "42"),
105 Colour::Yellow => write!(f, "43"),
106 Colour::Blue => write!(f, "44"),
107 Colour::Purple => write!(f, "45"),
108 Colour::Cyan => write!(f, "46"),
109 Colour::White => write!(f, "47"),
110 Colour::Fixed(num) => write!(f, "48;5;{}", &num),
111 Colour::RGB(r,g,b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
112 }
113 }
114 }
115
116
117 /// Like `ANSIString`, but only displays the style prefix.
118 #[derive(Clone, Copy, Debug)]
119 pub struct Prefix(Style);
120
121 /// Like `ANSIString`, but only displays the difference between two
122 /// styles.
123 #[derive(Clone, Copy, Debug)]
124 pub struct Infix(Style, Style);
125
126 /// Like `ANSIString`, but only displays the style suffix.
127 #[derive(Clone, Copy, Debug)]
128 pub struct Suffix(Style);
129
130
131 impl Style {
132
133 /// The prefix for this style.
134 pub fn prefix(self) -> Prefix {
135 Prefix(self)
136 }
137
138 /// The infix between this style and another.
139 pub fn infix(self, other: Style) -> Infix {
140 Infix(self, other)
141 }
142
143 /// The suffix for this style.
144 pub fn suffix(self) -> Suffix {
145 Suffix(self)
146 }
147 }
148
149
150 impl Colour {
151
152 /// The prefix for this colour.
153 pub fn prefix(self) -> Prefix {
154 Prefix(self.normal())
155 }
156
157 /// The infix between this colour and another.
158 pub fn infix(self, other: Colour) -> Infix {
159 Infix(self.normal(), other.normal())
160 }
161
162 /// The suffix for this colour.
163 pub fn suffix(self) -> Suffix {
164 Suffix(self.normal())
165 }
166 }
167
168
169 impl fmt::Display for Prefix {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 let f: &mut fmt::Write = f;
172 self.0.write_prefix(f)
173 }
174 }
175
176
177 impl fmt::Display for Infix {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 use difference::Difference;
180
181 match Difference::between(&self.0, &self.1) {
182 Difference::ExtraStyles(style) => {
183 let f: &mut fmt::Write = f;
184 style.write_prefix(f)
185 },
186 Difference::Reset => {
187 let f: &mut fmt::Write = f;
188 write!(f, "{}{}", RESET, self.0.prefix())
189 },
190 Difference::NoDifference => {
191 Ok(()) // nothing to write
192 },
193 }
194 }
195 }
196
197
198 impl fmt::Display for Suffix {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 let f: &mut fmt::Write = f;
201 self.0.write_suffix(f)
202 }
203 }
204
205
206
207 #[cfg(test)]
208 mod test {
209 use style::Style;
210 use style::Colour::*;
211
212 macro_rules! test {
213 ($name: ident: $style: expr; $input: expr => $result: expr) => {
214 #[test]
215 fn $name() {
216 assert_eq!($style.paint($input).to_string(), $result.to_string());
217
218 let mut v = Vec::new();
219 $style.paint($input.as_bytes()).write_to(&mut v).unwrap();
220 assert_eq!(v.as_slice(), $result.as_bytes());
221 }
222 };
223 }
224
225 test!(plain: Style::default(); "text/plain" => "text/plain");
226 test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m");
227 test!(black: Black.normal(); "hi" => "\x1B[30mhi\x1B[0m");
228 test!(yellow_bold: Yellow.bold(); "hi" => "\x1B[1;33mhi\x1B[0m");
229 test!(yellow_bold_2: Yellow.normal().bold(); "hi" => "\x1B[1;33mhi\x1B[0m");
230 test!(blue_underline: Blue.underline(); "hi" => "\x1B[4;34mhi\x1B[0m");
231 test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[1;4;32mhi\x1B[0m");
232 test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[1;4;32mhi\x1B[0m");
233 test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m");
234 test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m");
235 test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m");
236 test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m");
237 test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m");
238 test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m");
239 test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m");
240 test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m");
241 test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m");
242 test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m");
243 test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m");
244 test!(rgb: RGB(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m");
245 test!(rgb_on_blue: RGB(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m");
246 test!(blue_on_rgb: Blue.on(RGB(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m");
247 test!(rgb_on_rgb: RGB(70,130,180).on(RGB(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m");
248 test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m");
249 test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m");
250 test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m");
251 test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m");
252 test!(italic: Style::new().italic(); "hi" => "\x1B[3mhi\x1B[0m");
253 test!(blink: Style::new().blink(); "hi" => "\x1B[5mhi\x1B[0m");
254 test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m");
255 test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m");
256 test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m");
257
258 }