@@ -40,8 +40,10 @@ import Text.Pandoc.Shared
40import Text.Pandoc.Options
40import Text.Pandoc.Options
41import Text.Pandoc.Parsing hiding ((<|>), many, optional, space,
41import Text.Pandoc.Parsing hiding ((<|>), many, optional, space,
42 mathDisplay, mathInline)
42 mathDisplay, mathInline)
43+import Text.Parsec.Prim (ParsecT, runParserT)
43import qualified Text.Pandoc.UTF8 as UTF8
44import qualified Text.Pandoc.UTF8 as UTF8
44import Data.Char ( chr, ord )
45import Data.Char ( chr, ord )
46+import Control.Monad.Trans (lift)
45import Control.Monad
47import Control.Monad
46import Text.Pandoc.Builder
48import Text.Pandoc.Builder
47import Data.Char (isLetter, isAlphaNum)
49import Data.Char (isLetter, isAlphaNum)
@@ -303,6 +305,8 @@ blockCommands = M.fromList $
303 , ("documentclass", skipopts *> braced *> preamble)
305 , ("documentclass", skipopts *> braced *> preamble)
304 , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
306 , ("centerline", (para . trimInlines) <$> (skipopts *> tok))
305 , ("caption", tok >>= setCaption)
307 , ("caption", tok >>= setCaption)
308+ , ("PandocStartInclude", startInclude)
309+ , ("PandocEndInclude", endInclude)
306 ] ++ map ignoreBlocks
310 ] ++ map ignoreBlocks
307 -- these commands will be ignored unless --parse-raw is specified,
311 -- these commands will be ignored unless --parse-raw is specified,
308 -- in which case they will appear as raw latex blocks
312 -- in which case they will appear as raw latex blocks
@@ -794,31 +798,107 @@ rawEnv name = do
794 (withRaw (env name blocks) >>= applyMacros' . snd)
798 (withRaw (env name blocks) >>= applyMacros' . snd)
795 else env name blocks
799 else env name blocks
803+type IncludeParser = ParsecT [Char] [String] IO String
797-- | Replace "include" commands with file contents.
805-- | Replace "include" commands with file contents.
798handleIncludes :: String -> IO String
806handleIncludes :: String -> IO String
799−handleIncludes = handleIncludes' []
807+handleIncludes s = do
800−
808+ res <- runParserT includeParser' [] "input" s
801−-- parents parameter prevents infinite include loops
809+ case res of
802−handleIncludes' :: [FilePath] -> String -> IO String
810+ Right s' -> return s'
803−handleIncludes' _ [] = return []
811+ Left e -> error $ show e
804−handleIncludes' parents ('\\':'%':xs) =
812+
805− ("\\%"++) `fmap` handleIncludes' parents xs
813+includeParser' :: IncludeParser
806−handleIncludes' parents ('%':xs) = handleIncludes' parents
814+includeParser' =
807− $ drop 1 $ dropWhile (/='\n') xs
815+ concat <$> many (comment' <|> escaped' <|> blob' <|> include'
808−handleIncludes' parents ('\\':xs) =
816+ <|> startMarker' <|> endMarker'
809− case runParser include defaultParserState "input" ('\\':xs) of
817+ <|> verbCmd' <|> verbatimEnv' <|> backslash')
810− Right (fs, rest) -> do yss <- mapM (\f -> if f `elem` parents
818+
819+comment' :: IncludeParser
822+ xs <- manyTill anyChar newline
823+ return ('%':xs ++ "\n")
825+escaped' :: IncludeParser
826+escaped' = try $ string "\\%" <|> string "\\\\"
828+verbCmd' :: IncludeParser
829+verbCmd' = fmap snd <$>
833+ manyTill anyChar (char c)
835+verbatimEnv' :: IncludeParser
836+verbatimEnv' = fmap snd <$>
840+ guard $ name `elem` ["verbatim", "Verbatim", "lstlisting",
842+ manyTill anyChar (try $ string $ "\\end{" ++ name ++ "}")
844+blob' :: IncludeParser
845+blob' = try $ many1 (noneOf "\\%")
847+backslash' :: IncludeParser
848+backslash' = string "\\"
850+braced' :: IncludeParser
851+braced' = try $ char '{' *> manyTill (satisfy (/='}')) (char '}')
853+include' :: IncludeParser
857+ try (string "include")
858+ <|> try (string "input")
859+ <|> string "usepackage"
861+ skipMany $ try $ char '[' *> (manyTill anyChar (char ']'))
862+ fs <- (map trim . splitBy (==',')) <$> braced'
864+ let fs' = if name == "usepackage"
865+ then map (flip replaceExtension ".sty") fs
866+ else map (flip replaceExtension ".tex") fs
867+ containers <- getState
868+ let fn = case containers of
871+ -- now process each include file in order...
873+ results' <- forM fs' (\f -> do
874+ when (f `elem` containers) $
811− then "" <$ warn ("Include file loop in '"
875+ fail "Include file loop!"
813− else readTeXFile f >>=
876+ contents <- lift $ readTeXFile f
814− handleIncludes' (f:parents)) fs
877+ return $ "\\PandocStartInclude{" ++ f ++ "}" ++
815− rest' <- handleIncludes' parents rest
878+ contents ++ "\\PandocEndInclude{" ++
816− return $ intercalate "\n" yss ++ rest'
879+ fn ++ "}{" ++ show (sourceLine pos) ++ "}{"
817− _ -> case runParser (verbCmd <|> verbatimEnv) defaultParserState
880+ ++ show (sourceColumn pos) ++ "}")
818− "input" ('\\':xs) of
881+ setInput $ concat results' ++ rest
819− Right (r, rest) -> (r ++) `fmap` handleIncludes' parents rest
882+ return ""
820− _ -> ('\\':) `fmap` handleIncludes' parents xs
883+
821−handleIncludes' parents (x:xs) = (x:) `fmap` handleIncludes' parents xs
884+startMarker' :: IncludeParser
885+startMarker' = try $ do
886+ string "\\PandocStartInclude"
889+ setPosition $ newPos fn 1 1
890+ return $ "\\PandocStartInclude{" ++ fn ++ "}"
892+endMarker' :: IncludeParser
893+endMarker' = try $ do
894+ string "\\PandocEndInclude"
899+ setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)
900+ return $ "\\PandocEndInclude{" ++ fn ++ "}{" ++ ln ++ "}{" ++
823readTeXFile :: FilePath -> IO String
903readTeXFile :: FilePath -> IO String
824readTeXFile f = do
904readTeXFile f = do
@@ -833,27 +913,7 @@ readFileFromDirs (d:ds) f =
833 E.catch (UTF8.readFile $ d </> f) $ \(_ :: E.SomeException) ->
913 E.catch (UTF8.readFile $ d </> f) $ \(_ :: E.SomeException) ->
834 readFileFromDirs ds f
914 readFileFromDirs ds f
836−include :: LP ([FilePath], String)
916+----
838− name <- controlSeq "include"
839− <|> controlSeq "input"
840− <|> controlSeq "usepackage"
842− fs <- (splitBy (==',')) <$> braced
844− let fs' = if name == "usepackage"
845− then map (flip replaceExtension ".sty") fs
846− else map (flip replaceExtension ".tex") fs
849−verbCmd :: LP (String, String)
851− (_,r) <- withRaw $ do
854− manyTill anyChar (char c)
858keyval :: LP (String, String)
918keyval :: LP (String, String)
859keyval = try $ do
919keyval = try $ do
@@ -875,17 +935,6 @@ alltt t = walk strToCode <$> parseFromString blocks
875 where strToCode (Str s) = Code nullAttr s
935 where strToCode (Str s) = Code nullAttr s
876 strToCode x = x
936 strToCode x = x
878−verbatimEnv :: LP (String, String)
880− (_,r) <- withRaw $ do
883− guard $ name `elem` ["verbatim", "Verbatim", "lstlisting",
889rawLaTeXBlock :: Parser [Char] ParserState String
938rawLaTeXBlock :: Parser [Char] ParserState String
890rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
939rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
@@ -1218,3 +1267,16 @@ simpTable = try $ do
1218 lookAhead $ controlSeq "end" -- make sure we're at end
1267 lookAhead $ controlSeq "end" -- make sure we're at end
1219 return $ table mempty (zip aligns (repeat 0)) header'' rows
1268 return $ table mempty (zip aligns (repeat 0)) header'' rows
1270+startInclude :: LP Blocks
1273+ setPosition $ newPos fn 1 1
1276+endInclude :: LP Blocks
1281+ setPosition $ newPos fn (fromMaybe 1 $ safeRead ln) (fromMaybe 1 $ safeRead co)