@@ -1,3 +1,6 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
14{-# LANGUAGE OverloadedStrings #-}
25{-# LANGUAGE PatternGuards #-}
36{-# LANGUAGE ScopedTypeVariables #-}
@@ -18,58 +21,51 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
1821 applyMacros,
1922 rawLaTeXInline,
2023 rawLaTeXBlock,
21− inlineCommand
24+ inlineCommand,
25+ tokenize,
26+ untokenize
2227 ) where
2328
2429import Control.Applicative (many, optional, (<|>))
2530import Control.Monad
2631import Control.Monad.Except (throwError)
27−import Data.Char (isDigit, isLetter, isAlphaNum, toUpper, chr)
32+import Data.Char (isDigit, isLetter, toUpper, chr)
2833import Data.Default
2934import Data.List (intercalate)
3035import qualified Data.Map as M
3136import Data.Maybe (fromMaybe, maybeToList)
3237import qualified Data.Set as Set
38+import qualified Data.Sequence as Seq
3339import Data.Text (Text)
3440import qualified Data.Text as T
35−import Skylighting (defaultSyntaxMap)
3641import System.FilePath (addExtension, replaceExtension, takeExtension)
37−import Text.Collate.Lang (renderLang)
38−import Text.Pandoc.Builder as B
42+import Text.Pandoc.BCP47 (Lang (..), renderLang)
43+import Text.Pandoc.Builder
3944import Text.Pandoc.Class.PandocPure (PandocPure)
4045import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
41− readFileFromDirs, report,
42− setResourcePath)
46+ readFileFromDirs, report, setResourcePath,
47+ translateTerm)
4348import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
44−import Text.Pandoc.Highlighting (languagesByExtension)
49+import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
4550import Text.Pandoc.ImageSize (numUnit, showFl)
4651import Text.Pandoc.Logging
4752import Text.Pandoc.Options
4853import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
4954 optional, space, spaces, withRaw, (<|>))
50−import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
55+import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
56+ ArgSpec (..), Tok (..), TokType (..))
5157import Text.Pandoc.Readers.LaTeX.Parsing
58+import Text.Pandoc.Readers.LaTeX.Accent (accentCommands)
5259import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
53−import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
54− inlineEnvironment,
55− mathDisplay, mathInline,
56− newtheorem, theoremstyle, proof,
57− theoremEnvironment)
5860import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
59−import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
60−import Text.Pandoc.Readers.LaTeX.Lang (inlineLanguageCommands,
61− enquoteCommands,
61+import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
6262 babelLangToBCP47, setDefaultLanguage)
63−import Text.Pandoc.Readers.LaTeX.SIunitx (siunitxCommands)
64−import Text.Pandoc.Readers.LaTeX.Inline (acronymCommands, refCommands,
65− nameCommands, charCommands,
66− accentCommands,
67− biblatexInlineCommands,
68− verbCommands, rawInlineOr,
69− listingsLanguage)
63+import Text.Pandoc.Readers.LaTeX.SIunitx
7064import Text.Pandoc.Shared
65+import qualified Text.Pandoc.Translations as Translations
7166import Text.Pandoc.Walk
72−import Data.List.NonEmpty (nonEmpty)
67+import qualified Text.Pandoc.Builder as B
68+import Safe
7369
7470-- for debugging:
7571-- import Text.Pandoc.Extensions (getDefaultExtensions)
@@ -77,17 +73,16 @@ import Data.List.NonEmpty (nonEmpty)
7773-- import Debug.Trace (traceShowId)
7874
7975-- | Parse LaTeX from string and return 'Pandoc' document.
80−readLaTeX :: (PandocMonad m, ToSources a)
76+readLaTeX :: PandocMonad m
8177 => ReaderOptions -- ^ Reader options
82− -> a -- ^ Input to parse
78+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
8379 -> m Pandoc
8480readLaTeX opts ltx = do
85− let sources = toSources ltx
8681 parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
87− (tokenizeSources sources)
82+ (tokenize "source" (crFilter ltx))
8883 case parsed of
8984 Right result -> return result
90− Left e -> throwError $ PandocParsecError sources e
85+ Left e -> throwError $ PandocParsecError ltx e
9186
9287parseLaTeX :: PandocMonad m => LP m Pandoc
9388parseLaTeX = do
@@ -98,7 +93,11 @@ parseLaTeX = do
9893 let doc' = doc bs
9994 let headerLevel (Header n _ _) = [n]
10095 headerLevel _ = []
101− let bottomLevel = maybe 1 minimum $ nonEmpty $ query headerLevel doc'
96+#if MIN_VERSION_safe(0,3,18)
97+ let bottomLevel = minimumBound 1 $ query headerLevel doc'
98+#else
99+ let bottomLevel = minimumDef 1 $ query headerLevel doc'
100+#endif
102101 let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
103102 adjustHeaders _ x = x
104103 let (Pandoc _ bs') =
@@ -133,11 +132,11 @@ resolveRefs _ x = x
133132
134133
135134rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
136− => ParserT Sources s m Text
135+ => ParserT Text s m Text
137136rawLaTeXBlock = do
138137 lookAhead (try (char '\\' >> letter))
139138 inp <- getInput
140− let toks = tokenizeSources inp
139+ let toks = tokenize "source" inp
141140 snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
142141 <|> rawLaTeXParser toks True
143142 (do choice (map controlSeq
@@ -164,11 +163,11 @@ beginOrEndCommand = try $ do
164163 (txt <> untokenize rawargs)
165164
166165rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
167− => ParserT Sources s m Text
166+ => ParserT Text s m Text
168167rawLaTeXInline = do
169168 lookAhead (try (char '\\' >> letter))
170169 inp <- getInput
171− let toks = tokenizeSources inp
170+ let toks = tokenize "source" inp
172171 raw <- snd <$>
173172 ( rawLaTeXParser toks True
174173 (mempty <$ (controlSeq "input" >> skipMany rawopt >> braced))
@@ -179,11 +178,11 @@ rawLaTeXInline = do
179178 finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
180179 return $ raw <> T.pack finalbraces
181180
182−inlineCommand :: PandocMonad m => ParserT Sources ParserState m Inlines
181+inlineCommand :: PandocMonad m => ParserT Text ParserState m Inlines
183182inlineCommand = do
184183 lookAhead (try (char '\\' >> letter))
185184 inp <- getInput
186− let toks = tokenizeSources inp
185+ let toks = tokenize "source" inp
187186 fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
188187 inlines
189188
@@ -192,6 +191,12 @@ inlineCommand = do
192191word :: PandocMonad m => LP m Inlines
193192word = str . untoken <$> satisfyTok isWordTok
194193
194+regularSymbol :: PandocMonad m => LP m Inlines
195+regularSymbol = str . untoken <$> satisfyTok isRegularSymbol
196+ where isRegularSymbol (Tok _ Symbol t) = not $ T.any isSpecial t
197+ isRegularSymbol _ = False
198+ isSpecial c = c `Set.member` specialChars
199+
195200inlineGroup :: PandocMonad m => LP m Inlines
196201inlineGroup = do
197202 ils <- grouped inline
@@ -232,6 +237,16 @@ mkImage options (T.unpack -> src) = do
232237 _ -> return src
233238 return $ imageWith attr (T.pack src') "" alt
234239
240+doxspace :: PandocMonad m => LP m Inlines
241+doxspace =
242+ (space <$ lookAhead (satisfyTok startsWithLetter)) <|> return mempty
243+ where startsWithLetter (Tok _ Word t) =
244+ case T.uncons t of
245+ Just (c, _) | isLetter c -> True
246+ _ -> False
247+ startsWithLetter _ = False
248+
249+
235250removeDoubleQuotes :: Text -> Text
236251removeDoubleQuotes t =
237252 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
@@ -281,6 +296,18 @@ quoted' f starter ender = do
281296lit :: Text -> LP m Inlines
282297lit = pure . str
283298
299+enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines
300+enquote starred mblang = do
301+ skipopts
302+ let lang = mblang >>= babelLangToBCP47
303+ let langspan = case lang of
304+ Nothing -> id
305+ Just l -> spanWith ("",[],[("lang", renderLang l)])
306+ quoteContext <- sQuoteContext <$> getState
307+ if starred || quoteContext == InDoubleQuote
308+ then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok
309+ else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok
310+
284311blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
285312blockquote cvariant mblang = do
286313 citepar <- if cvariant
@@ -296,13 +323,114 @@ blockquote cvariant mblang = do
296323 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
297324 return $ blockQuote . langdiv $ (bs <> citepar)
298325
326+doAcronym :: PandocMonad m => Text -> LP m Inlines
327+doAcronym form = do
328+ acro <- braced
329+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
330+ ("acronym-form", "singular+" <> form)])
331+ $ str $ untokenize acro]
332+
333+doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
334+doAcronymPlural form = do
335+ acro <- braced
336+ plural <- lit "s"
337+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
338+ ("acronym-form", "plural+" <> form)]) $
339+ mconcat [str $ untokenize acro, plural]]
340+
341+doverb :: PandocMonad m => LP m Inlines
342+doverb = do
343+ Tok _ Symbol t <- anySymbol
344+ marker <- case T.uncons t of
345+ Just (c, ts) | T.null ts -> return c
346+ _ -> mzero
347+ withVerbatimMode $
348+ code . untokenize <$>
349+ manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
350+
351+verbTok :: PandocMonad m => Char -> LP m Tok
352+verbTok stopchar = do
353+ t@(Tok pos toktype txt) <- anyTok
354+ case T.findIndex (== stopchar) txt of
355+ Nothing -> return t
356+ Just i -> do
357+ let (t1, t2) = T.splitAt i txt
358+ inp <- getInput
359+ setInput $ Tok (incSourceColumn pos i) Symbol (T.singleton stopchar)
360+ : totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
361+ return $ Tok pos toktype t1
362+
363+listingsLanguage :: [(Text, Text)] -> Maybe Text
364+listingsLanguage opts =
365+ case lookup "language" opts of
366+ Nothing -> Nothing
367+ Just l -> fromListingsLanguage l `mplus` Just l
368+
369+dolstinline :: PandocMonad m => LP m Inlines
370+dolstinline = do
371+ options <- option [] keyvals
372+ let classes = maybeToList $ listingsLanguage options
373+ doinlinecode classes
374+
375+domintinline :: PandocMonad m => LP m Inlines
376+domintinline = do
377+ skipopts
378+ cls <- untokenize <$> braced
379+ doinlinecode [cls]
380+
381+doinlinecode :: PandocMonad m => [Text] -> LP m Inlines
382+doinlinecode classes = do
383+ Tok _ Symbol t <- anySymbol
384+ marker <- case T.uncons t of
385+ Just (c, ts) | T.null ts -> return c
386+ _ -> mzero
387+ let stopchar = if marker == '{' then '}' else marker
388+ withVerbatimMode $
389+ codeWith ("",classes,[]) . T.map nlToSpace . untokenize <$>
390+ manyTill (verbTok stopchar) (symbol stopchar)
391+
392+nlToSpace :: Char -> Char
393+nlToSpace '\n' = ' '
394+nlToSpace x = x
395+
396+mathDisplay :: Text -> Inlines
397+mathDisplay = displayMath . trimMath
398+
399+mathInline :: Text -> Inlines
400+mathInline = math . trimMath
401+
402+dollarsMath :: PandocMonad m => LP m Inlines
403+dollarsMath = do
404+ symbol '$'
405+ display <- option False (True <$ symbol '$')
406+ (do contents <- try $ untokenize <$> pDollarsMath 0
407+ if display
408+ then mathDisplay contents <$ symbol '$'
409+ else return $ mathInline contents)
410+ <|> (guard display >> return (mathInline ""))
411+
412+-- Int is number of embedded groupings
413+pDollarsMath :: PandocMonad m => Int -> LP m [Tok]
414+pDollarsMath n = do
415+ tk@(Tok _ toktype t) <- anyTok
416+ case toktype of
417+ Symbol | t == "$"
418+ , n == 0 -> return []
419+ | t == "\\" -> do
420+ tk' <- anyTok
421+ (tk :) . (tk' :) <$> pDollarsMath n
422+ | t == "{" -> (tk :) <$> pDollarsMath (n+1)
423+ | t == "}" ->
424+ if n > 0
425+ then (tk :) <$> pDollarsMath (n-1)
426+ else mzero
427+ _ -> (tk :) <$> pDollarsMath n
428+
299429inlineCommand' :: PandocMonad m => LP m Inlines
300430inlineCommand' = try $ do
301431 Tok _ (CtrlSeq name) cmd <- anyControlSeq
302432 guard $ name /= "begin" && name /= "end" && name /= "and"
303− star <- if T.all isAlphaNum name
304− then option "" ("*" <$ symbol '*' <* sp)
305− else pure ""
433+ star <- option "" ("*" <$ symbol '*' <* sp)
306434 overlay <- option "" overlaySpecification
307435 let name' = name <> star <> overlay
308436 let names = ordNub [name', name] -- check non-starred as fallback
@@ -316,6 +444,9 @@ inlineCommand' = try $ do
316444tok :: PandocMonad m => LP m Inlines
317445tok = tokWith inline
318446
447+inBrackets :: Inlines -> Inlines
448+inBrackets x = str "[" <> x <> str "]"
449+
319450unescapeURL :: Text -> Text
320451unescapeURL = T.concat . go . T.splitOn "\\"
321452 where
@@ -327,103 +458,287 @@ unescapeURL = T.concat . go . T.splitOn "\\"
327458 , isEscapable c = t
328459 | otherwise = "\\" <> t
329460
461+mathEnvWith :: PandocMonad m
462+ => (Inlines -> a) -> Maybe Text -> Text -> LP m a
463+mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
464+ where inner x = case innerEnv of
465+ Nothing -> x
466+ Just y -> "\\begin{" <> y <> "}\n" <> x <>
467+ "\\end{" <> y <> "}"
468+
469+mathEnv :: PandocMonad m => Text -> LP m Text
470+mathEnv name = do
471+ skipopts
472+ optional blankline
473+ res <- manyTill anyTok (end_ name)
474+ return $ stripTrailingNewlines $ untokenize res
475+
476+inlineEnvironment :: PandocMonad m => LP m Inlines
477+inlineEnvironment = try $ do
478+ controlSeq "begin"
479+ name <- untokenize <$> braced
480+ M.findWithDefault mzero name inlineEnvironments
481+
482+inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
483+inlineEnvironments = M.fromList [
484+ ("displaymath", mathEnvWith id Nothing "displaymath")
485+ , ("math", math <$> mathEnv "math")
486+ , ("equation", mathEnvWith id Nothing "equation")
487+ , ("equation*", mathEnvWith id Nothing "equation*")
488+ , ("gather", mathEnvWith id (Just "gathered") "gather")
489+ , ("gather*", mathEnvWith id (Just "gathered") "gather*")
490+ , ("multline", mathEnvWith id (Just "gathered") "multline")
491+ , ("multline*", mathEnvWith id (Just "gathered") "multline*")
492+ , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
493+ , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
494+ , ("align", mathEnvWith id (Just "aligned") "align")
495+ , ("align*", mathEnvWith id (Just "aligned") "align*")
496+ , ("alignat", mathEnvWith id (Just "aligned") "alignat")
497+ , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
498+ , ("dmath", mathEnvWith id Nothing "dmath")
499+ , ("dmath*", mathEnvWith id Nothing "dmath*")
500+ , ("dgroup", mathEnvWith id (Just "aligned") "dgroup")
501+ , ("dgroup*", mathEnvWith id (Just "aligned") "dgroup*")
502+ , ("darray", mathEnvWith id (Just "aligned") "darray")
503+ , ("darray*", mathEnvWith id (Just "aligned") "darray*")
504+ ]
505+
330506inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
331−inlineCommands = M.unions
332− [ accentCommands tok
333− , citationCommands inline
334− , siunitxCommands tok
335− , acronymCommands
336− , refCommands
337− , nameCommands
338− , verbCommands
339− , charCommands
340− , enquoteCommands tok
341− , inlineLanguageCommands tok
342− , biblatexInlineCommands tok
343− , rest ]
344− where
345− rest = M.fromList
346− [ ("emph", extractSpaces emph <$> tok)
347− , ("textit", extractSpaces emph <$> tok)
348− , ("textsl", extractSpaces emph <$> tok)
349− , ("textsc", extractSpaces smallcaps <$> tok)
350− , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
351− , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
352− , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
353− , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
354− , ("texttt", ttfamily)
355− , ("sout", extractSpaces strikeout <$> tok)
356− , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
357− , ("textsuperscript", extractSpaces superscript <$> tok)
358− , ("textsubscript", extractSpaces subscript <$> tok)
359− , ("textbf", extractSpaces strong <$> tok)
360− , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
361− , ("underline", underline <$> tok)
362− , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
363− , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
364− , ("lettrine", rawInlineOr "lettrine" lettrine)
365− , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
366− , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
367− , ("ensuremath", mathInline . untokenize <$> braced)
368− , ("texorpdfstring", const <$> tok <*> tok)
369− -- old TeX commands
370− , ("em", extractSpaces emph <$> inlines)
371− , ("it", extractSpaces emph <$> inlines)
372− , ("sl", extractSpaces emph <$> inlines)
373− , ("bf", extractSpaces strong <$> inlines)
374− , ("tt", code . stringify . toList <$> inlines)
375− , ("rm", inlines)
376− , ("itshape", extractSpaces emph <$> inlines)
377− , ("slshape", extractSpaces emph <$> inlines)
378− , ("scshape", extractSpaces smallcaps <$> inlines)
379− , ("bfseries", extractSpaces strong <$> inlines)
380− , ("MakeUppercase", makeUppercase <$> tok)
381− , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
382− , ("uppercase", makeUppercase <$> tok)
383− , ("MakeLowercase", makeLowercase <$> tok)
384− , ("MakeTextLowercase", makeLowercase <$> tok)
385− , ("lowercase", makeLowercase <$> tok)
386− , ("thanks", skipopts >> note <$> grouped block)
387− , ("footnote", skipopts >> note <$> grouped block)
388− , ("passthrough", tok) -- \passthrough macro used by latex writer
389− -- for listings
390− , ("includegraphics", do options <- option [] keyvals
391− src <- braced
392− mkImage options .
393− unescapeURL .
394− removeDoubleQuotes $ untokenize src)
395− -- hyperref
396− , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
397− bracedUrl)
398− , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
399− , ("href", do url <- bracedUrl
400− sp
401− link (unescapeURL $ untokenize url) "" <$> tok)
402− , ("hyperlink", hyperlink)
403− , ("hyperref", hyperref)
404− , ("hypertarget", hypertargetInline)
405− -- hyphenat
406− , ("nohyphens", tok)
407− , ("textnhtt", ttfamily)
408− , ("nhttfamily", ttfamily)
409− -- LaTeX colors
410− , ("textcolor", coloredInline "color")
411− , ("colorbox", coloredInline "background-color")
412− -- etoolbox
413− , ("ifstrequal", ifstrequal)
414− , ("newtoggle", braced >>= newToggle)
415− , ("toggletrue", braced >>= setToggle True)
416− , ("togglefalse", braced >>= setToggle False)
417− , ("iftoggle", try $ ifToggle >> inline)
418− -- include
419− , ("input", rawInlineOr "input" $ include "input")
420− -- soul package
421− , ("ul", underline <$> tok)
422− -- ulem package
423− , ("uline", underline <$> tok)
424− -- plain tex stuff that should just be passed through as raw tex
425− , ("ifdim", ifdim)
426− ]
507+inlineCommands =
508+ M.union inlineLanguageCommands $
509+ M.union (accentCommands tok) $
510+ M.union (citationCommands inline) $
511+ M.fromList
512+ [ ("emph", extractSpaces emph <$> tok)
513+ , ("textit", extractSpaces emph <$> tok)
514+ , ("textsl", extractSpaces emph <$> tok)
515+ , ("textsc", extractSpaces smallcaps <$> tok)
516+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
517+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
518+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
519+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
520+ , ("texttt", ttfamily)
521+ , ("sout", extractSpaces strikeout <$> tok)
522+ , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
523+ , ("lq", return (str "‘"))
524+ , ("rq", return (str "’"))
525+ , ("textquoteleft", return (str "‘"))
526+ , ("textquoteright", return (str "’"))
527+ , ("textquotedblleft", return (str "“"))
528+ , ("textquotedblright", return (str "”"))
529+ , ("textsuperscript", extractSpaces superscript <$> tok)
530+ , ("textsubscript", extractSpaces subscript <$> tok)
531+ , ("textbackslash", lit "\\")
532+ , ("backslash", lit "\\")
533+ , ("slash", lit "/")
534+ , ("textbf", extractSpaces strong <$> tok)
535+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
536+ , ("underline", underline <$> tok)
537+ , ("ldots", lit "…")
538+ , ("vdots", lit "\8942")
539+ , ("dots", lit "…")
540+ , ("mdots", lit "…")
541+ , ("sim", lit "~")
542+ , ("sep", lit ",")
543+ , ("label", rawInlineOr "label" dolabel)
544+ , ("ref", rawInlineOr "ref" $ doref "ref")
545+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
546+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
547+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
548+ , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
549+ , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
550+ , ("lettrine", rawInlineOr "lettrine" lettrine)
551+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
552+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
553+ , ("ensuremath", mathInline . untokenize <$> braced)
554+ , ("texorpdfstring", const <$> tok <*> tok)
555+ , ("P", lit "¶")
556+ , ("S", lit "§")
557+ , ("$", lit "$")
558+ , ("%", lit "%")
559+ , ("&", lit "&")
560+ , ("#", lit "#")
561+ , ("_", lit "_")
562+ , ("{", lit "{")
563+ , ("}", lit "}")
564+ , ("qed", lit "\a0\x25FB")
565+ -- old TeX commands
566+ , ("em", extractSpaces emph <$> inlines)
567+ , ("it", extractSpaces emph <$> inlines)
568+ , ("sl", extractSpaces emph <$> inlines)
569+ , ("bf", extractSpaces strong <$> inlines)
570+ , ("tt", code . stringify . toList <$> inlines)
571+ , ("rm", inlines)
572+ , ("itshape", extractSpaces emph <$> inlines)
573+ , ("slshape", extractSpaces emph <$> inlines)
574+ , ("scshape", extractSpaces smallcaps <$> inlines)
575+ , ("bfseries", extractSpaces strong <$> inlines)
576+ , ("MakeUppercase", makeUppercase <$> tok)
577+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
578+ , ("uppercase", makeUppercase <$> tok)
579+ , ("MakeLowercase", makeLowercase <$> tok)
580+ , ("MakeTextLowercase", makeLowercase <$> tok)
581+ , ("lowercase", makeLowercase <$> tok)
582+ , ("/", pure mempty) -- italic correction
583+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
584+ guard $ not inTableCell
585+ optional rawopt
586+ spaces))
587+ , (",", lit "\8198")
588+ , ("@", pure mempty)
589+ , (" ", lit "\160")
590+ , ("ps", pure $ str "PS." <> space)
591+ , ("TeX", lit "TeX")
592+ , ("LaTeX", lit "LaTeX")
593+ , ("bar", lit "|")
594+ , ("textless", lit "<")
595+ , ("textgreater", lit ">")
596+ , ("thanks", skipopts >> note <$> grouped block)
597+ , ("footnote", skipopts >> note <$> grouped block)
598+ , ("passthrough", tok) -- \passthrough macro used by latex writer
599+ -- for listings
600+ , ("verb", doverb)
601+ , ("lstinline", dolstinline)
602+ , ("mintinline", domintinline)
603+ , ("Verb", doverb)
604+ , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
605+ bracedUrl)
606+ , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
607+ , ("href", do url <- bracedUrl
608+ sp
609+ link (unescapeURL $ untokenize url) "" <$> tok)
610+ , ("includegraphics", do options <- option [] keyvals
611+ src <- braced
612+ mkImage options . unescapeURL . removeDoubleQuotes $
613+ untokenize src)
614+ , ("enquote*", enquote True Nothing)
615+ , ("enquote", enquote False Nothing)
616+ -- foreignquote is supposed to use native quote marks
617+ , ("foreignquote*", braced >>= enquote True . Just . untokenize)
618+ , ("foreignquote", braced >>= enquote False . Just . untokenize)
619+ -- hypehnquote uses regular quotes
620+ , ("hyphenquote*", braced >>= enquote True . Just . untokenize)
621+ , ("hyphenquote", braced >>= enquote False . Just . untokenize)
622+ , ("figurename", doTerm Translations.Figure)
623+ , ("prefacename", doTerm Translations.Preface)
624+ , ("refname", doTerm Translations.References)
625+ , ("bibname", doTerm Translations.Bibliography)
626+ , ("chaptername", doTerm Translations.Chapter)
627+ , ("partname", doTerm Translations.Part)
628+ , ("contentsname", doTerm Translations.Contents)
629+ , ("listfigurename", doTerm Translations.ListOfFigures)
630+ , ("listtablename", doTerm Translations.ListOfTables)
631+ , ("indexname", doTerm Translations.Index)
632+ , ("abstractname", doTerm Translations.Abstract)
633+ , ("tablename", doTerm Translations.Table)
634+ , ("enclname", doTerm Translations.Encl)
635+ , ("ccname", doTerm Translations.Cc)
636+ , ("headtoname", doTerm Translations.To)
637+ , ("pagename", doTerm Translations.Page)
638+ , ("seename", doTerm Translations.See)
639+ , ("seealsoname", doTerm Translations.SeeAlso)
640+ , ("proofname", doTerm Translations.Proof)
641+ , ("glossaryname", doTerm Translations.Glossary)
642+ , ("lstlistingname", doTerm Translations.Listing)
643+ , ("hyperlink", hyperlink)
644+ , ("hypertarget", hypertargetInline)
645+ -- glossaries package
646+ , ("gls", doAcronym "short")
647+ , ("Gls", doAcronym "short")
648+ , ("glsdesc", doAcronym "long")
649+ , ("Glsdesc", doAcronym "long")
650+ , ("GLSdesc", doAcronym "long")
651+ , ("acrlong", doAcronym "long")
652+ , ("Acrlong", doAcronym "long")
653+ , ("acrfull", doAcronym "full")
654+ , ("Acrfull", doAcronym "full")
655+ , ("acrshort", doAcronym "abbrv")
656+ , ("Acrshort", doAcronym "abbrv")
657+ , ("glspl", doAcronymPlural "short")
658+ , ("Glspl", doAcronymPlural "short")
659+ , ("glsdescplural", doAcronymPlural "long")
660+ , ("Glsdescplural", doAcronymPlural "long")
661+ , ("GLSdescplural", doAcronymPlural "long")
662+ -- acronyms package
663+ , ("ac", doAcronym "short")
664+ , ("acf", doAcronym "full")
665+ , ("acs", doAcronym "abbrv")
666+ , ("acl", doAcronym "long")
667+ , ("acp", doAcronymPlural "short")
668+ , ("acfp", doAcronymPlural "full")
669+ , ("acsp", doAcronymPlural "abbrv")
670+ , ("aclp", doAcronymPlural "long")
671+ , ("Ac", doAcronym "short")
672+ , ("Acf", doAcronym "full")
673+ , ("Acs", doAcronym "abbrv")
674+ , ("Acl", doAcronym "long")
675+ , ("Acp", doAcronymPlural "short")
676+ , ("Acfp", doAcronymPlural "full")
677+ , ("Acsp", doAcronymPlural "abbrv")
678+ , ("Aclp", doAcronymPlural "long")
679+ -- siuntix
680+ , ("si", skipopts *> dosi tok)
681+ , ("SI", doSI tok)
682+ , ("SIrange", doSIrange True tok)
683+ , ("numrange", doSIrange False tok)
684+ , ("numlist", doSInumlist)
685+ , ("num", doSInum)
686+ , ("ang", doSIang)
687+ -- hyphenat
688+ , ("bshyp", lit "\\\173")
689+ , ("fshyp", lit "/\173")
690+ , ("dothyp", lit ".\173")
691+ , ("colonhyp", lit ":\173")
692+ , ("hyp", lit "-")
693+ , ("nohyphens", tok)
694+ , ("textnhtt", ttfamily)
695+ , ("nhttfamily", ttfamily)
696+ -- LaTeX colors
697+ , ("textcolor", coloredInline "color")
698+ , ("colorbox", coloredInline "background-color")
699+ -- fontawesome
700+ , ("faCheck", lit "\10003")
701+ , ("faClose", lit "\10007")
702+ -- xspace
703+ , ("xspace", doxspace)
704+ -- etoolbox
705+ , ("ifstrequal", ifstrequal)
706+ , ("newtoggle", braced >>= newToggle)
707+ , ("toggletrue", braced >>= setToggle True)
708+ , ("togglefalse", braced >>= setToggle False)
709+ , ("iftoggle", try $ ifToggle >> inline)
710+ -- biblatex misc
711+ , ("RN", romanNumeralUpper)
712+ , ("Rn", romanNumeralLower)
713+ -- babel
714+ , ("foreignlanguage", foreignlanguage)
715+ -- include
716+ , ("input", rawInlineOr "input" $ include "input")
717+ -- soul package
718+ , ("ul", underline <$> tok)
719+ -- ulem package
720+ , ("uline", underline <$> tok)
721+ -- plain tex stuff that should just be passed through as raw tex
722+ , ("ifdim", ifdim)
723+ -- bibtex
724+ , ("mkbibquote", spanWith nullAttr . doubleQuoted <$> tok)
725+ , ("mkbibemph", spanWith nullAttr . emph <$> tok)
726+ , ("mkbibitalic", spanWith nullAttr . emph <$> tok)
727+ , ("mkbibbold", spanWith nullAttr . strong <$> tok)
728+ , ("mkbibparens",
729+ spanWith nullAttr . (\x -> str "(" <> x <> str ")") <$> tok)
730+ , ("mkbibbrackets",
731+ spanWith nullAttr . (\x -> str "[" <> x <> str "]") <$> tok)
732+ , ("autocap", spanWith nullAttr <$> tok)
733+ , ("textnormal", spanWith ("",["nodecor"],[]) <$> tok)
734+ , ("bibstring",
735+ (\x -> spanWith ("",[],[("bibstring",x)]) (str x)) . untokenize
736+ <$> braced)
737+ , ("adddot", pure (str "."))
738+ , ("adddotspace", pure (spanWith nullAttr (str "." <> space)))
739+ , ("addabbrvspace", pure space)
740+ , ("hyphen", pure (str "-"))
741+ ]
427742
428743lettrine :: PandocMonad m => LP m Inlines
429744lettrine = do
@@ -447,18 +762,32 @@ alterStr :: (Text -> Text) -> Inline -> Inline
447762alterStr f (Str xs) = Str (f xs)
448763alterStr _ x = x
449764
765+foreignlanguage :: PandocMonad m => LP m Inlines
766+foreignlanguage = do
767+ babelLang <- untokenize <$> braced
768+ case babelLangToBCP47 babelLang of
769+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
770+ _ -> tok
771+
772+inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
773+inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
774+ where
775+ mk (polyglossia, bcp47Func) =
776+ ("text" <> polyglossia, inlineLanguage bcp47Func)
777+
778+inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
779+inlineLanguage bcp47Func = do
780+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
781+ <$> rawopt
782+ let lang = renderLang $ bcp47Func o
783+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
784+
450785hyperlink :: PandocMonad m => LP m Inlines
451786hyperlink = try $ do
452787 src <- untokenize <$> braced
453788 lab <- tok
454789 return $ link ("#" <> src) "" lab
455790
456−hyperref :: PandocMonad m => LP m Inlines
457−hyperref = try $ do
458− url <- (("#" <>) . untokenize <$> try (sp *> bracketedToks <* sp))
459− <|> untokenize <$> (bracedUrl <* bracedUrl <* bracedUrl)
460− link url "" <$> tok
461−
462791hypertargetBlock :: PandocMonad m => LP m Blocks
463792hypertargetBlock = try $ do
464793 ref <- untokenize <$> braced
@@ -473,6 +802,31 @@ hypertargetInline = try $ do
473802 ils <- grouped inline
474803 return $ spanWith (ref, [], []) ils
475804
805+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
806+romanNumeralUpper =
807+ str . toRomanNumeral <$> romanNumeralArg
808+
809+romanNumeralLower :: (PandocMonad m) => LP m Inlines
810+romanNumeralLower =
811+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
812+
813+romanNumeralArg :: (PandocMonad m) => LP m Int
814+romanNumeralArg = spaces *> (parser <|> inBraces)
815+ where
816+ inBraces = do
817+ symbol '{'
818+ spaces
819+ res <- parser
820+ spaces
821+ symbol '}'
822+ return res
823+ parser = do
824+ s <- untokenize <$> many1 (satisfyTok isWordTok)
825+ let (digits, rest) = T.span isDigit s
826+ unless (T.null rest) $
827+ Prelude.fail "Non-digits in argument to \\Rn or \\RN"
828+ safeRead digits
829+
476830newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
477831newToggle name = do
478832 updateState $ \st ->
@@ -503,6 +857,9 @@ ifToggle = do
503857 report $ UndefinedToggle name' pos
504858 return ()
505859
860+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
861+doTerm term = str <$> translateTerm term
862+
506863ifstrequal :: (PandocMonad m, Monoid a) => LP m a
507864ifstrequal = do
508865 str1 <- tok
@@ -523,6 +880,13 @@ coloredInline stylename = do
523880ttfamily :: PandocMonad m => LP m Inlines
524881ttfamily = code . stringify . toList <$> tok
525882
883+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
884+rawInlineOr name' fallback = do
885+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
886+ if parseRaw
887+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
888+ else fallback
889+
526890processHBox :: Inlines -> Inlines
527891processHBox = walk convert
528892 where
@@ -573,53 +937,55 @@ treatAsInline = Set.fromList
573937 , "pagebreak"
574938 ]
575939
940+dolabel :: PandocMonad m => LP m Inlines
941+dolabel = do
942+ v <- braced
943+ let refstr = untokenize v
944+ updateState $ \st ->
945+ st{ sLastLabel = Just refstr }
946+ return $ spanWith (refstr,[],[("label", refstr)])
947+ $ inBrackets $ str $ untokenize v
948+
949+doref :: PandocMonad m => Text -> LP m Inlines
950+doref cls = do
951+ v <- braced
952+ let refstr = untokenize v
953+ return $ linkWith ("",[],[ ("reference-type", cls)
954+ , ("reference", refstr)])
955+ ("#" <> refstr)
956+ ""
957+ (inBrackets $ str refstr)
958+
576959lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
577960lookupListDefault d = (fromMaybe d .) . lookupList
578961 where lookupList l m = msum $ map (`M.lookup` m) l
579962
580963inline :: PandocMonad m => LP m Inlines
581−inline = do
582− Tok pos toktype t <- lookAhead anyTok
583− let symbolAsString = str . untoken <$> anySymbol
584− let unescapedSymbolAsString =
585− do s <- untoken <$> anySymbol
586− report $ ParsingUnescaped s pos
587− return $ str s
588− case toktype of
589− Comment -> mempty <$ comment
590− Spaces -> space <$ whitespace
591− Newline -> softbreak <$ endline
592− Word -> word
593− Esc1 -> str . T.singleton <$> primEscape
594− Esc2 -> str . T.singleton <$> primEscape
595− Symbol ->
596− case t of
597− "-" -> symbol '-' *>
598− option (str "-") (symbol '-' *>
599− option (str "–") (str "—" <$ symbol '-'))
600− "'" -> symbol '\'' *>
601− option (str "’") (str "”" <$ symbol '\'')
602− "~" -> str "\160" <$ symbol '~'
603− "`" -> doubleQuote <|> singleQuote <|> symbolAsString
604− "\"" -> doubleQuote <|> singleQuote <|> symbolAsString
605− "“" -> doubleQuote <|> symbolAsString
606− "‘" -> singleQuote <|> symbolAsString
607− "$" -> dollarsMath <|> unescapedSymbolAsString
608− "|" -> (guardEnabled Ext_literate_haskell *>
609− symbol '|' *> doLHSverb) <|> symbolAsString
610− "{" -> inlineGroup
611− "#" -> unescapedSymbolAsString
612− "&" -> unescapedSymbolAsString
613− "_" -> unescapedSymbolAsString
614− "^" -> unescapedSymbolAsString
615− "\\" -> mzero
616− "}" -> mzero
617− _ -> symbolAsString
618− CtrlSeq _ -> macroDef (rawInline "latex")
619− <|> inlineCommand'
620− <|> inlineEnvironment
621− <|> inlineGroup
622− _ -> mzero
964+inline = (mempty <$ comment)
965+ <|> (space <$ whitespace)
966+ <|> (softbreak <$ endline)
967+ <|> word
968+ <|> macroDef (rawInline "latex")
969+ <|> inlineCommand'
970+ <|> inlineEnvironment
971+ <|> inlineGroup
972+ <|> (symbol '-' *>
973+ option (str "-") (symbol '-' *>
974+ option (str "–") (str "—" <$ symbol '-')))
975+ <|> doubleQuote
976+ <|> singleQuote
977+ <|> (str "”" <$ try (symbol '\'' >> symbol '\''))
978+ <|> (str "’" <$ symbol '\'')
979+ <|> (str "\160" <$ symbol '~')
980+ <|> dollarsMath
981+ <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
982+ <|> (str . T.singleton <$> primEscape)
983+ <|> regularSymbol
984+ <|> (do res <- symbolIn "#^'`\"[]&"
985+ pos <- getPosition
986+ let s = untoken res
987+ report $ ParsingUnescaped s pos
988+ return $ str s)
623989
624990inlines :: PandocMonad m => LP m Inlines
625991inlines = mconcat <$> many inline
@@ -632,7 +998,7 @@ opt = do
632998 parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
633999 case parsed of
6341000 Right result -> return result
635− Left e -> throwError $ PandocParsecError (toSources toks) e
1001+ Left e -> throwError $ PandocParsecError (untokenize toks) e
6361002
6371003-- block elements:
6381004
@@ -735,6 +1101,143 @@ authors = try $ do
7351101 egroup
7361102 addMeta "author" (map trimInlines auths)
7371103
1104+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1105+macroDef constructor = do
1106+ (_, s) <- withRaw (commandDef <|> environmentDef)
1107+ (constructor (untokenize s) <$
1108+ guardDisabled Ext_latex_macros)
1109+ <|> return mempty
1110+ where commandDef = do
1111+ (name, macro') <- newcommand <|> letmacro <|> defmacro
1112+ guardDisabled Ext_latex_macros <|>
1113+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1114+ environmentDef = do
1115+ mbenv <- newenvironment
1116+ case mbenv of
1117+ Nothing -> return ()
1118+ Just (name, macro1, macro2) ->
1119+ guardDisabled Ext_latex_macros <|>
1120+ do updateState $ \s -> s{ sMacros =
1121+ M.insert name macro1 (sMacros s) }
1122+ updateState $ \s -> s{ sMacros =
1123+ M.insert ("end" <> name) macro2 (sMacros s) }
1124+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1125+ -- is equivalent to
1126+ -- @\newcommand{\envname}[n-args][default]{begin}@
1127+ -- @\newcommand{\endenvname}@
1128+
1129+letmacro :: PandocMonad m => LP m (Text, Macro)
1130+letmacro = do
1131+ controlSeq "let"
1132+ (name, contents) <- withVerbatimMode $ do
1133+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1134+ optional $ symbol '='
1135+ spaces
1136+ -- we first parse in verbatim mode, and then expand macros,
1137+ -- because we don't want \let\foo\bar to turn into
1138+ -- \let\foo hello if we have previously \def\bar{hello}
1139+ contents <- bracedOrToken
1140+ return (name, contents)
1141+ contents' <- doMacros' 0 contents
1142+ return (name, Macro ExpandWhenDefined [] Nothing contents')
1143+
1144+defmacro :: PandocMonad m => LP m (Text, Macro)
1145+defmacro = try $
1146+ -- we use withVerbatimMode, because macros are to be expanded
1147+ -- at point of use, not point of definition
1148+ withVerbatimMode $ do
1149+ controlSeq "def"
1150+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1151+ argspecs <- many (argspecArg <|> argspecPattern)
1152+ contents <- bracedOrToken
1153+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1154+
1155+argspecArg :: PandocMonad m => LP m ArgSpec
1156+argspecArg = do
1157+ Tok _ (Arg i) _ <- satisfyTok isArgTok
1158+ return $ ArgNum i
1159+
1160+argspecPattern :: PandocMonad m => LP m ArgSpec
1161+argspecPattern =
1162+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1163+ (toktype' == Symbol || toktype' == Word) &&
1164+ (txt /= "{" && txt /= "\\" && txt /= "}")))
1165+
1166+newcommand :: PandocMonad m => LP m (Text, Macro)
1167+newcommand = do
1168+ pos <- getPosition
1169+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1170+ controlSeq "renewcommand" <|>
1171+ controlSeq "providecommand" <|>
1172+ controlSeq "DeclareMathOperator" <|>
1173+ controlSeq "DeclareRobustCommand"
1174+ withVerbatimMode $ do
1175+ Tok _ (CtrlSeq name) txt <- do
1176+ optional (symbol '*')
1177+ anyControlSeq <|>
1178+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1179+ spaces
1180+ numargs <- option 0 $ try bracketedNum
1181+ let argspecs = map ArgNum [1..numargs]
1182+ spaces
1183+ optarg <- option Nothing $ Just <$> try bracketedToks
1184+ spaces
1185+ contents' <- bracedOrToken
1186+ let contents =
1187+ case mtype of
1188+ "DeclareMathOperator" ->
1189+ Tok pos (CtrlSeq "mathop") "\\mathop"
1190+ : Tok pos Symbol "{"
1191+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1192+ : Tok pos Symbol "{"
1193+ : (contents' ++
1194+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1195+ _ -> contents'
1196+ macros <- sMacros <$> getState
1197+ case M.lookup name macros of
1198+ Just macro
1199+ | mtype == "newcommand" -> do
1200+ report $ MacroAlreadyDefined txt pos
1201+ return (name, macro)
1202+ | mtype == "providecommand" -> return (name, macro)
1203+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1204+
1205+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1206+newenvironment = do
1207+ pos <- getPosition
1208+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1209+ controlSeq "renewenvironment" <|>
1210+ controlSeq "provideenvironment"
1211+ withVerbatimMode $ do
1212+ optional $ symbol '*'
1213+ spaces
1214+ name <- untokenize <$> braced
1215+ spaces
1216+ numargs <- option 0 $ try bracketedNum
1217+ spaces
1218+ optarg <- option Nothing $ Just <$> try bracketedToks
1219+ let argspecs = map (\i -> ArgNum i) [1..numargs]
1220+ startcontents <- spaces >> bracedOrToken
1221+ endcontents <- spaces >> bracedOrToken
1222+ macros <- sMacros <$> getState
1223+ case M.lookup name macros of
1224+ Just _
1225+ | mtype == "newenvironment" -> do
1226+ report $ MacroAlreadyDefined name pos
1227+ return Nothing
1228+ | mtype == "provideenvironment" ->
1229+ return Nothing
1230+ _ -> return $ Just (name,
1231+ Macro ExpandWhenUsed argspecs optarg startcontents,
1232+ Macro ExpandWhenUsed [] Nothing endcontents)
1233+
1234+bracketedNum :: PandocMonad m => LP m Int
1235+bracketedNum = do
1236+ ds <- untokenize <$> bracketedToks
1237+ case safeRead ds of
1238+ Just i -> return i
1239+ _ -> return 0
1240+
7381241looseItem :: PandocMonad m => LP m Blocks
7391242looseItem = do
7401243 inListItem <- sInListItem <$> getState
@@ -840,7 +1343,7 @@ blockCommands = M.fromList
8401343 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
8411344 , ("signature", mempty <$ (skipopts *> authors))
8421345 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
843− , ("newtheorem", newtheorem inline)
1346+ , ("newtheorem", newtheorem)
8441347 , ("theoremstyle", theoremstyle)
8451348 -- KOMA-Script metadata commands
8461349 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -959,7 +1462,7 @@ environments = M.union (tableEnvironments blocks inline) $
9591462 , ("lilypond", rawVerbEnv "lilypond")
9601463 , ("ly", rawVerbEnv "ly")
9611464 -- amsthm
962− , ("proof", proof blocks opt)
1465+ , ("proof", proof)
9631466 -- etoolbox
9641467 , ("ifstrequal", ifstrequal)
9651468 , ("newtoggle", braced >>= newToggle)
@@ -980,17 +1483,128 @@ filecontents = try $ do
9801483 st{ sFileContents = M.insert fp txt (sFileContents st) }
9811484 return mempty
9821485
1486+theoremstyle :: PandocMonad m => LP m Blocks
1487+theoremstyle = do
1488+ stylename <- untokenize <$> braced
1489+ let mbstyle = case stylename of
1490+ "plain" -> Just PlainStyle
1491+ "definition" -> Just DefinitionStyle
1492+ "remark" -> Just RemarkStyle
1493+ _ -> Nothing
1494+ case mbstyle of
1495+ Nothing -> return ()
1496+ Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
1497+ return mempty
1498+
1499+newtheorem :: PandocMonad m => LP m Blocks
1500+newtheorem = do
1501+ number <- option True (False <$ symbol '*' <* sp)
1502+ name <- untokenize <$> braced
1503+ sp
1504+ series <- option Nothing $ Just . untokenize <$> bracketedToks
1505+ sp
1506+ showName <- tok
1507+ sp
1508+ syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
1509+ sty <- sLastTheoremStyle <$> getState
1510+ let spec = TheoremSpec { theoremName = showName
1511+ , theoremStyle = sty
1512+ , theoremSeries = series
1513+ , theoremSyncTo = syncTo
1514+ , theoremNumber = number
1515+ , theoremLastNum = DottedNum [0] }
1516+ tmap <- sTheoremMap <$> getState
1517+ updateState $ \s -> s{ sTheoremMap =
1518+ M.insert name spec tmap }
1519+ return mempty
1520+
1521+proof :: PandocMonad m => LP m Blocks
1522+proof = do
1523+ title <- option (B.text "Proof") opt
1524+ bs <- env "proof" blocks
1525+ return $
1526+ B.divWith ("", ["proof"], []) $
1527+ addQed $ addTitle (B.emph (title <> ".")) bs
1528+
1529+addTitle :: Inlines -> Blocks -> Blocks
1530+addTitle ils bs =
1531+ case B.toList bs of
1532+ (Para xs : rest)
1533+ -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
1534+ _ -> B.para ils <> bs
1535+
1536+addQed :: Blocks -> Blocks
1537+addQed bs =
1538+ case Seq.viewr (B.unMany bs) of
1539+ s Seq.:> Para ils
1540+ -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
1541+ _ -> bs <> B.para qedSign
1542+ where
1543+ qedSign = B.str "\xa0\x25FB"
1544+
9831545environment :: PandocMonad m => LP m Blocks
9841546environment = try $ do
9851547 controlSeq "begin"
9861548 name <- untokenize <$> braced
9871549 M.findWithDefault mzero name environments <|>
988− theoremEnvironment blocks opt name <|>
1550+ theoremEnvironment name <|>
9891551 if M.member name (inlineEnvironments
9901552 :: M.Map Text (LP PandocPure Inlines))
9911553 then mzero
9921554 else try (rawEnv name) <|> rawVerbEnv name
9931555
1556+theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
1557+theoremEnvironment name = do
1558+ tmap <- sTheoremMap <$> getState
1559+ case M.lookup name tmap of
1560+ Nothing -> mzero
1561+ Just tspec -> do
1562+ optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
1563+ mblabel <- option Nothing $ Just . untokenize <$>
1564+ try (spaces >> controlSeq "label" >> spaces >> braced)
1565+ bs <- env name blocks
1566+ number <-
1567+ if theoremNumber tspec
1568+ then do
1569+ let name' = fromMaybe name $ theoremSeries tspec
1570+ num <- getNextNumber
1571+ (maybe (DottedNum [0]) theoremLastNum .
1572+ M.lookup name' . sTheoremMap)
1573+ updateState $ \s ->
1574+ s{ sTheoremMap =
1575+ M.adjust
1576+ (\spec -> spec{ theoremLastNum = num })
1577+ name'
1578+ (sTheoremMap s)
1579+ }
1580+
1581+ case mblabel of
1582+ Just ident ->
1583+ updateState $ \s ->
1584+ s{ sLabels = M.insert ident
1585+ (B.toList $
1586+ theoremName tspec <> "\160" <>
1587+ str (renderDottedNum num)) (sLabels s) }
1588+ Nothing -> return ()
1589+ return $ space <> B.text (renderDottedNum num)
1590+ else return mempty
1591+ let titleEmph = case theoremStyle tspec of
1592+ PlainStyle -> B.strong
1593+ DefinitionStyle -> B.strong
1594+ RemarkStyle -> B.emph
1595+ let title = titleEmph (theoremName tspec <> number)
1596+ <> optTitle <> "." <> space
1597+ return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
1598+ $ case theoremStyle tspec of
1599+ PlainStyle -> walk italicize bs
1600+ _ -> bs
1601+
1602+italicize :: Block -> Block
1603+italicize x@(Para [Image{}]) = x -- see #6925
1604+italicize (Para ils) = Para [Emph ils]
1605+italicize (Plain ils) = Plain [Emph ils]
1606+italicize x = x
1607+
9941608rawEnv :: PandocMonad m => Text -> LP m Blocks
9951609rawEnv name = do
9961610 exts <- getOption readerExtensions
@@ -1162,8 +1776,7 @@ inputListing = do
11621776 let (ident,classes,kvs) = parseListingsOptions options
11631777 let classes' =
11641778 (case listingsLanguage options of
1165− Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1166− (T.pack $ takeExtension $ T.unpack f)) <>)
1779+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
11671780 Just _ -> id) classes
11681781 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
11691782 let lastline = fromMaybe (length codeLines) $
@@ -1231,18 +1844,12 @@ orderedList' = try $ do
12311844
12321845block :: PandocMonad m => LP m Blocks
12331846block = do
1234− Tok _ toktype _ <- lookAhead anyTok
1235− res <- (case toktype of
1236− Newline -> mempty <$ spaces1
1237− Spaces -> mempty <$ spaces1
1238− Comment -> mempty <$ spaces1
1239− Word -> paragraph
1240− CtrlSeq "begin" -> environment
1241− CtrlSeq _ -> macroDef (rawBlock "latex")
1242− <|> blockCommand
1243− _ -> mzero)
1244− <|> paragraph
1245− <|> grouped block
1847+ res <- (mempty <$ spaces1)
1848+ <|> environment
1849+ <|> macroDef (rawBlock "latex")
1850+ <|> blockCommand
1851+ <|> paragraph
1852+ <|> grouped block
12461853 trace (T.take 60 $ tshow $ B.toList res)
12471854 return res
12481855