Parse `#id key=value key2="quoted value"` into (id, attrs).
(src: &str)
| 311 | |
| 312 | /// Parse `#id key=value key2="quoted value"` into (id, attrs). |
| 313 | fn parse_attrs(src: &str) -> Result<(Option<String>, BTreeMap<String, String>)> { |
| 314 | let mut id = None; |
| 315 | let mut attrs = BTreeMap::new(); |
| 316 | for token in tokenize(src) { |
| 317 | if let Some(rest) = token.strip_prefix('#') { |
| 318 | id = Some(rest.to_string()); |
| 319 | } else if let Some(eq) = token.find('=') { |
| 320 | let key = token[..eq].trim().to_string(); |
| 321 | let mut val = token[eq + 1..].trim().to_string(); |
| 322 | if val.len() >= 2 && val.starts_with('"') && val.ends_with('"') { |
| 323 | val = val[1..val.len() - 1].to_string(); |
| 324 | } |
| 325 | attrs.insert(key, val); |
| 326 | } |
| 327 | // bare tokens with neither # nor = are ignored |
| 328 | } |
| 329 | Ok((id, attrs)) |
| 330 | } |
| 331 | |
| 332 | /// Whitespace tokenizer that keeps double-quoted values intact. |
| 333 | fn tokenize(src: &str) -> Vec<String> { |
no test coverage detected