@@ -25,18 +25,18 @@ public static string Humanize(string text, string xmlCommentEndOfLine)
2525 . HumanizeRefTags ( )
2626 . HumanizeHrefTags ( )
2727 . HumanizeCodeTags ( )
28- . HumanizeMultilineCodeTags ( )
28+ . HumanizeMultilineCodeTags ( xmlCommentEndOfLine )
2929 . HumanizeParaTags ( )
3030 . HumanizeBrTags ( xmlCommentEndOfLine ) // must be called after HumanizeParaTags() so that it replaces any additional <br> tags
3131 . DecodeXml ( ) ;
3232 }
3333
3434 private static string NormalizeIndentation ( this string text , string xmlCommentEndOfLine )
3535 {
36- string [ ] lines = text . Split ( ' \n ' ) ;
36+ var lines = text . Split ( [ " \r \n " , " \n " ] , StringSplitOptions . None ) ;
3737 string padding = GetCommonLeadingWhitespace ( lines ) ;
3838
39- int padLen = padding == null ? 0 : padding . Length ;
39+ int padLen = padding ? . Length ?? 0 ;
4040
4141 // remove leading padding from each line
4242 for ( int i = 0 , l = lines . Length ; i < l ; ++ i )
@@ -51,7 +51,7 @@ private static string NormalizeIndentation(this string text, string xmlCommentEn
5151
5252 // remove leading empty lines, but not all leading padding
5353 // remove all trailing whitespace, regardless
54- return string . Join ( xmlCommentEndOfLine ?? " \r \n " , lines . SkipWhile ( x => string . IsNullOrWhiteSpace ( x ) ) ) . TrimEnd ( ) ;
54+ return string . Join ( EndOfLine ( xmlCommentEndOfLine ) , lines . SkipWhile ( string . IsNullOrWhiteSpace ) ) . TrimEnd ( ) ;
5555 }
5656
5757 private static string GetCommonLeadingWhitespace ( string [ ] lines )
@@ -105,7 +105,7 @@ private static string HumanizeCodeTags(this string text)
105105 return CodeTag ( ) . Replace ( text , ( match ) => "`" + match . Groups [ "display" ] . Value + "`" ) ;
106106 }
107107
108- private static string HumanizeMultilineCodeTags ( this string text )
108+ private static string HumanizeMultilineCodeTags ( this string text , string xmlCommentEndOfLine )
109109 {
110110 return MultilineCodeTag ( ) . Replace ( text , match =>
111111 {
@@ -115,12 +115,17 @@ private static string HumanizeMultilineCodeTags(this string text)
115115 var builder = new StringBuilder ( ) . Append ( "```" ) ;
116116 if ( ! codeText . StartsWith ( "\r " ) && ! codeText . StartsWith ( "\n " ) )
117117 {
118- builder . AppendLine ( ) ;
118+ builder . Append ( EndOfLine ( xmlCommentEndOfLine ) ) ;
119119 }
120120
121- return builder . AppendLine ( codeText . TrimEnd ( ) )
122- . Append ( "```" )
123- . ToString ( ) ;
121+ builder . Append ( RemoveCommonLeadingWhitespace ( codeText , xmlCommentEndOfLine ) ) ;
122+ if ( ! codeText . EndsWith ( "\n " ) )
123+ {
124+ builder . Append ( EndOfLine ( xmlCommentEndOfLine ) ) ;
125+ }
126+
127+ builder . Append ( "```" ) ;
128+ return DoubleUpLineBreaks ( ) . Replace ( builder . ToString ( ) , EndOfLine ( xmlCommentEndOfLine ) ) ;
124129 }
125130
126131 return $ "```{ codeText } ```";
@@ -129,30 +134,54 @@ private static string HumanizeMultilineCodeTags(this string text)
129134
130135 private static string HumanizeParaTags ( this string text )
131136 {
132- return ParaTag ( ) . Replace ( text , match =>
133- {
134- var paraText = "<br>" + match . Groups [ "display" ] . Value . Trim ( ) ;
135- return LineBreaks ( ) . Replace ( paraText , _ => string . Empty ) ;
136- } ) ;
137+ return ParaTag ( ) . Replace ( text , match => "<br>" + match . Groups [ "display" ] . Value . Trim ( ) ) ;
137138 }
138139
139140 private static string HumanizeBrTags ( this string text , string xmlCommentEndOfLine )
140141 {
141- return BrTag ( ) . Replace ( text , _ => xmlCommentEndOfLine ?? Environment . NewLine ) ;
142+ return BrTag ( ) . Replace ( text , _ => EndOfLine ( xmlCommentEndOfLine ) ) ;
142143 }
143144
144145 private static string DecodeXml ( this string text )
145146 {
146147 return WebUtility . HtmlDecode ( text ) ;
147148 }
148149
150+ private static string RemoveCommonLeadingWhitespace ( string input , string xmlCommentEndOfLine )
151+ {
152+ var lines = input . Split ( [ "\r \n " , "\n " ] , StringSplitOptions . None ) ;
153+ var padding = GetCommonLeadingWhitespace ( lines ) ;
154+ if ( string . IsNullOrEmpty ( padding ) )
155+ {
156+ return input ;
157+ }
158+
159+ var minLeadingSpaces = padding . Length ;
160+ var builder = new StringBuilder ( ) ;
161+ foreach ( var line in lines )
162+ {
163+ builder . Append ( string . IsNullOrWhiteSpace ( line )
164+ ? line
165+ : line . Substring ( minLeadingSpaces ) ) ;
166+ builder . Append ( EndOfLine ( xmlCommentEndOfLine ) ) ;
167+ }
168+
169+ return builder . ToString ( ) ;
170+ }
171+
172+ internal static string EndOfLine ( string xmlCommentEndOfLine )
173+ {
174+ return xmlCommentEndOfLine ?? Environment . NewLine ;
175+ }
176+
149177 private const string RefTagPattern = @"<(see|paramref) (name|cref|langword)=""([TPF]{1}:)?(?<display>.+?)"" ?/>" ;
150178 private const string CodeTagPattern = @"<c>(?<display>.+?)</c>" ;
151179 private const string MultilineCodeTagPattern = @"<code>(?<display>.+?)</code>" ;
152180 private const string ParaTagPattern = @"<para>(?<display>.+?)</para>" ;
153181 private const string HrefPattern = @"<see href=\""(.*)\"">(.*)<\/see>" ;
154182 private const string BrPattern = @"(<br ?\/?>)" ; // handles <br>, <br/>, <br />
155183 private const string LineBreaksPattern = @"\r?\n" ;
184+ private const string DoubleUpLineBreaksPattern = @"(\r?\n){2,}" ;
156185
157186#if NET7_0_OR_GREATER
158187 [ GeneratedRegex ( RefTagPattern ) ]
@@ -175,6 +204,9 @@ private static string DecodeXml(this string text)
175204
176205 [ GeneratedRegex ( LineBreaksPattern ) ]
177206 private static partial Regex LineBreaks ( ) ;
207+
208+ [ GeneratedRegex ( DoubleUpLineBreaksPattern ) ]
209+ private static partial Regex DoubleUpLineBreaks ( ) ;
178210#else
179211 private static readonly Regex _refTag = new ( RefTagPattern ) ;
180212 private static readonly Regex _codeTag = new ( CodeTagPattern ) ;
@@ -183,6 +215,7 @@ private static string DecodeXml(this string text)
183215 private static readonly Regex _hrefTag = new ( HrefPattern ) ;
184216 private static readonly Regex _brTag = new ( BrPattern ) ;
185217 private static readonly Regex _lineBreaks = new ( LineBreaksPattern ) ;
218+ private static readonly Regex _doubleUpLineBreaks = new ( DoubleUpLineBreaksPattern ) ;
186219
187220 private static Regex RefTag ( ) => _refTag ;
188221 private static Regex CodeTag ( ) => _codeTag ;
@@ -191,6 +224,7 @@ private static string DecodeXml(this string text)
191224 private static Regex HrefTag ( ) => _hrefTag ;
192225 private static Regex BrTag ( ) => _brTag ;
193226 private static Regex LineBreaks ( ) => _lineBreaks ;
227+ private static Regex DoubleUpLineBreaks ( ) => _doubleUpLineBreaks ;
194228#endif
195229 }
196230}
0 commit comments