Skip to content

Commit

Permalink
Handle pipes in code spans in table cells correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkkrp committed Jan 19, 2018
1 parent def30fc commit 39ea64c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,9 @@
* 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.

## MMark 0.0.5.0

* Documentation improvements.
Expand Down
20 changes: 20 additions & 0 deletions Text/MMark/Parser.hs
Expand Up @@ -462,6 +462,7 @@ pTable = 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
Expand Down Expand Up @@ -538,6 +539,23 @@ pParagraph = do
(if allowNaked then toBlock else Paragraph)
(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
(takeWhile1P Nothing (== '`') <|>
takeWhile1P Nothing (\x -> x /= '`' && notNewline x))
finalizer

----------------------------------------------------------------------------
-- Inline parser

Expand Down Expand Up @@ -590,6 +608,8 @@ pInlines = do
else pPlain

-- | Parse a code span.
--
-- See also: 'pCodeSpanB'.

pCodeSpan :: IParser Inline
pCodeSpan = do
Expand Down
15 changes: 15 additions & 0 deletions tests/Text/MMarkSpec.hs
Expand Up @@ -1837,6 +1837,21 @@ spec = parallel $ do
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 '`')
, 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"
Expand Down

0 comments on commit 39ea64c

Please sign in to comment.