styled_str/types/
lines.rs1use crate::StyledStr;
4
5#[derive(Debug)]
7pub struct Lines<'a> {
8 remainder: StyledStr<'a>,
9}
10
11impl<'a> Lines<'a> {
12 pub(super) fn new(str: StyledStr<'a>) -> Self {
13 Self { remainder: str }
14 }
15}
16
17impl<'a> Iterator for Lines<'a> {
18 type Item = StyledStr<'a>;
19
20 fn next(&mut self) -> Option<Self::Item> {
21 if self.remainder.is_empty() {
22 return None;
23 }
24
25 let text = self.remainder.text();
27 let next_pos = text.find('\n').map_or(text.len(), |pos| pos + 1);
28 let (mut line, remainder) = self.remainder.split_at(next_pos);
29 self.remainder = remainder;
30
31 if line.text.ends_with('\n') {
33 line.pop();
34 }
35 if line.text.ends_with('\r') {
36 line.pop();
37 }
38 Some(line)
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use crate::styled;
45
46 #[test]
47 fn lines_basics() {
48 let str = styled!("[[red on white]]Test");
49 let lines: Vec<_> = str.lines().collect();
50 assert_eq!(lines, [str]);
51
52 let str_with_nl = styled!("[[red on white]]Test\n");
53 let lines: Vec<_> = str_with_nl.lines().collect();
54 assert_eq!(lines, [str]);
55
56 let str_with_nl = styled!("[[red on white]]Test\r\n");
57 let lines: Vec<_> = str_with_nl.lines().collect();
58 assert_eq!(lines, [str]);
59 }
60
61 #[test]
62 fn lines_with_multiline_text() {
63 let str = styled!("[[red on white]]Test\nHello, [[bold green]]world[[* -bold]]!");
64 let expected_lines = [
65 styled!("[[red on white]]Test"),
66 styled!("[[red on white]]Hello, [[bold green]]world[[green]]!"),
67 ];
68
69 let lines: Vec<_> = str.lines().collect();
70 assert_eq!(lines, expected_lines);
71 }
72
73 #[test]
74 fn styles_bordering_on_newlines() {
75 let str = styled!("[[red on white]]Test\n[[/]]Hello,[[bold green]]\nworld[[* -bold]]!\n");
76 let expected_lines = [
77 styled!("[[red on white]]Test"),
78 styled!("Hello,"),
79 styled!("[[bold green]]world[[green]]!"),
80 ];
81
82 let lines: Vec<_> = str.lines().collect();
83 assert_eq!(lines, expected_lines);
84 }
85}