packages feed

mmark 0.0.5.0 → 0.0.5.1

raw patch · 5 files changed

+91/−14 lines, 5 files

Files

CHANGELOG.md view
@@ -1,3 +1,17 @@+## MMark 0.0.5.1++* The parser can now recover from block-level parse errors in tables and+  continue parsing.++* Pipes in code spans in table cells are not considered as table cell+  delimiters anymore.++* Table sub-parser now faster rejects inputs that do not look like a table,+  this improves overall performance.++* Better handling of the cases when a block can be interpreted as a list and+  as a table at the same time.+ ## MMark 0.0.5.0  * Documentation improvements.
README.md view
@@ -268,11 +268,11 @@  Library             | Parsing library     | Execution time | Allocated   | Max residency --------------------|---------------------|---------------:|------------:|-------------:-`cmark-0.5.6`       | Custom C code       |       316.1 μs |     228,440 |         9,608-`mmark-0.0.4.3`     | Megaparsec          |       7.280 ms |  32,207,640 |        37,856-`cheapskate-0.1.1`  | Custom Haskell code |       10.30 ms |  44,686,272 |       799,200-`markdown-0.1.16` † | Attoparsec          |       13.58 ms |  69,261,816 |       699,656-`pandoc-2.0.5`      | Parsec              |       36.04 ms | 141,868,840 |     1,471,080+`cmark-0.5.6`       | Custom C code       |       323.4 μs |     228,440 |         9,608+`mmark-0.0.5.1`     | Megaparsec          |       7.027 ms |  26,180,272 |        37,792+`cheapskate-0.1.1`  | Custom Haskell code |       10.76 ms |  44,686,272 |       799,200+`markdown-0.1.16` † | Attoparsec          |       14.13 ms |  69,261,816 |       699,656+`pandoc-2.0.5`      | Parsec              |       37.90 ms | 141,868,840 |     1,471,080  *Results are ordered from fastest to slowest.* 
Text/MMark/Parser.hs view
@@ -170,11 +170,11 @@         [ Just <$> pThematicBreak         , Just <$> pAtxHeading         , Just <$> pFencedCodeBlock+        , Just <$> pTable         , Just <$> pUnorderedList         , Just <$> pOrderedList         , Just <$> pBlockquote         , pReferenceDef-        , Just <$> pTable         , Just <$> pParagraph ]       _  ->           Just <$> pIndentedCodeBlock@@ -441,6 +441,8 @@ pTable :: BParser (Block Isp) pTable = do   (n, headerRow) <- try $ do+    pos <- L.indentLevel+    option False (T.any (== '|') <$> lookAhead nonEmptyLine) >>= guard     let pipe' = option False (True <$ pipe)     l <- pipe'     headerRow <- NE.sepBy1 cell (try (pipe <* notFollowedBy eol))@@ -448,18 +450,22 @@     let n = NE.length headerRow     guard (n > 1 || l || r)     eol <* sc'+    L.indentLevel >>= \i -> guard (i == pos || i == (pos <> pos1))     lookAhead nonEmptyLine >>= guard . isHeaderLike     return (n, headerRow)-  caligns <- rowWrapper (NE.fromList <$> sepByCount n calign pipe)-  otherRows <- many $ do-    lookAhead (option True (isBlank <$> nonEmptyLine)) >>= guard . not-    rowWrapper (NE.fromList <$> sepByCount n cell pipe)-  Table caligns (headerRow :| otherRows) <$ sc+  withRecovery recover $ do+    sc'+    caligns <- rowWrapper (NE.fromList <$> sepByCount n calign pipe)+    otherRows <- many $ do+      endOfTable >>= guard . not+      rowWrapper (NE.fromList <$> sepByCount n cell pipe)+    Table caligns (headerRow :| otherRows) <$ sc   where     cell = do       startPos <- getPosition       txt      <- fmap (T.stripEnd . T.pack) . foldMany' . choice $         [ (++) . T.unpack <$> hidden (string "\\|")+        , (++) . T.unpack <$> pCodeSpanB         , (:) <$> label "inline content" (satisfy cellChar) ]       return (IspSpan startPos txt)     cellChar x = x /= '|' && notNewline x@@ -488,6 +494,13 @@       8 % 10     isHeaderConstituent x =       isSpace x || x == '|' || x == '-' || x == ':'+    endOfTable =+      lookAhead (option True (isBlank <$> nonEmptyLine))+    recover err =+      Naked (IspError (replaceEof "end of table block" err)) <$+        manyTill+          (optional nonEmptyLine)+          (endOfTable >>= guard) <* sc  -- | Parse a paragraph or naked text (is some cases). @@ -530,6 +543,23 @@     (IspSpan startPos (assembleParagraph (l:ls []))) <$ sc  ----------------------------------------------------------------------------+-- Auxiliary block-level parsers++-- | 'match' a code span, this is a specialised and adjusted version of+-- 'pCodeSpan'.++pCodeSpanB :: BParser Text+pCodeSpanB = fmap fst . match . hidden $ do+  n <- try (length <$> some (char '`'))+  let finalizer = try $ do+        void $ count n (char '`')+        notFollowedBy (char '`')+  skipManyTill (label "code span content" $+                  takeWhile1P Nothing (== '`') <|>+                  takeWhile1P Nothing (\x -> x /= '`' && notNewline x))+    finalizer++---------------------------------------------------------------------------- -- Inline parser  -- | The top level inline parser.@@ -581,6 +611,8 @@             else pPlain  -- | Parse a code span.+--+-- See also: 'pCodeSpanB'.  pCodeSpan :: IParser Inline pCodeSpan = do
mmark.cabal view
@@ -1,5 +1,5 @@ name:                 mmark-version:              0.0.5.0+version:              0.0.5.1 cabal-version:        >= 1.18 tested-with:          GHC==7.10.3, GHC==8.0.2, GHC==8.2.2 license:              BSD3
tests/Text/MMarkSpec.hs view
@@ -1805,7 +1805,7 @@         let o = "<table>\n<thead>\n<tr><th>Foo</th></tr>\n</thead>\n<tbody>\n<tr><td>foo</td></tr>\n</tbody>\n</table>\n"         "|Foo\n---\nfoo" ==-> o         "Foo|\n---\nfoo" ==-> o-        "| Foo |\n  ---  \n  foo  " ==-> o+        "| Foo |\n ---  \n  foo  " ==-> o         "| Foo |\n| --- |\n| foo |" ==-> o       it "reports correct parse errors when parsing the header line" $         (let s = "Foo | Bar\na-- | ---"@@ -1824,7 +1824,7 @@           "<p>Foo | Bar\nab- | ---</p>\n"       it "demands that number of columns in rows match number of columns in header" $         (let s = "Foo | Bar | Baz\n--- | --- | ---\nfoo | bar"-         in s ~-> err (posN 41 s) (ueof <> etok '|' <> eic))+         in s ~-> err (posN 41 s) (ulabel "end of table block" <> etok '|' <> eic))         >>         (let s = "Foo | Bar | Baz\n--- | --- | ---\nfoo | bar\n\nHere it goes."          in s ~-> err (posN 41 s) (utok '\n' <> etok '|' <> eic))@@ -1837,6 +1837,21 @@       it "escaped pipes do not fool position tracking" $         let s = "Foo | Bar\n--- | ---\n\\| *fo | bar"         in s ~-> err (posN 26 s) (ueib <> etok '*' <> elabel "inline content")+      it "pipes in code spans in headers do not fool the parser" $+        "`|Foo|` | `|Bar|`\n--- | ---\nfoo | bar" ==->+          "<table>\n<thead>\n<tr><th><code>|Foo|</code></th><th><code>|Bar|</code></th></tr>\n</thead>\n<tbody>\n<tr><td>foo</td><td>bar</td></tr>\n</tbody>\n</table>\n"+      it "pipes in code spans in cells do not fool the parser" $+        "Foo | Bar\n--- | ---\n`|foo|` | `|bar|`" ==->+          "<table>\n<thead>\n<tr><th>Foo</th><th>Bar</th></tr>\n</thead>\n<tbody>\n<tr><td><code>|foo|</code></td><td><code>|bar|</code></td></tr>\n</tbody>\n</table>\n"+      it "multi-line code spans are disallowed in table headers" $+        "`Foo\nBar` | Bar\n--- | ---\nfoo | bar" ==->+          "<p><code>Foo Bar</code> | Bar\n--- | ---\nfoo | bar</p>\n"+      it "multi-line code spans are disallowed in table cells" $+        let s = "Foo | Bar\n--- | ---\n`foo\nbar` | bar"+        in s ~~->+           [ err (posN 24 s) (utok '\n' <> etok '`' <> elabel "code span content")+           , err (posN 35 s) (ueib <> etok '`' <> elabel "code span content")+           ]       it "parses tables with just header row" $         "Foo | Bar\n--- | ---" ==->           "<table>\n<thead>\n<tr><th>Foo</th><th>Bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n"@@ -1849,6 +1864,22 @@            [ err (posN 10 s) (ueib <> etok '*' <> eic)            , err (posN 26 s) (ueib <> etok '_' <> eic)            , errFancy (posN 32 s) (nonFlanking "_") ]+      it "tables have higher precedence than unordered lists" $ do+        "+ foo | bar\n------|----\n" ==->+          "<table>\n<thead>\n<tr><th>+ foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n"+        "+ foo | bar\n -----|----\n" ==->+          "<table>\n<thead>\n<tr><th>+ foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n"+      it "tables have higher precedence than ordered lists" $ do+        "1. foo | bar\n-------|----\n" ==->+          "<table>\n<thead>\n<tr><th>1. foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n"+        "1. foo | bar\n ------|----\n" ==->+          "<table>\n<thead>\n<tr><th>1. foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n"+      it "if table is indented inside unordered list, it's put there" $+        "+ foo | bar\n  ----|----\n" ==->+          "<ul>\n<li>\n<table>\n<thead>\n<tr><th>foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n</li>\n</ul>\n"+      it "if table is indented inside ordered list, it's put there" $+        "1. foo | bar\n   ----|----\n" ==->+          "<ol>\n<li>\n<table>\n<thead>\n<tr><th>foo</th><th>bar</th></tr>\n</thead>\n<tbody>\n</tbody>\n</table>\n</li>\n</ol>\n"       it "renders a comprehensive table correctly" $         withFiles "data/table.md" "data/table.html"     context "multiple parse errors" $ do