commonmark-extensions 0.2.3 → 0.2.3.1
raw patch · 7 files changed
+172/−39 lines, 7 filesdep ~commonmarkPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: commonmark
API changes (from Hackage documentation)
Files
- changelog.md +12/−0
- commonmark-extensions.cabal +1/−1
- src/Commonmark/Extensions/FancyList.hs +43/−15
- src/Commonmark/Extensions/Math.hs +25/−21
- src/Commonmark/Extensions/PipeTable.hs +2/−0
- test/fancy_lists.md +59/−2
- test/math.md +30/−0
changelog.md view
@@ -1,5 +1,17 @@ # Changelog for commonmark-extensions +## 0.2.3.1++- `math` extension: don't fail when display math contains+ embedded inline math. See jgm/pandoc#7942.+- Make math parsing more sophisticated.+ Count embeddings inside `{..}`, since math can contain+ e.g. `\text{...}` which itself contains math delimiters.+- Small improvement in pipe table parsing.+ The old parser failed on some edge cases with extra whitespace+ after pipes (which we should just ignore).+- `fancy_list` extension: improve list type ambiguity resolution (#89).+ ## 0.2.3 - Allow bare word attribute in fenced_divs (#84). This follows a similar
commonmark-extensions.cabal view
@@ -1,5 +1,5 @@ name: commonmark-extensions-version: 0.2.3+version: 0.2.3.1 synopsis: Pure Haskell commonmark parser. description: This library provides some useful extensions to core commonmark
src/Commonmark/Extensions/FancyList.hs view
@@ -29,23 +29,48 @@ fancyOrderedListMarker :: Monad m => BlockParser m il bl ListType fancyOrderedListMarker = do- initialParen <- option False $ True <$ symbol '('- (start, enumtype) <- pDecimal <|>- pLowerRoman <|> pUpperRoman <|>- pLowerAlpha <|> pUpperAlpha- delimtype <- if initialParen- then TwoParens <$ symbol ')'- else Period <$ symbol '.' <|> OneParen <$ symbol ')'- when (delimtype == Period &&- (enumtype == UpperRoman || enumtype == UpperAlpha)) $ do- Tok tt _ t <- lookAhead anyTok- guard $ case tt of- Spaces -> T.length t > 1- LineEnd -> True- _ -> False- return $! OrderedList start enumtype delimtype+ mbListType <- getParentListType+ -- first try to parse an item like the parent+ let pInSeries = case mbListType of+ Just (OrderedList _ e d) -> try (pMarker e d)+ _ -> mzero+ pInSeries <|>+ do initialParen <- option False $ True <$ symbol '('+ (start, enumtype) <- pDecimal <|>+ (case mbListType of+ Nothing -> pLowerRomanOne <|> pUpperRomanOne+ _ -> mzero) <|>+ pLowerAlpha <|> pUpperAlpha <|>+ pLowerRoman <|> pUpperRoman+ delimtype <- if initialParen+ then TwoParens <$ symbol ')'+ else Period <$ symbol '.' <|> OneParen <$ symbol ')'+ when (delimtype == Period &&+ (enumtype == UpperRoman || enumtype == UpperAlpha)) $ checkSpace+ return $! OrderedList start enumtype delimtype where+ checkSpace = do+ Tok tt _ t <- lookAhead anyTok+ guard $ case tt of+ Spaces -> T.length t > 1+ LineEnd -> True+ _ -> False+ pMarker e d = do+ when (d == TwoParens) $ () <$ symbol '('+ (start, enumtype) <- case e of+ Decimal -> pDecimal+ LowerRoman -> pLowerRoman+ UpperRoman -> pUpperRoman+ LowerAlpha -> pLowerAlpha+ UpperAlpha -> pUpperAlpha+ delimtype <- case d of+ TwoParens -> TwoParens <$ symbol ')'+ OneParen -> OneParen <$ symbol ')'+ Period -> Period <$ symbol '.'+ when (delimtype == Period &&+ (enumtype == UpperRoman || enumtype == UpperAlpha)) $ checkSpace+ return $! OrderedList start enumtype delimtype pDecimal = do Tok WordChars _ ds <- satisfyWord (\t -> T.all isDigit t && T.length t < 10)@@ -70,6 +95,9 @@ case T.uncons ds of Nothing -> mzero Just (c,_) -> return $! (1 + ord c - ord 'A', UpperAlpha)++ pLowerRomanOne = (1, LowerRoman) <$ satisfyWord (== "i")+ pUpperRomanOne = (1, UpperRoman) <$ satisfyWord (== "I") pLowerRoman = do Tok WordChars _ ds <- satisfyWord (\t ->
src/Commonmark/Extensions/Math.hs view
@@ -4,6 +4,7 @@ ( HasMath(..) , mathSpec ) where+import Control.Monad (mzero) import Commonmark.Types import Commonmark.Tokens import Commonmark.Syntax@@ -13,6 +14,7 @@ import Commonmark.Html import Text.Parsec import Data.Text (Text)+import qualified Data.Text as T mathSpec :: (Monad m, IsBlock il bl, IsInline il, HasMath il) => SyntaxSpec m il bl@@ -35,26 +37,28 @@ displayMath t = (displayMath t) <$ addName "displayMath" parseMath :: (Monad m, HasMath a) => InlineParser m a-parseMath = pDisplayMath <|> pInlineMath--pInlineMath :: (Monad m, HasMath a) => InlineParser m a-pInlineMath = try $ do- symbol '$'- notFollowedBy whitespace- (_, toks) <- withRaw $ many1 $- choice [ () <$ symbol '\\' >> anyTok- , whitespace >> lookAhead (noneOfToks [Symbol '$'])- , noneOfToks [Symbol '$']- ]+parseMath = try $ do symbol '$'- return $! inlineMath (untokenize toks)+ display <- (True <$ symbol '$') <|> (False <$ notFollowedBy whitespace)+ contents <- try $ untokenize <$> pDollarsMath 0+ if display+ then displayMath contents <$ symbol '$'+ else if T.all (==' ') (T.takeEnd 1 contents)+ -- don't allow math to end with SPACE + $+ then mzero+ else return $ inlineMath contents -pDisplayMath :: (Monad m, HasMath a) => InlineParser m a-pDisplayMath = try $ do- count 2 $ symbol '$'- (_, toks) <- withRaw $ many1 $- choice [ () <$ symbol '\\' >> anyTok- , noneOfToks [Symbol '$']- ]- count 2 $ symbol '$'- return $! displayMath (untokenize toks)+-- Int is number of embedded groupings+pDollarsMath :: Monad m => Int -> InlineParser m [Tok]+pDollarsMath n = do+ tk@(Tok toktype _ _) <- anyTok+ case toktype of+ Symbol '$'+ | n == 0 -> return []+ Symbol '\\' -> do+ tk' <- anyTok+ (tk :) . (tk' :) <$> pDollarsMath n+ Symbol '{' -> (tk :) <$> pDollarsMath (n+1)+ Symbol '}' | n > 0 -> (tk :) <$> pDollarsMath (n-1)+ | otherwise -> mzero+ _ -> (tk :) <$> pDollarsMath n
src/Commonmark/Extensions/PipeTable.hs view
@@ -76,6 +76,7 @@ pCells = try $ do hasPipe <- option False $ True <$ symbol '|' pipedCells <- many (try $ pCell <* symbol '|')+ skipMany $ satisfyTok (hasType Spaces) unpipedCell <- option [] $ (:[]) <$> pCell let cells = pipedCells ++ unpipedCell guard $ not (null cells)@@ -100,6 +101,7 @@ pDividers = try $ do hasPipe <- option False $ True <$ symbol '|' pipedAligns <- many (try $ pDivider <* symbol '|')+ skipMany $ satisfyTok (hasType Spaces) unpipedAlign <- option [] $ (:[]) <$> pDivider let aligns = pipedAligns ++ unpipedAlign guard $ not (null aligns)
test/fancy_lists.md view
@@ -157,8 +157,8 @@ ```````````````````````````````` -Note that with decimal enumerators and Upper Alpha or Upper-Roman style, we require at least two spaces after the list+Note that with Upper Alpha or Upper Roman style list items+followed by periods, we require at least two spaces after the list marker in order to avoid capturing initials: ```````````````````````````````` example@@ -221,3 +221,60 @@ </ol> ```````````````````````````````` +In cases of ambiguity (such as `'v.'`, which could be+lowercase Roman or lowercase alphabetical, we prefer an+interpretation that continues an existing list:++```````````````````````````````` example+u. one+v. two+.+<ol start="21" type="a">+<li>one</li>+<li>two</li>+</ol>+````````````````````````````````++```````````````````````````````` example+iv. one+v. two+.+<ol start="4" type="i">+<li>one</li>+<li>two</li>+</ol>+````````````````````````````````++When ambiguities cannot be resolved this way,+we prefer to interpret `i.` and `I.` as Roman numerals,+and other single letters as alphabetical:++```````````````````````````````` example+i. one+ii. two+.+<ol type="i">+<li>one</li>+<li>two</li>+</ol>+````````````````````````````````++```````````````````````````````` example+I. one+.+<ol type="I">+<li>one</li>+</ol>+````````````````````````````````++```````````````````````````````` example+C. one+CI. one+.+<ol start="3" type="A">+<li>one</li>+</ol>+<ol start="101" type="I">+<li>one</li>+</ol>+````````````````````````````````
test/math.md view
@@ -37,6 +37,27 @@ \]</span></p> ```````````````````````````````` +Note that math can contain embedded math. In scanning+for a closing delimiter, we skip material in balanced+curly braces:++```````````````````````````````` example+This is display math:+$$+\text{Hello $x^2$}+$$+And this is inline math:+$\text{Hello $x$ there!}$+.+<p>This is display math:+<span class="math display">\[+\text{Hello $x^2$}+\]</span>+And this is inline math:+<span class="math inline">\(\text{Hello $x$ there!}\)</span></p>+````````````````````````````````++ To avoid treating currency signs as math delimiters, one may occasionally have to backslash-escape them: @@ -44,6 +65,15 @@ The cost is between \$10 and 30$. . <p>The cost is between $10 and 30$.</p>+````````````````````````````````++Dollar signs must also be backslash-escaped if they+occur within math:++```````````````````````````````` example+$\text{\$}$+.+<p><span class="math inline">\(\text{\$}\)</span></p> ```````````````````````````````` Everthing inside the math construction is treated