]> git.proxmox.com Git - rustc.git/blame - vendor/mdbook/src/utils/string.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / vendor / mdbook / src / utils / string.rs
CommitLineData
6522a427 1use once_cell::sync::Lazy;
416331ca
XL
2use regex::Regex;
3use std::ops::Bound::{Excluded, Included, Unbounded};
4use std::ops::RangeBounds;
2c00a5a8 5
416331ca
XL
6/// Take a range of lines from a string.
7pub 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
27static ANCHOR_START: Lazy<Regex> =
28 Lazy::new(|| Regex::new(r"ANCHOR:\s*(?P<anchor_name>[\w_-]+)").unwrap());
29static 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.
34pub 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.
66pub 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.
84pub 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)]
119mod 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}