Skip to content

Commit

Permalink
fix: xml indentation issue on external <code> (#9465)
Browse files Browse the repository at this point in the history
fix: xml intention issue on external <code>

Co-authored-by: Yufei Huang <yufeih@users.noreply.github.com>
  • Loading branch information
yufeih and yufeih authored Nov 24, 2023
1 parent 4ed6faa commit f04be7b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Docfx.Common;

public class XHtmlWriter : XmlWriter
class XHtmlWriter : XmlWriter
{
private static HashSet<string> _voidElements;
private string _currentElement;
Expand All @@ -15,7 +15,7 @@ public class XHtmlWriter : XmlWriter

public XHtmlWriter(TextWriter writer)
{
_writer = Create(writer);
_writer = Create(writer, new() { OmitXmlDeclaration = true });
// void element (ref: http://www.w3.org/TR/html-markup/syntax.html)
_voidElements = new HashSet<string> { "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr" };
}
Expand Down
20 changes: 16 additions & 4 deletions src/Docfx.Dotnet/Parsers/XmlComment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ private XmlComment(string xml, XmlCommentParserContext context)
}

// Transform triple slash comment
var doc = XmlCommentTransformer.Transform(xml);
xml = XmlCommentTransformer.Transform(xml);
var doc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);

_context = context;

Expand Down Expand Up @@ -139,9 +140,9 @@ private void ResolveCode(XDocument doc, XmlCommentParserContext context)
continue;
}

var indent = ((IXmlLineInfo)node).LinePosition - 2;
var indent = new string(' ', ((IXmlLineInfo)node).LinePosition - 2);
var (lang, value) = ResolveCodeSource(node, context);
value = TrimEachLine(value ?? node.Value, new(' ', indent));
value = TrimEachLine(value ?? node.Value, indent);
var code = new XElement("code", value);

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

code.SetAttributeValue("class", $"lang-{lang}");
node.ReplaceWith(new XElement("pre", code));

if (node.PreviousNode is null)
{
// Xml writer formats <pre><code> with unintended identation
// when there is no preceeding text node.
// Prepend a text node with the same indentation to force <pre><code>.
node.ReplaceWith($"\n{indent}", new XElement("pre", code));
}
else
{
node.ReplaceWith(new XElement("pre", code));
}
}
}

Expand Down
11 changes: 5 additions & 6 deletions src/Docfx.Dotnet/Parsers/XmlCommentTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Docfx.Dotnet;

internal static class XmlCommentTransformer
static class XmlCommentTransformer
{
private static readonly XslCompiledTransform _transform;

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

public static XDocument Transform(string xml)
public static string Transform(string xml)
{
using var ms = new MemoryStream();
using var writer = new XHtmlWriter(new StreamWriter(ms));
using var ms = new StringWriter();
using var writer = new XHtmlWriter(ms);
XDocument doc = XDocument.Parse(xml, LoadOptions.PreserveWhitespace);
_transform.Transform(doc.CreateNavigator(), writer);
ms.Seek(0, SeekOrigin.Begin);
return XDocument.Load(ms, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
return ms.ToString();
}
}
48 changes: 48 additions & 0 deletions test/Docfx.Dotnet.Tests/XmlCommentUnitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ public static void SeeLangword()
Verify("<see langword=\"undefined-langword\" />", "<code>undefined-langword</code>");
}

[Fact]
public static void ParaNewLine()
{
Assert.Equal(
"""
a
<p>b</p>
<p>c</p>
""",
XmlComment.Parse("""
<summary>
a
<para>b</para>
<para>c</para>
</summary>
""").Summary,
ignoreLineEndingDifferences: true);
}

[Fact]
public static void Issue8122()
{
Expand Down Expand Up @@ -152,6 +171,35 @@ public void ExternalCodeBlockXaml()
ignoreLineEndingDifferences: true);
}

[Theory]
[InlineData("<example><code source='Example.cs' region='SDK_CustomProcessor' /></example>")]
[InlineData("""
<example>
<code source='Example.cs' region='SDK_CustomProcessor' />
</example>
""")]
public void Issue9462(string input)
{
var commentModel = XmlComment.Parse(input, new()
{
ResolveCode = _ =>
"""
#region SDK_CustomProcessor
using System;
using System.Collections.Generic;
#endregion
"""
});
Assert.Equal(
"""
<pre><code class="lang-cs">using System;
using System.Collections.Generic;</code></pre>
""",
commentModel.Examples.Single(),
ignoreLineEndingDifferences: true);
}

[Fact]
public static void MarkdownCodeBlock()
{
Expand Down

0 comments on commit f04be7b

Please sign in to comment.