parser_test/
highlighter.rs1use std::str::{CharIndices};
2use std::iter::Peekable;
3
4pub struct Highlighter<'a> {
16 spans: Peekable<CharIndices<'a>>,
17}
18impl<'a> Highlighter<'a> {
19 pub fn new(spans: &'a str) -> Highlighter<'a> {
20 Self {
21 spans: spans.char_indices().peekable(),
22 }
23 }
24}
25
26impl<'a> Iterator for Highlighter<'a> {
27 type Item = (usize, usize);
28
29 fn next(&mut self) -> Option<Self::Item> {
30 match self.spans.next() {
31 Some((mut start, mut c)) => {
32 while c.is_whitespace() || c == 'I' {
33 start += 1;
34 c = match self.spans.next() {
35 Some((_, c)) => c,
36 None => return None,
37 };
38 }
39
40 match c {
41 '^' => {
42 while let Some((pos, c)) = self.spans.next() {
43 match c {
44 '-' => {
45 continue;
46 }
47 '^' => {
48 return Some((start, pos));
49 }
50 _ => panic!("Unexpected symbol in ^ span: {} at: {}", c, pos)
51 }
52 }
53 panic!("Unterminated ^ span at {}", start);
54
55 }
56 '|' => {
57 return Some((start, start));
58
59 }
60 _ => {
61 panic!("Unexpected character: {}, ^, | or whitespace is allowed", c);
62 }
63 }
64 }
65 None => None
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::Highlighter;
73
74 #[test]
75 fn single_span() {
76 let mut hl = Highlighter::new("|");
77 assert_eq!(hl.next(), Some((0, 0)));
78 assert_eq!(hl.next(), None);
79 }
80
81 #[test]
82 fn many_single_spans() {
83 let mut hl = Highlighter::new("|||");
84 assert_eq!(hl.next(), Some((0, 0)));
85 assert_eq!(hl.next(), Some((1, 1)));
86 assert_eq!(hl.next(), Some((2, 2)));
87 assert_eq!(hl.next(), None);
88 }
89
90 #[test]
91 fn single_span_after_whitespace() {
92 let mut hl = Highlighter::new(" |");
93 assert_eq!(hl.next(), Some((3, 3)));
94 assert_eq!(hl.next(), None);
95 }
96
97 #[test]
98 fn span_after_whitespace() {
99 let mut hl = Highlighter::new(" ^---^ ");
100 assert_eq!(hl.next(), Some((1, 5)));
101 assert_eq!(hl.next(), None);
102 }
103
104 #[test]
105 fn two_single_bars() {
106 let mut hl = Highlighter::new("| |");
107 assert_eq!(hl.next(), Some((0, 0)));
108 assert_eq!(hl.next(), Some((2, 2)));
109 assert_eq!(hl.next(), None);
110 }
111
112 #[test]
113 fn double_caret_single_bar() {
114 let mut hl = Highlighter::new("^^|");
115 assert_eq!(hl.next(), Some((0, 1)));
116 assert_eq!(hl.next(), Some((2, 2)));
117 assert_eq!(hl.next(), None);
118 }
119
120 #[test]
121 fn two_double_carets() {
122 let mut hl = Highlighter::new("^^^^");
123 assert_eq!(hl.next(), Some((0, 1)));
124 assert_eq!(hl.next(), Some((2, 3)));
125 assert_eq!(hl.next(), None);
126 }
127
128 #[test]
129 fn long_span_single_span() {
130 let mut hl = Highlighter::new("^--^|");
131 assert_eq!(hl.next(), Some((0, 3)));
132 assert_eq!(hl.next(), Some((4, 4)));
133 assert_eq!(hl.next(), None);
134 }
135
136 #[test]
137 fn long_span_double_caret() {
138 let mut hl = Highlighter::new("^--^^^");
139 assert_eq!(hl.next(), Some((0, 3)));
140 assert_eq!(hl.next(), Some((4, 5)));
141 assert_eq!(hl.next(), None);
142 }
143
144 #[test]
145 fn many_spans() {
146 let mut hl = Highlighter::new("^-^ ^^ ^--^ | ^----^ ");
147 assert_eq!(hl.next(), Some((0, 2)));
148 assert_eq!(hl.next(), Some((4, 5)));
149 assert_eq!(hl.next(), Some((7, 10)));
150 assert_eq!(hl.next(), Some((12, 12)));
151 assert_eq!(hl.next(), Some((14, 19)));
152 assert_eq!(hl.next(), None);
153 }
154
155 #[test]
156 fn alternate_space() {
157 let mut hl = Highlighter::new("II^^^^");
158 assert_eq!(hl.next(), Some((2, 3)));
159 assert_eq!(hl.next(), Some((4, 5)));
160 assert_eq!(hl.next(), None);
161 }
162
163
164 #[test]
165 fn unterminated_span() {
166 let mut hl = Highlighter::new("^--");
167 let r = std::panic::catch_unwind(move || hl.next());
168 assert!(r.is_err());
169 }
170
171 #[test]
172 fn unterminated_span2() {
173 let mut hl = Highlighter::new("^-- ");
174 let r = std::panic::catch_unwind(move || hl.next());
175 assert!(r.is_err());
176 }
177
178 #[test]
179 fn unterminated_span3() {
180 let mut hl = Highlighter::new("^^^");
181 let _ = hl.next();
182 let r = std::panic::catch_unwind(move || hl.next());
183 assert!(r.is_err());
184 }
185
186 #[test]
187 fn unterminated_span4() {
188 let mut hl = Highlighter::new("^");
189 let r = std::panic::catch_unwind(move || hl.next());
190 assert!(r.is_err());
191 }
192
193 #[test]
194 fn space_after_caret() {
195 let mut hl = Highlighter::new("^ ");
196 let r = std::panic::catch_unwind(move || hl.next());
197 assert!(r.is_err());
198 }
199
200 #[test]
201 fn bar_after_caret() {
202 let mut hl = Highlighter::new("^|");
203 let r = std::panic::catch_unwind(move || hl.next());
204 assert!(r.is_err());
205 }
206}