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