@@ -1,4 +1,5 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE PatternGuards #-}
23{-# LANGUAGE FlexibleInstances #-}
34{-# LANGUAGE MultiParamTypeClasses #-}
45{-# LANGUAGE ScopedTypeVariables #-}
@@ -30,6 +31,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3031 Portability : portable
3132
3233Conversion of LaTeX to 'Pandoc' document.
34+
35+TODO:
36+[ ] exported rawLaTeXInline, rawLaTeXBlock, inlineCommand
3337-}
3438module Text.Pandoc.Readers.LaTeX ( readLaTeX,
3539 rawLaTeXInline,
@@ -42,7 +46,7 @@ import Control.Monad
4246import Control.Monad.Except (throwError)
4347import Data.Char (chr, isAlphaNum, isLetter, ord, isDigit)
4448import Data.Default
45−import Data.Text (Text, unpack)
49+import Data.Text (Text)
4650import qualified Data.Text as T
4751import Data.List (intercalate, isPrefixOf)
4852import qualified Data.Map as M
@@ -59,11 +63,11 @@ import Text.Pandoc.ImageSize (numUnit, showFl)
5963import Text.Pandoc.Logging
6064import Text.Pandoc.Options
6165import Text.Pandoc.Parsing hiding (many, optional, withRaw,
62− mathInline, mathDisplay,
66+ mathInline, mathDisplay, macro,
6367 space, (<|>), spaces, blankline)
6468import Text.Pandoc.Shared
6569import Text.Pandoc.Walk
66−import Text.Pandoc.Error (PandocError(PandocParsecError))
70+import Text.Pandoc.Error (PandocError(PandocParsecError, PandocMacroLoop))
6771
6872import Text.Pandoc.Extensions (getDefaultExtensions)
6973import Debug.Trace (traceShowId)
@@ -103,32 +107,44 @@ testParser :: LP PandocIO a -> Text -> IO a
103107testParser p t = do
104108 res <- runIOorExplode (runParserT p defaultLaTeXState{
105109 sOptions = def{ readerExtensions =
106− getDefaultExtensions "latex" }} "name" (tokenize t))
110+ enableExtension Ext_raw_tex $
111+ getDefaultExtensions "latex" }} "source" (tokenize t))
107112 case res of
108113 Left e -> error (show e)
109114 Right r -> return r
110115
111−data Macro = CommandMacro Text ([Tok] -> [Tok])
112− | EnvironmentMacro Text ([Tok] -> [Tok])
116+data Macro = Macro Int (Maybe [Tok]) [Tok]
117+ deriving Show
113118
114119data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
115120 , sMeta :: Meta
116121 , sQuoteContext :: QuoteContext
117− , sMacros :: [Macro]
122+ , sMacros :: M.Map Text Macro
118123 , sContainers :: [String]
119124 , sHeaders :: M.Map Inlines String
120125 , sLogMessages :: [LogMessage]
121− , sIdentifiers :: Set.Set String }
126+ , sIdentifiers :: Set.Set String
127+ , sVerbatimMode :: Bool
128+ , sCaption :: Maybe Inlines
129+ , sInListItem :: Bool
130+ , sInTableCell :: Bool
131+ }
132+ deriving Show
122133
123134defaultLaTeXState :: LaTeXState
124135defaultLaTeXState = LaTeXState{ sOptions = def
125136 , sMeta = nullMeta
126137 , sQuoteContext = NoQuote
127− , sMacros = []
138+ , sMacros = M.empty
128139 , sContainers = []
129140 , sHeaders = M.empty
130141 , sLogMessages = []
131− , sIdentifiers = Set.empty }
142+ , sIdentifiers = Set.empty
143+ , sVerbatimMode = False
144+ , sCaption = Nothing
145+ , sInListItem = False
146+ , sInTableCell = False
147+ }
132148
133149instance PandocMonad m => HasQuoteContext LaTeXState m where
134150 getQuoteContext = sQuoteContext <$> getState
@@ -172,17 +188,48 @@ instance Default LaTeXState where
172188
173189type LP m = ParserT [Tok] LaTeXState m
174190
175−rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState m String
191+withVerbatimMode :: PandocMonad m => LP m a -> LP m a
192+withVerbatimMode parser = do
193+ updateState $ \st -> st{ sVerbatimMode = True }
194+ result <- parser
195+ updateState $ \st -> st{ sVerbatimMode = False }
196+ return result
197+
198+-- TODO: export our local macro parsing code
199+-- use that in markdown reader and change ParserState
200+-- TODO: remove use of texmath's applyMacros in Markdown reader
201+-- (and elsewhere?). Instead, use an exported
202+-- applyMacros that uses our Macro type. or perhaps
203+-- just run the latex reader on the math (adding delims
204+-- $$).
205+
206+-- TODO: replace ParserState with variable and constraints.
207+-- can we use 'tokens' from Parsec?
208+-- feed ParserState -> LaTeXState and then back again
209+rawLaTeXBlock :: PandocMonad m => ParserT String ParserState m String
176210rawLaTeXBlock = mzero
211+-- rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState String
212+-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
177213
178−rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState m Inline
214+rawLaTeXInline :: PandocMonad m => ParserT String ParserState m Inline
179215rawLaTeXInline = mzero
216+-- rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState Inline
217+-- rawLaTeXInline = do
218+-- raw <- (snd <$> withRaw inlineCommand)
219+-- <|> (snd <$> withRaw inlineEnvironment)
220+-- <|> (snd <$> withRaw blockCommand)
221+-- RawInline "latex" <$> applyMacros' raw
180222
181−inlineCommand :: PandocMonad m => ParserT String LaTeXState m Inlines
223+-- TODO this is only used in org reader.
224+-- I think the reason is that tarleb wanted to avoid
225+-- the blockCommand alternative in rawLaTeXInline.
226+-- I don't know whyt that's there and I think it should be
227+-- removed.
228+inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
182229inlineCommand = mzero
183230
184−data TokType = CtrlSeq | Spaces | Newline | Symbol | Word | Comment |
185− Esc1 | Esc2
231+data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
232+ Esc1 | Esc2 | Arg Int
186233 deriving (Eq, Ord, Show)
187234
188235data Tok = Tok (Line, Column) TokType Text
@@ -197,7 +244,7 @@ totoks (lin,col) t =
197244 Nothing -> []
198245 Just (c, rest)
199246 | c == '\n' ->
200− Tok (lin, col) Newline (T.singleton '\n')
247+ Tok (lin, col) Newline "\n"
201248 : totoks (lin + 1,1) rest
202249 | isSpaceOrTab c ->
203250 let (sps, rest') = T.span isSpaceOrTab t
@@ -209,7 +256,7 @@ totoks (lin,col) t =
209256 : totoks (lin, col + T.length ws) rest'
210257 | c == '%' ->
211258 let (cs, rest') = T.break (== '\n') rest
212− in Tok (lin, col) Comment (T.singleton '%' <> cs)
259+ in Tok (lin, col) Comment ("%" <> cs)
213260 : totoks (lin, col + 1 + T.length cs) rest'
214261 | c == '\\' ->
215262 case T.uncons rest of
@@ -217,14 +264,25 @@ totoks (lin,col) t =
217264 Just (d, rest')
218265 | isLetter d ->
219266 let (ws, rest'') = T.span isLetter rest
220− in Tok (lin, col) CtrlSeq (T.singleton '\\' <> ws)
221− : totoks (lin, col + 1 + T.length ws) rest''
267+ (ss, rest''') = T.span isSpaceOrTab rest''
268+ in Tok (lin, col) (CtrlSeq ws) ("\\" <> ws <> ss)
269+ : totoks (lin,
270+ col + 1 + T.length ws + T.length ss) rest'''
222271 | d == '\t' || d == '\n' ->
223− Tok (lin, col) Symbol (T.singleton '\\')
272+ Tok (lin, col) Symbol ("\\")
224273 : totoks (lin, col + 1) rest
225274 | otherwise ->
226− Tok (lin, col) CtrlSeq (T.pack [c,d])
275+ Tok (lin, col) (CtrlSeq (T.singleton d)) (T.pack [c,d])
227276 : totoks (lin, col + 2) rest'
277+ | c == '#' ->
278+ let (t1, t2) = T.span (\d -> d >= '0' && d <= '9') rest
279+ in case safeRead (T.unpack t1) of
280+ Just i ->
281+ Tok (lin, col) (Arg i) ("#" <> t1)
282+ : totoks (lin, col + 1 + T.length t1) t2
283+ Nothing ->
284+ Tok (lin, col) Symbol ("#")
285+ : totoks (lin, col + 1) t2
228286 | c == '^' ->
229287 case T.uncons rest of
230288 Just ('^', rest') ->
@@ -241,9 +299,9 @@ totoks (lin,col) t =
241299 | d < '\128' ->
242300 Tok (lin, col) Esc1 (T.pack ['^','^',d])
243301 : totoks (lin, col + 3) rest''
244− _ -> [Tok (lin, col) Symbol (T.singleton '^'),
245− Tok (lin, col + 1) Symbol (T.singleton '^')]
246− _ -> Tok (lin, col) Symbol (T.singleton '^')
302+ _ -> [Tok (lin, col) Symbol ("^"),
303+ Tok (lin, col + 1) Symbol ("^")]
304+ _ -> Tok (lin, col) Symbol ("^")
247305 : totoks (lin, col + 1) rest
248306 | otherwise ->
249307 Tok (lin, col) Symbol (T.singleton c) : totoks (lin, col + 1) rest
@@ -261,10 +319,12 @@ untokenize = mconcat . map untoken
261319untoken :: Tok -> Text
262320untoken (Tok _ _ t) = t
263321
264−-- we put withMacros in front of satisfyTok, so it works on everything
265322satisfyTok :: PandocMonad m => (Tok -> Bool) -> LP m Tok
266323satisfyTok f =
267− doMacros *> tokenPrim (T.unpack . untoken) updatePos matcher
324+ try $ do
325+ res <- tokenPrim (T.unpack . untoken) updatePos matcher
326+ doMacros 0 -- apply macros on remaining input stream
327+ return res
268328 where matcher t | f t = Just t
269329 | otherwise = Nothing
270330 updatePos :: SourcePos -> Tok -> [Tok] -> SourcePos
@@ -272,26 +332,51 @@ satisfyTok f =
272332 setSourceColumn (setSourceLine spos lin) col
273333 updatePos spos _ [] = spos
274334
275−-- TODO use something other than LaTeXState
276−doMacros :: PandocMonad m => LP m ()
277−doMacros = do
278− inp <- getInput
279− macros <- sMacros <$> getState
280− case inp of
281− t@(Tok spos CtrlSeq txt) : ts
282− | txt == "\\macro" -> do -- TODO actually check macros
283− setInput $ map (setpos spos) (tokenize "Hi there") ++ ts
284− -- TODO loop detection
285− doMacros
286− _ -> return ()
335+doMacros :: PandocMonad m => Int -> LP m ()
336+doMacros n = do
337+ applyMacros <- readerApplyMacros . sOptions <$> getState
338+ verbatimMode <- sVerbatimMode <$> getState
339+ when (applyMacros && not verbatimMode) $ do
340+ inp <- getInput
341+ case inp of
342+ Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" :
343+ Tok _ Word name : Tok _ Symbol "}" : ts
344+ -> handleMacros spos name ts
345+ Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" :
346+ Tok _ Word name : Tok _ Symbol "}" : ts
347+ -> handleMacros spos ("end" <> name) ts
348+ Tok spos (CtrlSeq name) _ : ts
349+ -> handleMacros spos name ts
350+ _ -> return ()
351+ where handleMacros spos name ts = do
352+ macros <- sMacros <$> getState
353+ case M.lookup name macros of
354+ Nothing -> return ()
355+ Just (Macro numargs optarg newtoks) -> do
356+ setInput ts
357+ let getarg = spaces >> braced
358+ args <- case optarg of
359+ Nothing -> count numargs getarg
360+ Just o ->
361+ (:) <$> option o bracketedToks
362+ <*> count (numargs - 1) getarg
363+ let addTok (Tok _ (Arg i) _) acc | i > 0
364+ , i <= numargs =
365+ map (setpos spos) (args !! (i - 1)) ++ acc
366+ addTok t acc = setpos spos t : acc
367+ ts' <- getInput
368+ setInput $ foldr addTok ts' newtoks
369+ if n > 20 -- detect macro expansion loops
370+ then throwError $ PandocMacroLoop (T.unpack name)
371+ else doMacros (n + 1)
287372
288373setpos :: (Line, Column) -> Tok -> Tok
289374setpos spos (Tok _ tt txt) = Tok spos tt txt
290375
291376anyControlSeq :: PandocMonad m => LP m Tok
292−anyControlSeq = satisfyTok isCtrlSeq <* optional sp
293− where isCtrlSeq (Tok _ CtrlSeq _) = True
294− isCtrlSeq _ = False
377+anyControlSeq = satisfyTok isCtrlSeq
378+ where isCtrlSeq (Tok _ (CtrlSeq _) _) = True
379+ isCtrlSeq _ = False
295380
296381anySymbol :: PandocMonad m => LP m Tok
297382anySymbol = satisfyTok isSym
@@ -309,7 +394,7 @@ tokTypeIn toktypes (Tok _ tt _) = tt `elem` toktypes
309394
310395controlSeq :: PandocMonad m => Text -> LP m Tok
311396controlSeq name = satisfyTok isNamed
312− where isNamed (Tok _ CtrlSeq n) = n == T.singleton '\\' <> name
397+ where isNamed (Tok _ (CtrlSeq n) _) = n == name
313398 isNamed _ = False
314399
315400symbol :: PandocMonad m => Char -> LP m Tok
@@ -356,15 +441,13 @@ endline = try $ do
356441 notFollowedBy blankline
357442
358443blankline :: PandocMonad m => LP m ()
359−blankline = try $ do
360− skipMany (satisfyTok (tokTypeIn [Spaces, Newline]))
361− newlineTok
444+blankline = try $ skipMany whitespace *> newlineTok
362445
363446primEscape :: PandocMonad m => LP m Char
364447primEscape = do
365448 Tok _ toktype t <- satisfyTok (tokTypeIn [Esc1, Esc2])
366449 case toktype of
367− Esc1 -> case T.uncons t of
450+ Esc1 -> case T.uncons (T.drop 2 t) of
368451 Just (c, _)
369452 | c >= '\64' && c <= '\127' -> return (chr (ord c - 64))
370453 | otherwise -> return (chr (ord c + 64))
@@ -374,14 +457,13 @@ primEscape = do
374457 Nothing -> fail $ "Could not read: " ++ T.unpack t
375458 _ -> fail "Expected an Esc1 or Esc2 token" -- should not happen
376459
377−bgroup :: PandocMonad m => LP m ()
460+bgroup :: PandocMonad m => LP m Tok
378461bgroup = try $ do
379462 skipMany sp
380463 symbol '{' <|> controlSeq "bgroup" <|> controlSeq "begingroup"
381− return ()
382464
383−egroup :: PandocMonad m => LP m ()
384−egroup = () <$ (symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup")
465+egroup :: PandocMonad m => LP m Tok
466+egroup = (symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup")
385467
386468grouped :: (PandocMonad m, Monoid a) => LP m a -> LP m a
387469grouped parser = try $ do
@@ -391,10 +473,20 @@ grouped parser = try $ do
391473 try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup)
392474
393475braced :: PandocMonad m => LP m [Tok]
394−braced = try $ do
395− bgroup
396− -- {{a,b}} should be parsed the same as {a,b}
397− try (braced <* egroup) <|> manyTill anyTok egroup
476+braced = bgroup *> braced' 1
477+ where braced' (n :: Int) =
478+ handleEgroup n <|> handleBgroup n <|> handleOther n
479+ handleEgroup n = do
480+ t <- egroup
481+ if n == 1
482+ then return []
483+ else (t:) <$> braced' (n - 1)
484+ handleBgroup n = do
485+ t <- bgroup
486+ (t:) <$> braced' (n + 1)
487+ handleOther n = do
488+ t <- anyTok
489+ (t:) <$> braced' n
398490
399491bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
400492bracketed parser = try $ do
@@ -414,8 +506,17 @@ dimenarg = try $ do
414506
415507-- inline elements:
416508
417−inlineText :: PandocMonad m => LP m Inlines
418−inlineText = (str . T.unpack . untoken) <$> satisfyTok isWordTok
509+word :: PandocMonad m => LP m Inlines
510+word = (str . T.unpack . untoken) <$> satisfyTok isWordTok
511+
512+regularSymbol :: PandocMonad m => LP m Inlines
513+regularSymbol = (str . T.unpack . untoken) <$> satisfyTok isRegularSymbol
514+ where isRegularSymbol (Tok _ Symbol t) = not $ T.any isSpecial t
515+ isRegularSymbol _ = False
516+ isSpecial c = c `Set.member` specialChars
517+
518+specialChars :: Set.Set Char
519+specialChars = Set.fromList "#$%&~_^\\{}"
419520
420521isWordTok :: Tok -> Bool
421522isWordTok (Tok _ Word _) = True
@@ -435,9 +536,44 @@ doLHSverb =
435536 (codeWith ("",["haskell"],[]) . T.unpack . untokenize)
436537 <$> manyTill (satisfyTok (not . isNewlineTok)) (symbol '|')
437538
539+mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
540+mkImage options src = do
541+ let replaceTextwidth (k,v) =
542+ case numUnit v of
543+ Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
544+ _ -> (k, v)
545+ let kvs = map replaceTextwidth
546+ $ filter (\(k,_) -> k `elem` ["width", "height"]) options
547+ let attr = ("",[], kvs)
548+ let alt = str "image"
549+ case takeExtension src of
550+ "" -> do
551+ defaultExt <- getOption readerDefaultImageExtension
552+ return $ imageWith attr (addExtension src defaultExt) "" alt
553+ _ -> return $ imageWith attr src "" alt
554+
555+-- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
556+dosiunitx :: PandocMonad m => LP m Inlines
557+dosiunitx = do
558+ skipopts
559+ value <- tok
560+ valueprefix <- option "" $ bracketed tok
561+ unit <- tok
562+ let emptyOr160 "" = ""
563+ emptyOr160 _ = "\160"
564+ return . mconcat $ [valueprefix,
565+ emptyOr160 valueprefix,
566+ value,
567+ emptyOr160 unit,
568+ unit]
569+
438570lit :: String -> LP m Inlines
439571lit = pure . str
440572
573+removeDoubleQuotes :: Text -> Text
574+removeDoubleQuotes t =
575+ maybe t id $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
576+
441577doubleQuote :: PandocMonad m => LP m Inlines
442578doubleQuote = do
443579 quoted' doubleQuoted (try $ count 2 $ symbol '`')
@@ -496,7 +632,9 @@ doverb = do
496632 marker <- case T.uncons t of
497633 Just (c, ts) | T.null ts -> return c
498634 _ -> mzero
499− (code . T.unpack . untokenize) <$> manyTill (verbTok marker) (symbol marker)
635+ withVerbatimMode $
636+ (code . T.unpack . untokenize) <$>
637+ manyTill (verbTok marker) (symbol marker)
500638
501639verbTok :: PandocMonad m => Char -> LP m Tok
502640verbTok stopchar = do
@@ -519,8 +657,9 @@ dolstinline = do
519657 Just (c, ts) | T.null ts -> return c
520658 _ -> mzero
521659 let stopchar = if marker == '{' then '}' else marker
522− (codeWith ("",classes,[]) . T.unpack . untokenize) <$>
523− manyTill (verbTok stopchar) (symbol stopchar)
660+ withVerbatimMode $
661+ (codeWith ("",classes,[]) . T.unpack . untokenize) <$>
662+ manyTill (verbTok stopchar) (symbol stopchar)
524663
525664keyval :: PandocMonad m => LP m (String, String)
526665keyval = try $ do
@@ -749,52 +888,129 @@ toksToString = T.unpack . untokenize
749888
750889mathDisplay :: String -> Inlines
751890mathDisplay = displayMath . trim
752−-- TODO we shouldn't need applyMacros
753−-- mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
754891
755892mathInline :: String -> Inlines
756893mathInline = math . trim
757−-- TODO we shouldn't need applyMacros
758−-- mathInline p = math <$> (try p >>= applyMacros')
759894
760895dollarsMath :: PandocMonad m => LP m Inlines
761896dollarsMath = do
762897 symbol '$'
763898 display <- option False (True <$ symbol '$')
764− contents <- many1Till anyTok (symbol '$')
765− when display (() <$ symbol '$')
766− let constructor = if display then mathDisplay else mathInline
767− return $ constructor $ toksToString contents
899+ contents <- trim . toksToString <$>
900+ many (notFollowedBy (symbol '$') >> anyTok)
901+ if display
902+ then do
903+ mathDisplay contents <$ try (symbol '$' >> symbol '$')
904+ <|> (guard (null contents) >> return (mathInline ""))
905+ else mathInline contents <$ (symbol '$')
906+
907+-- citations
908+
909+addPrefix :: [Inline] -> [Citation] -> [Citation]
910+addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
911+addPrefix _ _ = []
912+
913+addSuffix :: [Inline] -> [Citation] -> [Citation]
914+addSuffix s ks@(_:_) =
915+ let k = last ks
916+ in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
917+addSuffix _ _ = []
918+
919+simpleCiteArgs :: PandocMonad m => LP m [Citation]
920+simpleCiteArgs = try $ do
921+ first <- optionMaybe $ toList <$> opt
922+ second <- optionMaybe $ toList <$> opt
923+ keys <- try $ bgroup *> (manyTill citationLabel egroup)
924+ let (pre, suf) = case (first , second ) of
925+ (Just s , Nothing) -> (mempty, s )
926+ (Just s , Just t ) -> (s , t )
927+ _ -> (mempty, mempty)
928+ conv k = Citation { citationId = k
929+ , citationPrefix = []
930+ , citationSuffix = []
931+ , citationMode = NormalCitation
932+ , citationHash = 0
933+ , citationNoteNum = 0
934+ }
935+ return $ addPrefix pre $ addSuffix suf $ map conv keys
936+
937+citationLabel :: PandocMonad m => LP m String
938+citationLabel = do
939+ optional sp
940+ toksToString <$>
941+ (many1 (satisfyTok isWordTok <|> symbolIn bibtexKeyChar)
942+ <* optional sp
943+ <* optional (symbol ',')
944+ <* optional sp)
945+ where bibtexKeyChar = ".:;?!`'()/*@_+=-[]" :: [Char]
946+
947+cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
948+cites mode multi = try $ do
949+ cits <- if multi
950+ then many1 simpleCiteArgs
951+ else count 1 simpleCiteArgs
952+ let cs = concat cits
953+ return $ case mode of
954+ AuthorInText -> case cs of
955+ (c:rest) -> c {citationMode = mode} : rest
956+ [] -> []
957+ _ -> map (\a -> a {citationMode = mode}) cs
958+
959+citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
960+citation name mode multi = do
961+ (c,raw) <- withRaw $ cites mode multi
962+ return $ cite c (rawInline "latex" $ "\\" ++ name ++ (toksToString raw))
963+
964+handleCitationPart :: Inlines -> [Citation]
965+handleCitationPart ils =
966+ let isCite Cite{} = True
967+ isCite _ = False
968+ (pref, rest) = break isCite (toList ils)
969+ in case rest of
970+ (Cite cs _:suff) -> addPrefix pref $ addSuffix suff cs
971+ _ -> []
972+
973+complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
974+complexNatbibCitation mode = try $ do
975+ (cs, raw) <-
976+ withRaw $ concat <$> do
977+ bgroup
978+ items <- mconcat <$>
979+ many1 (notFollowedBy (symbol ';') >> inline)
980+ `sepBy1` (symbol ';')
981+ egroup
982+ return $ map handleCitationPart items
983+ case cs of
984+ [] -> mzero
985+ (c:cits) -> return $ cite (c{ citationMode = mode }:cits)
986+ (rawInline "latex" $ "\\citetext" ++ toksToString raw)
987+
988+inNote :: Inlines -> Inlines
989+inNote ils =
990+ note $ para $ ils <> str "."
768991
769992inlineCommand' :: PandocMonad m => LP m Inlines
770993inlineCommand' = try $ do
771− cs@(Tok _ CtrlSeq t) <- anyControlSeq
772− let name = T.drop 1 t
994+ Tok _ (CtrlSeq name) cmd <- anyControlSeq
773995 guard $ name /= "begin" && name /= "end"
774− mbstar <- option Nothing (Just <$> symbol '*')
775− let names = name : maybe [] (const [name <> "*"]) mbstar
776− optional $ try $ symbol '{' >> symbol '}'
996+ (star, rawstar) <- withRaw $ option "" ("*" <$ symbol '*' <* optional sp)
997+ let name' = name <> star
998+ let names = ordNub [name', name] -- check non-starred as fallback
777999 let raw = do
7781000 guard $ not (isBlockCommand name)
7791001 (_, rawargs) <- withRaw
7801002 (skipangles *> skipopts *> option "" dimenarg *> many braced)
781− let rawcommand = T.unpack $ untokenize $
782− cs : maybe [] (:[]) mbstar ++ rawargs
1003+ let rawcommand = T.unpack $ cmd <> untokenize (rawstar ++ rawargs)
7831004 (guardEnabled Ext_raw_tex >> return (rawInline "latex" rawcommand))
7841005 <|> ignore rawcommand
785− -- transformed <- applyMacros' rawcommand -- TODO or get rid of
786− -- exts <- getOption readerExtensions
787− -- if transformed /= rawcommand
788− -- then parseFromString' inlines transformed
789− -- else if extensionEnabled Ext_raw_tex exts
790− -- then return $ rawInline "latex" rawcommand
791− -- else ignore rawcommand
7921006 lookupListDefault raw names inlineCommands
7931007
7941008tok :: PandocMonad m => LP m Inlines
795−tok = try $ grouped inline <|> inlineCommand' <|> singleChar
796− where singleChar = do
1009+tok = grouped inline <|> inlineCommand' <|> singleChar
1010+ where singleChar = try $ do
7971011 Tok (lin,col) toktype t <- satisfyTok (tokTypeIn [Word, Symbol])
1012+ guard $ not $ toktype == Symbol &&
1013+ T.any (`Set.member` specialChars) t
7981014 if T.length t > 1
7991015 then do
8001016 let (t1, t2) = (T.take 1 t, T.drop 1 t)
@@ -816,14 +1032,6 @@ rawopt = do
8161032skipopts :: PandocMonad m => LP m ()
8171033skipopts = skipMany rawopt
8181034
819−-- eat an optional argument and one or more arguments in braces
820−ignoreInlines :: PandocMonad m => Text -> (Text, LP m Inlines)
821−ignoreInlines name = (name, p)
822− where p = do oa <- optargs
823− let rawCommand = '\\' : T.unpack (name <> oa)
824− let doraw = guardRaw >> return (rawInline "latex" rawCommand)
825− doraw <|> ignore rawCommand
826−
8271035guardRaw :: PandocMonad m => LP m ()
8281036guardRaw = getOption readerExtensions >>= guard . extensionEnabled Ext_raw_tex
8291037
@@ -865,20 +1073,18 @@ unescapeURL (x:xs) = x:unescapeURL xs
8651073unescapeURL [] = ""
8661074
8671075mathEnvWith :: PandocMonad m
868− => (Inlines -> a) -> Maybe String -> String -> LP m a
1076+ => (Inlines -> a) -> Maybe Text -> Text -> LP m a
8691077mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
8701078 where inner x = case innerEnv of
871− Nothing -> x
872− Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
873− "\\end{" ++ y ++ "}"
1079+ Nothing -> x
1080+ Just y -> "\\begin{" ++ T.unpack y ++ "}\n" ++ x ++
1081+ "\\end{" ++ T.unpack y ++ "}"
8741082
875−mathEnv :: PandocMonad m => String -> LP m String
1083+mathEnv :: PandocMonad m => Text -> LP m String
8761084mathEnv name = do
8771085 skipopts
8781086 optional blankline
879− let endEnv = try $ controlSeq "end" *>
880− (T.unpack . untokenize <$> braced) >>= guard . (== name)
881− res <- manyTill anyTok endEnv
1087+ res <- manyTill anyTok (end_ name)
8821088 return $ stripTrailingNewlines $ T.unpack $ untokenize res
8831089
8841090inlineEnvironment :: PandocMonad m => LP m Inlines
@@ -986,7 +1192,10 @@ inlineCommands = M.fromList $
9861192 , ("v", option (str "v") $ try $ tok >>= accent hacek)
9871193 , ("u", option (str "u") $ try $ tok >>= accent breve)
9881194 , ("i", lit "i")
989− , ("\\", linebreak <$ (optional (bracketed inline) *> spaces))
1195+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
1196+ guard $ not inTableCell
1197+ optional (bracketed inline)
1198+ spaces))
9901199 , (",", lit "\8198")
9911200 , ("@", pure mempty)
9921201 , (" ", lit "\160")
@@ -1003,71 +1212,72 @@ inlineCommands = M.fromList $
10031212 , ("Verb", doverb)
10041213 , ("url", ((unescapeURL . T.unpack . untokenize) <$> braced) >>= \url ->
10051214 pure (link url "" (str url)))
1006−-- , ("href", (unescapeURL <$> braced <* optional sp) >>= \url ->
1007−-- tok >>= \lab ->
1008−-- pure (link url "" lab))
1009−-- , ("includegraphics", do options <- option [] keyvals
1010−-- src <- unescapeURL . removeDoubleQuotes <$> braced
1011−-- mkImage options src)
1215+ , ("href", (unescapeURL . toksToString <$>
1216+ braced <* optional sp) >>= \url ->
1217+ tok >>= \lab -> pure (link url "" lab))
1218+ , ("includegraphics", do options <- option [] keyvals
1219+ src <- unescapeURL . T.unpack .
1220+ removeDoubleQuotes . untokenize <$> braced
1221+ mkImage options src)
10121222 , ("enquote", enquote)
1013−-- , ("cite", citation "cite" NormalCitation False)
1014−-- , ("Cite", citation "Cite" NormalCitation False)
1015−-- , ("citep", citation "citep" NormalCitation False)
1016−-- , ("citep*", citation "citep*" NormalCitation False)
1017−-- , ("citeal", citation "citeal" NormalCitation False)
1018−-- , ("citealp", citation "citealp" NormalCitation False)
1019−-- , ("citealp*", citation "citealp*" NormalCitation False)
1020−-- , ("autocite", citation "autocite" NormalCitation False)
1021−-- , ("smartcite", citation "smartcite" NormalCitation False)
1022−-- , ("footcite", inNote <$> citation "footcite" NormalCitation False)
1023−-- , ("parencite", citation "parencite" NormalCitation False)
1024−-- , ("supercite", citation "supercite" NormalCitation False)
1025−-- , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
1026−-- , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
1027−-- , ("citeyear", citation "citeyear" SuppressAuthor False)
1028−-- , ("autocite*", citation "autocite*" SuppressAuthor False)
1029−-- , ("cite*", citation "cite*" SuppressAuthor False)
1030−-- , ("parencite*", citation "parencite*" SuppressAuthor False)
1031−-- , ("textcite", citation "textcite" AuthorInText False)
1032−-- , ("citet", citation "citet" AuthorInText False)
1033−-- , ("citet*", citation "citet*" AuthorInText False)
1034−-- , ("citealt", citation "citealt" AuthorInText False)
1035−-- , ("citealt*", citation "citealt*" AuthorInText False)
1036−-- , ("textcites", citation "textcites" AuthorInText True)
1037−-- , ("cites", citation "cites" NormalCitation True)
1038−-- , ("autocites", citation "autocites" NormalCitation True)
1039−-- , ("footcites", inNote <$> citation "footcites" NormalCitation True)
1040−-- , ("parencites", citation "parencites" NormalCitation True)
1041−-- , ("supercites", citation "supercites" NormalCitation True)
1042−-- , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
1043−-- , ("Autocite", citation "Autocite" NormalCitation False)
1044−-- , ("Smartcite", citation "Smartcite" NormalCitation False)
1045−-- , ("Footcite", citation "Footcite" NormalCitation False)
1046−-- , ("Parencite", citation "Parencite" NormalCitation False)
1047−-- , ("Supercite", citation "Supercite" NormalCitation False)
1048−-- , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
1049−-- , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
1050−-- , ("Citeyear", citation "Citeyear" SuppressAuthor False)
1051−-- , ("Autocite*", citation "Autocite*" SuppressAuthor False)
1052−-- , ("Cite*", citation "Cite*" SuppressAuthor False)
1053−-- , ("Parencite*", citation "Parencite*" SuppressAuthor False)
1054−-- , ("Textcite", citation "Textcite" AuthorInText False)
1055−-- , ("Textcites", citation "Textcites" AuthorInText True)
1056−-- , ("Cites", citation "Cites" NormalCitation True)
1057−-- , ("Autocites", citation "Autocites" NormalCitation True)
1058−-- , ("Footcites", citation "Footcites" NormalCitation True)
1059−-- , ("Parencites", citation "Parencites" NormalCitation True)
1060−-- , ("Supercites", citation "Supercites" NormalCitation True)
1061−-- , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
1062−-- , ("citetext", complexNatbibCitation NormalCitation)
1063−-- , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
1064−-- complexNatbibCitation AuthorInText)
1065−-- <|> citation "citeauthor" AuthorInText False)
1066−-- , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
1067−-- addMeta "nocite"))
1223+ , ("cite", citation "cite" NormalCitation False)
1224+ , ("Cite", citation "Cite" NormalCitation False)
1225+ , ("citep", citation "citep" NormalCitation False)
1226+ , ("citep*", citation "citep*" NormalCitation False)
1227+ , ("citeal", citation "citeal" NormalCitation False)
1228+ , ("citealp", citation "citealp" NormalCitation False)
1229+ , ("citealp*", citation "citealp*" NormalCitation False)
1230+ , ("autocite", citation "autocite" NormalCitation False)
1231+ , ("smartcite", citation "smartcite" NormalCitation False)
1232+ , ("footcite", inNote <$> citation "footcite" NormalCitation False)
1233+ , ("parencite", citation "parencite" NormalCitation False)
1234+ , ("supercite", citation "supercite" NormalCitation False)
1235+ , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
1236+ , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
1237+ , ("citeyear", citation "citeyear" SuppressAuthor False)
1238+ , ("autocite*", citation "autocite*" SuppressAuthor False)
1239+ , ("cite*", citation "cite*" SuppressAuthor False)
1240+ , ("parencite*", citation "parencite*" SuppressAuthor False)
1241+ , ("textcite", citation "textcite" AuthorInText False)
1242+ , ("citet", citation "citet" AuthorInText False)
1243+ , ("citet*", citation "citet*" AuthorInText False)
1244+ , ("citealt", citation "citealt" AuthorInText False)
1245+ , ("citealt*", citation "citealt*" AuthorInText False)
1246+ , ("textcites", citation "textcites" AuthorInText True)
1247+ , ("cites", citation "cites" NormalCitation True)
1248+ , ("autocites", citation "autocites" NormalCitation True)
1249+ , ("footcites", inNote <$> citation "footcites" NormalCitation True)
1250+ , ("parencites", citation "parencites" NormalCitation True)
1251+ , ("supercites", citation "supercites" NormalCitation True)
1252+ , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
1253+ , ("Autocite", citation "Autocite" NormalCitation False)
1254+ , ("Smartcite", citation "Smartcite" NormalCitation False)
1255+ , ("Footcite", citation "Footcite" NormalCitation False)
1256+ , ("Parencite", citation "Parencite" NormalCitation False)
1257+ , ("Supercite", citation "Supercite" NormalCitation False)
1258+ , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
1259+ , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
1260+ , ("Citeyear", citation "Citeyear" SuppressAuthor False)
1261+ , ("Autocite*", citation "Autocite*" SuppressAuthor False)
1262+ , ("Cite*", citation "Cite*" SuppressAuthor False)
1263+ , ("Parencite*", citation "Parencite*" SuppressAuthor False)
1264+ , ("Textcite", citation "Textcite" AuthorInText False)
1265+ , ("Textcites", citation "Textcites" AuthorInText True)
1266+ , ("Cites", citation "Cites" NormalCitation True)
1267+ , ("Autocites", citation "Autocites" NormalCitation True)
1268+ , ("Footcites", citation "Footcites" NormalCitation True)
1269+ , ("Parencites", citation "Parencites" NormalCitation True)
1270+ , ("Supercites", citation "Supercites" NormalCitation True)
1271+ , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
1272+ , ("citetext", complexNatbibCitation NormalCitation)
1273+ , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
1274+ complexNatbibCitation AuthorInText)
1275+ <|> citation "citeauthor" AuthorInText False)
1276+ , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
1277+ addMeta "nocite"))
10681278 , ("hypertarget", braced >> tok)
10691279-- -- siuntix
1070−-- , ("SI", dosiunitx)
1280+ , ("SI", dosiunitx)
10711281 -- hyphenat
10721282 , ("bshyp", lit "\\\173")
10731283 , ("fshyp", lit "/\173")
@@ -1080,16 +1290,18 @@ inlineCommands = M.fromList $
10801290 -- fontawesome
10811291 , ("faCheck", lit "\10003")
10821292 , ("faClose", lit "\10007")
1083− ] ++ map ignoreInlines
1293+ ]
1294+
10841295 -- these commands will be ignored unless --parse-raw is specified,
10851296 -- in which case they will appear as raw latex blocks:
1086− [ "index"
1087− , "hspace"
1088− , "vspace"
1089− , "newpage"
1090− , "clearpage"
1091− , "pagebreak"
1092− ]
1297+ -- [ "index"
1298+ -- , "hspace"
1299+ -- , "vspace"
1300+ -- , "newpage"
1301+ -- , "clearpage"
1302+ -- , "pagebreak"
1303+ -- , "noindent"
1304+ -- ]
10931305
10941306ttfamily :: PandocMonad m => LP m Inlines
10951307ttfamily = (code . stringify . toList) <$> tok
@@ -1102,27 +1314,42 @@ rawInlineOr name' fallback = do
11021314 else fallback
11031315
11041316getRawCommand :: PandocMonad m => Text -> LP m String
1105−getRawCommand name' = do
1317+getRawCommand txt = do
11061318 (_, rawargs) <- withRaw
11071319 (many (try (optional sp *> opt)) *>
11081320 option "" (try (optional sp *> dimenarg)) *>
11091321 many braced)
1110− return $ '\\' : T.unpack (name' <> untokenize rawargs)
1322+ return $ T.unpack (txt <> untokenize rawargs)
11111323
11121324isBlockCommand :: Text -> Bool
11131325isBlockCommand s =
11141326 s `M.member` (blockCommands :: M.Map Text (LP PandocPure Blocks))
11151327
1116−lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
1328+isInlineCommand :: Text -> Bool
1329+isInlineCommand s =
1330+ s `M.member` (inlineCommands :: M.Map Text (LP PandocPure Inlines))
1331+ || s `Set.member` treatAsRawInline
1332+
1333+treatAsRawInline :: Set.Set Text
1334+treatAsRawInline = Set.fromList
1335+ [ "index"
1336+ , "hspace"
1337+ , "vspace"
1338+ , "newpage"
1339+ , "clearpage"
1340+ , "pagebreak"
1341+ , "noindent"
1342+ ]
1343+
1344+lookupListDefault :: (Show k, Ord k) => v -> [k] -> M.Map k v -> v
11171345lookupListDefault d = (fromMaybe d .) . lookupList
1118− where
1119− lookupList l m = msum $ map (`M.lookup` m) l
1346+ where lookupList l m = msum $ map (`M.lookup` m) l
11201347
11211348inline :: PandocMonad m => LP m Inlines
11221349inline = (mempty <$ comment)
11231350 <|> (space <$ whitespace)
11241351 <|> (softbreak <$ endline)
1125− <|> inlineText
1352+ <|> word
11261353 <|> inlineCommand'
11271354 <|> inlineEnvironment
11281355 <|> inlineGroup
@@ -1139,7 +1366,8 @@ inline = (mempty <$ comment)
11391366 <|> dollarsMath
11401367 <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
11411368 <|> (str . (:[]) <$> primEscape)
1142− <|> (do res <- symbolIn "#&~^'`\"[]"
1369+ <|> regularSymbol
1370+ <|> (do res <- symbolIn "#^'`\"[]"
11431371 pos <- getPosition
11441372 let s = T.unpack (untoken res)
11451373 report $ ParsingUnescaped s pos
@@ -1150,6 +1378,37 @@ inlines = mconcat <$> many inline
11501378
11511379-- block elements:
11521380
1381+begin_ :: PandocMonad m => Text -> LP m ()
1382+begin_ t = (try $ do
1383+ controlSeq "begin"
1384+ spaces
1385+ symbol '{'
1386+ spaces
1387+ Tok _ Word txt <- satisfyTok isWordTok
1388+ spaces
1389+ symbol '}'
1390+ guard (t == txt)) <?> ("\\begin{" ++ T.unpack t ++ "}")
1391+
1392+end_ :: PandocMonad m => Text -> LP m ()
1393+end_ t = (try $ do
1394+ controlSeq "end"
1395+ spaces
1396+ symbol '{'
1397+ spaces
1398+ Tok _ Word txt <- satisfyTok isWordTok
1399+ spaces
1400+ symbol '}'
1401+ guard $ t == txt) <?> ("\\end{" ++ T.unpack t ++ "}")
1402+
1403+preamble :: PandocMonad m => LP m Blocks
1404+preamble = mempty <$ many preambleBlock
1405+ where preambleBlock = spaces1
1406+ <|> void include
1407+ <|> void macroDef
1408+ <|> void blockCommand
1409+ <|> void braced
1410+ <|> (notFollowedBy (begin_ "document") >> void anyTok)
1411+
11531412paragraph :: PandocMonad m => LP m Blocks
11541413paragraph = do
11551414 x <- trimInlines . mconcat <$> many1 inline
@@ -1159,11 +1418,12 @@ paragraph = do
11591418
11601419include :: PandocMonad m => LP m Blocks
11611420include = do
1162− (Tok _ _ name) <- controlSeq "include" <|> controlSeq "input" <|>
1421+ (Tok _ (CtrlSeq name) _) <-
1422+ controlSeq "include" <|> controlSeq "input" <|>
11631423 controlSeq "subfile" <|> controlSeq "usepackage"
11641424 skipMany $ bracketed inline -- skip options
11651425 fs <- (map trim . splitBy (==',') . T.unpack . untokenize) <$> braced
1166− let fs' = if name == "\\usepackage"
1426+ let fs' = if name == "usepackage"
11671427 then map (maybeAddExtension ".sty") fs
11681428 else map (maybeAddExtension ".tex") fs
11691429 dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
@@ -1179,7 +1439,7 @@ ignoreBlocks :: PandocMonad m => Text -> (Text, LP m Blocks)
11791439ignoreBlocks name = (name, p)
11801440 where
11811441 p = do oa <- optargs
1182− let rawCommand = '\\' : T.unpack (name <> oa)
1442+ let rawCommand = T.unpack ("\\" <> name <> oa)
11831443 let doraw = guardRaw >> return (rawBlock "latex" rawCommand)
11841444 doraw <|> ignore rawCommand
11851445
@@ -1198,6 +1458,109 @@ authors = try $ do
11981458 egroup
11991459 addMeta "author" (map trimInlines auths)
12001460
1461+macroDef :: PandocMonad m => LP m Blocks
1462+macroDef = mempty <$ ((commandDef <|> environmentDef) <* doMacros 0)
1463+ where commandDef = do
1464+ (name, macro) <- newcommand
1465+ updateState $ \s -> s{ sMacros = M.insert name macro (sMacros s) }
1466+ environmentDef = do
1467+ (name, macro1, macro2) <- newenvironment
1468+ updateState $ \s -> s{ sMacros =
1469+ M.insert name macro1 (sMacros s) }
1470+ updateState $ \s -> s{ sMacros =
1471+ M.insert ("end" <> name) macro2 (sMacros s) }
1472+ -- @\newenvironment{envname}[n-args][default]{begin}{end}@
1473+ -- is equivalent to
1474+ -- @\newcommand{\envname}[n-args][default]{begin}@
1475+ -- @\newcommand{\endenvname}@
1476+
1477+newcommand :: PandocMonad m => LP m (Text, Macro)
1478+newcommand = do
1479+ pos <- getPosition
1480+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
1481+ controlSeq "renewcommand" <|>
1482+ controlSeq "providecommand"
1483+ optional $ symbol '*'
1484+ symbol '{'
1485+ spaces
1486+ Tok _ (CtrlSeq name) txt <- withVerbatimMode anyControlSeq
1487+ spaces
1488+ symbol '}'
1489+ spaces
1490+ numargs <- option 0 $ try bracketedNum
1491+ spaces
1492+ optarg <- option Nothing $ Just <$> try bracketedToks
1493+ spaces
1494+ contents <- braced
1495+ when (mtype == "newcommand") $ do
1496+ macros <- sMacros <$> getState
1497+ case M.lookup name macros of
1498+ Just _ -> report $ MacroAlreadyDefined (T.unpack txt) pos
1499+ Nothing -> return ()
1500+ return (name, Macro numargs optarg contents)
1501+
1502+newenvironment :: PandocMonad m => LP m (Text, Macro, Macro)
1503+newenvironment = do
1504+ pos <- getPosition
1505+ Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
1506+ controlSeq "renewenvironment" <|>
1507+ controlSeq "provideenvironment"
1508+ optional $ symbol '*'
1509+ symbol '{'
1510+ spaces
1511+ Tok _ Word name <- satisfyTok isWordTok
1512+ spaces
1513+ symbol '}'
1514+ spaces
1515+ numargs <- option 0 $ try bracketedNum
1516+ spaces
1517+ optarg <- option Nothing $ Just <$> try bracketedToks
1518+ spaces
1519+ startcontents <- braced
1520+ spaces
1521+ endcontents <- braced
1522+ when (mtype == "newenvironment") $ do
1523+ macros <- sMacros <$> getState
1524+ case M.lookup name macros of
1525+ Just _ -> report $ MacroAlreadyDefined (T.unpack name) pos
1526+ Nothing -> return ()
1527+ return (name, Macro numargs optarg startcontents,
1528+ Macro 0 Nothing endcontents)
1529+
1530+bracketedToks :: PandocMonad m => LP m [Tok]
1531+bracketedToks = do
1532+ symbol '['
1533+ manyTill anyTok (symbol ']')
1534+
1535+bracketedNum :: PandocMonad m => LP m Int
1536+bracketedNum = do
1537+ ds <- untokenize <$> bracketedToks
1538+ case safeRead (T.unpack ds) of
1539+ Just i -> return i
1540+ _ -> return 0
1541+
1542+setCaption :: PandocMonad m => LP m Blocks
1543+setCaption = do
1544+ ils <- tok
1545+ mblabel <- option Nothing $
1546+ try $ spaces >> controlSeq "label" >> (Just <$> tok)
1547+ let ils' = case mblabel of
1548+ Just lab -> ils <> spanWith
1549+ ("",[],[("data-label", stringify lab)]) mempty
1550+ Nothing -> ils
1551+ updateState $ \st -> st{ sCaption = Just ils' }
1552+ return mempty
1553+
1554+looseItem :: PandocMonad m => LP m Blocks
1555+looseItem = do
1556+ inListItem <- sInListItem <$> getState
1557+ guard $ not inListItem
1558+ skipopts
1559+ return mempty
1560+
1561+resetCaption :: PandocMonad m => LP m ()
1562+resetCaption = updateState $ \st -> st{ sCaption = Nothing }
1563+
12011564section :: PandocMonad m => Attr -> Int -> LP m Blocks
12021565section (ident, classes, kvs) lvl = do
12031566 skipopts
@@ -1210,18 +1573,14 @@ section (ident, classes, kvs) lvl = do
12101573
12111574blockCommand :: PandocMonad m => LP m Blocks
12121575blockCommand = try $ do
1213− Tok _ CtrlSeq name <- anyControlSeq
1214− guard $ name /= "\\begin" && name /= "\\end"
1576+ Tok _ (CtrlSeq name) txt <- anyControlSeq
1577+ guard $ name /= "begin" && name /= "end"
12151578 star <- option "" ("*" <$ symbol '*' <* optional sp)
12161579 let name' = name <> star
1217− let names = name : [name' | name' /= name]
1218− let raw = rawBlock "latex" <$> getRawCommand name'
1219− -- TODO do we still need this?
1220− -- rawcommand <- getRawCommand name'
1221− -- transformed <- applyMacros' rawcommand
1222− -- guard $ transformed /= rawcommand
1223− -- notFollowedBy $ parseFromString' inlines transformed
1224− -- parseFromString' blocks transformed
1580+ let names = ordNub [name', name]
1581+ let raw = do
1582+ guard $ not (isInlineCommand name)
1583+ rawBlock "latex" <$> getRawCommand txt
12251584 lookupListDefault raw names blockCommands
12261585
12271586closing :: PandocMonad m => LP m Blocks
@@ -1243,8 +1602,8 @@ blockCommands = M.fromList $
12431602 [ ("par", mempty <$ skipopts)
12441603 , ("parbox", braced >> grouped blocks)
12451604 , ("title", mempty <$ (skipopts *>
1246− (grouped inline >>= addMeta "title")
1247− <|> (grouped block >>= addMeta "title")))
1605+ (grouped inline >>= addMeta "title")
1606+ <|> (grouped block >>= addMeta "title")))
12481607 , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
12491608 , ("author", mempty <$ (skipopts *> authors))
12501609 -- -- in letter class, temp. store address & sig as title, author
@@ -1278,24 +1637,26 @@ blockCommands = M.fromList $
12781637 , ("hrule", pure horizontalRule)
12791638 , ("strut", pure mempty)
12801639 , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
1281−-- , ("item", skipopts *> looseItem)
1282−-- , ("documentclass", skipopts *> braced *> preamble)
1640+ , ("item", looseItem)
1641+ , ("documentclass", skipopts *> braced *> preamble)
12831642 , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
1284−-- , ("caption", skipopts *> setCaption)
1285−-- , ("bibliography", mempty <$ (skipopts *> braced >>=
1286−-- addMeta "bibliography" . splitBibs))
1287−-- , ("addbibresource", mempty <$ (skipopts *> braced >>=
1288−-- addMeta "bibliography" . splitBibs))
1289−-- -- includes
1290−-- , ("lstinputlisting", inputListing)
1291−-- , ("graphicspath", graphicsPath)
1292−-- -- hyperlink
1293− , ("hypertarget", braced >> grouped block)
1643+ , ("caption", skipopts *> setCaption)
1644+ , ("bibliography", mempty <$ (skipopts *> braced >>=
1645+ addMeta "bibliography" . splitBibs . toksToString))
1646+ , ("addbibresource", mempty <$ (skipopts *> braced >>=
1647+ addMeta "bibliography" . splitBibs . toksToString))
1648+ -- includes
1649+ , ("lstinputlisting", inputListing)
1650+ , ("graphicspath", graphicsPath)
1651+ -- hyperlink
1652+ , ("hypertarget", try $ braced >> grouped block)
12941653 ] ++ map ignoreBlocks
12951654 -- these commands will be ignored unless --parse-raw is specified,
12961655 -- in which case they will appear as raw latex blocks
1297− [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
1298− -- newcommand, etc. should be parsed by macro, but we need this
1656+ [ "newcommand", "renewcommand"
1657+ , "newenvironment", "renewenvironment"
1658+ , "providecommand", "provideenvironment"
1659+ -- newcommand, etc. should be parsed by macroDef, but we need this
12991660 -- here so these aren't parsed as inline commands to ignore
13001661 , "special", "pdfannot", "pdfstringdef"
13011662 , "bibliographystyle"
@@ -1315,63 +1676,52 @@ blockCommands = M.fromList $
13151676environments :: PandocMonad m => M.Map Text (LP m Blocks)
13161677environments = M.fromList
13171678 [ ("document", env "document" blocks)
1318−-- , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
1319−-- , ("letter", env "letter" letterContents)
1320−-- , ("minipage", env "minipage" $
1321−-- skipopts *> spaces' *> optional braced *> spaces' *> blocks)
1322−-- , ("figure", env "figure" $ skipopts *> figure)
1323−-- , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
1324−-- , ("center", env "center" blocks)
1325−-- , ("longtable", env "longtable" $
1326−-- resetCaption *> simpTable "longtable" False >>= addTableCaption)
1327−-- , ("table", env "table" $
1328−-- resetCaption *> skipopts *> blocks >>= addTableCaption)
1329−-- , ("tabular*", env "tabular" $ simpTable "tabular*" True)
1330−-- , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1331−-- , ("tabular", env "tabular" $ simpTable "tabular" False)
1332−-- , ("quote", blockQuote <$> env "quote" blocks)
1333−-- , ("quotation", blockQuote <$> env "quotation" blocks)
1334−-- , ("verse", blockQuote <$> env "verse" blocks)
1335−-- , ("itemize", bulletList <$> listenv "itemize" (many item))
1336−-- , ("description", definitionList <$> listenv "description" (many descItem))
1337−-- , ("enumerate", orderedList')
1338−-- , ("alltt", alltt =<< verbEnv "alltt")
1339−-- , ("code", guardEnabled Ext_literate_haskell *>
1340−-- (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
1341−-- verbEnv "code"))
1342−-- , ("comment", mempty <$ verbEnv "comment")
1343−-- , ("verbatim", codeBlock <$> verbEnv "verbatim")
1344−-- , ("Verbatim", fancyverbEnv "Verbatim")
1345−-- , ("BVerbatim", fancyverbEnv "BVerbatim")
1346−-- , ("lstlisting", do attr <- parseListingsOptions <$> option [] keyvals
1347−-- codeBlockWith attr <$> verbEnv "lstlisting")
1348−-- , ("minted", do options <- option [] keyvals
1349−-- lang <- grouped (many1 $ satisfy (/='}'))
1350−-- let kvs = [ (if k == "firstnumber"
1351−-- then "startFrom"
1352−-- else k, v) | (k,v) <- options ]
1353−-- let classes = [ lang | not (null lang) ] ++
1354−-- [ "numberLines" |
1355−-- lookup "linenos" options == Just "true" ]
1356−-- let attr = ("",classes,kvs)
1357−-- codeBlockWith attr <$> verbEnv "minted")
1358−-- , ("obeylines", parseFromString
1359−-- (para . trimInlines . mconcat <$> many inline) =<<
1360−-- intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
1361−-- , ("displaymath", mathEnvWith para Nothing "displaymath")
1362−-- , ("equation", mathEnvWith para Nothing "equation")
1363−-- , ("equation*", mathEnvWith para Nothing "equation*")
1364−-- , ("gather", mathEnvWith para (Just "gathered") "gather")
1365−-- , ("gather*", mathEnvWith para (Just "gathered") "gather*")
1366−-- , ("multline", mathEnvWith para (Just "gathered") "multline")
1367−-- , ("multline*", mathEnvWith para (Just "gathered") "multline*")
1368−-- , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
1369−-- , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
1370−-- , ("align", mathEnvWith para (Just "aligned") "align")
1371−-- , ("align*", mathEnvWith para (Just "aligned") "align*")
1372−-- , ("alignat", mathEnvWith para (Just "aligned") "alignat")
1373−-- , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
1374−-- , ("tikzpicture", rawVerbEnv "tikzpicture")
1679+ , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
1680+ , ("letter", env "letter" letterContents)
1681+ , ("minipage", env "minipage" $
1682+ skipopts *> spaces *> optional braced *> spaces *> blocks)
1683+ , ("figure", env "figure" $ skipopts *> figure)
1684+ , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
1685+ , ("center", env "center" blocks)
1686+ , ("longtable", env "longtable" $
1687+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
1688+ , ("table", env "table" $
1689+ resetCaption *> skipopts *> blocks >>= addTableCaption)
1690+ , ("tabular*", env "tabular" $ simpTable "tabular*" True)
1691+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1692+ , ("tabular", env "tabular" $ simpTable "tabular" False)
1693+ , ("quote", blockQuote <$> env "quote" blocks)
1694+ , ("quotation", blockQuote <$> env "quotation" blocks)
1695+ , ("verse", blockQuote <$> env "verse" blocks)
1696+ , ("itemize", bulletList <$> listenv "itemize" (many item))
1697+ , ("description", definitionList <$> listenv "description" (many descItem))
1698+ , ("enumerate", orderedList')
1699+ , ("alltt", alltt <$> env "alltt" blocks)
1700+ , ("code", guardEnabled Ext_literate_haskell *>
1701+ (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
1702+ verbEnv "code"))
1703+ , ("comment", mempty <$ verbEnv "comment")
1704+ , ("verbatim", codeBlock <$> verbEnv "verbatim")
1705+ , ("Verbatim", fancyverbEnv "Verbatim")
1706+ , ("BVerbatim", fancyverbEnv "BVerbatim")
1707+ , ("lstlisting", do attr <- parseListingsOptions <$> option [] keyvals
1708+ codeBlockWith attr <$> verbEnv "lstlisting")
1709+ , ("minted", minted)
1710+ , ("obeylines", obeylines)
1711+ , ("displaymath", mathEnvWith para Nothing "displaymath")
1712+ , ("equation", mathEnvWith para Nothing "equation")
1713+ , ("equation*", mathEnvWith para Nothing "equation*")
1714+ , ("gather", mathEnvWith para (Just "gathered") "gather")
1715+ , ("gather*", mathEnvWith para (Just "gathered") "gather*")
1716+ , ("multline", mathEnvWith para (Just "gathered") "multline")
1717+ , ("multline*", mathEnvWith para (Just "gathered") "multline*")
1718+ , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
1719+ , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
1720+ , ("align", mathEnvWith para (Just "aligned") "align")
1721+ , ("align*", mathEnvWith para (Just "aligned") "align*")
1722+ , ("alignat", mathEnvWith para (Just "aligned") "alignat")
1723+ , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
1724+ , ("tikzpicture", rawVerbEnv "tikzpicture")
13751725 ]
13761726
13771727environment :: PandocMonad m => LP m Blocks
@@ -1382,9 +1732,7 @@ environment = do
13821732 <|> rawEnv name
13831733
13841734env :: PandocMonad m => Text -> LP m a -> LP m a
1385−env name p = p <*
1386− (try (controlSeq "end" *> braced >>= guard . (== name) . untokenize)
1387− <?> ("\\end{" ++ T.unpack name ++ "}"))
1735+env name p = p <* end_ name
13881736
13891737rawEnv :: PandocMonad m => Text -> LP m Blocks
13901738rawEnv name = do
@@ -1404,525 +1752,355 @@ rawEnv name = do
14041752 report $ SkippedContent ("\\end{" ++ T.unpack name ++ "}") pos2
14051753 return bs
14061754
1407− -- raw' <- applyMacros' $ beginCommand <> untokenize raw
1408− -- if raw' /= beginCommand ++ raw
1409− -- then parseFromString' blocks raw'
1410− -- else if parseRaw
1411− -- then return $ rawBlock "latex" $ beginCommand ++ raw'
1412− -- else do
1413− -- unless parseRaw $ do
1414− -- report $ SkippedContent beginCommand pos1
1415− -- pos2 <- getPosition
1416− -- report $ SkippedContent ("\\end{" ++ name ++ "}") pos2
1417− -- return bs
1755+rawVerbEnv :: PandocMonad m => Text -> LP m Blocks
1756+rawVerbEnv name = do
1757+ pos <- getPosition
1758+ (_, raw) <- withRaw $ verbEnv name
1759+ let raw' = "\\begin{tikzpicture}" ++ toksToString raw
1760+ exts <- getOption readerExtensions
1761+ let parseRaw = extensionEnabled Ext_raw_tex exts
1762+ if parseRaw
1763+ then return $ rawBlock "latex" raw'
1764+ else do
1765+ report $ SkippedContent raw' pos
1766+ return mempty
1767+
1768+verbEnv :: PandocMonad m => Text -> LP m String
1769+verbEnv name = withVerbatimMode $ do
1770+ skipopts
1771+ optional blankline
1772+ res <- manyTill anyTok (end_ name)
1773+ return $ stripTrailingNewlines $ toksToString res
1774+
1775+fancyverbEnv :: PandocMonad m => Text -> LP m Blocks
1776+fancyverbEnv name = do
1777+ options <- option [] keyvals
1778+ let kvs = [ (if k == "firstnumber"
1779+ then "startFrom"
1780+ else k, v) | (k,v) <- options ]
1781+ let classes = [ "numberLines" |
1782+ lookup "numbers" options == Just "left" ]
1783+ let attr = ("",classes,kvs)
1784+ codeBlockWith attr <$> verbEnv name
1785+
1786+obeylines :: PandocMonad m => LP m Blocks
1787+obeylines = do
1788+ para . fromList . removeLeadingTrailingBreaks .
1789+ walk softBreakToHard . toList <$> env "obeylines" inlines
1790+ where softBreakToHard SoftBreak = LineBreak
1791+ softBreakToHard x = x
1792+ removeLeadingTrailingBreaks = reverse . dropWhile isLineBreak .
1793+ reverse . dropWhile isLineBreak
1794+ isLineBreak LineBreak = True
1795+ isLineBreak _ = False
1796+
1797+minted :: PandocMonad m => LP m Blocks
1798+minted = do
1799+ options <- option [] keyvals
1800+ lang <- toksToString <$> braced
1801+ let kvs = [ (if k == "firstnumber"
1802+ then "startFrom"
1803+ else k, v) | (k,v) <- options ]
1804+ let classes = [ lang | not (null lang) ] ++
1805+ [ "numberLines" |
1806+ lookup "linenos" options == Just "true" ]
1807+ let attr = ("",classes,kvs)
1808+ codeBlockWith attr <$> verbEnv "minted"
1809+
1810+letterContents :: PandocMonad m => LP m Blocks
1811+letterContents = do
1812+ bs <- blocks
1813+ st <- getState
1814+ -- add signature (author) and address (title)
1815+ let addr = case lookupMeta "address" (sMeta st) of
1816+ Just (MetaBlocks [Plain xs]) ->
1817+ para $ trimInlines $ fromList xs
1818+ _ -> mempty
1819+ return $ addr <> bs -- sig added by \closing
1820+
1821+figure :: PandocMonad m => LP m Blocks
1822+figure = try $ do
1823+ resetCaption
1824+ blocks >>= addImageCaption
1825+
1826+addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
1827+addImageCaption = walkM go
1828+ where go (Image attr alt (src,tit))
1829+ | not ("fig:" `isPrefixOf` tit) = do
1830+ mbcapt <- sCaption <$> getState
1831+ return $ case mbcapt of
1832+ Just ils -> Image attr (toList ils) (src, "fig:" ++ tit)
1833+ Nothing -> Image attr alt (src,tit)
1834+ go x = return x
1835+
1836+graphicsPath :: PandocMonad m => LP m Blocks
1837+graphicsPath = do
1838+ ps <- map toksToString <$> (bgroup *> manyTill braced egroup)
1839+ getResourcePath >>= setResourcePath . (++ ps)
1840+ return mempty
1841+
1842+splitBibs :: String -> [Inlines]
1843+splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
1844+
1845+alltt :: Blocks -> Blocks
1846+alltt = walk strToCode
1847+ where strToCode (Str s) = Code nullAttr s
1848+ strToCode Space = RawInline (Format "latex") "\\ "
1849+ strToCode SoftBreak = LineBreak
1850+ strToCode x = x
1851+
1852+parseListingsOptions :: [(String, String)] -> Attr
1853+parseListingsOptions options =
1854+ let kvs = [ (if k == "firstnumber"
1855+ then "startFrom"
1856+ else k, v) | (k,v) <- options ]
1857+ classes = [ "numberLines" |
1858+ lookup "numbers" options == Just "left" ]
1859+ ++ maybeToList (lookup "language" options
1860+ >>= fromListingsLanguage)
1861+ in (fromMaybe "" (lookup "label" options), classes, kvs)
1862+
1863+inputListing :: PandocMonad m => LP m Blocks
1864+inputListing = do
1865+ pos <- getPosition
1866+ options <- option [] keyvals
1867+ f <- filter (/='"') . toksToString <$> braced
1868+ dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
1869+ mbCode <- readFileFromDirs dirs f
1870+ codeLines <- case mbCode of
1871+ Just s -> return $ lines s
1872+ Nothing -> do
1873+ report $ CouldNotLoadIncludeFile f pos
1874+ return []
1875+ let (ident,classes,kvs) = parseListingsOptions options
1876+ let language = case lookup "language" options >>= fromListingsLanguage of
1877+ Just l -> [l]
1878+ Nothing -> take 1 $ languagesByExtension (takeExtension f)
1879+ let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1880+ let lastline = fromMaybe (length codeLines) $
1881+ lookup "lastline" options >>= safeRead
1882+ let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
1883+ drop (firstline - 1) codeLines
1884+ return $ codeBlockWith (ident,ordNub (classes ++ language),kvs) codeContents
1885+
1886+-- lists
1887+
1888+item :: PandocMonad m => LP m Blocks
1889+item = void blocks *> controlSeq "item" *> skipopts *> blocks
1890+
1891+descItem :: PandocMonad m => LP m (Inlines, [Blocks])
1892+descItem = do
1893+ blocks -- skip blocks before item
1894+ controlSeq "item"
1895+ optional sp
1896+ ils <- opt
1897+ bs <- blocks
1898+ return (ils, [bs])
1899+
1900+listenv :: PandocMonad m => Text -> LP m a -> LP m a
1901+listenv name p = try $ do
1902+ oldInListItem <- sInListItem `fmap` getState
1903+ updateState $ \st -> st{ sInListItem = True }
1904+ res <- env name p
1905+ updateState $ \st -> st{ sInListItem = oldInListItem }
1906+ return res
1907+
1908+orderedList' :: PandocMonad m => LP m Blocks
1909+orderedList' = try $ do
1910+ spaces
1911+ let markerSpec = do
1912+ symbol '['
1913+ ts <- toksToString <$> manyTill anyTok (symbol ']')
1914+ case runParser anyOrderedListMarker def "option" ts of
1915+ Right r -> return r
1916+ Left _ -> do
1917+ pos <- getPosition
1918+ report $ SkippedContent ("[" ++ ts ++ "]") pos
1919+ return (1, DefaultStyle, DefaultDelim)
1920+ (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) markerSpec
1921+ spaces
1922+ optional $ try $ controlSeq "setlength"
1923+ *> grouped (count 1 $ controlSeq "itemindent")
1924+ *> braced
1925+ spaces
1926+ start <- option 1 $ try $ do pos <- getPosition
1927+ controlSeq "setcounter"
1928+ ctr <- toksToString <$> braced
1929+ guard $ "enum" `isPrefixOf` ctr
1930+ guard $ all (`elem` ['i','v']) (drop 4 ctr)
1931+ optional sp
1932+ num <- toksToString <$> braced
1933+ case safeRead num of
1934+ Just i -> return (i + 1 :: Int)
1935+ Nothing -> do
1936+ report $ SkippedContent
1937+ ("\\setcounter{" ++ ctr ++
1938+ "}{" ++ num ++ "}") pos
1939+ return 1
1940+ bs <- listenv "enumerate" (many item)
1941+ return $ orderedListWith (start, style, delim) bs
1942+
1943+-- tables
1944+
1945+hline :: PandocMonad m => LP m ()
1946+hline = try $ do
1947+ spaces
1948+ controlSeq "hline" <|>
1949+ -- booktabs rules:
1950+ controlSeq "toprule" <|>
1951+ controlSeq "bottomrule" <|>
1952+ controlSeq "midrule" <|>
1953+ controlSeq "endhead" <|>
1954+ controlSeq "endfirsthead"
1955+ spaces
1956+ optional $ bracketed inline
1957+ return ()
1958+
1959+lbreak :: PandocMonad m => LP m Tok
1960+lbreak = (controlSeq "\\" <|> controlSeq "tabularnewline") <* spaces
1961+
1962+amp :: PandocMonad m => LP m Tok
1963+amp = symbol '&'
1964+
1965+-- Split a Word into individual Symbols (for parseAligns)
1966+splitWordTok :: PandocMonad m => LP m ()
1967+splitWordTok = do
1968+ inp <- getInput
1969+ case inp of
1970+ (Tok spos Word t : rest) -> do
1971+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) ++ rest
1972+ _ -> return ()
1973+
1974+parseAligns :: PandocMonad m => LP m [(Alignment, Double, ([Tok], [Tok]))]
1975+parseAligns = try $ do
1976+ let maybeBar = skipMany $
1977+ sp <|> () <$ symbol '|' <|> () <$ (symbol '@' >> braced)
1978+ let cAlign = AlignCenter <$ symbol 'c'
1979+ let lAlign = AlignLeft <$ symbol 'l'
1980+ let rAlign = AlignRight <$ symbol 'r'
1981+ let parAlign = AlignLeft <$ symbol 'p'
1982+ -- aligns from tabularx
1983+ let xAlign = AlignLeft <$ symbol 'X'
1984+ let mAlign = AlignLeft <$ symbol 'm'
1985+ let bAlign = AlignLeft <$ symbol 'b'
1986+ let alignChar = splitWordTok *> ( cAlign <|> lAlign <|> rAlign <|> parAlign
1987+ <|> xAlign <|> mAlign <|> bAlign )
1988+ let alignPrefix = symbol '>' >> braced
1989+ let alignSuffix = symbol '<' >> braced
1990+ let colWidth = try $ do
1991+ symbol '{'
1992+ ds <- trim . toksToString <$> manyTill anyTok (controlSeq "linewidth")
1993+ spaces
1994+ symbol '}'
1995+ case safeRead ds of
1996+ Just w -> return w
1997+ Nothing -> return 0.0
1998+ let alignSpec = try $ do
1999+ spaces
2000+ pref <- option [] alignPrefix
2001+ spaces
2002+ al <- alignChar
2003+ width <- colWidth <|> option 0.0 (do s <- toksToString <$> braced
2004+ pos <- getPosition
2005+ report $ SkippedContent s pos
2006+ return 0.0)
2007+ spaces
2008+ suff <- option [] alignSuffix
2009+ return (al, width, (pref, suff))
2010+ bgroup
2011+ spaces
2012+ maybeBar
2013+ aligns' <- many (alignSpec <* maybeBar)
2014+ spaces
2015+ egroup
2016+ spaces
2017+ return aligns'
2018+
2019+parseTableRow :: PandocMonad m
2020+ => Text -- ^ table environment name
2021+ -> [([Tok], [Tok])] -- ^ pref/suffixes
2022+ -> LP m [Blocks]
2023+parseTableRow envname prefsufs = do
2024+ notFollowedBy (spaces *> end_ envname)
2025+ let cols = length prefsufs
2026+ -- add prefixes and suffixes in token stream:
2027+ let celltoks (pref, suff) = do
2028+ prefpos <- getPosition
2029+ contents <- many (notFollowedBy
2030+ (() <$ amp <|> () <$ lbreak <|> end_ envname)
2031+ >> anyTok)
2032+ suffpos <- getPosition
2033+ option [] (count 1 amp)
2034+ return $ map (setpos (sourceLine prefpos, sourceColumn prefpos)) pref
2035+ ++ contents ++
2036+ map (setpos (sourceLine suffpos, sourceColumn suffpos)) suff
2037+ rawcells <- sequence (map celltoks prefsufs)
2038+ oldInput <- getInput
2039+ cells <- sequence $ map (\ts -> setInput ts >> parseTableCell) rawcells
2040+ setInput oldInput
2041+ spaces
2042+ let numcells = length cells
2043+ guard $ numcells <= cols && numcells >= 1
2044+ guard $ cells /= [mempty]
2045+ -- note: a & b in a three-column table leaves an empty 3rd cell:
2046+ return $ cells ++ replicate (cols - numcells) mempty
2047+
2048+parseTableCell :: PandocMonad m => LP m Blocks
2049+parseTableCell = do
2050+ let plainify bs = case toList bs of
2051+ [Para ils] -> plain (fromList ils)
2052+ _ -> bs
2053+ updateState $ \st -> st{ sInTableCell = True }
2054+ cells <- plainify <$> blocks
2055+ updateState $ \st -> st{ sInTableCell = False }
2056+ return cells
2057+
2058+simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
2059+simpTable envname hasWidthParameter = try $ do
2060+ when hasWidthParameter $ () <$ (spaces >> tok)
2061+ skipopts
2062+ colspecs <- parseAligns
2063+ let (aligns, widths, prefsufs) = unzip3 colspecs
2064+ let cols = length colspecs
2065+ optional $ controlSeq "caption" *> skipopts *> setCaption
2066+ optional lbreak
2067+ spaces
2068+ skipMany hline
2069+ spaces
2070+ header' <- option [] $ try (parseTableRow envname prefsufs <*
2071+ lbreak <* many1 hline)
2072+ spaces
2073+ rows <- sepEndBy (parseTableRow envname prefsufs)
2074+ (lbreak <* optional (skipMany hline))
2075+ spaces
2076+ optional $ controlSeq "caption" *> skipopts *> setCaption
2077+ optional lbreak
2078+ spaces
2079+ let header'' = if null header'
2080+ then replicate cols mempty
2081+ else header'
2082+ lookAhead $ controlSeq "end" -- make sure we're at end
2083+ return $ table mempty (zip aligns widths) header'' rows
2084+
2085+addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
2086+addTableCaption = walkM go
2087+ where go (Table c als ws hs rs) = do
2088+ mbcapt <- sCaption <$> getState
2089+ return $ case mbcapt of
2090+ Just ils -> Table (toList ils) als ws hs rs
2091+ Nothing -> Table c als ws hs rs
2092+ go x = return x
2093+
14182094
14192095block :: PandocMonad m => LP m Blocks
14202096block = (mempty <$ spaces1)
14212097 <|> environment
14222098 <|> include
1423− -- <|> macro
1424− <|> blockCommand
2099+ <|> macroDef
14252100 <|> paragraph
2101+ <|> blockCommand
14262102 <|> grouped block
14272103
14282104blocks :: PandocMonad m => LP m Blocks
14292105blocks = mconcat <$> many block
14302106
1431−{-
1432−-- graphicsPath :: PandocMonad m => LP m Blocks
1433−-- graphicsPath = do
1434−-- ps <- bgroup *> (manyTill braced egroup)
1435−-- getResourcePath >>= setResourcePath . (++ ps)
1436−-- return mempty
1437−--
1438−-- addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1439−-- addMeta field val = updateState $ \st ->
1440−-- st{ sMeta = addMetaField field val $ sMeta st }
1441−--
1442−-- splitBibs :: String -> [Inlines]
1443−-- splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
1444−--
1445−-- setCaption :: PandocMonad m => LP m Blocks
1446−-- setCaption = do
1447−-- ils <- tok
1448−-- mblabel <- option Nothing $
1449−-- try $ spaces' >> controlSeq "label" >> (Just <$> tok)
1450−-- let ils' = case mblabel of
1451−-- Just lab -> ils <> spanWith
1452−-- ("",[],[("data-label", stringify lab)]) mempty
1453−-- Nothing -> ils
1454−-- updateState $ \st -> st{ stateCaption = Just ils' }
1455−-- return mempty
1456−--
1457−-- resetCaption :: PandocMonad m => LP m ()
1458−-- resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
1459−--
1460−-- mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
1461−-- mkImage options src = do
1462−-- let replaceTextwidth (k,v) = case numUnit v of
1463−-- Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
1464−-- _ -> (k, v)
1465−-- let kvs = map replaceTextwidth $ filter (\(k,_) -> k `elem` ["width", "height"]) options
1466−-- let attr = ("",[], kvs)
1467−-- let alt = str "image"
1468−-- case takeExtension src of
1469−-- "" -> do
1470−-- defaultExt <- getOption readerDefaultImageExtension
1471−-- return $ imageWith attr (addExtension src defaultExt) "" alt
1472−-- _ -> return $ imageWith attr src "" alt
1473−--
1474−-- inNote :: Inlines -> Inlines
1475−-- inNote ils =
1476−-- note $ para $ ils <> str "."
1477−--
1478−-
1479−-- -- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
1480−-- dosiunitx :: PandocMonad m => LP m Inlines
1481−-- dosiunitx = do
1482−-- skipopts
1483−-- value <- tok
1484−-- valueprefix <- option "" $ char '[' >> (mconcat <$> manyTill tok (char ']'))
1485−-- unit <- tok
1486−-- let emptyOr160 "" = ""
1487−-- emptyOr160 _ = "\160"
1488−-- return . mconcat $ [valueprefix,
1489−-- emptyOr160 valueprefix,
1490−-- value,
1491−-- emptyOr160 unit,
1492−-- unit]
1493−--
1494−-- skipangles :: PandocMonad m => LP m ()
1495−-- skipangles = skipMany rawangle
1496−--
1497−-- inlineText :: PandocMonad m => LP m Inlines
1498−-- inlineText = str <$> many1 inlineChar
1499−--
1500−-- inlineChar :: PandocMonad m => LP m Char
1501−-- inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
1502−--
1503−--
1504−-- inlineEnvironment :: PandocMonad m => LP m Inlines
1505−-- inlineEnvironment = try $ do
1506−-- controlSeq "begin"
1507−-- name <- braced
1508−-- M.findWithDefault mzero name inlineEnvironments
1509−--
1510−--
1511−-- rawVerbEnv :: PandocMonad m => String -> LP m Blocks
1512−-- rawVerbEnv name = do
1513−-- pos <- getPosition
1514−-- (_, raw) <- withRaw $ verbEnv name
1515−-- let raw' = "\\begin{tikzpicture}" ++ raw
1516−-- exts <- getOption readerExtensions
1517−-- let parseRaw = extensionEnabled Ext_raw_tex exts
1518−-- if parseRaw
1519−-- then return $ rawBlock "latex" raw'
1520−-- else do
1521−-- report $ SkippedContent raw' pos
1522−-- return mempty
1523−--
1524−-- ----
1525−--
1526−-- alltt :: PandocMonad m => String -> LP m Blocks
1527−-- alltt t = walk strToCode <$> parseFromString' blocks
1528−-- (substitute " " "\\ " $ substitute "%" "\\%" $
1529−-- intercalate "\\\\\n" $ lines t)
1530−-- where strToCode (Str s) = Code nullAttr s
1531−-- strToCode x = x
1532−--
1533−-- rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState String
1534−-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
1535−--
1536−-- rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState Inline
1537−-- rawLaTeXInline = do
1538−-- raw <- (snd <$> withRaw inlineCommand)
1539−-- <|> (snd <$> withRaw inlineEnvironment)
1540−-- <|> (snd <$> withRaw blockCommand)
1541−-- RawInline "latex" <$> applyMacros' raw
1542−--
1543−-- addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
1544−-- addImageCaption = walkM go
1545−-- where go (Image attr alt (src,tit))
1546−-- | not ("fig:" `isPrefixOf` tit) = do
1547−-- mbcapt <- stateCaption <$> getState
1548−-- return $ case mbcapt of
1549−-- Just ils -> Image attr (toList ils) (src, "fig:" ++ tit)
1550−-- Nothing -> Image attr alt (src,tit)
1551−-- go x = return x
1552−--
1553−-- addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
1554−-- addTableCaption = walkM go
1555−-- where go (Table c als ws hs rs) = do
1556−-- mbcapt <- stateCaption <$> getState
1557−-- return $ case mbcapt of
1558−-- Just ils -> Table (toList ils) als ws hs rs
1559−-- Nothing -> Table c als ws hs rs
1560−-- go x = return x
1561−--
1562−--
1563−-- figure :: PandocMonad m => LP m Blocks
1564−-- figure = try $ do
1565−-- resetCaption
1566−-- blocks >>= addImageCaption
1567−--
1568−-- letterContents :: PandocMonad m => LP m Blocks
1569−-- letterContents = do
1570−-- bs <- blocks
1571−-- st <- getState
1572−-- -- add signature (author) and address (title)
1573−-- let addr = case lookupMeta "address" (sMeta st) of
1574−-- Just (MetaBlocks [Plain xs]) ->
1575−-- para $ trimInlines $ fromList xs
1576−-- _ -> mempty
1577−-- return $ addr <> bs -- sig added by \closing
1578−--
1579−--
1580−-- item :: PandocMonad m => LP m Blocks
1581−-- item = blocks *> controlSeq "item" *> skipopts *> blocks
1582−--
1583−-- looseItem :: PandocMonad m => LP m Blocks
1584−-- looseItem = do
1585−-- ctx <- stateParserContext `fmap` getState
1586−-- if ctx == ListItemState
1587−-- then mzero
1588−-- else return mempty
1589−--
1590−-- descItem :: PandocMonad m => LP m (Inlines, [Blocks])
1591−-- descItem = do
1592−-- blocks -- skip blocks before item
1593−-- controlSeq "item"
1594−-- optional sp
1595−-- ils <- opt
1596−-- bs <- blocks
1597−-- return (ils, [bs])
1598−--
1599−--
1600−-- listenv :: PandocMonad m => String -> LP m a -> LP m a
1601−-- listenv name p = try $ do
1602−-- oldCtx <- stateParserContext `fmap` getState
1603−-- updateState $ \st -> st{ stateParserContext = ListItemState }
1604−-- res <- env name p
1605−-- updateState $ \st -> st{ stateParserContext = oldCtx }
1606−-- return res
1607−--
1608−-- mathEnvWith :: PandocMonad m
1609−-- => (Inlines -> a) -> Maybe String -> String -> LP m a
1610−-- mathEnvWith f innerEnv name = f <$> mathDisplay (inner <$> mathEnv name)
1611−-- where inner x = case innerEnv of
1612−-- Nothing -> x
1613−-- Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
1614−-- "\\end{" ++ y ++ "}"
1615−--
1616−-- mathEnv :: PandocMonad m => String -> LP m String
1617−-- mathEnv name = do
1618−-- skipopts
1619−-- optional blankline
1620−-- let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
1621−-- charMuncher = skipMany comment *>
1622−-- (many1 (noneOf "\\%") <|> try (string "\\%")
1623−-- <|> try (string "\\\\") <|> count 1 anyChar)
1624−-- res <- concat <$> manyTill charMuncher endEnv
1625−-- return $ stripTrailingNewlines res
1626−--
1627−-- verbEnv :: PandocMonad m => String -> LP m String
1628−-- verbEnv name = do
1629−-- skipopts
1630−-- optional blankline
1631−-- let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
1632−-- charMuncher = anyChar
1633−-- res <- manyTill charMuncher endEnv
1634−-- return $ stripTrailingNewlines res
1635−--
1636−-- fancyverbEnv :: PandocMonad m => String -> LP m Blocks
1637−-- fancyverbEnv name = do
1638−-- options <- option [] keyvals
1639−-- let kvs = [ (if k == "firstnumber"
1640−-- then "startFrom"
1641−-- else k, v) | (k,v) <- options ]
1642−-- let classes = [ "numberLines" |
1643−-- lookup "numbers" options == Just "left" ]
1644−-- let attr = ("",classes,kvs)
1645−-- codeBlockWith attr <$> verbEnv name
1646−--
1647−-- orderedList' :: PandocMonad m => LP m Blocks
1648−-- orderedList' = try $ do
1649−-- optional sp
1650−-- (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
1651−-- try $ char '[' *> anyOrderedListMarker <* char ']'
1652−-- spaces
1653−-- optional $ try $ controlSeq "setlength" *> grouped (controlSeq "itemindent") *> braced
1654−-- spaces
1655−-- start <- option 1 $ try $ do controlSeq "setcounter"
1656−-- grouped (string "enum" *> many1 (oneOf "iv"))
1657−-- optional sp
1658−-- num <- grouped (many1 digit)
1659−-- spaces
1660−-- return (read num + 1 :: Int)
1661−-- bs <- listenv "enumerate" (many item)
1662−-- return $ orderedListWith (start, style, delim) bs
1663−--
1664−-- paragraph :: PandocMonad m => LP m Blocks
1665−-- paragraph = do
1666−-- x <- trimInlines . mconcat <$> many1 inline
1667−-- if x == mempty
1668−-- then return mempty
1669−-- else return $ para x
1670−--
1671−-- preamble :: PandocMonad m => LP m Blocks
1672−-- preamble = mempty <$> manyTill preambleBlock beginDoc
1673−-- where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
1674−-- preambleBlock = void comment
1675−-- <|> void sp
1676−-- <|> void blanklines
1677−-- <|> void include
1678−-- <|> void macro
1679−-- <|> void blockCommand
1680−-- <|> void anyControlSeq
1681−-- <|> void braced
1682−-- <|> void anyChar
1683−--
1684−-- -------
1685−--
1686−-- -- citations
1687−--
1688−-- addPrefix :: [Inline] -> [Citation] -> [Citation]
1689−-- addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
1690−-- addPrefix _ _ = []
1691−--
1692−-- addSuffix :: [Inline] -> [Citation] -> [Citation]
1693−-- addSuffix s ks@(_:_) =
1694−-- let k = last ks
1695−-- in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
1696−-- addSuffix _ _ = []
1697−--
1698−-- simpleCiteArgs :: PandocMonad m => LP m [Citation]
1699−-- simpleCiteArgs = try $ do
1700−-- first <- optionMaybe $ toList <$> opt
1701−-- second <- optionMaybe $ toList <$> opt
1702−-- keys <- try $ bgroup *> (manyTill citationLabel egroup)
1703−-- let (pre, suf) = case (first , second ) of
1704−-- (Just s , Nothing) -> (mempty, s )
1705−-- (Just s , Just t ) -> (s , t )
1706−-- _ -> (mempty, mempty)
1707−-- conv k = Citation { citationId = k
1708−-- , citationPrefix = []
1709−-- , citationSuffix = []
1710−-- , citationMode = NormalCitation
1711−-- , citationHash = 0
1712−-- , citationNoteNum = 0
1713−-- }
1714−-- return $ addPrefix pre $ addSuffix suf $ map conv keys
1715−--
1716−-- citationLabel :: PandocMonad m => LP m String
1717−-- citationLabel = optional sp *>
1718−-- (many1 (satisfy isBibtexKeyChar)
1719−-- <* optional sp
1720−-- <* optional (char ',')
1721−-- <* optional sp)
1722−-- where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
1723−--
1724−-- cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
1725−-- cites mode multi = try $ do
1726−-- cits <- if multi
1727−-- then many1 simpleCiteArgs
1728−-- else count 1 simpleCiteArgs
1729−-- let cs = concat cits
1730−-- return $ case mode of
1731−-- AuthorInText -> case cs of
1732−-- (c:rest) -> c {citationMode = mode} : rest
1733−-- [] -> []
1734−-- _ -> map (\a -> a {citationMode = mode}) cs
1735−--
1736−-- citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
1737−-- citation name mode multi = do
1738−-- (c,raw) <- withRaw $ cites mode multi
1739−-- return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
1740−--
1741−-- complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
1742−-- complexNatbibCitation mode = try $ do
1743−-- let ils = (toList . trimInlines . mconcat) <$>
1744−-- many (notFollowedBy (oneOf "\\};") >> inline)
1745−-- let parseOne = try $ do
1746−-- skipSpaces
1747−-- pref <- ils
1748−-- cit' <- inline -- expect a citation
1749−-- let citlist = toList cit'
1750−-- cits' <- case citlist of
1751−-- [Cite cs _] -> return cs
1752−-- _ -> mzero
1753−-- suff <- ils
1754−-- skipSpaces
1755−-- optional $ char ';'
1756−-- return $ addPrefix pref $ addSuffix suff cits'
1757−-- (c:cits, raw) <- withRaw $ grouped parseOne
1758−-- return $ cite (c{ citationMode = mode }:cits)
1759−-- (rawInline "latex" $ "\\citetext" ++ raw)
1760−--
1761−-- -- tables
1762−--
1763−-- parseAligns :: PandocMonad m => LP m [(Alignment, Double, (String, String))]
1764−-- parseAligns = try $ do
1765−-- bgroup
1766−-- let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
1767−-- maybeBar
1768−-- let cAlign = AlignCenter <$ char 'c'
1769−-- let lAlign = AlignLeft <$ char 'l'
1770−-- let rAlign = AlignRight <$ char 'r'
1771−-- let parAlign = AlignLeft <$ char 'p'
1772−-- -- algins from tabularx
1773−-- let xAlign = AlignLeft <$ char 'X'
1774−-- let mAlign = AlignLeft <$ char 'm'
1775−-- let bAlign = AlignLeft <$ char 'b'
1776−-- let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
1777−-- <|> xAlign <|> mAlign <|> bAlign
1778−-- let alignPrefix = char '>' >> braced
1779−-- let alignSuffix = char '<' >> braced
1780−-- let colWidth = try $ do
1781−-- char '{'
1782−-- ds <- many1 (oneOf "0123456789.")
1783−-- spaces
1784−-- string "\\linewidth"
1785−-- char '}'
1786−-- case safeRead ds of
1787−-- Just w -> return w
1788−-- Nothing -> return 0.0
1789−-- let alignSpec = do
1790−-- spaces
1791−-- pref <- option "" alignPrefix
1792−-- spaces
1793−-- al <- alignChar
1794−-- width <- colWidth <|> option 0.0 (do s <- braced
1795−-- pos <- getPosition
1796−-- report $ SkippedContent s pos
1797−-- return 0.0)
1798−-- spaces
1799−-- suff <- option "" alignSuffix
1800−-- return (al, width, (pref, suff))
1801−-- aligns' <- sepEndBy alignSpec maybeBar
1802−-- spaces
1803−-- egroup
1804−-- spaces
1805−-- return $ aligns'
1806−--
1807−-- hline :: PandocMonad m => LP m ()
1808−-- hline = try $ do
1809−-- spaces'
1810−-- controlSeq "hline" <|>
1811−-- -- booktabs rules:
1812−-- controlSeq "toprule" <|>
1813−-- controlSeq "bottomrule" <|>
1814−-- controlSeq "midrule" <|>
1815−-- controlSeq "endhead" <|>
1816−-- controlSeq "endfirsthead"
1817−-- spaces'
1818−-- optional $ bracketed (many1 (satisfy (/=']')))
1819−-- return ()
1820−--
1821−-- lbreak :: PandocMonad m => LP m ()
1822−-- lbreak = () <$ try (spaces' *>
1823−-- (controlSeq "\\" <|> controlSeq "tabularnewline") <*
1824−-- spaces')
1825−--
1826−-- amp :: PandocMonad m => LP m ()
1827−-- amp = () <$ try (spaces' *> char '&' <* spaces')
1828−--
1829−-- parseTableRow :: PandocMonad m
1830−-- => String -- ^ table environment name
1831−-- -> [(String, String)] -- ^ pref/suffixes
1832−-- -> LP m [Blocks]
1833−-- parseTableRow envname prefsufs = try $ do
1834−-- let cols = length prefsufs
1835−-- let tableCellRaw = concat <$> many
1836−-- (do notFollowedBy amp
1837−-- notFollowedBy lbreak
1838−-- notFollowedBy $ () <$ try (string ("\\end{" ++ envname ++ "}"))
1839−-- many1 (noneOf "&%\n\r\\")
1840−-- <|> try (string "\\&")
1841−-- <|> count 1 anyChar)
1842−-- let plainify bs = case toList bs of
1843−-- [Para ils] -> plain (fromList ils)
1844−-- _ -> bs
1845−-- rawcells <- sepBy1 tableCellRaw amp
1846−-- guard $ length rawcells == cols
1847−-- let rawcells' = zipWith (\c (p, s) -> p ++ trim c ++ s) rawcells prefsufs
1848−-- let tableCell = plainify <$> blocks
1849−-- cells' <- mapM (parseFromString' tableCell) rawcells'
1850−-- let numcells = length cells'
1851−-- guard $ numcells <= cols && numcells >= 1
1852−-- guard $ cells' /= [mempty]
1853−-- -- note: a & b in a three-column table leaves an empty 3rd cell:
1854−-- let cells'' = cells' ++ replicate (cols - numcells) mempty
1855−-- spaces'
1856−-- return cells''
1857−--
1858−-- spaces' :: PandocMonad m => LP m ()
1859−-- spaces' = spaces *> skipMany (comment *> spaces)
1860−--
1861−-- simpTable :: PandocMonad m => String -> Bool -> LP m Blocks
1862−-- simpTable envname hasWidthParameter = try $ do
1863−-- when hasWidthParameter $ () <$ (spaces' >> tok)
1864−-- skipopts
1865−-- colspecs <- parseAligns
1866−-- let (aligns, widths, prefsufs) = unzip3 colspecs
1867−-- let cols = length colspecs
1868−-- optional $ controlSeq "caption" *> skipopts *> setCaption
1869−-- optional lbreak
1870−-- spaces'
1871−-- skipMany hline
1872−-- spaces'
1873−-- header' <- option [] $ try (parseTableRow envname prefsufs <*
1874−-- lbreak <* many1 hline)
1875−-- spaces'
1876−-- rows <- sepEndBy (parseTableRow envname prefsufs)
1877−-- (lbreak <* optional (skipMany hline))
1878−-- spaces'
1879−-- optional $ controlSeq "caption" *> skipopts *> setCaption
1880−-- optional lbreak
1881−-- spaces'
1882−-- let header'' = if null header'
1883−-- then replicate cols mempty
1884−-- else header'
1885−-- lookAhead $ controlSeq "end" -- make sure we're at end
1886−-- return $ table mempty (zip aligns widths) header'' rows
1887−--
1888−-- removeDoubleQuotes :: String -> String
1889−-- removeDoubleQuotes ('"':xs) =
1890−-- case reverse xs of
1891−-- '"':ys -> reverse ys
1892−-- _ -> '"':xs
1893−-- removeDoubleQuotes xs = xs
1894−--
1895−-- inputListing :: PandocMonad m => LP m Blocks
1896−-- inputListing = do
1897−-- pos <- getPosition
1898−-- options <- option [] keyvals
1899−-- f <- filter (/='"') <$> braced
1900−-- dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
1901−-- mbCode <- readFileFromDirs dirs f
1902−-- codeLines <- case mbCode of
1903−-- Just s -> return $ lines s
1904−-- Nothing -> do
1905−-- report $ CouldNotLoadIncludeFile f pos
1906−-- return []
1907−-- let (ident,classes,kvs) = parseListingsOptions options
1908−-- let language = case lookup "language" options >>= fromListingsLanguage of
1909−-- Just l -> [l]
1910−-- Nothing -> take 1 $ languagesByExtension (takeExtension f)
1911−-- let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1912−-- let lastline = fromMaybe (length codeLines) $
1913−-- lookup "lastline" options >>= safeRead
1914−-- let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
1915−-- drop (firstline - 1) codeLines
1916−-- return $ codeBlockWith (ident,ordNub (classes ++ language),kvs) codeContents
1917−--
1918−-- parseListingsOptions :: [(String, String)] -> Attr
1919−-- parseListingsOptions options =
1920−-- let kvs = [ (if k == "firstnumber"
1921−-- then "startFrom"
1922−-- else k, v) | (k,v) <- options ]
1923−-- classes = [ "numberLines" |
1924−-- lookup "numbers" options == Just "left" ]
1925−-- ++ maybeToList (lookup "language" options
1926−-- >>= fromListingsLanguage)
1927−-- in (fromMaybe "" (lookup "label" options), classes, kvs)
1928−-}