Parses the `lang.md` file and extracts a mapping of language reference topics to their descriptions. Note that, even if the input looks like Markdown, we do *not* implement a Markdown parser here. The structure of the file is strict and well-known in advance, so this will panic if there are problems in the input data.
(lang_md: &'static str)
| 269 | /// The structure of the file is strict and well-known in advance, so this will panic if there are |
| 270 | /// problems in the input data. |
| 271 | fn parse_lang_reference(lang_md: &'static str) -> Vec<(&'static str, &'static str)> { |
| 272 | let mut topics = vec![]; |
| 273 | |
| 274 | // Cope with Windows checkouts. It's tempting to make this a build-time conditional on the OS |
| 275 | // name, but we don't know how the files are checked out. Assume CRLF delimiters if we see at |
| 276 | // least one of them. |
| 277 | let line_end; |
| 278 | let section_start; |
| 279 | let body_start; |
| 280 | if lang_md.contains("\r\n") { |
| 281 | line_end = "\r\n"; |
| 282 | section_start = "\r\n\r\n# "; |
| 283 | body_start = "\r\n\r\n"; |
| 284 | } else { |
| 285 | line_end = "\n"; |
| 286 | section_start = "\n\n# "; |
| 287 | body_start = "\n\n"; |
| 288 | } |
| 289 | |
| 290 | for (start, _match) in lang_md.match_indices(section_start) { |
| 291 | let section = &lang_md[start + section_start.len()..]; |
| 292 | |
| 293 | let title_end = section.find(body_start).expect("Hardcoded text must be valid"); |
| 294 | let title = §ion[..title_end]; |
| 295 | let section = §ion[title_end + body_start.len()..]; |
| 296 | |
| 297 | let end = section.find(section_start).unwrap_or_else(|| { |
| 298 | if section.ends_with(line_end) { section.len() - line_end.len() } else { section.len() } |
| 299 | }); |
| 300 | let content = §ion[..end]; |
| 301 | topics.push((title, content)); |
| 302 | } |
| 303 | |
| 304 | topics |
| 305 | } |
| 306 | |
| 307 | /// Maintains the collection of topics as a trie indexed by their name. |
| 308 | struct Topics(Trie<String, Box<dyn Topic>>); |