@@ -169,6 +169,17 @@ struct TokenHandler<'a, 'tcx, F: Write> {
169169 write_line_number : fn ( & mut F , u32 , & ' static str ) ,
170170}
171171
172+ impl < F : Write > std:: fmt:: Debug for TokenHandler < ' _ , ' _ , F > {
173+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
174+ f. debug_struct ( "TokenHandler" )
175+ . field ( "closing_tags" , & self . closing_tags )
176+ . field ( "pending_exit_span" , & self . pending_exit_span )
177+ . field ( "current_class" , & self . current_class )
178+ . field ( "pending_elems" , & self . pending_elems )
179+ . finish ( )
180+ }
181+ }
182+
172183impl < F : Write > TokenHandler < ' _ , ' _ , F > {
173184 fn handle_exit_span ( & mut self ) {
174185 // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
@@ -221,6 +232,12 @@ impl<F: Write> TokenHandler<'_, '_, F> {
221232 } else {
222233 None
223234 } ;
235+ let mut last_pending = None ;
236+ // To prevent opening a macro expansion span being closed right away because
237+ // the currently open item is replaced by a new class.
238+ if let Some ( ( _, Some ( Class :: Expansion ) ) ) = self . pending_elems . last ( ) {
239+ last_pending = self . pending_elems . pop ( ) ;
240+ }
224241 for ( text, class) in self . pending_elems . iter ( ) {
225242 string (
226243 self . out ,
@@ -234,6 +251,16 @@ impl<F: Write> TokenHandler<'_, '_, F> {
234251 if let Some ( close_tag) = close_tag {
235252 exit_span ( self . out , close_tag) ;
236253 }
254+ if let Some ( ( text, class) ) = last_pending {
255+ string (
256+ self . out ,
257+ EscapeBodyText ( & text) ,
258+ class,
259+ & self . href_context ,
260+ close_tag. is_none ( ) ,
261+ self . write_line_number ,
262+ ) ;
263+ }
237264 }
238265 self . pending_elems . clear ( ) ;
239266 true
@@ -278,7 +305,7 @@ fn get_next_expansion<'a>(
278305 span : Span ,
279306) -> Option < & ' a ExpandedCode > {
280307 if let Some ( expanded_codes) = expanded_codes {
281- expanded_codes. iter ( ) . find ( |code| code. start_line == line && code. span . lo ( ) >= span. lo ( ) )
308+ expanded_codes. iter ( ) . find ( |code| code. start_line == line && code. span . lo ( ) > span. lo ( ) )
282309 } else {
283310 None
284311 }
@@ -328,7 +355,7 @@ fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option<Class>)>, expanded_code:
328355fn end_expansion < ' a , W : Write > (
329356 token_handler : & mut TokenHandler < ' _ , ' _ , W > ,
330357 expanded_codes : Option < & ' a Vec < ExpandedCode > > ,
331- level : usize ,
358+ expansion_start_tags : & [ ( & ' static str , Class ) ] ,
332359 line : u32 ,
333360 span : Span ,
334361) -> Option < & ' a ExpandedCode > {
@@ -337,15 +364,27 @@ fn end_expansion<'a, W: Write>(
337364 token_handler. pending_elems . push ( ( Cow :: Borrowed ( "</span>" ) , Some ( Class :: Expansion ) ) ) ;
338365 return Some ( expanded_code) ;
339366 }
340- if level == 0 {
367+ if expansion_start_tags. is_empty ( ) && token_handler. closing_tags . is_empty ( ) {
368+ // No need tag opened so we can just close expansion.
341369 token_handler. pending_elems . push ( ( Cow :: Borrowed ( "</span></span>" ) , Some ( Class :: Expansion ) ) ) ;
342370 return None ;
343371 }
372+
373+ // If tags were opened inside the expansion, we need to close them and re-open them outside
374+ // of the expansion span.
344375 let mut out = String :: new ( ) ;
345376 let mut end = String :: new ( ) ;
346- for ( tag, class) in
347- token_handler. closing_tags . iter ( ) . skip ( token_handler. closing_tags . len ( ) - level)
377+
378+ let mut closing_tags = token_handler. closing_tags . iter ( ) . peekable ( ) ;
379+ let mut start_closing_tags = expansion_start_tags. iter ( ) . peekable ( ) ;
380+
381+ while let ( Some ( tag) , Some ( start_tag) ) = ( closing_tags. peek ( ) , start_closing_tags. peek ( ) )
382+ && tag == start_tag
348383 {
384+ closing_tags. next ( ) ;
385+ start_closing_tags. next ( ) ;
386+ }
387+ for ( tag, class) in start_closing_tags. chain ( closing_tags) {
349388 out. push_str ( tag) ;
350389 end. push_str ( & format ! ( "<span class=\" {}\" >" , class. as_html( ) ) ) ;
351390 }
@@ -431,7 +470,7 @@ pub(super) fn write_code(
431470 } ;
432471 let mut current_expansion = get_expansion ( & mut token_handler, expanded_codes, line, file_span) ;
433472 token_handler. write_pending_elems ( None ) ;
434- let mut level = 0 ;
473+ let mut expansion_start_tags = Vec :: new ( ) ;
435474
436475 Classifier :: new (
437476 & src,
@@ -471,6 +510,12 @@ pub(super) fn write_code(
471510 if current_expansion. is_none ( ) {
472511 current_expansion =
473512 get_expansion ( & mut token_handler, expanded_codes, line, span) ;
513+ expansion_start_tags = token_handler. closing_tags . clone ( ) ;
514+ }
515+ if let Some ( ref current_expansion) = current_expansion
516+ && current_expansion. span . lo ( ) == span. hi ( )
517+ {
518+ start_expansion ( & mut token_handler. pending_elems , current_expansion) ;
474519 }
475520 } else {
476521 token_handler. pending_elems . push ( ( Cow :: Borrowed ( text) , class) ) ;
@@ -486,11 +531,13 @@ pub(super) fn write_code(
486531 }
487532 }
488533 if need_end {
489- current_expansion =
490- end_expansion ( & mut token_handler, expanded_codes, level, line, span) ;
491- if current_expansion. is_none ( ) {
492- level = 0 ;
493- }
534+ current_expansion = end_expansion (
535+ & mut token_handler,
536+ expanded_codes,
537+ & expansion_start_tags,
538+ line,
539+ span,
540+ ) ;
494541 }
495542 }
496543 }
@@ -511,9 +558,6 @@ pub(super) fn write_code(
511558 if should_add {
512559 let closing_tag =
513560 enter_span ( token_handler. out , class, & token_handler. href_context ) ;
514- if current_expansion. is_some ( ) {
515- level += 1 ;
516- }
517561 token_handler. closing_tags . push ( ( closing_tag, class) ) ;
518562 }
519563
@@ -522,9 +566,6 @@ pub(super) fn write_code(
522566 }
523567 Highlight :: ExitSpan => {
524568 token_handler. current_class = None ;
525- if current_expansion. is_some ( ) {
526- level -= 1 ;
527- }
528569 token_handler. pending_exit_span = Some (
529570 token_handler
530571 . closing_tags
0 commit comments