git.iko.soy/typeable/pandoc
on master help sign in
Factor out T.P.Readers.LaTeX.Math.
commitd2bb0c7c8d599e6cd2aaef787b207bbfa66d4b9e authorJohn MacFarlane <jgm@berkeley.edu> dateSun 28 Feb 2021, 21:05 (6 years ago) parent5537802
3 files changed+230−193
pandoc.cabal+1 src/Text/Pandoc/Readers/LaTeX.hs+8−193 src/Text/Pandoc/Readers/LaTeX/Math.hs+221
pandoc.cabal+1
@@ -632,6 +632,7 @@ library
632632 Text.Pandoc.Readers.LaTeX.SIunitx,
633633 Text.Pandoc.Readers.LaTeX.Accent,
634634 Text.Pandoc.Readers.LaTeX.Citation,
635+ Text.Pandoc.Readers.LaTeX.Math,
635636 Text.Pandoc.Readers.LaTeX.Table,
636637 Text.Pandoc.Readers.Odt.Base,
637638 Text.Pandoc.Readers.Odt.Namespaces,
src/Text/Pandoc/Readers/LaTeX.hs+8−193
@@ -35,7 +35,6 @@ import Data.List (intercalate)
3535import qualified Data.Map as M
3636import Data.Maybe (fromMaybe, maybeToList)
3737import qualified Data.Set as Set
38−import qualified Data.Sequence as Seq
3938import Data.Text (Text)
4039import qualified Data.Text as T
4140import System.FilePath (addExtension, replaceExtension, takeExtension)
@@ -57,6 +56,11 @@ import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
5756import Text.Pandoc.Readers.LaTeX.Parsing
5857import Text.Pandoc.Readers.LaTeX.Accent (accentCommands)
5958import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
59+import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
60+ inlineEnvironment,
61+ mathDisplay, mathInline,
62+ newtheorem, theoremstyle, proof,
63+ theoremEnvironment)
6064import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
6165import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
6266 babelLangToBCP47, setDefaultLanguage)
@@ -387,39 +391,6 @@ nlToSpace :: Char -> Char
387391nlToSpace '\n' = ' '
388392nlToSpace x = x
389393
390−mathDisplay :: Text -> Inlines
391−mathDisplay = displayMath . trimMath
392−
393−mathInline :: Text -> Inlines
394−mathInline = math . trimMath
395−
396−dollarsMath :: PandocMonad m => LP m Inlines
397−dollarsMath = do
398− symbol '$'
399− display <- option False (True <$ symbol '$')
400− (do contents <- try $ untokenize <$> pDollarsMath 0
401− if display
402− then mathDisplay contents <$ symbol '$'
403− else return $ mathInline contents)
404− <|> (guard display >> return (mathInline ""))
405−
406−-- Int is number of embedded groupings
407−pDollarsMath :: PandocMonad m => Int -> LP m [Tok]
408−pDollarsMath n = do
409− tk@(Tok _ toktype t) <- anyTok
410− case toktype of
411− Symbol | t == "$"
412− , n == 0 -> return []
413− | t == "\\" -> do
414− tk' <- anyTok
415− (tk :) . (tk' :) <$> pDollarsMath n
416− | t == "{" -> (tk :) <$> pDollarsMath (n+1)
417− | t == "}" ->
418− if n > 0
419− then (tk :) <$> pDollarsMath (n-1)
420− else mzero
421− _ -> (tk :) <$> pDollarsMath n
422−
423394inlineCommand' :: PandocMonad m => LP m Inlines
424395inlineCommand' = try $ do
425396 Tok _ (CtrlSeq name) cmd <- anyControlSeq
@@ -452,51 +423,6 @@ unescapeURL = T.concat . go . T.splitOn "\\"
452423 , isEscapable c = t
453424 | otherwise = "\\" <> t
454425
455−mathEnvWith :: PandocMonad m
456− => (Inlines -> a) -> Maybe Text -> Text -> LP m a
457−mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
458− where inner x = case innerEnv of
459− Nothing -> x
460− Just y -> "\\begin{" <> y <> "}\n" <> x <>
461− "\\end{" <> y <> "}"
462−
463−mathEnv :: PandocMonad m => Text -> LP m Text
464−mathEnv name = do
465− skipopts
466− optional blankline
467− res <- manyTill anyTok (end_ name)
468− return $ stripTrailingNewlines $ untokenize res
469−
470−inlineEnvironment :: PandocMonad m => LP m Inlines
471−inlineEnvironment = try $ do
472− controlSeq "begin"
473− name <- untokenize <$> braced
474− M.findWithDefault mzero name inlineEnvironments
475−
476−inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
477−inlineEnvironments = M.fromList [
478− ("displaymath", mathEnvWith id Nothing "displaymath")
479− , ("math", math <$> mathEnv "math")
480− , ("equation", mathEnvWith id Nothing "equation")
481− , ("equation*", mathEnvWith id Nothing "equation*")
482− , ("gather", mathEnvWith id (Just "gathered") "gather")
483− , ("gather*", mathEnvWith id (Just "gathered") "gather*")
484− , ("multline", mathEnvWith id (Just "gathered") "multline")
485− , ("multline*", mathEnvWith id (Just "gathered") "multline*")
486− , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
487− , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
488− , ("align", mathEnvWith id (Just "aligned") "align")
489− , ("align*", mathEnvWith id (Just "aligned") "align*")
490− , ("alignat", mathEnvWith id (Just "aligned") "alignat")
491− , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
492− , ("dmath", mathEnvWith id Nothing "dmath")
493− , ("dmath*", mathEnvWith id Nothing "dmath*")
494− , ("dgroup", mathEnvWith id (Just "aligned") "dgroup")
495− , ("dgroup*", mathEnvWith id (Just "aligned") "dgroup*")
496− , ("darray", mathEnvWith id (Just "aligned") "darray")
497− , ("darray*", mathEnvWith id (Just "aligned") "darray*")
498− ]
499−
500426inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
501427inlineCommands =
502428 M.union inlineLanguageCommands $
@@ -1354,7 +1280,7 @@ blockCommands = M.fromList
13541280 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
13551281 , ("signature", mempty <$ (skipopts *> authors))
13561282 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
1357− , ("newtheorem", newtheorem)
1283+ , ("newtheorem", newtheorem inline)
13581284 , ("theoremstyle", theoremstyle)
13591285 -- KOMA-Script metadata commands
13601286 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -1473,7 +1399,7 @@ environments = M.union (tableEnvironments blocks inline) $
14731399 , ("lilypond", rawVerbEnv "lilypond")
14741400 , ("ly", rawVerbEnv "ly")
14751401 -- amsthm
1476− , ("proof", proof)
1402+ , ("proof", proof blocks opt)
14771403 -- etoolbox
14781404 , ("ifstrequal", ifstrequal)
14791405 , ("newtoggle", braced >>= newToggle)
@@ -1494,128 +1420,17 @@ filecontents = try $ do
14941420 st{ sFileContents = M.insert fp txt (sFileContents st) }
14951421 return mempty
14961422
1497−theoremstyle :: PandocMonad m => LP m Blocks
1498−theoremstyle = do
1499− stylename <- untokenize <$> braced
1500− let mbstyle = case stylename of
1501− "plain" -> Just PlainStyle
1502− "definition" -> Just DefinitionStyle
1503− "remark" -> Just RemarkStyle
1504− _ -> Nothing
1505− case mbstyle of
1506− Nothing -> return ()
1507− Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
1508− return mempty
1509−
1510−newtheorem :: PandocMonad m => LP m Blocks
1511−newtheorem = do
1512− number <- option True (False <$ symbol '*' <* sp)
1513− name <- untokenize <$> braced
1514− sp
1515− series <- option Nothing $ Just . untokenize <$> bracketedToks
1516− sp
1517− showName <- tok
1518− sp
1519− syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
1520− sty <- sLastTheoremStyle <$> getState
1521− let spec = TheoremSpec { theoremName = showName
1522− , theoremStyle = sty
1523− , theoremSeries = series
1524− , theoremSyncTo = syncTo
1525− , theoremNumber = number
1526− , theoremLastNum = DottedNum [0] }
1527− tmap <- sTheoremMap <$> getState
1528− updateState $ \s -> s{ sTheoremMap =
1529− M.insert name spec tmap }
1530− return mempty
1531−
1532−proof :: PandocMonad m => LP m Blocks
1533−proof = do
1534− title <- option (B.text "Proof") opt
1535− bs <- env "proof" blocks
1536− return $
1537− B.divWith ("", ["proof"], []) $
1538− addQed $ addTitle (B.emph (title <> ".")) bs
1539−
1540−addTitle :: Inlines -> Blocks -> Blocks
1541−addTitle ils bs =
1542− case B.toList bs of
1543− (Para xs : rest)
1544− -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
1545− _ -> B.para ils <> bs
1546−
1547−addQed :: Blocks -> Blocks
1548−addQed bs =
1549− case Seq.viewr (B.unMany bs) of
1550− s Seq.:> Para ils
1551− -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
1552− _ -> bs <> B.para qedSign
1553− where
1554− qedSign = B.str "\xa0\x25FB"
1555−
15561423environment :: PandocMonad m => LP m Blocks
15571424environment = try $ do
15581425 controlSeq "begin"
15591426 name <- untokenize <$> braced
15601427 M.findWithDefault mzero name environments <|>
1561− theoremEnvironment name <|>
1428+ theoremEnvironment blocks opt name <|>
15621429 if M.member name (inlineEnvironments
15631430 :: M.Map Text (LP PandocPure Inlines))
15641431 then mzero
15651432 else try (rawEnv name) <|> rawVerbEnv name
15661433
1567−theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
1568−theoremEnvironment name = do
1569− tmap <- sTheoremMap <$> getState
1570− case M.lookup name tmap of
1571− Nothing -> mzero
1572− Just tspec -> do
1573− optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
1574− mblabel <- option Nothing $ Just . untokenize <$>
1575− try (spaces >> controlSeq "label" >> spaces >> braced)
1576− bs <- env name blocks
1577− number <-
1578− if theoremNumber tspec
1579− then do
1580− let name' = fromMaybe name $ theoremSeries tspec
1581− num <- getNextNumber
1582− (maybe (DottedNum [0]) theoremLastNum .
1583− M.lookup name' . sTheoremMap)
1584− updateState $ \s ->
1585− s{ sTheoremMap =
1586− M.adjust
1587− (\spec -> spec{ theoremLastNum = num })
1588− name'
1589− (sTheoremMap s)
1590− }
1591−
1592− case mblabel of
1593− Just ident ->
1594− updateState $ \s ->
1595− s{ sLabels = M.insert ident
1596− (B.toList $
1597− theoremName tspec <> "\160" <>
1598− str (renderDottedNum num)) (sLabels s) }
1599− Nothing -> return ()
1600− return $ space <> B.text (renderDottedNum num)
1601− else return mempty
1602− let titleEmph = case theoremStyle tspec of
1603− PlainStyle -> B.strong
1604− DefinitionStyle -> B.strong
1605− RemarkStyle -> B.emph
1606− let title = titleEmph (theoremName tspec <> number)
1607− <> optTitle <> "." <> space
1608− return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
1609− $ case theoremStyle tspec of
1610− PlainStyle -> walk italicize bs
1611− _ -> bs
1612−
1613−italicize :: Block -> Block
1614−italicize x@(Para [Image{}]) = x -- see #6925
1615−italicize (Para ils) = Para [Emph ils]
1616−italicize (Plain ils) = Plain [Emph ils]
1617−italicize x = x
1618−
16191434rawEnv :: PandocMonad m => Text -> LP m Blocks
16201435rawEnv name = do
16211436 exts <- getOption readerExtensions
src/Text/Pandoc/Readers/LaTeX/Math.hsnew file+221
@@ -0,0 +1,221 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Text.Pandoc.Readers.LaTeX.Math
3+ ( dollarsMath
4+ , inlineEnvironments
5+ , inlineEnvironment
6+ , mathInline
7+ , mathDisplay
8+ , theoremstyle
9+ , theoremEnvironment
10+ , newtheorem
11+ , proof
12+ )
13+where
14+import Data.Maybe (fromMaybe)
15+import Text.Pandoc.Walk (walk)
16+import Text.Pandoc.Builder as B
17+import qualified Data.Sequence as Seq
18+import Text.Pandoc.Readers.LaTeX.Parsing
19+import Text.Pandoc.Readers.LaTeX.Types
20+import Text.Pandoc.Class
21+import Text.Pandoc.Shared (trimMath, stripTrailingNewlines)
22+import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
23+ optional, space, spaces, withRaw, (<|>))
24+import Control.Applicative ((<|>), optional)
25+import Control.Monad (guard, mzero)
26+import qualified Data.Map as M
27+import Data.Text (Text)
28+
29+dollarsMath :: PandocMonad m => LP m Inlines
30+dollarsMath = do
31+ symbol '$'
32+ display <- option False (True <$ symbol '$')
33+ (do contents <- try $ untokenize <$> pDollarsMath 0
34+ if display
35+ then mathDisplay contents <$ symbol '$'
36+ else return $ mathInline contents)
37+ <|> (guard display >> return (mathInline ""))
38+
39+-- Int is number of embedded groupings
40+pDollarsMath :: PandocMonad m => Int -> LP m [Tok]
41+pDollarsMath n = do
42+ tk@(Tok _ toktype t) <- anyTok
43+ case toktype of
44+ Symbol | t == "$"
45+ , n == 0 -> return []
46+ | t == "\\" -> do
47+ tk' <- anyTok
48+ (tk :) . (tk' :) <$> pDollarsMath n
49+ | t == "{" -> (tk :) <$> pDollarsMath (n+1)
50+ | t == "}" ->
51+ if n > 0
52+ then (tk :) <$> pDollarsMath (n-1)
53+ else mzero
54+ _ -> (tk :) <$> pDollarsMath n
55+
56+mathDisplay :: Text -> Inlines
57+mathDisplay = displayMath . trimMath
58+
59+mathInline :: Text -> Inlines
60+mathInline = math . trimMath
61+
62+mathEnvWith :: PandocMonad m
63+ => (Inlines -> a) -> Maybe Text -> Text -> LP m a
64+mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
65+ where inner x = case innerEnv of
66+ Nothing -> x
67+ Just y -> "\\begin{" <> y <> "}\n" <> x <>
68+ "\\end{" <> y <> "}"
69+
70+mathEnv :: PandocMonad m => Text -> LP m Text
71+mathEnv name = do
72+ skipopts
73+ optional blankline
74+ res <- manyTill anyTok (end_ name)
75+ return $ stripTrailingNewlines $ untokenize res
76+
77+inlineEnvironment :: PandocMonad m => LP m Inlines
78+inlineEnvironment = try $ do
79+ controlSeq "begin"
80+ name <- untokenize <$> braced
81+ M.findWithDefault mzero name inlineEnvironments
82+
83+inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
84+inlineEnvironments = M.fromList [
85+ ("displaymath", mathEnvWith id Nothing "displaymath")
86+ , ("math", math <$> mathEnv "math")
87+ , ("equation", mathEnvWith id Nothing "equation")
88+ , ("equation*", mathEnvWith id Nothing "equation*")
89+ , ("gather", mathEnvWith id (Just "gathered") "gather")
90+ , ("gather*", mathEnvWith id (Just "gathered") "gather*")
91+ , ("multline", mathEnvWith id (Just "gathered") "multline")
92+ , ("multline*", mathEnvWith id (Just "gathered") "multline*")
93+ , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
94+ , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
95+ , ("align", mathEnvWith id (Just "aligned") "align")
96+ , ("align*", mathEnvWith id (Just "aligned") "align*")
97+ , ("alignat", mathEnvWith id (Just "aligned") "alignat")
98+ , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
99+ , ("dmath", mathEnvWith id Nothing "dmath")
100+ , ("dmath*", mathEnvWith id Nothing "dmath*")
101+ , ("dgroup", mathEnvWith id (Just "aligned") "dgroup")
102+ , ("dgroup*", mathEnvWith id (Just "aligned") "dgroup*")
103+ , ("darray", mathEnvWith id (Just "aligned") "darray")
104+ , ("darray*", mathEnvWith id (Just "aligned") "darray*")
105+ ]
106+
107+theoremstyle :: PandocMonad m => LP m Blocks
108+theoremstyle = do
109+ stylename <- untokenize <$> braced
110+ let mbstyle = case stylename of
111+ "plain" -> Just PlainStyle
112+ "definition" -> Just DefinitionStyle
113+ "remark" -> Just RemarkStyle
114+ _ -> Nothing
115+ case mbstyle of
116+ Nothing -> return ()
117+ Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
118+ return mempty
119+
120+newtheorem :: PandocMonad m => LP m Inlines -> LP m Blocks
121+newtheorem inline = do
122+ number <- option True (False <$ symbol '*' <* sp)
123+ name <- untokenize <$> braced
124+ sp
125+ series <- option Nothing $ Just . untokenize <$> bracketedToks
126+ sp
127+ showName <- tokWith inline
128+ sp
129+ syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
130+ sty <- sLastTheoremStyle <$> getState
131+ let spec = TheoremSpec { theoremName = showName
132+ , theoremStyle = sty
133+ , theoremSeries = series
134+ , theoremSyncTo = syncTo
135+ , theoremNumber = number
136+ , theoremLastNum = DottedNum [0] }
137+ tmap <- sTheoremMap <$> getState
138+ updateState $ \s -> s{ sTheoremMap =
139+ M.insert name spec tmap }
140+ return mempty
141+
142+theoremEnvironment :: PandocMonad m
143+ => LP m Blocks -> LP m Inlines -> Text -> LP m Blocks
144+theoremEnvironment blocks opt name = do
145+ tmap <- sTheoremMap <$> getState
146+ case M.lookup name tmap of
147+ Nothing -> mzero
148+ Just tspec -> do
149+ optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
150+ mblabel <- option Nothing $ Just . untokenize <$>
151+ try (spaces >> controlSeq "label" >> spaces >> braced)
152+ bs <- env name blocks
153+ number <-
154+ if theoremNumber tspec
155+ then do
156+ let name' = fromMaybe name $ theoremSeries tspec
157+ num <- getNextNumber
158+ (maybe (DottedNum [0]) theoremLastNum .
159+ M.lookup name' . sTheoremMap)
160+ updateState $ \s ->
161+ s{ sTheoremMap =
162+ M.adjust
163+ (\spec -> spec{ theoremLastNum = num })
164+ name'
165+ (sTheoremMap s)
166+ }
167+
168+ case mblabel of
169+ Just ident ->
170+ updateState $ \s ->
171+ s{ sLabels = M.insert ident
172+ (B.toList $
173+ theoremName tspec <> "\160" <>
174+ str (renderDottedNum num)) (sLabels s) }
175+ Nothing -> return ()
176+ return $ space <> B.text (renderDottedNum num)
177+ else return mempty
178+ let titleEmph = case theoremStyle tspec of
179+ PlainStyle -> B.strong
180+ DefinitionStyle -> B.strong
181+ RemarkStyle -> B.emph
182+ let title = titleEmph (theoremName tspec <> number)
183+ <> optTitle <> "." <> space
184+ return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
185+ $ case theoremStyle tspec of
186+ PlainStyle -> walk italicize bs
187+ _ -> bs
188+
189+
190+
191+proof :: PandocMonad m => LP m Blocks -> LP m Inlines -> LP m Blocks
192+proof blocks opt = do
193+ title <- option (B.text "Proof") opt
194+ bs <- env "proof" blocks
195+ return $
196+ B.divWith ("", ["proof"], []) $
197+ addQed $ addTitle (B.emph (title <> ".")) bs
198+
199+addTitle :: Inlines -> Blocks -> Blocks
200+addTitle ils bs =
201+ case B.toList bs of
202+ (Para xs : rest)
203+ -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
204+ _ -> B.para ils <> bs
205+
206+addQed :: Blocks -> Blocks
207+addQed bs =
208+ case Seq.viewr (B.unMany bs) of
209+ s Seq.:> Para ils
210+ -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
211+ _ -> bs <> B.para qedSign
212+ where
213+ qedSign = B.str "\xa0\x25FB"
214+
215+italicize :: Block -> Block
216+italicize x@(Para [Image{}]) = x -- see #6925
217+italicize (Para ils) = Para [Emph ils]
218+italicize (Plain ils) = Plain [Emph ils]
219+italicize x = x
220+
221+