Improvements to LaTeX reader:

* Handle \ps
* Ignore ignorable commands in a uniform way.
* Handle \P
* handleIncludes skips \verb commands.
This commit is contained in:
John MacFarlane
2012-02-04 22:28:16 -08:00
parent 4257b9aff5
commit be8bddcaf3
2 changed files with 65 additions and 27 deletions
+63 -26
View File
@@ -199,8 +199,23 @@ blockCommand = try $ do
inBrackets :: Inlines -> Inlines
inBrackets x = (str "[") <> x <> (str "]")
-- eat an optional argument and one or more arguments in braces
ignoreInlines :: String -> (String, LP Inlines)
ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
where optargs = optional opt *> skipMany (optional sp *> braced)
contseq = '\\':name
doraw = (rawInline "latex" . (contseq ++) . snd) <$>
(getState >>= guard . stateParseRaw >> (withRaw optargs))
ignoreBlocks :: String -> (String, LP Blocks)
ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
where optargs = optional opt *> skipMany (optional sp *> braced)
contseq = '\\':name
doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
(getState >>= guard . stateParseRaw >> (withRaw optargs))
blockCommands :: M.Map String (LP Blocks)
blockCommands = M.fromList
blockCommands = M.fromList $
[ ("par", pure mempty)
, ("title", mempty <$ (tok >>= addTitle))
, ("subtitle", mempty <$ (tok >>= addSubtitle))
@@ -209,11 +224,7 @@ blockCommands = M.fromList
, ("address", mempty <$ (tok >>= addTitle))
, ("signature", mempty <$ authors)
, ("date", mempty <$ (tok >>= addDate))
, ("maketitle", pure mempty)
-- \ignore{} is used conventionally in literate haskell for definitions
-- that are to be processed by the compiler but not printed.
, ("ignore", mempty <$ tok)
, ("hyperdef", mempty <$ (tok *> tok))
-- sectioning
, ("chapter", updateState (\s -> s{ stateHasChapters = True }) *> section 0)
, ("section", section 1)
, ("subsection", section 2)
@@ -221,23 +232,27 @@ blockCommands = M.fromList
, ("paragraph", section 4)
, ("subparagraph", section 5)
, ("opening", (para . trimInlines) <$> tok)
, ("closing", (para . trimInlines) <$> tok)
, ("closing", closing)
, ("rule", optional opt *> tok *> tok *> pure horizontalRule)
, ("begin", mzero) -- these are here so they won't be interpreted as inline
, ("end", mzero)
, ("item", loose_item)
, ("documentclass", optional opt *> braced *> preamble)
-- should be parsed by macro, but we need this
-- here so these aren't parsed as inline
, ("newcommand", mempty <$ (tok *> optional opt *> tok))
, ("renewcommand", mempty <$ (tok *> optional opt *> tok))
, ("newenvironment", mempty <$ (tok *> tok *> tok))
, ("renewenvironment", mempty <$ (tok *> tok *> tok))
, ("special", pure mempty)
, ("pdfannot", pure mempty)
, ("pdfstringdef", pure mempty)
, ("index", pure mempty)
, ("bibliography", pure mempty)
] ++ map ignoreBlocks
-- these commands will be ignored unless --parse-raw is specified,
-- in which case they will appear as raw latex blocks
[ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
-- newcommand, etc. should be parsed by macro, but we need this
-- here so these aren't parsed as inline commands to ignore
, "special", "pdfannot", "pdfstringdef"
, "bibliography", "maketitle", "makeindex", "makeglossary"
, "addcontentsline", "addtocontents", "addtocounter"
-- \ignore{} is used conventionally in literate haskell for definitions
-- that are to be processed by the compiler but not printed.
, "ignore"
, "hyperdef"
, "noindent"
, "markboth", "markright", "markleft"
]
addTitle :: Inlines -> LP ()
@@ -288,7 +303,7 @@ isBlockCommand :: String -> Bool
isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
inlineCommands :: M.Map String (LP Inlines)
inlineCommands = M.fromList
inlineCommands = M.fromList $
[ ("emph", emph <$> tok)
, ("textit", emph <$> tok)
, ("textsc", smallcaps <$> tok)
@@ -307,6 +322,8 @@ inlineCommands = M.fromList
, ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
, ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
, ("ensuremath", mathInline $ braced)
, ("P", lit "")
, ("S", lit "§")
, ("$", lit "$")
, ("%", lit "%")
, ("&", lit "&")
@@ -339,7 +356,6 @@ inlineCommands = M.fromList
, ("pounds", lit "£")
, ("euro", lit "")
, ("copyright", lit "©")
, ("sect", lit "§")
, ("`", option (str "`") $ try $ tok >>= accent grave)
, ("'", option (str "'") $ try $ tok >>= accent acute)
, ("^", option (str "^") $ try $ tok >>= accent hat)
@@ -352,6 +368,7 @@ inlineCommands = M.fromList
, (",", pure mempty)
, ("@", pure mempty)
, (" ", lit "\160")
, ("ps", pure $ str "PS." <> space)
, ("bar", lit "|")
, ("textless", lit "<")
, ("textgreater", lit ">")
@@ -417,7 +434,10 @@ inlineCommands = M.fromList
, ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
complexNatbibCitation AuthorInText)
<|> citation AuthorInText False)
]
] ++ map ignoreInlines
-- these commands will be ignored unless --parse-raw is specified,
-- in which case they will appear as raw latex blocks:
[ "index" ]
unescapeURL :: String -> String
unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
@@ -573,7 +593,8 @@ handleIncludes ('\\':xs) =
yss <- mapM getfile fs
(intercalate "\n" yss ++) `fmap`
handleIncludes rest
_ -> case runParser verbatimEnv defaultParserState "input" ('\\':xs) of
_ -> case runParser (verbCmd <|> verbatimEnv) defaultParserState
"input" ('\\':xs) of
Right (r, rest) -> (r ++) `fmap` handleIncludes rest
_ -> ('\\':) `fmap` handleIncludes xs
handleIncludes (x:xs) = (x:) `fmap` handleIncludes xs
@@ -589,6 +610,15 @@ include = do
else map (flip replaceExtension ".sty") fs
return (fs', rest)
verbCmd :: LP (String, String)
verbCmd = do
(_,r) <- withRaw $ do
controlSeq "verb"
c <- anyChar
manyTill anyChar (char c)
rest <- getInput
return (r, rest)
verbatimEnv :: LP (String, String)
verbatimEnv = do
(_,r) <- withRaw $ do
@@ -659,12 +689,19 @@ letter_contents = do
-- add signature (author) and address (title)
let addr = case stateTitle st of
[] -> mempty
x -> para $ fromList x
x -> para $ trimInlines $ fromList x
updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
return $ addr <> bs -- sig added by \closing
closing :: LP Blocks
closing = do
contents <- tok
st <- getState
let sigs = case stateAuthors st of
[] -> mempty
xs -> para $ fromList $ intercalate [LineBreak] xs
updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
return $ addr <> bs <> sigs
xs -> para $ trimInlines $ fromList
$ intercalate [LineBreak] xs
return $ para (trimInlines contents) <> sigs
item :: LP Blocks
item = blocks *> controlSeq "item" *> optional opt *> blocks
+2 -1
View File
@@ -1,5 +1,6 @@
Pandoc (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"]})
[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."]
[RawBlock "latex" "\\maketitle"
,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."]
,HorizontalRule
,Header 1 [Str "Headers"]
,Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]