aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCormac Relf <web@cormacrelf.net>2019-03-08 04:16:40 +1100
committerJohn MacFarlane <jgm@berkeley.edu>2019-03-07 10:16:40 -0700
commitd638873433860169daa29df816b9d156dca03d42 (patch)
tree208593e4d85f0e6bffe4da41a054296c4db869f9
parent449910bf407521e04222ee9c64da7c8a253af1dd (diff)
downloadpandoc-d638873433860169daa29df816b9d156dca03d42.tar.gz
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"`.
-rw-r--r--MANUAL.txt6
-rw-r--r--data/bash_completion.tpl2
-rw-r--r--src/Text/Pandoc/App/CommandLineOptions.hs2
-rw-r--r--src/Text/Pandoc/PDF.hs110
4 files changed, 86 insertions, 34 deletions
diff --git a/MANUAL.txt b/MANUAL.txt
index 89280e0e0..df5dccd5e 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1200,9 +1200,9 @@ Options affecting specific writers {.options}
: Use the specified engine when producing PDF output.
Valid values are `pdflatex`, `lualatex`, `xelatex`, `latexmk`,
- `wkhtmltopdf`, `weasyprint`, `prince`, `context`, and `pdfroff`.
- The default is `pdflatex`. If the engine is not in your PATH,
- the full path of the engine may be specified here.
+ `tectonic`, `wkhtmltopdf`, `weasyprint`, `prince`, `context`,
+ and `pdfroff`. The default is `pdflatex`. If the engine is
+ not in your PATH, the full path of the engine may be specified here.
`--pdf-engine-opt=`*STRING*
diff --git a/data/bash_completion.tpl b/data/bash_completion.tpl
index 71fe583f5..d065c34bb 100644
--- a/data/bash_completion.tpl
+++ b/data/bash_completion.tpl
@@ -34,7 +34,7 @@ _pandoc()
return 0
;;
--pdf-engine)
- COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
+ COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk tectonic wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
return 0
;;
--print-default-data-file)
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
index 36c68057c..4253620f7 100644
--- a/src/Text/Pandoc/App/CommandLineOptions.hs
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -85,7 +85,7 @@ parseOptions options' defaults = do
return (opts{ optInputFiles = map normalizePath args })
latexEngines :: [String]
-latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk"]
+latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk", "tectonic"]
htmlEngines :: [String]
htmlEngines = ["wkhtmltopdf", "weasyprint", "prince"]
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index 65713b40c..9f5bc7a8d 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -70,7 +70,7 @@ makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex,
-> WriterOptions -- ^ options
-> Pandoc -- ^ document
-> PandocIO (Either ByteString ByteString)
-makePDF program pdfargs writer opts doc = do
+makePDF program pdfargs writer opts doc =
case takeBaseName program of
"wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc
prog | prog `elem` ["weasyprint", "prince"] -> do
@@ -107,6 +107,7 @@ makePDF program pdfargs writer opts doc = do
source <- writer opts doc'
res <- case baseProg of
"context" -> context2pdf verbosity program pdfargs tmpdir source
+ "tectonic" -> tectonic2pdf verbosity program pdfargs tmpdir source
prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"]
-> tex2pdf verbosity program pdfargs tmpdir source
_ -> return $ Left $ UTF8.fromStringLazy
@@ -200,6 +201,21 @@ convertImage tmpdir fname =
mime = getMimeType fname
doNothing = return (Right fname)
+tectonic2pdf :: Verbosity -- ^ Verbosity level
+ -> String -- ^ tex program
+ -> [String] -- ^ Arguments to the latex-engine
+ -> FilePath -- ^ temp directory for output
+ -> Text -- ^ tex source
+ -> PandocIO (Either ByteString ByteString)
+tectonic2pdf verbosity program args tmpDir source = do
+ (exit, log', mbPdf) <- runTectonic verbosity program args tmpDir source
+ case (exit, mbPdf) of
+ (ExitFailure _, _) -> return $ Left $ extractMsg log'
+ (ExitSuccess, Nothing) -> return $ Left ""
+ (ExitSuccess, Just pdf) -> do
+ missingCharacterWarnings verbosity log'
+ return $ Right pdf
+
tex2pdf :: Verbosity -- ^ Verbosity level
-> String -- ^ tex program
-> [String] -- ^ Arguments to the latex-engine
@@ -207,12 +223,9 @@ tex2pdf :: Verbosity -- ^ Verbosity level
-> Text -- ^ tex source
-> PandocIO (Either ByteString ByteString)
tex2pdf verbosity program args tmpDir source = do
- let numruns =
- if takeBaseName program == "latexmk"
- then 1
- else if "\\tableofcontents" `T.isInfixOf` source
- then 3 -- to get page numbers
- else 2 -- 1 run won't give you PDF bookmarks
+ let numruns | takeBaseName program == "latexmk" = 1
+ | "\\tableofcontents" `T.isInfixOf` source = 3 -- to get page numbers
+ | otherwise = 2 -- 1 run won't give you PDF bookmarks
(exit, log', mbPdf) <- runTeXProgram verbosity program args 1 numruns
tmpDir source
case (exit, mbPdf) of
@@ -262,6 +275,59 @@ extractConTeXtMsg log' = do
-- running tex programs
+runTectonic :: Verbosity -> String -> [String] -> FilePath
+ -> Text -> PandocIO (ExitCode, ByteString, Maybe ByteString)
+runTectonic verbosity program args' tmpDir' source = do
+ let getOutDir acc (a:b:xs) = if a `elem` ["-o", "--outdir"]
+ then (reverse acc ++ xs, Just b)
+ else getOutDir (b:a:acc) xs
+ getOutDir acc xs = (reverse acc ++ xs, Nothing)
+ (args, outDir) = getOutDir [] args'
+ tmpDir = fromMaybe tmpDir' outDir
+ liftIO $ createDirectoryIfMissing True tmpDir
+ -- run tectonic on stdin so it reads \include commands from $PWD instead of a temp directory
+ let sourceBL = BL.fromStrict $ UTF8.fromText source
+ let programArgs = ["--outdir", tmpDir] ++ args ++ ["-"]
+ env <- liftIO getEnvironment
+ when (verbosity >= INFO) $ liftIO $
+ showVerboseInfo (Just tmpDir) program programArgs env (UTF8.toStringLazy sourceBL)
+ (exit, out) <- liftIO $ E.catch
+ (pipeProcess (Just env) program programArgs sourceBL)
+ (\(e :: IOError) -> if isDoesNotExistError e
+ then E.throwIO $ PandocPDFProgramNotFoundError
+ program
+ else E.throwIO e)
+ when (verbosity >= INFO) $ liftIO $ do
+ putStrLn "[makePDF] Running"
+ BL.hPutStr stdout out
+ putStr "\n"
+ let pdfFile = tmpDir </> "texput.pdf"
+ (_, pdf) <- getResultingPDF Nothing pdfFile
+ return (exit, out, pdf)
+
+-- read a pdf that has been written to a temporary directory, and optionally read
+-- logs
+getResultingPDF :: Maybe String -> String -> PandocIO (Maybe ByteString, Maybe ByteString)
+getResultingPDF logFile pdfFile = do
+ pdfExists <- liftIO $ doesFileExist pdfFile
+ pdf <- if pdfExists
+ -- We read PDF as a strict bytestring to make sure that the
+ -- temp directory is removed on Windows.
+ -- See https://github.com/jgm/pandoc/issues/1192.
+ then (Just . BL.fromChunks . (:[])) `fmap`
+ liftIO (BS.readFile pdfFile)
+ else return Nothing
+ -- Note that some things like Missing character warnings
+ -- appear in the log but not on stderr, so we prefer the log:
+ log' <- case logFile of
+ Just logFile' -> do
+ logExists <- liftIO $ doesFileExist logFile'
+ if logExists
+ then liftIO $ Just <$> BL.readFile logFile'
+ else return Nothing
+ Nothing -> return Nothing
+ return (log', pdf)
+
-- Run a TeX program on an input bytestring and return (exit code,
-- contents of stdout, contents of produced PDF if any). Rerun
-- a fixed number of times to resolve references.
@@ -276,12 +342,11 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir' source = do
let file = tmpDir </> "input.tex"
exists <- liftIO $ doesFileExist file
unless exists $ liftIO $ BS.writeFile file $ UTF8.fromText source
- let programArgs =
- if takeBaseName program == "latexmk"
- then ["-interaction=batchmode", "-halt-on-error", "-pdf",
- "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
- else ["-halt-on-error", "-interaction", "nonstopmode",
- "-output-directory", tmpDir] ++ args ++ [file]
+ let isLatexMk = takeBaseName program == "latexmk"
+ programArgs | isLatexMk = ["-interaction=batchmode", "-halt-on-error", "-pdf",
+ "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
+ | otherwise = ["-halt-on-error", "-interaction", "nonstopmode",
+ "-output-directory", tmpDir] ++ args ++ [file]
env' <- liftIO getEnvironment
let sep = [searchPathSeparator]
let texinputs = maybe (tmpDir ++ sep) ((tmpDir ++ sep) ++)
@@ -306,23 +371,10 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir' source = do
if runNumber < numRuns
then runTeXProgram verbosity program args (runNumber + 1) numRuns tmpDir source
else do
- let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
- pdfExists <- liftIO $ doesFileExist pdfFile
- pdf <- if pdfExists
- -- We read PDF as a strict bytestring to make sure that the
- -- temp directory is removed on Windows.
- -- See https://github.com/jgm/pandoc/issues/1192.
- then (Just . BL.fromChunks . (:[])) `fmap`
- liftIO (BS.readFile pdfFile)
- else return Nothing
- -- Note that some things like Missing character warnings
- -- appear in the log but not on stderr, so we prefer the log:
let logFile = replaceExtension file ".log"
- logExists <- liftIO $ doesFileExist logFile
- log' <- if logExists
- then liftIO $ BL.readFile logFile
- else return out
- return (exit, log', pdf)
+ let pdfFile = replaceExtension file ".pdf"
+ (log', pdf) <- getResultingPDF (Just logFile) pdfFile
+ return (exit, fromMaybe out log', pdf)
generic2pdf :: Verbosity
-> String