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 bytes that go *before* a piece of text to the given writer.
write_prefix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error>13     fn write_prefix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
14 
15         // If there are actually no styles here, then don’t write *any* codes
16         // as the prefix. An empty ANSI code may not affect the terminal
17         // output at all, but a user may just want a code-free string.
18         if self.is_plain() {
19             return Ok(());
20         }
21 
22         // Write the codes’ prefix, then write numbers, separated by
23         // semicolons, for each text style we want to apply.
24         write!(f, "\x1B[")?;
25         let mut written_anything = false;
26 
27         {
28             let mut write_char = |c| {
29                 if written_anything { write!(f, ";")?; }
30                 written_anything = true;
31                 write!(f, "{}", c)?;
32                 Ok(())
33             };
34 
35             if self.is_bold           { write_char('1')? }
36             if self.is_dimmed         { write_char('2')? }
37             if self.is_italic         { write_char('3')? }
38             if self.is_underline      { write_char('4')? }
39             if self.is_blink          { write_char('5')? }
40             if self.is_reverse        { write_char('7')? }
41             if self.is_hidden         { write_char('8')? }
42             if self.is_strikethrough  { write_char('9')? }
43         }
44 
45         // The foreground and background colours, if specified, need to be
46         // handled specially because the number codes are more complicated.
47         // (see `write_background_code` and `write_foreground_code`)
48         if let Some(bg) = self.background {
49             if written_anything { write!(f, ";")?; }
50             written_anything = true;
51             bg.write_background_code(f)?;
52         }
53 
54         if let Some(fg) = self.foreground {
55             if written_anything { write!(f, ";")?; }
56             fg.write_foreground_code(f)?;
57         }
58 
59         // All the codes end with an `m`, because reasons.
60         write!(f, "m")?;
61 
62         Ok(())
63     }
64 
65     /// Write any bytes that go *after* a piece of text to the given writer.
write_suffix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error>66     fn write_suffix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
67         if self.is_plain() {
68             Ok(())
69         }
70         else {
71             write!(f, "{}", RESET)
72         }
73     }
74 }
75 
76 
77 /// The code to send to reset all styles and return to `Style::default()`.
78 pub static RESET: &str = "\x1B[0m";
79 
80 
81 
82 impl Colour {
write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error>83     fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
84         match *self {
85             Colour::Black      => write!(f, "30"),
86             Colour::Red        => write!(f, "31"),
87             Colour::Green      => write!(f, "32"),
88             Colour::Yellow     => write!(f, "33"),
89             Colour::Blue       => write!(f, "34"),
90             Colour::Purple     => write!(f, "35"),
91             Colour::Cyan       => write!(f, "36"),
92             Colour::White      => write!(f, "37"),
93             Colour::Fixed(num) => write!(f, "38;5;{}", &num),
94             Colour::RGB(r,g,b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
95         }
96     }
97 
write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error>98     fn write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
99         match *self {
100             Colour::Black      => write!(f, "40"),
101             Colour::Red        => write!(f, "41"),
102             Colour::Green      => write!(f, "42"),
103             Colour::Yellow     => write!(f, "43"),
104             Colour::Blue       => write!(f, "44"),
105             Colour::Purple     => write!(f, "45"),
106             Colour::Cyan       => write!(f, "46"),
107             Colour::White      => write!(f, "47"),
108             Colour::Fixed(num) => write!(f, "48;5;{}", &num),
109             Colour::RGB(r,g,b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
110         }
111     }
112 }
113 
114 
115 /// Like `ANSIString`, but only displays the style prefix.
116 ///
117 /// This type implements the `Display` trait, meaning it can be written to a
118 /// `std::fmt` formatting without doing any extra allocation, and written to a
119 /// string with the `.to_string()` method. For examples, see
120 /// [`Style::prefix`](struct.Style.html#method.prefix).
121 #[derive(Clone, Copy, Debug)]
122 pub struct Prefix(Style);
123 
124 /// Like `ANSIString`, but only displays the difference between two
125 /// styles.
126 ///
127 /// This type implements the `Display` trait, meaning it can be written to a
128 /// `std::fmt` formatting without doing any extra allocation, and written to a
129 /// string with the `.to_string()` method. For examples, see
130 /// [`Style::infix`](struct.Style.html#method.infix).
131 #[derive(Clone, Copy, Debug)]
132 pub struct Infix(Style, Style);
133 
134 /// Like `ANSIString`, but only displays the style suffix.
135 ///
136 /// This type implements the `Display` trait, meaning it can be written to a
137 /// `std::fmt` formatting without doing any extra allocation, and written to a
138 /// string with the `.to_string()` method. For examples, see
139 /// [`Style::suffix`](struct.Style.html#method.suffix).
140 #[derive(Clone, Copy, Debug)]
141 pub struct Suffix(Style);
142 
143 
144 impl Style {
145 
146     /// The prefix bytes for this style. These are the bytes that tell the
147     /// terminal to use a different colour or font style.
148     ///
149     /// # Examples
150     ///
151     /// ```
152     /// use ansi_term::{Style, Colour::Blue};
153     ///
154     /// let style = Style::default().bold();
155     /// assert_eq!("\x1b[1m",
156     ///            style.prefix().to_string());
157     ///
158     /// let style = Blue.bold();
159     /// assert_eq!("\x1b[1;34m",
160     ///            style.prefix().to_string());
161     ///
162     /// let style = Style::default();
163     /// assert_eq!("",
164     ///            style.prefix().to_string());
165     /// ```
prefix(self) -> Prefix166     pub fn prefix(self) -> Prefix {
167         Prefix(self)
168     }
169 
170     /// The infix bytes between this style and `next` style. These are the bytes
171     /// that tell the terminal to change the style to `next`. These may include
172     /// a reset followed by the next colour and style, depending on the two styles.
173     ///
174     /// # Examples
175     ///
176     /// ```
177     /// use ansi_term::{Style, Colour::Green};
178     ///
179     /// let style = Style::default().bold();
180     /// assert_eq!("\x1b[32m",
181     ///            style.infix(Green.bold()).to_string());
182     ///
183     /// let style = Green.normal();
184     /// assert_eq!("\x1b[1m",
185     ///            style.infix(Green.bold()).to_string());
186     ///
187     /// let style = Style::default();
188     /// assert_eq!("",
189     ///            style.infix(style).to_string());
190     /// ```
infix(self, next: Style) -> Infix191     pub fn infix(self, next: Style) -> Infix {
192         Infix(self, next)
193     }
194 
195     /// The suffix for this style. These are the bytes that tell the terminal
196     /// to reset back to its normal colour and font style.
197     ///
198     /// # Examples
199     ///
200     /// ```
201     /// use ansi_term::{Style, Colour::Green};
202     ///
203     /// let style = Style::default().bold();
204     /// assert_eq!("\x1b[0m",
205     ///            style.suffix().to_string());
206     ///
207     /// let style = Green.normal().bold();
208     /// assert_eq!("\x1b[0m",
209     ///            style.suffix().to_string());
210     ///
211     /// let style = Style::default();
212     /// assert_eq!("",
213     ///            style.suffix().to_string());
214     /// ```
suffix(self) -> Suffix215     pub fn suffix(self) -> Suffix {
216         Suffix(self)
217     }
218 }
219 
220 
221 impl Colour {
222 
223     /// The prefix bytes for this colour as a `Style`. These are the bytes
224     /// that tell the terminal to use a different colour or font style.
225     ///
226     /// See also [`Style::prefix`](struct.Style.html#method.prefix).
227     ///
228     /// # Examples
229     ///
230     /// ```
231     /// use ansi_term::Colour::Green;
232     ///
233     /// assert_eq!("\x1b[0m",
234     ///            Green.suffix().to_string());
235     /// ```
prefix(self) -> Prefix236     pub fn prefix(self) -> Prefix {
237         Prefix(self.normal())
238     }
239 
240     /// The infix bytes between this colour and `next` colour. These are the bytes
241     /// that tell the terminal to use the `next` colour, or to do nothing if
242     /// the two colours are equal.
243     ///
244     /// See also [`Style::infix`](struct.Style.html#method.infix).
245     ///
246     /// # Examples
247     ///
248     /// ```
249     /// use ansi_term::Colour::{Red, Yellow};
250     ///
251     /// assert_eq!("\x1b[33m",
252     ///            Red.infix(Yellow).to_string());
253     /// ```
infix(self, next: Colour) -> Infix254     pub fn infix(self, next: Colour) -> Infix {
255         Infix(self.normal(), next.normal())
256     }
257 
258     /// The suffix for this colour as a `Style`. These are the bytes that
259     /// tell the terminal to reset back to its normal colour and font style.
260     ///
261     /// See also [`Style::suffix`](struct.Style.html#method.suffix).
262     ///
263     /// # Examples
264     ///
265     /// ```
266     /// use ansi_term::Colour::Purple;
267     ///
268     /// assert_eq!("\x1b[0m",
269     ///            Purple.suffix().to_string());
270     /// ```
suffix(self) -> Suffix271     pub fn suffix(self) -> Suffix {
272         Suffix(self.normal())
273     }
274 }
275 
276 
277 impl fmt::Display for Prefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result278     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
279         let f: &mut fmt::Write = f;
280         self.0.write_prefix(f)
281     }
282 }
283 
284 
285 impl fmt::Display for Infix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result286     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287         use difference::Difference;
288 
289         match Difference::between(&self.0, &self.1) {
290             Difference::ExtraStyles(style) => {
291                 let f: &mut fmt::Write = f;
292                 style.write_prefix(f)
293             },
294             Difference::Reset => {
295                 let f: &mut fmt::Write = f;
296                 write!(f, "{}{}", RESET, self.1.prefix())
297             },
298             Difference::NoDifference => {
299                 Ok(())   // nothing to write
300             },
301         }
302     }
303 }
304 
305 
306 impl fmt::Display for Suffix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result307     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308         let f: &mut fmt::Write = f;
309         self.0.write_suffix(f)
310     }
311 }
312 
313 
314 
315 #[cfg(test)]
316 mod test {
317     use style::Style;
318     use style::Colour::*;
319 
320     macro_rules! test {
321         ($name: ident: $style: expr; $input: expr => $result: expr) => {
322             #[test]
323             fn $name() {
324                 assert_eq!($style.paint($input).to_string(), $result.to_string());
325 
326                 let mut v = Vec::new();
327                 $style.paint($input.as_bytes()).write_to(&mut v).unwrap();
328                 assert_eq!(v.as_slice(), $result.as_bytes());
329             }
330         };
331     }
332 
333     test!(plain:                 Style::default();                  "text/plain" => "text/plain");
334     test!(red:                   Red;                               "hi" => "\x1B[31mhi\x1B[0m");
335     test!(black:                 Black.normal();                    "hi" => "\x1B[30mhi\x1B[0m");
336     test!(yellow_bold:           Yellow.bold();                     "hi" => "\x1B[1;33mhi\x1B[0m");
337     test!(yellow_bold_2:         Yellow.normal().bold();            "hi" => "\x1B[1;33mhi\x1B[0m");
338     test!(blue_underline:        Blue.underline();                  "hi" => "\x1B[4;34mhi\x1B[0m");
339     test!(green_bold_ul:         Green.bold().underline();          "hi" => "\x1B[1;4;32mhi\x1B[0m");
340     test!(green_bold_ul_2:       Green.underline().bold();          "hi" => "\x1B[1;4;32mhi\x1B[0m");
341     test!(purple_on_white:       Purple.on(White);                  "hi" => "\x1B[47;35mhi\x1B[0m");
342     test!(purple_on_white_2:     Purple.normal().on(White);         "hi" => "\x1B[47;35mhi\x1B[0m");
343     test!(yellow_on_blue:        Style::new().on(Blue).fg(Yellow);  "hi" => "\x1B[44;33mhi\x1B[0m");
344     test!(yellow_on_blue_2:      Cyan.on(Blue).fg(Yellow);          "hi" => "\x1B[44;33mhi\x1B[0m");
345     test!(cyan_bold_on_white:    Cyan.bold().on(White);             "hi" => "\x1B[1;47;36mhi\x1B[0m");
346     test!(cyan_ul_on_white:      Cyan.underline().on(White);        "hi" => "\x1B[4;47;36mhi\x1B[0m");
347     test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m");
348     test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m");
349     test!(fixed:                 Fixed(100);                        "hi" => "\x1B[38;5;100mhi\x1B[0m");
350     test!(fixed_on_purple:       Fixed(100).on(Purple);             "hi" => "\x1B[45;38;5;100mhi\x1B[0m");
351     test!(fixed_on_fixed:        Fixed(100).on(Fixed(200));         "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m");
352     test!(rgb:                   RGB(70,130,180);                   "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m");
353     test!(rgb_on_blue:           RGB(70,130,180).on(Blue);          "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m");
354     test!(blue_on_rgb:           Blue.on(RGB(70,130,180));          "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m");
355     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");
356     test!(bold:                  Style::new().bold();               "hi" => "\x1B[1mhi\x1B[0m");
357     test!(underline:             Style::new().underline();          "hi" => "\x1B[4mhi\x1B[0m");
358     test!(bunderline:            Style::new().bold().underline();   "hi" => "\x1B[1;4mhi\x1B[0m");
359     test!(dimmed:                Style::new().dimmed();             "hi" => "\x1B[2mhi\x1B[0m");
360     test!(italic:                Style::new().italic();             "hi" => "\x1B[3mhi\x1B[0m");
361     test!(blink:                 Style::new().blink();              "hi" => "\x1B[5mhi\x1B[0m");
362     test!(reverse:               Style::new().reverse();            "hi" => "\x1B[7mhi\x1B[0m");
363     test!(hidden:                Style::new().hidden();             "hi" => "\x1B[8mhi\x1B[0m");
364     test!(stricken:              Style::new().strikethrough();      "hi" => "\x1B[9mhi\x1B[0m");
365 
366     #[test]
test_infix()367     fn test_infix() {
368         assert_eq!(Style::new().dimmed().infix(Style::new()).to_string(), "\x1B[0m");
369         assert_eq!(White.dimmed().infix(White.normal()).to_string(), "\x1B[0m\x1B[37m");
370         assert_eq!(White.normal().infix(White.bold()).to_string(), "\x1B[1m");
371         assert_eq!(White.normal().infix(Blue.normal()).to_string(), "\x1B[34m");
372         assert_eq!(Blue.bold().infix(Blue.bold()).to_string(), "");
373     }
374 }
375