stylish_stringlike/text/
paintable.rs

1#[cfg(test)]
2use ansi_term::{ANSIStrings, Style};
3use std::borrow::Borrow;
4/// Provides functionality to display strings with markup.
5pub trait Paintable {
6    /// Applies markup to a given string.
7    ///
8    /// # Example
9    ///
10    /// ```
11    /// use stylish_stringlike::text::Paintable;
12    /// struct MyMarkup {
13    ///     tag: String,
14    /// }
15    ///
16    /// impl Paintable for MyMarkup {
17    ///     fn paint(&self, target: &str) -> String {
18    ///         [
19    ///             format!("<{}>", self.tag).as_str(),
20    ///             target,
21    ///             format!("</{}>", self.tag).as_str(),
22    ///         ]
23    ///         .iter()
24    ///         .map(|x| *x)
25    ///         .collect()
26    ///     }
27    /// }
28    /// let italic = MyMarkup {
29    ///     tag: String::from("i"),
30    /// };
31    /// assert_eq!(italic.paint("foo"), String::from("<i>foo</i>"));
32    /// ```
33    fn paint(&self, target: &str) -> String;
34    /// Applies markup to a given iterator of ([`Paintable`], [`str`]) objects.
35    /// Provide an implementation for this if multiple adjacent [`Paintable`]s
36    /// can be joined together.
37    ///
38    /// # Example
39    /// ```
40    /// use std::borrow::Borrow;
41    /// use stylish_stringlike::text::Paintable;
42    /// #[derive(Clone, Eq, PartialEq)]
43    /// struct MyMarkup {
44    ///     tag: String,
45    /// }
46    ///
47    /// impl Paintable for MyMarkup {
48    ///     fn paint(&self, target: &str) -> String {
49    ///         [
50    ///             format!("<{}>", self.tag).as_str(),
51    ///             target,
52    ///             format!("</{}>", self.tag).as_str(),
53    ///         ]
54    ///         .iter()
55    ///         .map(|x| *x)
56    ///         .collect()
57    ///     }
58    ///     fn paint_many<'a, T, U, V>(groups: T) -> String
59    ///     where
60    ///         T: IntoIterator<Item = (U, V)> + 'a,
61    ///         U: Borrow<Self> + 'a,
62    ///         V: Borrow<str> + 'a,
63    ///     {
64    ///         let mut result = String::new();
65    ///         let mut previous_span = String::new();
66    ///         let mut previous_tag: Option<MyMarkup> = None;
67    ///         for (painter, s) in groups {
68    ///             match previous_tag {
69    ///                 Some(ref p) if painter.borrow() != p => {
70    ///                     result += &p.paint(&previous_span);
71    ///                     previous_span = String::from(s.borrow());
72    ///                     previous_tag = Some(painter.borrow().clone());
73    ///                 }
74    ///                 Some(ref p) => {
75    ///                     previous_span.push_str(s.borrow());
76    ///                 }
77    ///                 None => {
78    ///                     previous_span.push_str(s.borrow());
79    ///                     previous_tag = Some(painter.borrow().clone());
80    ///                 }
81    ///             }
82    ///         }
83    ///         if let Some(p) = previous_tag {
84    ///             if !previous_span.is_empty() {
85    ///                 result += &p.paint(&previous_span);
86    ///             }
87    ///         }
88    ///         result
89    ///     }
90    /// }
91    /// let italic = MyMarkup {
92    ///     tag: String::from("i"),
93    /// };
94    /// let bold = MyMarkup {
95    ///     tag: String::from("b"),
96    /// };
97    /// let foobarbaz = vec![(&italic, "foo"), (&italic, "bar"), (&bold, "baz")];
98    /// assert_eq!(
99    ///     MyMarkup::paint_many(foobarbaz),
100    ///     String::from("<i>foobar</i><b>baz</b>")
101    /// );
102    /// ```
103    fn paint_many<'a, T, U, V>(groups: T) -> String
104    where
105        T: IntoIterator<Item = (U, V)> + 'a,
106        U: Borrow<Self> + 'a,
107        V: Borrow<str> + 'a,
108    {
109        let mut result = String::new();
110        for (painter, text) in groups {
111            result.push_str(&painter.borrow().paint(text.borrow()));
112        }
113        result
114    }
115}
116
117#[cfg(test)]
118impl Paintable for Style {
119    fn paint(&self, target: &str) -> String {
120        Style::paint(*self, target).to_string()
121    }
122    fn paint_many<'a, T, U, V>(groups: T) -> String
123    where
124        T: IntoIterator<Item = (U, V)> + 'a,
125        U: Borrow<Style> + 'a,
126        V: Borrow<str> + 'a,
127    {
128        let mut strings = vec![];
129        for (style, text) in groups {
130            let text = text.borrow().to_string();
131            strings.push(Style::paint(*style.borrow(), text));
132        }
133        format!("{}", ANSIStrings(strings.as_slice()))
134    }
135}