diff --git a/CodeBlocker.Test/DocCommentTests.cs b/CodeBlocker.Test/DocCommentTests.cs
index eabbbb2..f802433 100644
--- a/CodeBlocker.Test/DocCommentTests.cs
+++ b/CodeBlocker.Test/DocCommentTests.cs
@@ -74,6 +74,23 @@ public void EitherLineTerminatorSplitsTheText()
Render(new DocComment { Summary = "a\r\nb" }));
}
+ [TestMethod]
+ [DataRow("\u0085", DisplayName = "NEL")]
+ [DataRow("\u2028", DisplayName = "LINE SEPARATOR")]
+ [DataRow("\u2029", DisplayName = "PARAGRAPH SEPARATOR")]
+ public void EveryLineTerminatorTheCompilerRecognisesStartsANewCommentLine(string separator)
+ {
+ // The compiler ends a /// comment at each of these, so text after one left inside a line is
+ // parsed as code and the generated file does not compile.
+ string rendered = Render(new DocComment { Summary = $"Line one{separator}Line two" });
+
+ Assert.AreEqual(Render(new DocComment { Summary = "Line one\nLine two" }), rendered);
+ foreach (string line in rendered.Split('\n', '\r', '\u0085', '\u2028', '\u2029'))
+ {
+ Assert.IsTrue(line.Length == 0 || line.StartsWith("///", StringComparison.Ordinal), $"Not inside the comment: \"{line}\"");
+ }
+ }
+
[TestMethod]
public void TextContentIsEscapedByDefault()
{
diff --git a/CodeBlocker/Templates/DocComment.cs b/CodeBlocker/Templates/DocComment.cs
index 6e52b13..48902fa 100644
--- a/CodeBlocker/Templates/DocComment.cs
+++ b/CodeBlocker/Templates/DocComment.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2023-2026 ktsu-dev contributors
+// Copyright (c) 2023-2026 ktsu-dev contributors
namespace ktsu.CodeBlocker.Templates;
@@ -221,13 +221,17 @@ private void WriteNamedElement(CodeBlocker codeBlocker, string tagName, string?
private string Escape(string text) => EscapeText ? EscapeContent(text) : text;
///
- /// Splits text into lines, accepting either line terminator so that a caller's verbatim or raw
- /// string literal lays out the same way whichever platform the source file was written on.
+ /// Splits text into lines at every terminator the C# compiler recognises: either platform's
+ /// line ending, so that a caller's verbatim or raw string literal lays out the same way
+ /// whichever platform the source file was written on, and also NEL (U+0085), LINE SEPARATOR
+ /// (U+2028) and PARAGRAPH SEPARATOR (U+2029). The compiler ends a /// comment at any of
+ /// those, so left inside a line they would push the rest of the text out of the comment and
+ /// into the code.
///
/// The text to split.
/// The text's lines.
private static string[] SplitLines(string text) =>
- text.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n');
+ text.Replace("\r\n", "\n").Split('\n', '\r', '\u0085', '\u2028', '\u2029');
///
/// Escapes the characters that would otherwise be read as markup in element content.