@@ -425,13 +425,43 @@ impl SynAttributeHelpers for [syn::Attribute] {
425425}
426426
427427fn split_doc_attr ( input : & str ) -> Vec < String > {
428- input
429- // Convert two newline (indicate "new paragraph") into two line break.
430- . replace ( "\n \n " , " \n \n " )
431- // Convert newline after two spaces (indicate "line break") into line break.
432- . split ( " \n " )
433- // Convert single newline (indicate hard-wrapped) into space.
434- . map ( |s| s. replace ( '\n' , " " ) )
435- . map ( |s| s. trim_end ( ) . to_string ( ) )
436- . collect ( )
428+ if !input. contains ( '\n' ) {
429+ // This is a special case for single-line doc comments, which normally already contain a leading space
430+ // if it is desired.
431+ return vec ! [ input. to_owned( ) ] ;
432+ }
433+
434+ // Calculate the common leading whitespace across all non-empty lines, so we can trim it from all lines while
435+ // preserving relative indentation. This is important for items nested (esp. in modules) where the doc comment
436+ // is usually indented to the same level as the item, leaving whitespace at the beginning of each line.
437+ // We want to trim that, but preserve relative indentation.
438+ // Note: we assume you aren't using mixed tabs and spaces, but that is probably safe to assume for rust code
439+ // which is usually indented with spaces.
440+ let common_indent = input
441+ . lines ( )
442+ . filter ( |line| !line. trim ( ) . is_empty ( ) )
443+ . map ( |line| line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . count ( ) )
444+ . min ( )
445+ . unwrap_or ( 0 ) ;
446+
447+ let mut lines: Vec < String > = input
448+ . lines ( )
449+ // Trim leading empty/whitespace lines
450+ . skip_while ( |line| line. trim ( ) . is_empty ( ) )
451+ // Add a leading space to non-empty lines to prevent misinterpreting leading symbols and
452+ // mirror the behaviour of single-line doc comments, which already have a leading space.
453+ . map ( |s| {
454+ if s. trim ( ) . is_empty ( ) {
455+ String :: new ( )
456+ } else {
457+ format ! ( " {}" , s. chars( ) . skip( common_indent) . collect:: <String >( ) )
458+ }
459+ } )
460+ . collect ( ) ;
461+ // Remove trailing empty/whitespace lines
462+ while lines. last ( ) . is_some_and ( |line| line. trim ( ) . is_empty ( ) ) {
463+ lines. pop ( ) ;
464+ }
465+
466+ lines
437467}
0 commit comments