Skip to content

Commit 03cf14d

Browse files
yufeihp-kostov
authored andcommitted
fix: xml indentation issue on external <code> (dotnet#9465)
fix: xml intention issue on external <code> Co-authored-by: Yufei Huang <[email protected]>
1 parent 0f2e419 commit 03cf14d

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

src/Docfx.Common/XHtmlWriter.cs renamed to src/Docfx.Dotnet/Parsers/XHtmlWriter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Docfx.Common;
77

8-
public class XHtmlWriter : XmlWriter
8+
class XHtmlWriter : XmlWriter
99
{
1010
private static HashSet<string> _voidElements;
1111
private string _currentElement;
@@ -15,7 +15,7 @@ public class XHtmlWriter : XmlWriter
1515

1616
public XHtmlWriter(TextWriter writer)
1717
{
18-
_writer = Create(writer);
18+
_writer = Create(writer, new() { OmitXmlDeclaration = true });
1919
// void element (ref: http://www.w3.org/TR/html-markup/syntax.html)
2020
_voidElements = new HashSet<string> { "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr" };
2121
}

src/Docfx.Dotnet/Parsers/XmlComment.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ private XmlComment(string xml, XmlCommentParserContext context)
6868
}
6969

7070
// Transform triple slash comment
71-
var doc = XmlCommentTransformer.Transform(xml);
71+
xml = XmlCommentTransformer.Transform(xml);
72+
var doc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
7273

7374
_context = context;
7475

@@ -139,9 +140,9 @@ private void ResolveCode(XDocument doc, XmlCommentParserContext context)
139140
continue;
140141
}
141142

142-
var indent = ((IXmlLineInfo)node).LinePosition - 2;
143+
var indent = new string(' ', ((IXmlLineInfo)node).LinePosition - 2);
143144
var (lang, value) = ResolveCodeSource(node, context);
144-
value = TrimEachLine(value ?? node.Value, new(' ', indent));
145+
value = TrimEachLine(value ?? node.Value, indent);
145146
var code = new XElement("code", value);
146147

147148
if (node.Attribute("language") is { } languageAttribute)
@@ -155,7 +156,18 @@ private void ResolveCode(XDocument doc, XmlCommentParserContext context)
155156
}
156157

157158
code.SetAttributeValue("class", $"lang-{lang}");
158-
node.ReplaceWith(new XElement("pre", code));
159+
160+
if (node.PreviousNode is null)
161+
{
162+
// Xml writer formats <pre><code> with unintended identation
163+
// when there is no preceeding text node.
164+
// Prepend a text node with the same indentation to force <pre><code>.
165+
node.ReplaceWith($"\n{indent}", new XElement("pre", code));
166+
}
167+
else
168+
{
169+
node.ReplaceWith(new XElement("pre", code));
170+
}
159171
}
160172
}
161173

src/Docfx.Dotnet/Parsers/XmlCommentTransformer.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace Docfx.Dotnet;
1212

13-
internal static class XmlCommentTransformer
13+
static class XmlCommentTransformer
1414
{
1515
private static readonly XslCompiledTransform _transform;
1616

@@ -25,13 +25,12 @@ static XmlCommentTransformer()
2525
_transform.Load(reader, xsltSettings, new XmlUrlResolver());
2626
}
2727

28-
public static XDocument Transform(string xml)
28+
public static string Transform(string xml)
2929
{
30-
using var ms = new MemoryStream();
31-
using var writer = new XHtmlWriter(new StreamWriter(ms));
30+
using var ms = new StringWriter();
31+
using var writer = new XHtmlWriter(ms);
3232
XDocument doc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace);
3333
_transform.Transform(doc.CreateNavigator(), writer);
34-
ms.Seek(0, SeekOrigin.Begin);
35-
return XDocument.Load(ms, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
34+
return ms.ToString();
3635
}
3736
}

test/Docfx.Dotnet.Tests/XmlCommentUnitTest.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ public static void SeeLangword()
2222
Verify("<see langword=\"undefined-langword\" />", "<code>undefined-langword</code>");
2323
}
2424

25+
[Fact]
26+
public static void ParaNewLine()
27+
{
28+
Assert.Equal(
29+
"""
30+
a
31+
<p>b</p>
32+
<p>c</p>
33+
""",
34+
XmlComment.Parse("""
35+
<summary>
36+
a
37+
<para>b</para>
38+
<para>c</para>
39+
</summary>
40+
""").Summary,
41+
ignoreLineEndingDifferences: true);
42+
}
43+
2544
[Fact]
2645
public static void Issue8122()
2746
{
@@ -152,6 +171,35 @@ public void ExternalCodeBlockXaml()
152171
ignoreLineEndingDifferences: true);
153172
}
154173

174+
[Theory]
175+
[InlineData("<example><code source='Example.cs' region='SDK_CustomProcessor' /></example>")]
176+
[InlineData("""
177+
<example>
178+
<code source='Example.cs' region='SDK_CustomProcessor' />
179+
</example>
180+
""")]
181+
public void Issue9462(string input)
182+
{
183+
var commentModel = XmlComment.Parse(input, new()
184+
{
185+
ResolveCode = _ =>
186+
"""
187+
#region SDK_CustomProcessor
188+
189+
using System;
190+
using System.Collections.Generic;
191+
#endregion
192+
"""
193+
});
194+
Assert.Equal(
195+
"""
196+
<pre><code class="lang-cs">using System;
197+
using System.Collections.Generic;</code></pre>
198+
""",
199+
commentModel.Examples.Single(),
200+
ignoreLineEndingDifferences: true);
201+
}
202+
155203
[Fact]
156204
public static void MarkdownCodeBlock()
157205
{

0 commit comments

Comments
 (0)