commonmark-extensions 0.2.3.5 → 0.2.3.6
raw patch · 6 files changed
+121/−46 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- changelog.md +14/−0
- commonmark-extensions.cabal +1/−1
- src/Commonmark/Extensions/Math.hs +2/−1
- src/Commonmark/Extensions/PipeTable.hs +51/−43
- test/math.md +5/−1
- test/pipe_tables.md +48/−0
changelog.md view
@@ -1,5 +1,19 @@ # Changelog for commonmark-extensions +## 0.2.3.6++ * Fix pipe table parser so that `|`s don't interfere with+ other block structures (Michael Howell, #111, fixing #52 and+ #95). This parser is structured as a system that parses the+ *second* line first, then parses the first line. That is, if+ it detects a delimiter row as the second line of a+ paragraph, it converts the paragraph into a table. This+ seems counterintuitive, but it works better than trying to+ convert a table into a paragraph, since it might need to be+ something else.++ * Improve parsing of inline math (#110).+ ## 0.2.3.5 - Resolve entities inside wikilinks (#105, Michał Kukieła).
commonmark-extensions.cabal view
@@ -1,5 +1,5 @@ name: commonmark-extensions-version: 0.2.3.5+version: 0.2.3.6 synopsis: Pure Haskell commonmark parser. description: This library provides some useful extensions to core commonmark
src/Commonmark/Extensions/Math.hs view
@@ -41,9 +41,10 @@ symbol '$' display <- (True <$ symbol '$') <|> (False <$ notFollowedBy whitespace) contents <- try $ untokenize <$> pDollarsMath 0+ let isWs c = c == ' ' || c == '\t' || c == '\r' || c == '\n' if display then displayMath contents <$ symbol '$'- else if T.all (==' ') (T.takeEnd 1 contents)+ else if T.null contents || isWs (T.last contents) -- don't allow math to end with SPACE + $ then mzero else return $ inlineMath contents
src/Commonmark/Extensions/PipeTable.hs view
@@ -12,7 +12,8 @@ ) where -import Control.Monad (guard)+import Control.Monad (guard, void, mzero)+import Control.Monad.Trans.Class (lift) import Commonmark.Syntax import Commonmark.Types import Commonmark.Tokens@@ -137,30 +138,55 @@ { syntaxBlockSpecs = [pipeTableBlockSpec] } +-- This parser is structured as a system that parses the *second* line first,+-- then parses the first line. That is, if it detects a delimiter row as the+-- second line of a paragraph, it converts the paragraph into a table. This seems+-- counterintuitive, but it works better than trying to convert a table into+-- a paragraph, since it might need to be something else.+--+-- See GH-52 and GH-95 pipeTableBlockSpec :: (Monad m, IsBlock il bl, IsInline il, HasPipeTable il bl) => BlockSpec m il bl pipeTableBlockSpec = BlockSpec { blockType = "PipeTable" -- :: Text , blockStart = try $ do -- :: BlockParser m il bl ()- interruptsParagraph >>= guard . not- nonindentSpaces- notFollowedBy whitespace- pos <- getPosition- (cells, toks) <- withRaw pCells- nl <- lookAhead lineEnd- let tabledata = PipeTableData- { pipeTableAlignments = []- , pipeTableHeaders = cells- , pipeTableRows = []- }- addNodeToStack $- Node (defBlockData pipeTableBlockSpec){- blockStartPos = [pos]- , blockData = toDyn tabledata- , blockLines = [toks ++ [nl]]- } []- return BlockStartMatch+ (cur:rest) <- nodeStack <$> getState+ guard $ blockParagraph (bspec cur)+ nonindentSpaces+ pos <- getPosition+ aligns <- pDividers+ skipWhile (hasType Spaces)+ lookAhead (eof <|> void lineEnd)++ st <- getState++ let headerLine =+ case blockLines $ rootLabel cur of+ [onlyLine] -> onlyLine+ _ -> []++ cellsR <- lift $ runParserT pCells st "" headerLine+ case cellsR of+ Right cells ->+ if length cells /= length aligns+ then mzero -- parse fail: not a table+ else do+ updateState $ \st' -> st'{ nodeStack = rest }+ let tabledata = PipeTableData+ { pipeTableAlignments = aligns+ , pipeTableHeaders = cells+ , pipeTableRows = []+ }+ addNodeToStack $+ Node (defBlockData pipeTableBlockSpec){+ blockStartPos = blockStartPos (rootLabel cur) ++ [pos]+ , blockData = toDyn tabledata+ , blockAttributes = blockAttributes (rootLabel cur)+ } []+ _ ->+ mzero -- parse fail: not a table+ return BlockStartMatch , blockCanContain = \_ -> False -- :: BlockSpec m il bl -> Bool , blockContainsLines = False -- :: Bool , blockParagraph = False -- :: Bool@@ -173,26 +199,11 @@ , pipeTableHeaders = [] , pipeTableRows = [] } pos <- getPosition- if null (blockLines ndata)- then do- cells <- pCells- let tabledata' = tabledata{ pipeTableRows =- cells : pipeTableRows tabledata }- return $! (pos, Node ndata{ blockData =- toDyn tabledata' } children)- else- -- last line was first; check for separators- -- and if not found, convert to paragraph:- try (do aligns <- pDividers- guard $ length aligns ==- length (pipeTableHeaders tabledata)- let tabledata' = tabledata{ pipeTableAlignments = aligns }- return $! (pos, Node ndata{- blockLines = []- , blockData = toDyn tabledata'- } children))- <|> (return $! (pos, Node ndata{- blockSpec = paraSpec } children))+ cells <- pCells+ let tabledata' = tabledata{ pipeTableRows =+ cells : pipeTableRows tabledata }+ return $! (pos, Node ndata{ blockData =+ toDyn tabledata' } children) , blockConstructor = \(Node ndata _) -> do let tabledata = fromDyn (blockData ndata)@@ -206,8 +217,5 @@ (reverse $ pipeTableRows tabledata) return $! (pipeTable aligns headers rows) , blockFinalize = \(Node ndata children) parent ->- defaultFinalizer- (if null (blockLines ndata)- then Node ndata children- else Node ndata{ blockSpec = paraSpec } children) parent+ defaultFinalizer (Node ndata children) parent }
test/math.md view
@@ -18,9 +18,13 @@ ```````````````````````````````` example This is not math: 2000$. And neither is this $ 4 $.+Or this $4+$. . <p>This is not math: 2000$.-And neither is this $ 4 $.</p>+And neither is this $ 4 $.+Or this $4+$.</p> ```````````````````````````````` Display math delimiters can be surrounded by whitespace:
test/pipe_tables.md view
@@ -264,3 +264,51 @@ </code></pre> ```````````````````````````````` ++Pipe tables have exactly one header row, and do not interrupt paragraphs.++```````````````````````````````` example+| Too much table | to be considered table |+| Too much table | to be considered table |+|----------------|------------------------|+| Too much table | to be considered table |+.+<p>| Too much table | to be considered table |+| Too much table | to be considered table |+|----------------|------------------------|+| Too much table | to be considered table |</p>+````````````````````````````````+++Other block structures, like headers, have higher priority than tables.+Tables can be nested in other elements, but don't benefit from laziness.++```````````````````````````````` example+# abc | def+------|-----+++> abc | def+> ----|-----+++> abc | def+----|-----+.+<h1>abc | def</h1>+<p>------|-----</p>+<blockquote>+<table>+<thead>+<tr>+<th>abc</th>+<th>def</th>+</tr>+</thead>+</table>+</blockquote>+<blockquote>+<p>abc | def+----|-----</p>+</blockquote>+````````````````````````````````