stylish_stringlike/text/
tag.rs

1use crate::text::Paintable;
2use std::borrow::Borrow;
3
4/// A simple format for surrounding text in tags
5#[derive(Clone, Debug, Default, PartialEq)]
6pub struct Tag {
7    opening: String,
8    closing: String,
9}
10
11impl Tag {
12    pub fn new(opening: &str, closing: &str) -> Self {
13        Self {
14            opening: opening.to_string(),
15            closing: closing.to_string(),
16        }
17    }
18}
19
20impl Paintable for Tag {
21    fn paint(&self, target: &str) -> String {
22        [self.opening.as_str(), target, self.closing.as_str()]
23            .iter()
24            .copied()
25            .collect()
26    }
27    fn paint_many<'a, T, U, V>(groups: T) -> String
28    where
29        T: IntoIterator<Item = (U, V)> + 'a,
30        U: Borrow<Self> + 'a,
31        V: Borrow<str> + 'a,
32    {
33        let mut result = String::new();
34        let mut previous_span = String::new();
35        let mut previous_tag: Option<Self> = None;
36        for (painter, s) in groups {
37            match previous_tag {
38                Some(ref p) if painter.borrow() != p => {
39                    result += &p.paint(&previous_span);
40                    previous_span = String::from(s.borrow());
41                    previous_tag = Some(painter.borrow().clone());
42                }
43                Some(ref _p) => {
44                    previous_span.push_str(s.borrow());
45                }
46                None => {
47                    previous_span.push_str(s.borrow());
48                    previous_tag = Some(painter.borrow().clone());
49                }
50            }
51        }
52        if let Some(p) = previous_tag {
53            if !previous_span.is_empty() {
54                result += &p.paint(&previous_span);
55            }
56        }
57        result
58    }
59}
60
61#[cfg(test)]
62mod test {
63    use super::*;
64    #[test]
65    fn tag_text() {
66        let fmt_1 = Tag::new("<1>", "</1>");
67        let fmt_2 = Tag::new("<2>", "</2>");
68        let texts = vec![(&fmt_1, "foo"), (&fmt_2, "bar"), (&fmt_2, "baz")];
69        assert_eq!(
70            Tag::paint_many(texts),
71            String::from("<1>foo</1><2>barbaz</2>")
72        );
73    }
74    #[test]
75    fn tag_empty() {
76        let texts: Vec<(&Tag, &str)> = vec![];
77        assert_eq!(Tag::paint_many(texts), String::new());
78    }
79}