1use std::borrow::Cow;
2use std::fmt;
3use std::io;
4use std::ops::Deref;
5
6use ansi::RESET;
7use difference::Difference;
8use style::{Style, Colour};
9use write::AnyWrite;
10
11
12#[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}
21
22
23impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S>
35where <S as ToOwned>::Owned: fmt::Debug {
36 fn clone(&self) -> ANSIGenericString<'a, S> {
37 ANSIGenericString {
38 style: self.style,
39 string: self.string.clone(),
40 }
41 }
42}
43
44pub type ANSIString<'a> = ANSIGenericString<'a, str>;
90
91pub type ANSIByteString<'a> = ANSIGenericString<'a, [u8]>;
94
95impl<'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 {
98 fn from(input: I) -> ANSIGenericString<'a, S> {
99 ANSIGenericString {
100 string: input.into(),
101 style: Style::default(),
102 }
103 }
104}
105
106impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S>
107where <S as ToOwned>::Owned: fmt::Debug {
108 type Target = S;
109
110 fn deref(&self) -> &S {
111 self.string.deref()
112 }
113}
114
115
116pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized>
119 (pub &'a [ANSIGenericString<'a, S>])
120 where <S as ToOwned>::Owned: fmt::Debug;
121
122pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>;
125
126#[allow(non_snake_case)]
128pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> {
129 ANSIGenericStrings(arg)
130}
131
132pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>;
135
136#[allow(non_snake_case)]
138pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> {
139 ANSIGenericStrings(arg)
140}
141
142
143impl Style {
146
147 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
159impl Colour {
160
161 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
180impl<'a> fmt::Display for ANSIString<'a> {
183 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
189impl<'a> ANSIByteString<'a> {
190 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
198impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
199where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
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
208impl<'a> fmt::Display for ANSIStrings<'a> {
211 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
217impl<'a> ANSIByteStrings<'a> {
218 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
227impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericStrings<'a, S>
228where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
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 => {},
245 }
246
247 w.write_str(&window[1].string)?;
248 }
249
250 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#[cfg(test)]
267mod tests {
268 pub use super::super::ANSIStrings;
269 pub use style::Style;
270 pub use style::Colour::*;
271
272 #[test]
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}