Skip to content

Commit 8898798

Browse files
committed
#24 Write \n when formatting <br /> or <hr /> into plaintext.
1 parent f8873ab commit 8898798

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

MwParserFromScratch/MwParserFromScratch.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
5+
<LangVersion>latest</LangVersion>
56
<GenerateDocumentationFile>true</GenerateDocumentationFile>
67

78
<AssemblyName>MwParserFromScratch</AssemblyName>

MwParserFromScratch/Nodes/Inline.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ public override TagStyle TagStyle
889889
{
890890
set
891891
{
892-
if (value == TagStyle.SelfClosing && value == TagStyle.CompactSelfClosing)
892+
if (value is TagStyle.SelfClosing or TagStyle.CompactSelfClosing)
893893
{
894894
if (Content != null && Content.Lines.Count > 0)
895895
throw new InvalidOperationException("Cannot self-close a tag with non-empty content.");
@@ -904,8 +904,30 @@ public override TagStyle TagStyle
904904
/// <inheritdoc />
905905
internal override void ToPlainTextCore(StringBuilder builder, NodePlainTextFormatter formatter)
906906
{
907-
if (Content != null)
908-
formatter(Content, builder);
907+
if (string.Equals(Name, "br", StringComparison.OrdinalIgnoreCase)
908+
|| string.Equals(Name, "hr", StringComparison.OrdinalIgnoreCase))
909+
{
910+
// for <br /> or <hr />, by default, we want to actually render a line break.
911+
// Abnormal cases in MW:
912+
// <br>abc</br> will be rendered as <br />abc<br />.
913+
// <br></br> will be rendered as <br /><br />.
914+
// In practice, however, <br>abc</br> won't be parsed correctly, as <br> itself as self-closing.
915+
// See WikitextParserOptions.DefaultSelfClosingOnlyTags
916+
builder.Append('\n');
917+
if (Content != null)
918+
{
919+
formatter(Content, builder);
920+
builder.Append('\n');
921+
}
922+
return;
923+
}
924+
925+
// We are not wrapping other block-style elements, e.g., <div>, with \n,
926+
// as these elements could be overridden into inline-style. Inline elements, e.g., <span>
927+
// could be otherwise overridden into block-style.
928+
// We leave such triaging responsibility to the library consumer (`formatter` arg).
929+
930+
if (Content != null) formatter(Content, builder);
909931
}
910932

911933
}

MwParserFromScratch/Nodes/Node.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ public Node Clone()
364364

365365
private static void DefaultNodePlainTextFormatter(Node node, StringBuilder builder)
366366
{
367+
Debug.Assert(node != null);
368+
Debug.Assert(builder != null);
367369
node.ToPlainTextCore(builder, DefaultNodePlainTextFormatter);
368370
}
369371

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using UnitTestProject1.Primitive;
2+
using Xunit;
3+
using Xunit.Abstractions;
4+
5+
namespace UnitTestProject1;
6+
7+
public class RegressionTests : ParserTestBase
8+
{
9+
10+
/// <inheritdoc />
11+
public RegressionTests(ITestOutputHelper output) : base(output)
12+
{
13+
}
14+
15+
/// <summary>
16+
/// ToPlainText containing <br /> does not translate such tag in a \n new line
17+
/// </summary>
18+
[Fact]
19+
public void Issue24()
20+
{
21+
var root = this.ParseWikitext(
22+
"<span>Member of the [[Pennsylvania Senate]]<br/> from the [[Pennsylvania Senate, District 48|48th]] district</span>"
23+
);
24+
Assert.Equal("Member of the Pennsylvania Senate\n from the 48th district", root.ToPlainText());
25+
26+
// Abnormal case 1 -- actually the second </br> won't be treated as closing tag, as <br> itself is self-closing.
27+
// See WikitextParserOptions.DefaultSelfClosingOnlyTags
28+
root = this.ParseWikitext("test<br>foo</br>bar");
29+
Assert.Equal("test\nfoo</br>bar", root.ToPlainText());
30+
}
31+
32+
}

0 commit comments

Comments
 (0)