1use tty_interface::Style;
2
3pub type Segment = Vec<Text>;
5
6pub type DrawerContents = Vec<Segment>;
9
10#[derive(Debug, Clone, Eq, PartialEq)]
12pub struct Text(String, Option<Style>);
13
14impl Text {
15 pub fn new(content: String) -> Self {
17 Self(content, None)
18 }
19
20 pub fn new_styled(content: String, style: Style) -> Self {
22 Self(content, Some(style))
23 }
24
25 pub fn content(&self) -> &str {
27 &self.0
28 }
29
30 pub fn style(&self) -> Option<&Style> {
32 self.1.as_ref()
33 }
34
35 pub fn as_segment(self) -> Segment {
37 vec![self]
38 }
39}
40
41pub(crate) fn set_segment_style(segment: &mut Segment, style: Style) {
42 let segment_length = get_segment_length(segment);
43 set_segment_subset_style(segment, 0, segment_length, style);
44}
45
46pub(crate) fn set_segment_subset_style(
48 segment: &mut Segment,
49 start: usize,
50 end: usize,
51 style: Style,
52) {
53 let mut index = 0;
54 let mut i = 0;
55 loop {
56 if i == segment.len() {
57 break;
58 }
59
60 let text = &segment[i];
61
62 let start_intersects = start > index && start < index + text.content().len();
63 let end_intersects = end > index && end < index + text.content().len();
64
65 if start_intersects {
66 let (first, second) = split_text(text, start - index);
67
68 segment[i] = first;
69 segment.insert(i + 1, second);
70 } else if end_intersects {
71 let (first, second) = split_text(text, end - index);
72
73 segment[i] = first;
74 segment.insert(i + 1, second);
75 }
76
77 index += segment[i].content().len();
78 i += 1;
79 }
80
81 index = 0;
82 for text in segment {
83 if index >= start && index < end {
84 text.1 = Some(style);
85 }
86
87 index += text.content().len();
88 }
89}
90
91pub(crate) fn get_segment_length(segment: &Segment) -> usize {
92 segment.iter().map(|text| text.content().len()).sum()
93}
94
95fn split_text(text: &Text, index: usize) -> (Text, Text) {
96 let (prefix, suffix) = text.0.split_at(index);
97
98 let first = Text(prefix.to_string(), text.1);
99 let second = Text(suffix.to_string(), text.1);
100
101 (first, second)
102}
103
104#[cfg(test)]
105mod tests {
106 use tty_interface::Color;
107
108 use crate::text::Text;
109
110 use super::set_segment_subset_style;
111
112 macro_rules! text {
113 ($content: expr) => {
114 Text::new($content.to_string())
115 };
116 }
117
118 macro_rules! text_styled {
119 ($content: expr, $color: expr) => {
120 Text::new_styled($content.to_string(), $color.as_style())
121 };
122 }
123
124 #[test]
125 fn test_set_segment_style_entirely() {
126 let mut segment = vec![
127 text!("TEST1"),
128 text_styled!("TEST2", Color::Red),
129 text_styled!("TEST3", Color::Blue),
130 text!("TEST4"),
131 ];
132
133 set_segment_subset_style(&mut segment, 0, 20, Color::Green.as_style());
134
135 assert_eq!(
136 vec![
137 text_styled!("TEST1", Color::Green),
138 text_styled!("TEST2", Color::Green),
139 text_styled!("TEST3", Color::Green),
140 text_styled!("TEST4", Color::Green),
141 ],
142 segment
143 );
144 }
145
146 #[test]
147 fn test_set_segment_style_neatly() {
148 let mut segment = vec![
149 text!("TEST1"),
150 text_styled!("TEST2", Color::Red),
151 text_styled!("TEST3", Color::Blue),
152 text!("TEST4"),
153 ];
154
155 set_segment_subset_style(&mut segment, 5, 15, Color::Green.as_style());
156
157 assert_eq!(
158 vec![
159 text!("TEST1"),
160 text_styled!("TEST2", Color::Green),
161 text_styled!("TEST3", Color::Green),
162 text!("TEST4"),
163 ],
164 segment
165 );
166 }
167
168 #[test]
169 fn test_set_segment_style_split() {
170 let mut segment = vec![
171 text!("TEST1"),
172 text_styled!("TEST2", Color::Red),
173 text_styled!("TEST3", Color::Blue),
174 text!("TEST4"),
175 ];
176
177 set_segment_subset_style(&mut segment, 3, 7, Color::Green.as_style());
178 set_segment_subset_style(&mut segment, 11, 14, Color::Magenta.as_style());
179
180 assert_eq!(
181 vec![
182 text!("TES"),
183 text_styled!("T1", Color::Green),
184 text_styled!("TE", Color::Green),
185 text_styled!("ST2", Color::Red),
186 text_styled!("T", Color::Blue),
187 text_styled!("EST", Color::Magenta),
188 text_styled!("3", Color::Blue),
189 text!("TEST4"),
190 ],
191 segment
192 );
193 }
194}