@@ -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
@@ -232,6 +231,16 @@ mkImage options (T.unpack -> src) = do
232231 _ -> return src
233232 return $ imageWith attr (T.pack src') "" alt
234233
234+doxspace :: PandocMonad m => LP m Inlines
235+doxspace =
236+ (space <$ lookAhead (satisfyTok startsWithLetter)) <|> return mempty
237+ where startsWithLetter (Tok _ Word t) =
238+ case T.uncons t of
239+ Just (c, _) | isLetter c -> True
240+ _ -> False
241+ startsWithLetter _ = False
242+
243+
235244removeDoubleQuotes :: Text -> Text
236245removeDoubleQuotes t =
237246 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
@@ -281,6 +290,18 @@ quoted' f starter ender = do
281290lit :: Text -> LP m Inlines
282291lit = pure . str
283292
293+enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines
294+enquote starred mblang = do
295+ skipopts
296+ let lang = mblang >>= babelLangToBCP47
297+ let langspan = case lang of
298+ Nothing -> id
299+ Just l -> spanWith ("",[],[("lang", renderLang l)])
300+ quoteContext <- sQuoteContext <$> getState
301+ if starred || quoteContext == InDoubleQuote
302+ then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok
303+ else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok
304+
284305blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
285306blockquote cvariant mblang = do
286307 citepar <- if cvariant
@@ -296,13 +317,114 @@ blockquote cvariant mblang = do
296317 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
297318 return $ blockQuote . langdiv $ (bs <> citepar)
298319
320+doAcronym :: PandocMonad m => Text -> LP m Inlines
321+doAcronym form = do
322+ acro <- braced
323+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
324+ ("acronym-form", "singular+" <> form)])
325+ $ str $ untokenize acro]
326+
327+doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
328+doAcronymPlural form = do
329+ acro <- braced
330+ plural <- lit "s"
331+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
332+ ("acronym-form", "plural+" <> form)]) $
333+ mconcat [str $ untokenize acro, plural]]
334+
335+doverb :: PandocMonad m => LP m Inlines
336+doverb = do
337+ Tok _ Symbol t <- anySymbol
338+ marker <- case T.uncons t of
339+ Just (c, ts) | T.null ts -> return c
340+ _ -> mzero
341+ withVerbatimMode $
342+ code . untokenize <$>
343+ manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
344+
345+verbTok :: PandocMonad m => Char -> LP m Tok
346+verbTok stopchar = do
347+ t@(Tok pos toktype txt) <- anyTok
348+ case T.findIndex (== stopchar) txt of
349+ Nothing -> return t
350+ Just i -> do
351+ let (t1, t2) = T.splitAt i txt
352+ inp <- getInput
353+ setInput $ Tok (incSourceColumn pos i) Symbol (T.singleton stopchar)
354+ : totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
355+ return $ Tok pos toktype t1
356+
357+listingsLanguage :: [(Text, Text)] -> Maybe Text
358+listingsLanguage opts =
359+ case lookup "language" opts of
360+ Nothing -> Nothing
361+ Just l -> fromListingsLanguage l `mplus` Just l
362+
363+dolstinline :: PandocMonad m => LP m Inlines
364+dolstinline = do
365+ options <- option [] keyvals
366+ let classes = maybeToList $ listingsLanguage options
367+ doinlinecode classes
368+
369+domintinline :: PandocMonad m => LP m Inlines
370+domintinline = do
371+ skipopts
372+ cls <- untokenize <$> braced
373+ doinlinecode [cls]
374+
375+doinlinecode :: PandocMonad m => [Text] -> LP m Inlines
376+doinlinecode classes = do
377+ Tok _ Symbol t <- anySymbol
378+ marker <- case T.uncons t of
379+ Just (c, ts) | T.null ts -> return c
380+ _ -> mzero
381+ let stopchar = if marker == '{' then '}' else marker
382+ withVerbatimMode $
383+ codeWith ("",classes,[]) . T.map nlToSpace . untokenize <$>
384+ manyTill (verbTok stopchar) (symbol stopchar)
385+
386+nlToSpace :: Char -> Char
387+nlToSpace '\n' = ' '
388+nlToSpace x = x
389+
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+
299423inlineCommand' :: PandocMonad m => LP m Inlines
300424inlineCommand' = try $ do
301425 Tok _ (CtrlSeq name) cmd <- anyControlSeq
302426 guard $ name /= "begin" && name /= "end" && name /= "and"
303− star <- if T.all isAlphaNum name
304− then option "" ("*" <$ symbol '*' <* sp)
305− else pure ""
427+ star <- option "" ("*" <$ symbol '*' <* sp)
306428 overlay <- option "" overlaySpecification
307429 let name' = name <> star <> overlay
308430 let names = ordNub [name', name] -- check non-starred as fallback
@@ -316,6 +438,9 @@ inlineCommand' = try $ do
316438tok :: PandocMonad m => LP m Inlines
317439tok = tokWith inline
318440
441+inBrackets :: Inlines -> Inlines
442+inBrackets x = str "[" <> x <> str "]"
443+
319444unescapeURL :: Text -> Text
320445unescapeURL = T.concat . go . T.splitOn "\\"
321446 where
@@ -327,103 +452,287 @@ unescapeURL = T.concat . go . T.splitOn "\\"
327452 , isEscapable c = t
328453 | otherwise = "\\" <> t
329454
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+
330500inlineCommands :: 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− ]
501+inlineCommands =
502+ M.union inlineLanguageCommands $
503+ M.union (accentCommands tok) $
504+ M.union (citationCommands inline) $
505+ M.fromList
506+ [ ("emph", extractSpaces emph <$> tok)
507+ , ("textit", extractSpaces emph <$> tok)
508+ , ("textsl", extractSpaces emph <$> tok)
509+ , ("textsc", extractSpaces smallcaps <$> tok)
510+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
511+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
512+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
513+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
514+ , ("texttt", ttfamily)
515+ , ("sout", extractSpaces strikeout <$> tok)
516+ , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
517+ , ("lq", return (str "‘"))
518+ , ("rq", return (str "’"))
519+ , ("textquoteleft", return (str "‘"))
520+ , ("textquoteright", return (str "’"))
521+ , ("textquotedblleft", return (str "“"))
522+ , ("textquotedblright", return (str "”"))
523+ , ("textsuperscript", extractSpaces superscript <$> tok)
524+ , ("textsubscript", extractSpaces subscript <$> tok)
525+ , ("textbackslash", lit "\\")
526+ , ("backslash", lit "\\")
527+ , ("slash", lit "/")
528+ , ("textbf", extractSpaces strong <$> tok)
529+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
530+ , ("underline", underline <$> tok)
531+ , ("ldots", lit "…")
532+ , ("vdots", lit "\8942")
533+ , ("dots", lit "…")
534+ , ("mdots", lit "…")
535+ , ("sim", lit "~")
536+ , ("sep", lit ",")
537+ , ("label", rawInlineOr "label" dolabel)
538+ , ("ref", rawInlineOr "ref" $ doref "ref")
539+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
540+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
541+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
542+ , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
543+ , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
544+ , ("lettrine", rawInlineOr "lettrine" lettrine)
545+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
546+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
547+ , ("ensuremath", mathInline . untokenize <$> braced)
548+ , ("texorpdfstring", const <$> tok <*> tok)
549+ , ("P", lit "¶")
550+ , ("S", lit "§")
551+ , ("$", lit "$")
552+ , ("%", lit "%")
553+ , ("&", lit "&")
554+ , ("#", lit "#")
555+ , ("_", lit "_")
556+ , ("{", lit "{")
557+ , ("}", lit "}")
558+ , ("qed", lit "\a0\x25FB")
559+ -- old TeX commands
560+ , ("em", extractSpaces emph <$> inlines)
561+ , ("it", extractSpaces emph <$> inlines)
562+ , ("sl", extractSpaces emph <$> inlines)
563+ , ("bf", extractSpaces strong <$> inlines)
564+ , ("tt", code . stringify . toList <$> inlines)
565+ , ("rm", inlines)
566+ , ("itshape", extractSpaces emph <$> inlines)
567+ , ("slshape", extractSpaces emph <$> inlines)
568+ , ("scshape", extractSpaces smallcaps <$> inlines)
569+ , ("bfseries", extractSpaces strong <$> inlines)
570+ , ("MakeUppercase", makeUppercase <$> tok)
571+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
572+ , ("uppercase", makeUppercase <$> tok)
573+ , ("MakeLowercase", makeLowercase <$> tok)
574+ , ("MakeTextLowercase", makeLowercase <$> tok)
575+ , ("lowercase", makeLowercase <$> tok)
576+ , ("/", pure mempty) -- italic correction
577+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
578+ guard $ not inTableCell
579+ optional rawopt
580+ spaces))
581+ , (",", lit "\8198")
582+ , ("@", pure mempty)
583+ , (" ", lit "\160")
584+ , ("ps", pure $ str "PS." <> space)
585+ , ("TeX", lit "TeX")
586+ , ("LaTeX", lit "LaTeX")
587+ , ("bar", lit "|")
588+ , ("textless", lit "<")
589+ , ("textgreater", lit ">")
590+ , ("thanks", skipopts >> note <$> grouped block)
591+ , ("footnote", skipopts >> note <$> grouped block)
592+ , ("passthrough", tok) -- \passthrough macro used by latex writer
593+ -- for listings
594+ , ("verb", doverb)
595+ , ("lstinline", dolstinline)
596+ , ("mintinline", domintinline)
597+ , ("Verb", doverb)
598+ , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
599+ bracedUrl)
600+ , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
601+ , ("href", do url <- bracedUrl
602+ sp
603+ link (unescapeURL $ untokenize url) "" <$> tok)
604+ , ("includegraphics", do options <- option [] keyvals
605+ src <- braced
606+ mkImage options . unescapeURL . removeDoubleQuotes $
607+ untokenize src)
608+ , ("enquote*", enquote True Nothing)
609+ , ("enquote", enquote False Nothing)
610+ -- foreignquote is supposed to use native quote marks
611+ , ("foreignquote*", braced >>= enquote True . Just . untokenize)
612+ , ("foreignquote", braced >>= enquote False . Just . untokenize)
613+ -- hypehnquote uses regular quotes
614+ , ("hyphenquote*", braced >>= enquote True . Just . untokenize)
615+ , ("hyphenquote", braced >>= enquote False . Just . untokenize)
616+ , ("figurename", doTerm Translations.Figure)
617+ , ("prefacename", doTerm Translations.Preface)
618+ , ("refname", doTerm Translations.References)
619+ , ("bibname", doTerm Translations.Bibliography)
620+ , ("chaptername", doTerm Translations.Chapter)
621+ , ("partname", doTerm Translations.Part)
622+ , ("contentsname", doTerm Translations.Contents)
623+ , ("listfigurename", doTerm Translations.ListOfFigures)
624+ , ("listtablename", doTerm Translations.ListOfTables)
625+ , ("indexname", doTerm Translations.Index)
626+ , ("abstractname", doTerm Translations.Abstract)
627+ , ("tablename", doTerm Translations.Table)
628+ , ("enclname", doTerm Translations.Encl)
629+ , ("ccname", doTerm Translations.Cc)
630+ , ("headtoname", doTerm Translations.To)
631+ , ("pagename", doTerm Translations.Page)
632+ , ("seename", doTerm Translations.See)
633+ , ("seealsoname", doTerm Translations.SeeAlso)
634+ , ("proofname", doTerm Translations.Proof)
635+ , ("glossaryname", doTerm Translations.Glossary)
636+ , ("lstlistingname", doTerm Translations.Listing)
637+ , ("hyperlink", hyperlink)
638+ , ("hypertarget", hypertargetInline)
639+ -- glossaries package
640+ , ("gls", doAcronym "short")
641+ , ("Gls", doAcronym "short")
642+ , ("glsdesc", doAcronym "long")
643+ , ("Glsdesc", doAcronym "long")
644+ , ("GLSdesc", doAcronym "long")
645+ , ("acrlong", doAcronym "long")
646+ , ("Acrlong", doAcronym "long")
647+ , ("acrfull", doAcronym "full")
648+ , ("Acrfull", doAcronym "full")
649+ , ("acrshort", doAcronym "abbrv")
650+ , ("Acrshort", doAcronym "abbrv")
651+ , ("glspl", doAcronymPlural "short")
652+ , ("Glspl", doAcronymPlural "short")
653+ , ("glsdescplural", doAcronymPlural "long")
654+ , ("Glsdescplural", doAcronymPlural "long")
655+ , ("GLSdescplural", doAcronymPlural "long")
656+ -- acronyms package
657+ , ("ac", doAcronym "short")
658+ , ("acf", doAcronym "full")
659+ , ("acs", doAcronym "abbrv")
660+ , ("acl", doAcronym "long")
661+ , ("acp", doAcronymPlural "short")
662+ , ("acfp", doAcronymPlural "full")
663+ , ("acsp", doAcronymPlural "abbrv")
664+ , ("aclp", doAcronymPlural "long")
665+ , ("Ac", doAcronym "short")
666+ , ("Acf", doAcronym "full")
667+ , ("Acs", doAcronym "abbrv")
668+ , ("Acl", doAcronym "long")
669+ , ("Acp", doAcronymPlural "short")
670+ , ("Acfp", doAcronymPlural "full")
671+ , ("Acsp", doAcronymPlural "abbrv")
672+ , ("Aclp", doAcronymPlural "long")
673+ -- siuntix
674+ , ("si", skipopts *> dosi tok)
675+ , ("SI", doSI tok)
676+ , ("SIrange", doSIrange True tok)
677+ , ("numrange", doSIrange False tok)
678+ , ("numlist", doSInumlist)
679+ , ("num", doSInum)
680+ , ("ang", doSIang)
681+ -- hyphenat
682+ , ("bshyp", lit "\\\173")
683+ , ("fshyp", lit "/\173")
684+ , ("dothyp", lit ".\173")
685+ , ("colonhyp", lit ":\173")
686+ , ("hyp", lit "-")
687+ , ("nohyphens", tok)
688+ , ("textnhtt", ttfamily)
689+ , ("nhttfamily", ttfamily)
690+ -- LaTeX colors
691+ , ("textcolor", coloredInline "color")
692+ , ("colorbox", coloredInline "background-color")
693+ -- fontawesome
694+ , ("faCheck", lit "\10003")
695+ , ("faClose", lit "\10007")
696+ -- xspace
697+ , ("xspace", doxspace)
698+ -- etoolbox
699+ , ("ifstrequal", ifstrequal)
700+ , ("newtoggle", braced >>= newToggle)
701+ , ("toggletrue", braced >>= setToggle True)
702+ , ("togglefalse", braced >>= setToggle False)
703+ , ("iftoggle", try $ ifToggle >> inline)
704+ -- biblatex misc
705+ , ("RN", romanNumeralUpper)
706+ , ("Rn", romanNumeralLower)
707+ -- babel
708+ , ("foreignlanguage", foreignlanguage)
709+ -- include
710+ , ("input", rawInlineOr "input" $ include "input")
711+ -- soul package
712+ , ("ul", underline <$> tok)
713+ -- ulem package
714+ , ("uline", underline <$> tok)
715+ -- plain tex stuff that should just be passed through as raw tex
716+ , ("ifdim", ifdim)
717+ -- bibtex
718+ , ("mkbibquote", spanWith nullAttr . doubleQuoted <$> tok)
719+ , ("mkbibemph", spanWith nullAttr . emph <$> tok)
720+ , ("mkbibitalic", spanWith nullAttr . emph <$> tok)
721+ , ("mkbibbold", spanWith nullAttr . strong <$> tok)
722+ , ("mkbibparens",
723+ spanWith nullAttr . (\x -> str "(" <> x <> str ")") <$> tok)
724+ , ("mkbibbrackets",
725+ spanWith nullAttr . (\x -> str "[" <> x <> str "]") <$> tok)
726+ , ("autocap", spanWith nullAttr <$> tok)
727+ , ("textnormal", spanWith ("",["nodecor"],[]) <$> tok)
728+ , ("bibstring",
729+ (\x -> spanWith ("",[],[("bibstring",x)]) (str x)) . untokenize
730+ <$> braced)
731+ , ("adddot", pure (str "."))
732+ , ("adddotspace", pure (spanWith nullAttr (str "." <> space)))
733+ , ("addabbrvspace", pure space)
734+ , ("hyphen", pure (str "-"))
735+ ]
427736
428737lettrine :: PandocMonad m => LP m Inlines
429738lettrine = do
@@ -447,18 +756,32 @@ alterStr :: (Text -> Text) -> Inline -> Inline
447756alterStr f (Str xs) = Str (f xs)
448757alterStr _ x = x
449758
759+foreignlanguage :: PandocMonad m => LP m Inlines
760+foreignlanguage = do
761+ babelLang <- untokenize <$> braced
762+ case babelLangToBCP47 babelLang of
763+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
764+ _ -> tok
765+
766+inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
767+inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
768+ where
769+ mk (polyglossia, bcp47Func) =
770+ ("text" <> polyglossia, inlineLanguage bcp47Func)
771+
772+inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
773+inlineLanguage bcp47Func = do
774+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
775+ <$> rawopt
776+ let lang = renderLang $ bcp47Func o
777+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
778+
450779hyperlink :: PandocMonad m => LP m Inlines
451780hyperlink = try $ do
452781 src <- untokenize <$> braced
453782 lab <- tok
454783 return $ link ("#" <> src) "" lab
455784
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−
462785hypertargetBlock :: PandocMonad m => LP m Blocks
463786hypertargetBlock = try $ do
464787 ref <- untokenize <$> braced
@@ -473,6 +796,31 @@ hypertargetInline = try $ do
473796 ils <- grouped inline
474797 return $ spanWith (ref, [], []) ils
475798
799+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
800+romanNumeralUpper =
801+ str . toRomanNumeral <$> romanNumeralArg
802+
803+romanNumeralLower :: (PandocMonad m) => LP m Inlines
804+romanNumeralLower =
805+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
806+
807+romanNumeralArg :: (PandocMonad m) => LP m Int
808+romanNumeralArg = spaces *> (parser <|> inBraces)
809+ where
810+ inBraces = do
811+ symbol '{'
812+ spaces
813+ res <- parser
814+ spaces
815+ symbol '}'
816+ return res
817+ parser = do
818+ s <- untokenize <$> many1 (satisfyTok isWordTok)
819+ let (digits, rest) = T.span isDigit s
820+ unless (T.null rest) $
821+ Prelude.fail "Non-digits in argument to \\Rn or \\RN"
822+ safeRead digits
823+
476824newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
477825newToggle name = do
478826 updateState $ \st ->
@@ -503,6 +851,9 @@ ifToggle = do
503851 report $ UndefinedToggle name' pos
504852 return ()
505853
854+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
855+doTerm term = str <$> translateTerm term
856+
506857ifstrequal :: (PandocMonad m, Monoid a) => LP m a
507858ifstrequal = do
508859 str1 <- tok
@@ -523,6 +874,13 @@ coloredInline stylename = do
523874ttfamily :: PandocMonad m => LP m Inlines
524875ttfamily = code . stringify . toList <$> tok
525876
877+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
878+rawInlineOr name' fallback = do
879+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
880+ if parseRaw
881+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
882+ else fallback
883+
526884processHBox :: Inlines -> Inlines
527885processHBox = walk convert
528886 where
@@ -573,6 +931,25 @@ treatAsInline = Set.fromList
573931 , "pagebreak"
574932 ]
575933
934+dolabel :: PandocMonad m => LP m Inlines
935+dolabel = do
936+ v <- braced
937+ let refstr = untokenize v
938+ updateState $ \st ->
939+ st{ sLastLabel = Just refstr }
940+ return $ spanWith (refstr,[],[("label", refstr)])
941+ $ inBrackets $ str $ untokenize v
942+
943+doref :: PandocMonad m => Text -> LP m Inlines
944+doref cls = do
945+ v <- braced
946+ let refstr = untokenize v
947+ return $ linkWith ("",[],[ ("reference-type", cls)
948+ , ("reference", refstr)])
949+ ("#" <> refstr)
950+ ""
951+ (inBrackets $ str refstr)
952+
576953lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
577954lookupListDefault d = (fromMaybe d .) . lookupList
578955 where lookupList l m = msum $ map (`M.lookup` m) l
@@ -632,7 +1009,7 @@ opt = do
6321009 parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
6331010 case parsed of
6341011 Right result -> return result
635− Left e -> throwError $ PandocParsecError (toSources toks) e
1012+ Left e -> throwError $ PandocParsecError (untokenize toks) e
6361013
6371014-- block elements:
6381015
@@ -735,6 +1112,143 @@ authors = try $ do
7351112 egroup
7361113 addMeta "author" (map trimInlines auths)
7371114
1115+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1116+macroDef constructor = do
1117+ (_, s) <- withRaw (commandDef <|> environmentDef)
1118+ (constructor (untokenize s) <$
1119+ guardDisabled Ext_latex_macros)
1120+ <|> return mempty
1121+ where commandDef = do
1122+ (name, macro') <- newcommand <|> letmacro <|> defmacro
1123+ guardDisabled Ext_latex_macros <|>
1124+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1125+ environmentDef = do
1126+ mbenv <- newenvironment
1127+ case mbenv of
1128+ Nothing -> return ()
1129+ Just (name, macro1, macro2) ->
1130+ guardDisabled Ext_latex_macros <|>
1131+ do updateState $ \s -> s{ sMacros =
1132+ M.insert name macro1 (sMacros s) }
1133+ updateState $ \s -> s{ sMacros =
1134+ M.insert ("end" <> name) macro2 (sMacros s) }
1135+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1136+ -- is equivalent to
1137+ -- @\newcommand{\envname}[n-args][default]{begin}@
1138+ -- @\newcommand{\endenvname}@
1139+
1140+letmacro :: PandocMonad m => LP m (Text, Macro)
1141+letmacro = do
1142+ controlSeq "let"
1143+ (name, contents) <- withVerbatimMode $ do
1144+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1145+ optional $ symbol '='
1146+ spaces
1147+ -- we first parse in verbatim mode, and then expand macros,
1148+ -- because we don't want \let\foo\bar to turn into
1149+ -- \let\foo hello if we have previously \def\bar{hello}
1150+ contents <- bracedOrToken
1151+ return (name, contents)
1152+ contents' <- doMacros' 0 contents
1153+ return (name, Macro ExpandWhenDefined [] Nothing contents')
1154+
1155+defmacro :: PandocMonad m => LP m (Text, Macro)
1156+defmacro = try $
1157+ -- we use withVerbatimMode, because macros are to be expanded
1158+ -- at point of use, not point of definition
1159+ withVerbatimMode $ do
1160+ controlSeq "def"
1161+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1162+ argspecs <- many (argspecArg <|> argspecPattern)
1163+ contents <- bracedOrToken
1164+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1165+
1166+argspecArg :: PandocMonad m => LP m ArgSpec
1167+argspecArg = do
1168+ Tok _ (Arg i) _ <- satisfyTok isArgTok
1169+ return $ ArgNum i
1170+
1171+argspecPattern :: PandocMonad m => LP m ArgSpec
1172+argspecPattern =
1173+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1174+ (toktype' == Symbol || toktype' == Word) &&
1175+ (txt /= "{" && txt /= "\\" && txt /= "}")))
1176+
1177+newcommand :: PandocMonad m => LP m (Text, Macro)
1178+newcommand = do
1179+ pos <- getPosition
1180+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1181+ controlSeq "renewcommand" <|>
1182+ controlSeq "providecommand" <|>
1183+ controlSeq "DeclareMathOperator" <|>
1184+ controlSeq "DeclareRobustCommand"
1185+ withVerbatimMode $ do
1186+ Tok _ (CtrlSeq name) txt <- do
1187+ optional (symbol '*')
1188+ anyControlSeq <|>
1189+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1190+ spaces
1191+ numargs <- option 0 $ try bracketedNum
1192+ let argspecs = map ArgNum [1..numargs]
1193+ spaces
1194+ optarg <- option Nothing $ Just <$> try bracketedToks
1195+ spaces
1196+ contents' <- bracedOrToken
1197+ let contents =
1198+ case mtype of
1199+ "DeclareMathOperator" ->
1200+ Tok pos (CtrlSeq "mathop") "\\mathop"
1201+ : Tok pos Symbol "{"
1202+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1203+ : Tok pos Symbol "{"
1204+ : (contents' ++
1205+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1206+ _ -> contents'
1207+ macros <- sMacros <$> getState
1208+ case M.lookup name macros of
1209+ Just macro
1210+ | mtype == "newcommand" -> do
1211+ report $ MacroAlreadyDefined txt pos
1212+ return (name, macro)
1213+ | mtype == "providecommand" -> return (name, macro)
1214+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1215+
1216+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1217+newenvironment = do
1218+ pos <- getPosition
1219+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1220+ controlSeq "renewenvironment" <|>
1221+ controlSeq "provideenvironment"
1222+ withVerbatimMode $ do
1223+ optional $ symbol '*'
1224+ spaces
1225+ name <- untokenize <$> braced
1226+ spaces
1227+ numargs <- option 0 $ try bracketedNum
1228+ spaces
1229+ optarg <- option Nothing $ Just <$> try bracketedToks
1230+ let argspecs = map (\i -> ArgNum i) [1..numargs]
1231+ startcontents <- spaces >> bracedOrToken
1232+ endcontents <- spaces >> bracedOrToken
1233+ macros <- sMacros <$> getState
1234+ case M.lookup name macros of
1235+ Just _
1236+ | mtype == "newenvironment" -> do
1237+ report $ MacroAlreadyDefined name pos
1238+ return Nothing
1239+ | mtype == "provideenvironment" ->
1240+ return Nothing
1241+ _ -> return $ Just (name,
1242+ Macro ExpandWhenUsed argspecs optarg startcontents,
1243+ Macro ExpandWhenUsed [] Nothing endcontents)
1244+
1245+bracketedNum :: PandocMonad m => LP m Int
1246+bracketedNum = do
1247+ ds <- untokenize <$> bracketedToks
1248+ case safeRead ds of
1249+ Just i -> return i
1250+ _ -> return 0
1251+
7381252looseItem :: PandocMonad m => LP m Blocks
7391253looseItem = do
7401254 inListItem <- sInListItem <$> getState
@@ -840,7 +1354,7 @@ blockCommands = M.fromList
8401354 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
8411355 , ("signature", mempty <$ (skipopts *> authors))
8421356 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
843− , ("newtheorem", newtheorem inline)
1357+ , ("newtheorem", newtheorem)
8441358 , ("theoremstyle", theoremstyle)
8451359 -- KOMA-Script metadata commands
8461360 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -959,7 +1473,7 @@ environments = M.union (tableEnvironments blocks inline) $
9591473 , ("lilypond", rawVerbEnv "lilypond")
9601474 , ("ly", rawVerbEnv "ly")
9611475 -- amsthm
962− , ("proof", proof blocks opt)
1476+ , ("proof", proof)
9631477 -- etoolbox
9641478 , ("ifstrequal", ifstrequal)
9651479 , ("newtoggle", braced >>= newToggle)
@@ -980,17 +1494,128 @@ filecontents = try $ do
9801494 st{ sFileContents = M.insert fp txt (sFileContents st) }
9811495 return mempty
9821496
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+
9831556environment :: PandocMonad m => LP m Blocks
9841557environment = try $ do
9851558 controlSeq "begin"
9861559 name <- untokenize <$> braced
9871560 M.findWithDefault mzero name environments <|>
988− theoremEnvironment blocks opt name <|>
1561+ theoremEnvironment name <|>
9891562 if M.member name (inlineEnvironments
9901563 :: M.Map Text (LP PandocPure Inlines))
9911564 then mzero
9921565 else try (rawEnv name) <|> rawVerbEnv name
9931566
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+
9941619rawEnv :: PandocMonad m => Text -> LP m Blocks
9951620rawEnv name = do
9961621 exts <- getOption readerExtensions
@@ -1162,8 +1787,7 @@ inputListing = do
11621787 let (ident,classes,kvs) = parseListingsOptions options
11631788 let classes' =
11641789 (case listingsLanguage options of
1165− Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1166− (T.pack $ takeExtension $ T.unpack f)) <>)
1790+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
11671791 Just _ -> id) classes
11681792 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
11691793 let lastline = fromMaybe (length codeLines) $