Skip to main content

styled_str/types/
lines.rs

1//! `Lines` iterator.
2
3use crate::StyledStr;
4
5/// Iterator over lines in a [`StyledStr`]. Returned by [`StyledStr::lines()`].
6#[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        // Find the next '\n' occurrence in the text
26        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        // Pop the ending `\n` and `\r`, same as `lines()` iterator for `str` does.
32        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}