git.iko.soy/typeable/pandoc
on master help sign in
Factor out T.P.Readers.LaTeX.Macro.
commit382f0e23d22b15aaa9fe2aeb6117ef0a102e379d authorJohn MacFarlane <jgm@berkeley.edu> dateMon 1 Mar 2021, 08:55 (6 years ago) parente1454fe
3 files changed+156−139
pandoc.cabal+1 src/Text/Pandoc/Readers/LaTeX.hs+2−139 src/Text/Pandoc/Readers/LaTeX/Macro.hs+153
pandoc.cabal+1
@@ -634,6 +634,7 @@ library
634634 Text.Pandoc.Readers.LaTeX.Citation,
635635 Text.Pandoc.Readers.LaTeX.Math,
636636 Text.Pandoc.Readers.LaTeX.Table,
637+ Text.Pandoc.Readers.LaTeX.Macro,
637638 Text.Pandoc.Readers.Odt.Base,
638639 Text.Pandoc.Readers.Odt.Namespaces,
639640 Text.Pandoc.Readers.Odt.StyleReader,
src/Text/Pandoc/Readers/LaTeX.hs+2−139
@@ -47,8 +47,7 @@ import Text.Pandoc.Logging
4747import Text.Pandoc.Options
4848import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
4949 optional, space, spaces, withRaw, (<|>))
50−import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
51− ArgSpec (..), Tok (..), TokType (..))
50+import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
5251import Text.Pandoc.Readers.LaTeX.Parsing
5352import Text.Pandoc.Readers.LaTeX.Accent (accentCommands)
5453import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
@@ -58,6 +57,7 @@ import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
5857 newtheorem, theoremstyle, proof,
5958 theoremEnvironment)
6059import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
60+import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
6161import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
6262 babelLangToBCP47, setDefaultLanguage)
6363import Text.Pandoc.Readers.LaTeX.SIunitx (siunitxCommands)
@@ -1027,143 +1027,6 @@ authors = try $ do
10271027 egroup
10281028 addMeta "author" (map trimInlines auths)
10291029
1030−macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1031−macroDef constructor = do
1032− (_, s) <- withRaw (commandDef <|> environmentDef)
1033− (constructor (untokenize s) <$
1034− guardDisabled Ext_latex_macros)
1035− <|> return mempty
1036− where commandDef = do
1037− (name, macro') <- newcommand <|> letmacro <|> defmacro
1038− guardDisabled Ext_latex_macros <|>
1039− updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1040− environmentDef = do
1041− mbenv <- newenvironment
1042− case mbenv of
1043− Nothing -> return ()
1044− Just (name, macro1, macro2) ->
1045− guardDisabled Ext_latex_macros <|>
1046− do updateState $ \s -> s{ sMacros =
1047− M.insert name macro1 (sMacros s) }
1048− updateState $ \s -> s{ sMacros =
1049− M.insert ("end" <> name) macro2 (sMacros s) }
1050− -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1051− -- is equivalent to
1052− -- @\newcommand{\envname}[n-args][default]{begin}@
1053− -- @\newcommand{\endenvname}@
1054−
1055−letmacro :: PandocMonad m => LP m (Text, Macro)
1056−letmacro = do
1057− controlSeq "let"
1058− (name, contents) <- withVerbatimMode $ do
1059− Tok _ (CtrlSeq name) _ <- anyControlSeq
1060− optional $ symbol '='
1061− spaces
1062− -- we first parse in verbatim mode, and then expand macros,
1063− -- because we don't want \let\foo\bar to turn into
1064− -- \let\foo hello if we have previously \def\bar{hello}
1065− contents <- bracedOrToken
1066− return (name, contents)
1067− contents' <- doMacros' 0 contents
1068− return (name, Macro ExpandWhenDefined [] Nothing contents')
1069−
1070−defmacro :: PandocMonad m => LP m (Text, Macro)
1071−defmacro = try $
1072− -- we use withVerbatimMode, because macros are to be expanded
1073− -- at point of use, not point of definition
1074− withVerbatimMode $ do
1075− controlSeq "def"
1076− Tok _ (CtrlSeq name) _ <- anyControlSeq
1077− argspecs <- many (argspecArg <|> argspecPattern)
1078− contents <- bracedOrToken
1079− return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1080−
1081−argspecArg :: PandocMonad m => LP m ArgSpec
1082−argspecArg = do
1083− Tok _ (Arg i) _ <- satisfyTok isArgTok
1084− return $ ArgNum i
1085−
1086−argspecPattern :: PandocMonad m => LP m ArgSpec
1087−argspecPattern =
1088− Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1089− (toktype' == Symbol || toktype' == Word) &&
1090− (txt /= "{" && txt /= "\\" && txt /= "}")))
1091−
1092−newcommand :: PandocMonad m => LP m (Text, Macro)
1093−newcommand = do
1094− pos <- getPosition
1095− Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1096− controlSeq "renewcommand" <|>
1097− controlSeq "providecommand" <|>
1098− controlSeq "DeclareMathOperator" <|>
1099− controlSeq "DeclareRobustCommand"
1100− withVerbatimMode $ do
1101− Tok _ (CtrlSeq name) txt <- do
1102− optional (symbol '*')
1103− anyControlSeq <|>
1104− (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1105− spaces
1106− numargs <- option 0 $ try bracketedNum
1107− let argspecs = map ArgNum [1..numargs]
1108− spaces
1109− optarg <- option Nothing $ Just <$> try bracketedToks
1110− spaces
1111− contents' <- bracedOrToken
1112− let contents =
1113− case mtype of
1114− "DeclareMathOperator" ->
1115− Tok pos (CtrlSeq "mathop") "\\mathop"
1116− : Tok pos Symbol "{"
1117− : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1118− : Tok pos Symbol "{"
1119− : (contents' ++
1120− [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1121− _ -> contents'
1122− macros <- sMacros <$> getState
1123− case M.lookup name macros of
1124− Just macro
1125− | mtype == "newcommand" -> do
1126− report $ MacroAlreadyDefined txt pos
1127− return (name, macro)
1128− | mtype == "providecommand" -> return (name, macro)
1129− _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1130−
1131−newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1132−newenvironment = do
1133− pos <- getPosition
1134− Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1135− controlSeq "renewenvironment" <|>
1136− controlSeq "provideenvironment"
1137− withVerbatimMode $ do
1138− optional $ symbol '*'
1139− spaces
1140− name <- untokenize <$> braced
1141− spaces
1142− numargs <- option 0 $ try bracketedNum
1143− spaces
1144− optarg <- option Nothing $ Just <$> try bracketedToks
1145− let argspecs = map (\i -> ArgNum i) [1..numargs]
1146− startcontents <- spaces >> bracedOrToken
1147− endcontents <- spaces >> bracedOrToken
1148− macros <- sMacros <$> getState
1149− case M.lookup name macros of
1150− Just _
1151− | mtype == "newenvironment" -> do
1152− report $ MacroAlreadyDefined name pos
1153− return Nothing
1154− | mtype == "provideenvironment" ->
1155− return Nothing
1156− _ -> return $ Just (name,
1157− Macro ExpandWhenUsed argspecs optarg startcontents,
1158− Macro ExpandWhenUsed [] Nothing endcontents)
1159−
1160−bracketedNum :: PandocMonad m => LP m Int
1161−bracketedNum = do
1162− ds <- untokenize <$> bracketedToks
1163− case safeRead ds of
1164− Just i -> return i
1165− _ -> return 0
1166−
11671030looseItem :: PandocMonad m => LP m Blocks
11681031looseItem = do
11691032 inListItem <- sInListItem <$> getState
src/Text/Pandoc/Readers/LaTeX/Macro.hsnew file+153
@@ -0,0 +1,153 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Text.Pandoc.Readers.LaTeX.Macro
3+ ( macroDef
4+ )
5+where
6+import Text.Pandoc.Extensions (Extension(..))
7+import Text.Pandoc.Logging (LogMessage(MacroAlreadyDefined))
8+import Text.Pandoc.Readers.LaTeX.Parsing
9+import Text.Pandoc.Readers.LaTeX.Types
10+import Text.Pandoc.Class
11+import Text.Pandoc.Shared (safeRead)
12+import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
13+ optional, space, spaces, withRaw, (<|>))
14+import Control.Applicative ((<|>), optional)
15+import qualified Data.Map as M
16+import Data.Text (Text)
17+
18+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
19+macroDef constructor = do
20+ (_, s) <- withRaw (commandDef <|> environmentDef)
21+ (constructor (untokenize s) <$
22+ guardDisabled Ext_latex_macros)
23+ <|> return mempty
24+ where commandDef = do
25+ (name, macro') <- newcommand <|> letmacro <|> defmacro
26+ guardDisabled Ext_latex_macros <|>
27+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
28+ environmentDef = do
29+ mbenv <- newenvironment
30+ case mbenv of
31+ Nothing -> return ()
32+ Just (name, macro1, macro2) ->
33+ guardDisabled Ext_latex_macros <|>
34+ do updateState $ \s -> s{ sMacros =
35+ M.insert name macro1 (sMacros s) }
36+ updateState $ \s -> s{ sMacros =
37+ M.insert ("end" <> name) macro2 (sMacros s) }
38+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
39+ -- is equivalent to
40+ -- @\newcommand{\envname}[n-args][default]{begin}@
41+ -- @\newcommand{\endenvname}@
42+
43+letmacro :: PandocMonad m => LP m (Text, Macro)
44+letmacro = do
45+ controlSeq "let"
46+ (name, contents) <- withVerbatimMode $ do
47+ Tok _ (CtrlSeq name) _ <- anyControlSeq
48+ optional $ symbol '='
49+ spaces
50+ -- we first parse in verbatim mode, and then expand macros,
51+ -- because we don't want \let\foo\bar to turn into
52+ -- \let\foo hello if we have previously \def\bar{hello}
53+ contents <- bracedOrToken
54+ return (name, contents)
55+ contents' <- doMacros' 0 contents
56+ return (name, Macro ExpandWhenDefined [] Nothing contents')
57+
58+defmacro :: PandocMonad m => LP m (Text, Macro)
59+defmacro = try $
60+ -- we use withVerbatimMode, because macros are to be expanded
61+ -- at point of use, not point of definition
62+ withVerbatimMode $ do
63+ controlSeq "def"
64+ Tok _ (CtrlSeq name) _ <- anyControlSeq
65+ argspecs <- many (argspecArg <|> argspecPattern)
66+ contents <- bracedOrToken
67+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
68+
69+argspecArg :: PandocMonad m => LP m ArgSpec
70+argspecArg = do
71+ Tok _ (Arg i) _ <- satisfyTok isArgTok
72+ return $ ArgNum i
73+
74+argspecPattern :: PandocMonad m => LP m ArgSpec
75+argspecPattern =
76+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
77+ (toktype' == Symbol || toktype' == Word) &&
78+ (txt /= "{" && txt /= "\\" && txt /= "}")))
79+
80+newcommand :: PandocMonad m => LP m (Text, Macro)
81+newcommand = do
82+ pos <- getPosition
83+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
84+ controlSeq "renewcommand" <|>
85+ controlSeq "providecommand" <|>
86+ controlSeq "DeclareMathOperator" <|>
87+ controlSeq "DeclareRobustCommand"
88+ withVerbatimMode $ do
89+ Tok _ (CtrlSeq name) txt <- do
90+ optional (symbol '*')
91+ anyControlSeq <|>
92+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
93+ spaces
94+ numargs <- option 0 $ try bracketedNum
95+ let argspecs = map ArgNum [1..numargs]
96+ spaces
97+ optarg <- option Nothing $ Just <$> try bracketedToks
98+ spaces
99+ contents' <- bracedOrToken
100+ let contents =
101+ case mtype of
102+ "DeclareMathOperator" ->
103+ Tok pos (CtrlSeq "mathop") "\\mathop"
104+ : Tok pos Symbol "{"
105+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
106+ : Tok pos Symbol "{"
107+ : (contents' ++
108+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
109+ _ -> contents'
110+ macros <- sMacros <$> getState
111+ case M.lookup name macros of
112+ Just macro
113+ | mtype == "newcommand" -> do
114+ report $ MacroAlreadyDefined txt pos
115+ return (name, macro)
116+ | mtype == "providecommand" -> return (name, macro)
117+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
118+
119+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
120+newenvironment = do
121+ pos <- getPosition
122+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
123+ controlSeq "renewenvironment" <|>
124+ controlSeq "provideenvironment"
125+ withVerbatimMode $ do
126+ optional $ symbol '*'
127+ spaces
128+ name <- untokenize <$> braced
129+ spaces
130+ numargs <- option 0 $ try bracketedNum
131+ spaces
132+ optarg <- option Nothing $ Just <$> try bracketedToks
133+ let argspecs = map (\i -> ArgNum i) [1..numargs]
134+ startcontents <- spaces >> bracedOrToken
135+ endcontents <- spaces >> bracedOrToken
136+ macros <- sMacros <$> getState
137+ case M.lookup name macros of
138+ Just _
139+ | mtype == "newenvironment" -> do
140+ report $ MacroAlreadyDefined name pos
141+ return Nothing
142+ | mtype == "provideenvironment" ->
143+ return Nothing
144+ _ -> return $ Just (name,
145+ Macro ExpandWhenUsed argspecs optarg startcontents,
146+ Macro ExpandWhenUsed [] Nothing endcontents)
147+
148+bracketedNum :: PandocMonad m => LP m Int
149+bracketedNum = do
150+ ds <- untokenize <$> bracketedToks
151+ case safeRead ds of
152+ Just i -> return i
153+ _ -> return 0