git.iko.soy/typeable/pandoc
on master help sign in
Add tectonic as an option for --pdf-engine. (#5346)

Closes #5345 Runs tectonic on STDIN instead of a temporary .tex file, so that it looks in the working directory for `\include` and `\input` like the rest of the engines. Allows overriding the output directory without messing up the args with `--pdf-engine-opt=--outdir --pdf-engine-opt="$DIR"`.

commitd638873433860169daa29df816b9d156dca03d42 authorCormac Relf <web@cormacrelf.net> dateFri 8 Mar 2019, 04:16 (8 years ago) parent449910b
4 files changed+86−34
MANUAL.txt+3−3 data/bash_completion.tpl+1−1 src/Text/Pandoc/App/CommandLineOptions.hs+1−1 src/Text/Pandoc/PDF.hs+81−29
MANUAL.txt+3−3
@@ -1200,9 +1200,9 @@ Options affecting specific writers {.options}
12001200
12011201: Use the specified engine when producing PDF output.
12021202 Valid values are `pdflatex`, `lualatex`, `xelatex`, `latexmk`,
1203− `wkhtmltopdf`, `weasyprint`, `prince`, `context`, and `pdfroff`.
1204− The default is `pdflatex`. If the engine is not in your PATH,
1205− the full path of the engine may be specified here.
1203+ `tectonic`, `wkhtmltopdf`, `weasyprint`, `prince`, `context`,
1204+ and `pdfroff`. The default is `pdflatex`. If the engine is
1205+ not in your PATH, the full path of the engine may be specified here.
12061206
12071207`--pdf-engine-opt=`*STRING*
12081208
data/bash_completion.tpl+1−1
@@ -34,7 +34,7 @@ _pandoc()
3434 return 0
3535 ;;
3636 --pdf-engine)
37− COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
37+ COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk tectonic wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
3838 return 0
3939 ;;
4040 --print-default-data-file)
src/Text/Pandoc/App/CommandLineOptions.hs+1−1
@@ -85,7 +85,7 @@ parseOptions options' defaults = do
8585 return (opts{ optInputFiles = map normalizePath args })
8686
8787latexEngines :: [String]
88−latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk"]
88+latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk", "tectonic"]
8989
9090htmlEngines :: [String]
9191htmlEngines = ["wkhtmltopdf", "weasyprint", "prince"]
src/Text/Pandoc/PDF.hs+81−29
@@ -70,7 +70,7 @@ makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex,
7070 -> WriterOptions -- ^ options
7171 -> Pandoc -- ^ document
7272 -> PandocIO (Either ByteString ByteString)
73−makePDF program pdfargs writer opts doc = do
73+makePDF program pdfargs writer opts doc =
7474 case takeBaseName program of
7575 "wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc
7676 prog | prog `elem` ["weasyprint", "prince"] -> do
@@ -107,6 +107,7 @@ makePDF program pdfargs writer opts doc = do
107107 source <- writer opts doc'
108108 res <- case baseProg of
109109 "context" -> context2pdf verbosity program pdfargs tmpdir source
110+ "tectonic" -> tectonic2pdf verbosity program pdfargs tmpdir source
110111 prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"]
111112 -> tex2pdf verbosity program pdfargs tmpdir source
112113 _ -> return $ Left $ UTF8.fromStringLazy
@@ -200,6 +201,21 @@ convertImage tmpdir fname =
200201 mime = getMimeType fname
201202 doNothing = return (Right fname)
202203
204+tectonic2pdf :: Verbosity -- ^ Verbosity level
205+ -> String -- ^ tex program
206+ -> [String] -- ^ Arguments to the latex-engine
207+ -> FilePath -- ^ temp directory for output
208+ -> Text -- ^ tex source
209+ -> PandocIO (Either ByteString ByteString)
210+tectonic2pdf verbosity program args tmpDir source = do
211+ (exit, log', mbPdf) <- runTectonic verbosity program args tmpDir source
212+ case (exit, mbPdf) of
213+ (ExitFailure _, _) -> return $ Left $ extractMsg log'
214+ (ExitSuccess, Nothing) -> return $ Left ""
215+ (ExitSuccess, Just pdf) -> do
216+ missingCharacterWarnings verbosity log'
217+ return $ Right pdf
218+
203219tex2pdf :: Verbosity -- ^ Verbosity level
204220 -> String -- ^ tex program
205221 -> [String] -- ^ Arguments to the latex-engine
@@ -207,12 +223,9 @@ tex2pdf :: Verbosity -- ^ Verbosity level
207223 -> Text -- ^ tex source
208224 -> PandocIO (Either ByteString ByteString)
209225tex2pdf verbosity program args tmpDir source = do
210− let numruns =
211− if takeBaseName program == "latexmk"
212− then 1
213− else if "\\tableofcontents" `T.isInfixOf` source
214− then 3 -- to get page numbers
215− else 2 -- 1 run won't give you PDF bookmarks
226+ let numruns | takeBaseName program == "latexmk" = 1
227+ | "\\tableofcontents" `T.isInfixOf` source = 3 -- to get page numbers
228+ | otherwise = 2 -- 1 run won't give you PDF bookmarks
216229 (exit, log', mbPdf) <- runTeXProgram verbosity program args 1 numruns
217230 tmpDir source
218231 case (exit, mbPdf) of
@@ -262,6 +275,59 @@ extractConTeXtMsg log' = do
262275
263276-- running tex programs
264277
278+runTectonic :: Verbosity -> String -> [String] -> FilePath
279+ -> Text -> PandocIO (ExitCode, ByteString, Maybe ByteString)
280+runTectonic verbosity program args' tmpDir' source = do
281+ let getOutDir acc (a:b:xs) = if a `elem` ["-o", "--outdir"]
282+ then (reverse acc ++ xs, Just b)
283+ else getOutDir (b:a:acc) xs
284+ getOutDir acc xs = (reverse acc ++ xs, Nothing)
285+ (args, outDir) = getOutDir [] args'
286+ tmpDir = fromMaybe tmpDir' outDir
287+ liftIO $ createDirectoryIfMissing True tmpDir
288+ -- run tectonic on stdin so it reads \include commands from $PWD instead of a temp directory
289+ let sourceBL = BL.fromStrict $ UTF8.fromText source
290+ let programArgs = ["--outdir", tmpDir] ++ args ++ ["-"]
291+ env <- liftIO getEnvironment
292+ when (verbosity >= INFO) $ liftIO $
293+ showVerboseInfo (Just tmpDir) program programArgs env (UTF8.toStringLazy sourceBL)
294+ (exit, out) <- liftIO $ E.catch
295+ (pipeProcess (Just env) program programArgs sourceBL)
296+ (\(e :: IOError) -> if isDoesNotExistError e
297+ then E.throwIO $ PandocPDFProgramNotFoundError
298+ program
299+ else E.throwIO e)
300+ when (verbosity >= INFO) $ liftIO $ do
301+ putStrLn "[makePDF] Running"
302+ BL.hPutStr stdout out
303+ putStr "\n"
304+ let pdfFile = tmpDir </> "texput.pdf"
305+ (_, pdf) <- getResultingPDF Nothing pdfFile
306+ return (exit, out, pdf)
307+
308+-- read a pdf that has been written to a temporary directory, and optionally read
309+-- logs
310+getResultingPDF :: Maybe String -> String -> PandocIO (Maybe ByteString, Maybe ByteString)
311+getResultingPDF logFile pdfFile = do
312+ pdfExists <- liftIO $ doesFileExist pdfFile
313+ pdf <- if pdfExists
314+ -- We read PDF as a strict bytestring to make sure that the
315+ -- temp directory is removed on Windows.
316+ -- See https://github.com/jgm/pandoc/issues/1192.
317+ then (Just . BL.fromChunks . (:[])) `fmap`
318+ liftIO (BS.readFile pdfFile)
319+ else return Nothing
320+ -- Note that some things like Missing character warnings
321+ -- appear in the log but not on stderr, so we prefer the log:
322+ log' <- case logFile of
323+ Just logFile' -> do
324+ logExists <- liftIO $ doesFileExist logFile'
325+ if logExists
326+ then liftIO $ Just <$> BL.readFile logFile'
327+ else return Nothing
328+ Nothing -> return Nothing
329+ return (log', pdf)
330+
265331-- Run a TeX program on an input bytestring and return (exit code,
266332-- contents of stdout, contents of produced PDF if any). Rerun
267333-- a fixed number of times to resolve references.
@@ -276,12 +342,11 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir' source = do
276342 let file = tmpDir </> "input.tex"
277343 exists <- liftIO $ doesFileExist file
278344 unless exists $ liftIO $ BS.writeFile file $ UTF8.fromText source
279− let programArgs =
280− if takeBaseName program == "latexmk"
281− then ["-interaction=batchmode", "-halt-on-error", "-pdf",
282− "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
283− else ["-halt-on-error", "-interaction", "nonstopmode",
284− "-output-directory", tmpDir] ++ args ++ [file]
345+ let isLatexMk = takeBaseName program == "latexmk"
346+ programArgs | isLatexMk = ["-interaction=batchmode", "-halt-on-error", "-pdf",
347+ "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
348+ | otherwise = ["-halt-on-error", "-interaction", "nonstopmode",
349+ "-output-directory", tmpDir] ++ args ++ [file]
285350 env' <- liftIO getEnvironment
286351 let sep = [searchPathSeparator]
287352 let texinputs = maybe (tmpDir ++ sep) ((tmpDir ++ sep) ++)
@@ -306,23 +371,10 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir' source = do
306371 if runNumber < numRuns
307372 then runTeXProgram verbosity program args (runNumber + 1) numRuns tmpDir source
308373 else do
309− let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
310− pdfExists <- liftIO $ doesFileExist pdfFile
311− pdf <- if pdfExists
312− -- We read PDF as a strict bytestring to make sure that the
313− -- temp directory is removed on Windows.
314− -- See https://github.com/jgm/pandoc/issues/1192.
315− then (Just . BL.fromChunks . (:[])) `fmap`
316− liftIO (BS.readFile pdfFile)
317− else return Nothing
318− -- Note that some things like Missing character warnings
319− -- appear in the log but not on stderr, so we prefer the log:
320374 let logFile = replaceExtension file ".log"
321− logExists <- liftIO $ doesFileExist logFile
322− log' <- if logExists
323− then liftIO $ BL.readFile logFile
324− else return out
325− return (exit, log', pdf)
375+ let pdfFile = replaceExtension file ".pdf"
376+ (log', pdf) <- getResultingPDF (Just logFile) pdfFile
377+ return (exit, fromMaybe out log', pdf)
326378
327379generic2pdf :: Verbosity
328380 -> String