@@ -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,90 +1152,79 @@ 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")
6471225 anyTok
6481226 return mempty)
6491227
650−rule :: PandocMonad m => LP m Blocks
651−rule = do
652− skipopts
653− width <- T.takeWhile (\c -> isDigit c || c == '.') . stringify <$> tok
654− _thickness <- tok
655− -- 0-width rules are used to fix spacing issues:
656− case safeRead width of
657− Just (0 :: Double) -> return mempty
658− _ -> return horizontalRule
659−
6601228paragraph :: PandocMonad m => LP m Blocks
6611229paragraph = do
6621230 x <- trimInlines . mconcat <$> many1 inline
@@ -694,16 +1262,6 @@ include name = do
6941262 mapM_ (insertIncluded defaultExt) fs
6951263 return mempty
6961264
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−
7071265insertIncluded :: PandocMonad m
7081266 => FilePath
7091267 -> FilePath
@@ -713,12 +1271,13 @@ insertIncluded defaultExtension f' = do
7131271 ".tex" -> f'
7141272 ".sty" -> f'
7151273 _ -> addExtension f' defaultExtension
1274+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
7161275 pos <- getPosition
7171276 containers <- getIncludeFiles <$> getState
7181277 when (T.pack f `elem` containers) $
7191278 throwError $ PandocParseError $ T.pack $ "Include file loop at " ++ show pos
7201279 updateState $ addIncludeFile $ T.pack f
721− mbcontents <- readFileFromTexinputs f
1280+ mbcontents <- readFileFromDirs dirs f
7221281 contents <- case mbcontents of
7231282 Just s -> return s
7241283 Nothing -> do
@@ -727,6 +1286,10 @@ insertIncluded defaultExtension f' = do
7271286 getInput >>= setInput . (tokenize f contents ++)
7281287 updateState dropLatestIncludeFile
7291288
1289+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> LP m ()
1290+addMeta field val = updateState $ \st ->
1291+ st{ sMeta = addMetaField field val $ sMeta st }
1292+
7301293authors :: PandocMonad m => LP m ()
7311294authors = try $ do
7321295 bgroup
@@ -735,6 +1298,150 @@ authors = try $ do
7351298 egroup
7361299 addMeta "author" (map trimInlines auths)
7371300
1301+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1302+macroDef constructor = do
1303+ (_, s) <- withRaw (commandDef <|> environmentDef)
1304+ (constructor (untokenize s) <$
1305+ guardDisabled Ext_latex_macros)
1306+ <|> return mempty
1307+ where commandDef = do
1308+ (name, macro') <- newcommand <|> letmacro <|> defmacro
1309+ guardDisabled Ext_latex_macros <|>
1310+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1311+ environmentDef = do
1312+ mbenv <- newenvironment
1313+ case mbenv of
1314+ Nothing -> return ()
1315+ Just (name, macro1, macro2) ->
1316+ guardDisabled Ext_latex_macros <|>
1317+ do updateState $ \s -> s{ sMacros =
1318+ M.insert name macro1 (sMacros s) }
1319+ updateState $ \s -> s{ sMacros =
1320+ M.insert ("end" <> name) macro2 (sMacros s) }
1321+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1322+ -- is equivalent to
1323+ -- @\newcommand{\envname}[n-args][default]{begin}@
1324+ -- @\newcommand{\endenvname}@
1325+
1326+letmacro :: PandocMonad m => LP m (Text, Macro)
1327+letmacro = do
1328+ controlSeq "let"
1329+ (name, contents) <- withVerbatimMode $ do
1330+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1331+ optional $ symbol '='
1332+ spaces
1333+ -- we first parse in verbatim mode, and then expand macros,
1334+ -- because we don't want \let\foo\bar to turn into
1335+ -- \let\foo hello if we have previously \def\bar{hello}
1336+ contents <- bracedOrToken
1337+ return (name, contents)
1338+ contents' <- doMacros' 0 contents
1339+ return (name, Macro ExpandWhenDefined [] Nothing contents')
1340+
1341+defmacro :: PandocMonad m => LP m (Text, Macro)
1342+defmacro = try $
1343+ -- we use withVerbatimMode, because macros are to be expanded
1344+ -- at point of use, not point of definition
1345+ withVerbatimMode $ do
1346+ controlSeq "def"
1347+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1348+ argspecs <- many (argspecArg <|> argspecPattern)
1349+ contents <- bracedOrToken
1350+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1351+
1352+argspecArg :: PandocMonad m => LP m ArgSpec
1353+argspecArg = do
1354+ Tok _ (Arg i) _ <- satisfyTok isArgTok
1355+ return $ ArgNum i
1356+
1357+argspecPattern :: PandocMonad m => LP m ArgSpec
1358+argspecPattern =
1359+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1360+ (toktype' == Symbol || toktype' == Word) &&
1361+ (txt /= "{" && txt /= "\\" && txt /= "}")))
1362+
1363+newcommand :: PandocMonad m => LP m (Text, Macro)
1364+newcommand = do
1365+ pos <- getPosition
1366+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1367+ controlSeq "renewcommand" <|>
1368+ controlSeq "providecommand" <|>
1369+ controlSeq "DeclareMathOperator" <|>
1370+ controlSeq "DeclareRobustCommand"
1371+ withVerbatimMode $ do
1372+ Tok _ (CtrlSeq name) txt <- do
1373+ optional (symbol '*')
1374+ anyControlSeq <|>
1375+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1376+ spaces
1377+ numargs <- option 0 $ try bracketedNum
1378+ let argspecs = map ArgNum [1..numargs]
1379+ spaces
1380+ optarg <- option Nothing $ Just <$> try bracketedToks
1381+ spaces
1382+ contents' <- bracedOrToken
1383+ let contents =
1384+ case mtype of
1385+ "DeclareMathOperator" ->
1386+ Tok pos (CtrlSeq "mathop") "\\mathop"
1387+ : Tok pos Symbol "{"
1388+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1389+ : Tok pos Symbol "{"
1390+ : (contents' ++
1391+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1392+ _ -> contents'
1393+ macros <- sMacros <$> getState
1394+ case M.lookup name macros of
1395+ Just macro
1396+ | mtype == "newcommand" -> do
1397+ report $ MacroAlreadyDefined txt pos
1398+ return (name, macro)
1399+ | mtype == "providecommand" -> return (name, macro)
1400+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1401+
1402+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1403+newenvironment = do
1404+ pos <- getPosition
1405+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1406+ controlSeq "renewenvironment" <|>
1407+ controlSeq "provideenvironment"
1408+ withVerbatimMode $ do
1409+ optional $ symbol '*'
1410+ spaces
1411+ name <- untokenize <$> braced
1412+ spaces
1413+ numargs <- option 0 $ try bracketedNum
1414+ spaces
1415+ optarg <- option Nothing $ Just <$> try bracketedToks
1416+ let argspecs = map (\i -> ArgNum i) [1..numargs]
1417+ startcontents <- spaces >> bracedOrToken
1418+ endcontents <- spaces >> bracedOrToken
1419+ macros <- sMacros <$> getState
1420+ case M.lookup name macros of
1421+ Just _
1422+ | mtype == "newenvironment" -> do
1423+ report $ MacroAlreadyDefined name pos
1424+ return Nothing
1425+ | mtype == "provideenvironment" ->
1426+ return Nothing
1427+ _ -> return $ Just (name,
1428+ Macro ExpandWhenUsed argspecs optarg startcontents,
1429+ Macro ExpandWhenUsed [] Nothing endcontents)
1430+
1431+bracketedNum :: PandocMonad m => LP m Int
1432+bracketedNum = do
1433+ ds <- untokenize <$> bracketedToks
1434+ case safeRead ds of
1435+ Just i -> return i
1436+ _ -> return 0
1437+
1438+setCaption :: PandocMonad m => LP m ()
1439+setCaption = try $ do
1440+ skipopts
1441+ ils <- tok
1442+ optional $ try $ spaces *> label
1443+ updateState $ \st -> st{ sCaption = Just ils }
1444+
7381445looseItem :: PandocMonad m => LP m Blocks
7391446looseItem = do
7401447 inListItem <- sInListItem <$> getState
@@ -748,6 +1455,10 @@ epigraph = do
7481455 p2 <- grouped block
7491456 return $ divWith ("", ["epigraph"], []) (p1 <> p2)
7501457
1458+resetCaption :: PandocMonad m => LP m ()
1459+resetCaption = updateState $ \st -> st{ sCaption = Nothing
1460+ , sLastLabel = Nothing }
1461+
7511462section :: PandocMonad m => Attr -> Int -> LP m Blocks
7521463section (ident, classes, kvs) lvl = do
7531464 skipopts
@@ -840,7 +1551,7 @@ blockCommands = M.fromList
8401551 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
8411552 , ("signature", mempty <$ (skipopts *> authors))
8421553 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
843− , ("newtheorem", newtheorem inline)
1554+ , ("newtheorem", newtheorem)
8441555 , ("theoremstyle", theoremstyle)
8451556 -- KOMA-Script metadata commands
8461557 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -884,11 +1595,11 @@ blockCommands = M.fromList
8841595 --
8851596 , ("hrule", pure horizontalRule)
8861597 , ("strut", pure mempty)
887− , ("rule", rule)
1598+ , ("rule", skipopts *> tok *> tok $> horizontalRule)
8881599 , ("item", looseItem)
8891600 , ("documentclass", skipopts *> braced *> preamble)
8901601 , ("centerline", para . trimInlines <$> (skipopts *> tok))
891− , ("caption", mempty <$ setCaption inline)
1602+ , ("caption", mempty <$ setCaption)
8921603 , ("bibliography", mempty <$ (skipopts *> braced >>=
8931604 addMeta "bibliography" . splitBibs . untokenize))
8941605 , ("addbibresource", mempty <$ (skipopts *> braced >>=
@@ -926,8 +1637,7 @@ blockCommands = M.fromList
9261637
9271638
9281639environments :: PandocMonad m => M.Map Text (LP m Blocks)
929−environments = M.union (tableEnvironments blocks inline) $
930− M.fromList
1640+environments = M.fromList
9311641 [ ("document", env "document" blocks <* skipMany anyTok)
9321642 , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
9331643 , ("sloppypar", env "sloppypar" blocks)
@@ -936,7 +1646,14 @@ environments = M.union (tableEnvironments blocks inline) $
9361646 skipopts *> spaces *> optional braced *> spaces *> blocks)
9371647 , ("figure", env "figure" $ skipopts *> figure)
9381648 , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
939− , ("center", divWith ("", ["center"], []) <$> env "center" blocks)
1649+ , ("center", env "center" blocks)
1650+ , ("longtable", env "longtable" $
1651+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
1652+ , ("table", env "table" $
1653+ skipopts *> resetCaption *> blocks >>= addTableCaption)
1654+ , ("tabular*", env "tabular*" $ simpTable "tabular*" True)
1655+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1656+ , ("tabular", env "tabular" $ simpTable "tabular" False)
9401657 , ("quote", blockQuote <$> env "quote" blocks)
9411658 , ("quotation", blockQuote <$> env "quotation" blocks)
9421659 , ("verse", blockQuote <$> env "verse" blocks)
@@ -959,7 +1676,7 @@ environments = M.union (tableEnvironments blocks inline) $
9591676 , ("lilypond", rawVerbEnv "lilypond")
9601677 , ("ly", rawVerbEnv "ly")
9611678 -- amsthm
962− , ("proof", proof blocks opt)
1679+ , ("proof", proof)
9631680 -- etoolbox
9641681 , ("ifstrequal", ifstrequal)
9651682 , ("newtoggle", braced >>= newToggle)
@@ -968,29 +1685,130 @@ environments = M.union (tableEnvironments blocks inline) $
9681685 , ("iftoggle", try $ ifToggle >> block)
9691686 ]
9701687
971−filecontents :: PandocMonad m => LP m Blocks
972−filecontents = try $ do
973− controlSeq "begin"
1688+theoremstyle :: PandocMonad m => LP m Blocks
1689+theoremstyle = do
1690+ stylename <- untokenize <$> braced
1691+ let mbstyle = case stylename of
1692+ "plain" -> Just PlainStyle
1693+ "definition" -> Just DefinitionStyle
1694+ "remark" -> Just RemarkStyle
1695+ _ -> Nothing
1696+ case mbstyle of
1697+ Nothing -> return ()
1698+ Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
1699+ return mempty
1700+
1701+newtheorem :: PandocMonad m => LP m Blocks
1702+newtheorem = do
1703+ number <- option True (False <$ symbol '*' <* sp)
9741704 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) }
1705+ sp
1706+ series <- option Nothing $ Just . untokenize <$> bracketedToks
1707+ sp
1708+ showName <- tok
1709+ sp
1710+ syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
1711+ sty <- sLastTheoremStyle <$> getState
1712+ let spec = TheoremSpec { theoremName = showName
1713+ , theoremStyle = sty
1714+ , theoremSeries = series
1715+ , theoremSyncTo = syncTo
1716+ , theoremNumber = number
1717+ , theoremLastNum = DottedNum [0] }
1718+ tmap <- sTheoremMap <$> getState
1719+ updateState $ \s -> s{ sTheoremMap =
1720+ M.insert name spec tmap }
9811721 return mempty
9821722
1723+proof :: PandocMonad m => LP m Blocks
1724+proof = do
1725+ title <- option (B.text "Proof") opt
1726+ bs <- env "proof" blocks
1727+ return $
1728+ B.divWith ("", ["proof"], []) $
1729+ addQed $ addTitle (B.emph (title <> ".")) bs
1730+
1731+addTitle :: Inlines -> Blocks -> Blocks
1732+addTitle ils bs =
1733+ case B.toList bs of
1734+ (Para xs : rest)
1735+ -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
1736+ _ -> B.para ils <> bs
1737+
1738+addQed :: Blocks -> Blocks
1739+addQed bs =
1740+ case Seq.viewr (B.unMany bs) of
1741+ s Seq.:> Para ils
1742+ -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
1743+ _ -> bs <> B.para qedSign
1744+ where
1745+ qedSign = B.str "\xa0\x25FB"
1746+
9831747environment :: PandocMonad m => LP m Blocks
9841748environment = try $ do
9851749 controlSeq "begin"
9861750 name <- untokenize <$> braced
9871751 M.findWithDefault mzero name environments <|>
988− theoremEnvironment blocks opt name <|>
1752+ theoremEnvironment name <|>
9891753 if M.member name (inlineEnvironments
9901754 :: M.Map Text (LP PandocPure Inlines))
9911755 then mzero
9921756 else try (rawEnv name) <|> rawVerbEnv name
9931757
1758+theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
1759+theoremEnvironment name = do
1760+ tmap <- sTheoremMap <$> getState
1761+ case M.lookup name tmap of
1762+ Nothing -> mzero
1763+ Just tspec -> do
1764+ optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
1765+ mblabel <- option Nothing $ Just . untokenize <$>
1766+ try (spaces >> controlSeq "label" >> spaces >> braced)
1767+ bs <- env name blocks
1768+ number <-
1769+ if theoremNumber tspec
1770+ then do
1771+ let name' = fromMaybe name $ theoremSeries tspec
1772+ num <- getNextNumber
1773+ (maybe (DottedNum [0]) theoremLastNum .
1774+ M.lookup name' . sTheoremMap)
1775+ updateState $ \s ->
1776+ s{ sTheoremMap =
1777+ M.adjust
1778+ (\spec -> spec{ theoremLastNum = num })
1779+ name'
1780+ (sTheoremMap s)
1781+ }
1782+
1783+ case mblabel of
1784+ Just ident ->
1785+ updateState $ \s ->
1786+ s{ sLabels = M.insert ident
1787+ (B.toList $
1788+ theoremName tspec <> "\160" <>
1789+ str (renderDottedNum num)) (sLabels s) }
1790+ Nothing -> return ()
1791+ return $ space <> B.text (renderDottedNum num)
1792+ else return mempty
1793+ let titleEmph = case theoremStyle tspec of
1794+ PlainStyle -> B.strong
1795+ DefinitionStyle -> B.strong
1796+ RemarkStyle -> B.emph
1797+ let title = titleEmph (theoremName tspec <> number)
1798+ <> optTitle <> "." <> space
1799+ return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
1800+ $ case theoremStyle tspec of
1801+ PlainStyle -> walk italicize bs
1802+ _ -> bs
1803+
1804+italicize :: Block -> Block
1805+italicize (Para ils) = Para [Emph ils]
1806+italicize (Plain ils) = Plain [Emph ils]
1807+italicize x = x
1808+
1809+env :: PandocMonad m => Text -> LP m a -> LP m a
1810+env name p = p <* end_ name
1811+
9941812rawEnv :: PandocMonad m => Text -> LP m Blocks
9951813rawEnv name = do
9961814 exts <- getOption readerExtensions
@@ -998,17 +1816,15 @@ rawEnv name = do
9981816 rawOptions <- mconcat <$> many rawopt
9991817 let beginCommand = "\\begin{" <> name <> "}" <> rawOptions
10001818 pos1 <- getPosition
1819+ (bs, raw) <- withRaw $ env name blocks
10011820 if parseRaw
1002− then do
1003− (_, raw) <- withRaw $ env name blocks
1004− return $ rawBlock "latex"
1821+ then return $ rawBlock "latex"
10051822 $ beginCommand <> untokenize raw
10061823 else do
1007− bs <- env name blocks
10081824 report $ SkippedContent beginCommand pos1
10091825 pos2 <- getPosition
10101826 report $ SkippedContent ("\\end{" <> name <> "}") pos2
1011− return $ divWith ("",[name],[]) bs
1827+ return bs
10121828
10131829rawVerbEnv :: PandocMonad m => Text -> LP m Blocks
10141830rawVerbEnv name = do
@@ -1067,7 +1883,8 @@ inputMinted = do
10671883 pos <- getPosition
10681884 attr <- mintedAttr
10691885 f <- T.filter (/='"') . untokenize <$> braced
1070− mbCode <- readFileFromTexinputs (T.unpack f)
1886+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
1887+ mbCode <- readFileFromDirs dirs (T.unpack f)
10711888 rawcode <- case mbCode of
10721889 Just s -> return s
10731890 Nothing -> do
@@ -1153,7 +1970,8 @@ inputListing = do
11531970 pos <- getPosition
11541971 options <- option [] keyvals
11551972 f <- T.filter (/='"') . untokenize <$> braced
1156− mbCode <- readFileFromTexinputs (T.unpack f)
1973+ dirs <- map T.unpack . splitTextBy (==':') . fromMaybe "." <$> lookupEnv "TEXINPUTS"
1974+ mbCode <- readFileFromDirs dirs (T.unpack f)
11571975 codeLines <- case mbCode of
11581976 Just s -> return $ T.lines s
11591977 Nothing -> do
@@ -1162,8 +1980,7 @@ inputListing = do
11621980 let (ident,classes,kvs) = parseListingsOptions options
11631981 let classes' =
11641982 (case listingsLanguage options of
1165− Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1166− (T.pack $ takeExtension $ T.unpack f)) <>)
1983+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
11671984 Just _ -> id) classes
11681985 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
11691986 let lastline = fromMaybe (length codeLines) $
@@ -1229,23 +2046,358 @@ orderedList' = try $ do
12292046 bs <- listenv "enumerate" (many item)
12302047 return $ orderedListWith (start, style, delim) bs
12312048
2049+-- tables
2050+
2051+hline :: PandocMonad m => LP m ()
2052+hline = try $ do
2053+ spaces
2054+ controlSeq "hline" <|>
2055+ -- booktabs rules:
2056+ controlSeq "toprule" <|>
2057+ controlSeq "bottomrule" <|>
2058+ controlSeq "midrule" <|>
2059+ controlSeq "endhead" <|>
2060+ controlSeq "endfirsthead"
2061+ spaces
2062+ optional opt
2063+ return ()
2064+
2065+lbreak :: PandocMonad m => LP m Tok
2066+lbreak = (controlSeq "\\" <|> controlSeq "tabularnewline")
2067+ <* skipopts <* spaces
2068+
2069+amp :: PandocMonad m => LP m Tok
2070+amp = symbol '&'
2071+
2072+-- Split a Word into individual Symbols (for parseAligns)
2073+splitWordTok :: PandocMonad m => LP m ()
2074+splitWordTok = do
2075+ inp <- getInput
2076+ case inp of
2077+ (Tok spos Word t : rest) ->
2078+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) <> rest
2079+ _ -> return ()
2080+
2081+parseAligns :: PandocMonad m => LP m [(Alignment, ColWidth, ([Tok], [Tok]))]
2082+parseAligns = try $ do
2083+ let maybeBar = skipMany
2084+ (try $ sp *> (() <$ symbol '|' <|> () <$ (symbol '@' >> braced)))
2085+ let cAlign = AlignCenter <$ symbol 'c'
2086+ let lAlign = AlignLeft <$ symbol 'l'
2087+ let rAlign = AlignRight <$ symbol 'r'
2088+ let parAlign = AlignLeft <$ symbol 'p'
2089+ -- aligns from tabularx
2090+ let xAlign = AlignLeft <$ symbol 'X'
2091+ let mAlign = AlignLeft <$ symbol 'm'
2092+ let bAlign = AlignLeft <$ symbol 'b'
2093+ let alignChar = splitWordTok *> ( cAlign <|> lAlign <|> rAlign <|> parAlign
2094+ <|> xAlign <|> mAlign <|> bAlign )
2095+ let alignPrefix = symbol '>' >> braced
2096+ let alignSuffix = symbol '<' >> braced
2097+ let colWidth = try $ do
2098+ symbol '{'
2099+ ds <- trim . untokenize <$> manyTill anyTok (controlSeq "linewidth")
2100+ spaces
2101+ symbol '}'
2102+ return $ safeRead ds
2103+ let alignSpec = do
2104+ pref <- option [] alignPrefix
2105+ spaces
2106+ al <- alignChar
2107+ width <- colWidth <|> option Nothing (do s <- untokenize <$> braced
2108+ pos <- getPosition
2109+ report $ SkippedContent s pos
2110+ return Nothing)
2111+ spaces
2112+ suff <- option [] alignSuffix
2113+ return (al, width, (pref, suff))
2114+ let starAlign = do -- '*{2}{r}' == 'rr', we just expand like a macro
2115+ symbol '*'
2116+ spaces
2117+ ds <- trim . untokenize <$> braced
2118+ spaces
2119+ spec <- braced
2120+ case safeRead ds of
2121+ Just n ->
2122+ getInput >>= setInput . (mconcat (replicate n spec) ++)
2123+ Nothing -> Prelude.fail $ "Could not parse " <> T.unpack ds <> " as number"
2124+ bgroup
2125+ spaces
2126+ maybeBar
2127+ aligns' <- many $ try $ spaces >> optional starAlign >>
2128+ (alignSpec <* maybeBar)
2129+ spaces
2130+ egroup
2131+ spaces
2132+ return $ map toSpec aligns'
2133+ where
2134+ toColWidth (Just w) | w > 0 = ColWidth w
2135+ toColWidth _ = ColWidthDefault
2136+ toSpec (x, y, z) = (x, toColWidth y, z)
2137+
2138+-- N.B. this parser returns a Row that may have erroneous empty cells
2139+-- in it. See the note above fixTableHead for details.
2140+parseTableRow :: PandocMonad m
2141+ => Text -- ^ table environment name
2142+ -> [([Tok], [Tok])] -- ^ pref/suffixes
2143+ -> LP m Row
2144+parseTableRow envname prefsufs = do
2145+ notFollowedBy (spaces *> end_ envname)
2146+ -- add prefixes and suffixes in token stream:
2147+ let celltoks (pref, suff) = do
2148+ prefpos <- getPosition
2149+ contents <- mconcat <$>
2150+ many ( snd <$> withRaw (controlSeq "parbox" >> parbox) -- #5711
2151+ <|>
2152+ snd <$> withRaw (inlineEnvironment <|> dollarsMath)
2153+ <|>
2154+ (do notFollowedBy
2155+ (() <$ amp <|> () <$ lbreak <|> end_ envname)
2156+ count 1 anyTok) )
2157+
2158+ suffpos <- getPosition
2159+ option [] (count 1 amp)
2160+ return $ map (setpos prefpos) pref ++ contents ++ map (setpos suffpos) suff
2161+ rawcells <- mapM celltoks prefsufs
2162+ oldInput <- getInput
2163+ cells <- mapM (\ts -> setInput ts >> parseTableCell) rawcells
2164+ setInput oldInput
2165+ spaces
2166+ return $ Row nullAttr cells
2167+
2168+parseTableCell :: PandocMonad m => LP m Cell
2169+parseTableCell = do
2170+ spaces
2171+ updateState $ \st -> st{ sInTableCell = True }
2172+ cell' <- multicolumnCell
2173+ <|> multirowCell
2174+ <|> parseSimpleCell
2175+ <|> parseEmptyCell
2176+ updateState $ \st -> st{ sInTableCell = False }
2177+ spaces
2178+ return cell'
2179+ where
2180+ -- The parsing of empty cells is important in LaTeX, especially when dealing
2181+ -- with multirow/multicolumn. See #6603.
2182+ parseEmptyCell = spaces $> emptyCell
2183+
2184+cellAlignment :: PandocMonad m => LP m Alignment
2185+cellAlignment = skipMany (symbol '|') *> alignment <* skipMany (symbol '|')
2186+ where
2187+ alignment = do
2188+ c <- untoken <$> singleChar
2189+ return $ case c of
2190+ "l" -> AlignLeft
2191+ "r" -> AlignRight
2192+ "c" -> AlignCenter
2193+ "*" -> AlignDefault
2194+ _ -> AlignDefault
2195+
2196+plainify :: Blocks -> Blocks
2197+plainify bs = case toList bs of
2198+ [Para ils] -> plain (fromList ils)
2199+ _ -> bs
2200+
2201+multirowCell :: PandocMonad m => LP m Cell
2202+multirowCell = controlSeq "multirow" >> do
2203+ -- Full prototype for \multirow macro is:
2204+ -- \multirow[vpos]{nrows}[bigstruts]{width}[vmove]{text}
2205+ -- However, everything except `nrows` and `text` make
2206+ -- sense in the context of the Pandoc AST
2207+ _ <- optional $ symbol '[' *> cellAlignment <* symbol ']' -- vertical position
2208+ nrows <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2209+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- bigstrut-related
2210+ _ <- symbol '{' *> manyTill anyTok (symbol '}') -- Cell width
2211+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- Length used for fine-tuning
2212+ content <- symbol '{' *> (plainify <$> blocks) <* symbol '}'
2213+ return $ cell AlignDefault (RowSpan nrows) (ColSpan 1) content
2214+
2215+multicolumnCell :: PandocMonad m => LP m Cell
2216+multicolumnCell = controlSeq "multicolumn" >> do
2217+ span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2218+ alignment <- symbol '{' *> cellAlignment <* symbol '}'
2219+
2220+ let singleCell = do
2221+ content <- plainify <$> blocks
2222+ return $ cell alignment (RowSpan 1) (ColSpan span') content
2223+
2224+ -- Two possible contents: either a \multirow cell, or content.
2225+ -- E.g. \multicol{1}{c}{\multirow{2}{1em}{content}}
2226+ -- Note that a \multirow cell can be nested in a \multicolumn,
2227+ -- but not the other way around. See #6603
2228+ let nestedCell = do
2229+ (Cell _ _ (RowSpan rs) _ bs) <- multirowCell
2230+ return $ cell
2231+ alignment
2232+ (RowSpan rs)
2233+ (ColSpan span')
2234+ (fromList bs)
2235+
2236+ symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
2237+
2238+-- Parse a simple cell, i.e. not multirow/multicol
2239+parseSimpleCell :: PandocMonad m => LP m Cell
2240+parseSimpleCell = simpleCell <$> (plainify <$> blocks)
2241+
2242+-- LaTeX tables are stored with empty cells underneath multirow cells
2243+-- denoting the grid spaces taken up by them. More specifically, if a
2244+-- cell spans m rows, then it will overwrite all the cells in the
2245+-- columns it spans for (m-1) rows underneath it, requiring padding
2246+-- cells in these places. These padding cells need to be removed for
2247+-- proper table reading. See #6603.
2248+--
2249+-- These fixTable functions do not otherwise fix up malformed
2250+-- input tables: that is left to the table builder.
2251+fixTableHead :: TableHead -> TableHead
2252+fixTableHead (TableHead attr rows) = TableHead attr rows'
2253+ where
2254+ rows' = fixTableRows rows
2255+
2256+fixTableBody :: TableBody -> TableBody
2257+fixTableBody (TableBody attr rhc th tb)
2258+ = TableBody attr rhc th' tb'
2259+ where
2260+ th' = fixTableRows th
2261+ tb' = fixTableRows tb
2262+
2263+fixTableRows :: [Row] -> [Row]
2264+fixTableRows = fixTableRows' $ repeat Nothing
2265+ where
2266+ fixTableRows' oldHang (Row attr cells : rs)
2267+ = let (newHang, cells') = fixTableRow oldHang cells
2268+ rs' = fixTableRows' newHang rs
2269+ in Row attr cells' : rs'
2270+ fixTableRows' _ [] = []
2271+
2272+-- The overhang is represented as Just (relative cell dimensions) or
2273+-- Nothing for an empty grid space.
2274+fixTableRow :: [Maybe (ColSpan, RowSpan)] -> [Cell] -> ([Maybe (ColSpan, RowSpan)], [Cell])
2275+fixTableRow oldHang cells
2276+ -- If there's overhang, drop cells until their total width meets the
2277+ -- width of the occupied grid spaces (or we run out)
2278+ | (n, prefHang, restHang) <- splitHang oldHang
2279+ , n > 0
2280+ = let cells' = dropToWidth getCellW n cells
2281+ (restHang', cells'') = fixTableRow restHang cells'
2282+ in (prefHang restHang', cells'')
2283+ -- Otherwise record the overhang of a pending cell and fix the rest
2284+ -- of the row
2285+ | c@(Cell _ _ h w _):cells' <- cells
2286+ = let h' = max 1 h
2287+ w' = max 1 w
2288+ oldHang' = dropToWidth getHangW w' oldHang
2289+ (newHang, cells'') = fixTableRow oldHang' cells'
2290+ in (toHang w' h' <> newHang, c : cells'')
2291+ | otherwise
2292+ = (oldHang, [])
2293+ where
2294+ getCellW (Cell _ _ _ w _) = w
2295+ getHangW = maybe 1 fst
2296+ getCS (ColSpan n) = n
2297+
2298+ toHang c r
2299+ | r > 1 = [Just (c, r)]
2300+ | otherwise = replicate (getCS c) Nothing
2301+
2302+ -- Take the prefix of the overhang list representing filled grid
2303+ -- spaces. Also return the remainder and the length of this prefix.
2304+ splitHang = splitHang' 0 id
2305+
2306+ splitHang' !n l (Just (c, r):xs)
2307+ = splitHang' (n + c) (l . (toHang c (r-1) ++)) xs
2308+ splitHang' n l xs = (n, l, xs)
2309+
2310+ -- Drop list items until the total width of the dropped items
2311+ -- exceeds the passed width.
2312+ dropToWidth _ n l | n < 1 = l
2313+ dropToWidth wproj n (c:cs) = dropToWidth wproj (n - wproj c) cs
2314+ dropToWidth _ _ [] = []
2315+
2316+simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
2317+simpTable envname hasWidthParameter = try $ do
2318+ when hasWidthParameter $ () <$ (spaces >> tok)
2319+ skipopts
2320+ colspecs <- parseAligns
2321+ let (aligns, widths, prefsufs) = unzip3 colspecs
2322+ optional $ controlSeq "caption" *> setCaption
2323+ spaces
2324+ optional label
2325+ spaces
2326+ optional lbreak
2327+ spaces
2328+ skipMany hline
2329+ spaces
2330+ header' <- option [] . try . fmap (:[]) $
2331+ parseTableRow envname prefsufs <* lbreak <* many1 hline
2332+ spaces
2333+ rows <- sepEndBy (parseTableRow envname prefsufs)
2334+ (lbreak <* optional (skipMany hline))
2335+ spaces
2336+ optional $ controlSeq "caption" *> setCaption
2337+ spaces
2338+ optional label
2339+ spaces
2340+ optional lbreak
2341+ spaces
2342+ lookAhead $ controlSeq "end" -- make sure we're at end
2343+ let th = fixTableHead $ TableHead nullAttr header'
2344+ let tbs = [fixTableBody $ TableBody nullAttr 0 [] rows]
2345+ let tf = TableFoot nullAttr []
2346+ return $ table emptyCaption (zip aligns widths) th tbs tf
2347+
2348+addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
2349+addTableCaption = walkM go
2350+ where go (Table attr c spec th tb tf) = do
2351+ st <- getState
2352+ let mblabel = sLastLabel st
2353+ capt <- case (sCaption st, mblabel) of
2354+ (Just ils, Nothing) -> return $ caption Nothing (plain ils)
2355+ (Just ils, Just lab) -> do
2356+ num <- getNextNumber sLastTableNum
2357+ setState
2358+ st{ sLastTableNum = num
2359+ , sLabels = M.insert lab
2360+ [Str (renderDottedNum num)]
2361+ (sLabels st) }
2362+ return $ caption Nothing (plain ils) -- add number??
2363+ (Nothing, _) -> return c
2364+ let attr' = case (attr, mblabel) of
2365+ ((_,classes,kvs), Just ident) ->
2366+ (ident,classes,kvs)
2367+ _ -> attr
2368+ return $ addAttrDiv attr' $ Table nullAttr capt spec th tb tf
2369+ go x = return x
2370+
2371+-- TODO: For now we add a Div to contain table attributes, since
2372+-- most writers don't do anything yet with attributes on Table.
2373+-- This can be removed when that changes.
2374+addAttrDiv :: Attr -> Block -> Block
2375+addAttrDiv ("",[],[]) b = b
2376+addAttrDiv attr b = Div attr [b]
2377+
12322378block :: PandocMonad m => LP m Blocks
12332379block = 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
2380+ res <- (mempty <$ spaces1)
2381+ <|> environment
2382+ <|> macroDef (rawBlock "latex")
2383+ <|> blockCommand
2384+ <|> paragraph
2385+ <|> grouped block
12462386 trace (T.take 60 $ tshow $ B.toList res)
12472387 return res
12482388
12492389blocks :: PandocMonad m => LP m Blocks
12502390blocks = mconcat <$> many block
12512391
2392+setDefaultLanguage :: PandocMonad m => LP m Blocks
2393+setDefaultLanguage = do
2394+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
2395+ <$> rawopt
2396+ polylang <- untokenize <$> braced
2397+ case M.lookup polylang polyglossiaLangToBCP47 of
2398+ Nothing -> return mempty -- TODO mzero? warning?
2399+ Just langFunc -> do
2400+ let l = langFunc o
2401+ setTranslations l
2402+ updateState $ setMeta "lang" $ str (renderLang l)
2403+ return mempty