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}