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