diff --git a/Iceshrimp.Backend/Core/Helpers/LibMfm/Serialization/MfmSerializer.cs b/Iceshrimp.Backend/Core/Helpers/LibMfm/Serialization/MfmSerializer.cs index 19b23caa..0d7aacba 100644 --- a/Iceshrimp.Backend/Core/Helpers/LibMfm/Serialization/MfmSerializer.cs +++ b/Iceshrimp.Backend/Core/Helpers/LibMfm/Serialization/MfmSerializer.cs @@ -17,7 +17,7 @@ public static class MfmSerializer { result.Append($"\n```{mfmCodeBlockNode.Language?.Value ?? ""}\n"); result.Append(mfmCodeBlockNode.Code); - result.Append("\n```\n\n"); + result.Append("\n```\n"); break; } case MfmMathBlockNode mfmMathBlockNode: diff --git a/Iceshrimp.Parsing/Mfm.fs b/Iceshrimp.Parsing/Mfm.fs index 9b14ce54..a6e52ad4 100644 --- a/Iceshrimp.Parsing/Mfm.fs +++ b/Iceshrimp.Parsing/Mfm.fs @@ -202,13 +202,15 @@ module private MfmParser = |>> fun v -> MfmInlineCodeNode(v) :> MfmNode let codeBlockNode = - opt (previousCharSatisfies isNewline >>. skipNewline) + opt skipNewline + >>. opt skipNewline >>. previousCharSatisfiesNot isNotNewline >>. skipString "```" >>. opt (many1CharsTill asciiLetter (lookAhead newline)) .>>. (skipNewline >>. manyCharsTill anyChar (attempt (skipNewline >>. skipString "```"))) - .>> (opt <| attempt (skipNewline >>. skipNewline)) + .>> (skipNewline <|> eof) + .>> opt skipNewline |>> fun (lang: string option, code: string) -> MfmCodeBlockNode(code, lang) :> MfmNode let mathNode = diff --git a/Iceshrimp.Tests/Parsing/MfmTests.cs b/Iceshrimp.Tests/Parsing/MfmTests.cs index 5d92a52c..155be67b 100644 --- a/Iceshrimp.Tests/Parsing/MfmTests.cs +++ b/Iceshrimp.Tests/Parsing/MfmTests.cs @@ -140,26 +140,38 @@ public class MfmTests [TestMethod] public void TestCodeBlock() { - const string input = """ - test 123 + const string canonical = """ + test 123 + ``` + this is a code block + ``` + test 123 + """; - ``` - this is a code block - ``` + const string alt = """ + test 123 + + ``` + this is a code block + ``` + + test 123 + """; - test 123 - """; List expected = [ - new MfmTextNode("test 123\n"), + new MfmTextNode("test 123"), new MfmCodeBlockNode("this is a code block", null), new MfmTextNode("test 123") ]; - var res = Mfm.parse(input); + var res = Mfm.parse(canonical); + var res2 = Mfm.parse(alt); AssertionOptions.FormattingOptions.MaxDepth = 100; res.ToList().Should().Equal(expected, MfmNodeEqual); - MfmSerializer.Serialize(res).Should().BeEquivalentTo(input); + res2.ToList().Should().Equal(expected, MfmNodeEqual); + MfmSerializer.Serialize(res).Should().BeEquivalentTo(canonical); + MfmSerializer.Serialize(res2).Should().BeEquivalentTo(canonical); } [TestMethod]