]>
Commit | Line | Data |
---|---|---|
6522a427 | 1 | use once_cell::sync::Lazy; |
416331ca XL |
2 | use regex::Regex; |
3 | use std::ops::Bound::{Excluded, Included, Unbounded}; | |
4 | use std::ops::RangeBounds; | |
2c00a5a8 | 5 | |
416331ca XL |
6 | /// Take a range of lines from a string. |
7 | pub fn take_lines<R: RangeBounds<usize>>(s: &str, range: R) -> String { | |
8 | let start = match range.start_bound() { | |
9 | Excluded(&n) => n + 1, | |
10 | Included(&n) => n, | |
11 | Unbounded => 0, | |
12 | }; | |
f035d41b | 13 | let lines = s.lines().skip(start); |
416331ca | 14 | match range.end_bound() { |
f035d41b XL |
15 | Excluded(end) => lines |
16 | .take(end.saturating_sub(start)) | |
17 | .collect::<Vec<_>>() | |
18 | .join("\n"), | |
19 | Included(end) => lines | |
20 | .take((end + 1).saturating_sub(start)) | |
21 | .collect::<Vec<_>>() | |
22 | .join("\n"), | |
23 | Unbounded => lines.collect::<Vec<_>>().join("\n"), | |
2c00a5a8 XL |
24 | } |
25 | } | |
26 | ||
6522a427 EL |
27 | static ANCHOR_START: Lazy<Regex> = |
28 | Lazy::new(|| Regex::new(r"ANCHOR:\s*(?P<anchor_name>[\w_-]+)").unwrap()); | |
29 | static ANCHOR_END: Lazy<Regex> = | |
30 | Lazy::new(|| Regex::new(r"ANCHOR_END:\s*(?P<anchor_name>[\w_-]+)").unwrap()); | |
e74abb32 | 31 | |
416331ca XL |
32 | /// Take anchored lines from a string. |
33 | /// Lines containing anchor are ignored. | |
34 | pub fn take_anchored_lines(s: &str, anchor: &str) -> String { | |
416331ca XL |
35 | let mut retained = Vec::<&str>::new(); |
36 | let mut anchor_found = false; | |
2c00a5a8 | 37 | |
416331ca XL |
38 | for l in s.lines() { |
39 | if anchor_found { | |
e74abb32 | 40 | match ANCHOR_END.captures(l) { |
416331ca XL |
41 | Some(cap) => { |
42 | if &cap["anchor_name"] == anchor { | |
43 | break; | |
44 | } | |
45 | } | |
46 | None => { | |
e74abb32 | 47 | if !ANCHOR_START.is_match(l) { |
416331ca XL |
48 | retained.push(l); |
49 | } | |
50 | } | |
51 | } | |
f035d41b XL |
52 | } else if let Some(cap) = ANCHOR_START.captures(l) { |
53 | if &cap["anchor_name"] == anchor { | |
54 | anchor_found = true; | |
416331ca XL |
55 | } |
56 | } | |
2c00a5a8 | 57 | } |
2c00a5a8 | 58 | |
416331ca | 59 | retained.join("\n") |
2c00a5a8 XL |
60 | } |
61 | ||
e74abb32 XL |
62 | /// Keep lines contained within the range specified as-is. |
63 | /// For any lines not in the range, include them but use `#` at the beginning. This will hide the | |
64 | /// lines from initial display but include them when expanding the code snippet or testing with | |
65 | /// rustdoc. | |
66 | pub fn take_rustdoc_include_lines<R: RangeBounds<usize>>(s: &str, range: R) -> String { | |
67 | let mut output = String::with_capacity(s.len()); | |
68 | ||
69 | for (index, line) in s.lines().enumerate() { | |
70 | if !range.contains(&index) { | |
71 | output.push_str("# "); | |
72 | } | |
73 | output.push_str(line); | |
5869c6ff | 74 | output.push('\n'); |
e74abb32 XL |
75 | } |
76 | output.pop(); | |
77 | output | |
78 | } | |
79 | ||
80 | /// Keep lines between the anchor comments specified as-is. | |
81 | /// For any lines not between the anchors, include them but use `#` at the beginning. This will | |
82 | /// hide the lines from initial display but include them when expanding the code snippet or testing | |
83 | /// with rustdoc. | |
84 | pub fn take_rustdoc_include_anchored_lines(s: &str, anchor: &str) -> String { | |
85 | let mut output = String::with_capacity(s.len()); | |
86 | let mut within_anchored_section = false; | |
87 | ||
88 | for l in s.lines() { | |
89 | if within_anchored_section { | |
90 | match ANCHOR_END.captures(l) { | |
91 | Some(cap) => { | |
92 | if &cap["anchor_name"] == anchor { | |
93 | within_anchored_section = false; | |
94 | } | |
95 | } | |
96 | None => { | |
97 | if !ANCHOR_START.is_match(l) { | |
98 | output.push_str(l); | |
5869c6ff | 99 | output.push('\n'); |
e74abb32 XL |
100 | } |
101 | } | |
102 | } | |
f035d41b XL |
103 | } else if let Some(cap) = ANCHOR_START.captures(l) { |
104 | if &cap["anchor_name"] == anchor { | |
105 | within_anchored_section = true; | |
e74abb32 | 106 | } |
f035d41b XL |
107 | } else if !ANCHOR_END.is_match(l) { |
108 | output.push_str("# "); | |
109 | output.push_str(l); | |
5869c6ff | 110 | output.push('\n'); |
e74abb32 XL |
111 | } |
112 | } | |
113 | ||
114 | output.pop(); | |
115 | output | |
116 | } | |
117 | ||
2c00a5a8 XL |
118 | #[cfg(test)] |
119 | mod tests { | |
e74abb32 XL |
120 | use super::{ |
121 | take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines, | |
122 | take_rustdoc_include_lines, | |
123 | }; | |
2c00a5a8 XL |
124 | |
125 | #[test] | |
064997fb | 126 | #[allow(clippy::reversed_empty_ranges)] // Intentionally checking that those are correctly handled |
2c00a5a8 XL |
127 | fn take_lines_test() { |
128 | let s = "Lorem\nipsum\ndolor\nsit\namet"; | |
129 | assert_eq!(take_lines(s, 1..3), "ipsum\ndolor"); | |
130 | assert_eq!(take_lines(s, 3..), "sit\namet"); | |
131 | assert_eq!(take_lines(s, ..3), "Lorem\nipsum\ndolor"); | |
132 | assert_eq!(take_lines(s, ..), s); | |
133 | // corner cases | |
134 | assert_eq!(take_lines(s, 4..3), ""); | |
135 | assert_eq!(take_lines(s, ..100), s); | |
136 | } | |
416331ca XL |
137 | |
138 | #[test] | |
139 | fn take_anchored_lines_test() { | |
140 | let s = "Lorem\nipsum\ndolor\nsit\namet"; | |
141 | assert_eq!(take_anchored_lines(s, "test"), ""); | |
142 | ||
143 | let s = "Lorem\nipsum\ndolor\nANCHOR_END: test\nsit\namet"; | |
144 | assert_eq!(take_anchored_lines(s, "test"), ""); | |
145 | ||
146 | let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet"; | |
147 | assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet"); | |
148 | assert_eq!(take_anchored_lines(s, "something"), ""); | |
149 | ||
150 | let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum"; | |
151 | assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet"); | |
152 | assert_eq!(take_anchored_lines(s, "something"), ""); | |
153 | ||
154 | let s = "Lorem\nANCHOR: test\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum"; | |
155 | assert_eq!(take_anchored_lines(s, "test"), "ipsum\ndolor\nsit\namet"); | |
156 | assert_eq!(take_anchored_lines(s, "something"), ""); | |
157 | ||
158 | let s = "Lorem\nANCHOR: test2\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nANCHOR_END:test2\nipsum"; | |
159 | assert_eq!( | |
160 | take_anchored_lines(s, "test2"), | |
161 | "ipsum\ndolor\nsit\namet\nlorem" | |
162 | ); | |
163 | assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet"); | |
164 | assert_eq!(take_anchored_lines(s, "something"), ""); | |
165 | } | |
e74abb32 XL |
166 | |
167 | #[test] | |
064997fb | 168 | #[allow(clippy::reversed_empty_ranges)] // Intentionally checking that those are correctly handled |
e74abb32 XL |
169 | fn take_rustdoc_include_lines_test() { |
170 | let s = "Lorem\nipsum\ndolor\nsit\namet"; | |
171 | assert_eq!( | |
172 | take_rustdoc_include_lines(s, 1..3), | |
173 | "# Lorem\nipsum\ndolor\n# sit\n# amet" | |
174 | ); | |
175 | assert_eq!( | |
176 | take_rustdoc_include_lines(s, 3..), | |
177 | "# Lorem\n# ipsum\n# dolor\nsit\namet" | |
178 | ); | |
179 | assert_eq!( | |
180 | take_rustdoc_include_lines(s, ..3), | |
181 | "Lorem\nipsum\ndolor\n# sit\n# amet" | |
182 | ); | |
183 | assert_eq!(take_rustdoc_include_lines(s, ..), s); | |
184 | // corner cases | |
185 | assert_eq!( | |
186 | take_rustdoc_include_lines(s, 4..3), | |
187 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet" | |
188 | ); | |
189 | assert_eq!(take_rustdoc_include_lines(s, ..100), s); | |
190 | } | |
191 | ||
192 | #[test] | |
193 | fn take_rustdoc_include_anchored_lines_test() { | |
194 | let s = "Lorem\nipsum\ndolor\nsit\namet"; | |
195 | assert_eq!( | |
196 | take_rustdoc_include_anchored_lines(s, "test"), | |
197 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet" | |
198 | ); | |
199 | ||
200 | let s = "Lorem\nipsum\ndolor\nANCHOR_END: test\nsit\namet"; | |
201 | assert_eq!( | |
202 | take_rustdoc_include_anchored_lines(s, "test"), | |
203 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet" | |
204 | ); | |
205 | ||
206 | let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet"; | |
207 | assert_eq!( | |
208 | take_rustdoc_include_anchored_lines(s, "test"), | |
209 | "# Lorem\n# ipsum\ndolor\nsit\namet" | |
210 | ); | |
211 | assert_eq!( | |
212 | take_rustdoc_include_anchored_lines(s, "something"), | |
213 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet" | |
214 | ); | |
215 | ||
216 | let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum"; | |
217 | assert_eq!( | |
218 | take_rustdoc_include_anchored_lines(s, "test"), | |
219 | "# Lorem\n# ipsum\ndolor\nsit\namet\n# lorem\n# ipsum" | |
220 | ); | |
221 | assert_eq!( | |
222 | take_rustdoc_include_anchored_lines(s, "something"), | |
223 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet\n# lorem\n# ipsum" | |
224 | ); | |
225 | ||
226 | let s = "Lorem\nANCHOR: test\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum"; | |
227 | assert_eq!( | |
228 | take_rustdoc_include_anchored_lines(s, "test"), | |
229 | "# Lorem\nipsum\ndolor\nsit\namet\n# lorem\n# ipsum" | |
230 | ); | |
231 | assert_eq!( | |
232 | take_rustdoc_include_anchored_lines(s, "something"), | |
233 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet\n# lorem\n# ipsum" | |
234 | ); | |
235 | ||
236 | let s = "Lorem\nANCHOR: test2\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nANCHOR_END:test2\nipsum"; | |
237 | assert_eq!( | |
238 | take_rustdoc_include_anchored_lines(s, "test2"), | |
239 | "# Lorem\nipsum\ndolor\nsit\namet\nlorem\n# ipsum" | |
240 | ); | |
241 | assert_eq!( | |
242 | take_rustdoc_include_anchored_lines(s, "test"), | |
243 | "# Lorem\n# ipsum\ndolor\nsit\namet\n# lorem\n# ipsum" | |
244 | ); | |
245 | assert_eq!( | |
246 | take_rustdoc_include_anchored_lines(s, "something"), | |
247 | "# Lorem\n# ipsum\n# dolor\n# sit\n# amet\n# lorem\n# ipsum" | |
248 | ); | |
249 | ||
250 | let s = "Lorem\nANCHOR: test\nipsum\nANCHOR_END: test\ndolor\nANCHOR: test\nsit\nANCHOR_END: test\namet"; | |
251 | assert_eq!( | |
252 | take_rustdoc_include_anchored_lines(s, "test"), | |
253 | "# Lorem\nipsum\n# dolor\nsit\n# amet" | |
254 | ); | |
255 | } | |
2c00a5a8 | 256 | } |