|
8 | 8 | use std::borrow::Cow;
|
9 | 9 | use std::collections::VecDeque;
|
10 | 10 | use std::fmt::{self, Display, Write};
|
11 |
| -use std::iter; |
| 11 | +use std::{cmp, iter}; |
12 | 12 |
|
13 | 13 | use rustc_data_structures::fx::FxIndexMap;
|
14 | 14 | use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
|
@@ -345,33 +345,39 @@ fn end_expansion<'a, W: Write>(
|
345 | 345 | token_handler.pending_elems.push((Cow::Borrowed("</span>"), Some(Class::Expansion)));
|
346 | 346 | return Some(expanded_code);
|
347 | 347 | }
|
| 348 | + |
| 349 | + const CLOSE_EXPANSION: &str = "</span></span>"; |
| 350 | + |
348 | 351 | if expansion_start_tags.is_empty() && token_handler.closing_tags.is_empty() {
|
349 | 352 | // No need tag opened so we can just close expansion.
|
350 |
| - token_handler.pending_elems.push((Cow::Borrowed("</span></span>"), Some(Class::Expansion))); |
| 353 | + token_handler.pending_elems.push((Cow::Borrowed(CLOSE_EXPANSION), Some(Class::Expansion))); |
351 | 354 | return None;
|
352 | 355 | }
|
353 | 356 |
|
354 |
| - // If tags were opened inside the expansion, we need to close them and re-open them outside |
355 |
| - // of the expansion span. |
356 |
| - let mut out = String::new(); |
357 |
| - let mut end = String::new(); |
| 357 | + let skip = iter::zip(token_handler.closing_tags.as_slice(), expansion_start_tags) |
| 358 | + .position(|(tag, start_tag)| tag != start_tag) |
| 359 | + .unwrap_or_else(|| cmp::min(token_handler.closing_tags.len(), expansion_start_tags.len())); |
358 | 360 |
|
359 |
| - let mut closing_tags = token_handler.closing_tags.iter().peekable(); |
360 |
| - let mut start_closing_tags = expansion_start_tags.iter().peekable(); |
| 361 | + let tags = iter::chain( |
| 362 | + expansion_start_tags.iter().skip(skip), |
| 363 | + token_handler.closing_tags.iter().skip(skip), |
| 364 | + ); |
361 | 365 |
|
362 |
| - while let (Some(tag), Some(start_tag)) = (closing_tags.peek(), start_closing_tags.peek()) |
363 |
| - && tag == start_tag |
364 |
| - { |
365 |
| - closing_tags.next(); |
366 |
| - start_closing_tags.next(); |
| 366 | + let len = tags |
| 367 | + .clone() |
| 368 | + .map(|(tag, class)| tag.len() + "<span class=\"\">".len() + class.as_html().len()) |
| 369 | + .sum::<usize>(); |
| 370 | + let mut elem = String::with_capacity(len + CLOSE_EXPANSION.len()); |
| 371 | + elem.push_str(CLOSE_EXPANSION); |
| 372 | + |
| 373 | + for (tag, _) in tags.clone() { |
| 374 | + elem.push_str(tag); |
367 | 375 | }
|
368 |
| - for (tag, class) in start_closing_tags.chain(closing_tags) { |
369 |
| - out.push_str(tag); |
370 |
| - end.push_str(&format!("<span class=\"{}\">", class.as_html())); |
| 376 | + for (_, class) in tags { |
| 377 | + write!(elem, "<span class=\"{}\">", class.as_html()).unwrap(); |
371 | 378 | }
|
372 |
| - token_handler |
373 |
| - .pending_elems |
374 |
| - .push((Cow::Owned(format!("</span></span>{out}{end}")), Some(Class::Expansion))); |
| 379 | + |
| 380 | + token_handler.pending_elems.push((Cow::Owned(elem), Some(Class::Expansion))); |
375 | 381 | None
|
376 | 382 | }
|
377 | 383 |
|
|
0 commit comments