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> ANSIGenericString<'a, S>
107 where <S as ToOwned>::Owned: fmt::Debug {
108
109 pub fn style_ref(&self) -> &Style {
111 &self.style
112 }
113
114 pub fn style_ref_mut(&mut self) -> &mut Style {
116 &mut self.style
117 }
118}
119
120impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S>
121where <S as ToOwned>::Owned: fmt::Debug {
122 type Target = S;
123
124 fn deref(&self) -> &S {
125 self.string.deref()
126 }
127}
128
129
130#[derive(Debug, PartialEq)]
133pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized>
134 (pub &'a [ANSIGenericString<'a, S>])
135 where <S as ToOwned>::Owned: fmt::Debug, S: PartialEq;
136
137pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>;
140
141#[allow(non_snake_case)]
143pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> {
144 ANSIGenericStrings(arg)
145}
146
147pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>;
150
151#[allow(non_snake_case)]
153pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> {
154 ANSIGenericStrings(arg)
155}
156
157
158impl Style {
161
162 #[must_use]
164 pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
165 where I: Into<Cow<'a, S>>,
166 <S as ToOwned>::Owned: fmt::Debug {
167 ANSIGenericString {
168 string: input.into(),
169 style: self,
170 }
171 }
172}
173
174
175impl Colour {
176
177 #[must_use]
186 pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
187 where 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}
195
196
197impl<'a> fmt::Display for ANSIString<'a> {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 let w: &mut fmt::Write = f;
202 self.write_to_any(w)
203 }
204}
205
206impl<'a> ANSIByteString<'a> {
207 pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
210 let w: &mut io::Write = w;
211 self.write_to_any(w)
212 }
213}
214
215impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
216where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
217 fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
218 write!(w, "{}", self.style.prefix())?;
219 w.write_str(self.string.as_ref())?;
220 write!(w, "{}", self.style.suffix())
221 }
222}
223
224
225impl<'a> fmt::Display for ANSIStrings<'a> {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 let f: &mut fmt::Write = f;
230 self.write_to_any(f)
231 }
232}
233
234impl<'a> ANSIByteStrings<'a> {
235 pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
239 let w: &mut io::Write = w;
240 self.write_to_any(w)
241 }
242}
243
244impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> ANSIGenericStrings<'a, S>
245where <S as ToOwned>::Owned: fmt::Debug, &'a S: AsRef<[u8]> {
246 fn write_to_any<W: AnyWrite<wstr=S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
247 use self::Difference::*;
248
249 let first = match self.0.first() {
250 None => return Ok(()),
251 Some(f) => f,
252 };
253
254 write!(w, "{}", first.style.prefix())?;
255 w.write_str(first.string.as_ref())?;
256
257 for window in self.0.windows(2) {
258 match 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 => {},
262 }
263
264 w.write_str(&window[1].string)?;
265 }
266
267 if let Some(last) = self.0.last() {
271 if !last.style.is_plain() {
272 write!(w, "{}", RESET)?;
273 }
274 }
275
276 Ok(())
277 }
278}
279
280
281#[cfg(test)]
284mod tests {
285 pub use super::super::ANSIStrings;
286 pub use style::Style;
287 pub use style::Colour::*;
288
289 #[test]
290 fn no_control_codes_for_plain() {
291 let one = Style::default().paint("one");
292 let two = Style::default().paint("two");
293 let output = format!("{}", ANSIStrings( &[ one, two ] ));
294 assert_eq!(&*output, "onetwo");
295 }
296}