1use std::borrow::Cow;
2use std::fmt;
3use std::io;
4use std::ops::Deref;
56use ansi::RESET;
7use difference::Difference;
8use style::{Style, Colour};
9use write::AnyWrite;
101112/// 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)]
16pub struct ANSIGenericString<'a, S: 'a + ToOwned + ?Sized>
17where <S as ToOwned>::Owned: fmt::Debug {
18 style: Style,
19 string: Cow<'a, S>,
20}
212223/// 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/// ```
34impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S>
35where <S as ToOwned>::Owned: fmt::Debug {
36fn clone(&self) -> ANSIGenericString<'a, S> {
37 ANSIGenericString {
38 style: self.style,
39 string: self.string.clone(),
40 }
41 }
42}
4344// 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.
64656667/// 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/// ```
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/// ```
89pub type ANSIString<'a> = ANSIGenericString<'a, str>;
9091/// An `ANSIByteString` represents a formatted series of bytes. Use
92/// `ANSIByteString` when styling text with an unknown encoding.
93pub type ANSIByteString<'a> = ANSIGenericString<'a, [u8]>;
9495impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for ANSIGenericString<'a, S>
96where I: Into<Cow<'a, S>>,
97 <S as ToOwned>::Owned: fmt::Debug {
98fn from(input: I) -> ANSIGenericString<'a, S> {
99 ANSIGenericString {
100 string: input.into(),
101 style: Style::default(),
102 }
103 }
104}
105106impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
107where <S as ToOwned>::Owned: fmt::Debug {
108109/// Directly access the style
110pub fn style_ref(&self) -> &Style {
111&self.style
112 }
113114/// Directly access the style mutably
115pub fn style_ref_mut(&mut self) -> &mut Style {
116&mut self.style
117 }
118}
119120impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S>
121where <S as ToOwned>::Owned: fmt::Debug {
122type Target = S;
123124fn deref(&self) -> &S {
125self.string.deref()
126 }
127}
128129130/// A set of `ANSIGenericString`s collected together, in order to be
131/// written with a minimum of control characters.
132#[derive(Debug, PartialEq)]
133pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized>
134 (pub &'a [ANSIGenericString<'a, S>])
135where <S as ToOwned>::Owned: fmt::Debug, S: PartialEq;
136137/// A set of `ANSIString`s collected together, in order to be written with a
138/// minimum of control characters.
139pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>;
140141/// A function to construct an `ANSIStrings` instance.
142#[allow(non_snake_case)]
143pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> {
144 ANSIGenericStrings(arg)
145}
146147/// A set of `ANSIByteString`s collected together, in order to be
148/// written with a minimum of control characters.
149pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>;
150151/// A function to construct an `ANSIByteStrings` instance.
152#[allow(non_snake_case)]
153pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> {
154 ANSIGenericStrings(arg)
155}
156157158// ---- paint functions ----
159160impl Style {
161162/// Paints the given text with this colour, returning an ANSI string.
163#[must_use]
164pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
165where I: Into<Cow<'a, S>>,
166 <S as ToOwned>::Owned: fmt::Debug {
167 ANSIGenericString {
168 string: input.into(),
169 style: self,
170 }
171 }
172}
173174175impl Colour {
176177/// Paints the given text with this colour, returning an ANSI string.
178 /// This is a short-cut so you don’t have to use `Blue.normal()` just
179 /// to get blue text.
180 ///
181 /// ```
182 /// use ansi_term::Colour::Blue;
183 /// println!("{}", Blue.paint("da ba dee"));
184 /// ```
185#[must_use]
186pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
187where I: Into<Cow<'a, S>>,
188 <S as ToOwned>::Owned: fmt::Debug {
189 ANSIGenericString {
190 string: input.into(),
191 style: self.normal(),
192 }
193 }
194}
195196197// ---- writers for individual ANSI strings ----
198199impl<'a> fmt::Display for ANSIString<'a> {
200fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201let w: &mut fmt::Write = f;
202self.write_to_any(w)
203 }
204}
205206impl<'a> ANSIByteString<'a> {
207/// Write an `ANSIByteString` to an `io::Write`. This writes the escape
208 /// sequences for the associated `Style` around the bytes.
209pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
210let w: &mut io::Write = w;
211self.write_to_any(w)
212 }
213}
214215impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
216where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
217fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
218write!(w, "{}", self.style.prefix())?;
219 w.write_str(self.string.as_ref())?;
220write!(w, "{}", self.style.suffix())
221 }
222}
223224225// ---- writers for combined ANSI strings ----
226227impl<'a> fmt::Display for ANSIStrings<'a> {
228fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229let f: &mut fmt::Write = f;
230self.write_to_any(f)
231 }
232}
233234impl<'a> ANSIByteStrings<'a> {
235/// Write `ANSIByteStrings` to an `io::Write`. This writes the minimal
236 /// escape sequences for the associated `Style`s around each set of
237 /// bytes.
238pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
239let w: &mut io::Write = w;
240self.write_to_any(w)
241 }
242}
243244impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> ANSIGenericStrings<'a, S>
245where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
246fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
247use self::Difference::*;
248249let first = match self.0.first() {
250None => return Ok(()),
251Some(f) => f,
252 };
253254write!(w, "{}", first.style.prefix())?;
255 w.write_str(first.string.as_ref())?;
256257for window in self.0.windows(2) {
258match Difference::between(&window[0].style, &window[1].style) {
259 ExtraStyles(style) => write!(w, "{}", style.prefix())?,
260 Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?,
261 NoDifference => {/* Do nothing! */},
262 }
263264 w.write_str(&window[1].string)?;
265 }
266267// Write the final reset string after all of the ANSIStrings have been
268 // written, *except* if the last one has no styles, because it would
269 // have already been written by this point.
270if let Some(last) = self.0.last() {
271if !last.style.is_plain() {
272write!(w, "{}", RESET)?;
273 }
274 }
275276Ok(())
277 }
278}
279280281// ---- tests ----
282283#[cfg(test)]
284mod tests {
285pub use super::super::ANSIStrings;
286pub use style::Style;
287pub use style::Colour::*;
288289#[test]
290fn no_control_codes_for_plain() {
291let one = Style::default().paint("one");
292let two = Style::default().paint("two");
293let output = format!("{}", ANSIStrings( &[ one, two ] ));
294assert_eq!(&*output, "onetwo");
295 }
296}