@@ -25,18 +25,18 @@ public static string Humanize(string text, string xmlCommentEndOfLine)
25
25
. HumanizeRefTags ( )
26
26
. HumanizeHrefTags ( )
27
27
. HumanizeCodeTags ( )
28
- . HumanizeMultilineCodeTags ( )
28
+ . HumanizeMultilineCodeTags ( xmlCommentEndOfLine )
29
29
. HumanizeParaTags ( )
30
30
. HumanizeBrTags ( xmlCommentEndOfLine ) // must be called after HumanizeParaTags() so that it replaces any additional <br> tags
31
31
. DecodeXml ( ) ;
32
32
}
33
33
34
34
private static string NormalizeIndentation ( this string text , string xmlCommentEndOfLine )
35
35
{
36
- string [ ] lines = text . Split ( ' \n ' ) ;
36
+ var lines = text . Split ( [ " \r \n " , " \n " ] , StringSplitOptions . None ) ;
37
37
string padding = GetCommonLeadingWhitespace ( lines ) ;
38
38
39
- int padLen = padding == null ? 0 : padding . Length ;
39
+ int padLen = padding ? . Length ?? 0 ;
40
40
41
41
// remove leading padding from each line
42
42
for ( int i = 0 , l = lines . Length ; i < l ; ++ i )
@@ -51,7 +51,7 @@ private static string NormalizeIndentation(this string text, string xmlCommentEn
51
51
52
52
// remove leading empty lines, but not all leading padding
53
53
// 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 ( ) ;
55
55
}
56
56
57
57
private static string GetCommonLeadingWhitespace ( string [ ] lines )
@@ -105,7 +105,7 @@ private static string HumanizeCodeTags(this string text)
105
105
return CodeTag ( ) . Replace ( text , ( match ) => "`" + match . Groups [ "display" ] . Value + "`" ) ;
106
106
}
107
107
108
- private static string HumanizeMultilineCodeTags ( this string text )
108
+ private static string HumanizeMultilineCodeTags ( this string text , string xmlCommentEndOfLine )
109
109
{
110
110
return MultilineCodeTag ( ) . Replace ( text , match =>
111
111
{
@@ -115,12 +115,17 @@ private static string HumanizeMultilineCodeTags(this string text)
115
115
var builder = new StringBuilder ( ) . Append ( "```" ) ;
116
116
if ( ! codeText . StartsWith ( "\r " ) && ! codeText . StartsWith ( "\n " ) )
117
117
{
118
- builder . AppendLine ( ) ;
118
+ builder . Append ( EndOfLine ( xmlCommentEndOfLine ) ) ;
119
119
}
120
120
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 ) ) ;
124
129
}
125
130
126
131
return $ "```{ codeText } ```";
@@ -129,30 +134,54 @@ private static string HumanizeMultilineCodeTags(this string text)
129
134
130
135
private static string HumanizeParaTags ( this string text )
131
136
{
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 ( ) ) ;
137
138
}
138
139
139
140
private static string HumanizeBrTags ( this string text , string xmlCommentEndOfLine )
140
141
{
141
- return BrTag ( ) . Replace ( text , _ => xmlCommentEndOfLine ?? Environment . NewLine ) ;
142
+ return BrTag ( ) . Replace ( text , _ => EndOfLine ( xmlCommentEndOfLine ) ) ;
142
143
}
143
144
144
145
private static string DecodeXml ( this string text )
145
146
{
146
147
return WebUtility . HtmlDecode ( text ) ;
147
148
}
148
149
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
+
149
177
private const string RefTagPattern = @"<(see|paramref) (name|cref|langword)=""([TPF]{1}:)?(?<display>.+?)"" ?/>" ;
150
178
private const string CodeTagPattern = @"<c>(?<display>.+?)</c>" ;
151
179
private const string MultilineCodeTagPattern = @"<code>(?<display>.+?)</code>" ;
152
180
private const string ParaTagPattern = @"<para>(?<display>.+?)</para>" ;
153
181
private const string HrefPattern = @"<see href=\""(.*)\"">(.*)<\/see>" ;
154
182
private const string BrPattern = @"(<br ?\/?>)" ; // handles <br>, <br/>, <br />
155
183
private const string LineBreaksPattern = @"\r?\n" ;
184
+ private const string DoubleUpLineBreaksPattern = @"(\r?\n){2,}" ;
156
185
157
186
#if NET7_0_OR_GREATER
158
187
[ GeneratedRegex ( RefTagPattern ) ]
@@ -175,6 +204,9 @@ private static string DecodeXml(this string text)
175
204
176
205
[ GeneratedRegex ( LineBreaksPattern ) ]
177
206
private static partial Regex LineBreaks ( ) ;
207
+
208
+ [ GeneratedRegex ( DoubleUpLineBreaksPattern ) ]
209
+ private static partial Regex DoubleUpLineBreaks ( ) ;
178
210
#else
179
211
private static readonly Regex _refTag = new ( RefTagPattern ) ;
180
212
private static readonly Regex _codeTag = new ( CodeTagPattern ) ;
@@ -183,6 +215,7 @@ private static string DecodeXml(this string text)
183
215
private static readonly Regex _hrefTag = new ( HrefPattern ) ;
184
216
private static readonly Regex _brTag = new ( BrPattern ) ;
185
217
private static readonly Regex _lineBreaks = new ( LineBreaksPattern ) ;
218
+ private static readonly Regex _doubleUpLineBreaks = new ( DoubleUpLineBreaksPattern ) ;
186
219
187
220
private static Regex RefTag ( ) => _refTag ;
188
221
private static Regex CodeTag ( ) => _codeTag ;
@@ -191,6 +224,7 @@ private static string DecodeXml(this string text)
191
224
private static Regex HrefTag ( ) => _hrefTag ;
192
225
private static Regex BrTag ( ) => _brTag ;
193
226
private static Regex LineBreaks ( ) => _lineBreaks ;
227
+ private static Regex DoubleUpLineBreaks ( ) => _doubleUpLineBreaks ;
194
228
#endif
195
229
}
196
230
}
0 commit comments