diff --git a/src/Markdown.hs b/src/Markdown.hs index e6fc411..48bb336 100644 --- a/src/Markdown.hs +++ b/src/Markdown.hs @@ -45,7 +45,15 @@ element = try htmlBlock "HTML Block", paragraphBlock "Paragarph" ] - <* blockEnding + -- a block is normally followed by a blank line or the end of input, but a + -- block that ends without one is the next block's problem rather than a + -- parse error for the whole document. requiring the ending here turned + -- "- a\n:" into a hard failure, because listItem has already eaten the + -- newline that blockEnding wants and the consumed input escapes document's + -- many. the try matters for the same reason optional isn't enough on its + -- own, blockEnding can consume one line ending before finding out there is + -- no second one. + <* optional (try blockEnding) lineEnding :: (Logger m, Characters s, HasCallStack) => Parser s m () lineEnding = {-logCallStack *>-} ((try eof) <|> void newline) @@ -137,7 +145,7 @@ fencedCodeBlock = between (string "```") (string "```") $ do language' <- T.pack <$> (many (notFollowedBy lineEnding *> anySingle)) lineEnding code <- T.pack <$> (many ((notFollowedBy $ string "```") *> anySingle)) - let language = if language' == "" then Just language' else Nothing + let language = if language' == "" then Nothing else Just language' pure $ Code (C {language, code}) mempty blockquoteBlock :: (Logger m, Characters s) => Parser s m Element @@ -170,7 +178,11 @@ listBlock list_type prefix child_parser_factory nest_level = do optional ((notFollowedBy blockEnding) *> lineEnding) - child <- optional $ child_parser_factory $ nest_level + 1 + -- the try is load bearing, optional only recovers from a failure that + -- consumed nothing and the child parser eats the next item's indentation + -- before finding out it belongs to this list's level rather than the + -- child's + child <- optional $ try $ child_parser_factory $ nest_level + 1 case child of Just c -> pure $ LI {content = [Transparent content, List c mempty]}