@@ -38,8 +38,9 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
38import Control.Applicative (many, optional, (<|>))
38import Control.Applicative (many, optional, (<|>))
39import Control.Monad
39import Control.Monad
40import Control.Monad.Except (throwError)
40import Control.Monad.Except (throwError)
41−import Data.Char (chr, isAlphaNum, isLetter, ord)
41+import Data.Char (chr, isAlphaNum, isLetter, ord, isDigit)
42import Data.Text (Text, unpack)
42import Data.Text (Text, unpack)
43+import qualified Data.Text as T
43import Data.List (intercalate, isPrefixOf)
44import Data.List (intercalate, isPrefixOf)
44import qualified Data.Map as M
45import qualified Data.Map as M
45import Data.Maybe (fromMaybe, maybeToList)
46import Data.Maybe (fromMaybe, maybeToList)
@@ -47,15 +48,21 @@ import Safe (minimumDef)
47import System.FilePath (addExtension, replaceExtension, takeExtension)
48import System.FilePath (addExtension, replaceExtension, takeExtension)
48import Text.Pandoc.Builder
49import Text.Pandoc.Builder
49import Text.Pandoc.Class (PandocMonad, PandocPure, lookupEnv, readFileFromDirs,
50import Text.Pandoc.Class (PandocMonad, PandocPure, lookupEnv, readFileFromDirs,
50− report, setResourcePath, getResourcePath)
51+ report, setResourcePath, getResourcePath,
52+ runIOorExplode, PandocIO)
51import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
53import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
52import Text.Pandoc.ImageSize (numUnit, showFl)
54import Text.Pandoc.ImageSize (numUnit, showFl)
53import Text.Pandoc.Logging
55import Text.Pandoc.Logging
54import Text.Pandoc.Options
56import Text.Pandoc.Options
55−import Text.Pandoc.Parsing hiding (many, mathDisplay, mathInline, optional,
57+import Text.Pandoc.Parsing hiding (many, optional, withRaw,
58+ mathInline, mathDisplay,
56− space, (<|>))
59+ space, (<|>), spaces, blankline)
57import Text.Pandoc.Shared
60import Text.Pandoc.Shared
58import Text.Pandoc.Walk
61import Text.Pandoc.Walk
62+import Text.Pandoc.Error (PandocError(PandocParsecError))
64+import Text.Pandoc.Extensions (getDefaultExtensions)
65+import Debug.Trace (traceShowId)
60-- | Parse LaTeX from string and return 'Pandoc' document.
67-- | Parse LaTeX from string and return 'Pandoc' document.
61readLaTeX :: PandocMonad m
68readLaTeX :: PandocMonad m
@@ -63,11 +70,11 @@ readLaTeX :: PandocMonad m
63 -> Text -- ^ String to parse (assumes @'\n'@ line endings)
70 -> Text -- ^ String to parse (assumes @'\n'@ line endings)
64 -> m Pandoc
71 -> m Pandoc
65readLaTeX opts ltx = do
72readLaTeX opts ltx = do
66− parsed <- readWithM parseLaTeX def{ stateOptions = opts }
73+ parsed <- runParserT parseLaTeX def{ stateOptions = opts } "source"
67− (unpack (crFilter ltx))
74+ (tokenize (crFilter ltx))
68 case parsed of
75 case parsed of
69 Right result -> return result
76 Right result -> return result
70− Left e -> throwError e
77+ Left e -> throwError $ PandocParsecError (T.unpack ltx) e
72parseLaTeX :: PandocMonad m => LP m Pandoc
79parseLaTeX :: PandocMonad m => LP m Pandoc
73parseLaTeX = do
80parseLaTeX = do
@@ -88,177 +95,249 @@ parseLaTeX = do
88 else id) doc'
95 else id) doc'
89 return $ Pandoc meta bs'
96 return $ Pandoc meta bs'
98+testParser :: LP PandocIO a -> Text -> IO a
100+ res <- runIOorExplode (runParserT p defaultParserState{
101+ stateOptions = def{ readerExtensions =
102+ getDefaultExtensions "latex" }} "name" (tokenize t))
104+ Left e -> error (show e)
91−type LP m = ParserT String ParserState m
107+type LP m = ParserT [Tok] ParserState m
93−anyControlSeq :: PandocMonad m => LP m String
109+rawLaTeXBlock :: PandocMonad m => ParserT String ParserState m String
94−anyControlSeq = do
110+rawLaTeXBlock = mzero
96− next <- option '\n' anyChar
112+rawLaTeXInline :: PandocMonad m => ParserT String ParserState m Inline
113+rawLaTeXInline = mzero
115+inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
116+inlineCommand = mzero
118+data TokType = CtrlSeq | Spaces | Newline | Symbol | Word | Comment |
120+ deriving (Eq, Ord, Show)
122+data Tok = Tok (Line, Column) TokType Text
123+ deriving (Eq, Ord, Show)
125+tokenize :: Text -> [Tok]
126+tokenize = totoks (1, 1)
128+totoks :: (Line, Column) -> Text -> [Tok]
97− case next of
130+ case T.uncons t of
98− '\n' -> return ""
131+ Nothing -> []
99− c | isLetter c -> (c:) <$> (many letter <* optional sp)
132+ Just (c, rest)
100− | otherwise -> return [c]
133+ | c == '\n' ->
101−
134+ Tok (lin, col) Newline (T.singleton '\n')
135+ : totoks (lin + 1,1) rest
137+ let (sps, rest') = T.span isSpaceOrTab t
138+ in Tok (lin, col) Spaces sps
139+ : totoks (lin, col + T.length sps) rest'
141+ let (ws, rest') = T.span isAlphaNum t
142+ in Tok (lin, col) Word ws
143+ : totoks (lin, col + T.length ws) rest'
145+ let (cs, rest') = T.break (== '\n') rest
146+ in Tok (lin, col) Comment (T.singleton '%' <> cs)
147+ : totoks (lin, col + 1 + T.length cs) rest'
149+ case T.uncons rest of
150+ Nothing -> [Tok (lin, col) Symbol (T.singleton c)]
153+ let (ws, rest'') = T.span isLetter rest
154+ in Tok (lin, col) CtrlSeq (T.singleton '\\' <> ws)
155+ : totoks (lin, col + 1 + T.length ws) rest''
156+ | d == '\t' || d == '\n' ->
157+ Tok (lin, col) Symbol (T.singleton '\\')
158+ : totoks (lin, col + 1) rest
160+ Tok (lin, col) CtrlSeq (T.pack [c,d])
161+ : totoks (lin, col + 2) rest'
163+ case T.uncons rest of
164+ Just ('^', rest') ->
165+ case T.uncons rest' of
168+ case T.uncons rest'' of
169+ Just (e, rest''') | isLowerHex e ->
170+ Tok (lin, col) Esc2 (T.pack ['^','^',d,e])
171+ : totoks (lin, col + 4) rest'''
173+ Tok (lin, col) Esc1 (T.pack ['^','^',d])
174+ : totoks (lin, col + 3) rest''
176+ Tok (lin, col) Esc1 (T.pack ['^','^',d])
177+ : totoks (lin, col + 3) rest''
178+ _ -> [Tok (lin, col) Symbol (T.singleton '^'),
179+ Tok (lin, col + 1) Symbol (T.singleton '^')]
180+ _ -> Tok (lin, col) Symbol (T.singleton '^')
181+ : totoks (lin, col + 1) rest
183+ Tok (lin, col) Symbol (T.singleton c) : totoks (lin, col + 1) rest
185+ where isSpaceOrTab ' ' = True
186+ isSpaceOrTab '\t' = True
187+ isSpaceOrTab _ = False
189+isLowerHex :: Char -> Bool
190+isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
192+untokenize :: [Tok] -> Text
193+untokenize = mconcat . map untoken
195+untoken :: Tok -> Text
196+untoken (Tok _ _ t) = t
198+satisfyTok :: Monad m
200+ -> ParserT [Tok] u m Tok
201+satisfyTok f = tokenPrim (T.unpack . untoken) updatePos matcher
202+ where matcher t | f t = Just t
203+ | otherwise = Nothing
204+ updatePos :: SourcePos -> Tok -> [Tok] -> SourcePos
205+ updatePos spos _ (Tok (lin,col) _ _ : _) =
206+ setSourceColumn (setSourceLine spos lin) col
207+ updatePos spos _ [] = spos
209+anyControlSeq :: PandocMonad m => LP m Tok
210+anyControlSeq = satisfyTok isCtrlSeq <* optional sp
211+ where isCtrlSeq (Tok _ CtrlSeq _) = True
214+anySymbol :: PandocMonad m => LP m Tok
215+anySymbol = satisfyTok isSym
216+ where isSym (Tok _ Symbol _) = True
219+spaces :: PandocMonad m => LP m ()
220+spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline]))
222+spaces1 :: PandocMonad m => LP m ()
223+spaces1 = skipMany1 (satisfyTok (tokTypeIn [Comment, Spaces, Newline]))
225+tokTypeIn :: [TokType] -> Tok -> Bool
226+tokTypeIn toktypes (Tok _ tt _) = tt `elem` toktypes
228+controlSeq :: PandocMonad m => Text -> LP m Tok
229+controlSeq name = satisfyTok isNamed
230+ where isNamed (Tok _ CtrlSeq n) = n == T.singleton '\\' <> name
102−controlSeq :: PandocMonad m => String -> LP m String
233+symbol :: PandocMonad m => Char -> LP m Tok
103−controlSeq name = try $ do
234+symbol c = satisfyTok isc
104− char '\\'
235+ where isc (Tok _ Symbol d) = case T.uncons d of
105− case name of
236+ Just (c',_) -> c == c'
106− "" -> mzero
237+ _ -> False
107− [c] | not (isLetter c) -> string [c]
238+ isc _ = False
108− cs -> string cs <* notFollowedBy letter <* optional sp
239+
111−dimenarg :: PandocMonad m => LP m String
240+symbolIn :: PandocMonad m => [Char] -> LP m Tok
112−dimenarg = try $ do
241+symbolIn cs = satisfyTok isInCs
113− ch <- option "" $ string "="
242+ where isInCs (Tok _ Symbol d) = case T.uncons d of
114− num <- many1 digit
243+ Just (c,_) -> c `elem` cs
115− dim <- oneOfStrings ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
244+ _ -> False
116− return $ ch ++ num ++ dim
245+ isInCs _ = False
118sp :: PandocMonad m => LP m ()
247sp :: PandocMonad m => LP m ()
119sp = whitespace <|> endline
248sp = whitespace <|> endline
121whitespace :: PandocMonad m => LP m ()
250whitespace :: PandocMonad m => LP m ()
122−whitespace = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
251+whitespace = () <$ satisfyTok isSpaceTok
123−
252+ where isSpaceTok (Tok _ Spaces _) = True
124−endline :: PandocMonad m => LP m ()
253+ isSpaceTok _ = False
125−endline = try (newline >> lookAhead anyChar >> notFollowedBy blankline)
127−isLowerHex :: Char -> Bool
255+newlineTok :: PandocMonad m => LP m ()
128−isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
256+newlineTok = () <$ satisfyTok isNewlineTok
130−tildeEscape :: PandocMonad m => LP m Char
258+isNewlineTok :: Tok -> Bool
131−tildeEscape = try $ do
259+isNewlineTok (Tok _ Newline _) = True
132− string "^^"
260+isNewlineTok _ = False
133− c <- satisfy (\x -> x >= '\0' && x <= '\128')
134− d <- if isLowerHex c
135− then option "" $ count 1 (satisfy isLowerHex)
139− x | x >= 64 && x <= 127 -> return $ chr (x - 64)
140− | otherwise -> return $ chr (x + 64)
141− else return $ chr $ read ('0':'x':c:d)
143comment :: PandocMonad m => LP m ()
262comment :: PandocMonad m => LP m ()
144−comment = do
263+comment = () <$ satisfyTok isCommentTok
145− char '%'
264+ where isCommentTok (Tok _ Comment _) = True
146− skipMany (satisfy (/='\n'))
265+ isCommentTok _ = False
147− optional newline
266+
267+anyTok :: PandocMonad m => LP m Tok
268+anyTok = satisfyTok (const True)
270+endline :: PandocMonad m => LP m ()
274+ notFollowedBy blankline
276+blankline :: PandocMonad m => LP m ()
278+ skipMany (satisfyTok (tokTypeIn [Spaces, Newline]))
281+primEscape :: PandocMonad m => LP m Char
283+ Tok _ toktype t <- satisfyTok (tokTypeIn [Esc1, Esc2])
285+ Esc1 -> case T.uncons t of
287+ | c >= '\64' && c <= '\127' -> return (chr (ord c - 64))
288+ | otherwise -> return (chr (ord c + 64))
289+ Nothing -> fail "Empty content of Esc1"
290+ Esc2 -> case safeRead ('0':'x':T.unpack (T.drop 2 t)) of
148− return ()
291+ Just x -> return (chr x)
292+ Nothing -> fail $ "Could not read: " ++ T.unpack t
293+ _ -> fail "Expected an Esc1 or Esc2 token" -- should not happen
150bgroup :: PandocMonad m => LP m ()
295bgroup :: PandocMonad m => LP m ()
151bgroup = try $ do
296bgroup = try $ do
152− skipMany (spaceChar <|> try (newline <* notFollowedBy blankline))
297+ skipMany sp
154− <|> () <$ controlSeq "bgroup"
155− <|> () <$ controlSeq "begingroup"
298+ symbol '{' <|> controlSeq "bgroup" <|> controlSeq "begingroup"
157egroup :: PandocMonad m => LP m ()
301egroup :: PandocMonad m => LP m ()
158−egroup = () <$ char '}'
159− <|> () <$ controlSeq "egroup"
160− <|> () <$ controlSeq "endgroup"
302+egroup = () <$ (symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup")
162−grouped :: PandocMonad m => Monoid a => LP m a -> LP m a
304+grouped :: (PandocMonad m, Monoid a) => LP m a -> LP m a
163grouped parser = try $ do
305grouped parser = try $ do
165 -- first we check for an inner 'grouped', because
307 -- first we check for an inner 'grouped', because
166 -- {{a,b}} should be parsed the same as {a,b}
308 -- {{a,b}} should be parsed the same as {a,b}
167− try (grouped parser <* egroup)
168− <|> (mconcat <$> manyTill parser egroup)
309+ try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup)
170−braced :: PandocMonad m => LP m String
311+braced :: PandocMonad m => LP m [Tok]
171−braced = grouped chunk
312+braced = try $ do
172− where chunk =
313+ bgroup
173− many1 (satisfy (\c -> c /= '\\' && c /= '}' && c /= '{'))
314+ -- {{a,b}} should be parsed the same as {a,b}
174− <|> try (string "\\}")
315+ try (braced <* egroup) <|> manyTill anyTok egroup
175− <|> try (string "\\{")
176− <|> try (string "\\\\")
177− <|> ((\x -> "{" ++ x ++ "}") <$> braced)
180bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
317bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
318+bracketed parser = try $ do
181−bracketed parser = try $ char '[' *> (mconcat <$> manyTill parser (char ']'))
320+ mconcat <$> manyTill parser (symbol ']')
183−mathDisplay :: PandocMonad m => LP m String -> LP m Inlines
184−mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
186−mathInline :: PandocMonad m => LP m String -> LP m Inlines
187−mathInline p = math <$> (try p >>= applyMacros')
189−mathChars :: PandocMonad m => LP m String
191− concat <$> many (escapedChar
192− <|> (snd <$> withRaw braced)
193− <|> many1 (satisfy isOrdChar))
194− where escapedChar = try $ do char '\\'
197− isOrdChar '$' = False
198− isOrdChar '{' = False
199− isOrdChar '}' = False
200− isOrdChar '\\' = False
203−quoted' :: PandocMonad m => (Inlines -> Inlines) -> LP m String -> LP m () -> LP m Inlines
204−quoted' f starter ender = do
206− smart <- extensionEnabled Ext_smart <$> getOption readerExtensions
209− ils <- many (notFollowedBy ender >> inline)
210− (ender >> return (f (mconcat ils))) <|>
211− (<> mconcat ils) <$>
212− lit (case startchs of
218−doubleQuote :: PandocMonad m => LP m Inlines
322+dimenarg :: PandocMonad m => LP m Text
219−doubleQuote = do
323+dimenarg = try $ do
220− quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
324+ ch <- option False $ True <$ symbol '='
221− <|> quoted' doubleQuoted (string "“") (void $ char '”')
325+ Tok _ _ s <- satisfyTok isWordTok
222− -- the following is used by babel for localized quotes:
326+ guard $ (T.take 2 (T.reverse s)) `elem`
223− <|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
327+ ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
224− <|> quoted' doubleQuoted (string "\"") (void $ char '"')
328+ let num = T.take (T.length s - 2) s
329+ guard $ T.length num > 0
330+ guard $ T.all isDigit num
331+ return $ T.pack ['=' | ch] <> s
226−singleQuote :: PandocMonad m => LP m Inlines
333+-- inline elements:
228− smart <- extensionEnabled Ext_smart <$> getOption readerExtensions
230− then quoted' singleQuoted (string "`") (try $ char '\'' >> notFollowedBy letter)
231− <|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
232− else str <$> many1 (oneOf "`\'‘’")
234−inline :: PandocMonad m => LP m Inlines
335+inlineText :: PandocMonad m => LP m Inlines
235−inline = (mempty <$ comment)
336+inlineText = (str . T.unpack . untoken) <$> satisfyTok isWordTok
236− <|> (space <$ whitespace)
237− <|> (softbreak <$ endline)
240− <|> inlineEnvironment
242− <|> (char '-' *> option (str "-")
243− (char '-' *> option (str "–") (str "—" <$ char '-')))
246− <|> (str "”" <$ try (string "''"))
247− <|> (str "”" <$ char '”')
248− <|> (str "’" <$ char '\'')
249− <|> (str "’" <$ char '’')
250− <|> (str "\160" <$ char '~')
251− <|> mathDisplay (string "$$" *> mathChars <* string "$$")
252− <|> mathInline (char '$' *> mathChars <* char '$')
253− <|> (guardEnabled Ext_literate_haskell *> char '|' *> doLHSverb)
254− <|> (str . (:[]) <$> tildeEscape)
255− <|> (do res <- oneOf "#&~^'`\"[]"
257− report $ ParsingUnescaped [res] pos
260−inlines :: PandocMonad m => LP m Inlines
338+isWordTok :: Tok -> Bool
261−inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
339+isWordTok (Tok _ Word _) = True
263inlineGroup :: PandocMonad m => LP m Inlines
342inlineGroup :: PandocMonad m => LP m Inlines
264inlineGroup = do
343inlineGroup = do
@@ -269,233 +348,466 @@ inlineGroup = do
269 -- we need the span so we can detitlecase bibtex entries;
348 -- we need the span so we can detitlecase bibtex entries;
270 -- we need to know when something is {C}apitalized
349 -- we need to know when something is {C}apitalized
272−block :: PandocMonad m => LP m Blocks
351+doLHSverb :: PandocMonad m => LP m Inlines
273−block = (mempty <$ comment)
352+doLHSverb =
274− <|> (mempty <$ ((spaceChar <|> newline) *> spaces))
353+ (codeWith ("",["haskell"],[]) . T.unpack . untokenize)
275− <|> environment
354+ <$> manyTill (satisfyTok (not . isNewlineTok)) (symbol '|')
282−blocks :: PandocMonad m => LP m Blocks
283−blocks = mconcat <$> many block
285−getRawCommand :: PandocMonad m => String -> LP m String
356+lit :: String -> LP m Inlines
286−getRawCommand name' = do
357+lit = pure . str
287− rawargs <- withRaw (many (try (optional sp *> opt)) *>
288− option "" (try (optional sp *> dimenarg)) *>
290− return $ '\\' : name' ++ snd rawargs
292−lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
359+doubleQuote :: PandocMonad m => LP m Inlines
293−lookupListDefault d = (fromMaybe d .) . lookupList
360+doubleQuote = do
294− where
361+ quoted' doubleQuoted (try $ count 2 $ symbol '`')
295− lookupList l m = msum $ map (`M.lookup` m) l
362+ (void $ try $ count 2 $ symbol '\'')
363+ <|> quoted' doubleQuoted ((:[]) <$> symbol '“') (void $ symbol '”')
364+ -- the following is used by babel for localized quotes:
365+ <|> quoted' doubleQuoted (try $ sequence [symbol '"', symbol '`'])
366+ (void $ try $ sequence [symbol '"', symbol '\''])
367+ <|> quoted' doubleQuoted ((:[]) <$> symbol '"')
297−blockCommand :: PandocMonad m => LP m Blocks
370+singleQuote :: PandocMonad m => LP m Inlines
298−blockCommand = try $ do
371+singleQuote = do
299− name <- anyControlSeq
372+ quoted' singleQuoted ((:[]) <$> symbol '`')
300− guard $ name /= "begin" && name /= "end"
373+ (try $ symbol '\'' >>
301− star <- option "" (string "*" <* optional sp)
374+ notFollowedBy (satisfyTok startsWithLetter))
302− let name' = name ++ star
375+ <|> quoted' singleQuoted ((:[]) <$> symbol '‘')
303− let raw = do
376+ (try $ symbol '’' >>
304− rawcommand <- getRawCommand name'
377+ notFollowedBy (satisfyTok startsWithLetter))
305− transformed <- applyMacros' rawcommand
378+ where startsWithLetter (Tok _ Word t) =
306− guard $ transformed /= rawcommand
379+ case T.uncons t of
307− notFollowedBy $ parseFromString' inlines transformed
380+ Just (c, _) | isLetter c -> True
308− parseFromString' blocks transformed
381+ _ -> False
309− lookupListDefault raw [name',name] blockCommands
382+ startsWithLetter _ = False
384+quoted' :: PandocMonad m
385+ => (Inlines -> Inlines)
389+quoted' f starter ender = do
390+ startchs <- (T.unpack . untokenize) <$> starter
391+ smart <- extensionEnabled Ext_smart <$> getOption readerExtensions
394+ ils <- many (notFollowedBy ender >> inline)
395+ (ender >> return (f (mconcat ils))) <|>
396+ (<> mconcat ils) <$>
397+ lit (case startchs of
311−inBrackets :: Inlines -> Inlines
403+enquote :: PandocMonad m => LP m Inlines
312−inBrackets x = str "[" <> x <> str "]"
404+enquote = do
406+ context <- stateQuoteContext <$> getState
407+ if context == InDoubleQuote
408+ then singleQuoted <$> withQuoteContext InSingleQuote tok
409+ else doubleQuoted <$> withQuoteContext InDoubleQuote tok
314−-- eat an optional argument and one or more arguments in braces
315−ignoreInlines :: PandocMonad m => String -> (String, LP m Inlines)
411+doverb :: PandocMonad m => LP m Inlines
316−ignoreInlines name = (name, p)
412+doverb = do
317− where
413+ Tok _ Symbol t <- anySymbol
318− p = do oa <- optargs
414+ marker <- case T.uncons t of
319− let rawCommand = '\\':name ++ oa
415+ Just (c, ts) | T.null ts -> return c
320− let doraw = guardRaw >> return (rawInline "latex" rawCommand)
416+ _ -> mzero
321− doraw <|> ignore rawCommand
417+ (code . T.unpack . untokenize) <$> manyTill (verbTok marker) (symbol marker)
419+verbTok :: PandocMonad m => Char -> LP m Tok
420+verbTok stopchar = do
421+ t@(Tok (lin, col) toktype txt) <- satisfyTok (not . isNewlineTok)
422+ case T.findIndex (== stopchar) txt of
425+ let (t1, t2) = T.splitAt i txt
427+ setInput $ Tok (lin, col + i) Symbol (T.singleton stopchar)
428+ : (totoks (lin, col + i + 1) (T.drop 1 t2)) ++ inp
429+ return $ Tok (lin, col) toktype t1
323−guardRaw :: PandocMonad m => LP m ()
431+dolstinline :: PandocMonad m => LP m Inlines
324−guardRaw = getOption readerExtensions >>= guard . extensionEnabled Ext_raw_tex
432+dolstinline = do
433+ options <- option [] keyvals
434+ let classes = maybeToList $ lookup "language" options >>= fromListingsLanguage
435+ Tok _ Symbol t <- anySymbol
436+ marker <- case T.uncons t of
437+ Just (c, ts) | T.null ts -> return c
439+ let stopchar = if marker == '{' then '}' else marker
440+ (codeWith ("",classes,[]) . T.unpack . untokenize) <$>
441+ manyTill (verbTok stopchar) (symbol stopchar)
326−optargs :: PandocMonad m => LP m String
443+keyval :: PandocMonad m => LP m (String, String)
327−optargs = snd <$> withRaw (skipopts *> skipMany (try $ optional sp *> braced))
444+keyval = try $ do
445+ Tok _ Word key <- satisfyTok isWordTok
446+ let isSpecSym (Tok _ Symbol t) = t `elem` [".",":","-","|","\\"]
448+ val <- option [] $ do
450+ braced <|> (many1 (satisfyTok isWordTok <|> satisfyTok isSpecSym))
452+ optional (symbol ',')
454+ return (T.unpack key, T.unpack . untokenize $ val)
329−ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a
456+keyvals :: PandocMonad m => LP m [(String, String)]
330−ignore raw = do
457+keyvals = try $ symbol '[' >> manyTill keyval (symbol ']')
332− report $ SkippedContent raw pos
335−ignoreBlocks :: PandocMonad m => String -> (String, LP m Blocks)
459+accent :: (Char -> String) -> Inlines -> LP m Inlines
336−ignoreBlocks name = (name, p)
460+accent f ils =
337− where
461+ case toList ils of
338− p = do oa <- optargs
462+ (Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
339− let rawCommand = '\\':name ++ oa
463+ [] -> mzero
340− let doraw = guardRaw >> return (rawBlock "latex" rawCommand)
464+ _ -> return ils
341− doraw <|> ignore rawCommand
343−blockCommands :: PandocMonad m => M.Map String (LP m Blocks)
466+grave :: Char -> String
344−blockCommands = M.fromList $
467+grave 'A' = "À"
345− [ ("par", mempty <$ skipopts)
468+grave 'E' = "È"
346− , ("parbox", braced >> grouped blocks)
469+grave 'I' = "Ì"
347− , ("title", mempty <$ (skipopts *>
470+grave 'O' = "Ò"
348− (grouped inline >>= addMeta "title")
471+grave 'U' = "Ù"
349− <|> (grouped block >>= addMeta "title")))
472+grave 'a' = "à"
350− , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
473+grave 'e' = "è"
351− , ("author", mempty <$ (skipopts *> authors))
474+grave 'i' = "ì"
352− -- -- in letter class, temp. store address & sig as title, author
475+grave 'o' = "ò"
353− , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
476+grave 'u' = "ù"
354− , ("signature", mempty <$ (skipopts *> authors))
477+grave c = [c]
355− , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
356− -- Koma-script metadata commands
357− , ("dedication", mempty <$ (skipopts *> tok >>= addMeta "dedication"))
359− , ("part", section nullAttr (-1))
360− , ("part*", section nullAttr (-1))
361− , ("chapter", section nullAttr 0)
362− , ("chapter*", section ("",["unnumbered"],[]) 0)
363− , ("section", section nullAttr 1)
364− , ("section*", section ("",["unnumbered"],[]) 1)
365− , ("subsection", section nullAttr 2)
366− , ("subsection*", section ("",["unnumbered"],[]) 2)
367− , ("subsubsection", section nullAttr 3)
368− , ("subsubsection*", section ("",["unnumbered"],[]) 3)
369− , ("paragraph", section nullAttr 4)
370− , ("paragraph*", section ("",["unnumbered"],[]) 4)
371− , ("subparagraph", section nullAttr 5)
372− , ("subparagraph*", section ("",["unnumbered"],[]) 5)
374− , ("frametitle", section nullAttr 3)
375− , ("framesubtitle", section nullAttr 4)
377− , ("opening", (para . trimInlines) <$> (skipopts *> tok))
378− , ("closing", skipopts *> closing)
380− , ("hrule", pure horizontalRule)
381− , ("strut", pure mempty)
382− , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
383− , ("item", skipopts *> looseItem)
384− , ("documentclass", skipopts *> braced *> preamble)
385− , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
386− , ("caption", skipopts *> setCaption)
387− , ("bibliography", mempty <$ (skipopts *> braced >>=
388− addMeta "bibliography" . splitBibs))
389− , ("addbibresource", mempty <$ (skipopts *> braced >>=
390− addMeta "bibliography" . splitBibs))
392− , ("lstinputlisting", inputListing)
393− , ("graphicspath", graphicsPath)
395− , ("hypertarget", braced >> grouped block)
396− ] ++ map ignoreBlocks
397− -- these commands will be ignored unless --parse-raw is specified,
398− -- in which case they will appear as raw latex blocks
399− [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
400− -- newcommand, etc. should be parsed by macro, but we need this
401− -- here so these aren't parsed as inline commands to ignore
402− , "special", "pdfannot", "pdfstringdef"
403− , "bibliographystyle"
404− , "maketitle", "makeindex", "makeglossary"
405− , "addcontentsline", "addtocontents", "addtocounter"
406− -- \ignore{} is used conventionally in literate haskell for definitions
407− -- that are to be processed by the compiler but not printed.
410− , "markboth", "markright", "markleft"
411− , "hspace", "vspace"
417−graphicsPath :: PandocMonad m => LP m Blocks
479+acute :: Char -> String
418−graphicsPath = do
480+acute 'A' = "Á"
419− ps <- bgroup *> (manyTill braced egroup)
481+acute 'E' = "É"
420− getResourcePath >>= setResourcePath . (++ ps)
482+acute 'I' = "Í"
421− return mempty
483+acute 'O' = "Ó"
423−addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
506+circ :: Char -> String
424−addMeta field val = updateState $ \st ->
507+circ 'A' = "Â"
425− st{ stateMeta = addMetaField field val $ stateMeta st }
508+circ 'E' = "Ê"
427−splitBibs :: String -> [Inlines]
510+circ 'O' = "Ô"
428−splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
511+circ 'U' = "Û"
430−setCaption :: PandocMonad m => LP m Blocks
513+circ 'e' = "ê"
431−setCaption = do
514+circ 'i' = "î"
432− ils <- tok
515+circ 'o' = "ô"
433− mblabel <- option Nothing $
516+circ 'u' = "û"
434− try $ spaces' >> controlSeq "label" >> (Just <$> tok)
517+circ 'C' = "Ĉ"
435− let ils' = case mblabel of
518+circ 'c' = "ĉ"
436− Just lab -> ils <> spanWith
519+circ 'G' = "Ĝ"
437− ("",[],[("data-label", stringify lab)]) mempty
520+circ 'g' = "ĝ"
438− Nothing -> ils
521+circ 'H' = "Ĥ"
439− updateState $ \st -> st{ stateCaption = Just ils' }
522+circ 'h' = "ĥ"
440− return mempty
523+circ 'J' = "Ĵ"
442−resetCaption :: PandocMonad m => LP m ()
533+tilde :: Char -> String
443−resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
534+tilde 'A' = "Ã"
445−authors :: PandocMonad m => LP m ()
546+umlaut :: Char -> String
446−authors = try $ do
547+umlaut 'A' = "Ä"
447− bgroup
548+umlaut 'E' = "Ë"
448− let oneAuthor = mconcat <$>
549+umlaut 'I' = "Ï"
449− many1 (notFollowedBy' (controlSeq "and") >>
550+umlaut 'O' = "Ö"
450− (inline <|> mempty <$ blockCommand))
551+umlaut 'U' = "Ü"
451− -- skip e.g. \vspace{10pt}
552+umlaut 'a' = "ä"
452− auths <- sepBy oneAuthor (controlSeq "and")
553+umlaut 'e' = "ë"
453− egroup
554+umlaut 'i' = "ï"
454− addMeta "author" (map trimInlines auths)
555+umlaut 'o' = "ö"
456−section :: PandocMonad m => Attr -> Int -> LP m Blocks
559+hungarumlaut :: Char -> String
457−section (ident, classes, kvs) lvl = do
560+hungarumlaut 'A' = "A̋"
458− skipopts
561+hungarumlaut 'E' = "E̋"
459− contents <- grouped inline
562+hungarumlaut 'I' = "I̋"
460− lab <- option ident $ try (spaces' >> controlSeq "label" >> spaces' >> braced)
563+hungarumlaut 'O' = "Ő"
461− attr' <- registerHeader (lab, classes, kvs) contents
564+hungarumlaut 'U' = "Ű"
462− return $ headerWith attr' lvl contents
565+hungarumlaut 'Y' = "ӳ"
566+hungarumlaut 'a' = "a̋"
567+hungarumlaut 'e' = "e̋"
568+hungarumlaut 'i' = "i̋"
569+hungarumlaut 'o' = "ő"
570+hungarumlaut 'u' = "ű"
571+hungarumlaut 'y' = "ӳ"
574+dot :: Char -> String
586+macron :: Char -> String
599+cedilla :: Char -> String
614+hacek :: Char -> String
650+breve :: Char -> String
665+toksToString :: [Tok] -> String
666+toksToString = T.unpack . untokenize
668+mathDisplay :: String -> Inlines
669+mathDisplay = displayMath . trim
670+-- TODO we shouldn't need applyMacros
671+-- mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
673+mathInline :: String -> Inlines
674+mathInline = math . trim
675+-- TODO we shouldn't need applyMacros
676+-- mathInline p = math <$> (try p >>= applyMacros')
678+dollarsMath :: PandocMonad m => LP m Inlines
681+ display <- option False (True <$ symbol '$')
682+ contents <- many1Till anyTok (symbol '$')
683+ when display (() <$ symbol '$')
684+ let constructor = if display then mathDisplay else mathInline
685+ return $ constructor $ toksToString contents
464−inlineCommand :: PandocMonad m => LP m Inlines
687+inlineCommand' :: PandocMonad m => LP m Inlines
465−inlineCommand = try $ do
688+inlineCommand' = try $ do
466− (name, raw') <- withRaw anyControlSeq
689+ cs@(Tok _ CtrlSeq t) <- anyControlSeq
690+ let name = T.drop 1 t
467 guard $ name /= "begin" && name /= "end"
691 guard $ name /= "begin" && name /= "end"
468− star <- option "" (string "*")
692+ mbstar <- option Nothing (Just <$> symbol '*')
469− let name' = name ++ star
693+ let names = name : maybe [] (const [name <> "*"]) mbstar
694+ optional $ try $ symbol '{' >> symbol '}'
470 let raw = do
695 let raw = do
471− guard $ not (isBlockCommand name)
696+ guard $ not (isBlockCommand name)
472− rawargs <- withRaw
697+ (_, rawargs) <- withRaw
473− (skipangles *> skipopts *> option "" dimenarg *> many braced)
698+ (skipangles *> skipopts *> option "" dimenarg *> many braced)
474− let rawcommand = raw' ++ star ++ snd rawargs
699+ let rawcommand = T.unpack $ untokenize $
700+ cs : maybe [] (:[]) mbstar ++ rawargs
701+ (guardEnabled Ext_raw_tex >> return (rawInline "latex" rawcommand))
702+ <|> ignore rawcommand
475− transformed <- applyMacros' rawcommand
703+ -- transformed <- applyMacros' rawcommand -- TODO or get rid of
476− exts <- getOption readerExtensions
704+ -- exts <- getOption readerExtensions
477− if transformed /= rawcommand
705+ -- if transformed /= rawcommand
478− then parseFromString' inlines transformed
706+ -- then parseFromString' inlines transformed
479− else if extensionEnabled Ext_raw_tex exts
707+ -- else if extensionEnabled Ext_raw_tex exts
480− then return $ rawInline "latex" rawcommand
708+ -- then return $ rawInline "latex" rawcommand
481− else ignore rawcommand
709+ -- else ignore rawcommand
482− (lookupListDefault raw [name',name] inlineCommands <*
710+ lookupListDefault raw names inlineCommands
712+tok :: PandocMonad m => LP m Inlines
713+tok = try $ grouped inline <|> inlineCommand' <|> singleChar
714+ where singleChar = do
715+ Tok (lin,col) toktype t <- satisfyTok (tokTypeIn [Word, Symbol])
718+ let (t1, t2) = (T.take 1 t, T.drop 1 t)
720+ setInput $ (Tok (lin, col + 1) toktype t2) : inp
721+ return $ str (T.unpack t1)
722+ else return $ str (T.unpack t)
724+opt :: PandocMonad m => LP m Inlines
725+opt = bracketed inline
727+rawopt :: PandocMonad m => LP m Text
730+ inner <- untokenize <$> manyTill anyTok (symbol ']')
483− optional (try (string "{}")))
731+ optional sp
484−
732+ return $ "[" <> inner <> "]"
485−rawInlineOr :: PandocMonad m => String -> LP m Inlines -> LP m Inlines
733+
486−rawInlineOr name' fallback = do
734+skipopts :: PandocMonad m => LP m ()
487− parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
735+skipopts = skipMany rawopt
489− then rawInline "latex" <$> getRawCommand name'
737+-- eat an optional argument and one or more arguments in braces
490− else fallback
738+ignoreInlines :: PandocMonad m => Text -> (Text, LP m Inlines)
739+ignoreInlines name = (name, p)
740+ where p = do oa <- optargs
741+ let rawCommand = '\\' : T.unpack (name <> oa)
742+ let doraw = guardRaw >> return (rawInline "latex" rawCommand)
743+ doraw <|> ignore rawCommand
745+guardRaw :: PandocMonad m => LP m ()
746+guardRaw = getOption readerExtensions >>= guard . extensionEnabled Ext_raw_tex
748+optargs :: PandocMonad m => LP m Text
750+ (_, raw) <- withRaw (skipopts *> skipMany (try $ optional sp *> braced))
751+ return $ untokenize raw
753+-- opts in angle brackets are used in beamer
754+rawangle :: PandocMonad m => LP m ()
757+ () <$ manyTill anyTok (symbol '>')
759+skipangles :: PandocMonad m => LP m ()
760+skipangles = skipMany rawangle
762+ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a
765+ report $ SkippedContent raw pos
768+withRaw :: PandocMonad m => LP m a -> LP m (a, [Tok])
772+ nxt <- option (Tok (0,0) Word "") (lookAhead anyTok)
773+ let raw = takeWhile (/= nxt) inp
774+ return (result, raw)
492−isBlockCommand :: String -> Bool
776+inBrackets :: Inlines -> Inlines
493−isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Blocks))
777+inBrackets x = str "[" <> x <> str "]"
779+unescapeURL :: String -> String
780+unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
781+ where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
782+unescapeURL (x:xs) = x:unescapeURL xs
785+mathEnvWith :: PandocMonad m
786+ => (Inlines -> a) -> Maybe String -> String -> LP m a
787+mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
788+ where inner x = case innerEnv of
790+ Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
791+ "\\end{" ++ y ++ "}"
793+mathEnv :: PandocMonad m => String -> LP m String
797+ let endEnv = try $ controlSeq "end" *>
798+ (T.unpack . untokenize <$> braced) >>= guard . (== name)
799+ res <- manyTill anyTok endEnv
800+ return $ stripTrailingNewlines $ T.unpack $ untokenize res
802+inlineEnvironment :: PandocMonad m => LP m Inlines
803+inlineEnvironment = try $ do
805+ name <- untokenize <$> braced
806+ M.findWithDefault mzero name inlineEnvironments
496−inlineEnvironments :: PandocMonad m => M.Map String (LP m Inlines)
808+inlineEnvironments :: PandocMonad m => M.Map Text (LP m Inlines)
497−inlineEnvironments = M.fromList
809+inlineEnvironments = M.fromList [
498− [ ("displaymath", mathEnvWith id Nothing "displaymath")
810+ ("displaymath", mathEnvWith id Nothing "displaymath")
499 , ("math", math <$> mathEnv "math")
811 , ("math", math <$> mathEnv "math")
500 , ("equation", mathEnvWith id Nothing "equation")
812 , ("equation", mathEnvWith id Nothing "equation")
501 , ("equation*", mathEnvWith id Nothing "equation*")
813 , ("equation*", mathEnvWith id Nothing "equation*")
@@ -511,7 +823,7 @@ inlineEnvironments = M.fromList
511 , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
823 , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
514−inlineCommands :: PandocMonad m => M.Map String (LP m Inlines)
826+inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
515inlineCommands = M.fromList $
827inlineCommands = M.fromList $
516 [ ("emph", extractSpaces emph <$> tok)
828 [ ("emph", extractSpaces emph <$> tok)
517 , ("textit", extractSpaces emph <$> tok)
829 , ("textit", extractSpaces emph <$> tok)
@@ -540,9 +852,9 @@ inlineCommands = M.fromList $
540 , ("textgreek", tok)
852 , ("textgreek", tok)
541 , ("sep", lit ",")
853 , ("sep", lit ",")
542 , ("cref", rawInlineOr "cref" (inBrackets <$> tok)) -- from cleveref.sty
854 , ("cref", rawInlineOr "cref" (inBrackets <$> tok)) -- from cleveref.sty
543− , ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
855+ , ("(", mathInline . toksToString <$> manyTill anyTok (controlSeq ")"))
544− , ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
856+ , ("[", mathDisplay . toksToString <$> manyTill anyTok (controlSeq "]"))
545− , ("ensuremath", mathInline braced)
857+ , ("ensuremath", mathInline . toksToString <$> braced)
546 , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok)
858 , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok)
547 , ("P", lit "¶")
859 , ("P", lit "¶")
548 , ("S", lit "§")
860 , ("S", lit "§")
@@ -592,7 +904,7 @@ inlineCommands = M.fromList $
592 , ("v", option (str "v") $ try $ tok >>= accent hacek)
904 , ("v", option (str "v") $ try $ tok >>= accent hacek)
593 , ("u", option (str "u") $ try $ tok >>= accent breve)
905 , ("u", option (str "u") $ try $ tok >>= accent breve)
594 , ("i", lit "i")
906 , ("i", lit "i")
595− , ("\\", linebreak <$ (optional (bracketed inline) *> spaces'))
907+ , ("\\", linebreak <$ (optional (bracketed inline) *> spaces))
596 , (",", lit "\8198")
908 , (",", lit "\8198")
597 , ("@", pure mempty)
909 , ("@", pure mempty)
598 , (" ", lit "\160")
910 , (" ", lit "\160")
@@ -607,73 +919,73 @@ inlineCommands = M.fromList $
607 , ("verb", doverb)
919 , ("verb", doverb)
608 , ("lstinline", dolstinline)
920 , ("lstinline", dolstinline)
609 , ("Verb", doverb)
921 , ("Verb", doverb)
610− , ("url", (unescapeURL <$> braced) >>= \url ->
922+ , ("url", ((unescapeURL . T.unpack . untokenize) <$> braced) >>= \url ->
611− pure (link url "" (str url)))
923+ pure (link url "" (str url)))
612− , ("href", (unescapeURL <$> braced <* optional sp) >>= \url ->
924+-- , ("href", (unescapeURL <$> braced <* optional sp) >>= \url ->
613− tok >>= \lab ->
925+-- tok >>= \lab ->
614− pure (link url "" lab))
926+-- pure (link url "" lab))
615− , ("includegraphics", do options <- option [] keyvals
927+-- , ("includegraphics", do options <- option [] keyvals
616− src <- unescapeURL . removeDoubleQuotes <$> braced
928+-- src <- unescapeURL . removeDoubleQuotes <$> braced
617− mkImage options src)
929+-- mkImage options src)
618 , ("enquote", enquote)
930 , ("enquote", enquote)
619− , ("cite", citation "cite" NormalCitation False)
931+-- , ("cite", citation "cite" NormalCitation False)
620− , ("Cite", citation "Cite" NormalCitation False)
932+-- , ("Cite", citation "Cite" NormalCitation False)
621− , ("citep", citation "citep" NormalCitation False)
933+-- , ("citep", citation "citep" NormalCitation False)
622− , ("citep*", citation "citep*" NormalCitation False)
934+-- , ("citep*", citation "citep*" NormalCitation False)
623− , ("citeal", citation "citeal" NormalCitation False)
935+-- , ("citeal", citation "citeal" NormalCitation False)
624− , ("citealp", citation "citealp" NormalCitation False)
936+-- , ("citealp", citation "citealp" NormalCitation False)
625− , ("citealp*", citation "citealp*" NormalCitation False)
937+-- , ("citealp*", citation "citealp*" NormalCitation False)
626− , ("autocite", citation "autocite" NormalCitation False)
938+-- , ("autocite", citation "autocite" NormalCitation False)
627− , ("smartcite", citation "smartcite" NormalCitation False)
939+-- , ("smartcite", citation "smartcite" NormalCitation False)
628− , ("footcite", inNote <$> citation "footcite" NormalCitation False)
940+-- , ("footcite", inNote <$> citation "footcite" NormalCitation False)
629− , ("parencite", citation "parencite" NormalCitation False)
941+-- , ("parencite", citation "parencite" NormalCitation False)
630− , ("supercite", citation "supercite" NormalCitation False)
942+-- , ("supercite", citation "supercite" NormalCitation False)
631− , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
943+-- , ("footcitetext", inNote <$> citation "footcitetext" NormalCitation False)
632− , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
944+-- , ("citeyearpar", citation "citeyearpar" SuppressAuthor False)
633− , ("citeyear", citation "citeyear" SuppressAuthor False)
945+-- , ("citeyear", citation "citeyear" SuppressAuthor False)
634− , ("autocite*", citation "autocite*" SuppressAuthor False)
946+-- , ("autocite*", citation "autocite*" SuppressAuthor False)
635− , ("cite*", citation "cite*" SuppressAuthor False)
947+-- , ("cite*", citation "cite*" SuppressAuthor False)
636− , ("parencite*", citation "parencite*" SuppressAuthor False)
948+-- , ("parencite*", citation "parencite*" SuppressAuthor False)
637− , ("textcite", citation "textcite" AuthorInText False)
949+-- , ("textcite", citation "textcite" AuthorInText False)
638− , ("citet", citation "citet" AuthorInText False)
950+-- , ("citet", citation "citet" AuthorInText False)
639− , ("citet*", citation "citet*" AuthorInText False)
951+-- , ("citet*", citation "citet*" AuthorInText False)
640− , ("citealt", citation "citealt" AuthorInText False)
952+-- , ("citealt", citation "citealt" AuthorInText False)
641− , ("citealt*", citation "citealt*" AuthorInText False)
953+-- , ("citealt*", citation "citealt*" AuthorInText False)
642− , ("textcites", citation "textcites" AuthorInText True)
954+-- , ("textcites", citation "textcites" AuthorInText True)
643− , ("cites", citation "cites" NormalCitation True)
955+-- , ("cites", citation "cites" NormalCitation True)
644− , ("autocites", citation "autocites" NormalCitation True)
956+-- , ("autocites", citation "autocites" NormalCitation True)
645− , ("footcites", inNote <$> citation "footcites" NormalCitation True)
957+-- , ("footcites", inNote <$> citation "footcites" NormalCitation True)
646− , ("parencites", citation "parencites" NormalCitation True)
958+-- , ("parencites", citation "parencites" NormalCitation True)
647− , ("supercites", citation "supercites" NormalCitation True)
959+-- , ("supercites", citation "supercites" NormalCitation True)
648− , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
960+-- , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
649− , ("Autocite", citation "Autocite" NormalCitation False)
961+-- , ("Autocite", citation "Autocite" NormalCitation False)
650− , ("Smartcite", citation "Smartcite" NormalCitation False)
962+-- , ("Smartcite", citation "Smartcite" NormalCitation False)
651− , ("Footcite", citation "Footcite" NormalCitation False)
963+-- , ("Footcite", citation "Footcite" NormalCitation False)
652− , ("Parencite", citation "Parencite" NormalCitation False)
964+-- , ("Parencite", citation "Parencite" NormalCitation False)
653− , ("Supercite", citation "Supercite" NormalCitation False)
965+-- , ("Supercite", citation "Supercite" NormalCitation False)
654− , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
966+-- , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
655− , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
967+-- , ("Citeyearpar", citation "Citeyearpar" SuppressAuthor False)
656− , ("Citeyear", citation "Citeyear" SuppressAuthor False)
968+-- , ("Citeyear", citation "Citeyear" SuppressAuthor False)
657− , ("Autocite*", citation "Autocite*" SuppressAuthor False)
969+-- , ("Autocite*", citation "Autocite*" SuppressAuthor False)
658− , ("Cite*", citation "Cite*" SuppressAuthor False)
970+-- , ("Cite*", citation "Cite*" SuppressAuthor False)
659− , ("Parencite*", citation "Parencite*" SuppressAuthor False)
971+-- , ("Parencite*", citation "Parencite*" SuppressAuthor False)
660− , ("Textcite", citation "Textcite" AuthorInText False)
972+-- , ("Textcite", citation "Textcite" AuthorInText False)
661− , ("Textcites", citation "Textcites" AuthorInText True)
973+-- , ("Textcites", citation "Textcites" AuthorInText True)
662− , ("Cites", citation "Cites" NormalCitation True)
974+-- , ("Cites", citation "Cites" NormalCitation True)
663− , ("Autocites", citation "Autocites" NormalCitation True)
975+-- , ("Autocites", citation "Autocites" NormalCitation True)
664− , ("Footcites", citation "Footcites" NormalCitation True)
976+-- , ("Footcites", citation "Footcites" NormalCitation True)
665− , ("Parencites", citation "Parencites" NormalCitation True)
977+-- , ("Parencites", citation "Parencites" NormalCitation True)
666− , ("Supercites", citation "Supercites" NormalCitation True)
978+-- , ("Supercites", citation "Supercites" NormalCitation True)
667− , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
979+-- , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
668− , ("citetext", complexNatbibCitation NormalCitation)
980+-- , ("citetext", complexNatbibCitation NormalCitation)
669− , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
981+-- , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
670− complexNatbibCitation AuthorInText)
982+-- complexNatbibCitation AuthorInText)
671− <|> citation "citeauthor" AuthorInText False)
983+-- <|> citation "citeauthor" AuthorInText False)
672− , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
984+-- , ("nocite", mempty <$ (citation "nocite" NormalCitation False >>=
673− addMeta "nocite"))
985+-- addMeta "nocite"))
674 , ("hypertarget", braced >> tok)
986 , ("hypertarget", braced >> tok)
675− -- siuntix
987+-- -- siuntix
676− , ("SI", dosiunitx)
988+-- , ("SI", dosiunitx)
677 -- hyphenat
989 -- hyphenat
678 , ("bshyp", lit "\\\173")
990 , ("bshyp", lit "\\\173")
679 , ("fshyp", lit "/\173")
991 , ("fshyp", lit "/\173")
@@ -700,543 +1012,137 @@ inlineCommands = M.fromList $
700ttfamily :: PandocMonad m => LP m Inlines
1012ttfamily :: PandocMonad m => LP m Inlines
701ttfamily = (code . stringify . toList) <$> tok
1013ttfamily = (code . stringify . toList) <$> tok
703−mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
1015+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
704−mkImage options src = do
1016+rawInlineOr name' fallback = do
705− let replaceTextwidth (k,v) = case numUnit v of
1017+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
706− Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
1018+ if parseRaw
707− _ -> (k, v)
1019+ then rawInline "latex" <$> getRawCommand name'
708− let kvs = map replaceTextwidth $ filter (\(k,_) -> k `elem` ["width", "height"]) options
1020+ else fallback
709− let attr = ("",[], kvs)
710− let alt = str "image"
711− case takeExtension src of
713− defaultExt <- getOption readerDefaultImageExtension
714− return $ imageWith attr (addExtension src defaultExt) "" alt
715− _ -> return $ imageWith attr src "" alt
717−inNote :: Inlines -> Inlines
719− note $ para $ ils <> str "."
721−unescapeURL :: String -> String
1022+getRawCommand :: PandocMonad m => Text -> LP m String
722−unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
1023+getRawCommand name' = do
723− where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
1024+ (_, rawargs) <- withRaw
724−unescapeURL (x:xs) = x:unescapeURL xs
1025+ (many (try (optional sp *> opt)) *>
725−unescapeURL [] = ""
1026+ option "" (try (optional sp *> dimenarg)) *>
1028+ return $ '\\' : T.unpack (name' <> untokenize rawargs)
727−enquote :: PandocMonad m => LP m Inlines
1030+isBlockCommand :: Text -> Bool
728−enquote = do
1031+isBlockCommand s =
729− skipopts
1032+ s `M.member` (blockCommands :: M.Map Text (LP PandocPure Blocks))
730− context <- stateQuoteContext <$> getState
731− if context == InDoubleQuote
732− then singleQuoted <$> withQuoteContext InSingleQuote tok
733− else doubleQuoted <$> withQuoteContext InDoubleQuote tok
735−doverb :: PandocMonad m => LP m Inlines
1034+lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
736−doverb = do
1035+lookupListDefault d = (fromMaybe d .) . lookupList
737− marker <- anyChar
1036+ where
738− code <$> manyTill (satisfy (/='\n')) (char marker)
1037+ lookupList l m = msum $ map (`M.lookup` m) l
740−dolstinline :: PandocMonad m => LP m Inlines
1039+inline :: PandocMonad m => LP m Inlines
741−dolstinline = do
1040+inline = (mempty <$ comment)
742− options <- option [] keyvals
1041+ <|> (space <$ whitespace)
743− let classes = maybeToList $ lookup "language" options >>= fromListingsLanguage
1042+ <|> (softbreak <$ endline)
744− marker <- char '{' <|> anyChar
1043+ <|> inlineText
745− codeWith ("",classes,[]) <$> manyTill (satisfy (/='\n')) (char '}' <|> char marker)
1044+ <|> inlineCommand'
1045+ <|> inlineEnvironment
1048+ option (str "-") (symbol '-' *>
1049+ option (str "–") (str "—" <$ symbol '-')))
1052+ <|> (str "”" <$ try (symbol '\'' >> symbol '\''))
1053+ <|> (str "”" <$ symbol '”')
1054+ <|> (str "’" <$ symbol '\'')
1055+ <|> (str "’" <$ symbol '’')
1056+ <|> (str "\160" <$ symbol '~')
1058+ <|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
1059+ <|> (str . (:[]) <$> primEscape)
1060+ <|> (do res <- symbolIn "#&~^'`\"[]"
1062+ let s = T.unpack (untoken res)
1063+ report $ ParsingUnescaped s pos
747−doLHSverb :: PandocMonad m => LP m Inlines
1066+inlines :: PandocMonad m => LP m Inlines
748−doLHSverb = codeWith ("",["haskell"],[]) <$> manyTill (satisfy (/='\n')) (char '|')
1067+inlines = mconcat <$> many inline
750−-- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
1069+-- PREVIOUSLY HAD (notFollowedBy (char '}') *> inline)
751−dosiunitx :: PandocMonad m => LP m Inlines
755− valueprefix <- option "" $ char '[' >> (mconcat <$> manyTill tok (char ']'))
757− let emptyOr160 "" = ""
758− emptyOr160 _ = "\160"
759− return . mconcat $ [valueprefix,
760− emptyOr160 valueprefix,
765−lit :: String -> LP m Inlines
1071+-- block elements:
768−accent :: (Char -> String) -> Inlines -> LP m Inlines
1073+paragraph :: PandocMonad m => LP m Blocks
769−accent f ils =
1074+paragraph = do
770− case toList ils of
1075+ x <- trimInlines . mconcat <$> many1 inline
771− (Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
1076+ if x == mempty
772− [] -> mzero
1077+ then return mempty
773− _ -> return ils
1078+ else return $ para x
775−grave :: Char -> String
1080+include :: PandocMonad m => LP m Blocks
776−grave 'A' = "À"
1081+include = do
777−grave 'E' = "È"
1082+ (Tok _ _ name) <- controlSeq "include" <|> controlSeq "input" <|>
778−grave 'I' = "Ì"
1083+ controlSeq "subfile" <|> controlSeq "usepackage"
779−grave 'O' = "Ò"
1084+ skipMany $ bracketed inline -- skip options
780−grave 'U' = "Ù"
1085+ fs <- (map trim . splitBy (==',') . T.unpack . untokenize) <$> braced
781−grave 'a' = "à"
1086+ let fs' = if name == "\\usepackage"
782−grave 'e' = "è"
1087+ then map (maybeAddExtension ".sty") fs
783−grave 'i' = "ì"
1088+ else map (maybeAddExtension ".tex") fs
784−grave 'o' = "ò"
1089+ dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
785−grave 'u' = "ù"
1090+ mconcat <$> mapM (insertIncludedFile blocks (tokenize . T.pack) dirs) fs'
788−acute :: Char -> String
1092+maybeAddExtension :: String -> FilePath -> FilePath
789−acute 'A' = "Á"
1093+maybeAddExtension ext fp =
790−acute 'E' = "É"
1094+ if null (takeExtension fp)
791−acute 'I' = "Í"
1095+ then addExtension fp ext
792−acute 'O' = "Ó"
1096+ else fp
815−circ :: Char -> String
1098+ignoreBlocks :: PandocMonad m => Text -> (Text, LP m Blocks)
816−circ 'A' = "Â"
1099+ignoreBlocks name = (name, p)
817−circ 'E' = "Ê"
1100+ where
818−circ 'I' = "Î"
1101+ p = do oa <- optargs
819−circ 'O' = "Ô"
1102+ let rawCommand = '\\' : T.unpack (name <> oa)
820−circ 'U' = "Û"
1103+ let doraw = guardRaw >> return (rawBlock "latex" rawCommand)
821−circ 'a' = "â"
1104+ doraw <|> ignore rawCommand
842−tilde :: Char -> String
855−umlaut :: Char -> String
868−hungarumlaut :: Char -> String
869−hungarumlaut 'A' = "A̋"
870−hungarumlaut 'E' = "E̋"
871−hungarumlaut 'I' = "I̋"
872−hungarumlaut 'O' = "Ő"
873−hungarumlaut 'U' = "Ű"
874−hungarumlaut 'Y' = "ӳ"
875−hungarumlaut 'a' = "a̋"
876−hungarumlaut 'e' = "e̋"
877−hungarumlaut 'i' = "i̋"
878−hungarumlaut 'o' = "ő"
879−hungarumlaut 'u' = "ű"
880−hungarumlaut 'y' = "ӳ"
883−dot :: Char -> String
895−macron :: Char -> String
908−cedilla :: Char -> String
923−hacek :: Char -> String
959−breve :: Char -> String
974−tok :: PandocMonad m => LP m Inlines
975−tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
977−opt :: PandocMonad m => LP m Inlines
978−opt = bracketed inline
980−rawopt :: PandocMonad m => LP m String
982− contents <- bracketed (many1 (noneOf "[]") <|> try (string "\\]") <|>
983− try (string "\\[") <|> rawopt)
985− return $ "[" ++ contents ++ "]"
987−skipopts :: PandocMonad m => LP m ()
988−skipopts = skipMany rawopt
990−-- opts in angle brackets are used in beamer
991−rawangle :: PandocMonad m => LP m ()
994− skipMany (noneOf ">")
998−skipangles :: PandocMonad m => LP m ()
999−skipangles = skipMany rawangle
1001−inlineText :: PandocMonad m => LP m Inlines
1002−inlineText = str <$> many1 inlineChar
1004−inlineChar :: PandocMonad m => LP m Char
1005−inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
1007−environment :: PandocMonad m => LP m Blocks
1011− M.findWithDefault mzero name environments
1014−inlineEnvironment :: PandocMonad m => LP m Inlines
1015−inlineEnvironment = try $ do
1018− M.findWithDefault mzero name inlineEnvironments
1020−rawEnv :: PandocMonad m => String -> LP m Blocks
1022− exts <- getOption readerExtensions
1023− let parseRaw = extensionEnabled Ext_raw_tex exts
1024− rawOptions <- mconcat <$> many rawopt
1025− let beginCommand = "\\begin{" ++ name ++ "}" ++ rawOptions
1026− pos1 <- getPosition
1027− (bs, raw) <- withRaw $ env name blocks
1028− raw' <- applyMacros' $ beginCommand ++ raw
1029− if raw' /= beginCommand ++ raw
1030− then parseFromString' blocks raw'
1032− then return $ rawBlock "latex" $ beginCommand ++ raw'
1034− unless parseRaw $ do
1035− report $ SkippedContent beginCommand pos1
1036− pos2 <- getPosition
1037− report $ SkippedContent ("\\end{" ++ name ++ "}") pos2
1040−rawVerbEnv :: PandocMonad m => String -> LP m Blocks
1041−rawVerbEnv name = do
1043− (_, raw) <- withRaw $ verbEnv name
1044− let raw' = "\\begin{tikzpicture}" ++ raw
1045− exts <- getOption readerExtensions
1046− let parseRaw = extensionEnabled Ext_raw_tex exts
1048− then return $ rawBlock "latex" raw'
1050− report $ SkippedContent raw' pos
1055−maybeAddExtension :: String -> FilePath -> FilePath
1056−maybeAddExtension ext fp =
1057− if null (takeExtension fp)
1058− then addExtension fp ext
1061−include :: PandocMonad m => LP m Blocks
1065− name <- try (string "include")
1066− <|> try (string "input")
1067− <|> try (string "subfile")
1068− <|> string "usepackage"
1070− skipMany $ try $ char '[' *> manyTill anyChar (char ']')
1071− fs <- (map trim . splitBy (==',')) <$> braced
1072− return $ if name == "usepackage"
1073− then map (maybeAddExtension ".sty") fs
1074− else map (maybeAddExtension ".tex") fs
1075− dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
1076− mconcat <$> mapM (insertIncludedFile blocks dirs) fs'
1078−inputListing :: PandocMonad m => LP m Blocks
1081− options <- option [] keyvals
1082− f <- filter (/='"') <$> braced
1083− dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
1084− mbCode <- readFileFromDirs dirs f
1085− codeLines <- case mbCode of
1086− Just s -> return $ lines s
1088− report $ CouldNotLoadIncludeFile f pos
1090− let (ident,classes,kvs) = parseListingsOptions options
1091− let language = case lookup "language" options >>= fromListingsLanguage of
1093− Nothing -> take 1 $ languagesByExtension (takeExtension f)
1094− let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1095− let lastline = fromMaybe (length codeLines) $
1096− lookup "lastline" options >>= safeRead
1097− let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
1098− drop (firstline - 1) codeLines
1099− return $ codeBlockWith (ident,ordNub (classes ++ language),kvs) codeContents
1101−parseListingsOptions :: [(String, String)] -> Attr
1102−parseListingsOptions options =
1103− let kvs = [ (if k == "firstnumber"
1105− else k, v) | (k,v) <- options ]
1106− classes = [ "numberLines" |
1107− lookup "numbers" options == Just "left" ]
1108− ++ maybeToList (lookup "language" options
1109− >>= fromListingsLanguage)
1110− in (fromMaybe "" (lookup "label" options), classes, kvs)
1114−keyval :: PandocMonad m => LP m (String, String)
1116− key <- many1 alphaNum
1117− val <- option "" $ char '=' >> braced <|> (many1 (alphaNum <|> oneOf ".:-|\\"))
1119− optional (char ',')
1106+addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1107+addMeta field val = updateState $ \st ->
1108+ st{ stateMeta = addMetaField field val $ stateMeta st }
1124−keyvals :: PandocMonad m => LP m [(String, String)]
1110+authors :: PandocMonad m => LP m ()
1125−keyvals = try $ char '[' *> manyTill keyval (char ']')
1111+authors = try $ do
1127−alltt :: PandocMonad m => String -> LP m Blocks
1113+ let oneAuthor = mconcat <$>
1128−alltt t = walk strToCode <$> parseFromString' blocks
1114+ many1 (notFollowedBy' (controlSeq "and") >>
1129− (substitute " " "\\ " $ substitute "%" "\\%" $
1115+ (inline <|> mempty <$ blockCommand))
1130− intercalate "\\\\\n" $ lines t)
1116+ -- skip e.g. \vspace{10pt}
1131− where strToCode (Str s) = Code nullAttr s
1117+ auths <- sepBy oneAuthor (controlSeq "and")
1132− strToCode x = x
1118+ egroup
1133−
1119+ addMeta "author" (map trimInlines auths)
1134−rawLaTeXBlock :: PandocMonad m => LP m String
1135−rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
1137−rawLaTeXInline :: PandocMonad m => LP m Inline
1139− raw <- (snd <$> withRaw inlineCommand)
1140− <|> (snd <$> withRaw inlineEnvironment)
1141− <|> (snd <$> withRaw blockCommand)
1142− RawInline "latex" <$> applyMacros' raw
1144−addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
1145−addImageCaption = walkM go
1146− where go (Image attr alt (src,tit))
1147− | not ("fig:" `isPrefixOf` tit) = do
1148− mbcapt <- stateCaption <$> getState
1149− return $ case mbcapt of
1150− Just ils -> Image attr (toList ils) (src, "fig:" ++ tit)
1151− Nothing -> Image attr alt (src,tit)
1154−addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
1155−addTableCaption = walkM go
1156− where go (Table c als ws hs rs) = do
1157− mbcapt <- stateCaption <$> getState
1158− return $ case mbcapt of
1159− Just ils -> Table (toList ils) als ws hs rs
1160− Nothing -> Table c als ws hs rs
1163−environments :: PandocMonad m => M.Map String (LP m Blocks)
1164−environments = M.fromList
1165− [ ("document", env "document" blocks <* skipMany anyChar)
1166− , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
1167− , ("letter", env "letter" letterContents)
1168− , ("minipage", env "minipage" $
1169− skipopts *> spaces' *> optional braced *> spaces' *> blocks)
1170− , ("figure", env "figure" $ skipopts *> figure)
1171− , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
1172− , ("center", env "center" blocks)
1173− , ("longtable", env "longtable" $
1174− resetCaption *> simpTable "longtable" False >>= addTableCaption)
1175− , ("table", env "table" $
1176− resetCaption *> skipopts *> blocks >>= addTableCaption)
1177− , ("tabular*", env "tabular" $ simpTable "tabular*" True)
1178− , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
1179− , ("tabular", env "tabular" $ simpTable "tabular" False)
1180− , ("quote", blockQuote <$> env "quote" blocks)
1181− , ("quotation", blockQuote <$> env "quotation" blocks)
1182− , ("verse", blockQuote <$> env "verse" blocks)
1183− , ("itemize", bulletList <$> listenv "itemize" (many item))
1184− , ("description", definitionList <$> listenv "description" (many descItem))
1185− , ("enumerate", orderedList')
1186− , ("alltt", alltt =<< verbEnv "alltt")
1187− , ("code", guardEnabled Ext_literate_haskell *>
1188− (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
1190− , ("comment", mempty <$ verbEnv "comment")
1191− , ("verbatim", codeBlock <$> verbEnv "verbatim")
1192− , ("Verbatim", fancyverbEnv "Verbatim")
1193− , ("BVerbatim", fancyverbEnv "BVerbatim")
1194− , ("lstlisting", do attr <- parseListingsOptions <$> option [] keyvals
1195− codeBlockWith attr <$> verbEnv "lstlisting")
1196− , ("minted", do options <- option [] keyvals
1197− lang <- grouped (many1 $ satisfy (/='}'))
1198− let kvs = [ (if k == "firstnumber"
1200− else k, v) | (k,v) <- options ]
1201− let classes = [ lang | not (null lang) ] ++
1203− lookup "linenos" options == Just "true" ]
1204− let attr = ("",classes,kvs)
1205− codeBlockWith attr <$> verbEnv "minted")
1206− , ("obeylines", parseFromString
1207− (para . trimInlines . mconcat <$> many inline) =<<
1208− intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
1209− , ("displaymath", mathEnvWith para Nothing "displaymath")
1210− , ("equation", mathEnvWith para Nothing "equation")
1211− , ("equation*", mathEnvWith para Nothing "equation*")
1212− , ("gather", mathEnvWith para (Just "gathered") "gather")
1213− , ("gather*", mathEnvWith para (Just "gathered") "gather*")
1214− , ("multline", mathEnvWith para (Just "gathered") "multline")
1215− , ("multline*", mathEnvWith para (Just "gathered") "multline*")
1216− , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
1217− , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
1218− , ("align", mathEnvWith para (Just "aligned") "align")
1219− , ("align*", mathEnvWith para (Just "aligned") "align*")
1220− , ("alignat", mathEnvWith para (Just "aligned") "alignat")
1221− , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
1222− , ("tikzpicture", rawVerbEnv "tikzpicture")
1225−figure :: PandocMonad m => LP m Blocks
1121+section :: PandocMonad m => Attr -> Int -> LP m Blocks
1226−figure = try $ do
1122+section (ident, classes, kvs) lvl = do
1227− resetCaption
1123+ skipopts
1228− blocks >>= addImageCaption
1124+ contents <- grouped inline
1125+ lab <- option ident $
1126+ try (spaces >> controlSeq "label"
1127+ >> spaces >> toksToString <$> braced)
1128+ attr' <- registerHeader (lab, classes, kvs) contents
1129+ return $ headerWith attr' lvl contents
1230−letterContents :: PandocMonad m => LP m Blocks
1131+blockCommand :: PandocMonad m => LP m Blocks
1231−letterContents = do
1132+blockCommand = try $ do
1232− bs <- blocks
1133+ Tok _ CtrlSeq name <- anyControlSeq
1233− st <- getState
1134+ guard $ name /= "\\begin" && name /= "\\end"
1234− -- add signature (author) and address (title)
1135+ star <- option "" ("*" <$ symbol '*' <* optional sp)
1235− let addr = case lookupMeta "address" (stateMeta st) of
1136+ let name' = name <> star
1236− Just (MetaBlocks [Plain xs]) ->
1137+ let names = name : [name' | name' /= name]
1237− para $ trimInlines $ fromList xs
1138+ let raw = rawBlock "latex" <$> getRawCommand name'
1238− _ -> mempty
1139+ -- TODO do we still need this?
1239− return $ addr <> bs -- sig added by \closing
1140+ -- rawcommand <- getRawCommand name'
1141+ -- transformed <- applyMacros' rawcommand
1142+ -- guard $ transformed /= rawcommand
1143+ -- notFollowedBy $ parseFromString' inlines transformed
1144+ -- parseFromString' blocks transformed
1145+ lookupListDefault raw names blockCommands
1241closing :: PandocMonad m => LP m Blocks
1147closing :: PandocMonad m => LP m Blocks
1242closing = do
1148closing = do
@@ -1252,321 +1158,1316 @@ closing = do
1252 _ -> mempty
1158 _ -> mempty
1253 return $ para (trimInlines contents) <> sigs
1159 return $ para (trimInlines contents) <> sigs
1255−item :: PandocMonad m => LP m Blocks
1161+blockCommands :: PandocMonad m => M.Map Text (LP m Blocks)
1256−item = blocks *> controlSeq "item" *> skipopts *> blocks
1162+blockCommands = M.fromList $
1257−
1163+ [ ("par", mempty <$ skipopts)
1258−looseItem :: PandocMonad m => LP m Blocks
1164+ , ("parbox", braced >> grouped blocks)
1259−looseItem = do
1165+ , ("title", mempty <$ (skipopts *>
1260− ctx <- stateParserContext `fmap` getState
1166+ (grouped inline >>= addMeta "title")
1261− if ctx == ListItemState
1167+ <|> (grouped block >>= addMeta "title")))
1262− then mzero
1168+ , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
1263− else return mempty
1169+ , ("author", mempty <$ (skipopts *> authors))
1264−
1170+ -- -- in letter class, temp. store address & sig as title, author
1265−descItem :: PandocMonad m => LP m (Inlines, [Blocks])
1171+ , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
1266−descItem = do
1172+ , ("signature", mempty <$ (skipopts *> authors))
1267− blocks -- skip blocks before item
1173+ , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
1268− controlSeq "item"
1174+ -- Koma-script metadata commands
1269− optional sp
1175+ , ("dedication", mempty <$ (skipopts *> tok >>= addMeta "dedication"))
1270− ils <- opt
1176+ -- sectioning
1271− bs <- blocks
1177+ , ("part", section nullAttr (-1))
1272− return (ils, [bs])
1178+ , ("part*", section nullAttr (-1))
1273−
1179+ , ("chapter", section nullAttr 0)
1274−env :: PandocMonad m => String -> LP m a -> LP m a
1180+ , ("chapter*", section ("",["unnumbered"],[]) 0)
1275−env name p = p <*
1181+ , ("section", section nullAttr 1)
1276− (try (controlSeq "end" *> braced >>= guard . (== name))
1182+ , ("section*", section ("",["unnumbered"],[]) 1)
1277− <?> ("\\end{" ++ name ++ "}"))
1183+ , ("subsection", section nullAttr 2)
1278−
1184+ , ("subsection*", section ("",["unnumbered"],[]) 2)
1279−listenv :: PandocMonad m => String -> LP m a -> LP m a
1185+ , ("subsubsection", section nullAttr 3)
1280−listenv name p = try $ do
1186+ , ("subsubsection*", section ("",["unnumbered"],[]) 3)
1281− oldCtx <- stateParserContext `fmap` getState
1187+ , ("paragraph", section nullAttr 4)
1282− updateState $ \st -> st{ stateParserContext = ListItemState }
1188+ , ("paragraph*", section ("",["unnumbered"],[]) 4)
1283− res <- env name p
1189+ , ("subparagraph", section nullAttr 5)
1284− updateState $ \st -> st{ stateParserContext = oldCtx }
1190+ , ("subparagraph*", section ("",["unnumbered"],[]) 5)
1285− return res
1191+ -- beamer slides
1286−
1192+ , ("frametitle", section nullAttr 3)
1287−mathEnvWith :: PandocMonad m
1193+ , ("framesubtitle", section nullAttr 4)
1288− => (Inlines -> a) -> Maybe String -> String -> LP m a
1194+ -- letters
1289−mathEnvWith f innerEnv name = f <$> mathDisplay (inner <$> mathEnv name)
1195+ , ("opening", (para . trimInlines) <$> (skipopts *> tok))
1290− where inner x = case innerEnv of
1196+ , ("closing", skipopts *> closing)
1291− Nothing -> x
1197+ --
1292− Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
1198+ , ("hrule", pure horizontalRule)
1293− "\\end{" ++ y ++ "}"
1199+ , ("strut", pure mempty)
1294−
1200+ , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
1295−mathEnv :: PandocMonad m => String -> LP m String
1201+-- , ("item", skipopts *> looseItem)
1296−mathEnv name = do
1202+-- , ("documentclass", skipopts *> braced *> preamble)
1297− skipopts
1203+-- , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
1298− optional blankline
1204+-- , ("caption", skipopts *> setCaption)
1299− let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
1205+-- , ("bibliography", mempty <$ (skipopts *> braced >>=
1300− charMuncher = skipMany comment *>
1206+-- addMeta "bibliography" . splitBibs))
1301− (many1 (noneOf "\\%") <|> try (string "\\%")
1207+-- , ("addbibresource", mempty <$ (skipopts *> braced >>=
1302− <|> try (string "\\\\") <|> count 1 anyChar)
1208+-- addMeta "bibliography" . splitBibs))
1303− res <- concat <$> manyTill charMuncher endEnv
1209+-- -- includes
1304− return $ stripTrailingNewlines res
1210+-- , ("lstinputlisting", inputListing)
1305−
1211+-- , ("graphicspath", graphicsPath)
1306−verbEnv :: PandocMonad m => String -> LP m String
1212+-- -- hyperlink
1307−verbEnv name = do
1213+ , ("hypertarget", braced >> grouped block)
1308− skipopts
1214+ ] ++ map ignoreBlocks
1309− optional blankline
1215+ -- these commands will be ignored unless --parse-raw is specified,
1310− let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
1216+ -- in which case they will appear as raw latex blocks
1311− charMuncher = anyChar
1217+ [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
1312− res <- manyTill charMuncher endEnv
1218+ -- newcommand, etc. should be parsed by macro, but we need this
1313− return $ stripTrailingNewlines res
1219+ -- here so these aren't parsed as inline commands to ignore
1314−
1220+ , "special", "pdfannot", "pdfstringdef"
1315−fancyverbEnv :: PandocMonad m => String -> LP m Blocks
1221+ , "bibliographystyle"
1316−fancyverbEnv name = do
1222+ , "maketitle", "makeindex", "makeglossary"
1317− options <- option [] keyvals
1223+ , "addcontentsline", "addtocontents", "addtocounter"
1318− let kvs = [ (if k == "firstnumber"
1224+ -- \ignore{} is used conventionally in literate haskell for definitions
1319− then "startFrom"
1225+ -- that are to be processed by the compiler but not printed.
1320− else k, v) | (k,v) <- options ]
1226+ , "ignore"
1321− let classes = [ "numberLines" |
1227+ , "hyperdef"
1322− lookup "numbers" options == Just "left" ]
1228+ , "markboth", "markright", "markleft"
1323− let attr = ("",classes,kvs)
1229+ , "hspace", "vspace"
1324− codeBlockWith attr <$> verbEnv name
1230+ , "newpage"
1326−orderedList' :: PandocMonad m => LP m Blocks
1232+ , "pagebreak"
1327−orderedList' = try $ do
1233+ ]
1329− (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
1330− try $ char '[' *> anyOrderedListMarker <* char ']'
1332− optional $ try $ controlSeq "setlength" *> grouped (controlSeq "itemindent") *> braced
1334− start <- option 1 $ try $ do controlSeq "setcounter"
1335− grouped (string "enum" *> many1 (oneOf "iv"))
1337− num <- grouped (many1 digit)
1339− return (read num + 1 :: Int)
1340− bs <- listenv "enumerate" (many item)
1341− return $ orderedListWith (start, style, delim) bs
1343−paragraph :: PandocMonad m => LP m Blocks
1235+block :: PandocMonad m => LP m Blocks
1344−paragraph = do
1236+block = (mempty <$ spaces1)
1345− x <- trimInlines . mconcat <$> many1 inline
1237+ -- <|> environment
1346− if x == mempty
1238+ <|> include
1347− then return mempty
1239+ -- <|> macro
1348− else return $ para x
1240+ <|> blockCommand
1350−preamble :: PandocMonad m => LP m Blocks
1244+blocks :: PandocMonad m => LP m Blocks
1351−preamble = mempty <$> manyTill preambleBlock beginDoc
1245+blocks = mconcat <$> many block
1352− where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
1353− preambleBlock = void comment
1355− <|> void blanklines
1358− <|> void blockCommand
1359− <|> void anyControlSeq
1367−addPrefix :: [Inline] -> [Citation] -> [Citation]
1368−addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
1371−addSuffix :: [Inline] -> [Citation] -> [Citation]
1372−addSuffix s ks@(_:_) =
1374− in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
1377−simpleCiteArgs :: PandocMonad m => LP m [Citation]
1378−simpleCiteArgs = try $ do
1379− first <- optionMaybe $ toList <$> opt
1380− second <- optionMaybe $ toList <$> opt
1381− keys <- try $ bgroup *> (manyTill citationLabel egroup)
1382− let (pre, suf) = case (first , second ) of
1383− (Just s , Nothing) -> (mempty, s )
1384− (Just s , Just t ) -> (s , t )
1385− _ -> (mempty, mempty)
1386− conv k = Citation { citationId = k
1387− , citationPrefix = []
1388− , citationSuffix = []
1389− , citationMode = NormalCitation
1391− , citationNoteNum = 0
1393− return $ addPrefix pre $ addSuffix suf $ map conv keys
1395−citationLabel :: PandocMonad m => LP m String
1396−citationLabel = optional sp *>
1397− (many1 (satisfy isBibtexKeyChar)
1399− <* optional (char ',')
1401− where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
1403−cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
1404−cites mode multi = try $ do
1406− then many1 simpleCiteArgs
1407− else count 1 simpleCiteArgs
1408− let cs = concat cits
1409− return $ case mode of
1410− AuthorInText -> case cs of
1411− (c:rest) -> c {citationMode = mode} : rest
1413− _ -> map (\a -> a {citationMode = mode}) cs
1415−citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
1416−citation name mode multi = do
1417− (c,raw) <- withRaw $ cites mode multi
1418− return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
1420−complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
1421−complexNatbibCitation mode = try $ do
1422− let ils = (toList . trimInlines . mconcat) <$>
1423− many (notFollowedBy (oneOf "\\};") >> inline)
1424− let parseOne = try $ do
1427− cit' <- inline -- expect a citation
1428− let citlist = toList cit'
1429− cits' <- case citlist of
1430− [Cite cs _] -> return cs
1434− optional $ char ';'
1435− return $ addPrefix pref $ addSuffix suff cits'
1436− (c:cits, raw) <- withRaw $ grouped parseOne
1437− return $ cite (c{ citationMode = mode }:cits)
1438− (rawInline "latex" $ "\\citetext" ++ raw)
1442−parseAligns :: PandocMonad m => LP m [(Alignment, Double, (String, String))]
1443−parseAligns = try $ do
1445− let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
1447− let cAlign = AlignCenter <$ char 'c'
1448− let lAlign = AlignLeft <$ char 'l'
1449− let rAlign = AlignRight <$ char 'r'
1450− let parAlign = AlignLeft <$ char 'p'
1451− -- algins from tabularx
1452− let xAlign = AlignLeft <$ char 'X'
1453− let mAlign = AlignLeft <$ char 'm'
1454− let bAlign = AlignLeft <$ char 'b'
1455− let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
1456− <|> xAlign <|> mAlign <|> bAlign
1457− let alignPrefix = char '>' >> braced
1458− let alignSuffix = char '<' >> braced
1459− let colWidth = try $ do
1461− ds <- many1 (oneOf "0123456789.")
1463− string "\\linewidth"
1465− case safeRead ds of
1467− Nothing -> return 0.0
1470− pref <- option "" alignPrefix
1473− width <- colWidth <|> option 0.0 (do s <- braced
1475− report $ SkippedContent s pos
1478− suff <- option "" alignSuffix
1479− return (al, width, (pref, suff))
1480− aligns' <- sepEndBy alignSpec maybeBar
1486−hline :: PandocMonad m => LP m ()
1489− controlSeq "hline" <|>
1491− controlSeq "toprule" <|>
1492− controlSeq "bottomrule" <|>
1493− controlSeq "midrule" <|>
1494− controlSeq "endhead" <|>
1495− controlSeq "endfirsthead"
1497− optional $ bracketed (many1 (satisfy (/=']')))
1500−lbreak :: PandocMonad m => LP m ()
1247+{-
1501−lbreak = () <$ try (spaces' *>
1248+-- -- | Parse LaTeX from string and return 'Pandoc' document.
1502− (controlSeq "\\" <|> controlSeq "tabularnewline") <*
1249+-- readLaTeX :: PandocMonad m
1503− spaces')
1250+-- => ReaderOptions -- ^ Reader options
1504−
1251+-- -> Text -- ^ String to parse (assumes @'\n'@ line endings)
1505−amp :: PandocMonad m => LP m ()
1252+-- -> m Pandoc
1506−amp = () <$ try (spaces' *> char '&' <* spaces')
1253+-- readLaTeX opts ltx = do
1507−
1254+-- parsed <- readWithM parseLaTeX def{ stateOptions = opts }
1508−parseTableRow :: PandocMonad m
1255+-- (unpack (crFilter ltx))
1509− => String -- ^ table environment name
1256+-- case parsed of
1510− -> [(String, String)] -- ^ pref/suffixes
1257+-- Right result -> return result
1511− -> LP m [Blocks]
1258+-- Left e -> throwError e
1512−parseTableRow envname prefsufs = try $ do
1259+--
1513− let cols = length prefsufs
1260+--
1514− let tableCellRaw = concat <$> many
1261+-- parseLaTeX :: PandocMonad m => LP m Pandoc
1515− (do notFollowedBy amp
1262+-- parseLaTeX = do
1516− notFollowedBy lbreak
1263+-- bs <- blocks
1517− notFollowedBy $ () <$ try (string ("\\end{" ++ envname ++ "}"))
1264+-- eof
1518− many1 (noneOf "&%\n\r\\")
1265+-- st <- getState
1519− <|> try (string "\\&")
1266+-- let meta = stateMeta st
1520− <|> count 1 anyChar)
1267+-- let doc' = doc bs
1521− let plainify bs = case toList bs of
1268+-- let headerLevel (Header n _ _) = [n]
1522− [Para ils] -> plain (fromList ils)
1269+-- headerLevel _ = []
1523− _ -> bs
1270+-- let bottomLevel = minimumDef 1 $ query headerLevel doc'
1524− rawcells <- sepBy1 tableCellRaw amp
1271+-- let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
1525− guard $ length rawcells == cols
1272+-- adjustHeaders _ x = x
1526− let rawcells' = zipWith (\c (p, s) -> p ++ trim c ++ s) rawcells prefsufs
1273+-- let (Pandoc _ bs') =
1527− let tableCell = plainify <$> blocks
1274+-- -- handle the case where you have \part or \chapter
1528− cells' <- mapM (parseFromString' tableCell) rawcells'
1275+-- (if bottomLevel < 1
1529− let numcells = length cells'
1276+-- then walk (adjustHeaders (1 - bottomLevel))
1530− guard $ numcells <= cols && numcells >= 1
1277+-- else id) doc'
1531− guard $ cells' /= [mempty]
1278+-- return $ Pandoc meta bs'
1532− -- note: a & b in a three-column table leaves an empty 3rd cell:
1279+--
1533− let cells'' = cells' ++ replicate (cols - numcells) mempty
1280+-- anyControlSeq :: PandocMonad m => LP m String
1534− spaces'
1281+-- anyControlSeq = do
1535− return cells''
1282+-- char '\\'
1536−
1283+-- next <- option '\n' anyChar
1537−spaces' :: PandocMonad m => LP m ()
1284+-- case next of
1538−spaces' = spaces *> skipMany (comment *> spaces)
1285+-- '\n' -> return ""
1539−
1286+-- c | isLetter c -> (c:) <$> (many letter <* optional sp)
1540−simpTable :: PandocMonad m => String -> Bool -> LP m Blocks
1287+-- | otherwise -> return [c]
1541−simpTable envname hasWidthParameter = try $ do
1288+--
1542− when hasWidthParameter $ () <$ (spaces' >> tok)
1289+-- controlSeq :: PandocMonad m => String -> LP m String
1543− skipopts
1290+-- controlSeq name = try $ do
1544− colspecs <- parseAligns
1291+-- char '\\'
1545− let (aligns, widths, prefsufs) = unzip3 colspecs
1292+-- case name of
1546− let cols = length colspecs
1293+-- "" -> mzero
1547− optional $ controlSeq "caption" *> skipopts *> setCaption
1294+-- [c] | not (isLetter c) -> string [c]
1548− optional lbreak
1295+-- cs -> string cs <* notFollowedBy letter <* optional sp
1549− spaces'
1296+-- return name
1550− skipMany hline
1297+--
1551− spaces'
1298+-- dimenarg :: PandocMonad m => LP m String
1552− header' <- option [] $ try (parseTableRow envname prefsufs <*
1299+-- dimenarg = try $ do
1553− lbreak <* many1 hline)
1300+-- ch <- option "" $ string "="
1554− spaces'
1301+-- num <- many1 digit
1555− rows <- sepEndBy (parseTableRow envname prefsufs)
1302+-- dim <- oneOfStrings ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
1556− (lbreak <* optional (skipMany hline))
1303+-- return $ ch ++ num ++ dim
1558− optional $ controlSeq "caption" *> skipopts *> setCaption
1305+-- sp :: PandocMonad m => LP m ()
1559− optional lbreak
1306+-- sp = whitespace <|> endline
1561− let header'' = if null header'
1308+-- whitespace :: PandocMonad m => LP m ()
1562− then replicate cols mempty
1309+-- whitespace = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
1563− else header'
1310+--
1564− lookAhead $ controlSeq "end" -- make sure we're at end
1311+-- endline :: PandocMonad m => LP m ()
1565− return $ table mempty (zip aligns widths) header'' rows
1312+-- endline = try (newline >> lookAhead anyChar >> notFollowedBy blankline)
1567−removeDoubleQuotes :: String -> String
1314+-- isLowerHex :: Char -> Bool
1568−removeDoubleQuotes ('"':xs) =
1315+-- isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
1569− case reverse xs of
1316+--
1570− '"':ys -> reverse ys
1317+-- primEscape :: PandocMonad m => LP m Char
1571− _ -> '"':xs
1318+-- primEscape = try $ do
1572−removeDoubleQuotes xs = xs
1319+-- string "^^"
1320+-- c <- satisfy (\x -> x >= '\0' && x <= '\128')
1321+-- d <- if isLowerHex c
1322+-- then option "" $ count 1 (satisfy isLowerHex)
1325+-- then case ord c of
1326+-- x | x >= 64 && x <= 127 -> return $ chr (x - 64)
1327+-- | otherwise -> return $ chr (x + 64)
1328+-- else return $ chr $ read ('0':'x':c:d)
1330+-- comment :: PandocMonad m => LP m ()
1333+-- skipMany (satisfy (/='\n'))
1337+-- bgroup :: PandocMonad m => LP m ()
1338+-- bgroup = try $ do
1339+-- skipMany (spaceChar <|> try (newline <* notFollowedBy blankline))
1341+-- <|> () <$ controlSeq "bgroup"
1342+-- <|> () <$ controlSeq "begingroup"
1344+-- egroup :: PandocMonad m => LP m ()
1345+-- egroup = () <$ char '}'
1346+-- <|> () <$ controlSeq "egroup"
1347+-- <|> () <$ controlSeq "endgroup"
1349+-- grouped :: PandocMonad m => Monoid a => LP m a -> LP m a
1350+-- grouped parser = try $ do
1352+-- -- first we check for an inner 'grouped', because
1353+-- -- {{a,b}} should be parsed the same as {a,b}
1354+-- try (grouped parser <* egroup)
1355+-- <|> (mconcat <$> manyTill parser egroup)
1357+-- braced :: PandocMonad m => LP m String
1358+-- braced = grouped chunk
1360+-- many1 (satisfy (\c -> c /= '\\' && c /= '}' && c /= '{'))
1361+-- <|> try (string "\\}")
1362+-- <|> try (string "\\{")
1363+-- <|> try (string "\\\\")
1364+-- <|> ((\x -> "{" ++ x ++ "}") <$> braced)
1365+-- <|> count 1 anyChar
1367+-- bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
1368+-- bracketed parser = try $ char '[' *> (mconcat <$> manyTill parser (char ']'))
1370+-- mathDisplay :: PandocMonad m => LP m String -> LP m Inlines
1371+-- mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
1373+-- mathInline :: PandocMonad m => LP m String -> LP m Inlines
1374+-- mathInline p = math <$> (try p >>= applyMacros')
1376+-- mathChars :: PandocMonad m => LP m String
1378+-- concat <$> many (escapedChar
1379+-- <|> (snd <$> withRaw braced)
1380+-- <|> many1 (satisfy isOrdChar))
1381+-- where escapedChar = try $ do char '\\'
1384+-- isOrdChar '$' = False
1385+-- isOrdChar '{' = False
1386+-- isOrdChar '}' = False
1387+-- isOrdChar '\\' = False
1388+-- isOrdChar _ = True
1390+-- inline :: PandocMonad m => LP m Inlines
1391+-- inline = (mempty <$ comment)
1392+-- <|> (space <$ whitespace)
1393+-- <|> (softbreak <$ endline)
1395+-- <|> inlineCommand
1396+-- <|> inlineEnvironment
1398+-- <|> (char '-' *> option (str "-")
1399+-- (char '-' *> option (str "–") (str "—" <$ char '-')))
1402+-- <|> (str "”" <$ try (string "''"))
1403+-- <|> (str "”" <$ char '”')
1404+-- <|> (str "’" <$ char '\'')
1405+-- <|> (str "’" <$ char '’')
1406+-- <|> (str "\160" <$ char '~')
1407+-- <|> mathDisplay (string "$$" *> mathChars <* string "$$")
1408+-- <|> mathInline (char '$' *> mathChars <* char '$')
1409+-- <|> (guardEnabled Ext_literate_haskell *> char '|' *> doLHSverb)
1410+-- <|> (str . (:[]) <$> primEscape)
1411+-- <|> (do res <- oneOf "#&~^'`\"[]"
1412+-- pos <- getPosition
1413+-- report $ ParsingUnescaped [res] pos
1414+-- return $ str [res])
1416+-- inlines :: PandocMonad m => LP m Inlines
1417+-- inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
1419+-- inlineGroup :: PandocMonad m => LP m Inlines
1421+-- ils <- grouped inline
1423+-- then return mempty
1424+-- else return $ spanWith nullAttr ils
1425+-- -- we need the span so we can detitlecase bibtex entries;
1426+-- -- we need to know when something is {C}apitalized
1428+-- block :: PandocMonad m => LP m Blocks
1429+-- block = (mempty <$ comment)
1430+-- <|> (mempty <$ ((spaceChar <|> newline) *> spaces))
1436+-- <|> grouped block
1438+-- blocks :: PandocMonad m => LP m Blocks
1439+-- blocks = mconcat <$> many block
1441+-- getRawCommand :: PandocMonad m => String -> LP m String
1442+-- getRawCommand name' = do
1443+-- rawargs <- withRaw (many (try (optional sp *> opt)) *>
1444+-- option "" (try (optional sp *> dimenarg)) *>
1446+-- return $ '\\' : name' ++ snd rawargs
1448+-- lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
1449+-- lookupListDefault d = (fromMaybe d .) . lookupList
1451+-- lookupList l m = msum $ map (`M.lookup` m) l
1453+-- blockCommand :: PandocMonad m => LP m Blocks
1454+-- blockCommand = try $ do
1455+-- name <- anyControlSeq
1456+-- guard $ name /= "begin" && name /= "end"
1457+-- star <- option "" (string "*" <* optional sp)
1458+-- let name' = name ++ star
1460+-- rawcommand <- getRawCommand name'
1461+-- transformed <- applyMacros' rawcommand
1462+-- guard $ transformed /= rawcommand
1463+-- notFollowedBy $ parseFromString' inlines transformed
1464+-- parseFromString' blocks transformed
1465+-- lookupListDefault raw [name',name] blockCommands
1467+-- inBrackets :: Inlines -> Inlines
1468+-- inBrackets x = str "[" <> x <> str "]"
1470+-- -- eat an optional argument and one or more arguments in braces
1471+-- ignoreInlines :: PandocMonad m => Text -> (Text, LP m Inlines)
1472+-- ignoreInlines name = (name, p)
1474+-- p = do oa <- optargs
1475+-- let rawCommand = '\\':name ++ oa
1476+-- let doraw = guardRaw >> return (rawInline "latex" rawCommand)
1477+-- doraw <|> ignore rawCommand
1479+-- guardRaw :: PandocMonad m => LP m ()
1480+-- guardRaw = getOption readerExtensions >>= guard . extensionEnabled Ext_raw_tex
1482+-- optargs :: PandocMonad m => LP m String
1483+-- optargs = snd <$> withRaw (skipopts *> skipMany (try $ optional sp *> braced))
1485+-- ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a
1487+-- pos <- getPosition
1488+-- report $ SkippedContent raw pos
1491+-- ignoreBlocks :: PandocMonad m => String -> (String, LP m Blocks)
1492+-- ignoreBlocks name = (name, p)
1494+-- p = do oa <- optargs
1495+-- let rawCommand = '\\':name ++ oa
1496+-- let doraw = guardRaw >> return (rawBlock "latex" rawCommand)
1497+-- doraw <|> ignore rawCommand
1499+-- blockCommands :: PandocMonad m => M.Map String (LP m Blocks)
1500+-- blockCommands = M.fromList $
1501+-- [ ("par", mempty <$ skipopts)
1502+-- , ("parbox", braced >> grouped blocks)
1503+-- , ("title", mempty <$ (skipopts *>
1504+-- (grouped inline >>= addMeta "title")
1505+-- <|> (grouped block >>= addMeta "title")))
1506+-- , ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
1507+-- , ("author", mempty <$ (skipopts *> authors))
1508+-- -- -- in letter class, temp. store address & sig as title, author
1509+-- , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
1510+-- , ("signature", mempty <$ (skipopts *> authors))
1511+-- , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
1512+-- -- Koma-script metadata commands
1513+-- , ("dedication", mempty <$ (skipopts *> tok >>= addMeta "dedication"))
1515+-- , ("part", section nullAttr (-1))
1516+-- , ("part*", section nullAttr (-1))
1517+-- , ("chapter", section nullAttr 0)
1518+-- , ("chapter*", section ("",["unnumbered"],[]) 0)
1519+-- , ("section", section nullAttr 1)
1520+-- , ("section*", section ("",["unnumbered"],[]) 1)
1521+-- , ("subsection", section nullAttr 2)
1522+-- , ("subsection*", section ("",["unnumbered"],[]) 2)
1523+-- , ("subsubsection", section nullAttr 3)
1524+-- , ("subsubsection*", section ("",["unnumbered"],[]) 3)
1525+-- , ("paragraph", section nullAttr 4)
1526+-- , ("paragraph*", section ("",["unnumbered"],[]) 4)
1527+-- , ("subparagraph", section nullAttr 5)
1528+-- , ("subparagraph*", section ("",["unnumbered"],[]) 5)
1530+-- , ("frametitle", section nullAttr 3)
1531+-- , ("framesubtitle", section nullAttr 4)
1533+-- , ("opening", (para . trimInlines) <$> (skipopts *> tok))
1534+-- , ("closing", skipopts *> closing)
1536+-- , ("hrule", pure horizontalRule)
1537+-- , ("strut", pure mempty)
1538+-- , ("rule", skipopts *> tok *> tok *> pure horizontalRule)
1539+-- , ("item", skipopts *> looseItem)
1540+-- , ("documentclass", skipopts *> braced *> preamble)
1541+-- , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
1542+-- , ("caption", skipopts *> setCaption)
1543+-- , ("bibliography", mempty <$ (skipopts *> braced >>=
1544+-- addMeta "bibliography" . splitBibs))
1545+-- , ("addbibresource", mempty <$ (skipopts *> braced >>=
1546+-- addMeta "bibliography" . splitBibs))
1548+-- , ("lstinputlisting", inputListing)
1549+-- , ("graphicspath", graphicsPath)
1551+-- , ("hypertarget", braced >> grouped block)
1552+-- ] ++ map ignoreBlocks
1553+-- -- these commands will be ignored unless --parse-raw is specified,
1554+-- -- in which case they will appear as raw latex blocks
1555+-- [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
1556+-- -- newcommand, etc. should be parsed by macro, but we need this
1557+-- -- here so these aren't parsed as inline commands to ignore
1558+-- , "special", "pdfannot", "pdfstringdef"
1559+-- , "bibliographystyle"
1560+-- , "maketitle", "makeindex", "makeglossary"
1561+-- , "addcontentsline", "addtocontents", "addtocounter"
1562+-- -- \ignore{} is used conventionally in literate haskell for definitions
1563+-- -- that are to be processed by the compiler but not printed.
1566+-- , "markboth", "markright", "markleft"
1567+-- , "hspace", "vspace"
1573+-- graphicsPath :: PandocMonad m => LP m Blocks
1574+-- graphicsPath = do
1575+-- ps <- bgroup *> (manyTill braced egroup)
1576+-- getResourcePath >>= setResourcePath . (++ ps)
1579+-- addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1580+-- addMeta field val = updateState $ \st ->
1581+-- st{ stateMeta = addMetaField field val $ stateMeta st }
1583+-- splitBibs :: String -> [Inlines]
1584+-- splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
1586+-- setCaption :: PandocMonad m => LP m Blocks
1589+-- mblabel <- option Nothing $
1590+-- try $ spaces' >> controlSeq "label" >> (Just <$> tok)
1591+-- let ils' = case mblabel of
1592+-- Just lab -> ils <> spanWith
1593+-- ("",[],[("data-label", stringify lab)]) mempty
1595+-- updateState $ \st -> st{ stateCaption = Just ils' }
1598+-- resetCaption :: PandocMonad m => LP m ()
1599+-- resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
1601+-- authors :: PandocMonad m => LP m ()
1602+-- authors = try $ do
1604+-- let oneAuthor = mconcat <$>
1605+-- many1 (notFollowedBy' (controlSeq "and") >>
1606+-- (inline <|> mempty <$ blockCommand))
1607+-- -- skip e.g. \vspace{10pt}
1608+-- auths <- sepBy oneAuthor (controlSeq "and")
1610+-- addMeta "author" (map trimInlines auths)
1612+-- section :: PandocMonad m => Attr -> Int -> LP m Blocks
1613+-- section (ident, classes, kvs) lvl = do
1615+-- contents <- grouped inline
1616+-- lab <- option ident $ try (spaces' >> controlSeq "label" >> spaces' >> braced)
1617+-- attr' <- registerHeader (lab, classes, kvs) contents
1618+-- return $ headerWith attr' lvl contents
1620+-- inlineCommand :: PandocMonad m => LP m Inlines
1621+-- inlineCommand = try $ do
1622+-- (name, raw') <- withRaw anyControlSeq
1623+-- guard $ name /= "begin" && name /= "end"
1624+-- star <- option "" (string "*")
1625+-- let name' = name ++ star
1627+-- guard $ not (isBlockCommand name)
1628+-- rawargs <- withRaw
1629+-- (skipangles *> skipopts *> option "" dimenarg *> many braced)
1630+-- let rawcommand = raw' ++ star ++ snd rawargs
1631+-- transformed <- applyMacros' rawcommand
1632+-- exts <- getOption readerExtensions
1633+-- if transformed /= rawcommand
1634+-- then parseFromString' inlines transformed
1635+-- else if extensionEnabled Ext_raw_tex exts
1636+-- then return $ rawInline "latex" rawcommand
1637+-- else ignore rawcommand
1638+-- (lookupListDefault raw [name',name] inlineCommands <*
1639+-- optional (try (string "{}")))
1641+-- rawInlineOr :: PandocMonad m => String -> LP m Inlines -> LP m Inlines
1642+-- rawInlineOr name' fallback = do
1643+-- parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
1645+-- then rawInline "latex" <$> getRawCommand name'
1648+-- isBlockCommand :: String -> Bool
1649+-- isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Blocks))
1652+-- inlineEnvironments :: PandocMonad m => M.Map String (LP m Inlines)
1653+-- inlineEnvironments = M.fromList
1654+-- [ ("displaymath", mathEnvWith id Nothing "displaymath")
1655+-- , ("math", math <$> mathEnv "math")
1656+-- , ("equation", mathEnvWith id Nothing "equation")
1657+-- , ("equation*", mathEnvWith id Nothing "equation*")
1658+-- , ("gather", mathEnvWith id (Just "gathered") "gather")
1659+-- , ("gather*", mathEnvWith id (Just "gathered") "gather*")
1660+-- , ("multline", mathEnvWith id (Just "gathered") "multline")
1661+-- , ("multline*", mathEnvWith id (Just "gathered") "multline*")
1662+-- , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
1663+-- , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
1664+-- , ("align", mathEnvWith id (Just "aligned") "align")
1665+-- , ("align*", mathEnvWith id (Just "aligned") "align*")
1666+-- , ("alignat", mathEnvWith id (Just "aligned") "alignat")
1667+-- , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
1670+-- mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
1671+-- mkImage options src = do
1672+-- let replaceTextwidth (k,v) = case numUnit v of
1673+-- Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
1675+-- let kvs = map replaceTextwidth $ filter (\(k,_) -> k `elem` ["width", "height"]) options
1676+-- let attr = ("",[], kvs)
1677+-- let alt = str "image"
1678+-- case takeExtension src of
1680+-- defaultExt <- getOption readerDefaultImageExtension
1681+-- return $ imageWith attr (addExtension src defaultExt) "" alt
1682+-- _ -> return $ imageWith attr src "" alt
1684+-- inNote :: Inlines -> Inlines
1686+-- note $ para $ ils <> str "."
1689+-- -- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
1690+-- dosiunitx :: PandocMonad m => LP m Inlines
1694+-- valueprefix <- option "" $ char '[' >> (mconcat <$> manyTill tok (char ']'))
1696+-- let emptyOr160 "" = ""
1697+-- emptyOr160 _ = "\160"
1698+-- return . mconcat $ [valueprefix,
1699+-- emptyOr160 valueprefix,
1704+-- accent :: (Char -> String) -> Inlines -> LP m Inlines
1706+-- case toList ils of
1707+-- (Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
1711+-- grave :: Char -> String
1724+-- acute :: Char -> String
1751+-- circ :: Char -> String
1778+-- tilde :: Char -> String
1791+-- umlaut :: Char -> String
1804+-- hungarumlaut :: Char -> String
1805+-- hungarumlaut 'A' = "A̋"
1806+-- hungarumlaut 'E' = "E̋"
1807+-- hungarumlaut 'I' = "I̋"
1808+-- hungarumlaut 'O' = "Ő"
1809+-- hungarumlaut 'U' = "Ű"
1810+-- hungarumlaut 'Y' = "ӳ"
1811+-- hungarumlaut 'a' = "a̋"
1812+-- hungarumlaut 'e' = "e̋"
1813+-- hungarumlaut 'i' = "i̋"
1814+-- hungarumlaut 'o' = "ő"
1815+-- hungarumlaut 'u' = "ű"
1816+-- hungarumlaut 'y' = "ӳ"
1817+-- hungarumlaut c = [c]
1819+-- dot :: Char -> String
1831+-- macron :: Char -> String
1844+-- cedilla :: Char -> String
1845+-- cedilla 'c' = "ç"
1846+-- cedilla 'C' = "Ç"
1847+-- cedilla 's' = "ş"
1848+-- cedilla 'S' = "Ş"
1849+-- cedilla 't' = "ţ"
1850+-- cedilla 'T' = "Ţ"
1851+-- cedilla 'e' = "ȩ"
1852+-- cedilla 'E' = "Ȩ"
1853+-- cedilla 'h' = "ḩ"
1854+-- cedilla 'H' = "Ḩ"
1855+-- cedilla 'o' = "o̧"
1856+-- cedilla 'O' = "O̧"
1859+-- hacek :: Char -> String
1895+-- breve :: Char -> String
1910+-- tok :: PandocMonad m => LP m Inlines
1911+-- tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
1913+-- opt :: PandocMonad m => LP m Inlines
1914+-- opt = bracketed inline
1916+-- rawopt :: PandocMonad m => LP m String
1918+-- contents <- bracketed (many1 (noneOf "[]") <|> try (string "\\]") <|>
1919+-- try (string "\\[") <|> rawopt)
1921+-- return $ "[" ++ contents ++ "]"
1923+-- skipopts :: PandocMonad m => LP m ()
1924+-- skipopts = skipMany rawopt
1926+-- -- opts in angle brackets are used in beamer
1927+-- rawangle :: PandocMonad m => LP m ()
1928+-- rawangle = try $ do
1930+-- skipMany (noneOf ">")
1934+-- skipangles :: PandocMonad m => LP m ()
1935+-- skipangles = skipMany rawangle
1937+-- inlineText :: PandocMonad m => LP m Inlines
1938+-- inlineText = str <$> many1 inlineChar
1940+-- inlineChar :: PandocMonad m => LP m Char
1941+-- inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
1943+-- environment :: PandocMonad m => LP m Blocks
1945+-- controlSeq "begin"
1947+-- M.findWithDefault mzero name environments
1950+-- inlineEnvironment :: PandocMonad m => LP m Inlines
1951+-- inlineEnvironment = try $ do
1952+-- controlSeq "begin"
1954+-- M.findWithDefault mzero name inlineEnvironments
1956+-- rawEnv :: PandocMonad m => String -> LP m Blocks
1958+-- exts <- getOption readerExtensions
1959+-- let parseRaw = extensionEnabled Ext_raw_tex exts
1960+-- rawOptions <- mconcat <$> many rawopt
1961+-- let beginCommand = "\\begin{" ++ name ++ "}" ++ rawOptions
1962+-- pos1 <- getPosition
1963+-- (bs, raw) <- withRaw $ env name blocks
1964+-- raw' <- applyMacros' $ beginCommand ++ raw
1965+-- if raw' /= beginCommand ++ raw
1966+-- then parseFromString' blocks raw'
1968+-- then return $ rawBlock "latex" $ beginCommand ++ raw'
1970+-- unless parseRaw $ do
1971+-- report $ SkippedContent beginCommand pos1
1972+-- pos2 <- getPosition
1973+-- report $ SkippedContent ("\\end{" ++ name ++ "}") pos2
1976+-- rawVerbEnv :: PandocMonad m => String -> LP m Blocks
1977+-- rawVerbEnv name = do
1978+-- pos <- getPosition
1979+-- (_, raw) <- withRaw $ verbEnv name
1980+-- let raw' = "\\begin{tikzpicture}" ++ raw
1981+-- exts <- getOption readerExtensions
1982+-- let parseRaw = extensionEnabled Ext_raw_tex exts
1984+-- then return $ rawBlock "latex" raw'
1986+-- report $ SkippedContent raw' pos
1993+-- keyval :: PandocMonad m => LP m (String, String)
1994+-- keyval = try $ do
1995+-- key <- many1 alphaNum
1996+-- val <- option "" $ char '=' >> braced <|> (many1 (alphaNum <|> oneOf ".:-|\\"))
1997+-- skipMany spaceChar
1998+-- optional (char ',')
1999+-- skipMany spaceChar
2000+-- return (key, val)
2003+-- keyvals :: PandocMonad m => LP m [(String, String)]
2004+-- keyvals = try $ char '[' *> manyTill keyval (char ']')
2006+-- alltt :: PandocMonad m => String -> LP m Blocks
2007+-- alltt t = walk strToCode <$> parseFromString' blocks
2008+-- (substitute " " "\\ " $ substitute "%" "\\%" $
2009+-- intercalate "\\\\\n" $ lines t)
2010+-- where strToCode (Str s) = Code nullAttr s
2013+-- rawLaTeXBlock :: PandocMonad m => ParserT String ParserState String
2014+-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
2016+-- rawLaTeXInline :: PandocMonad m => ParserT String ParserState Inline
2017+-- rawLaTeXInline = do
2018+-- raw <- (snd <$> withRaw inlineCommand)
2019+-- <|> (snd <$> withRaw inlineEnvironment)
2020+-- <|> (snd <$> withRaw blockCommand)
2021+-- RawInline "latex" <$> applyMacros' raw
2023+-- addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
2024+-- addImageCaption = walkM go
2025+-- where go (Image attr alt (src,tit))
2026+-- | not ("fig:" `isPrefixOf` tit) = do
2027+-- mbcapt <- stateCaption <$> getState
2028+-- return $ case mbcapt of
2029+-- Just ils -> Image attr (toList ils) (src, "fig:" ++ tit)
2030+-- Nothing -> Image attr alt (src,tit)
2033+-- addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
2034+-- addTableCaption = walkM go
2035+-- where go (Table c als ws hs rs) = do
2036+-- mbcapt <- stateCaption <$> getState
2037+-- return $ case mbcapt of
2038+-- Just ils -> Table (toList ils) als ws hs rs
2039+-- Nothing -> Table c als ws hs rs
2042+-- environments :: PandocMonad m => M.Map String (LP m Blocks)
2043+-- environments = M.fromList
2044+-- [ ("document", env "document" blocks <* skipMany anyChar)
2045+-- , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
2046+-- , ("letter", env "letter" letterContents)
2047+-- , ("minipage", env "minipage" $
2048+-- skipopts *> spaces' *> optional braced *> spaces' *> blocks)
2049+-- , ("figure", env "figure" $ skipopts *> figure)
2050+-- , ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
2051+-- , ("center", env "center" blocks)
2052+-- , ("longtable", env "longtable" $
2053+-- resetCaption *> simpTable "longtable" False >>= addTableCaption)
2054+-- , ("table", env "table" $
2055+-- resetCaption *> skipopts *> blocks >>= addTableCaption)
2056+-- , ("tabular*", env "tabular" $ simpTable "tabular*" True)
2057+-- , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
2058+-- , ("tabular", env "tabular" $ simpTable "tabular" False)
2059+-- , ("quote", blockQuote <$> env "quote" blocks)
2060+-- , ("quotation", blockQuote <$> env "quotation" blocks)
2061+-- , ("verse", blockQuote <$> env "verse" blocks)
2062+-- , ("itemize", bulletList <$> listenv "itemize" (many item))
2063+-- , ("description", definitionList <$> listenv "description" (many descItem))
2064+-- , ("enumerate", orderedList')
2065+-- , ("alltt", alltt =<< verbEnv "alltt")
2066+-- , ("code", guardEnabled Ext_literate_haskell *>
2067+-- (codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
2069+-- , ("comment", mempty <$ verbEnv "comment")
2070+-- , ("verbatim", codeBlock <$> verbEnv "verbatim")
2071+-- , ("Verbatim", fancyverbEnv "Verbatim")
2072+-- , ("BVerbatim", fancyverbEnv "BVerbatim")
2073+-- , ("lstlisting", do attr <- parseListingsOptions <$> option [] keyvals
2074+-- codeBlockWith attr <$> verbEnv "lstlisting")
2075+-- , ("minted", do options <- option [] keyvals
2076+-- lang <- grouped (many1 $ satisfy (/='}'))
2077+-- let kvs = [ (if k == "firstnumber"
2079+-- else k, v) | (k,v) <- options ]
2080+-- let classes = [ lang | not (null lang) ] ++
2081+-- [ "numberLines" |
2082+-- lookup "linenos" options == Just "true" ]
2083+-- let attr = ("",classes,kvs)
2084+-- codeBlockWith attr <$> verbEnv "minted")
2085+-- , ("obeylines", parseFromString
2086+-- (para . trimInlines . mconcat <$> many inline) =<<
2087+-- intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
2088+-- , ("displaymath", mathEnvWith para Nothing "displaymath")
2089+-- , ("equation", mathEnvWith para Nothing "equation")
2090+-- , ("equation*", mathEnvWith para Nothing "equation*")
2091+-- , ("gather", mathEnvWith para (Just "gathered") "gather")
2092+-- , ("gather*", mathEnvWith para (Just "gathered") "gather*")
2093+-- , ("multline", mathEnvWith para (Just "gathered") "multline")
2094+-- , ("multline*", mathEnvWith para (Just "gathered") "multline*")
2095+-- , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
2096+-- , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
2097+-- , ("align", mathEnvWith para (Just "aligned") "align")
2098+-- , ("align*", mathEnvWith para (Just "aligned") "align*")
2099+-- , ("alignat", mathEnvWith para (Just "aligned") "alignat")
2100+-- , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
2101+-- , ("tikzpicture", rawVerbEnv "tikzpicture")
2104+-- figure :: PandocMonad m => LP m Blocks
2105+-- figure = try $ do
2107+-- blocks >>= addImageCaption
2109+-- letterContents :: PandocMonad m => LP m Blocks
2110+-- letterContents = do
2113+-- -- add signature (author) and address (title)
2114+-- let addr = case lookupMeta "address" (stateMeta st) of
2115+-- Just (MetaBlocks [Plain xs]) ->
2116+-- para $ trimInlines $ fromList xs
2118+-- return $ addr <> bs -- sig added by \closing
2121+-- item :: PandocMonad m => LP m Blocks
2122+-- item = blocks *> controlSeq "item" *> skipopts *> blocks
2124+-- looseItem :: PandocMonad m => LP m Blocks
2126+-- ctx <- stateParserContext `fmap` getState
2127+-- if ctx == ListItemState
2129+-- else return mempty
2131+-- descItem :: PandocMonad m => LP m (Inlines, [Blocks])
2133+-- blocks -- skip blocks before item
2134+-- controlSeq "item"
2138+-- return (ils, [bs])
2140+-- env :: PandocMonad m => String -> LP m a -> LP m a
2141+-- env name p = p <*
2142+-- (try (controlSeq "end" *> braced >>= guard . (== name))
2143+-- <?> ("\\end{" ++ name ++ "}"))
2145+-- listenv :: PandocMonad m => String -> LP m a -> LP m a
2146+-- listenv name p = try $ do
2147+-- oldCtx <- stateParserContext `fmap` getState
2148+-- updateState $ \st -> st{ stateParserContext = ListItemState }
2149+-- res <- env name p
2150+-- updateState $ \st -> st{ stateParserContext = oldCtx }
2153+-- mathEnvWith :: PandocMonad m
2154+-- => (Inlines -> a) -> Maybe String -> String -> LP m a
2155+-- mathEnvWith f innerEnv name = f <$> mathDisplay (inner <$> mathEnv name)
2156+-- where inner x = case innerEnv of
2158+-- Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
2159+-- "\\end{" ++ y ++ "}"
2161+-- mathEnv :: PandocMonad m => String -> LP m String
2162+-- mathEnv name = do
2164+-- optional blankline
2165+-- let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
2166+-- charMuncher = skipMany comment *>
2167+-- (many1 (noneOf "\\%") <|> try (string "\\%")
2168+-- <|> try (string "\\\\") <|> count 1 anyChar)
2169+-- res <- concat <$> manyTill charMuncher endEnv
2170+-- return $ stripTrailingNewlines res
2172+-- verbEnv :: PandocMonad m => String -> LP m String
2173+-- verbEnv name = do
2175+-- optional blankline
2176+-- let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
2177+-- charMuncher = anyChar
2178+-- res <- manyTill charMuncher endEnv
2179+-- return $ stripTrailingNewlines res
2181+-- fancyverbEnv :: PandocMonad m => String -> LP m Blocks
2182+-- fancyverbEnv name = do
2183+-- options <- option [] keyvals
2184+-- let kvs = [ (if k == "firstnumber"
2186+-- else k, v) | (k,v) <- options ]
2187+-- let classes = [ "numberLines" |
2188+-- lookup "numbers" options == Just "left" ]
2189+-- let attr = ("",classes,kvs)
2190+-- codeBlockWith attr <$> verbEnv name
2192+-- orderedList' :: PandocMonad m => LP m Blocks
2193+-- orderedList' = try $ do
2195+-- (_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
2196+-- try $ char '[' *> anyOrderedListMarker <* char ']'
2198+-- optional $ try $ controlSeq "setlength" *> grouped (controlSeq "itemindent") *> braced
2200+-- start <- option 1 $ try $ do controlSeq "setcounter"
2201+-- grouped (string "enum" *> many1 (oneOf "iv"))
2203+-- num <- grouped (many1 digit)
2205+-- return (read num + 1 :: Int)
2206+-- bs <- listenv "enumerate" (many item)
2207+-- return $ orderedListWith (start, style, delim) bs
2209+-- paragraph :: PandocMonad m => LP m Blocks
2211+-- x <- trimInlines . mconcat <$> many1 inline
2213+-- then return mempty
2214+-- else return $ para x
2216+-- preamble :: PandocMonad m => LP m Blocks
2217+-- preamble = mempty <$> manyTill preambleBlock beginDoc
2218+-- where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
2219+-- preambleBlock = void comment
2221+-- <|> void blanklines
2224+-- <|> void blockCommand
2225+-- <|> void anyControlSeq
2233+-- addPrefix :: [Inline] -> [Citation] -> [Citation]
2234+-- addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
2235+-- addPrefix _ _ = []
2237+-- addSuffix :: [Inline] -> [Citation] -> [Citation]
2238+-- addSuffix s ks@(_:_) =
2240+-- in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
2241+-- addSuffix _ _ = []
2243+-- simpleCiteArgs :: PandocMonad m => LP m [Citation]
2244+-- simpleCiteArgs = try $ do
2245+-- first <- optionMaybe $ toList <$> opt
2246+-- second <- optionMaybe $ toList <$> opt
2247+-- keys <- try $ bgroup *> (manyTill citationLabel egroup)
2248+-- let (pre, suf) = case (first , second ) of
2249+-- (Just s , Nothing) -> (mempty, s )
2250+-- (Just s , Just t ) -> (s , t )
2251+-- _ -> (mempty, mempty)
2252+-- conv k = Citation { citationId = k
2253+-- , citationPrefix = []
2254+-- , citationSuffix = []
2255+-- , citationMode = NormalCitation
2256+-- , citationHash = 0
2257+-- , citationNoteNum = 0
2259+-- return $ addPrefix pre $ addSuffix suf $ map conv keys
2261+-- citationLabel :: PandocMonad m => LP m String
2262+-- citationLabel = optional sp *>
2263+-- (many1 (satisfy isBibtexKeyChar)
2265+-- <* optional (char ',')
2267+-- where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
2269+-- cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
2270+-- cites mode multi = try $ do
2272+-- then many1 simpleCiteArgs
2273+-- else count 1 simpleCiteArgs
2274+-- let cs = concat cits
2275+-- return $ case mode of
2276+-- AuthorInText -> case cs of
2277+-- (c:rest) -> c {citationMode = mode} : rest
2279+-- _ -> map (\a -> a {citationMode = mode}) cs
2281+-- citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
2282+-- citation name mode multi = do
2283+-- (c,raw) <- withRaw $ cites mode multi
2284+-- return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
2286+-- complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
2287+-- complexNatbibCitation mode = try $ do
2288+-- let ils = (toList . trimInlines . mconcat) <$>
2289+-- many (notFollowedBy (oneOf "\\};") >> inline)
2290+-- let parseOne = try $ do
2293+-- cit' <- inline -- expect a citation
2294+-- let citlist = toList cit'
2295+-- cits' <- case citlist of
2296+-- [Cite cs _] -> return cs
2300+-- optional $ char ';'
2301+-- return $ addPrefix pref $ addSuffix suff cits'
2302+-- (c:cits, raw) <- withRaw $ grouped parseOne
2303+-- return $ cite (c{ citationMode = mode }:cits)
2304+-- (rawInline "latex" $ "\\citetext" ++ raw)
2308+-- parseAligns :: PandocMonad m => LP m [(Alignment, Double, (String, String))]
2309+-- parseAligns = try $ do
2311+-- let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
2313+-- let cAlign = AlignCenter <$ char 'c'
2314+-- let lAlign = AlignLeft <$ char 'l'
2315+-- let rAlign = AlignRight <$ char 'r'
2316+-- let parAlign = AlignLeft <$ char 'p'
2317+-- -- algins from tabularx
2318+-- let xAlign = AlignLeft <$ char 'X'
2319+-- let mAlign = AlignLeft <$ char 'm'
2320+-- let bAlign = AlignLeft <$ char 'b'
2321+-- let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
2322+-- <|> xAlign <|> mAlign <|> bAlign
2323+-- let alignPrefix = char '>' >> braced
2324+-- let alignSuffix = char '<' >> braced
2325+-- let colWidth = try $ do
2327+-- ds <- many1 (oneOf "0123456789.")
2329+-- string "\\linewidth"
2331+-- case safeRead ds of
2332+-- Just w -> return w
2333+-- Nothing -> return 0.0
2334+-- let alignSpec = do
2336+-- pref <- option "" alignPrefix
2339+-- width <- colWidth <|> option 0.0 (do s <- braced
2340+-- pos <- getPosition
2341+-- report $ SkippedContent s pos
2344+-- suff <- option "" alignSuffix
2345+-- return (al, width, (pref, suff))
2346+-- aligns' <- sepEndBy alignSpec maybeBar
2352+-- hline :: PandocMonad m => LP m ()
2355+-- controlSeq "hline" <|>
2356+-- -- booktabs rules:
2357+-- controlSeq "toprule" <|>
2358+-- controlSeq "bottomrule" <|>
2359+-- controlSeq "midrule" <|>
2360+-- controlSeq "endhead" <|>
2361+-- controlSeq "endfirsthead"
2363+-- optional $ bracketed (many1 (satisfy (/=']')))
2366+-- lbreak :: PandocMonad m => LP m ()
2367+-- lbreak = () <$ try (spaces' *>
2368+-- (controlSeq "\\" <|> controlSeq "tabularnewline") <*
2371+-- amp :: PandocMonad m => LP m ()
2372+-- amp = () <$ try (spaces' *> char '&' <* spaces')
2374+-- parseTableRow :: PandocMonad m
2375+-- => String -- ^ table environment name
2376+-- -> [(String, String)] -- ^ pref/suffixes
2378+-- parseTableRow envname prefsufs = try $ do
2379+-- let cols = length prefsufs
2380+-- let tableCellRaw = concat <$> many
2381+-- (do notFollowedBy amp
2382+-- notFollowedBy lbreak
2383+-- notFollowedBy $ () <$ try (string ("\\end{" ++ envname ++ "}"))
2384+-- many1 (noneOf "&%\n\r\\")
2385+-- <|> try (string "\\&")
2386+-- <|> count 1 anyChar)
2387+-- let plainify bs = case toList bs of
2388+-- [Para ils] -> plain (fromList ils)
2390+-- rawcells <- sepBy1 tableCellRaw amp
2391+-- guard $ length rawcells == cols
2392+-- let rawcells' = zipWith (\c (p, s) -> p ++ trim c ++ s) rawcells prefsufs
2393+-- let tableCell = plainify <$> blocks
2394+-- cells' <- mapM (parseFromString' tableCell) rawcells'
2395+-- let numcells = length cells'
2396+-- guard $ numcells <= cols && numcells >= 1
2397+-- guard $ cells' /= [mempty]
2398+-- -- note: a & b in a three-column table leaves an empty 3rd cell:
2399+-- let cells'' = cells' ++ replicate (cols - numcells) mempty
2403+-- spaces' :: PandocMonad m => LP m ()
2404+-- spaces' = spaces *> skipMany (comment *> spaces)
2406+-- simpTable :: PandocMonad m => String -> Bool -> LP m Blocks
2407+-- simpTable envname hasWidthParameter = try $ do
2408+-- when hasWidthParameter $ () <$ (spaces' >> tok)
2410+-- colspecs <- parseAligns
2411+-- let (aligns, widths, prefsufs) = unzip3 colspecs
2412+-- let cols = length colspecs
2413+-- optional $ controlSeq "caption" *> skipopts *> setCaption
2418+-- header' <- option [] $ try (parseTableRow envname prefsufs <*
2419+-- lbreak <* many1 hline)
2421+-- rows <- sepEndBy (parseTableRow envname prefsufs)
2422+-- (lbreak <* optional (skipMany hline))
2424+-- optional $ controlSeq "caption" *> skipopts *> setCaption
2427+-- let header'' = if null header'
2428+-- then replicate cols mempty
2430+-- lookAhead $ controlSeq "end" -- make sure we're at end
2431+-- return $ table mempty (zip aligns widths) header'' rows
2433+-- removeDoubleQuotes :: String -> String
2434+-- removeDoubleQuotes ('"':xs) =
2435+-- case reverse xs of
2436+-- '"':ys -> reverse ys
2438+-- removeDoubleQuotes xs = xs
2440+-- inputListing :: PandocMonad m => LP m Blocks
2441+-- inputListing = do
2442+-- pos <- getPosition
2443+-- options <- option [] keyvals
2444+-- f <- filter (/='"') <$> braced
2445+-- dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
2446+-- mbCode <- readFileFromDirs dirs f
2447+-- codeLines <- case mbCode of
2448+-- Just s -> return $ lines s
2450+-- report $ CouldNotLoadIncludeFile f pos
2452+-- let (ident,classes,kvs) = parseListingsOptions options
2453+-- let language = case lookup "language" options >>= fromListingsLanguage of
2455+-- Nothing -> take 1 $ languagesByExtension (takeExtension f)
2456+-- let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
2457+-- let lastline = fromMaybe (length codeLines) $
2458+-- lookup "lastline" options >>= safeRead
2459+-- let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
2460+-- drop (firstline - 1) codeLines
2461+-- return $ codeBlockWith (ident,ordNub (classes ++ language),kvs) codeContents
2463+-- parseListingsOptions :: [(String, String)] -> Attr
2464+-- parseListingsOptions options =
2465+-- let kvs = [ (if k == "firstnumber"
2467+-- else k, v) | (k,v) <- options ]
2468+-- classes = [ "numberLines" |
2469+-- lookup "numbers" options == Just "left" ]
2470+-- ++ maybeToList (lookup "language" options
2471+-- >>= fromListingsLanguage)
2472+-- in (fromMaybe "" (lookup "label" options), classes, kvs)