git.iko.soy/typeable/pandoc
on master help sign in
Improvements to LaTeX reader:
be8bddcJohn MacFarlane
src/Text/Pandoc/Readers/LaTeX.hs+63−26
@@ -199,8 +199,23 @@ blockCommand = try $ do
199inBrackets :: Inlines -> Inlines
199inBrackets :: Inlines -> Inlines
200inBrackets x = (str "[") <> x <> (str "]")
200inBrackets x = (str "[") <> x <> (str "]")
201
201
202+-- eat an optional argument and one or more arguments in braces
203+ignoreInlines :: String -> (String, LP Inlines)
204+ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
205+ where optargs = optional opt *> skipMany (optional sp *> braced)
206+ contseq = '\\':name
207+ doraw = (rawInline "latex" . (contseq ++) . snd) <$>
208+ (getState >>= guard . stateParseRaw >> (withRaw optargs))
209+
210+ignoreBlocks :: String -> (String, LP Blocks)
211+ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
212+ where optargs = optional opt *> skipMany (optional sp *> braced)
213+ contseq = '\\':name
214+ doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
215+ (getState >>= guard . stateParseRaw >> (withRaw optargs))
216+
202blockCommands :: M.Map String (LP Blocks)
217blockCommands :: M.Map String (LP Blocks)
203−blockCommands = M.fromList
218+blockCommands = M.fromList $
204 [ ("par", pure mempty)
219 [ ("par", pure mempty)
205 , ("title", mempty <$ (tok >>= addTitle))
220 , ("title", mempty <$ (tok >>= addTitle))
206 , ("subtitle", mempty <$ (tok >>= addSubtitle))
221 , ("subtitle", mempty <$ (tok >>= addSubtitle))
@@ -209,11 +224,7 @@ blockCommands = M.fromList
209 , ("address", mempty <$ (tok >>= addTitle))
224 , ("address", mempty <$ (tok >>= addTitle))
210 , ("signature", mempty <$ authors)
225 , ("signature", mempty <$ authors)
211 , ("date", mempty <$ (tok >>= addDate))
226 , ("date", mempty <$ (tok >>= addDate))
212− , ("maketitle", pure mempty)
227+ -- sectioning
213− -- \ignore{} is used conventionally in literate haskell for definitions
214− -- that are to be processed by the compiler but not printed.
215− , ("ignore", mempty <$ tok)
216− , ("hyperdef", mempty <$ (tok *> tok))
217 , ("chapter", updateState (\s -> s{ stateHasChapters = True }) *> section 0)
228 , ("chapter", updateState (\s -> s{ stateHasChapters = True }) *> section 0)
218 , ("section", section 1)
229 , ("section", section 1)
219 , ("subsection", section 2)
230 , ("subsection", section 2)
@@ -221,23 +232,27 @@ blockCommands = M.fromList
221 , ("paragraph", section 4)
232 , ("paragraph", section 4)
222 , ("subparagraph", section 5)
233 , ("subparagraph", section 5)
223 , ("opening", (para . trimInlines) <$> tok)
234 , ("opening", (para . trimInlines) <$> tok)
224− , ("closing", (para . trimInlines) <$> tok)
235+ , ("closing", closing)
225 , ("rule", optional opt *> tok *> tok *> pure horizontalRule)
236 , ("rule", optional opt *> tok *> tok *> pure horizontalRule)
226 , ("begin", mzero) -- these are here so they won't be interpreted as inline
237 , ("begin", mzero) -- these are here so they won't be interpreted as inline
227 , ("end", mzero)
238 , ("end", mzero)
228 , ("item", loose_item)
239 , ("item", loose_item)
229 , ("documentclass", optional opt *> braced *> preamble)
240 , ("documentclass", optional opt *> braced *> preamble)
241+ ] ++ map ignoreBlocks
242+ -- these commands will be ignored unless --parse-raw is specified,
243+ -- in which case they will appear as raw latex blocks
244+ [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
230− -- should be parsed by macro, but we need this
245+ -- newcommand, etc. should be parsed by macro, but we need this
231− -- here so these aren't parsed as inline
246+ -- here so these aren't parsed as inline commands to ignore
232− , ("newcommand", mempty <$ (tok *> optional opt *> tok))
233− , ("renewcommand", mempty <$ (tok *> optional opt *> tok))
234− , ("newenvironment", mempty <$ (tok *> tok *> tok))
235− , ("renewenvironment", mempty <$ (tok *> tok *> tok))
236− , ("special", pure mempty)
237− , ("pdfannot", pure mempty)
238− , ("pdfstringdef", pure mempty)
247+ , "special", "pdfannot", "pdfstringdef"
239− , ("index", pure mempty)
248+ , "bibliography", "maketitle", "makeindex", "makeglossary"
240− , ("bibliography", pure mempty)
249+ , "addcontentsline", "addtocontents", "addtocounter"
250+ -- \ignore{} is used conventionally in literate haskell for definitions
251+ -- that are to be processed by the compiler but not printed.
252+ , "ignore"
253+ , "hyperdef"
254+ , "noindent"
255+ , "markboth", "markright", "markleft"
241 ]
256 ]
242
257
243addTitle :: Inlines -> LP ()
258addTitle :: Inlines -> LP ()
@@ -288,7 +303,7 @@ isBlockCommand :: String -> Bool
288isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
303isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
289
304
290inlineCommands :: M.Map String (LP Inlines)
305inlineCommands :: M.Map String (LP Inlines)
291−inlineCommands = M.fromList
306+inlineCommands = M.fromList $
292 [ ("emph", emph <$> tok)
307 [ ("emph", emph <$> tok)
293 , ("textit", emph <$> tok)
308 , ("textit", emph <$> tok)
294 , ("textsc", smallcaps <$> tok)
309 , ("textsc", smallcaps <$> tok)
@@ -307,6 +322,8 @@ inlineCommands = M.fromList
307 , ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
322 , ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
308 , ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
323 , ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
309 , ("ensuremath", mathInline $ braced)
324 , ("ensuremath", mathInline $ braced)
325+ , ("P", lit "¶")
326+ , ("S", lit "§")
310 , ("$", lit "$")
327 , ("$", lit "$")
311 , ("%", lit "%")
328 , ("%", lit "%")
312 , ("&", lit "&")
329 , ("&", lit "&")
@@ -339,7 +356,6 @@ inlineCommands = M.fromList
339 , ("pounds", lit "£")
356 , ("pounds", lit "£")
340 , ("euro", lit "€")
357 , ("euro", lit "€")
341 , ("copyright", lit "©")
358 , ("copyright", lit "©")
342− , ("sect", lit "§")
343 , ("`", option (str "`") $ try $ tok >>= accent grave)
359 , ("`", option (str "`") $ try $ tok >>= accent grave)
344 , ("'", option (str "'") $ try $ tok >>= accent acute)
360 , ("'", option (str "'") $ try $ tok >>= accent acute)
345 , ("^", option (str "^") $ try $ tok >>= accent hat)
361 , ("^", option (str "^") $ try $ tok >>= accent hat)
@@ -352,6 +368,7 @@ inlineCommands = M.fromList
352 , (",", pure mempty)
368 , (",", pure mempty)
353 , ("@", pure mempty)
369 , ("@", pure mempty)
354 , (" ", lit "\160")
370 , (" ", lit "\160")
371+ , ("ps", pure $ str "PS." <> space)
355 , ("bar", lit "|")
372 , ("bar", lit "|")
356 , ("textless", lit "<")
373 , ("textless", lit "<")
357 , ("textgreater", lit ">")
374 , ("textgreater", lit ">")
@@ -417,7 +434,10 @@ inlineCommands = M.fromList
417 , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
434 , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
418 complexNatbibCitation AuthorInText)
435 complexNatbibCitation AuthorInText)
419 <|> citation AuthorInText False)
436 <|> citation AuthorInText False)
420− ]
437+ ] ++ map ignoreInlines
438+ -- these commands will be ignored unless --parse-raw is specified,
439+ -- in which case they will appear as raw latex blocks:
440+ [ "index" ]
421
441
422unescapeURL :: String -> String
442unescapeURL :: String -> String
423unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
443unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
@@ -573,7 +593,8 @@ handleIncludes ('\\':xs) =
573 yss <- mapM getfile fs
593 yss <- mapM getfile fs
574 (intercalate "\n" yss ++) `fmap`
594 (intercalate "\n" yss ++) `fmap`
575 handleIncludes rest
595 handleIncludes rest
576− _ -> case runParser verbatimEnv defaultParserState "input" ('\\':xs) of
596+ _ -> case runParser (verbCmd <|> verbatimEnv) defaultParserState
597+ "input" ('\\':xs) of
577 Right (r, rest) -> (r ++) `fmap` handleIncludes rest
598 Right (r, rest) -> (r ++) `fmap` handleIncludes rest
578 _ -> ('\\':) `fmap` handleIncludes xs
599 _ -> ('\\':) `fmap` handleIncludes xs
579handleIncludes (x:xs) = (x:) `fmap` handleIncludes xs
600handleIncludes (x:xs) = (x:) `fmap` handleIncludes xs
@@ -589,6 +610,15 @@ include = do
589 else map (flip replaceExtension ".sty") fs
610 else map (flip replaceExtension ".sty") fs
590 return (fs', rest)
611 return (fs', rest)
591
612
613+verbCmd :: LP (String, String)
614+verbCmd = do
615+ (_,r) <- withRaw $ do
616+ controlSeq "verb"
617+ c <- anyChar
618+ manyTill anyChar (char c)
619+ rest <- getInput
620+ return (r, rest)
621+
592verbatimEnv :: LP (String, String)
622verbatimEnv :: LP (String, String)
593verbatimEnv = do
623verbatimEnv = do
594 (_,r) <- withRaw $ do
624 (_,r) <- withRaw $ do
@@ -659,12 +689,19 @@ letter_contents = do
659 -- add signature (author) and address (title)
689 -- add signature (author) and address (title)
660 let addr = case stateTitle st of
690 let addr = case stateTitle st of
661 [] -> mempty
691 [] -> mempty
662− x -> para $ fromList x
692+ x -> para $ trimInlines $ fromList x
693+ updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
694+ return $ addr <> bs -- sig added by \closing
695+
696+closing :: LP Blocks
697+closing = do
698+ contents <- tok
699+ st <- getState
663 let sigs = case stateAuthors st of
700 let sigs = case stateAuthors st of
664 [] -> mempty
701 [] -> mempty
702+ xs -> para $ trimInlines $ fromList
665− xs -> para $ fromList $ intercalate [LineBreak] xs
703+ $ intercalate [LineBreak] xs
666− updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
667− return $ addr <> bs <> sigs
704+ return $ para (trimInlines contents) <> sigs
668
705
669item :: LP Blocks
706item :: LP Blocks
670item = blocks *> controlSeq "item" *> optional opt *> blocks
707item = blocks *> controlSeq "item" *> optional opt *> blocks
tests/latex-reader.native+2−1
@@ -1,5 +1,6 @@
1Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite"], docAuthors = [[Str "John",Space,Str "MacFarlane"],[Str "Anonymous"]], docDate = [Str "July",Space,Str "17,",Space,Str "2006"]})
1Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite"], docAuthors = [[Str "John",Space,Str "MacFarlane"],[Str "Anonymous"]], docDate = [Str "July",Space,Str "17,",Space,Str "2006"]})
2+[RawBlock "latex" "\\maketitle"
2−[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
3+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
3,HorizontalRule
4,HorizontalRule
4,Header 1 [Str "Headers"]
5,Header 1 [Str "Headers"]
5,Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
6,Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]