@@ -42,6 +42,7 @@ import Control.Exception (evaluate)
42import System.IO (hClose)
42import System.IO (hClose)
43import Control.Concurrent (putMVar, takeMVar, newEmptyMVar, forkIO)
43import Control.Concurrent (putMVar, takeMVar, newEmptyMVar, forkIO)
44import Text.Pandoc.UTF8 as UTF8
44import Text.Pandoc.UTF8 as UTF8
45+import Control.Monad (unless)
46tex2pdf :: String -- ^ tex program (pdflatex, lualatex, xelatex)
47tex2pdf :: String -- ^ tex program (pdflatex, lualatex, xelatex)
47 -> String -- ^ latex source
48 -> String -- ^ latex source
@@ -54,7 +55,8 @@ tex2pdf' :: FilePath -- ^ temp directory for output
54 -> String -- ^ tex source
55 -> String -- ^ tex source
55 -> IO (Either ByteString ByteString)
56 -> IO (Either ByteString ByteString)
56tex2pdf' tmpDir program source = do
57tex2pdf' tmpDir program source = do
58+ let numruns = 2 -- should suffice for toc and hyperrefs
57− (exit, log', mbPdf) <- runTeXProgram program 3 tmpDir source
59+ (exit, log', mbPdf) <- runTeXProgram program numruns tmpDir source
58 let msg = "Error producing PDF from TeX source."
60 let msg = "Error producing PDF from TeX source."
59 case (exit, mbPdf) of
61 case (exit, mbPdf) of
60 (ExitFailure _, _) -> return $ Left $
62 (ExitFailure _, _) -> return $ Left $
@@ -76,41 +78,29 @@ extractMsg log' = do
77 else BC.unlines (msg'' ++ lineno)
79 else BC.unlines (msg'' ++ lineno)
79−parseLine :: ByteString -> Bool
81− if "LaTeX Warning:" `BC.isPrefixOf` ln
82− then if "Rerun" `elem` ws
86− where ws = BC.words ln
88−hasUndefinedRefs :: ByteString -> Bool
89−hasUndefinedRefs = or . map parseLine . BC.lines
91-- running tex programs
81-- running tex programs
93-- Run a TeX program on an input bytestring and return (exit code,
83-- Run a TeX program on an input bytestring and return (exit code,
94-- contents of stdout, contents of produced PDF if any). Rerun
84-- contents of stdout, contents of produced PDF if any). Rerun
95−-- latex as needed to resolve references, but don't run bibtex/biber.
85+-- a fixed number of times to resolve references.
96runTeXProgram :: String -> Int -> FilePath -> String
86runTeXProgram :: String -> Int -> FilePath -> String
97 -> IO (ExitCode, ByteString, Maybe ByteString)
87 -> IO (ExitCode, ByteString, Maybe ByteString)
98runTeXProgram program runsLeft tmpDir source = do
88runTeXProgram program runsLeft tmpDir source = do
99− withTempFile tmpDir "tex2pdf" $ \file h -> do
89+ let file = tmpDir </> "input.tex"
100− UTF8.hPutStr h source
90+ exists <- doesFileExist file
101− hClose h
91+ unless exists $ UTF8.writeFile file source
102 let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
92 let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
103 "-output-directory", tmpDir, file]
93 "-output-directory", tmpDir, file]
104 (exit, out, err) <- readCommand program programArgs
94 (exit, out, err) <- readCommand program programArgs
106− let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
107− pdfExists <- doesFileExist pdfFile
109− then Just `fmap` B.readFile pdfFile
111− if hasUndefinedRefs out && runsLeft > 0
95+ if runsLeft > 1
112 then runTeXProgram program (runsLeft - 1) tmpDir source
96 then runTeXProgram program (runsLeft - 1) tmpDir source
98+ let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
99+ pdfExists <- doesFileExist pdfFile
101+ then Just `fmap` B.readFile pdfFile
113− else return (exit, out <> err, pdf)
103+ return (exit, out <> err, pdf)
115-- utility functions
105-- utility functions
@@ -140,4 +130,4 @@ readCommand cmd args = do
140 hClose outh
130 hClose outh
141 -- wait on the process
131 -- wait on the process
142 ex <- waitForProcess pid
132 ex <- waitForProcess pid
143− return (ex, out, err)
133+ return (ex, out, err)