1 use std::borrow::Cow;
2 use std::fmt;
3 use std::io;
4 use std::ops::Deref;
5 
6 use ansi::RESET;
7 use difference::Difference;
8 use style::{Style, Colour};
9 use write::AnyWrite;
10 
11 
12 /// An `ANSIGenericString` includes a generic string type and a `Style` to
13 /// display that string.  `ANSIString` and `ANSIByteString` are aliases for
14 /// this type on `str` and `[u8]`, respectively.
15 #[derive(PartialEq, Debug)]
16 pub struct ANSIGenericString<'a, S: 'a + ToOwned + ?Sized>
17 where <S as ToOwned>::Owned: fmt::Debug {
18     style: Style,
19     string: Cow<'a, S>,
20 }
21 
22 
23 /// Cloning an `ANSIGenericString` will clone its underlying string.
24 ///
25 /// ### Examples
26 ///
27 /// ```
28 /// use ansi_term::ANSIString;
29 ///
30 /// let plain_string = ANSIString::from("a plain string");
31 /// let clone_string = plain_string.clone();
32 /// assert_eq!(clone_string, plain_string);
33 /// ```
34 impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S>
35 where <S as ToOwned>::Owned: fmt::Debug {
clone(&self) -> ANSIGenericString<'a, S>36     fn clone(&self) -> ANSIGenericString<'a, S> {
37         ANSIGenericString {
38             style: self.style,
39             string: self.string.clone(),
40         }
41     }
42 }
43 
44 // You might think that the hand-written Clone impl above is the same as the
45 // one that gets generated with #[derive]. But it’s not *quite* the same!
46 //
47 // `str` is not Clone, and the derived Clone implementation puts a Clone
48 // constraint on the S type parameter (generated using --pretty=expanded):
49 //
50 //                  ↓_________________↓
51 //     impl <'a, S: ::std::clone::Clone + 'a + ToOwned + ?Sized> ::std::clone::Clone
52 //     for ANSIGenericString<'a, S> where
53 //     <S as ToOwned>::Owned: fmt::Debug { ... }
54 //
55 // This resulted in compile errors when you tried to derive Clone on a type
56 // that used it:
57 //
58 //     #[derive(PartialEq, Debug, Clone, Default)]
59 //     pub struct TextCellContents(Vec<ANSIString<'static>>);
60 //                                 ^^^^^^^^^^^^^^^^^^^^^^^^^
61 //     error[E0277]: the trait `std::clone::Clone` is not implemented for `str`
62 //
63 // The hand-written impl above can ignore that constraint and still compile.
64 
65 
66 
67 /// An ANSI String is a string coupled with the `Style` to display it
68 /// in a terminal.
69 ///
70 /// Although not technically a string itself, it can be turned into
71 /// one with the `to_string` method.
72 ///
73 /// ### Examples
74 ///
75 /// ```no_run
76 /// use ansi_term::ANSIString;
77 /// use ansi_term::Colour::Red;
78 ///
79 /// let red_string = Red.paint("a red string");
80 /// println!("{}", red_string);
81 /// ```
82 ///
83 /// ```
84 /// use ansi_term::ANSIString;
85 ///
86 /// let plain_string = ANSIString::from("a plain string");
87 /// assert_eq!(&*plain_string, "a plain string");
88 /// ```
89 pub type ANSIString<'a> = ANSIGenericString<'a, str>;
90 
91 /// An `ANSIByteString` represents a formatted series of bytes.  Use
92 /// `ANSIByteString` when styling text with an unknown encoding.
93 pub type ANSIByteString<'a> = ANSIGenericString<'a, [u8]>;
94 
95 impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for ANSIGenericString<'a, S>
96 where I: Into<Cow<'a, S>>,
97       <S as ToOwned>::Owned: fmt::Debug {
from(input: I) -> ANSIGenericString<'a, S>98     fn from(input: I) -> ANSIGenericString<'a, S> {
99         ANSIGenericString {
100             string: input.into(),
101             style:  Style::default(),
102         }
103     }
104 }
105 
106 impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S>
107 where <S as ToOwned>::Owned: fmt::Debug {
108     type Target = S;
109 
deref(&self) -> &S110     fn deref(&self) -> &S {
111         self.string.deref()
112     }
113 }
114 
115 
116 /// A set of `ANSIGenericString`s collected together, in order to be
117 /// written with a minimum of control characters.
118 pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized>
119     (pub &'a [ANSIGenericString<'a, S>])
120     where <S as ToOwned>::Owned: fmt::Debug;
121 
122 /// A set of `ANSIString`s collected together, in order to be written with a
123 /// minimum of control characters.
124 pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>;
125 
126 /// A function to construct an `ANSIStrings` instance.
127 #[allow(non_snake_case)]
ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a>128 pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> {
129     ANSIGenericStrings(arg)
130 }
131 
132 /// A set of `ANSIByteString`s collected together, in order to be
133 /// written with a minimum of control characters.
134 pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>;
135 
136 /// A function to construct an `ANSIByteStrings` instance.
137 #[allow(non_snake_case)]
ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a>138 pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> {
139     ANSIGenericStrings(arg)
140 }
141 
142 
143 // ---- paint functions ----
144 
145 impl Style {
146 
147     /// Paints the given text with this colour, returning an ANSI string.
paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S> where I: Into<Cow<'a, S>>, <S as ToOwned>::Owned: fmt::Debug148     pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
149     where I: Into<Cow<'a, S>>,
150           <S as ToOwned>::Owned: fmt::Debug {
151         ANSIGenericString {
152             string: input.into(),
153             style:  self,
154         }
155     }
156 }
157 
158 
159 impl Colour {
160 
161     /// Paints the given text with this colour, returning an ANSI string.
162     /// This is a short-cut so you don’t have to use `Blue.normal()` just
163     /// to get blue text.
164     ///
165     /// ```
166     /// use ansi_term::Colour::Blue;
167     /// println!("{}", Blue.paint("da ba dee"));
168     /// ```
paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S> where I: Into<Cow<'a, S>>, <S as ToOwned>::Owned: fmt::Debug169     pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
170     where I: Into<Cow<'a, S>>,
171           <S as ToOwned>::Owned: fmt::Debug {
172         ANSIGenericString {
173             string: input.into(),
174             style:  self.normal(),
175         }
176     }
177 }
178 
179 
180 // ---- writers for individual ANSI strings ----
181 
182 impl<'a> fmt::Display for ANSIString<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result183     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184         let w: &mut fmt::Write = f;
185         self.write_to_any(w)
186     }
187 }
188 
189 impl<'a> ANSIByteString<'a> {
190     /// Write an `ANSIByteString` to an `io::Write`.  This writes the escape
191     /// sequences for the associated `Style` around the bytes.
write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()>192     pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
193         let w: &mut io::Write = w;
194         self.write_to_any(w)
195     }
196 }
197 
198 impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
199 where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error>200     fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
201         write!(w, "{}", self.style.prefix())?;
202         w.write_str(self.string.as_ref())?;
203         write!(w, "{}", self.style.suffix())
204     }
205 }
206 
207 
208 // ---- writers for combined ANSI strings ----
209 
210 impl<'a> fmt::Display for ANSIStrings<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result211     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212         let f: &mut fmt::Write = f;
213         self.write_to_any(f)
214     }
215 }
216 
217 impl<'a> ANSIByteStrings<'a> {
218     /// Write `ANSIByteStrings` to an `io::Write`.  This writes the minimal
219     /// escape sequences for the associated `Style`s around each set of
220     /// bytes.
write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()>221     pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
222         let w: &mut io::Write = w;
223         self.write_to_any(w)
224     }
225 }
226 
227 impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericStrings<'a, S>
228 where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error>229     fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
230         use self::Difference::*;
231 
232         let first = match self.0.first() {
233             None => return Ok(()),
234             Some(f) => f,
235         };
236 
237         write!(w, "{}", first.style.prefix())?;
238         w.write_str(first.string.as_ref())?;
239 
240         for window in self.0.windows(2) {
241             match Difference::between(&window[0].style, &window[1].style) {
242                 ExtraStyles(style) => write!(w, "{}", style.prefix())?,
243                 Reset              => write!(w, "{}{}", RESET, window[1].style.prefix())?,
244                 NoDifference       => {/* Do nothing! */},
245             }
246 
247             w.write_str(&window[1].string)?;
248         }
249 
250         // Write the final reset string after all of the ANSIStrings have been
251         // written, *except* if the last one has no styles, because it would
252         // have already been written by this point.
253         if let Some(last) = self.0.last() {
254             if !last.style.is_plain() {
255                 write!(w, "{}", RESET)?;
256             }
257         }
258 
259         Ok(())
260     }
261 }
262 
263 
264 // ---- tests ----
265 
266 #[cfg(test)]
267 mod tests {
268     pub use super::super::ANSIStrings;
269     pub use style::Style;
270     pub use style::Colour::*;
271 
272     #[test]
no_control_codes_for_plain()273     fn no_control_codes_for_plain() {
274         let one = Style::default().paint("one");
275         let two = Style::default().paint("two");
276         let output = format!("{}", ANSIStrings( &[ one, two ] ));
277         assert_eq!(&*output, "onetwo");
278     }
279 }
280