| 440 | } else if b == b'\\' { |
| 441 | escaped = true; |
| 442 | } else if b == b'"' { |
| 443 | mode = DoctorLexMode::Code; |
| 444 | } |
| 445 | } |
| 446 | DoctorLexMode::RawString(hashes) => { |
| 447 | out.push(b); |
| 448 | if raw_string_end_at_for_doctor(bytes, i, hashes) { |
| 449 | for offset in 0..hashes { |
| 450 | if let Some(hash) = bytes.get(i + 1 + offset) { |
| 451 | out.push(*hash); |
| 452 | } |
| 453 | } |
| 454 | i += hashes + 1; |
| 455 | mode = DoctorLexMode::Code; |
| 456 | continue; |
| 457 | } |
| 458 | } |
| 459 | } |
| 460 | i += 1; |
| 461 | } |
| 462 | String::from_utf8(out).unwrap_or_else(|_| text.to_string()) |
| 463 | } |
| 464 | |
| 465 | struct TextRef { |
| 466 | raw: String, |
| 467 | line: usize, |
| 468 | } |
| 469 | |
| 470 | fn extract_virtual_refs(text: &str) -> Vec<TextRef> { |
| 471 | let text = strip_comments_for_doctor(text, true); |
| 472 | let text = text.as_str(); |
| 473 | let mut refs = Vec::new(); |
| 474 | for quote in ['"', '\''] { |
| 475 | let mut search_from = 0usize; |
| 476 | for part in text.split(quote).skip(1).step_by(2) { |
| 477 | if (part.starts_with("res://") || part.starts_with("dlc://")) |
| 478 | && let Some(rel) = text[search_from..].find(part) |
| 479 | { |
| 480 | let start = search_from + rel; |
| 481 | refs.push(TextRef { |
| 482 | raw: part.to_string(), |
| 483 | line: line_number_at(text, start), |
| 484 | }); |
| 485 | search_from = start + part.len(); |