2007-11-03 23:27:58 +00:00
|
|
|
{-
|
2010-03-23 13:31:09 -07:00
|
|
|
Copyright (C) 2006-2010 John MacFarlane <jgm@berkeley.edu>
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
-}
|
|
|
|
|
|
|
|
{- |
|
|
|
|
Module : Text.Pandoc.Readers.LaTeX
|
2010-03-23 13:31:09 -07:00
|
|
|
Copyright : Copyright (C) 2006-2010 John MacFarlane
|
2007-11-03 23:27:58 +00:00
|
|
|
License : GNU GPL, version 2 or above
|
|
|
|
|
|
|
|
Maintainer : John MacFarlane <jgm@berkeley.edu>
|
|
|
|
Stability : alpha
|
|
|
|
Portability : portable
|
|
|
|
|
|
|
|
Conversion of LaTeX to 'Pandoc' document.
|
|
|
|
-}
|
|
|
|
module Text.Pandoc.Readers.LaTeX (
|
|
|
|
readLaTeX,
|
|
|
|
rawLaTeXInline,
|
2008-08-11 07:04:36 +00:00
|
|
|
rawLaTeXEnvironment'
|
2007-11-03 23:27:58 +00:00
|
|
|
) where
|
|
|
|
|
|
|
|
import Text.ParserCombinators.Parsec
|
|
|
|
import Text.Pandoc.Definition
|
2010-07-04 13:43:45 -07:00
|
|
|
import Text.Pandoc.Shared
|
|
|
|
import Text.Pandoc.Parsing
|
2007-11-03 23:27:58 +00:00
|
|
|
import Data.Maybe ( fromMaybe )
|
2010-12-13 21:32:04 +01:00
|
|
|
import Data.Char ( chr, toUpper )
|
2007-11-03 23:27:58 +00:00
|
|
|
import Data.List ( isPrefixOf, isSuffixOf )
|
2011-01-05 10:11:24 -08:00
|
|
|
import Control.Monad ( when, guard )
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
-- | Parse LaTeX from string and return 'Pandoc' document.
|
|
|
|
readLaTeX :: ParserState -- ^ Parser state, including options for parser
|
2009-10-04 22:09:23 +00:00
|
|
|
-> String -- ^ String to parse (assumes @'\n'@ line endings)
|
2007-11-03 23:27:58 +00:00
|
|
|
-> Pandoc
|
|
|
|
readLaTeX = readWith parseLaTeX
|
|
|
|
|
|
|
|
-- characters with special meaning
|
2008-07-14 16:19:42 +00:00
|
|
|
specialChars :: [Char]
|
2010-12-13 21:32:04 +01:00
|
|
|
specialChars = "\\`$%^&_~#{}[]\n \t|<>'\"-"
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- utility functions
|
|
|
|
--
|
|
|
|
|
|
|
|
-- | Returns text between brackets and its matching pair.
|
2008-07-14 16:19:42 +00:00
|
|
|
bracketedText :: Char -> Char -> GenParser Char st [Char]
|
2007-11-03 23:27:58 +00:00
|
|
|
bracketedText openB closeB = do
|
|
|
|
result <- charsInBalanced' openB closeB
|
|
|
|
return $ [openB] ++ result ++ [closeB]
|
|
|
|
|
|
|
|
-- | Returns an option or argument of a LaTeX command.
|
2008-07-14 16:19:42 +00:00
|
|
|
optOrArg :: GenParser Char st [Char]
|
2011-01-05 11:54:06 -08:00
|
|
|
optOrArg = try $ spaces >> (bracketedText '{' '}' <|> bracketedText '[' ']')
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
-- | True if the string begins with '{'.
|
2008-07-14 16:19:42 +00:00
|
|
|
isArg :: [Char] -> Bool
|
|
|
|
isArg ('{':_) = True
|
|
|
|
isArg _ = False
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
-- | Returns list of options and arguments of a LaTeX command.
|
2008-07-14 16:19:42 +00:00
|
|
|
commandArgs :: GenParser Char st [[Char]]
|
2007-11-03 23:27:58 +00:00
|
|
|
commandArgs = many optOrArg
|
|
|
|
|
|
|
|
-- | Parses LaTeX command, returns (name, star, list of options or arguments).
|
2008-07-14 16:19:42 +00:00
|
|
|
command :: GenParser Char st ([Char], [Char], [[Char]])
|
2007-11-03 23:27:58 +00:00
|
|
|
command = do
|
|
|
|
char '\\'
|
|
|
|
name <- many1 letter
|
|
|
|
star <- option "" (string "*") -- some commands have starred versions
|
|
|
|
args <- commandArgs
|
|
|
|
return (name, star, args)
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
begin :: [Char] -> GenParser Char st [Char]
|
2007-11-03 23:27:58 +00:00
|
|
|
begin name = try $ do
|
|
|
|
string $ "\\begin{" ++ name ++ "}"
|
|
|
|
optional commandArgs
|
|
|
|
spaces
|
|
|
|
return name
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
end :: [Char] -> GenParser Char st [Char]
|
2007-11-03 23:27:58 +00:00
|
|
|
end name = try $ do
|
|
|
|
string $ "\\end{" ++ name ++ "}"
|
|
|
|
return name
|
|
|
|
|
|
|
|
-- | Returns a list of block elements containing the contents of an
|
|
|
|
-- environment.
|
2008-07-15 00:14:58 +00:00
|
|
|
environment :: [Char] -> GenParser Char ParserState [Block]
|
2008-08-11 07:04:36 +00:00
|
|
|
environment name = try $ begin name >> spaces >> manyTill block (end name) >>~ spaces
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
anyEnvironment :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
anyEnvironment = try $ do
|
|
|
|
string "\\begin{"
|
|
|
|
name <- many letter
|
|
|
|
star <- option "" (string "*") -- some environments have starred variants
|
|
|
|
char '}'
|
|
|
|
optional commandArgs
|
|
|
|
spaces
|
|
|
|
contents <- manyTill block (end (name ++ star))
|
2008-08-11 07:04:36 +00:00
|
|
|
spaces
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ BlockQuote contents
|
|
|
|
|
|
|
|
--
|
|
|
|
-- parsing documents
|
|
|
|
--
|
|
|
|
|
|
|
|
-- | Process LaTeX preamble, extracting metadata.
|
2008-07-14 16:19:42 +00:00
|
|
|
processLaTeXPreamble :: GenParser Char ParserState ()
|
2011-01-05 09:04:03 -08:00
|
|
|
processLaTeXPreamble = do
|
|
|
|
try $ string "\\documentclass"
|
|
|
|
skipMany $ bibliographic <|> macro <|> commentBlock <|> skipChar
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
-- | Parse LaTeX and return 'Pandoc'.
|
2008-07-14 16:19:42 +00:00
|
|
|
parseLaTeX :: GenParser Char ParserState Pandoc
|
2007-11-03 23:27:58 +00:00
|
|
|
parseLaTeX = do
|
2011-01-05 09:04:03 -08:00
|
|
|
skipMany $ spaces >> comment
|
2007-11-03 23:27:58 +00:00
|
|
|
spaces
|
2011-01-05 09:04:03 -08:00
|
|
|
blocks <- try (processLaTeXPreamble >> environment "document")
|
|
|
|
<|> (many block >>~ (spaces >> eof))
|
2007-11-03 23:27:58 +00:00
|
|
|
state <- getState
|
|
|
|
let blocks' = filter (/= Null) blocks
|
|
|
|
let title' = stateTitle state
|
|
|
|
let authors' = stateAuthors state
|
|
|
|
let date' = stateDate state
|
|
|
|
return $ Pandoc (Meta title' authors' date') blocks'
|
|
|
|
|
|
|
|
--
|
|
|
|
-- parsing blocks
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
parseBlocks :: GenParser Char ParserState [Block]
|
2007-11-03 23:27:58 +00:00
|
|
|
parseBlocks = spaces >> many block
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
block :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
block = choice [ hrule
|
|
|
|
, codeBlock
|
|
|
|
, header
|
|
|
|
, list
|
|
|
|
, blockQuote
|
2010-12-13 21:32:04 +01:00
|
|
|
, commentBlock
|
2011-01-04 19:18:20 -08:00
|
|
|
, macro
|
2007-11-03 23:27:58 +00:00
|
|
|
, bibliographic
|
|
|
|
, para
|
|
|
|
, itemBlock
|
|
|
|
, unknownEnvironment
|
2008-09-06 18:05:18 +00:00
|
|
|
, ignore
|
2010-12-14 19:34:28 -08:00
|
|
|
, unknownCommand
|
|
|
|
] <?> "block"
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- header blocks
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
header :: GenParser Char ParserState Block
|
2010-07-13 19:18:58 -07:00
|
|
|
header = section <|> chapter
|
|
|
|
|
|
|
|
chapter :: GenParser Char ParserState Block
|
|
|
|
chapter = try $ do
|
|
|
|
string "\\chapter"
|
|
|
|
result <- headerWithLevel 1
|
|
|
|
updateState $ \s -> s{ stateHasChapters = True }
|
|
|
|
return result
|
|
|
|
|
|
|
|
section :: GenParser Char ParserState Block
|
|
|
|
section = try $ do
|
2007-11-03 23:27:58 +00:00
|
|
|
char '\\'
|
|
|
|
subs <- many (try (string "sub"))
|
2010-02-12 03:03:23 +00:00
|
|
|
base <- try (string "section" >> return 1) <|> (string "paragraph" >> return 4)
|
2010-07-13 19:18:58 -07:00
|
|
|
st <- getState
|
|
|
|
let lev = if stateHasChapters st
|
|
|
|
then length subs + base + 1
|
|
|
|
else length subs + base
|
|
|
|
headerWithLevel lev
|
|
|
|
|
|
|
|
headerWithLevel :: Int -> GenParser Char ParserState Block
|
|
|
|
headerWithLevel lev = try $ do
|
2010-07-13 19:22:41 -07:00
|
|
|
spaces
|
2007-11-03 23:27:58 +00:00
|
|
|
optional (char '*')
|
2010-07-13 19:22:41 -07:00
|
|
|
spaces
|
2010-03-14 23:23:07 +00:00
|
|
|
optional $ bracketedText '[' ']' -- alt title
|
2010-07-13 19:22:41 -07:00
|
|
|
spaces
|
2007-11-03 23:27:58 +00:00
|
|
|
char '{'
|
2008-07-14 16:19:42 +00:00
|
|
|
title' <- manyTill inline (char '}')
|
2007-11-03 23:27:58 +00:00
|
|
|
spaces
|
2010-07-13 19:18:58 -07:00
|
|
|
return $ Header lev (normalizeSpaces title')
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- hrule block
|
|
|
|
--
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
hrule :: GenParser Char st Block
|
2007-11-03 23:27:58 +00:00
|
|
|
hrule = oneOfStrings [ "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n\n",
|
|
|
|
"\\newpage" ] >> spaces >> return HorizontalRule
|
|
|
|
|
|
|
|
--
|
|
|
|
-- code blocks
|
|
|
|
--
|
|
|
|
|
2008-12-02 22:42:08 +00:00
|
|
|
codeBlock :: GenParser Char ParserState Block
|
2010-12-30 00:48:55 +05:30
|
|
|
codeBlock = codeBlockWith "verbatim" <|> codeBlockWith "Verbatim" <|> codeBlockWith "lstlisting" <|> lhsCodeBlock
|
2008-12-02 22:42:08 +00:00
|
|
|
-- Note: Verbatim is from fancyvrb.
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-08-26 20:36:06 +00:00
|
|
|
codeBlockWith :: String -> GenParser Char st Block
|
|
|
|
codeBlockWith env = try $ do
|
|
|
|
string ("\\begin{" ++ env ++ "}") -- don't use begin function because it
|
|
|
|
-- gobbles whitespace
|
2007-11-03 23:27:58 +00:00
|
|
|
optional blanklines -- we want to gobble blank lines, but not
|
|
|
|
-- leading space
|
2008-08-26 20:36:06 +00:00
|
|
|
contents <- manyTill anyChar (try (string $ "\\end{" ++ env ++ "}"))
|
2007-11-03 23:27:58 +00:00
|
|
|
spaces
|
2008-08-26 20:36:06 +00:00
|
|
|
let classes = if env == "code" then ["haskell"] else []
|
|
|
|
return $ CodeBlock ("",classes,[]) (stripTrailingNewlines contents)
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-12-02 22:42:08 +00:00
|
|
|
lhsCodeBlock :: GenParser Char ParserState Block
|
|
|
|
lhsCodeBlock = do
|
|
|
|
failUnlessLHS
|
|
|
|
(CodeBlock (_,_,_) cont) <- codeBlockWith "code"
|
2009-11-03 06:50:17 +00:00
|
|
|
return $ CodeBlock ("", ["sourceCode","literate","haskell"], []) cont
|
2008-12-02 22:42:08 +00:00
|
|
|
|
2007-11-03 23:27:58 +00:00
|
|
|
--
|
|
|
|
-- block quotes
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
blockQuote :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
blockQuote = (environment "quote" <|> environment "quotation") >>~ spaces >>=
|
|
|
|
return . BlockQuote
|
|
|
|
|
|
|
|
--
|
|
|
|
-- list blocks
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
list :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
list = bulletList <|> orderedList <|> definitionList <?> "list"
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
listItem :: GenParser Char ParserState ([Inline], [Block])
|
2007-11-03 23:27:58 +00:00
|
|
|
listItem = try $ do
|
|
|
|
("item", _, args) <- command
|
|
|
|
spaces
|
|
|
|
state <- getState
|
|
|
|
let oldParserContext = stateParserContext state
|
2008-07-14 16:19:42 +00:00
|
|
|
updateState (\s -> s {stateParserContext = ListItemState})
|
2007-11-03 23:27:58 +00:00
|
|
|
blocks <- many block
|
2008-07-14 16:19:42 +00:00
|
|
|
updateState (\s -> s {stateParserContext = oldParserContext})
|
2007-11-03 23:27:58 +00:00
|
|
|
opt <- case args of
|
|
|
|
([x]) | "[" `isPrefixOf` x && "]" `isSuffixOf` x ->
|
|
|
|
parseFromString (many inline) $ tail $ init x
|
|
|
|
_ -> return []
|
|
|
|
return (opt, blocks)
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
orderedList :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
orderedList = try $ do
|
|
|
|
string "\\begin{enumerate}"
|
|
|
|
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
|
|
|
|
try $ do failIfStrict
|
|
|
|
char '['
|
|
|
|
res <- anyOrderedListMarker
|
|
|
|
char ']'
|
|
|
|
return res
|
|
|
|
spaces
|
|
|
|
option "" $ try $ do string "\\setlength{\\itemindent}"
|
|
|
|
char '{'
|
|
|
|
manyTill anyChar (char '}')
|
|
|
|
spaces
|
|
|
|
start <- option 1 $ try $ do failIfStrict
|
|
|
|
string "\\setcounter{enum"
|
|
|
|
many1 (oneOf "iv")
|
|
|
|
string "}{"
|
|
|
|
num <- many1 digit
|
|
|
|
char '}'
|
|
|
|
spaces
|
|
|
|
return $ (read num) + 1
|
|
|
|
items <- many listItem
|
|
|
|
end "enumerate"
|
|
|
|
spaces
|
|
|
|
return $ OrderedList (start, style, delim) $ map snd items
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
bulletList :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
bulletList = try $ do
|
|
|
|
begin "itemize"
|
|
|
|
spaces
|
|
|
|
items <- many listItem
|
|
|
|
end "itemize"
|
|
|
|
spaces
|
|
|
|
return (BulletList $ map snd items)
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
definitionList :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
definitionList = try $ do
|
|
|
|
begin "description"
|
|
|
|
spaces
|
|
|
|
items <- many listItem
|
|
|
|
end "description"
|
|
|
|
spaces
|
2009-12-07 08:26:53 +00:00
|
|
|
return $ DefinitionList $ map (\(t,d) -> (t,[d])) items
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- paragraph block
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
para :: GenParser Char ParserState Block
|
2008-09-06 18:05:18 +00:00
|
|
|
para = do
|
|
|
|
res <- many1 inline
|
|
|
|
spaces
|
|
|
|
return $ if null (filter (`notElem` [Str "", Space]) res)
|
|
|
|
then Null
|
|
|
|
else Para $ normalizeSpaces res
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- title authors date
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
bibliographic :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
bibliographic = choice [ maketitle, title, authors, date ]
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
maketitle :: GenParser Char st Block
|
2007-11-03 23:27:58 +00:00
|
|
|
maketitle = try (string "\\maketitle") >> spaces >> return Null
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
title :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
title = try $ do
|
|
|
|
string "\\title{"
|
|
|
|
tit <- manyTill inline (char '}')
|
|
|
|
spaces
|
|
|
|
updateState (\state -> state { stateTitle = tit })
|
|
|
|
return Null
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
authors :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
authors = try $ do
|
|
|
|
string "\\author{"
|
2009-12-31 01:16:34 +00:00
|
|
|
raw <- many1 (notFollowedBy (char '}') >> inline)
|
2010-12-21 08:41:24 -08:00
|
|
|
let authors' = map normalizeSpaces $ splitBy (== LineBreak) raw
|
2009-12-31 01:12:44 +00:00
|
|
|
char '}'
|
2007-11-03 23:27:58 +00:00
|
|
|
spaces
|
2009-12-31 01:16:34 +00:00
|
|
|
updateState (\s -> s { stateAuthors = authors' })
|
2007-11-03 23:27:58 +00:00
|
|
|
return Null
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
date :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
date = try $ do
|
|
|
|
string "\\date{"
|
2009-12-31 01:12:44 +00:00
|
|
|
date' <- manyTill inline (char '}')
|
2007-11-03 23:27:58 +00:00
|
|
|
spaces
|
2009-12-31 01:12:44 +00:00
|
|
|
updateState (\state -> state { stateDate = normalizeSpaces date' })
|
2007-11-03 23:27:58 +00:00
|
|
|
return Null
|
|
|
|
|
|
|
|
--
|
|
|
|
-- item block
|
|
|
|
-- for use in unknown environments that aren't being parsed as raw latex
|
|
|
|
--
|
|
|
|
|
|
|
|
-- this forces items to be parsed in different blocks
|
2008-07-14 16:19:42 +00:00
|
|
|
itemBlock :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
itemBlock = try $ do
|
|
|
|
("item", _, args) <- command
|
|
|
|
state <- getState
|
2008-09-06 18:05:18 +00:00
|
|
|
if stateParserContext state == ListItemState
|
2007-11-03 23:27:58 +00:00
|
|
|
then fail "item should be handled by list block"
|
|
|
|
else if null args
|
|
|
|
then return Null
|
|
|
|
else return $ Plain [Str (stripFirstAndLast (head args))]
|
|
|
|
|
|
|
|
--
|
|
|
|
-- raw LaTeX
|
|
|
|
--
|
|
|
|
|
|
|
|
-- | Parse any LaTeX environment and return a Para block containing
|
|
|
|
-- the whole literal environment as raw TeX.
|
|
|
|
rawLaTeXEnvironment :: GenParser Char st Block
|
2008-08-11 07:04:36 +00:00
|
|
|
rawLaTeXEnvironment = do
|
|
|
|
contents <- rawLaTeXEnvironment'
|
|
|
|
spaces
|
|
|
|
return $ Para [TeX contents]
|
|
|
|
|
|
|
|
-- | Parse any LaTeX environment and return a string containing
|
|
|
|
-- the whole literal environment as raw TeX.
|
|
|
|
rawLaTeXEnvironment' :: GenParser Char st String
|
|
|
|
rawLaTeXEnvironment' = try $ do
|
2007-11-03 23:27:58 +00:00
|
|
|
string "\\begin{"
|
|
|
|
name <- many1 letter
|
|
|
|
star <- option "" (string "*") -- for starred variants
|
|
|
|
let name' = name ++ star
|
|
|
|
char '}'
|
|
|
|
args <- option [] commandArgs
|
|
|
|
let argStr = concat args
|
|
|
|
contents <- manyTill (choice [ (many1 (noneOf "\\")),
|
2008-08-11 07:04:36 +00:00
|
|
|
rawLaTeXEnvironment',
|
2007-11-03 23:27:58 +00:00
|
|
|
string "\\" ])
|
|
|
|
(end name')
|
2008-08-11 07:04:36 +00:00
|
|
|
return $ "\\begin{" ++ name' ++ "}" ++ argStr ++
|
|
|
|
concat contents ++ "\\end{" ++ name' ++ "}"
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
unknownEnvironment :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
unknownEnvironment = try $ do
|
|
|
|
state <- getState
|
|
|
|
result <- if stateParseRaw state -- check whether we should include raw TeX
|
|
|
|
then rawLaTeXEnvironment -- if so, get whole raw environment
|
|
|
|
else anyEnvironment -- otherwise just the contents
|
|
|
|
return result
|
|
|
|
|
2008-09-06 18:05:18 +00:00
|
|
|
-- \ignore{} is used conventionally in literate haskell for definitions
|
|
|
|
-- that are to be processed by the compiler but not printed.
|
|
|
|
ignore :: GenParser Char ParserState Block
|
|
|
|
ignore = try $ do
|
|
|
|
("ignore", _, _) <- command
|
|
|
|
spaces
|
|
|
|
return Null
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
unknownCommand :: GenParser Char ParserState Block
|
2007-11-03 23:27:58 +00:00
|
|
|
unknownCommand = try $ do
|
2010-12-10 23:21:24 -08:00
|
|
|
spaces
|
|
|
|
notFollowedBy' $ oneOfStrings ["\\begin","\\end","\\item"]
|
2007-11-03 23:27:58 +00:00
|
|
|
state <- getState
|
2010-03-14 23:23:14 +00:00
|
|
|
when (stateParserContext state == ListItemState) $
|
|
|
|
notFollowedBy' (string "\\item")
|
2007-11-03 23:27:58 +00:00
|
|
|
if stateParseRaw state
|
2008-09-06 18:05:18 +00:00
|
|
|
then do
|
|
|
|
(name, star, args) <- command
|
|
|
|
spaces
|
|
|
|
return $ Plain [TeX ("\\" ++ name ++ star ++ concat args)]
|
2010-03-14 23:23:14 +00:00
|
|
|
else do
|
|
|
|
(name, _, args) <- command
|
2008-09-06 18:05:18 +00:00
|
|
|
spaces
|
2010-03-14 23:23:14 +00:00
|
|
|
if name `elem` commandsToIgnore
|
|
|
|
then return Null
|
|
|
|
else return $ Plain [Str $ concat args]
|
|
|
|
|
|
|
|
commandsToIgnore :: [String]
|
2011-01-05 11:56:37 -08:00
|
|
|
commandsToIgnore = ["special","pdfannot","pdfstringdef", "index","bibliography"]
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2011-01-05 09:04:03 -08:00
|
|
|
skipChar :: GenParser Char ParserState Block
|
|
|
|
skipChar = do
|
|
|
|
satisfy (/='\\') <|>
|
|
|
|
(notFollowedBy' (lookAhead $ string "\\begin{document}") >> anyChar)
|
|
|
|
spaces
|
|
|
|
return Null
|
2010-12-14 19:34:28 -08:00
|
|
|
|
2010-12-13 21:32:04 +01:00
|
|
|
commentBlock :: GenParser Char st Block
|
|
|
|
commentBlock = comment >> return Null
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- inline
|
|
|
|
--
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
inline :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
inline = choice [ str
|
|
|
|
, endline
|
|
|
|
, whitespace
|
|
|
|
, quoted
|
|
|
|
, apostrophe
|
|
|
|
, strong
|
|
|
|
, math
|
|
|
|
, ellipses
|
|
|
|
, emDash
|
|
|
|
, enDash
|
|
|
|
, hyphen
|
|
|
|
, emph
|
|
|
|
, strikeout
|
|
|
|
, superscript
|
|
|
|
, subscript
|
|
|
|
, ref
|
|
|
|
, lab
|
|
|
|
, code
|
|
|
|
, url
|
|
|
|
, link
|
|
|
|
, image
|
|
|
|
, footnote
|
|
|
|
, linebreak
|
|
|
|
, accentedChar
|
2010-03-13 04:30:27 +00:00
|
|
|
, nonbreakingSpace
|
2010-12-13 21:32:04 +01:00
|
|
|
, cite
|
2007-11-03 23:27:58 +00:00
|
|
|
, specialChar
|
2010-04-26 23:17:34 -07:00
|
|
|
, rawLaTeXInline'
|
2007-11-03 23:27:58 +00:00
|
|
|
, escapedChar
|
|
|
|
, unescapedChar
|
2010-12-13 21:32:04 +01:00
|
|
|
, comment
|
2007-11-03 23:27:58 +00:00
|
|
|
] <?> "inline"
|
|
|
|
|
2010-12-13 21:32:04 +01:00
|
|
|
|
|
|
|
-- latex comment
|
|
|
|
comment :: GenParser Char st Inline
|
|
|
|
comment = try $ char '%' >> manyTill anyChar newline >> spaces >> return (Str "")
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
accentedChar :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
accentedChar = normalAccentedChar <|> specialAccentedChar
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
normalAccentedChar :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
normalAccentedChar = try $ do
|
|
|
|
char '\\'
|
|
|
|
accent <- oneOf "'`^\"~"
|
|
|
|
character <- (try $ char '{' >> letter >>~ char '}') <|> letter
|
|
|
|
let table = fromMaybe [] $ lookup character accentTable
|
|
|
|
let result = case lookup accent table of
|
|
|
|
Just num -> chr num
|
|
|
|
Nothing -> '?'
|
|
|
|
return $ Str [result]
|
|
|
|
|
|
|
|
-- an association list of letters and association list of accents
|
|
|
|
-- and decimal character numbers.
|
2008-07-15 00:14:58 +00:00
|
|
|
accentTable :: [(Char, [(Char, Int)])]
|
2007-11-03 23:27:58 +00:00
|
|
|
accentTable =
|
|
|
|
[ ('A', [('`', 192), ('\'', 193), ('^', 194), ('~', 195), ('"', 196)]),
|
|
|
|
('E', [('`', 200), ('\'', 201), ('^', 202), ('"', 203)]),
|
|
|
|
('I', [('`', 204), ('\'', 205), ('^', 206), ('"', 207)]),
|
|
|
|
('N', [('~', 209)]),
|
|
|
|
('O', [('`', 210), ('\'', 211), ('^', 212), ('~', 213), ('"', 214)]),
|
|
|
|
('U', [('`', 217), ('\'', 218), ('^', 219), ('"', 220)]),
|
|
|
|
('a', [('`', 224), ('\'', 225), ('^', 227), ('"', 228)]),
|
|
|
|
('e', [('`', 232), ('\'', 233), ('^', 234), ('"', 235)]),
|
|
|
|
('i', [('`', 236), ('\'', 237), ('^', 238), ('"', 239)]),
|
|
|
|
('n', [('~', 241)]),
|
|
|
|
('o', [('`', 242), ('\'', 243), ('^', 244), ('~', 245), ('"', 246)]),
|
|
|
|
('u', [('`', 249), ('\'', 250), ('^', 251), ('"', 252)]) ]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
specialAccentedChar :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
specialAccentedChar = choice [ ccedil, aring, iuml, szlig, aelig,
|
|
|
|
oslash, pound, euro, copyright, sect ]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
ccedil :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
ccedil = try $ do
|
|
|
|
char '\\'
|
2008-07-15 00:14:58 +00:00
|
|
|
letter' <- oneOfStrings ["cc", "cC"]
|
|
|
|
let num = if letter' == "cc" then 231 else 199
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ Str [chr num]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
aring :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
aring = try $ do
|
|
|
|
char '\\'
|
2008-07-15 00:14:58 +00:00
|
|
|
letter' <- oneOfStrings ["aa", "AA"]
|
|
|
|
let num = if letter' == "aa" then 229 else 197
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ Str [chr num]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
iuml :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
iuml = try (string "\\\"") >> oneOfStrings ["\\i", "{\\i}"] >>
|
|
|
|
return (Str [chr 239])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
szlig :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
szlig = try (string "\\ss") >> return (Str [chr 223])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
oslash :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
oslash = try $ do
|
|
|
|
char '\\'
|
2008-07-15 00:14:58 +00:00
|
|
|
letter' <- choice [char 'o', char 'O']
|
|
|
|
let num = if letter' == 'o' then 248 else 216
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ Str [chr num]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
aelig :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
aelig = try $ do
|
|
|
|
char '\\'
|
2008-07-15 00:14:58 +00:00
|
|
|
letter' <- oneOfStrings ["ae", "AE"]
|
|
|
|
let num = if letter' == "ae" then 230 else 198
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ Str [chr num]
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
pound :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
pound = try (string "\\pounds") >> return (Str [chr 163])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
euro :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
euro = try (string "\\euro") >> return (Str [chr 8364])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
copyright :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
copyright = try (string "\\copyright") >> return (Str [chr 169])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
sect :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
sect = try (string "\\S") >> return (Str [chr 167])
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
escapedChar :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
escapedChar = do
|
2010-02-26 23:57:41 +00:00
|
|
|
result <- escaped (oneOf specialChars)
|
2007-11-03 23:27:58 +00:00
|
|
|
return $ if result == Str "\n" then Str " " else result
|
|
|
|
|
2008-09-06 20:45:53 +00:00
|
|
|
-- nonescaped special characters
|
2008-07-15 00:14:58 +00:00
|
|
|
unescapedChar :: GenParser Char st Inline
|
2010-12-13 21:32:04 +01:00
|
|
|
unescapedChar = oneOf "`$^&_#{}[]|<>" >>= return . (\c -> Str [c])
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
specialChar :: GenParser Char st Inline
|
2010-02-27 02:35:46 +00:00
|
|
|
specialChar = choice [ spacer, interwordSpace,
|
|
|
|
backslash, tilde, caret,
|
|
|
|
bar, lt, gt, doubleQuote ]
|
|
|
|
|
|
|
|
spacer :: GenParser Char st Inline
|
|
|
|
spacer = try (string "\\,") >> return (Str "")
|
|
|
|
|
|
|
|
interwordSpace :: GenParser Char st Inline
|
|
|
|
interwordSpace = try (string "\\ ") >> return (Str "\160")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
backslash :: GenParser Char st Inline
|
2008-09-06 20:45:53 +00:00
|
|
|
backslash = try (string "\\textbackslash") >> optional (try $ string "{}") >> return (Str "\\")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
tilde :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
tilde = try (string "\\ensuremath{\\sim}") >> return (Str "~")
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
caret :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
caret = try (string "\\^{}") >> return (Str "^")
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
bar :: GenParser Char st Inline
|
2008-09-06 20:45:53 +00:00
|
|
|
bar = try (string "\\textbar") >> optional (try $ string "{}") >> return (Str "\\")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
lt :: GenParser Char st Inline
|
2008-09-06 20:45:53 +00:00
|
|
|
lt = try (string "\\textless") >> optional (try $ string "{}") >> return (Str "<")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
gt :: GenParser Char st Inline
|
2008-09-06 20:45:53 +00:00
|
|
|
gt = try (string "\\textgreater") >> optional (try $ string "{}") >> return (Str ">")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
doubleQuote :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
doubleQuote = char '"' >> return (Str "\"")
|
|
|
|
|
2008-12-02 22:43:49 +00:00
|
|
|
code :: GenParser Char ParserState Inline
|
2010-12-30 00:48:55 +05:30
|
|
|
code = code1 <|> code2 <|> code3 <|> lhsInlineCode
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
code1 :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
code1 = try $ do
|
|
|
|
string "\\verb"
|
|
|
|
marker <- anyChar
|
|
|
|
result <- manyTill anyChar (char marker)
|
|
|
|
return $ Code $ removeLeadingTrailingSpace result
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
code2 :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
code2 = try $ do
|
|
|
|
string "\\texttt{"
|
|
|
|
result <- manyTill (noneOf "\\\n~$%^&{}") (char '}')
|
|
|
|
return $ Code result
|
|
|
|
|
2010-12-30 00:48:55 +05:30
|
|
|
code3 :: GenParser Char st Inline
|
|
|
|
code3 = try $ do
|
|
|
|
string "\\lstinline"
|
|
|
|
marker <- anyChar
|
|
|
|
result <- manyTill anyChar (char marker)
|
|
|
|
return $ Code $ removeLeadingTrailingSpace result
|
|
|
|
|
2008-12-02 22:43:49 +00:00
|
|
|
lhsInlineCode :: GenParser Char ParserState Inline
|
|
|
|
lhsInlineCode = try $ do
|
|
|
|
failUnlessLHS
|
|
|
|
char '|'
|
|
|
|
result <- manyTill (noneOf "|\n") (char '|')
|
|
|
|
return $ Code result
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
emph :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
emph = try $ oneOfStrings [ "\\emph{", "\\textit{" ] >>
|
|
|
|
manyTill inline (char '}') >>= return . Emph
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
strikeout :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
strikeout = try $ string "\\sout{" >> manyTill inline (char '}') >>=
|
|
|
|
return . Strikeout
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
superscript :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
superscript = try $ string "\\textsuperscript{" >>
|
|
|
|
manyTill inline (char '}') >>= return . Superscript
|
|
|
|
|
|
|
|
-- note: \textsubscript isn't a standard latex command, but we use
|
|
|
|
-- a defined version in pandoc.
|
2008-07-14 16:19:42 +00:00
|
|
|
subscript :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
subscript = try $ string "\\textsubscript{" >> manyTill inline (char '}') >>=
|
|
|
|
return . Subscript
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
apostrophe :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
apostrophe = char '\'' >> return Apostrophe
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
quoted :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
quoted = doubleQuoted <|> singleQuoted
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
singleQuoted :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
singleQuoted = enclosed singleQuoteStart singleQuoteEnd inline >>=
|
|
|
|
return . Quoted SingleQuote . normalizeSpaces
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
doubleQuoted :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
doubleQuoted = enclosed doubleQuoteStart doubleQuoteEnd inline >>=
|
|
|
|
return . Quoted DoubleQuote . normalizeSpaces
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
singleQuoteStart :: GenParser Char st Char
|
2007-11-03 23:27:58 +00:00
|
|
|
singleQuoteStart = char '`'
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
singleQuoteEnd :: GenParser Char st ()
|
2007-11-03 23:27:58 +00:00
|
|
|
singleQuoteEnd = try $ char '\'' >> notFollowedBy alphaNum
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
doubleQuoteStart :: CharParser st String
|
2007-11-03 23:27:58 +00:00
|
|
|
doubleQuoteStart = string "``"
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
doubleQuoteEnd :: CharParser st String
|
2009-01-24 20:00:26 +00:00
|
|
|
doubleQuoteEnd = try $ string "''"
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
ellipses :: GenParser Char st Inline
|
2008-09-06 20:45:53 +00:00
|
|
|
ellipses = try $ string "\\ldots" >> optional (try $ string "{}") >>
|
2007-11-03 23:27:58 +00:00
|
|
|
return Ellipses
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
enDash :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
enDash = try (string "--") >> return EnDash
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
emDash :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
emDash = try (string "---") >> return EmDash
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
hyphen :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
hyphen = char '-' >> return (Str "-")
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
lab :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
lab = try $ do
|
|
|
|
string "\\label{"
|
|
|
|
result <- manyTill anyChar (char '}')
|
|
|
|
return $ Str $ "(" ++ result ++ ")"
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
ref :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
ref = try (string "\\ref{") >> manyTill anyChar (char '}') >>= return . Str
|
|
|
|
|
2008-07-14 16:19:42 +00:00
|
|
|
strong :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
strong = try (string "\\textbf{") >> manyTill inline (char '}') >>=
|
|
|
|
return . Strong
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
whitespace :: GenParser Char st Inline
|
2010-03-13 04:30:27 +00:00
|
|
|
whitespace = many1 (oneOf " \t") >> return Space
|
|
|
|
|
|
|
|
nonbreakingSpace :: GenParser Char st Inline
|
|
|
|
nonbreakingSpace = char '~' >> return (Str "\160")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
-- hard line break
|
2008-07-15 00:14:58 +00:00
|
|
|
linebreak :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
linebreak = try (string "\\\\") >> return LineBreak
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
str :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
str = many1 (noneOf specialChars) >>= return . Str
|
|
|
|
|
|
|
|
-- endline internal to paragraph
|
2008-07-15 00:14:58 +00:00
|
|
|
endline :: GenParser Char st Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
endline = try $ newline >> notFollowedBy blankline >> return Space
|
|
|
|
|
|
|
|
-- math
|
2011-01-04 19:18:20 -08:00
|
|
|
math :: GenParser Char ParserState Inline
|
|
|
|
math = (math3 >>= applyMacros' >>= return . Math DisplayMath)
|
|
|
|
<|> (math1 >>= applyMacros' >>= return . Math InlineMath)
|
|
|
|
<|> (math2 >>= applyMacros' >>= return . Math InlineMath)
|
|
|
|
<|> (math4 >>= applyMacros' >>= return . Math DisplayMath)
|
|
|
|
<|> (math5 >>= applyMacros' >>= return . Math DisplayMath)
|
|
|
|
<|> (math6 >>= applyMacros' >>= return . Math DisplayMath)
|
2008-08-13 03:02:42 +00:00
|
|
|
<?> "math"
|
|
|
|
|
|
|
|
math1 :: GenParser Char st String
|
|
|
|
math1 = try $ char '$' >> manyTill anyChar (char '$')
|
|
|
|
|
|
|
|
math2 :: GenParser Char st String
|
|
|
|
math2 = try $ string "\\(" >> manyTill anyChar (try $ string "\\)")
|
|
|
|
|
|
|
|
math3 :: GenParser Char st String
|
|
|
|
math3 = try $ char '$' >> math1 >>~ char '$'
|
|
|
|
|
|
|
|
math4 :: GenParser Char st String
|
2008-09-06 21:24:33 +00:00
|
|
|
math4 = try $ do
|
Improved LaTeX reader's coverage of math modes.
Remove displaymath* (which is not in LaTeX) and recognize
all the amsmath environments that are alternatives to eqnarray, namely
equation, equation*, gather, gather*, gathered, multline, multline*,
align, align*, alignat, alignat*, aligned, alignedat, split
Resolves Issue #103. Thanks to shreevatsa.public
for the patch.
git-svn-id: https://pandoc.googlecode.com/svn/trunk@1577 788f1e2b-df1e-0410-8736-df70ead52e1b
2009-06-03 20:26:41 +00:00
|
|
|
name <- begin "displaymath" <|> begin "equation" <|> begin "equation*" <|>
|
|
|
|
begin "gather" <|> begin "gather*" <|> begin "gathered" <|>
|
|
|
|
begin "multline" <|> begin "multline*"
|
2008-09-06 21:24:33 +00:00
|
|
|
spaces
|
|
|
|
manyTill anyChar (end name)
|
2008-08-13 03:02:42 +00:00
|
|
|
|
|
|
|
math5 :: GenParser Char st String
|
2008-09-06 21:24:33 +00:00
|
|
|
math5 = try $ (string "\\[") >> spaces >> manyTill anyChar (try $ string "\\]")
|
2008-08-13 03:02:42 +00:00
|
|
|
|
|
|
|
math6 :: GenParser Char st String
|
2008-09-06 21:24:33 +00:00
|
|
|
math6 = try $ do
|
Improved LaTeX reader's coverage of math modes.
Remove displaymath* (which is not in LaTeX) and recognize
all the amsmath environments that are alternatives to eqnarray, namely
equation, equation*, gather, gather*, gathered, multline, multline*,
align, align*, alignat, alignat*, aligned, alignedat, split
Resolves Issue #103. Thanks to shreevatsa.public
for the patch.
git-svn-id: https://pandoc.googlecode.com/svn/trunk@1577 788f1e2b-df1e-0410-8736-df70ead52e1b
2009-06-03 20:26:41 +00:00
|
|
|
name <- begin "eqnarray" <|> begin "eqnarray*" <|> begin "align" <|>
|
|
|
|
begin "align*" <|> begin "alignat" <|> begin "alignat*" <|>
|
|
|
|
begin "split" <|> begin "aligned" <|> begin "alignedat"
|
2008-09-06 21:24:33 +00:00
|
|
|
spaces
|
|
|
|
res <- manyTill anyChar (end name)
|
Improved LaTeX reader's coverage of math modes.
Remove displaymath* (which is not in LaTeX) and recognize
all the amsmath environments that are alternatives to eqnarray, namely
equation, equation*, gather, gather*, gathered, multline, multline*,
align, align*, alignat, alignat*, aligned, alignedat, split
Resolves Issue #103. Thanks to shreevatsa.public
for the patch.
git-svn-id: https://pandoc.googlecode.com/svn/trunk@1577 788f1e2b-df1e-0410-8736-df70ead52e1b
2009-06-03 20:26:41 +00:00
|
|
|
return $ filter (/= '&') res -- remove alignment codes
|
2007-11-03 23:27:58 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- links and images
|
|
|
|
--
|
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
url :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
url = try $ do
|
|
|
|
string "\\url"
|
2008-07-15 00:14:58 +00:00
|
|
|
url' <- charsInBalanced '{' '}'
|
2010-03-23 15:07:48 -07:00
|
|
|
return $ Link [Code url'] (escapeURI url', "")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
link :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
link = try $ do
|
|
|
|
string "\\href{"
|
2008-07-15 00:14:58 +00:00
|
|
|
url' <- manyTill anyChar (char '}')
|
2007-11-03 23:27:58 +00:00
|
|
|
char '{'
|
2008-07-15 00:14:58 +00:00
|
|
|
label' <- manyTill inline (char '}')
|
2010-03-23 15:07:48 -07:00
|
|
|
return $ Link (normalizeSpaces label') (escapeURI url', "")
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
image :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
image = try $ do
|
|
|
|
("includegraphics", _, args) <- command
|
|
|
|
let args' = filter isArg args -- filter out options
|
2010-03-23 15:07:48 -07:00
|
|
|
let (src,tit) = case args' of
|
|
|
|
[] -> ("", "")
|
|
|
|
(x:_) -> (stripFirstAndLast x, "")
|
|
|
|
return $ Image [Str "image"] (escapeURI src, tit)
|
2007-11-03 23:27:58 +00:00
|
|
|
|
2008-07-15 00:14:58 +00:00
|
|
|
footnote :: GenParser Char ParserState Inline
|
2007-11-03 23:27:58 +00:00
|
|
|
footnote = try $ do
|
|
|
|
(name, _, (contents:[])) <- command
|
|
|
|
if ((name == "footnote") || (name == "thanks"))
|
|
|
|
then string ""
|
|
|
|
else fail "not a footnote or thanks command"
|
|
|
|
let contents' = stripFirstAndLast contents
|
|
|
|
-- parse the extracted block, which may contain various block elements:
|
|
|
|
rest <- getInput
|
|
|
|
setInput $ contents'
|
|
|
|
blocks <- parseBlocks
|
|
|
|
setInput rest
|
|
|
|
return $ Note blocks
|
|
|
|
|
2010-12-13 21:32:04 +01:00
|
|
|
-- | citations
|
|
|
|
cite :: GenParser Char ParserState Inline
|
|
|
|
cite = simpleCite <|> complexNatbibCites
|
|
|
|
|
|
|
|
simpleCiteArgs :: GenParser Char ParserState [Citation]
|
|
|
|
simpleCiteArgs = try $ do
|
|
|
|
first <- optionMaybe $ (char '[') >> manyTill inline (char ']')
|
|
|
|
second <- optionMaybe $ (char '[') >> manyTill inline (char ']')
|
|
|
|
char '{'
|
|
|
|
keys <- many1Till citationLabel (char '}')
|
|
|
|
let (pre, suf) = case (first , second ) of
|
|
|
|
(Just s , Nothing) -> ([], s )
|
|
|
|
(Just s , Just t ) -> (s , t )
|
|
|
|
_ -> ([], [])
|
|
|
|
conv k = Citation { citationId = k
|
|
|
|
, citationPrefix = []
|
|
|
|
, citationSuffix = []
|
|
|
|
, citationMode = NormalCitation
|
|
|
|
, citationHash = 0
|
|
|
|
, citationNoteNum = 0
|
|
|
|
}
|
|
|
|
return $ addPrefix pre $ addSuffix suf $ map conv keys
|
|
|
|
|
|
|
|
|
|
|
|
simpleCite :: GenParser Char ParserState Inline
|
|
|
|
simpleCite = try $ do
|
|
|
|
char '\\'
|
|
|
|
let biblatex = [a ++ "cite" | a <- ["auto", "foot", "paren", "super", ""]]
|
|
|
|
++ ["footcitetext"]
|
|
|
|
normal = ["cite" ++ a ++ b | a <- ["al", ""], b <- ["p", "p*", ""]]
|
|
|
|
++ biblatex
|
|
|
|
supress = ["citeyearpar", "citeyear", "autocite*", "cite*", "parencite*"]
|
|
|
|
intext = ["textcite"] ++ ["cite" ++ a ++ b | a <- ["al", ""], b <- ["t", "t*"]]
|
|
|
|
mintext = ["textcites"]
|
|
|
|
mnormal = map (++ "s") biblatex
|
|
|
|
cmdend = notFollowedBy (letter <|> char '*')
|
|
|
|
addUpper xs = xs ++ map (\(c:cs) -> toUpper c : cs) xs
|
|
|
|
toparser l t = try $ oneOfStrings (addUpper l) >> cmdend >> return t
|
|
|
|
(mode, multi) <- toparser normal (NormalCitation, False)
|
|
|
|
<|> toparser supress (SuppressAuthor, False)
|
|
|
|
<|> toparser intext (AuthorInText , False)
|
|
|
|
<|> toparser mnormal (NormalCitation, True )
|
|
|
|
<|> toparser mintext (AuthorInText , True )
|
|
|
|
cits <- if multi then
|
|
|
|
many1 simpleCiteArgs
|
|
|
|
else
|
|
|
|
simpleCiteArgs >>= \c -> return [c]
|
|
|
|
let (c:cs) = concat cits
|
|
|
|
cits' = case mode of
|
|
|
|
AuthorInText -> c {citationMode = mode} : cs
|
|
|
|
_ -> map (\a -> a {citationMode = mode}) (c:cs)
|
|
|
|
return $ Cite cits' []
|
|
|
|
|
|
|
|
complexNatbibCites :: GenParser Char ParserState Inline
|
|
|
|
complexNatbibCites = complexNatbibTextual <|> complexNatbibParenthetical
|
|
|
|
|
|
|
|
complexNatbibTextual :: GenParser Char ParserState Inline
|
|
|
|
complexNatbibTextual = try $ do
|
|
|
|
string "\\citeauthor{"
|
|
|
|
manyTill (noneOf "}") (char '}')
|
|
|
|
skipSpaces
|
|
|
|
Cite (c:cs) _ <- complexNatbibParenthetical
|
|
|
|
return $ Cite (c {citationMode = AuthorInText} : cs) []
|
|
|
|
|
|
|
|
|
|
|
|
complexNatbibParenthetical :: GenParser Char ParserState Inline
|
|
|
|
complexNatbibParenthetical = try $ do
|
|
|
|
string "\\citetext{"
|
|
|
|
cits <- many1Till parseOne (char '}')
|
|
|
|
return $ Cite (concat cits) []
|
|
|
|
where
|
|
|
|
parseOne = do
|
|
|
|
skipSpaces
|
|
|
|
pref <- many (notFollowedBy (oneOf "\\}") >> inline)
|
|
|
|
(Cite cites _) <- simpleCite
|
|
|
|
suff <- many (notFollowedBy (oneOf "\\};") >> inline)
|
|
|
|
skipSpaces
|
|
|
|
optional $ char ';'
|
|
|
|
return $ addPrefix pref $ addSuffix suff $ cites
|
|
|
|
|
|
|
|
addPrefix :: [Inline] -> [Citation] -> [Citation]
|
|
|
|
addPrefix p (k:ks) = k {citationPrefix = p ++ citationPrefix k} : ks
|
|
|
|
addPrefix _ _ = []
|
|
|
|
|
|
|
|
addSuffix :: [Inline] -> [Citation] -> [Citation]
|
|
|
|
addSuffix s ks@(_:_) = let k = last ks
|
|
|
|
in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
|
|
|
|
addSuffix _ _ = []
|
|
|
|
|
|
|
|
citationLabel :: GenParser Char ParserState String
|
|
|
|
citationLabel = do
|
|
|
|
res <- many1 $ noneOf ",}"
|
|
|
|
optional $ char ','
|
|
|
|
return $ removeLeadingTrailingSpace res
|
|
|
|
|
2010-04-26 23:17:34 -07:00
|
|
|
-- | Parse any LaTeX inline command and return it in a raw TeX inline element.
|
|
|
|
rawLaTeXInline' :: GenParser Char ParserState Inline
|
|
|
|
rawLaTeXInline' = do
|
|
|
|
notFollowedBy' $ oneOfStrings ["\\begin", "\\end", "\\item", "\\ignore",
|
|
|
|
"\\section"]
|
2011-01-05 09:04:03 -08:00
|
|
|
rawLaTeXInline
|
2010-04-26 23:17:34 -07:00
|
|
|
|
2007-11-03 23:27:58 +00:00
|
|
|
-- | Parse any LaTeX command and return it in a raw TeX inline element.
|
|
|
|
rawLaTeXInline :: GenParser Char ParserState Inline
|
|
|
|
rawLaTeXInline = try $ do
|
|
|
|
state <- getState
|
2007-12-30 02:07:55 +00:00
|
|
|
if stateParseRaw state
|
2008-09-06 18:05:18 +00:00
|
|
|
then do
|
|
|
|
(name, star, args) <- command
|
|
|
|
return $ TeX ("\\" ++ name ++ star ++ concat args)
|
2010-03-14 23:23:14 +00:00
|
|
|
else do
|
|
|
|
(name, _, args) <- command
|
|
|
|
spaces
|
|
|
|
if name `elem` commandsToIgnore
|
|
|
|
then return $ Str ""
|
|
|
|
else return $ Str (concat args)
|