[parsing/mfm] Fix incorrect handling of lists
This commit is contained in:
parent
27ac36d747
commit
5349346f52
2 changed files with 41 additions and 8 deletions
|
@ -174,6 +174,17 @@ module private MfmParser =
|
||||||
| None -> None
|
| None -> None
|
||||||
| Some items -> items |> dict |> Some
|
| Some items -> items |> dict |> Some
|
||||||
|
|
||||||
|
let pushLine: Parser<unit, int64> =
|
||||||
|
fun stream ->
|
||||||
|
stream.UserState <- stream.Line
|
||||||
|
Reply(())
|
||||||
|
|
||||||
|
let assertLine: Parser<unit, int64> =
|
||||||
|
fun stream ->
|
||||||
|
match stream.UserState = stream.Line with
|
||||||
|
| true -> Reply(())
|
||||||
|
| false -> Reply(Error, messageError "Line changed")
|
||||||
|
|
||||||
// References
|
// References
|
||||||
let node, nodeRef = createParserForwardedToRef ()
|
let node, nodeRef = createParserForwardedToRef ()
|
||||||
let inlineNode, inlineNodeRef = createParserForwardedToRef ()
|
let inlineNode, inlineNodeRef = createParserForwardedToRef ()
|
||||||
|
@ -195,21 +206,25 @@ module private MfmParser =
|
||||||
// Node parsers
|
// Node parsers
|
||||||
|
|
||||||
let italicNode =
|
let italicNode =
|
||||||
(italicPattern >>. manyTill inlineNode italicPattern)
|
(italicPattern >>. pushLine >>. manyTill inlineNode italicPattern .>> assertLine)
|
||||||
<|> (skipString "<i>" >>. manyTill inlineNode (skipString "</i>"))
|
<|> (skipString "<i>" >>. pushLine >>. manyTill inlineNode (skipString "</i>")
|
||||||
|
.>> assertLine)
|
||||||
|>> fun c -> MfmItalicNode(aggregateTextInline c) :> MfmNode
|
|>> fun c -> MfmItalicNode(aggregateTextInline c) :> MfmNode
|
||||||
|
|
||||||
let boldNode =
|
let boldNode =
|
||||||
(skipString "**" >>. manyTill inlineNode (skipString "**"))
|
(skipString "**" >>. pushLine >>. manyTill inlineNode (skipString "**")
|
||||||
<|> (skipString "<b>" >>. manyTill inlineNode (skipString "</b>"))
|
.>> assertLine)
|
||||||
|
<|> (skipString "<b>" >>. pushLine >>. manyTill inlineNode (skipString "</b>")
|
||||||
|
.>> assertLine)
|
||||||
|>> fun c -> MfmBoldNode(aggregateTextInline c) :> MfmNode
|
|>> fun c -> MfmBoldNode(aggregateTextInline c) :> MfmNode
|
||||||
|
|
||||||
let strikeNode =
|
let strikeNode =
|
||||||
skipString "~~" >>. manyTill inlineNode (skipString "~~")
|
skipString "~~" >>. pushLine >>. manyTill inlineNode (skipString "~~")
|
||||||
|
.>> assertLine
|
||||||
|>> fun c -> MfmStrikeNode(aggregateTextInline c) :> MfmNode
|
|>> fun c -> MfmStrikeNode(aggregateTextInline c) :> MfmNode
|
||||||
|
|
||||||
let codeNode =
|
let codeNode =
|
||||||
codePattern >>. manyCharsTill anyChar codePattern
|
codePattern >>. pushLine >>. manyCharsTill anyChar codePattern .>> assertLine
|
||||||
|>> fun v -> MfmInlineCodeNode(v) :> MfmNode
|
|>> fun v -> MfmInlineCodeNode(v) :> MfmNode
|
||||||
|
|
||||||
let codeBlockNode =
|
let codeBlockNode =
|
||||||
|
@ -225,7 +240,8 @@ module private MfmParser =
|
||||||
|>> fun (lang: string option, code: string) -> MfmCodeBlockNode(code, lang) :> MfmNode
|
|>> fun (lang: string option, code: string) -> MfmCodeBlockNode(code, lang) :> MfmNode
|
||||||
|
|
||||||
let mathNode =
|
let mathNode =
|
||||||
skipString "\(" >>. manyCharsTill anyChar (skipString "\)")
|
skipString "\(" >>. pushLine >>. manyCharsTill anyChar (skipString "\)")
|
||||||
|
.>> assertLine
|
||||||
|>> fun f -> MfmMathInlineNode(f) :> MfmNode
|
|>> fun f -> MfmMathInlineNode(f) :> MfmNode
|
||||||
|
|
||||||
let mathBlockNode =
|
let mathBlockNode =
|
||||||
|
@ -368,6 +384,7 @@ module private MfmParser =
|
||||||
|
|
||||||
// Populate references
|
// Populate references
|
||||||
do nodeRef.Value <- choice <| seqAttempt (seqFlatten <| nodeSeq)
|
do nodeRef.Value <- choice <| seqAttempt (seqFlatten <| nodeSeq)
|
||||||
|
|
||||||
do inlineNodeRef.Value <- choice <| (seqAttempt inlineNodeSeq) |>> fun v -> v :?> MfmInlineNode
|
do inlineNodeRef.Value <- choice <| (seqAttempt inlineNodeSeq) |>> fun v -> v :?> MfmInlineNode
|
||||||
|
|
||||||
// Final parse command
|
// Final parse command
|
||||||
|
@ -377,6 +394,6 @@ open MfmParser
|
||||||
|
|
||||||
module Mfm =
|
module Mfm =
|
||||||
let parse str =
|
let parse str =
|
||||||
match run parse str with
|
match runParserOnString parse 0 "" str with
|
||||||
| Success(result, _, _) -> aggregateText result
|
| Success(result, _, _) -> aggregateText result
|
||||||
| Failure(s, _, _) -> failwith $"Failed to parse MFM: {s}"
|
| Failure(s, _, _) -> failwith $"Failed to parse MFM: {s}"
|
||||||
|
|
|
@ -34,6 +34,22 @@ public class MfmTests
|
||||||
resMixedAlt.Should().Equal(expected, MfmNodeEqual);
|
resMixedAlt.Should().Equal(expected, MfmNodeEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestParseList()
|
||||||
|
{
|
||||||
|
const string input = """
|
||||||
|
* test
|
||||||
|
* test2
|
||||||
|
* test3
|
||||||
|
""";
|
||||||
|
|
||||||
|
List<MfmNode> expected = [new MfmTextNode("* test\n* test2\n* test3")];
|
||||||
|
|
||||||
|
var res = Mfm.parse(input).ToList();
|
||||||
|
res.Should().Equal(expected, MfmNodeEqual);
|
||||||
|
MfmSerializer.Serialize(res).Should().BeEquivalentTo(input);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestParseCode()
|
public void TestParseCode()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue