@@ -584,55 +584,79 @@ impl<'sess> State<'sess, '_> {
584584 return ;
585585 }
586586
587- let post_break_prefix = |prefix : & ' static str , line_len : usize | -> & ' static str {
587+ fn post_break_prefix ( prefix : & ' static str , has_content : bool ) -> & ' static str {
588+ if !has_content {
589+ return prefix;
590+ }
588591 match prefix {
589- "///" if line_len > 3 => "/// " ,
590- "//" if line_len > 2 => "// " ,
591- "/*" if line_len > 2 => "/* " ,
592- " *" if line_len > 2 => " * " ,
592+ "///" => "/// " ,
593+ "//" => "// " ,
594+ "/*" => "/* " ,
595+ " *" => " * " ,
593596 _ => prefix,
594597 }
595- } ;
598+ }
596599
597600 self . ibox ( 0 ) ;
598- let ( prefix, content) = if is_doc {
599- // Doc comments preserve leading whitespaces (right after the prefix).
600- self . word ( prefix) ;
601- let content = & line[ prefix. len ( ) ..] ;
602- let ( leading_ws, rest) =
603- content. split_at ( content. chars ( ) . take_while ( |& c| c. is_whitespace ( ) ) . count ( ) ) ;
601+ self . word ( prefix) ;
602+
603+ let content = & line[ prefix. len ( ) ..] ;
604+ let content = if is_doc {
605+ // Doc comments: emit ALL leading whitespace as breaking spaces to preserve formatting
606+ let ws_len = content. chars ( ) . take_while ( |& c| c. is_whitespace ( ) ) . count ( ) ;
607+ let ( leading_ws, rest) = content. split_at ( ws_len) ;
604608 if !leading_ws. is_empty ( ) {
605609 self . word ( leading_ws. to_owned ( ) ) ;
606610 }
607- let prefix = post_break_prefix ( prefix, rest. len ( ) ) ;
608- ( prefix, rest)
609- } else if line. starts_with ( "/*" ) && !line. starts_with ( "/* " ) {
610- self . word ( prefix) ;
611- ( prefix, line[ 2 ..] . trim_end ( ) )
611+ rest
612612 } else {
613- let content = line[ prefix. len ( ) ..] . trim ( ) ;
614- let prefix = post_break_prefix ( prefix, content. len ( ) ) ;
615- self . word ( prefix) ;
616- ( prefix, content)
617- } ;
618-
619- // Split the rest of the content into words.
620- let mut words = content. split_whitespace ( ) . peekable ( ) ;
621- while let Some ( word) = words. next ( ) {
622- self . word ( word. to_owned ( ) ) ;
623- if let Some ( next_word) = words. peek ( ) {
624- if * next_word == "*/" {
613+ // Non-doc comments: replace first whitespace with nbsp, rest of content continues
614+ if let Some ( first_char) = content. chars ( ) . next ( ) {
615+ if first_char. is_whitespace ( ) {
625616 self . nbsp ( ) ;
617+ & content[ first_char. len_utf8 ( ) ..]
626618 } else {
627- self . s . scan_break ( BreakToken {
628- offset : break_offset,
629- blank_space : 1 ,
630- post_break : if matches ! ( prefix, "/* " ) { None } else { Some ( prefix) } ,
631- ..Default :: default ( )
632- } ) ;
619+ content
633620 }
621+ } else {
622+ ""
634623 }
624+ } ;
625+
626+ let post_break = post_break_prefix ( prefix, !content. is_empty ( ) ) ;
627+
628+ // Process content character by character to preserve consecutive whitespaces
629+ let ( mut chars, mut current_word) = ( content. chars ( ) . peekable ( ) , String :: new ( ) ) ;
630+ while let Some ( ch) = chars. next ( ) {
631+ if ch. is_whitespace ( ) {
632+ // Print current word
633+ if !current_word. is_empty ( ) {
634+ self . word ( std:: mem:: take ( & mut current_word) ) ;
635+ }
636+
637+ // Preserve multiple spaces while adding a single break
638+ let mut ws_count = 1 ;
639+ while chars. peek ( ) . is_some_and ( |c| c. is_whitespace ( ) ) {
640+ ws_count += 1 ;
641+ chars. next ( ) ;
642+ }
643+ self . s . scan_break ( BreakToken {
644+ offset : break_offset,
645+ blank_space : ws_count,
646+ post_break : if post_break. starts_with ( "/*" ) { None } else { Some ( post_break) } ,
647+ ..Default :: default ( )
648+ } ) ;
649+ continue ;
650+ }
651+
652+ current_word. push ( ch) ;
653+ }
654+
655+ // Print final word
656+ if !current_word. is_empty ( ) {
657+ self . word ( current_word) ;
635658 }
659+
636660 self . end ( ) ;
637661 }
638662
0 commit comments