@@ -1,10 +1,14 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
15{-# LANGUAGE OverloadedStrings #-}
26{-# LANGUAGE PatternGuards #-}
37{-# LANGUAGE ScopedTypeVariables #-}
48{-# LANGUAGE ViewPatterns #-}
59{- |
610 Module : Text.Pandoc.Readers.LaTeX
7− Copyright : Copyright (C) 2006-2021 John MacFarlane
11+ Copyright : Copyright (C) 2006-2020 John MacFarlane
812 License : GNU GPL, version 2 or above
913
1014 Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -18,58 +22,50 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
1822 applyMacros,
1923 rawLaTeXInline,
2024 rawLaTeXBlock,
21− inlineCommand
25+ inlineCommand,
26+ tokenize,
27+ untokenize
2228 ) where
2329
2430import Control.Applicative (many, optional, (<|>))
2531import Control.Monad
2632import Control.Monad.Except (throwError)
27−import Data.Char (isDigit, isLetter, isAlphaNum, toUpper, chr)
33+import Data.Char (isDigit, isLetter, toUpper, chr)
2834import Data.Default
35+import Data.Functor (($>))
2936import Data.List (intercalate)
3037import qualified Data.Map as M
3138import Data.Maybe (fromMaybe, maybeToList)
3239import qualified Data.Set as Set
40+import qualified Data.Sequence as Seq
3341import Data.Text (Text)
3442import qualified Data.Text as T
35−import Skylighting (defaultSyntaxMap)
3643import System.FilePath (addExtension, replaceExtension, takeExtension)
37−import Text.Collate.Lang (renderLang)
38−import Text.Pandoc.Builder as B
44+import Text.Pandoc.BCP47 (Lang (..), renderLang)
45+import Text.Pandoc.Builder
3946import Text.Pandoc.Class.PandocPure (PandocPure)
4047import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
41− readFileFromDirs, report,
42− setResourcePath)
48+ readFileFromDirs, report, setResourcePath,
49+ setTranslations, translateTerm)
4350import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
44−import Text.Pandoc.Highlighting (languagesByExtension)
51+import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
4552import Text.Pandoc.ImageSize (numUnit, showFl)
4653import Text.Pandoc.Logging
4754import Text.Pandoc.Options
4855import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
4956 optional, space, spaces, withRaw, (<|>))
50−import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
57+import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
58+ ArgSpec (..), Tok (..), TokType (..))
5159import Text.Pandoc.Readers.LaTeX.Parsing
52−import 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)
58−import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
59−import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
60−import Text.Pandoc.Readers.LaTeX.Lang (inlineLanguageCommands,
61− enquoteCommands,
62− 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)
60+import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
61+ babelLangToBCP47)
62+import Text.Pandoc.Readers.LaTeX.SIunitx
7063import Text.Pandoc.Shared
64+import qualified Text.Pandoc.Translations as Translations
7165import Text.Pandoc.Walk
72−import Data.List.NonEmpty (nonEmpty)
66+import qualified Text.Pandoc.Builder as B
67+import qualified Data.Text.Normalize as Normalize
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,14 +163,14 @@ 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
174− (mempty <$ (controlSeq "input" >> skipMany rawopt >> braced))
173+ (mempty <$ (controlSeq "input" >> skipMany opt >> braced))
175174 inlines
176175 <|> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
177176 inlines
@@ -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,19 @@ 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+
250+lit :: Text -> LP m Inlines
251+lit = pure . str
252+
235253removeDoubleQuotes :: Text -> Text
236254removeDoubleQuotes t =
237255 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
@@ -278,14 +296,23 @@ quoted' f starter ender = do
278296 cs -> cs)
279297 else lit startchs
280298
281−lit :: Text -> LP m Inlines
282−lit = pure . str
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
283310
284311blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
285312blockquote cvariant mblang = do
286313 citepar <- if cvariant
287314 then (\xs -> para (cite xs mempty))
288− <$> cites inline NormalCitation False
315+ <$> cites NormalCitation False
289316 else option mempty $ para <$> bracketed inline
290317 let lang = mblang >>= babelLangToBCP47
291318 let langdiv = case lang of
@@ -296,13 +323,224 @@ 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+
429+-- citations
430+
431+addPrefix :: [Inline] -> [Citation] -> [Citation]
432+addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
433+addPrefix _ _ = []
434+
435+addSuffix :: [Inline] -> [Citation] -> [Citation]
436+addSuffix s ks@(_:_) =
437+ let k = last ks
438+ in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
439+addSuffix _ _ = []
440+
441+simpleCiteArgs :: PandocMonad m => LP m [Citation]
442+simpleCiteArgs = try $ do
443+ first <- optionMaybe $ toList <$> opt
444+ second <- optionMaybe $ toList <$> opt
445+ keys <- try $ bgroup *> manyTill citationLabel egroup
446+ let (pre, suf) = case (first , second ) of
447+ (Just s , Nothing) -> (mempty, s )
448+ (Just s , Just t ) -> (s , t )
449+ _ -> (mempty, mempty)
450+ conv k = Citation { citationId = k
451+ , citationPrefix = []
452+ , citationSuffix = []
453+ , citationMode = NormalCitation
454+ , citationHash = 0
455+ , citationNoteNum = 0
456+ }
457+ return $ addPrefix pre $ addSuffix suf $ map conv keys
458+
459+citationLabel :: PandocMonad m => LP m Text
460+citationLabel = do
461+ sp
462+ untokenize <$>
463+ (many1 (satisfyTok isWordTok <|> symbolIn bibtexKeyChar)
464+ <* sp
465+ <* optional (symbol ',')
466+ <* sp)
467+ where bibtexKeyChar = ".:;?!`'()/*@_+=-&[]" :: [Char]
468+
469+cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
470+cites mode multi = try $ do
471+ cits <- if multi
472+ then do
473+ multiprenote <- optionMaybe $ toList <$> paropt
474+ multipostnote <- optionMaybe $ toList <$> paropt
475+ let (pre, suf) = case (multiprenote, multipostnote) of
476+ (Just s , Nothing) -> (mempty, s)
477+ (Nothing , Just t) -> (mempty, t)
478+ (Just s , Just t ) -> (s, t)
479+ _ -> (mempty, mempty)
480+ tempCits <- many1 simpleCiteArgs
481+ case tempCits of
482+ (k:ks) -> case ks of
483+ (_:_) -> return $ (addMprenote pre k : init ks) ++
484+ [addMpostnote suf (last ks)]
485+ _ -> return [addMprenote pre (addMpostnote suf k)]
486+ _ -> return [[]]
487+ else count 1 simpleCiteArgs
488+ let cs = concat cits
489+ return $ case mode of
490+ AuthorInText -> case cs of
491+ (c:rest) -> c {citationMode = mode} : rest
492+ [] -> []
493+ _ -> map (\a -> a {citationMode = mode}) cs
494+ where mprenote (k:ks) = (k:ks) ++ [Space]
495+ mprenote _ = mempty
496+ mpostnote (k:ks) = [Str ",", Space] ++ (k:ks)
497+ mpostnote _ = mempty
498+ addMprenote mpn (k:ks) =
499+ let mpnfinal = case citationPrefix k of
500+ (_:_) -> mprenote mpn
501+ _ -> mpn
502+ in addPrefix mpnfinal (k:ks)
503+ addMprenote _ _ = []
504+ addMpostnote = addSuffix . mpostnote
505+
506+citation :: PandocMonad m => Text -> CitationMode -> Bool -> LP m Inlines
507+citation name mode multi = do
508+ (c,raw) <- withRaw $ cites mode multi
509+ return $ cite c (rawInline "latex" $ "\\" <> name <> untokenize raw)
510+
511+handleCitationPart :: Inlines -> [Citation]
512+handleCitationPart ils =
513+ let isCite Cite{} = True
514+ isCite _ = False
515+ (pref, rest) = break isCite (toList ils)
516+ in case rest of
517+ (Cite cs _:suff) -> addPrefix pref $ addSuffix suff cs
518+ _ -> []
519+
520+complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
521+complexNatbibCitation mode = try $ do
522+ (cs, raw) <-
523+ withRaw $ concat <$> do
524+ bgroup
525+ items <- mconcat <$>
526+ many1 (notFollowedBy (symbol ';') >> inline)
527+ `sepBy1` symbol ';'
528+ egroup
529+ return $ map handleCitationPart items
530+ case cs of
531+ [] -> mzero
532+ (c:cits) -> return $ cite (c{ citationMode = mode }:cits)
533+ (rawInline "latex" $ "\\citetext" <> untokenize raw)
534+
535+inNote :: Inlines -> Inlines
536+inNote ils =
537+ note $ para $ ils <> str "."
538+
299539inlineCommand' :: PandocMonad m => LP m Inlines
300540inlineCommand' = try $ do
301541 Tok _ (CtrlSeq name) cmd <- anyControlSeq
302542 guard $ name /= "begin" && name /= "end" && name /= "and"
303− star <- if T.all isAlphaNum name
304− then option "" ("*" <$ symbol '*' <* sp)
305− else pure ""
543+ star <- option "" ("*" <$ symbol '*' <* sp)
306544 overlay <- option "" overlaySpecification
307545 let name' = name <> star <> overlay
308546 let names = ordNub [name', name] -- check non-starred as fallback
@@ -313,8 +551,28 @@ inlineCommand' = try $ do
313551 <|> ignore rawcommand
314552 lookupListDefault raw names inlineCommands
315553
554+
316555tok :: PandocMonad m => LP m Inlines
317−tok = tokWith inline
556+tok = try $ spaces >> grouped inline <|> inlineCommand' <|> singleChar'
557+ where singleChar' = do
558+ Tok _ _ t <- singleChar
559+ return $ str t
560+
561+opt :: PandocMonad m => LP m Inlines
562+opt = do
563+ toks <- try (sp *> bracketedToks <* sp)
564+ -- now parse the toks as inlines
565+ st <- getState
566+ parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
567+ case parsed of
568+ Right result -> return result
569+ Left e -> throwError $ PandocParsecError (untokenize toks) e
570+
571+paropt :: PandocMonad m => LP m Inlines
572+paropt = parenWrapped inline
573+
574+inBrackets :: Inlines -> Inlines
575+inBrackets x = str "[" <> x <> str "]"
318576
319577unescapeURL :: Text -> Text
320578unescapeURL = T.concat . go . T.splitOn "\\"
@@ -327,107 +585,379 @@ unescapeURL = T.concat . go . T.splitOn "\\"
327585 , isEscapable c = t
328586 | otherwise = "\\" <> t
329587
588+mathEnvWith :: PandocMonad m
589+ => (Inlines -> a) -> Maybe Text -> Text -> LP m a
590+mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
591+ where inner x = case innerEnv of
592+ Nothing -> x
593+ Just y -> "\\begin{" <> y <> "}\n" <> x <>
594+ "\\end{" <> y <> "}"
595+
596+mathEnv :: PandocMonad m => Text -> LP m Text
597+mathEnv name = do
598+ skipopts
599+ optional blankline
600+ res <- manyTill anyTok (end_ name)
601+ return $ stripTrailingNewlines $ untokenize res
602+
603+inlineEnvironment :: PandocMonad m => LP m Inlines
604+inlineEnvironment = try $ do
605+ controlSeq "begin"
606+ name <- untokenize <$> braced
607+ M.findWithDefault mzero name inlineEnvironments
608+
609+inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
610+inlineEnvironments = M.fromList [
611+ ("displaymath", mathEnvWith id Nothing "displaymath")
612+ , ("math", math <$> mathEnv "math")
613+ , ("equation", mathEnvWith id Nothing "equation")
614+ , ("equation*", mathEnvWith id Nothing "equation*")
615+ , ("gather", mathEnvWith id (Just "gathered") "gather")
616+ , ("gather*", mathEnvWith id (Just "gathered") "gather*")
617+ , ("multline", mathEnvWith id (Just "gathered") "multline")
618+ , ("multline*", mathEnvWith id (Just "gathered") "multline*")
619+ , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
620+ , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
621+ , ("align", mathEnvWith id (Just "aligned") "align")
622+ , ("align*", mathEnvWith id (Just "aligned") "align*")
623+ , ("alignat", mathEnvWith id (Just "aligned") "alignat")
624+ , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
625+ , ("dmath", mathEnvWith id Nothing "dmath")
626+ , ("dmath*", mathEnvWith id Nothing "dmath*")
627+ , ("dgroup", mathEnvWith id (Just "aligned") "dgroup")
628+ , ("dgroup*", mathEnvWith id (Just "aligned") "dgroup*")
629+ , ("darray", mathEnvWith id (Just "aligned") "darray")
630+ , ("darray*", mathEnvWith id (Just "aligned") "darray*")
631+ ]
632+
330633inlineCommands :: 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− ]
634+inlineCommands = M.union inlineLanguageCommands $ M.fromList
635+ [ ("emph", extractSpaces emph <$> tok)
636+ , ("textit", extractSpaces emph <$> tok)
637+ , ("textsl", extractSpaces emph <$> tok)
638+ , ("textsc", extractSpaces smallcaps <$> tok)
639+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
640+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
641+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
642+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
643+ , ("texttt", ttfamily)
644+ , ("sout", extractSpaces strikeout <$> tok)
645+ , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
646+ , ("lq", return (str "‘"))
647+ , ("rq", return (str "’"))
648+ , ("textquoteleft", return (str "‘"))
649+ , ("textquoteright", return (str "’"))
650+ , ("textquotedblleft", return (str "“"))
651+ , ("textquotedblright", return (str "”"))
652+ , ("textsuperscript", extractSpaces superscript <$> tok)
653+ , ("textsubscript", extractSpaces subscript <$> tok)
654+ , ("textbackslash", lit "\\")
655+ , ("backslash", lit "\\")
656+ , ("slash", lit "/")
657+ , ("textbf", extractSpaces strong <$> tok)
658+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
659+ , ("underline", underline <$> tok)
660+ , ("ldots", lit "…")
661+ , ("vdots", lit "\8942")
662+ , ("dots", lit "…")
663+ , ("mdots", lit "…")
664+ , ("sim", lit "~")
665+ , ("sep", lit ",")
666+ , ("label", rawInlineOr "label" dolabel)
667+ , ("ref", rawInlineOr "ref" $ doref "ref")
668+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
669+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
670+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
671+ , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
672+ , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
673+ , ("lettrine", rawInlineOr "lettrine" lettrine)
674+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
675+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
676+ , ("ensuremath", mathInline . untokenize <$> braced)
677+ , ("texorpdfstring", const <$> tok <*> tok)
678+ , ("P", lit "¶")
679+ , ("S", lit "§")
680+ , ("$", lit "$")
681+ , ("%", lit "%")
682+ , ("&", lit "&")
683+ , ("#", lit "#")
684+ , ("_", lit "_")
685+ , ("{", lit "{")
686+ , ("}", lit "}")
687+ , ("qed", lit "\a0\x25FB")
688+ -- old TeX commands
689+ , ("em", extractSpaces emph <$> inlines)
690+ , ("it", extractSpaces emph <$> inlines)
691+ , ("sl", extractSpaces emph <$> inlines)
692+ , ("bf", extractSpaces strong <$> inlines)
693+ , ("tt", code . stringify . toList <$> inlines)
694+ , ("rm", inlines)
695+ , ("itshape", extractSpaces emph <$> inlines)
696+ , ("slshape", extractSpaces emph <$> inlines)
697+ , ("scshape", extractSpaces smallcaps <$> inlines)
698+ , ("bfseries", extractSpaces strong <$> inlines)
699+ , ("MakeUppercase", makeUppercase <$> tok)
700+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
701+ , ("uppercase", makeUppercase <$> tok)
702+ , ("MakeLowercase", makeLowercase <$> tok)
703+ , ("MakeTextLowercase", makeLowercase <$> tok)
704+ , ("lowercase", makeLowercase <$> tok)
705+ , ("/", pure mempty) -- italic correction
706+ , ("aa", lit "å")
707+ , ("AA", lit "Å")
708+ , ("ss", lit "ß")
709+ , ("o", lit "ø")
710+ , ("O", lit "Ø")
711+ , ("L", lit "Ł")
712+ , ("l", lit "ł")
713+ , ("ae", lit "æ")
714+ , ("AE", lit "Æ")
715+ , ("oe", lit "œ")
716+ , ("OE", lit "Œ")
717+ , ("pounds", lit "£")
718+ , ("euro", lit "€")
719+ , ("copyright", lit "©")
720+ , ("textasciicircum", lit "^")
721+ , ("textasciitilde", lit "~")
722+ , ("H", accent '\779' Nothing) -- hungarumlaut
723+ , ("`", accent '\768' (Just '`')) -- grave
724+ , ("'", accent '\769' (Just '\'')) -- acute
725+ , ("^", accent '\770' (Just '^')) -- circ
726+ , ("~", accent '\771' (Just '~')) -- tilde
727+ , ("\"", accent '\776' Nothing) -- umlaut
728+ , (".", accent '\775' Nothing) -- dot
729+ , ("=", accent '\772' Nothing) -- macron
730+ , ("|", accent '\781' Nothing) -- vertical line above
731+ , ("b", accent '\817' Nothing) -- macron below
732+ , ("c", accent '\807' Nothing) -- cedilla
733+ , ("G", accent '\783' Nothing) -- doublegrave
734+ , ("h", accent '\777' Nothing) -- hookabove
735+ , ("d", accent '\803' Nothing) -- dotbelow
736+ , ("f", accent '\785' Nothing) -- inverted breve
737+ , ("r", accent '\778' Nothing) -- ringabove
738+ , ("t", accent '\865' Nothing) -- double inverted breve
739+ , ("U", accent '\782' Nothing) -- double vertical line above
740+ , ("v", accent '\780' Nothing) -- hacek
741+ , ("u", accent '\774' Nothing) -- breve
742+ , ("k", accent '\808' Nothing) -- ogonek
743+ , ("textogonekcentered", accent '\808' Nothing) -- ogonek
744+ , ("i", lit "ı") -- dotless i
745+ , ("j", lit "ȷ") -- dotless j
746+ , ("newtie", accent '\785' Nothing) -- inverted breve
747+ , ("textcircled", accent '\8413' Nothing) -- combining circle
748+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
749+ guard $ not inTableCell
750+ optional opt
751+ spaces))
752+ , (",", lit "\8198")
753+ , ("@", pure mempty)
754+ , (" ", lit "\160")
755+ , ("ps", pure $ str "PS." <> space)
756+ , ("TeX", lit "TeX")
757+ , ("LaTeX", lit "LaTeX")
758+ , ("bar", lit "|")
759+ , ("textless", lit "<")
760+ , ("textgreater", lit ">")
761+ , ("thanks", skipopts >> note <$> grouped block)
762+ , ("footnote", skipopts >> note <$> grouped block)
763+ , ("passthrough", tok) -- \passthrough macro used by latex writer
764+ -- for listings
765+ , ("verb", doverb)
766+ , ("lstinline", dolstinline)
767+ , ("mintinline", domintinline)
768+ , ("Verb", doverb)
769+ , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
770+ bracedUrl)
771+ , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
772+ , ("href", do url <- bracedUrl
773+ sp
774+ link (unescapeURL $ untokenize url) "" <$> tok)
775+ , ("includegraphics", do options <- option [] keyvals
776+ src <- braced
777+ mkImage options . unescapeURL . removeDoubleQuotes $
778+ untokenize src)
779+ , ("enquote*", enquote True Nothing)
780+ , ("enquote", enquote False Nothing)
781+ -- foreignquote is supposed to use native quote marks
782+ , ("foreignquote*", braced >>= enquote True . Just . untokenize)
783+ , ("foreignquote", braced >>= enquote False . Just . untokenize)
784+ -- hypehnquote uses regular quotes
785+ , ("hyphenquote*", braced >>= enquote True . Just . untokenize)
786+ , ("hyphenquote", braced >>= enquote False . Just . untokenize)
787+ , ("figurename", doTerm Translations.Figure)
788+ , ("prefacename", doTerm Translations.Preface)
789+ , ("refname", doTerm Translations.References)
790+ , ("bibname", doTerm Translations.Bibliography)
791+ , ("chaptername", doTerm Translations.Chapter)
792+ , ("partname", doTerm Translations.Part)
793+ , ("contentsname", doTerm Translations.Contents)
794+ , ("listfigurename", doTerm Translations.ListOfFigures)
795+ , ("listtablename", doTerm Translations.ListOfTables)
796+ , ("indexname", doTerm Translations.Index)
797+ , ("abstractname", doTerm Translations.Abstract)
798+ , ("tablename", doTerm Translations.Table)
799+ , ("enclname", doTerm Translations.Encl)
800+ , ("ccname", doTerm Translations.Cc)
801+ , ("headtoname", doTerm Translations.To)
802+ , ("pagename", doTerm Translations.Page)
803+ , ("seename", doTerm Translations.See)
804+ , ("seealsoname", doTerm Translations.SeeAlso)
805+ , ("proofname", doTerm Translations.Proof)
806+ , ("glossaryname", doTerm Translations.Glossary)
807+ , ("lstlistingname", doTerm Translations.Listing)
808+ , ("cite", citation "cite" NormalCitation False)
809+ , ("Cite", citation "Cite" NormalCitation False)
810+ , ("citep", citation "citep" NormalCitation False)
811+ , ("citep*", citation "citep*" NormalCitation False)
812+ , ("citeal", citation "citeal" NormalCitation False)
813+ , ("citealp", citation "citealp" NormalCitation False)
814+ , ("citealp*", citation "citealp*" NormalCitation False)
815+ , ("autocite", citation "autocite" NormalCitation False)
816+ , ("smartcite", citation "smartcite" NormalCitation False)
817+ , ("footcite", inNote <$> citation "footcite" NormalCitation False)
818+ , ("parencite", citation "parencite" NormalCitation False)
819+ , ("supercite", citation "supercite" NormalCitation False)
820+ , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
821+ , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
822+ , ("citeyear", citation "citeyear" SuppressAuthor False)
823+ , ("autocite*", citation "autocite*" SuppressAuthor False)
824+ , ("cite*", citation "cite*" SuppressAuthor False)
825+ , ("parencite*", citation "parencite*" SuppressAuthor False)
826+ , ("textcite", citation "textcite" AuthorInText False)
827+ , ("citet", citation "citet" AuthorInText False)
828+ , ("citet*", citation "citet*" AuthorInText False)
829+ , ("citealt", citation "citealt" AuthorInText False)
830+ , ("citealt*", citation "citealt*" AuthorInText False)
831+ , ("textcites", citation "textcites" AuthorInText True)
832+ , ("cites", citation "cites" NormalCitation True)
833+ , ("autocites", citation "autocites" NormalCitation True)
834+ , ("footcites", inNote <$> citation "footcites" NormalCitation True)
835+ , ("parencites", citation "parencites" NormalCitation True)
836+ , ("supercites", citation "supercites" NormalCitation True)
837+ , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
838+ , ("Autocite", citation "Autocite" NormalCitation False)
839+ , ("Smartcite", citation "Smartcite" NormalCitation False)
840+ , ("Footcite", inNote <$> citation "Footcite" NormalCitation False)
841+ , ("Parencite", citation "Parencite" NormalCitation False)
842+ , ("Supercite", citation "Supercite" NormalCitation False)
843+ , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
844+ , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
845+ , ("Citeyear", citation "Citeyear" SuppressAuthor False)
846+ , ("Autocite*", citation "Autocite*" SuppressAuthor False)
847+ , ("Cite*", citation "Cite*" SuppressAuthor False)
848+ , ("Parencite*", citation "Parencite*" SuppressAuthor False)
849+ , ("Textcite", citation "Textcite" AuthorInText False)
850+ , ("Textcites", citation "Textcites" AuthorInText True)
851+ , ("Cites", citation "Cites" NormalCitation True)
852+ , ("Autocites", citation "Autocites" NormalCitation True)
853+ , ("Footcites", inNote <$> citation "Footcites" NormalCitation True)
854+ , ("Parencites", citation "Parencites" NormalCitation True)
855+ , ("Supercites", citation "Supercites" NormalCitation True)
856+ , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
857+ , ("citetext", complexNatbibCitation NormalCitation)
858+ , ("citeauthor", (try (tok *> sp *> controlSeq "citetext") *>
859+ complexNatbibCitation AuthorInText)
860+ <|> citation "citeauthor" AuthorInText False)
861+ , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
862+ addMeta "nocite"))
863+ , ("hyperlink", hyperlink)
864+ , ("hypertarget", hypertargetInline)
865+ -- glossaries package
866+ , ("gls", doAcronym "short")
867+ , ("Gls", doAcronym "short")
868+ , ("glsdesc", doAcronym "long")
869+ , ("Glsdesc", doAcronym "long")
870+ , ("GLSdesc", doAcronym "long")
871+ , ("acrlong", doAcronym "long")
872+ , ("Acrlong", doAcronym "long")
873+ , ("acrfull", doAcronym "full")
874+ , ("Acrfull", doAcronym "full")
875+ , ("acrshort", doAcronym "abbrv")
876+ , ("Acrshort", doAcronym "abbrv")
877+ , ("glspl", doAcronymPlural "short")
878+ , ("Glspl", doAcronymPlural "short")
879+ , ("glsdescplural", doAcronymPlural "long")
880+ , ("Glsdescplural", doAcronymPlural "long")
881+ , ("GLSdescplural", doAcronymPlural "long")
882+ -- acronyms package
883+ , ("ac", doAcronym "short")
884+ , ("acf", doAcronym "full")
885+ , ("acs", doAcronym "abbrv")
886+ , ("acl", doAcronym "long")
887+ , ("acp", doAcronymPlural "short")
888+ , ("acfp", doAcronymPlural "full")
889+ , ("acsp", doAcronymPlural "abbrv")
890+ , ("aclp", doAcronymPlural "long")
891+ , ("Ac", doAcronym "short")
892+ , ("Acf", doAcronym "full")
893+ , ("Acs", doAcronym "abbrv")
894+ , ("Acl", doAcronym "long")
895+ , ("Acp", doAcronymPlural "short")
896+ , ("Acfp", doAcronymPlural "full")
897+ , ("Acsp", doAcronymPlural "abbrv")
898+ , ("Aclp", doAcronymPlural "long")
899+ -- siuntix
900+ , ("si", skipopts *> dosi tok)
901+ , ("SI", doSI tok)
902+ , ("SIrange", doSIrange True tok)
903+ , ("numrange", doSIrange False tok)
904+ , ("numlist", doSInumlist)
905+ , ("num", doSInum)
906+ , ("ang", doSIang)
907+ -- hyphenat
908+ , ("bshyp", lit "\\\173")
909+ , ("fshyp", lit "/\173")
910+ , ("dothyp", lit ".\173")
911+ , ("colonhyp", lit ":\173")
912+ , ("hyp", lit "-")
913+ , ("nohyphens", tok)
914+ , ("textnhtt", ttfamily)
915+ , ("nhttfamily", ttfamily)
916+ -- LaTeX colors
917+ , ("textcolor", coloredInline "color")
918+ , ("colorbox", coloredInline "background-color")
919+ -- fontawesome
920+ , ("faCheck", lit "\10003")
921+ , ("faClose", lit "\10007")
922+ -- xspace
923+ , ("xspace", doxspace)
924+ -- etoolbox
925+ , ("ifstrequal", ifstrequal)
926+ , ("newtoggle", braced >>= newToggle)
927+ , ("toggletrue", braced >>= setToggle True)
928+ , ("togglefalse", braced >>= setToggle False)
929+ , ("iftoggle", try $ ifToggle >> inline)
930+ -- biblatex misc
931+ , ("RN", romanNumeralUpper)
932+ , ("Rn", romanNumeralLower)
933+ -- babel
934+ , ("foreignlanguage", foreignlanguage)
935+ -- include
936+ , ("input", rawInlineOr "input" $ include "input")
937+ -- soul package
938+ , ("ul", underline <$> tok)
939+ -- ulem package
940+ , ("uline", underline <$> tok)
941+ -- plain tex stuff that should just be passed through as raw tex
942+ , ("ifdim", ifdim)
943+ ]
944+
945+accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines
946+accent combiningAccent fallBack = try $ do
947+ ils <- tok
948+ case toList ils of
949+ (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
950+ -- try to normalize to the combined character:
951+ Str (Normalize.normalize Normalize.NFC
952+ (T.pack [x, combiningAccent]) <> xs) : ys
953+ [Space] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
954+ [] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
955+ _ -> return ils
956+
427957
428958lettrine :: PandocMonad m => LP m Inlines
429959lettrine = do
430− optional rawopt
960+ optional opt
431961 x <- tok
432962 y <- tok
433963 return $ extractSpaces (spanWith ("",["lettrine"],[])) x <> smallcaps y
@@ -447,18 +977,32 @@ alterStr :: (Text -> Text) -> Inline -> Inline
447977alterStr f (Str xs) = Str (f xs)
448978alterStr _ x = x
449979
980+foreignlanguage :: PandocMonad m => LP m Inlines
981+foreignlanguage = do
982+ babelLang <- untokenize <$> braced
983+ case babelLangToBCP47 babelLang of
984+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
985+ _ -> tok
986+
987+inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
988+inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
989+ where
990+ mk (polyglossia, bcp47Func) =
991+ ("text" <> polyglossia, inlineLanguage bcp47Func)
992+
993+inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
994+inlineLanguage bcp47Func = do
995+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
996+ <$> rawopt
997+ let lang = renderLang $ bcp47Func o
998+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
999+
4501000hyperlink :: PandocMonad m => LP m Inlines
4511001hyperlink = try $ do
4521002 src <- untokenize <$> braced
4531003 lab <- tok
4541004 return $ link ("#" <> src) "" lab
4551005
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−
4621006hypertargetBlock :: PandocMonad m => LP m Blocks
4631007hypertargetBlock = try $ do
4641008 ref <- untokenize <$> braced
@@ -473,6 +1017,31 @@ hypertargetInline = try $ do
4731017 ils <- grouped inline
4741018 return $ spanWith (ref, [], []) ils
4751019
1020+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
1021+romanNumeralUpper =
1022+ str . toRomanNumeral <$> romanNumeralArg
1023+
1024+romanNumeralLower :: (PandocMonad m) => LP m Inlines
1025+romanNumeralLower =
1026+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
1027+
1028+romanNumeralArg :: (PandocMonad m) => LP m Int
1029+romanNumeralArg = spaces *> (parser <|> inBraces)
1030+ where
1031+ inBraces = do
1032+ symbol '{'
1033+ spaces
1034+ res <- parser
1035+ spaces
1036+ symbol '}'
1037+ return res
1038+ parser = do
1039+ Tok _ Word s <- satisfyTok isWordTok
1040+ let (digits, rest) = T.span isDigit s
1041+ unless (T.null rest) $
1042+ Prelude.fail "Non-digits in argument to \\Rn or \\RN"
1043+ safeRead digits
1044+
4761045newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
4771046newToggle name = do
4781047 updateState $ \st ->
@@ -503,6 +1072,9 @@ ifToggle = do
5031072 report $ UndefinedToggle name' pos
5041073 return ()
5051074
1075+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
1076+doTerm term = str <$> translateTerm term
1077+
5061078ifstrequal :: (PandocMonad m, Monoid a) => LP m a
5071079ifstrequal = do
5081080 str1 <- tok
@@ -523,6 +1095,13 @@ coloredInline stylename = do
5231095ttfamily :: PandocMonad m => LP m Inlines
5241096ttfamily = code . stringify . toList <$> tok
5251097
1098+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
1099+rawInlineOr name' fallback = do
1100+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
1101+ if parseRaw
1102+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
1103+ else fallback
1104+
5261105processHBox :: Inlines -> Inlines
5271106processHBox = walk convert
5281107 where
@@ -573,74 +1152,73 @@ treatAsInline = Set.fromList
5731152 , "pagebreak"
5741153 ]
5751154
1155+label :: PandocMonad m => LP m ()
1156+label = do
1157+ controlSeq "label"
1158+ t <- braced
1159+ updateState $ \st -> st{ sLastLabel = Just $ untokenize t }
1160+
1161+dolabel :: PandocMonad m => LP m Inlines
1162+dolabel = do
1163+ v <- braced
1164+ let refstr = untokenize v
1165+ updateState $ \st ->
1166+ st{ sLastLabel = Just refstr }
1167+ return $ spanWith (refstr,[],[("label", refstr)])
1168+ $ inBrackets $ str $ untokenize v
1169+
1170+doref :: PandocMonad m => Text -> LP m Inlines
1171+doref cls = do
1172+ v <- braced
1173+ let refstr = untokenize v
1174+ return $ linkWith ("",[],[ ("reference-type", cls)
1175+ , ("reference", refstr)])
1176+ ("#" <> refstr)
1177+ ""
1178+ (inBrackets $ str refstr)
1179+
5761180lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
5771181lookupListDefault d = (fromMaybe d .) . lookupList
5781182 where lookupList l m = msum $ map (`M.lookup` m) l
5791183
5801184inline :: 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
1185+inline = (mempty <$ comment)
1186+ <|> (space <$ whitespace)
1187+ <|> (softbreak <$ endline)
1188+ <|> word
1189+ <|> macroDef (rawInline "latex")
1190+ <|> inlineCommand'
1191+ <|> inlineEnvironment
1192+ <|> inlineGroup
1193+ <|> (symbol '-' *>
1194+ option (str "-") (symbol '-' *>
1195+ option (str "–") (str "—" <$ symbol '-')))
1196+ <|> doubleQuote
1197+ <|> singleQuote
1198+ <|> (str "”" <$ try (symbol '\'' >> symbol '\''))
1199+ <|> (str "”" <$ symbol '”')
1200+ <|> (str "’" <$ symbol '\'')
1201+ <|> (str "’" <$ symbol '’')
1202+ <|> (str "\160" <$ symbol '~')
1203+ <|> dollarsMath
1204+ <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
1205+ <|> (str . T.singleton <$> primEscape)
1206+ <|> regularSymbol
1207+ <|> (do res <- symbolIn "#^'`\"[]&"
1208+ pos <- getPosition
1209+ let s = untoken res
1210+ report $ ParsingUnescaped s pos
1211+ return $ str s)
6231212
6241213inlines :: PandocMonad m => LP m Inlines
6251214inlines = mconcat <$> many inline
6261215
627−opt :: PandocMonad m => LP m Inlines
628−opt = do
629− toks <- try (sp *> bracketedToks <* sp)
630− -- now parse the toks as inlines
631− st <- getState
632− parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
633− case parsed of
634− Right result -> return result
635− Left e -> throwError $ PandocParsecError (toSources toks) e
636−
6371216-- block elements:
6381217
6391218preamble :: PandocMonad m => LP m Blocks
6401219preamble = mconcat <$> many preambleBlock
6411220 where preambleBlock = (mempty <$ spaces1)
6421221 <|> macroDef (rawBlock "latex")
643− <|> filecontents
6441222 <|> (mempty <$ blockCommand)
6451223 <|> (mempty <$ braced)
6461224 <|> (do notFollowedBy (begin_ "document")
@@ -694,16 +1272,6 @@ include name = do
6941272 mapM_ (insertIncluded defaultExt) fs
6951273 return mempty
6961274
697−readFileFromTexinputs :: PandocMonad m => FilePath -> LP m (Maybe Text)
698−readFileFromTexinputs fp = do
699− fileContentsMap <- sFileContents <$> getState
700− case M.lookup (T.pack fp) fileContentsMap of
701− Just t -> return (Just t)
702− Nothing -> do
703− dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "."
704− <$> lookupEnv "TEXINPUTS"
705− readFileFromDirs dirs fp
706−
7071275insertIncluded :: PandocMonad m
7081276 => FilePath
7091277 -> FilePath
@@ -713,12 +1281,13 @@ insertIncluded defaultExtension f' = do
7131281 ".tex" -> f'
7141282 ".sty" -> f'
7151283 _ -> addExtension f' defaultExtension
1284+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
7161285 pos <- getPosition
7171286 containers <- getIncludeFiles <$> getState
7181287 when (T.pack f `elem` containers) $
7191288 throwError $ PandocParseError $ T.pack $ "Include file loop at " ++ show pos
7201289 updateState $ addIncludeFile $ T.pack f
721− mbcontents <- readFileFromTexinputs f
1290+ mbcontents <- readFileFromDirs dirs f
7221291 contents <- case mbcontents of
7231292 Just s -> return s
7241293 Nothing -> do
@@ -727,6 +1296,10 @@ insertIncluded defaultExtension f' = do
7271296 getInput >>= setInput . (tokenize f contents ++)
7281297 updateState dropLatestIncludeFile
7291298
1299+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> LP m ()
1300+addMeta field val = updateState $ \st ->
1301+ st{ sMeta = addMetaField field val $ sMeta st }
1302+
7301303authors :: PandocMonad m => LP m ()
7311304authors = try $ do
7321305 bgroup
@@ -735,6 +1308,150 @@ authors = try $ do
7351308 egroup
7361309 addMeta "author" (map trimInlines auths)
7371310
1311+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1312+macroDef constructor = do
1313+ (_, s) <- withRaw (commandDef <|> environmentDef)
1314+ (constructor (untokenize s) <$
1315+ guardDisabled Ext_latex_macros)
1316+ <|> return mempty
1317+ where commandDef = do
1318+ (name, macro') <- newcommand <|> letmacro <|> defmacro
1319+ guardDisabled Ext_latex_macros <|>
1320+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1321+ environmentDef = do
1322+ mbenv <- newenvironment
1323+ case mbenv of
1324+ Nothing -> return ()
1325+ Just (name, macro1, macro2) ->
1326+ guardDisabled Ext_latex_macros <|>
1327+ do updateState $ \s -> s{ sMacros =
1328+ M.insert name macro1 (sMacros s) }
1329+ updateState $ \s -> s{ sMacros =
1330+ M.insert ("end" <> name) macro2 (sMacros s) }
1331+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1332+ -- is equivalent to
1333+ -- @\newcommand{\envname}[n-args][default]{begin}@
1334+ -- @\newcommand{\endenvname}@
1335+
1336+letmacro :: PandocMonad m => LP m (Text, Macro)
1337+letmacro = do
1338+ controlSeq "let"
1339+ (name, contents) <- withVerbatimMode $ do
1340+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1341+ optional $ symbol '='
1342+ spaces
1343+ -- we first parse in verbatim mode, and then expand macros,
1344+ -- because we don't want \let\foo\bar to turn into
1345+ -- \let\foo hello if we have previously \def\bar{hello}
1346+ contents <- bracedOrToken
1347+ return (name, contents)
1348+ contents' <- doMacros' 0 contents
1349+ return (name, Macro ExpandWhenDefined [] Nothing contents')
1350+
1351+defmacro :: PandocMonad m => LP m (Text, Macro)
1352+defmacro = try $
1353+ -- we use withVerbatimMode, because macros are to be expanded
1354+ -- at point of use, not point of definition
1355+ withVerbatimMode $ do
1356+ controlSeq "def"
1357+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1358+ argspecs <- many (argspecArg <|> argspecPattern)
1359+ contents <- bracedOrToken
1360+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1361+
1362+argspecArg :: PandocMonad m => LP m ArgSpec
1363+argspecArg = do
1364+ Tok _ (Arg i) _ <- satisfyTok isArgTok
1365+ return $ ArgNum i
1366+
1367+argspecPattern :: PandocMonad m => LP m ArgSpec
1368+argspecPattern =
1369+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1370+ (toktype' == Symbol || toktype' == Word) &&
1371+ (txt /= "{" && txt /= "\\" && txt /= "}")))
1372+
1373+newcommand :: PandocMonad m => LP m (Text, Macro)
1374+newcommand = do
1375+ pos <- getPosition
1376+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1377+ controlSeq "renewcommand" <|>
1378+ controlSeq "providecommand" <|>
1379+ controlSeq "DeclareMathOperator" <|>
1380+ controlSeq "DeclareRobustCommand"
1381+ withVerbatimMode $ do
1382+ Tok _ (CtrlSeq name) txt <- do
1383+ optional (symbol '*')
1384+ anyControlSeq <|>
1385+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1386+ spaces
1387+ numargs <- option 0 $ try bracketedNum
1388+ let argspecs = map ArgNum [1..numargs]
1389+ spaces
1390+ optarg <- option Nothing $ Just <$> try bracketedToks
1391+ spaces
1392+ contents' <- bracedOrToken
1393+ let contents =
1394+ case mtype of
1395+ "DeclareMathOperator" ->
1396+ Tok pos (CtrlSeq "mathop") "\\mathop"
1397+ : Tok pos Symbol "{"
1398+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1399+ : Tok pos Symbol "{"
1400+ : (contents' ++
1401+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1402+ _ -> contents'
1403+ macros <- sMacros <$> getState
1404+ case M.lookup name macros of
1405+ Just macro
1406+ | mtype == "newcommand" -> do
1407+ report $ MacroAlreadyDefined txt pos
1408+ return (name, macro)
1409+ | mtype == "providecommand" -> return (name, macro)
1410+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1411+
1412+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1413+newenvironment = do
1414+ pos <- getPosition
1415+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1416+ controlSeq "renewenvironment" <|>
1417+ controlSeq "provideenvironment"
1418+ withVerbatimMode $ do
1419+ optional $ symbol '*'
1420+ spaces
1421+ name <- untokenize <$> braced
1422+ spaces
1423+ numargs <- option 0 $ try bracketedNum
1424+ spaces
1425+ optarg <- option Nothing $ Just <$> try bracketedToks
1426+ let argspecs = map (\i -> ArgNum i) [1..numargs]
1427+ startcontents <- spaces >> bracedOrToken
1428+ endcontents <- spaces >> bracedOrToken
1429+ macros <- sMacros <$> getState
1430+ case M.lookup name macros of
1431+ Just _
1432+ | mtype == "newenvironment" -> do
1433+ report $ MacroAlreadyDefined name pos
1434+ return Nothing
1435+ | mtype == "provideenvironment" ->
1436+ return Nothing
1437+ _ -> return $ Just (name,
1438+ Macro ExpandWhenUsed argspecs optarg startcontents,
1439+ Macro ExpandWhenUsed [] Nothing endcontents)
1440+
1441+bracketedNum :: PandocMonad m => LP m Int
1442+bracketedNum = do
1443+ ds <- untokenize <$> bracketedToks
1444+ case safeRead ds of
1445+ Just i -> return i
1446+ _ -> return 0
1447+
1448+setCaption :: PandocMonad m => LP m ()
1449+setCaption = try $ do
1450+ skipopts
1451+ ils <- tok
1452+ optional $ try $ spaces *> label
1453+ updateState $ \st -> st{ sCaption = Just ils }
1454+
7381455looseItem :: PandocMonad m => LP m Blocks
7391456looseItem = do
7401457 inListItem <- sInListItem <$> getState
@@ -748,6 +1465,10 @@ epigraph = do
7481465 p2 <- grouped block
7491466 return $ divWith ("", ["epigraph"], []) (p1 <> p2)
7501467
1468+resetCaption :: PandocMonad m => LP m ()
1469+resetCaption = updateState $ \st -> st{ sCaption = Nothing
1470+ , sLastLabel = Nothing }
1471+
7511472section :: PandocMonad m => Attr -> Int -> LP m Blocks
7521473section (ident, classes, kvs) lvl = do
7531474 skipopts
@@ -840,7 +1561,7 @@ blockCommands = M.fromList
8401561 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
8411562 , ("signature", mempty <$ (skipopts *> authors))
8421563 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
843− , ("newtheorem", newtheorem inline)
1564+ , ("newtheorem", newtheorem)
8441565 , ("theoremstyle", theoremstyle)
8451566 -- KOMA-Script metadata commands
8461567 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -888,7 +1609,7 @@ blockCommands = M.fromList
8881609 , ("item", looseItem)
8891610 , ("documentclass", skipopts *> braced *> preamble)
8901611 , ("centerline", para . trimInlines <$> (skipopts *> tok))
891− , ("caption", mempty <$ setCaption inline)
1612+ , ("caption", mempty <$ setCaption)
8921613 , ("bibliography", mempty <$ (skipopts *> braced >>=
8931614 addMeta "bibliography" . splitBibs . untokenize))
8941615 , ("addbibresource", mempty <$ (skipopts *> braced >>=
@@ -926,8 +1647,7 @@ blockCommands = M.fromList
9261647
9271648
9281649environments :: PandocMonad m => M.Map Text (LP m Blocks)
929−environments = M.union (tableEnvironments blocks inline) $
930− M.fromList
1650+environments = M.fromList
9311651 [ ("document", env "document" blocks <* skipMany anyTok)
9321652 , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
9331653 , ("sloppypar", env "sloppypar" blocks)
@@ -937,6 +1657,13 @@ environments = M.union (tableEnvironments blocks inline) $
9371657 , ("figure", env "figure" $ skipopts *> figure)
9381658 , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
9391659 , ("center", divWith ("", ["center"], []) <$> env "center" blocks)
1660+ , ("longtable", env "longtable" $
1661+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
1662+ , ("table", env "table" $
1663+ skipopts *> resetCaption *> blocks >>= addTableCaption)
1664+ , ("tabular*", env "tabular*" $ simpTable "tabular*" True)
1665+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1666+ , ("tabular", env "tabular" $ simpTable "tabular" False)
9401667 , ("quote", blockQuote <$> env "quote" blocks)
9411668 , ("quotation", blockQuote <$> env "quotation" blocks)
9421669 , ("verse", blockQuote <$> env "verse" blocks)
@@ -959,7 +1686,7 @@ environments = M.union (tableEnvironments blocks inline) $
9591686 , ("lilypond", rawVerbEnv "lilypond")
9601687 , ("ly", rawVerbEnv "ly")
9611688 -- amsthm
962− , ("proof", proof blocks opt)
1689+ , ("proof", proof)
9631690 -- etoolbox
9641691 , ("ifstrequal", ifstrequal)
9651692 , ("newtoggle", braced >>= newToggle)
@@ -968,29 +1695,131 @@ environments = M.union (tableEnvironments blocks inline) $
9681695 , ("iftoggle", try $ ifToggle >> block)
9691696 ]
9701697
971−filecontents :: PandocMonad m => LP m Blocks
972−filecontents = try $ do
973− controlSeq "begin"
1698+theoremstyle :: PandocMonad m => LP m Blocks
1699+theoremstyle = do
1700+ stylename <- untokenize <$> braced
1701+ let mbstyle = case stylename of
1702+ "plain" -> Just PlainStyle
1703+ "definition" -> Just DefinitionStyle
1704+ "remark" -> Just RemarkStyle
1705+ _ -> Nothing
1706+ case mbstyle of
1707+ Nothing -> return ()
1708+ Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
1709+ return mempty
1710+
1711+newtheorem :: PandocMonad m => LP m Blocks
1712+newtheorem = do
1713+ number <- option True (False <$ symbol '*' <* sp)
9741714 name <- untokenize <$> braced
975− guard $ name == "filecontents" || name == "filecontents*"
976− skipopts
977− fp <- untokenize <$> braced
978− txt <- verbEnv name
979− updateState $ \st ->
980− st{ sFileContents = M.insert fp txt (sFileContents st) }
1715+ sp
1716+ series <- option Nothing $ Just . untokenize <$> bracketedToks
1717+ sp
1718+ showName <- tok
1719+ sp
1720+ syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
1721+ sty <- sLastTheoremStyle <$> getState
1722+ let spec = TheoremSpec { theoremName = showName
1723+ , theoremStyle = sty
1724+ , theoremSeries = series
1725+ , theoremSyncTo = syncTo
1726+ , theoremNumber = number
1727+ , theoremLastNum = DottedNum [0] }
1728+ tmap <- sTheoremMap <$> getState
1729+ updateState $ \s -> s{ sTheoremMap =
1730+ M.insert name spec tmap }
9811731 return mempty
9821732
1733+proof :: PandocMonad m => LP m Blocks
1734+proof = do
1735+ title <- option (B.text "Proof") opt
1736+ bs <- env "proof" blocks
1737+ return $
1738+ B.divWith ("", ["proof"], []) $
1739+ addQed $ addTitle (B.emph (title <> ".")) bs
1740+
1741+addTitle :: Inlines -> Blocks -> Blocks
1742+addTitle ils bs =
1743+ case B.toList bs of
1744+ (Para xs : rest)
1745+ -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
1746+ _ -> B.para ils <> bs
1747+
1748+addQed :: Blocks -> Blocks
1749+addQed bs =
1750+ case Seq.viewr (B.unMany bs) of
1751+ s Seq.:> Para ils
1752+ -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
1753+ _ -> bs <> B.para qedSign
1754+ where
1755+ qedSign = B.str "\xa0\x25FB"
1756+
9831757environment :: PandocMonad m => LP m Blocks
9841758environment = try $ do
9851759 controlSeq "begin"
9861760 name <- untokenize <$> braced
9871761 M.findWithDefault mzero name environments <|>
988− theoremEnvironment blocks opt name <|>
1762+ theoremEnvironment name <|>
9891763 if M.member name (inlineEnvironments
9901764 :: M.Map Text (LP PandocPure Inlines))
9911765 then mzero
9921766 else try (rawEnv name) <|> rawVerbEnv name
9931767
1768+theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
1769+theoremEnvironment name = do
1770+ tmap <- sTheoremMap <$> getState
1771+ case M.lookup name tmap of
1772+ Nothing -> mzero
1773+ Just tspec -> do
1774+ optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
1775+ mblabel <- option Nothing $ Just . untokenize <$>
1776+ try (spaces >> controlSeq "label" >> spaces >> braced)
1777+ bs <- env name blocks
1778+ number <-
1779+ if theoremNumber tspec
1780+ then do
1781+ let name' = fromMaybe name $ theoremSeries tspec
1782+ num <- getNextNumber
1783+ (maybe (DottedNum [0]) theoremLastNum .
1784+ M.lookup name' . sTheoremMap)
1785+ updateState $ \s ->
1786+ s{ sTheoremMap =
1787+ M.adjust
1788+ (\spec -> spec{ theoremLastNum = num })
1789+ name'
1790+ (sTheoremMap s)
1791+ }
1792+
1793+ case mblabel of
1794+ Just ident ->
1795+ updateState $ \s ->
1796+ s{ sLabels = M.insert ident
1797+ (B.toList $
1798+ theoremName tspec <> "\160" <>
1799+ str (renderDottedNum num)) (sLabels s) }
1800+ Nothing -> return ()
1801+ return $ space <> B.text (renderDottedNum num)
1802+ else return mempty
1803+ let titleEmph = case theoremStyle tspec of
1804+ PlainStyle -> B.strong
1805+ DefinitionStyle -> B.strong
1806+ RemarkStyle -> B.emph
1807+ let title = titleEmph (theoremName tspec <> number)
1808+ <> optTitle <> "." <> space
1809+ return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
1810+ $ case theoremStyle tspec of
1811+ PlainStyle -> walk italicize bs
1812+ _ -> bs
1813+
1814+italicize :: Block -> Block
1815+italicize x@(Para [Image{}]) = x -- see #6925
1816+italicize (Para ils) = Para [Emph ils]
1817+italicize (Plain ils) = Plain [Emph ils]
1818+italicize x = x
1819+
1820+env :: PandocMonad m => Text -> LP m a -> LP m a
1821+env name p = p <* end_ name
1822+
9941823rawEnv :: PandocMonad m => Text -> LP m Blocks
9951824rawEnv name = do
9961825 exts <- getOption readerExtensions
@@ -998,17 +1827,15 @@ rawEnv name = do
9981827 rawOptions <- mconcat <$> many rawopt
9991828 let beginCommand = "\\begin{" <> name <> "}" <> rawOptions
10001829 pos1 <- getPosition
1830+ (bs, raw) <- withRaw $ env name blocks
10011831 if parseRaw
1002− then do
1003− (_, raw) <- withRaw $ env name blocks
1004− return $ rawBlock "latex"
1832+ then return $ rawBlock "latex"
10051833 $ beginCommand <> untokenize raw
10061834 else do
1007− bs <- env name blocks
10081835 report $ SkippedContent beginCommand pos1
10091836 pos2 <- getPosition
10101837 report $ SkippedContent ("\\end{" <> name <> "}") pos2
1011− return $ divWith ("",[name],[]) bs
1838+ return bs
10121839
10131840rawVerbEnv :: PandocMonad m => Text -> LP m Blocks
10141841rawVerbEnv name = do
@@ -1067,7 +1894,8 @@ inputMinted = do
10671894 pos <- getPosition
10681895 attr <- mintedAttr
10691896 f <- T.filter (/='"') . untokenize <$> braced
1070− mbCode <- readFileFromTexinputs (T.unpack f)
1897+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
1898+ mbCode <- readFileFromDirs dirs (T.unpack f)
10711899 rawcode <- case mbCode of
10721900 Just s -> return s
10731901 Nothing -> do
@@ -1153,7 +1981,8 @@ inputListing = do
11531981 pos <- getPosition
11541982 options <- option [] keyvals
11551983 f <- T.filter (/='"') . untokenize <$> braced
1156− mbCode <- readFileFromTexinputs (T.unpack f)
1984+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
1985+ mbCode <- readFileFromDirs dirs (T.unpack f)
11571986 codeLines <- case mbCode of
11581987 Just s -> return $ T.lines s
11591988 Nothing -> do
@@ -1162,8 +1991,7 @@ inputListing = do
11621991 let (ident,classes,kvs) = parseListingsOptions options
11631992 let classes' =
11641993 (case listingsLanguage options of
1165− Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1166− (T.pack $ takeExtension $ T.unpack f)) <>)
1994+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
11671995 Just _ -> id) classes
11681996 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
11691997 let lastline = fromMaybe (length codeLines) $
@@ -1229,23 +2057,358 @@ orderedList' = try $ do
12292057 bs <- listenv "enumerate" (many item)
12302058 return $ orderedListWith (start, style, delim) bs
12312059
2060+-- tables
2061+
2062+hline :: PandocMonad m => LP m ()
2063+hline = try $ do
2064+ spaces
2065+ controlSeq "hline" <|>
2066+ -- booktabs rules:
2067+ controlSeq "toprule" <|>
2068+ controlSeq "bottomrule" <|>
2069+ controlSeq "midrule" <|>
2070+ controlSeq "endhead" <|>
2071+ controlSeq "endfirsthead"
2072+ spaces
2073+ optional opt
2074+ return ()
2075+
2076+lbreak :: PandocMonad m => LP m Tok
2077+lbreak = (controlSeq "\\" <|> controlSeq "tabularnewline")
2078+ <* skipopts <* spaces
2079+
2080+amp :: PandocMonad m => LP m Tok
2081+amp = symbol '&'
2082+
2083+-- Split a Word into individual Symbols (for parseAligns)
2084+splitWordTok :: PandocMonad m => LP m ()
2085+splitWordTok = do
2086+ inp <- getInput
2087+ case inp of
2088+ (Tok spos Word t : rest) ->
2089+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) <> rest
2090+ _ -> return ()
2091+
2092+parseAligns :: PandocMonad m => LP m [(Alignment, ColWidth, ([Tok], [Tok]))]
2093+parseAligns = try $ do
2094+ let maybeBar = skipMany
2095+ (try $ sp *> (() <$ symbol '|' <|> () <$ (symbol '@' >> braced)))
2096+ let cAlign = AlignCenter <$ symbol 'c'
2097+ let lAlign = AlignLeft <$ symbol 'l'
2098+ let rAlign = AlignRight <$ symbol 'r'
2099+ let parAlign = AlignLeft <$ symbol 'p'
2100+ -- aligns from tabularx
2101+ let xAlign = AlignLeft <$ symbol 'X'
2102+ let mAlign = AlignLeft <$ symbol 'm'
2103+ let bAlign = AlignLeft <$ symbol 'b'
2104+ let alignChar = splitWordTok *> ( cAlign <|> lAlign <|> rAlign <|> parAlign
2105+ <|> xAlign <|> mAlign <|> bAlign )
2106+ let alignPrefix = symbol '>' >> braced
2107+ let alignSuffix = symbol '<' >> braced
2108+ let colWidth = try $ do
2109+ symbol '{'
2110+ ds <- trim . untokenize <$> manyTill anyTok (controlSeq "linewidth")
2111+ spaces
2112+ symbol '}'
2113+ return $ safeRead ds
2114+ let alignSpec = do
2115+ pref <- option [] alignPrefix
2116+ spaces
2117+ al <- alignChar
2118+ width <- colWidth <|> option Nothing (do s <- untokenize <$> braced
2119+ pos <- getPosition
2120+ report $ SkippedContent s pos
2121+ return Nothing)
2122+ spaces
2123+ suff <- option [] alignSuffix
2124+ return (al, width, (pref, suff))
2125+ let starAlign = do -- '*{2}{r}' == 'rr', we just expand like a macro
2126+ symbol '*'
2127+ spaces
2128+ ds <- trim . untokenize <$> braced
2129+ spaces
2130+ spec <- braced
2131+ case safeRead ds of
2132+ Just n ->
2133+ getInput >>= setInput . (mconcat (replicate n spec) ++)
2134+ Nothing -> Prelude.fail $ "Could not parse " <> T.unpack ds <> " as number"
2135+ bgroup
2136+ spaces
2137+ maybeBar
2138+ aligns' <- many $ try $ spaces >> optional starAlign >>
2139+ (alignSpec <* maybeBar)
2140+ spaces
2141+ egroup
2142+ spaces
2143+ return $ map toSpec aligns'
2144+ where
2145+ toColWidth (Just w) | w > 0 = ColWidth w
2146+ toColWidth _ = ColWidthDefault
2147+ toSpec (x, y, z) = (x, toColWidth y, z)
2148+
2149+-- N.B. this parser returns a Row that may have erroneous empty cells
2150+-- in it. See the note above fixTableHead for details.
2151+parseTableRow :: PandocMonad m
2152+ => Text -- ^ table environment name
2153+ -> [([Tok], [Tok])] -- ^ pref/suffixes
2154+ -> LP m Row
2155+parseTableRow envname prefsufs = do
2156+ notFollowedBy (spaces *> end_ envname)
2157+ -- add prefixes and suffixes in token stream:
2158+ let celltoks (pref, suff) = do
2159+ prefpos <- getPosition
2160+ contents <- mconcat <$>
2161+ many ( snd <$> withRaw (controlSeq "parbox" >> parbox) -- #5711
2162+ <|>
2163+ snd <$> withRaw (inlineEnvironment <|> dollarsMath)
2164+ <|>
2165+ (do notFollowedBy
2166+ (() <$ amp <|> () <$ lbreak <|> end_ envname)
2167+ count 1 anyTok) )
2168+
2169+ suffpos <- getPosition
2170+ option [] (count 1 amp)
2171+ return $ map (setpos prefpos) pref ++ contents ++ map (setpos suffpos) suff
2172+ rawcells <- mapM celltoks prefsufs
2173+ oldInput <- getInput
2174+ cells <- mapM (\ts -> setInput ts >> parseTableCell) rawcells
2175+ setInput oldInput
2176+ spaces
2177+ return $ Row nullAttr cells
2178+
2179+parseTableCell :: PandocMonad m => LP m Cell
2180+parseTableCell = do
2181+ spaces
2182+ updateState $ \st -> st{ sInTableCell = True }
2183+ cell' <- multicolumnCell
2184+ <|> multirowCell
2185+ <|> parseSimpleCell
2186+ <|> parseEmptyCell
2187+ updateState $ \st -> st{ sInTableCell = False }
2188+ spaces
2189+ return cell'
2190+ where
2191+ -- The parsing of empty cells is important in LaTeX, especially when dealing
2192+ -- with multirow/multicolumn. See #6603.
2193+ parseEmptyCell = spaces $> emptyCell
2194+
2195+cellAlignment :: PandocMonad m => LP m Alignment
2196+cellAlignment = skipMany (symbol '|') *> alignment <* skipMany (symbol '|')
2197+ where
2198+ alignment = do
2199+ c <- untoken <$> singleChar
2200+ return $ case c of
2201+ "l" -> AlignLeft
2202+ "r" -> AlignRight
2203+ "c" -> AlignCenter
2204+ "*" -> AlignDefault
2205+ _ -> AlignDefault
2206+
2207+plainify :: Blocks -> Blocks
2208+plainify bs = case toList bs of
2209+ [Para ils] -> plain (fromList ils)
2210+ _ -> bs
2211+
2212+multirowCell :: PandocMonad m => LP m Cell
2213+multirowCell = controlSeq "multirow" >> do
2214+ -- Full prototype for \multirow macro is:
2215+ -- \multirow[vpos]{nrows}[bigstruts]{width}[vmove]{text}
2216+ -- However, everything except `nrows` and `text` make
2217+ -- sense in the context of the Pandoc AST
2218+ _ <- optional $ symbol '[' *> cellAlignment <* symbol ']' -- vertical position
2219+ nrows <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2220+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- bigstrut-related
2221+ _ <- symbol '{' *> manyTill anyTok (symbol '}') -- Cell width
2222+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- Length used for fine-tuning
2223+ content <- symbol '{' *> (plainify <$> blocks) <* symbol '}'
2224+ return $ cell AlignDefault (RowSpan nrows) (ColSpan 1) content
2225+
2226+multicolumnCell :: PandocMonad m => LP m Cell
2227+multicolumnCell = controlSeq "multicolumn" >> do
2228+ span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2229+ alignment <- symbol '{' *> cellAlignment <* symbol '}'
2230+
2231+ let singleCell = do
2232+ content <- plainify <$> blocks
2233+ return $ cell alignment (RowSpan 1) (ColSpan span') content
2234+
2235+ -- Two possible contents: either a \multirow cell, or content.
2236+ -- E.g. \multicol{1}{c}{\multirow{2}{1em}{content}}
2237+ -- Note that a \multirow cell can be nested in a \multicolumn,
2238+ -- but not the other way around. See #6603
2239+ let nestedCell = do
2240+ (Cell _ _ (RowSpan rs) _ bs) <- multirowCell
2241+ return $ cell
2242+ alignment
2243+ (RowSpan rs)
2244+ (ColSpan span')
2245+ (fromList bs)
2246+
2247+ symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
2248+
2249+-- Parse a simple cell, i.e. not multirow/multicol
2250+parseSimpleCell :: PandocMonad m => LP m Cell
2251+parseSimpleCell = simpleCell <$> (plainify <$> blocks)
2252+
2253+-- LaTeX tables are stored with empty cells underneath multirow cells
2254+-- denoting the grid spaces taken up by them. More specifically, if a
2255+-- cell spans m rows, then it will overwrite all the cells in the
2256+-- columns it spans for (m-1) rows underneath it, requiring padding
2257+-- cells in these places. These padding cells need to be removed for
2258+-- proper table reading. See #6603.
2259+--
2260+-- These fixTable functions do not otherwise fix up malformed
2261+-- input tables: that is left to the table builder.
2262+fixTableHead :: TableHead -> TableHead
2263+fixTableHead (TableHead attr rows) = TableHead attr rows'
2264+ where
2265+ rows' = fixTableRows rows
2266+
2267+fixTableBody :: TableBody -> TableBody
2268+fixTableBody (TableBody attr rhc th tb)
2269+ = TableBody attr rhc th' tb'
2270+ where
2271+ th' = fixTableRows th
2272+ tb' = fixTableRows tb
2273+
2274+fixTableRows :: [Row] -> [Row]
2275+fixTableRows = fixTableRows' $ repeat Nothing
2276+ where
2277+ fixTableRows' oldHang (Row attr cells : rs)
2278+ = let (newHang, cells') = fixTableRow oldHang cells
2279+ rs' = fixTableRows' newHang rs
2280+ in Row attr cells' : rs'
2281+ fixTableRows' _ [] = []
2282+
2283+-- The overhang is represented as Just (relative cell dimensions) or
2284+-- Nothing for an empty grid space.
2285+fixTableRow :: [Maybe (ColSpan, RowSpan)] -> [Cell] -> ([Maybe (ColSpan, RowSpan)], [Cell])
2286+fixTableRow oldHang cells
2287+ -- If there's overhang, drop cells until their total width meets the
2288+ -- width of the occupied grid spaces (or we run out)
2289+ | (n, prefHang, restHang) <- splitHang oldHang
2290+ , n > 0
2291+ = let cells' = dropToWidth getCellW n cells
2292+ (restHang', cells'') = fixTableRow restHang cells'
2293+ in (prefHang restHang', cells'')
2294+ -- Otherwise record the overhang of a pending cell and fix the rest
2295+ -- of the row
2296+ | c@(Cell _ _ h w _):cells' <- cells
2297+ = let h' = max 1 h
2298+ w' = max 1 w
2299+ oldHang' = dropToWidth getHangW w' oldHang
2300+ (newHang, cells'') = fixTableRow oldHang' cells'
2301+ in (toHang w' h' <> newHang, c : cells'')
2302+ | otherwise
2303+ = (oldHang, [])
2304+ where
2305+ getCellW (Cell _ _ _ w _) = w
2306+ getHangW = maybe 1 fst
2307+ getCS (ColSpan n) = n
2308+
2309+ toHang c r
2310+ | r > 1 = [Just (c, r)]
2311+ | otherwise = replicate (getCS c) Nothing
2312+
2313+ -- Take the prefix of the overhang list representing filled grid
2314+ -- spaces. Also return the remainder and the length of this prefix.
2315+ splitHang = splitHang' 0 id
2316+
2317+ splitHang' !n l (Just (c, r):xs)
2318+ = splitHang' (n + c) (l . (toHang c (r-1) ++)) xs
2319+ splitHang' n l xs = (n, l, xs)
2320+
2321+ -- Drop list items until the total width of the dropped items
2322+ -- exceeds the passed width.
2323+ dropToWidth _ n l | n < 1 = l
2324+ dropToWidth wproj n (c:cs) = dropToWidth wproj (n - wproj c) cs
2325+ dropToWidth _ _ [] = []
2326+
2327+simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
2328+simpTable envname hasWidthParameter = try $ do
2329+ when hasWidthParameter $ () <$ (spaces >> tok)
2330+ skipopts
2331+ colspecs <- parseAligns
2332+ let (aligns, widths, prefsufs) = unzip3 colspecs
2333+ optional $ controlSeq "caption" *> setCaption
2334+ spaces
2335+ optional label
2336+ spaces
2337+ optional lbreak
2338+ spaces
2339+ skipMany hline
2340+ spaces
2341+ header' <- option [] . try . fmap (:[]) $
2342+ parseTableRow envname prefsufs <* lbreak <* many1 hline
2343+ spaces
2344+ rows <- sepEndBy (parseTableRow envname prefsufs)
2345+ (lbreak <* optional (skipMany hline))
2346+ spaces
2347+ optional $ controlSeq "caption" *> setCaption
2348+ spaces
2349+ optional label
2350+ spaces
2351+ optional lbreak
2352+ spaces
2353+ lookAhead $ controlSeq "end" -- make sure we're at end
2354+ let th = fixTableHead $ TableHead nullAttr header'
2355+ let tbs = [fixTableBody $ TableBody nullAttr 0 [] rows]
2356+ let tf = TableFoot nullAttr []
2357+ return $ table emptyCaption (zip aligns widths) th tbs tf
2358+
2359+addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
2360+addTableCaption = walkM go
2361+ where go (Table attr c spec th tb tf) = do
2362+ st <- getState
2363+ let mblabel = sLastLabel st
2364+ capt <- case (sCaption st, mblabel) of
2365+ (Just ils, Nothing) -> return $ caption Nothing (plain ils)
2366+ (Just ils, Just lab) -> do
2367+ num <- getNextNumber sLastTableNum
2368+ setState
2369+ st{ sLastTableNum = num
2370+ , sLabels = M.insert lab
2371+ [Str (renderDottedNum num)]
2372+ (sLabels st) }
2373+ return $ caption Nothing (plain ils) -- add number??
2374+ (Nothing, _) -> return c
2375+ let attr' = case (attr, mblabel) of
2376+ ((_,classes,kvs), Just ident) ->
2377+ (ident,classes,kvs)
2378+ _ -> attr
2379+ return $ addAttrDiv attr' $ Table nullAttr capt spec th tb tf
2380+ go x = return x
2381+
2382+-- TODO: For now we add a Div to contain table attributes, since
2383+-- most writers don't do anything yet with attributes on Table.
2384+-- This can be removed when that changes.
2385+addAttrDiv :: Attr -> Block -> Block
2386+addAttrDiv ("",[],[]) b = b
2387+addAttrDiv attr b = Div attr [b]
2388+
12322389block :: PandocMonad m => LP m Blocks
12332390block = 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
2391+ res <- (mempty <$ spaces1)
2392+ <|> environment
2393+ <|> macroDef (rawBlock "latex")
2394+ <|> blockCommand
2395+ <|> paragraph
2396+ <|> grouped block
12462397 trace (T.take 60 $ tshow $ B.toList res)
12472398 return res
12482399
12492400blocks :: PandocMonad m => LP m Blocks
12502401blocks = mconcat <$> many block
12512402
2403+setDefaultLanguage :: PandocMonad m => LP m Blocks
2404+setDefaultLanguage = do
2405+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
2406+ <$> rawopt
2407+ polylang <- untokenize <$> braced
2408+ case M.lookup polylang polyglossiaLangToBCP47 of
2409+ Nothing -> return mempty -- TODO mzero? warning?
2410+ Just langFunc -> do
2411+ let l = langFunc o
2412+ setTranslations l
2413+ updateState $ setMeta "lang" $ str (renderLang l)
2414+ return mempty