@@ -1,3 +1,7 @@
1+{-# LANGUAGE BangPatterns #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
1{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE PatternGuards #-}
6{-# LANGUAGE PatternGuards #-}
3{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
@@ -18,58 +22,50 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
18 applyMacros,
22 applyMacros,
19 rawLaTeXInline,
23 rawLaTeXInline,
20 rawLaTeXBlock,
24 rawLaTeXBlock,
21− inlineCommand
25+ inlineCommand,
24import Control.Applicative (many, optional, (<|>))
30import Control.Applicative (many, optional, (<|>))
25import Control.Monad
31import Control.Monad
26import Control.Monad.Except (throwError)
32import Control.Monad.Except (throwError)
27−import Data.Char (isDigit, isLetter, isAlphaNum, toUpper, chr)
33+import Data.Char (isDigit, isLetter, toUpper, chr)
28import Data.Default
34import Data.Default
35+import Data.Functor (($>))
29import Data.List (intercalate)
36import Data.List (intercalate)
30import qualified Data.Map as M
37import qualified Data.Map as M
31import Data.Maybe (fromMaybe, maybeToList)
38import Data.Maybe (fromMaybe, maybeToList)
32import qualified Data.Set as Set
39import qualified Data.Set as Set
40+import qualified Data.Sequence as Seq
33import Data.Text (Text)
41import Data.Text (Text)
34import qualified Data.Text as T
42import qualified Data.Text as T
35−import Skylighting (defaultSyntaxMap)
36import System.FilePath (addExtension, replaceExtension, takeExtension)
43import System.FilePath (addExtension, replaceExtension, takeExtension)
37−import Text.Collate.Lang (renderLang)
44+import Text.Pandoc.BCP47 (Lang (..), renderLang)
38−import Text.Pandoc.Builder as B
45+import Text.Pandoc.Builder
39import Text.Pandoc.Class.PandocPure (PandocPure)
46import Text.Pandoc.Class.PandocPure (PandocPure)
40import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
47import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
41− readFileFromDirs, report,
48+ readFileFromDirs, report, setResourcePath,
42− setResourcePath)
49+ setTranslations, translateTerm)
43import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
50import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
44−import Text.Pandoc.Highlighting (languagesByExtension)
51+import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
45import Text.Pandoc.ImageSize (numUnit, showFl)
52import Text.Pandoc.ImageSize (numUnit, showFl)
46import Text.Pandoc.Logging
53import Text.Pandoc.Logging
47import Text.Pandoc.Options
54import Text.Pandoc.Options
48import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
55import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
49 optional, space, spaces, withRaw, (<|>))
56 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 (..))
51import Text.Pandoc.Readers.LaTeX.Parsing
59import Text.Pandoc.Readers.LaTeX.Parsing
52−import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
60+import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
53−import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
55− mathDisplay, mathInline,
56− newtheorem, theoremstyle, proof,
58−import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
59−import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
60−import Text.Pandoc.Readers.LaTeX.Lang (inlineLanguageCommands,
62− babelLangToBCP47, setDefaultLanguage)
61+ babelLangToBCP47)
63−import Text.Pandoc.Readers.LaTeX.SIunitx (siunitxCommands)
62+import Text.Pandoc.Readers.LaTeX.SIunitx
64−import Text.Pandoc.Readers.LaTeX.Inline (acronymCommands, refCommands,
65− nameCommands, charCommands,
67− biblatexInlineCommands,
68− verbCommands, rawInlineOr,
70import Text.Pandoc.Shared
63import Text.Pandoc.Shared
64+import qualified Text.Pandoc.Translations as Translations
71import Text.Pandoc.Walk
65import 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
74-- for debugging:
70-- for debugging:
75-- import Text.Pandoc.Extensions (getDefaultExtensions)
71-- import Text.Pandoc.Extensions (getDefaultExtensions)
@@ -77,17 +73,16 @@ import Data.List.NonEmpty (nonEmpty)
77-- import Debug.Trace (traceShowId)
73-- import Debug.Trace (traceShowId)
79-- | Parse LaTeX from string and return 'Pandoc' document.
75-- | Parse LaTeX from string and return 'Pandoc' document.
80−readLaTeX :: (PandocMonad m, ToSources a)
76+readLaTeX :: PandocMonad m
81 => ReaderOptions -- ^ Reader options
77 => ReaderOptions -- ^ Reader options
82− -> a -- ^ Input to parse
78+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
83 -> m Pandoc
79 -> m Pandoc
84readLaTeX opts ltx = do
80readLaTeX opts ltx = do
85− let sources = toSources ltx
86 parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
81 parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
87− (tokenizeSources sources)
82+ (tokenize "source" (crFilter ltx))
88 case parsed of
83 case parsed of
89 Right result -> return result
84 Right result -> return result
90− Left e -> throwError $ PandocParsecError sources e
85+ Left e -> throwError $ PandocParsecError ltx e
92parseLaTeX :: PandocMonad m => LP m Pandoc
87parseLaTeX :: PandocMonad m => LP m Pandoc
93parseLaTeX = do
88parseLaTeX = do
@@ -98,7 +93,11 @@ parseLaTeX = do
98 let doc' = doc bs
93 let doc' = doc bs
99 let headerLevel (Header n _ _) = [n]
94 let headerLevel (Header n _ _) = [n]
100 headerLevel _ = []
95 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'
99+ let bottomLevel = minimumDef 1 $ query headerLevel doc'
102 let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
101 let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
103 adjustHeaders _ x = x
102 adjustHeaders _ x = x
104 let (Pandoc _ bs') =
103 let (Pandoc _ bs') =
@@ -133,11 +132,11 @@ resolveRefs _ x = x
135rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
134rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
136− => ParserT Sources s m Text
135+ => ParserT Text s m Text
137rawLaTeXBlock = do
136rawLaTeXBlock = do
138 lookAhead (try (char '\\' >> letter))
137 lookAhead (try (char '\\' >> letter))
139 inp <- getInput
138 inp <- getInput
140− let toks = tokenizeSources inp
139+ let toks = tokenize "source" inp
141 snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
140 snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
142 <|> rawLaTeXParser toks True
141 <|> rawLaTeXParser toks True
143 (do choice (map controlSeq
142 (do choice (map controlSeq
@@ -164,14 +163,14 @@ beginOrEndCommand = try $ do
164 (txt <> untokenize rawargs)
163 (txt <> untokenize rawargs)
166rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
165rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
167− => ParserT Sources s m Text
166+ => ParserT Text s m Text
168rawLaTeXInline = do
167rawLaTeXInline = do
169 lookAhead (try (char '\\' >> letter))
168 lookAhead (try (char '\\' >> letter))
170 inp <- getInput
169 inp <- getInput
171− let toks = tokenizeSources inp
170+ let toks = tokenize "source" inp
172 raw <- snd <$>
171 raw <- snd <$>
173 ( rawLaTeXParser toks True
172 ( rawLaTeXParser toks True
174− (mempty <$ (controlSeq "input" >> skipMany rawopt >> braced))
173+ (mempty <$ (controlSeq "input" >> skipMany opt >> braced))
176 <|> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
175 <|> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
@@ -179,11 +178,11 @@ rawLaTeXInline = do
179 finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
178 finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
180 return $ raw <> T.pack finalbraces
179 return $ raw <> T.pack finalbraces
182−inlineCommand :: PandocMonad m => ParserT Sources ParserState m Inlines
181+inlineCommand :: PandocMonad m => ParserT Text ParserState m Inlines
183inlineCommand = do
182inlineCommand = do
184 lookAhead (try (char '\\' >> letter))
183 lookAhead (try (char '\\' >> letter))
185 inp <- getInput
184 inp <- getInput
186− let toks = tokenizeSources inp
185+ let toks = tokenize "source" inp
187 fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
186 fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
@@ -192,6 +191,12 @@ inlineCommand = do
192word :: PandocMonad m => LP m Inlines
191word :: PandocMonad m => LP m Inlines
193word = str . untoken <$> satisfyTok isWordTok
192word = str . untoken <$> satisfyTok isWordTok
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
195inlineGroup :: PandocMonad m => LP m Inlines
200inlineGroup :: PandocMonad m => LP m Inlines
196inlineGroup = do
201inlineGroup = do
197 ils <- grouped inline
202 ils <- grouped inline
@@ -232,6 +237,19 @@ mkImage options (T.unpack -> src) = do
232 _ -> return src
237 _ -> return src
233 return $ imageWith attr (T.pack src') "" alt
238 return $ imageWith attr (T.pack src') "" alt
240+doxspace :: PandocMonad m => LP m Inlines
242+ (space <$ lookAhead (satisfyTok startsWithLetter)) <|> return mempty
243+ where startsWithLetter (Tok _ Word t) =
245+ Just (c, _) | isLetter c -> True
247+ startsWithLetter _ = False
250+lit :: Text -> LP m Inlines
235removeDoubleQuotes :: Text -> Text
253removeDoubleQuotes :: Text -> Text
236removeDoubleQuotes t =
254removeDoubleQuotes t =
237 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
255 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
@@ -278,14 +296,23 @@ quoted' f starter ender = do
278 cs -> cs)
296 cs -> cs)
279 else lit startchs
297 else lit startchs
281−lit :: Text -> LP m Inlines
299+enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines
282−lit = pure . str
300+enquote starred mblang = do
302+ let lang = mblang >>= babelLangToBCP47
303+ let langspan = case lang of
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
284blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
311blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
285blockquote cvariant mblang = do
312blockquote cvariant mblang = do
286 citepar <- if cvariant
313 citepar <- if cvariant
287 then (\xs -> para (cite xs mempty))
314 then (\xs -> para (cite xs mempty))
288− <$> cites inline NormalCitation False
315+ <$> cites NormalCitation False
289 else option mempty $ para <$> bracketed inline
316 else option mempty $ para <$> bracketed inline
290 let lang = mblang >>= babelLangToBCP47
317 let lang = mblang >>= babelLangToBCP47
291 let langdiv = case lang of
318 let langdiv = case lang of
@@ -296,13 +323,224 @@ blockquote cvariant mblang = do
296 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
323 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
297 return $ blockQuote . langdiv $ (bs <> citepar)
324 return $ blockQuote . langdiv $ (bs <> citepar)
326+doAcronym :: PandocMonad m => Text -> LP m Inlines
329+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
330+ ("acronym-form", "singular+" <> form)])
331+ $ str $ untokenize acro]
333+doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
334+doAcronymPlural form = do
337+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
338+ ("acronym-form", "plural+" <> form)]) $
339+ mconcat [str $ untokenize acro, plural]]
341+doverb :: PandocMonad m => LP m Inlines
343+ Tok _ Symbol t <- anySymbol
344+ marker <- case T.uncons t of
345+ Just (c, ts) | T.null ts -> return c
348+ code . untokenize <$>
349+ manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
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
357+ let (t1, t2) = T.splitAt i txt
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
363+listingsLanguage :: [(Text, Text)] -> Maybe Text
364+listingsLanguage opts =
365+ case lookup "language" opts of
367+ Just l -> fromListingsLanguage l `mplus` Just l
369+dolstinline :: PandocMonad m => LP m Inlines
371+ options <- option [] keyvals
372+ let classes = maybeToList $ listingsLanguage options
373+ doinlinecode classes
375+domintinline :: PandocMonad m => LP m Inlines
378+ cls <- untokenize <$> braced
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
387+ let stopchar = if marker == '{' then '}' else marker
389+ codeWith ("",classes,[]) . T.map nlToSpace . untokenize <$>
390+ manyTill (verbTok stopchar) (symbol stopchar)
392+nlToSpace :: Char -> Char
396+mathDisplay :: Text -> Inlines
397+mathDisplay = displayMath . trimMath
399+mathInline :: Text -> Inlines
400+mathInline = math . trimMath
402+dollarsMath :: PandocMonad m => LP m Inlines
405+ display <- option False (True <$ symbol '$')
406+ (do contents <- try $ untokenize <$> pDollarsMath 0
408+ then mathDisplay contents <$ symbol '$'
409+ else return $ mathInline contents)
410+ <|> (guard display >> return (mathInline ""))
412+-- Int is number of embedded groupings
413+pDollarsMath :: PandocMonad m => Int -> LP m [Tok]
415+ tk@(Tok _ toktype t) <- anyTok
418+ , n == 0 -> return []
421+ (tk :) . (tk' :) <$> pDollarsMath n
422+ | t == "{" -> (tk :) <$> pDollarsMath (n+1)
425+ then (tk :) <$> pDollarsMath (n-1)
427+ _ -> (tk :) <$> pDollarsMath n
431+addPrefix :: [Inline] -> [Citation] -> [Citation]
432+addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
435+addSuffix :: [Inline] -> [Citation] -> [Citation]
436+addSuffix s ks@(_:_) =
438+ in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
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
455+ , citationNoteNum = 0
457+ return $ addPrefix pre $ addSuffix suf $ map conv keys
459+citationLabel :: PandocMonad m => LP m Text
463+ (many1 (satisfyTok isWordTok <|> symbolIn bibtexKeyChar)
465+ <* optional (symbol ',')
467+ where bibtexKeyChar = ".:;?!`'()/*@_+=-&[]" :: [Char]
469+cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
470+cites mode multi = try $ 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
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)]
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
493+ _ -> map (\a -> a {citationMode = mode}) cs
494+ where mprenote (k:ks) = (k:ks) ++ [Space]
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
502+ in addPrefix mpnfinal (k:ks)
503+ addMprenote _ _ = []
504+ addMpostnote = addSuffix . mpostnote
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)
511+handleCitationPart :: Inlines -> [Citation]
512+handleCitationPart ils =
513+ let isCite Cite{} = True
515+ (pref, rest) = break isCite (toList ils)
517+ (Cite cs _:suff) -> addPrefix pref $ addSuffix suff cs
520+complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
521+complexNatbibCitation mode = try $ do
523+ withRaw $ concat <$> do
525+ items <- mconcat <$>
526+ many1 (notFollowedBy (symbol ';') >> inline)
529+ return $ map handleCitationPart items
532+ (c:cits) -> return $ cite (c{ citationMode = mode }:cits)
533+ (rawInline "latex" $ "\\citetext" <> untokenize raw)
535+inNote :: Inlines -> Inlines
537+ note $ para $ ils <> str "."
299inlineCommand' :: PandocMonad m => LP m Inlines
539inlineCommand' :: PandocMonad m => LP m Inlines
300inlineCommand' = try $ do
540inlineCommand' = try $ do
301 Tok _ (CtrlSeq name) cmd <- anyControlSeq
541 Tok _ (CtrlSeq name) cmd <- anyControlSeq
302 guard $ name /= "begin" && name /= "end" && name /= "and"
542 guard $ name /= "begin" && name /= "end" && name /= "and"
303− star <- if T.all isAlphaNum name
304− then option "" ("*" <$ symbol '*' <* sp)
543+ star <- option "" ("*" <$ symbol '*' <* sp)
306 overlay <- option "" overlaySpecification
544 overlay <- option "" overlaySpecification
307 let name' = name <> star <> overlay
545 let name' = name <> star <> overlay
308 let names = ordNub [name', name] -- check non-starred as fallback
546 let names = ordNub [name', name] -- check non-starred as fallback
@@ -313,8 +551,28 @@ inlineCommand' = try $ do
313 <|> ignore rawcommand
551 <|> ignore rawcommand
314 lookupListDefault raw names inlineCommands
552 lookupListDefault raw names inlineCommands
316tok :: PandocMonad m => LP m Inlines
555tok :: 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
561+opt :: PandocMonad m => LP m Inlines
563+ toks <- try (sp *> bracketedToks <* sp)
564+ -- now parse the toks as inlines
566+ parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
568+ Right result -> return result
569+ Left e -> throwError $ PandocParsecError (untokenize toks) e
571+paropt :: PandocMonad m => LP m Inlines
572+paropt = parenWrapped inline
574+inBrackets :: Inlines -> Inlines
575+inBrackets x = str "[" <> x <> str "]"
319unescapeURL :: Text -> Text
577unescapeURL :: Text -> Text
320unescapeURL = T.concat . go . T.splitOn "\\"
578unescapeURL = T.concat . go . T.splitOn "\\"
@@ -327,107 +585,397 @@ unescapeURL = T.concat . go . T.splitOn "\\"
327 , isEscapable c = t
585 , isEscapable c = t
328 | otherwise = "\\" <> t
586 | otherwise = "\\" <> t
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
593+ Just y -> "\\begin{" <> y <> "}\n" <> x <>
594+ "\\end{" <> y <> "}"
596+mathEnv :: PandocMonad m => Text -> LP m Text
600+ res <- manyTill anyTok (end_ name)
601+ return $ stripTrailingNewlines $ untokenize res
603+inlineEnvironment :: PandocMonad m => LP m Inlines
604+inlineEnvironment = try $ do
606+ name <- untokenize <$> braced
607+ M.findWithDefault mzero name inlineEnvironments
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*")
330inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
633inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
331−inlineCommands = M.unions
634+inlineCommands = M.union inlineLanguageCommands $ M.fromList
332− [ accentCommands tok
635+ [ ("emph", extractSpaces emph <$> tok)
333− , citationCommands inline
636+ , ("textit", extractSpaces emph <$> tok)
334− , siunitxCommands tok
637+ , ("textsl", extractSpaces emph <$> tok)
335− , acronymCommands
638+ , ("textsc", extractSpaces smallcaps <$> tok)
336− , refCommands
639+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
337− , nameCommands
640+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
338− , verbCommands
641+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
339− , charCommands
642+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
340− , enquoteCommands tok
643+ , ("texttt", ttfamily)
341− , inlineLanguageCommands tok
644+ , ("sout", extractSpaces strikeout <$> tok)
342− , biblatexInlineCommands tok
645+ , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
343− , rest ]
646+ , ("lq", return (str "‘"))
344− where
647+ , ("rq", return (str "’"))
345− rest = M.fromList
648+ , ("textquoteleft", return (str "‘"))
346− [ ("emph", extractSpaces emph <$> tok)
649+ , ("textquoteright", return (str "’"))
347− , ("textit", extractSpaces emph <$> tok)
650+ , ("textquotedblleft", return (str "“"))
348− , ("textsl", extractSpaces emph <$> tok)
651+ , ("textquotedblright", return (str "”"))
349− , ("textsc", extractSpaces smallcaps <$> tok)
652+ , ("textsuperscript", extractSpaces superscript <$> tok)
350− , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
653+ , ("textsubscript", extractSpaces subscript <$> tok)
351− , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
654+ , ("textbackslash", lit "\\")
352− , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
655+ , ("backslash", lit "\\")
353− , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
656+ , ("slash", lit "/")
354− , ("texttt", ttfamily)
657+ , ("textbf", extractSpaces strong <$> tok)
355− , ("sout", extractSpaces strikeout <$> tok)
658+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
356− , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
659+ , ("underline", underline <$> tok)
357− , ("textsuperscript", extractSpaces superscript <$> tok)
660+ , ("ldots", lit "…")
358− , ("textsubscript", extractSpaces subscript <$> tok)
661+ , ("vdots", lit "\8942")
359− , ("textbf", extractSpaces strong <$> tok)
662+ , ("dots", lit "…")
360− , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
663+ , ("mdots", lit "…")
361− , ("underline", underline <$> tok)
664+ , ("sim", lit "~")
362− , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
665+ , ("sep", lit ",")
363− , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
666+ , ("label", rawInlineOr "label" dolabel)
364− , ("lettrine", rawInlineOr "lettrine" lettrine)
667+ , ("ref", rawInlineOr "ref" $ doref "ref")
365− , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
668+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
366− , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
669+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
367− , ("ensuremath", mathInline . untokenize <$> braced)
670+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
368− , ("texorpdfstring", const <$> tok <*> tok)
671+ , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
369− -- old TeX commands
672+ , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
370− , ("em", extractSpaces emph <$> inlines)
673+ , ("lettrine", rawInlineOr "lettrine" lettrine)
371− , ("it", extractSpaces emph <$> inlines)
674+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
372− , ("sl", extractSpaces emph <$> inlines)
675+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
373− , ("bf", extractSpaces strong <$> inlines)
676+ , ("ensuremath", mathInline . untokenize <$> braced)
374− , ("tt", code . stringify . toList <$> inlines)
677+ , ("texorpdfstring", const <$> tok <*> tok)
375− , ("rm", inlines)
678+ , ("P", lit "¶")
376− , ("itshape", extractSpaces emph <$> inlines)
679+ , ("S", lit "§")
377− , ("slshape", extractSpaces emph <$> inlines)
680+ , ("$", lit "$")
378− , ("scshape", extractSpaces smallcaps <$> inlines)
681+ , ("%", lit "%")
379− , ("bfseries", extractSpaces strong <$> inlines)
682+ , ("&", lit "&")
380− , ("MakeUppercase", makeUppercase <$> tok)
683+ , ("#", lit "#")
381− , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
684+ , ("_", lit "_")
382− , ("uppercase", makeUppercase <$> tok)
685+ , ("{", lit "{")
383− , ("MakeLowercase", makeLowercase <$> tok)
686+ , ("}", lit "}")
384− , ("MakeTextLowercase", makeLowercase <$> tok)
687+ , ("qed", lit "\a0\x25FB")
385− , ("lowercase", makeLowercase <$> tok)
688+ -- old TeX commands
386− , ("thanks", skipopts >> note <$> grouped block)
689+ , ("em", extractSpaces emph <$> inlines)
387− , ("footnote", skipopts >> note <$> grouped block)
690+ , ("it", extractSpaces emph <$> inlines)
388− , ("passthrough", tok) -- \passthrough macro used by latex writer
691+ , ("sl", extractSpaces emph <$> inlines)
389− -- for listings
692+ , ("bf", extractSpaces strong <$> inlines)
390− , ("includegraphics", do options <- option [] keyvals
693+ , ("tt", code . stringify . toList <$> inlines)
391− src <- braced
694+ , ("rm", inlines)
392− mkImage options .
695+ , ("itshape", extractSpaces emph <$> inlines)
393− unescapeURL .
696+ , ("slshape", extractSpaces emph <$> inlines)
394− removeDoubleQuotes $ untokenize src)
697+ , ("scshape", extractSpaces smallcaps <$> inlines)
395− -- hyperref
698+ , ("bfseries", extractSpaces strong <$> inlines)
396− , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
699+ , ("MakeUppercase", makeUppercase <$> tok)
397− bracedUrl)
700+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
398− , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
701+ , ("uppercase", makeUppercase <$> tok)
399− , ("href", do url <- bracedUrl
702+ , ("MakeLowercase", makeLowercase <$> tok)
400− sp
703+ , ("MakeTextLowercase", makeLowercase <$> tok)
401− link (unescapeURL $ untokenize url) "" <$> tok)
704+ , ("lowercase", makeLowercase <$> tok)
402− , ("hyperlink", hyperlink)
705+ , ("/", pure mempty) -- italic correction
403− , ("hyperref", hyperref)
706+ , ("aa", lit "å")
404− , ("hypertarget", hypertargetInline)
707+ , ("AA", lit "Å")
405− -- hyphenat
708+ , ("ss", lit "ß")
406− , ("nohyphens", tok)
709+ , ("o", lit "ø")
407− , ("textnhtt", ttfamily)
710+ , ("O", lit "Ø")
408− , ("nhttfamily", ttfamily)
711+ , ("L", lit "Ł")
409− -- LaTeX colors
712+ , ("l", lit "ł")
410− , ("textcolor", coloredInline "color")
713+ , ("ae", lit "æ")
411− , ("colorbox", coloredInline "background-color")
714+ , ("AE", lit "Æ")
412− -- etoolbox
715+ , ("oe", lit "œ")
413− , ("ifstrequal", ifstrequal)
716+ , ("OE", lit "Œ")
414− , ("newtoggle", braced >>= newToggle)
717+ , ("pounds", lit "£")
415− , ("toggletrue", braced >>= setToggle True)
718+ , ("euro", lit "€")
416− , ("togglefalse", braced >>= setToggle False)
719+ , ("copyright", lit "©")
417− , ("iftoggle", try $ ifToggle >> inline)
720+ , ("textasciicircum", lit "^")
418− -- include
721+ , ("textasciitilde", lit "~")
419− , ("input", rawInlineOr "input" $ include "input")
722+ , ("H", accent '\779' Nothing) -- hungarumlaut
420− -- soul package
723+ , ("`", accent '\768' (Just '`')) -- grave
421− , ("ul", underline <$> tok)
724+ , ("'", accent '\769' (Just '\'')) -- acute
422− -- ulem package
725+ , ("^", accent '\770' (Just '^')) -- circ
423− , ("uline", underline <$> tok)
726+ , ("~", accent '\771' (Just '~')) -- tilde
424− -- plain tex stuff that should just be passed through as raw tex
727+ , ("\"", accent '\776' Nothing) -- umlaut
425− , ("ifdim", ifdim)
728+ , (".", accent '\775' Nothing) -- dot
426− ]
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
752+ , (",", lit "\8198")
753+ , ("@", pure mempty)
755+ , ("ps", pure $ str "PS." <> space)
756+ , ("TeX", lit "TeX")
757+ , ("LaTeX", lit "LaTeX")
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
766+ , ("lstinline", dolstinline)
767+ , ("mintinline", domintinline)
769+ , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
771+ , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
772+ , ("href", do url <- bracedUrl
774+ link (unescapeURL $ untokenize url) "" <$> tok)
775+ , ("includegraphics", do options <- option [] keyvals
777+ mkImage options . unescapeURL . removeDoubleQuotes $
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 >>=
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")
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")
900+ , ("si", skipopts *> dosi tok)
902+ , ("SIrange", doSIrange True tok)
903+ , ("numrange", doSIrange False tok)
904+ , ("numlist", doSInumlist)
908+ , ("bshyp", lit "\\\173")
909+ , ("fshyp", lit "/\173")
910+ , ("dothyp", lit ".\173")
911+ , ("colonhyp", lit ":\173")
913+ , ("nohyphens", tok)
914+ , ("textnhtt", ttfamily)
915+ , ("nhttfamily", ttfamily)
917+ , ("textcolor", coloredInline "color")
918+ , ("colorbox", coloredInline "background-color")
920+ , ("faCheck", lit "\10003")
921+ , ("faClose", lit "\10007")
923+ , ("xspace", doxspace)
925+ , ("ifstrequal", ifstrequal)
926+ , ("newtoggle", braced >>= newToggle)
927+ , ("toggletrue", braced >>= setToggle True)
928+ , ("togglefalse", braced >>= setToggle False)
929+ , ("iftoggle", try $ ifToggle >> inline)
931+ , ("RN", romanNumeralUpper)
932+ , ("Rn", romanNumeralLower)
934+ , ("foreignlanguage", foreignlanguage)
936+ , ("input", rawInlineOr "input" $ include "input")
938+ , ("ul", underline <$> tok)
940+ , ("uline", underline <$> tok)
941+ -- plain tex stuff that should just be passed through as raw tex
944+ , ("mkbibquote", spanWith nullAttr . doubleQuoted <$> tok)
945+ , ("mkbibemph", spanWith nullAttr . emph <$> tok)
946+ , ("mkbibitalic", spanWith nullAttr . emph <$> tok)
947+ , ("mkbibbold", spanWith nullAttr . strong <$> tok)
949+ spanWith nullAttr . (\x -> str "(" <> x <> str ")") <$> tok)
951+ spanWith nullAttr . (\x -> str "[" <> x <> str "]") <$> tok)
952+ , ("autocap", spanWith nullAttr <$> tok)
953+ , ("textnormal", spanWith ("",["nodecor"],[]) <$> tok)
955+ (\x -> spanWith ("",[],[("bibstring",x)]) (str x)) . untokenize
957+ , ("adddot", pure (str "."))
958+ , ("adddotspace", pure (spanWith nullAttr (str "." <> space)))
959+ , ("addabbrvspace", pure space)
960+ , ("hyphen", pure (str "-"))
963+accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines
964+accent combiningAccent fallBack = try $ do
967+ (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
968+ -- try to normalize to the combined character:
969+ Str (Normalize.normalize Normalize.NFC
970+ (T.pack [x, combiningAccent]) <> xs) : ys
971+ [Space] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
972+ [] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
428lettrine :: PandocMonad m => LP m Inlines
976lettrine :: PandocMonad m => LP m Inlines
429lettrine = do
977lettrine = do
430− optional rawopt
978+ optional opt
433 return $ extractSpaces (spanWith ("",["lettrine"],[])) x <> smallcaps y
981 return $ extractSpaces (spanWith ("",["lettrine"],[])) x <> smallcaps y
@@ -447,18 +995,32 @@ alterStr :: (Text -> Text) -> Inline -> Inline
447alterStr f (Str xs) = Str (f xs)
995alterStr f (Str xs) = Str (f xs)
448alterStr _ x = x
996alterStr _ x = x
998+foreignlanguage :: PandocMonad m => LP m Inlines
1000+ babelLang <- untokenize <$> braced
1001+ case babelLangToBCP47 babelLang of
1002+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
1005+inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
1006+inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
1008+ mk (polyglossia, bcp47Func) =
1009+ ("text" <> polyglossia, inlineLanguage bcp47Func)
1011+inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
1012+inlineLanguage bcp47Func = do
1013+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
1015+ let lang = renderLang $ bcp47Func o
1016+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
450hyperlink :: PandocMonad m => LP m Inlines
1018hyperlink :: PandocMonad m => LP m Inlines
451hyperlink = try $ do
1019hyperlink = try $ do
452 src <- untokenize <$> braced
1020 src <- untokenize <$> braced
453 lab <- tok
1021 lab <- tok
454 return $ link ("#" <> src) "" lab
1022 return $ link ("#" <> src) "" lab
456−hyperref :: PandocMonad m => LP m Inlines
458− url <- (("#" <>) . untokenize <$> try (sp *> bracketedToks <* sp))
459− <|> untokenize <$> (bracedUrl <* bracedUrl <* bracedUrl)
462hypertargetBlock :: PandocMonad m => LP m Blocks
1024hypertargetBlock :: PandocMonad m => LP m Blocks
463hypertargetBlock = try $ do
1025hypertargetBlock = try $ do
464 ref <- untokenize <$> braced
1026 ref <- untokenize <$> braced
@@ -473,6 +1035,31 @@ hypertargetInline = try $ do
473 ils <- grouped inline
1035 ils <- grouped inline
474 return $ spanWith (ref, [], []) ils
1036 return $ spanWith (ref, [], []) ils
1038+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
1040+ str . toRomanNumeral <$> romanNumeralArg
1042+romanNumeralLower :: (PandocMonad m) => LP m Inlines
1044+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
1046+romanNumeralArg :: (PandocMonad m) => LP m Int
1047+romanNumeralArg = spaces *> (parser <|> inBraces)
1057+ s <- untokenize <$> many1 (satisfyTok isWordTok)
1058+ let (digits, rest) = T.span isDigit s
1059+ unless (T.null rest) $
1060+ Prelude.fail "Non-digits in argument to \\Rn or \\RN"
476newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
1063newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
477newToggle name = do
1064newToggle name = do
478 updateState $ \st ->
1065 updateState $ \st ->
@@ -503,6 +1090,9 @@ ifToggle = do
503 report $ UndefinedToggle name' pos
1090 report $ UndefinedToggle name' pos
504 return ()
1091 return ()
1093+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
1094+doTerm term = str <$> translateTerm term
506ifstrequal :: (PandocMonad m, Monoid a) => LP m a
1096ifstrequal :: (PandocMonad m, Monoid a) => LP m a
507ifstrequal = do
1097ifstrequal = do
508 str1 <- tok
1098 str1 <- tok
@@ -523,6 +1113,13 @@ coloredInline stylename = do
523ttfamily :: PandocMonad m => LP m Inlines
1113ttfamily :: PandocMonad m => LP m Inlines
524ttfamily = code . stringify . toList <$> tok
1114ttfamily = code . stringify . toList <$> tok
1116+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
1117+rawInlineOr name' fallback = do
1118+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
1120+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
526processHBox :: Inlines -> Inlines
1123processHBox :: Inlines -> Inlines
527processHBox = walk convert
1124processHBox = walk convert
@@ -573,67 +1170,67 @@ treatAsInline = Set.fromList
573 , "pagebreak"
1170 , "pagebreak"
1173+label :: PandocMonad m => LP m ()
1177+ updateState $ \st -> st{ sLastLabel = Just $ untokenize t }
1179+dolabel :: PandocMonad m => LP m Inlines
1182+ let refstr = untokenize v
1183+ updateState $ \st ->
1184+ st{ sLastLabel = Just refstr }
1185+ return $ spanWith (refstr,[],[("label", refstr)])
1186+ $ inBrackets $ str $ untokenize v
1188+doref :: PandocMonad m => Text -> LP m Inlines
1191+ let refstr = untokenize v
1192+ return $ linkWith ("",[],[ ("reference-type", cls)
1193+ , ("reference", refstr)])
1196+ (inBrackets $ str refstr)
576lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
1198lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
577lookupListDefault d = (fromMaybe d .) . lookupList
1199lookupListDefault d = (fromMaybe d .) . lookupList
578 where lookupList l m = msum $ map (`M.lookup` m) l
1200 where lookupList l m = msum $ map (`M.lookup` m) l
580inline :: PandocMonad m => LP m Inlines
1202inline :: PandocMonad m => LP m Inlines
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
589− Comment -> mempty <$ comment
1203+inline = (mempty <$ comment)
590− Spaces -> space <$ whitespace
1204+ <|> (space <$ whitespace)
591− Newline -> softbreak <$ endline
1205+ <|> (softbreak <$ endline)
592− Word -> word
1206+ <|> word
593− Esc1 -> str . T.singleton <$> primEscape
1207+ <|> macroDef (rawInline "latex")
594− Esc2 -> str . T.singleton <$> primEscape
1208+ <|> inlineCommand'
595− Symbol ->
1209+ <|> inlineEnvironment
596− case t of
1210+ <|> inlineGroup
597− "-" -> symbol '-' *>
1211+ <|> (symbol '-' *>
598− option (str "-") (symbol '-' *>
1212+ option (str "-") (symbol '-' *>
599− option (str "–") (str "—" <$ symbol '-'))
1213+ option (str "–") (str "—" <$ symbol '-')))
600− "'" -> symbol '\'' *>
1216+ <|> (str "”" <$ try (symbol '\'' >> symbol '\''))
1217+ <|> (str "”" <$ symbol '”')
601− option (str "’") (str "”" <$ symbol '\'')
1218+ <|> (str "’" <$ symbol '\'')
1219+ <|> (str "’" <$ symbol '’')
602− "~" -> str "\160" <$ symbol '~'
1220+ <|> (str "\160" <$ symbol '~')
603− "`" -> doubleQuote <|> singleQuote <|> symbolAsString
604− "\"" -> doubleQuote <|> singleQuote <|> symbolAsString
605− "“" -> doubleQuote <|> symbolAsString
606− "‘" -> singleQuote <|> symbolAsString
607− "$" -> dollarsMath <|> unescapedSymbolAsString
1221+ <|> dollarsMath
608− "|" -> (guardEnabled Ext_literate_haskell *>
1222+ <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
609− symbol '|' *> doLHSverb) <|> symbolAsString
1223+ <|> (str . T.singleton <$> primEscape)
610− "{" -> inlineGroup
1224+ <|> regularSymbol
611− "#" -> unescapedSymbolAsString
1225+ <|> (do res <- symbolIn "#^'`\"[]&"
612− "&" -> unescapedSymbolAsString
1226+ pos <- getPosition
613− "_" -> unescapedSymbolAsString
1227+ let s = untoken res
614− "^" -> unescapedSymbolAsString
1228+ report $ ParsingUnescaped s pos
615− "\\" -> mzero
1229+ return $ str s)
618− CtrlSeq _ -> macroDef (rawInline "latex")
620− <|> inlineEnvironment
624inlines :: PandocMonad m => LP m Inlines
1231inlines :: PandocMonad m => LP m Inlines
625inlines = mconcat <$> many inline
1232inlines = mconcat <$> many inline
627−opt :: PandocMonad m => LP m Inlines
629− toks <- try (sp *> bracketedToks <* sp)
630− -- now parse the toks as inlines
632− parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
634− Right result -> return result
635− Left e -> throwError $ PandocParsecError (toSources toks) e
637-- block elements:
1234-- block elements:
639preamble :: PandocMonad m => LP m Blocks
1236preamble :: PandocMonad m => LP m Blocks
@@ -727,6 +1324,10 @@ insertIncluded defaultExtension f' = do
727 getInput >>= setInput . (tokenize f contents ++)
1324 getInput >>= setInput . (tokenize f contents ++)
728 updateState dropLatestIncludeFile
1325 updateState dropLatestIncludeFile
1327+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> LP m ()
1328+addMeta field val = updateState $ \st ->
1329+ st{ sMeta = addMetaField field val $ sMeta st }
730authors :: PandocMonad m => LP m ()
1331authors :: PandocMonad m => LP m ()
731authors = try $ do
1332authors = try $ do
@@ -735,6 +1336,150 @@ authors = try $ do
736 addMeta "author" (map trimInlines auths)
1337 addMeta "author" (map trimInlines auths)
1339+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
1340+macroDef constructor = do
1341+ (_, s) <- withRaw (commandDef <|> environmentDef)
1342+ (constructor (untokenize s) <$
1343+ guardDisabled Ext_latex_macros)
1345+ where commandDef = do
1346+ (name, macro') <- newcommand <|> letmacro <|> defmacro
1347+ guardDisabled Ext_latex_macros <|>
1348+ updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1349+ environmentDef = do
1350+ mbenv <- newenvironment
1352+ Nothing -> return ()
1353+ Just (name, macro1, macro2) ->
1354+ guardDisabled Ext_latex_macros <|>
1355+ do updateState $ \s -> s{ sMacros =
1356+ M.insert name macro1 (sMacros s) }
1357+ updateState $ \s -> s{ sMacros =
1358+ M.insert ("end" <> name) macro2 (sMacros s) }
1359+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1360+ -- is equivalent to
1361+ -- @\newcommand{\envname}[n-args][default]{begin}@
1362+ -- @\newcommand{\endenvname}@
1364+letmacro :: PandocMonad m => LP m (Text, Macro)
1367+ (name, contents) <- withVerbatimMode $ do
1368+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1369+ optional $ symbol '='
1371+ -- we first parse in verbatim mode, and then expand macros,
1372+ -- because we don't want \let\foo\bar to turn into
1373+ -- \let\foo hello if we have previously \def\bar{hello}
1374+ contents <- bracedOrToken
1375+ return (name, contents)
1376+ contents' <- doMacros' 0 contents
1377+ return (name, Macro ExpandWhenDefined [] Nothing contents')
1379+defmacro :: PandocMonad m => LP m (Text, Macro)
1381+ -- we use withVerbatimMode, because macros are to be expanded
1382+ -- at point of use, not point of definition
1383+ withVerbatimMode $ do
1385+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1386+ argspecs <- many (argspecArg <|> argspecPattern)
1387+ contents <- bracedOrToken
1388+ return (name, Macro ExpandWhenUsed argspecs Nothing contents)
1390+argspecArg :: PandocMonad m => LP m ArgSpec
1392+ Tok _ (Arg i) _ <- satisfyTok isArgTok
1395+argspecPattern :: PandocMonad m => LP m ArgSpec
1397+ Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) ->
1398+ (toktype' == Symbol || toktype' == Word) &&
1399+ (txt /= "{" && txt /= "\\" && txt /= "}")))
1401+newcommand :: PandocMonad m => LP m (Text, Macro)
1404+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1405+ controlSeq "renewcommand" <|>
1406+ controlSeq "providecommand" <|>
1407+ controlSeq "DeclareMathOperator" <|>
1408+ controlSeq "DeclareRobustCommand"
1409+ withVerbatimMode $ do
1410+ Tok _ (CtrlSeq name) txt <- do
1411+ optional (symbol '*')
1413+ (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
1415+ numargs <- option 0 $ try bracketedNum
1416+ let argspecs = map ArgNum [1..numargs]
1418+ optarg <- option Nothing $ Just <$> try bracketedToks
1420+ contents' <- bracedOrToken
1423+ "DeclareMathOperator" ->
1424+ Tok pos (CtrlSeq "mathop") "\\mathop"
1425+ : Tok pos Symbol "{"
1426+ : Tok pos (CtrlSeq "mathrm") "\\mathrm"
1427+ : Tok pos Symbol "{"
1429+ [ Tok pos Symbol "}", Tok pos Symbol "}" ])
1431+ macros <- sMacros <$> getState
1432+ case M.lookup name macros of
1434+ | mtype == "newcommand" -> do
1435+ report $ MacroAlreadyDefined txt pos
1436+ return (name, macro)
1437+ | mtype == "providecommand" -> return (name, macro)
1438+ _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
1440+newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
1443+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1444+ controlSeq "renewenvironment" <|>
1445+ controlSeq "provideenvironment"
1446+ withVerbatimMode $ do
1447+ optional $ symbol '*'
1449+ name <- untokenize <$> braced
1451+ numargs <- option 0 $ try bracketedNum
1453+ optarg <- option Nothing $ Just <$> try bracketedToks
1454+ let argspecs = map (\i -> ArgNum i) [1..numargs]
1455+ startcontents <- spaces >> bracedOrToken
1456+ endcontents <- spaces >> bracedOrToken
1457+ macros <- sMacros <$> getState
1458+ case M.lookup name macros of
1460+ | mtype == "newenvironment" -> do
1461+ report $ MacroAlreadyDefined name pos
1463+ | mtype == "provideenvironment" ->
1465+ _ -> return $ Just (name,
1466+ Macro ExpandWhenUsed argspecs optarg startcontents,
1467+ Macro ExpandWhenUsed [] Nothing endcontents)
1469+bracketedNum :: PandocMonad m => LP m Int
1471+ ds <- untokenize <$> bracketedToks
1472+ case safeRead ds of
1476+setCaption :: PandocMonad m => LP m ()
1477+setCaption = try $ do
1480+ optional $ try $ spaces *> label
1481+ updateState $ \st -> st{ sCaption = Just ils }
738looseItem :: PandocMonad m => LP m Blocks
1483looseItem :: PandocMonad m => LP m Blocks
739looseItem = do
1484looseItem = do
740 inListItem <- sInListItem <$> getState
1485 inListItem <- sInListItem <$> getState
@@ -748,6 +1493,10 @@ epigraph = do
748 p2 <- grouped block
1493 p2 <- grouped block
749 return $ divWith ("", ["epigraph"], []) (p1 <> p2)
1494 return $ divWith ("", ["epigraph"], []) (p1 <> p2)
1496+resetCaption :: PandocMonad m => LP m ()
1497+resetCaption = updateState $ \st -> st{ sCaption = Nothing
1498+ , sLastLabel = Nothing }
751section :: PandocMonad m => Attr -> Int -> LP m Blocks
1500section :: PandocMonad m => Attr -> Int -> LP m Blocks
752section (ident, classes, kvs) lvl = do
1501section (ident, classes, kvs) lvl = do
753 skipopts
1502 skipopts
@@ -840,7 +1589,7 @@ blockCommands = M.fromList
840 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
1589 , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
841 , ("signature", mempty <$ (skipopts *> authors))
1590 , ("signature", mempty <$ (skipopts *> authors))
842 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
1591 , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
843− , ("newtheorem", newtheorem inline)
1592+ , ("newtheorem", newtheorem)
844 , ("theoremstyle", theoremstyle)
1593 , ("theoremstyle", theoremstyle)
845 -- KOMA-Script metadata commands
1594 -- KOMA-Script metadata commands
846 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
1595 , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
@@ -888,7 +1637,7 @@ blockCommands = M.fromList
888 , ("item", looseItem)
1637 , ("item", looseItem)
889 , ("documentclass", skipopts *> braced *> preamble)
1638 , ("documentclass", skipopts *> braced *> preamble)
890 , ("centerline", para . trimInlines <$> (skipopts *> tok))
1639 , ("centerline", para . trimInlines <$> (skipopts *> tok))
891− , ("caption", mempty <$ setCaption inline)
1640+ , ("caption", mempty <$ setCaption)
892 , ("bibliography", mempty <$ (skipopts *> braced >>=
1641 , ("bibliography", mempty <$ (skipopts *> braced >>=
893 addMeta "bibliography" . splitBibs . untokenize))
1642 addMeta "bibliography" . splitBibs . untokenize))
894 , ("addbibresource", mempty <$ (skipopts *> braced >>=
1643 , ("addbibresource", mempty <$ (skipopts *> braced >>=
@@ -926,8 +1675,7 @@ blockCommands = M.fromList
928environments :: PandocMonad m => M.Map Text (LP m Blocks)
1677environments :: PandocMonad m => M.Map Text (LP m Blocks)
929−environments = M.union (tableEnvironments blocks inline) $
930− M.fromList
1678+environments = M.fromList
931 [ ("document", env "document" blocks <* skipMany anyTok)
1679 [ ("document", env "document" blocks <* skipMany anyTok)
932 , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
1680 , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
933 , ("sloppypar", env "sloppypar" blocks)
1681 , ("sloppypar", env "sloppypar" blocks)
@@ -937,6 +1685,13 @@ environments = M.union (tableEnvironments blocks inline) $
937 , ("figure", env "figure" $ skipopts *> figure)
1685 , ("figure", env "figure" $ skipopts *> figure)
938 , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
1686 , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
939 , ("center", divWith ("", ["center"], []) <$> env "center" blocks)
1687 , ("center", divWith ("", ["center"], []) <$> env "center" blocks)
1688+ , ("longtable", env "longtable" $
1689+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
1690+ , ("table", env "table" $
1691+ skipopts *> resetCaption *> blocks >>= addTableCaption)
1692+ , ("tabular*", env "tabular*" $ simpTable "tabular*" True)
1693+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1694+ , ("tabular", env "tabular" $ simpTable "tabular" False)
940 , ("quote", blockQuote <$> env "quote" blocks)
1695 , ("quote", blockQuote <$> env "quote" blocks)
941 , ("quotation", blockQuote <$> env "quotation" blocks)
1696 , ("quotation", blockQuote <$> env "quotation" blocks)
942 , ("verse", blockQuote <$> env "verse" blocks)
1697 , ("verse", blockQuote <$> env "verse" blocks)
@@ -959,7 +1714,7 @@ environments = M.union (tableEnvironments blocks inline) $
959 , ("lilypond", rawVerbEnv "lilypond")
1714 , ("lilypond", rawVerbEnv "lilypond")
960 , ("ly", rawVerbEnv "ly")
1715 , ("ly", rawVerbEnv "ly")
961 -- amsthm
1716 -- amsthm
962− , ("proof", proof blocks opt)
1717+ , ("proof", proof)
963 -- etoolbox
1718 -- etoolbox
964 , ("ifstrequal", ifstrequal)
1719 , ("ifstrequal", ifstrequal)
965 , ("newtoggle", braced >>= newToggle)
1720 , ("newtoggle", braced >>= newToggle)
@@ -980,17 +1735,131 @@ filecontents = try $ do
980 st{ sFileContents = M.insert fp txt (sFileContents st) }
1735 st{ sFileContents = M.insert fp txt (sFileContents st) }
981 return mempty
1736 return mempty
1738+theoremstyle :: PandocMonad m => LP m Blocks
1740+ stylename <- untokenize <$> braced
1741+ let mbstyle = case stylename of
1742+ "plain" -> Just PlainStyle
1743+ "definition" -> Just DefinitionStyle
1744+ "remark" -> Just RemarkStyle
1747+ Nothing -> return ()
1748+ Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
1751+newtheorem :: PandocMonad m => LP m Blocks
1753+ number <- option True (False <$ symbol '*' <* sp)
1754+ name <- untokenize <$> braced
1756+ series <- option Nothing $ Just . untokenize <$> bracketedToks
1760+ syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
1761+ sty <- sLastTheoremStyle <$> getState
1762+ let spec = TheoremSpec { theoremName = showName
1763+ , theoremStyle = sty
1764+ , theoremSeries = series
1765+ , theoremSyncTo = syncTo
1766+ , theoremNumber = number
1767+ , theoremLastNum = DottedNum [0] }
1768+ tmap <- sTheoremMap <$> getState
1769+ updateState $ \s -> s{ sTheoremMap =
1770+ M.insert name spec tmap }
1773+proof :: PandocMonad m => LP m Blocks
1775+ title <- option (B.text "Proof") opt
1776+ bs <- env "proof" blocks
1778+ B.divWith ("", ["proof"], []) $
1779+ addQed $ addTitle (B.emph (title <> ".")) bs
1781+addTitle :: Inlines -> Blocks -> Blocks
1783+ case B.toList bs of
1785+ -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
1786+ _ -> B.para ils <> bs
1788+addQed :: Blocks -> Blocks
1790+ case Seq.viewr (B.unMany bs) of
1792+ -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
1793+ _ -> bs <> B.para qedSign
1795+ qedSign = B.str "\xa0\x25FB"
983environment :: PandocMonad m => LP m Blocks
1797environment :: PandocMonad m => LP m Blocks
984environment = try $ do
1798environment = try $ do
985 controlSeq "begin"
1799 controlSeq "begin"
986 name <- untokenize <$> braced
1800 name <- untokenize <$> braced
987 M.findWithDefault mzero name environments <|>
1801 M.findWithDefault mzero name environments <|>
988− theoremEnvironment blocks opt name <|>
1802+ theoremEnvironment name <|>
989 if M.member name (inlineEnvironments
1803 if M.member name (inlineEnvironments
990 :: M.Map Text (LP PandocPure Inlines))
1804 :: M.Map Text (LP PandocPure Inlines))
991 then mzero
1805 then mzero
992 else try (rawEnv name) <|> rawVerbEnv name
1806 else try (rawEnv name) <|> rawVerbEnv name
1808+theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
1809+theoremEnvironment name = do
1810+ tmap <- sTheoremMap <$> getState
1811+ case M.lookup name tmap of
1814+ optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
1815+ mblabel <- option Nothing $ Just . untokenize <$>
1816+ try (spaces >> controlSeq "label" >> spaces >> braced)
1817+ bs <- env name blocks
1819+ if theoremNumber tspec
1821+ let name' = fromMaybe name $ theoremSeries tspec
1822+ num <- getNextNumber
1823+ (maybe (DottedNum [0]) theoremLastNum .
1824+ M.lookup name' . sTheoremMap)
1825+ updateState $ \s ->
1828+ (\spec -> spec{ theoremLastNum = num })
1835+ updateState $ \s ->
1836+ s{ sLabels = M.insert ident
1838+ theoremName tspec <> "\160" <>
1839+ str (renderDottedNum num)) (sLabels s) }
1840+ Nothing -> return ()
1841+ return $ space <> B.text (renderDottedNum num)
1843+ let titleEmph = case theoremStyle tspec of
1844+ PlainStyle -> B.strong
1845+ DefinitionStyle -> B.strong
1846+ RemarkStyle -> B.emph
1847+ let title = titleEmph (theoremName tspec <> number)
1848+ <> optTitle <> "." <> space
1849+ return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
1850+ $ case theoremStyle tspec of
1851+ PlainStyle -> walk italicize bs
1854+italicize :: Block -> Block
1855+italicize x@(Para [Image{}]) = x -- see #6925
1856+italicize (Para ils) = Para [Emph ils]
1857+italicize (Plain ils) = Plain [Emph ils]
1860+env :: PandocMonad m => Text -> LP m a -> LP m a
1861+env name p = p <* end_ name
994rawEnv :: PandocMonad m => Text -> LP m Blocks
1863rawEnv :: PandocMonad m => Text -> LP m Blocks
995rawEnv name = do
1864rawEnv name = do
996 exts <- getOption readerExtensions
1865 exts <- getOption readerExtensions
@@ -998,6 +1867,7 @@ rawEnv name = do
998 rawOptions <- mconcat <$> many rawopt
1867 rawOptions <- mconcat <$> many rawopt
999 let beginCommand = "\\begin{" <> name <> "}" <> rawOptions
1868 let beginCommand = "\\begin{" <> name <> "}" <> rawOptions
1000 pos1 <- getPosition
1869 pos1 <- getPosition
1870+ (bs, raw) <- withRaw $ env name blocks
1001 if parseRaw
1871 if parseRaw
1003 (_, raw) <- withRaw $ env name blocks
1873 (_, raw) <- withRaw $ env name blocks
@@ -1162,8 +2032,7 @@ inputListing = do
1162 let (ident,classes,kvs) = parseListingsOptions options
2032 let (ident,classes,kvs) = parseListingsOptions options
1163 let classes' =
2033 let classes' =
1164 (case listingsLanguage options of
2034 (case listingsLanguage options of
1165− Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1166− (T.pack $ takeExtension $ T.unpack f)) <>)
2035+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
1167 Just _ -> id) classes
2036 Just _ -> id) classes
1168 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
2037 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1169 let lastline = fromMaybe (length codeLines) $
2038 let lastline = fromMaybe (length codeLines) $
@@ -1229,23 +2098,356 @@ orderedList' = try $ do
1229 bs <- listenv "enumerate" (many item)
2098 bs <- listenv "enumerate" (many item)
1230 return $ orderedListWith (start, style, delim) bs
2099 return $ orderedListWith (start, style, delim) bs
2103+hline :: PandocMonad m => LP m ()
2106+ controlSeq "hline" <|>
2108+ controlSeq "toprule" <|>
2109+ controlSeq "bottomrule" <|>
2110+ controlSeq "midrule" <|>
2111+ controlSeq "endhead" <|>
2112+ controlSeq "endfirsthead"
2117+lbreak :: PandocMonad m => LP m Tok
2118+lbreak = (controlSeq "\\" <|> controlSeq "tabularnewline")
2119+ <* skipopts <* spaces
2121+amp :: PandocMonad m => LP m Tok
2124+-- Split a Word into individual Symbols (for parseAligns)
2125+splitWordTok :: PandocMonad m => LP m ()
2129+ (Tok spos Word t : rest) ->
2130+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) <> rest
2133+parseAligns :: PandocMonad m => LP m [(Alignment, ColWidth, ([Tok], [Tok]))]
2134+parseAligns = try $ do
2135+ let maybeBar = skipMany
2136+ (try $ sp *> (() <$ symbol '|' <|> () <$ (symbol '@' >> braced)))
2137+ let cAlign = AlignCenter <$ symbol 'c'
2138+ let lAlign = AlignLeft <$ symbol 'l'
2139+ let rAlign = AlignRight <$ symbol 'r'
2140+ let parAlign = AlignLeft <$ symbol 'p'
2141+ -- aligns from tabularx
2142+ let xAlign = AlignLeft <$ symbol 'X'
2143+ let mAlign = AlignLeft <$ symbol 'm'
2144+ let bAlign = AlignLeft <$ symbol 'b'
2145+ let alignChar = splitWordTok *> ( cAlign <|> lAlign <|> rAlign <|> parAlign
2146+ <|> xAlign <|> mAlign <|> bAlign )
2147+ let alignPrefix = symbol '>' >> braced
2148+ let alignSuffix = symbol '<' >> braced
2149+ let colWidth = try $ do
2151+ ds <- trim . untokenize <$> manyTill anyTok (controlSeq "linewidth")
2154+ return $ safeRead ds
2156+ pref <- option [] alignPrefix
2159+ width <- colWidth <|> option Nothing (do s <- untokenize <$> braced
2161+ report $ SkippedContent s pos
2164+ suff <- option [] alignSuffix
2165+ return (al, width, (pref, suff))
2166+ let starAlign = do -- '*{2}{r}' == 'rr', we just expand like a macro
2169+ ds <- trim . untokenize <$> braced
2172+ case safeRead ds of
2174+ getInput >>= setInput . (mconcat (replicate n spec) ++)
2175+ Nothing -> Prelude.fail $ "Could not parse " <> T.unpack ds <> " as number"
2179+ aligns' <- many $ try $ spaces >> optional starAlign >>
2180+ (alignSpec <* maybeBar)
2184+ return $ map toSpec aligns'
2186+ toColWidth (Just w) | w > 0 = ColWidth w
2187+ toColWidth _ = ColWidthDefault
2188+ toSpec (x, y, z) = (x, toColWidth y, z)
2190+-- N.B. this parser returns a Row that may have erroneous empty cells
2191+-- in it. See the note above fixTableHead for details.
2192+parseTableRow :: PandocMonad m
2193+ => Text -- ^ table environment name
2194+ -> [([Tok], [Tok])] -- ^ pref/suffixes
2196+parseTableRow envname prefsufs = do
2197+ notFollowedBy (spaces *> end_ envname)
2198+ -- add prefixes and suffixes in token stream:
2199+ let celltoks (pref, suff) = do
2200+ prefpos <- getPosition
2201+ contents <- mconcat <$>
2202+ many ( snd <$> withRaw (controlSeq "parbox" >> parbox) -- #5711
2204+ snd <$> withRaw (inlineEnvironment <|> dollarsMath)
2207+ (() <$ amp <|> () <$ lbreak <|> end_ envname)
2210+ suffpos <- getPosition
2211+ option [] (count 1 amp)
2212+ return $ map (setpos prefpos) pref ++ contents ++ map (setpos suffpos) suff
2213+ rawcells <- mapM celltoks prefsufs
2214+ cells <- mapM (parseFromToks parseTableCell) rawcells
2216+ return $ Row nullAttr cells
2218+parseTableCell :: PandocMonad m => LP m Cell
2221+ updateState $ \st -> st{ sInTableCell = True }
2222+ cell' <- multicolumnCell
2224+ <|> parseSimpleCell
2226+ updateState $ \st -> st{ sInTableCell = False }
2230+ -- The parsing of empty cells is important in LaTeX, especially when dealing
2231+ -- with multirow/multicolumn. See #6603.
2232+ parseEmptyCell = spaces $> emptyCell
2234+cellAlignment :: PandocMonad m => LP m Alignment
2235+cellAlignment = skipMany (symbol '|') *> alignment <* skipMany (symbol '|')
2238+ c <- untoken <$> singleChar
2243+ "*" -> AlignDefault
2246+plainify :: Blocks -> Blocks
2247+plainify bs = case toList bs of
2248+ [Para ils] -> plain (fromList ils)
2251+multirowCell :: PandocMonad m => LP m Cell
2252+multirowCell = controlSeq "multirow" >> do
2253+ -- Full prototype for \multirow macro is:
2254+ -- \multirow[vpos]{nrows}[bigstruts]{width}[vmove]{text}
2255+ -- However, everything except `nrows` and `text` make
2256+ -- sense in the context of the Pandoc AST
2257+ _ <- optional $ symbol '[' *> cellAlignment <* symbol ']' -- vertical position
2258+ nrows <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2259+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- bigstrut-related
2260+ _ <- symbol '{' *> manyTill anyTok (symbol '}') -- Cell width
2261+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- Length used for fine-tuning
2262+ content <- symbol '{' *> (plainify <$> blocks) <* symbol '}'
2263+ return $ cell AlignDefault (RowSpan nrows) (ColSpan 1) content
2265+multicolumnCell :: PandocMonad m => LP m Cell
2266+multicolumnCell = controlSeq "multicolumn" >> do
2267+ span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2268+ alignment <- symbol '{' *> cellAlignment <* symbol '}'
2270+ let singleCell = do
2271+ content <- plainify <$> blocks
2272+ return $ cell alignment (RowSpan 1) (ColSpan span') content
2274+ -- Two possible contents: either a \multirow cell, or content.
2275+ -- E.g. \multicol{1}{c}{\multirow{2}{1em}{content}}
2276+ -- Note that a \multirow cell can be nested in a \multicolumn,
2277+ -- but not the other way around. See #6603
2278+ let nestedCell = do
2279+ (Cell _ _ (RowSpan rs) _ bs) <- multirowCell
2286+ symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
2288+-- Parse a simple cell, i.e. not multirow/multicol
2289+parseSimpleCell :: PandocMonad m => LP m Cell
2290+parseSimpleCell = simpleCell <$> (plainify <$> blocks)
2292+-- LaTeX tables are stored with empty cells underneath multirow cells
2293+-- denoting the grid spaces taken up by them. More specifically, if a
2294+-- cell spans m rows, then it will overwrite all the cells in the
2295+-- columns it spans for (m-1) rows underneath it, requiring padding
2296+-- cells in these places. These padding cells need to be removed for
2297+-- proper table reading. See #6603.
2299+-- These fixTable functions do not otherwise fix up malformed
2300+-- input tables: that is left to the table builder.
2301+fixTableHead :: TableHead -> TableHead
2302+fixTableHead (TableHead attr rows) = TableHead attr rows'
2304+ rows' = fixTableRows rows
2306+fixTableBody :: TableBody -> TableBody
2307+fixTableBody (TableBody attr rhc th tb)
2308+ = TableBody attr rhc th' tb'
2310+ th' = fixTableRows th
2311+ tb' = fixTableRows tb
2313+fixTableRows :: [Row] -> [Row]
2314+fixTableRows = fixTableRows' $ repeat Nothing
2316+ fixTableRows' oldHang (Row attr cells : rs)
2317+ = let (newHang, cells') = fixTableRow oldHang cells
2318+ rs' = fixTableRows' newHang rs
2319+ in Row attr cells' : rs'
2320+ fixTableRows' _ [] = []
2322+-- The overhang is represented as Just (relative cell dimensions) or
2323+-- Nothing for an empty grid space.
2324+fixTableRow :: [Maybe (ColSpan, RowSpan)] -> [Cell] -> ([Maybe (ColSpan, RowSpan)], [Cell])
2325+fixTableRow oldHang cells
2326+ -- If there's overhang, drop cells until their total width meets the
2327+ -- width of the occupied grid spaces (or we run out)
2328+ | (n, prefHang, restHang) <- splitHang oldHang
2330+ = let cells' = dropToWidth getCellW n cells
2331+ (restHang', cells'') = fixTableRow restHang cells'
2332+ in (prefHang restHang', cells'')
2333+ -- Otherwise record the overhang of a pending cell and fix the rest
2335+ | c@(Cell _ _ h w _):cells' <- cells
2338+ oldHang' = dropToWidth getHangW w' oldHang
2339+ (newHang, cells'') = fixTableRow oldHang' cells'
2340+ in (toHang w' h' <> newHang, c : cells'')
2344+ getCellW (Cell _ _ _ w _) = w
2345+ getHangW = maybe 1 fst
2346+ getCS (ColSpan n) = n
2349+ | r > 1 = [Just (c, r)]
2350+ | otherwise = replicate (getCS c) Nothing
2352+ -- Take the prefix of the overhang list representing filled grid
2353+ -- spaces. Also return the remainder and the length of this prefix.
2354+ splitHang = splitHang' 0 id
2356+ splitHang' !n l (Just (c, r):xs)
2357+ = splitHang' (n + c) (l . (toHang c (r-1) ++)) xs
2358+ splitHang' n l xs = (n, l, xs)
2360+ -- Drop list items until the total width of the dropped items
2361+ -- exceeds the passed width.
2362+ dropToWidth _ n l | n < 1 = l
2363+ dropToWidth wproj n (c:cs) = dropToWidth wproj (n - wproj c) cs
2364+ dropToWidth _ _ [] = []
2366+simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
2367+simpTable envname hasWidthParameter = try $ do
2368+ when hasWidthParameter $ () <$ (spaces >> tok)
2370+ colspecs <- parseAligns
2371+ let (aligns, widths, prefsufs) = unzip3 colspecs
2372+ optional $ controlSeq "caption" *> setCaption
2380+ header' <- option [] . try . fmap (:[]) $
2381+ parseTableRow envname prefsufs <* lbreak <* many1 hline
2383+ rows <- sepEndBy (parseTableRow envname prefsufs)
2384+ (lbreak <* optional (skipMany hline))
2386+ optional $ controlSeq "caption" *> setCaption
2392+ lookAhead $ controlSeq "end" -- make sure we're at end
2393+ let th = fixTableHead $ TableHead nullAttr header'
2394+ let tbs = [fixTableBody $ TableBody nullAttr 0 [] rows]
2395+ let tf = TableFoot nullAttr []
2396+ return $ table emptyCaption (zip aligns widths) th tbs tf
2398+addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
2399+addTableCaption = walkM go
2400+ where go (Table attr c spec th tb tf) = do
2402+ let mblabel = sLastLabel st
2403+ capt <- case (sCaption st, mblabel) of
2404+ (Just ils, Nothing) -> return $ caption Nothing (plain ils)
2405+ (Just ils, Just lab) -> do
2406+ num <- getNextNumber sLastTableNum
2408+ st{ sLastTableNum = num
2409+ , sLabels = M.insert lab
2410+ [Str (renderDottedNum num)]
2412+ return $ caption Nothing (plain ils) -- add number??
2413+ (Nothing, _) -> return c
2414+ let attr' = case (attr, mblabel) of
2415+ ((_,classes,kvs), Just ident) ->
2416+ (ident,classes,kvs)
2418+ return $ addAttrDiv attr' $ Table nullAttr capt spec th tb tf
2421+-- TODO: For now we add a Div to contain table attributes, since
2422+-- most writers don't do anything yet with attributes on Table.
2423+-- This can be removed when that changes.
2424+addAttrDiv :: Attr -> Block -> Block
2425+addAttrDiv ("",[],[]) b = b
2426+addAttrDiv attr b = Div attr [b]
1232block :: PandocMonad m => LP m Blocks
2428block :: PandocMonad m => LP m Blocks
1233block = do
2429block = do
1234− Tok _ toktype _ <- lookAhead anyTok
1235− res <- (case toktype of
1236− Newline -> mempty <$ spaces1
2430+ res <- (mempty <$ spaces1)
1237− Spaces -> mempty <$ spaces1
1238− Comment -> mempty <$ spaces1
1240− CtrlSeq "begin" -> environment
2431+ <|> environment
1241− CtrlSeq _ -> macroDef (rawBlock "latex")
2432+ <|> macroDef (rawBlock "latex")
1242− <|> blockCommand
2433+ <|> blockCommand
1244− <|> paragraph
2434+ <|> paragraph
1245− <|> grouped block
2435+ <|> grouped block
1246 trace (T.take 60 $ tshow $ B.toList res)
2436 trace (T.take 60 $ tshow $ B.toList res)
1247 return res
2437 return res
1249blocks :: PandocMonad m => LP m Blocks
2439blocks :: PandocMonad m => LP m Blocks
1250blocks = mconcat <$> many block
2440blocks = mconcat <$> many block
2442+setDefaultLanguage :: PandocMonad m => LP m Blocks
2443+setDefaultLanguage = do
2444+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
2446+ polylang <- untokenize <$> braced
2447+ case M.lookup polylang polyglossiaLangToBCP47 of
2448+ Nothing -> return mempty -- TODO mzero? warning?
2449+ Just langFunc -> do
2452+ updateState $ setMeta "lang" $ str (renderLang l)