git.iko.soy/typeable/pandoc
on master help sign in
Add latexmk as an option for --pdf-engine.

Closes #3195. Note that you can use --pdf-engine-opt=-outdir=bar to specify a persistent temp dir.

commit11aa5fd2880a32f56ca29e64c5121ac5702e4dea authorJohn MacFarlane <jgm@berkeley.edu> dateWed 27 Feb 2019, 23:38 (8 years ago) parentf152d4d
3 files changed+80−84
MANUAL.txt+7−4 src/Text/Pandoc/App/CommandLineOptions.hs+1−1 src/Text/Pandoc/PDF.hs+72−79
MANUAL.txt+7−4
@@ -1192,17 +1192,20 @@ Options affecting specific writers {.options}
11921192 the EPUB-specific contents. The default is `EPUB`. To put
11931193 the EPUB contents in the top level, use an empty string.
11941194
1195−`--pdf-engine=pdflatex`|`lualatex`|`xelatex`|`wkhtmltopdf`|`weasyprint`|`prince`|`context`|`pdfroff`
1195+`--pdf-engine=`*PROGRAM*
11961196
11971197: Use the specified engine when producing PDF output.
1198+ Valid values are `pdflatex`, `lualatex`, `xelatex`, `latexmk`,
1199+ `wkhtmltopdf`, `weasyprint`, `prince`, `context`, and `pdfroff`.
11981200 The default is `pdflatex`. If the engine is not in your PATH,
11991201 the full path of the engine may be specified here.
12001202
12011203`--pdf-engine-opt=`*STRING*
12021204
12031205: Use the given string as a command-line argument to the `pdf-engine`.
1204− If used multiple times, the arguments are provided with spaces between
1205− them. Note that no check for duplicate options is done.
1206+ For example, to use a persistent directory `foo` for `latexmk`'s
1207+ auxiliary files, use `--pdf-engine-opt=-outdir=foo`.
1208+ Note that no check for duplicate options is done.
12061209
12071210[Dublin Core elements]: http://dublincore.org/documents/dces/
12081211[ISO 8601 format]: http://www.w3.org/TR/NOTE-datetime
@@ -1449,7 +1452,7 @@ Language variables
14491452 :::
14501453
14511454 More text in English. ['Zitat auf Deutsch.']{lang=de}
1452−
1455+
14531456`dir`
14541457: the base script direction, either `rtl` (right-to-left)
14551458 or `ltr` (left-to-right).
src/Text/Pandoc/App/CommandLineOptions.hs+1−1
@@ -104,7 +104,7 @@ parseOptions options' defaults = do
104104 return (opts{ optInputFiles = map normalizePath args })
105105
106106latexEngines :: [String]
107−latexEngines = ["pdflatex", "lualatex", "xelatex"]
107+latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk"]
108108
109109htmlEngines :: [String]
110110htmlEngines = ["wkhtmltopdf", "weasyprint", "prince"]
src/Text/Pandoc/PDF.hs+72−79
@@ -69,6 +69,7 @@ import Text.Pandoc.Writers.Shared (getField, metaToJSON)
6969#ifdef _WINDOWS
7070import Data.List (intercalate)
7171#endif
72+import Data.List (isPrefixOf)
7273import Text.Pandoc.Class (PandocIO, extractMedia, fillMediaBag, getCommonState,
7374 getVerbosity, putCommonState, report, runIO,
7475 runIOorExplode, setVerbosity)
@@ -99,7 +100,7 @@ makePDF program pdfargs writer opts doc = do
99100 let args = ["-ms", "-mpdfmark", "-e", "-t", "-k", "-KUTF-8", "-i",
100101 "--no-toc-relocation"] ++ pdfargs
101102 verbosity <- getVerbosity
102− liftIO $ ms2pdf verbosity program args source
103+ liftIO $ generic2pdf verbosity program args source
103104 baseProg -> do
104105 commonState <- getCommonState
105106 verbosity <- getVerbosity
@@ -111,14 +112,20 @@ makePDF program pdfargs writer opts doc = do
111112 if '~' `elem` tmp
112113 then withTempDirectory "." templ action
113114 else withSystemTempDirectory templ action
114− liftIO $ withTempDir "tex2pdf." $ \tmpdir -> do
115+ liftIO $ withTempDir "tex2pdf." $ \tmpdir' -> do
116+#ifdef _WINDOWS
117+ -- note: we want / even on Windows, for TexLive
118+ let tmpdir = changePathSeparators tmpdir'
119+#else
120+ let tmpdir = tmpdir'
121+#endif
115122 source <- runIOorExplode $ do
116123 putCommonState commonState
117124 doc' <- handleImages tmpdir doc
118125 writer opts doc'
119126 case baseProg of
120− "context" -> context2pdf verbosity program tmpdir source
121− prog | prog `elem` ["pdflatex", "lualatex", "xelatex"]
127+ "context" -> context2pdf verbosity program pdfargs tmpdir source
128+ prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"]
122129 -> tex2pdf verbosity program pdfargs tmpdir source
123130 _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program
124131
@@ -213,7 +220,10 @@ tex2pdf :: Verbosity -- ^ Verbosity level
213220 -> Text -- ^ tex source
214221 -> IO (Either ByteString ByteString)
215222tex2pdf verbosity program args tmpDir source = do
216− let numruns = if "\\tableofcontents" `T.isInfixOf` source
223+ let numruns =
224+ if takeBaseName program == "latexmk"
225+ then 1
226+ else if "\\tableofcontents" `T.isInfixOf` source
217227 then 3 -- to get page numbers
218228 else 2 -- 1 run won't give you PDF bookmarks
219229 (exit, log', mbPdf) <- E.catch
@@ -276,40 +286,32 @@ extractConTeXtMsg log' = do
276286-- a fixed number of times to resolve references.
277287runTeXProgram :: Verbosity -> String -> [String] -> Int -> Int -> FilePath
278288 -> Text -> IO (ExitCode, ByteString, Maybe ByteString)
279−runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
289+runTeXProgram verbosity program args runNumber numRuns tmpDir' source = do
290+ let tmpDir =
291+ case [x | x <- args, "-outdir=" `isPrefixOf` x] of
292+ [x] -> drop 8 x
293+ _ -> tmpDir'
294+ createDirectoryIfMissing True tmpDir
280295 let file = tmpDir </> "input.tex"
281296 exists <- doesFileExist file
282297 unless exists $ BS.writeFile file $ UTF8.fromText source
283−#ifdef _WINDOWS
284− -- note: we want / even on Windows, for TexLive
285− let tmpDir' = changePathSeparators tmpDir
286− let file' = changePathSeparators file
287−#else
288− let tmpDir' = tmpDir
289− let file' = file
290−#endif
291− let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
292− "-output-directory", tmpDir'] ++ args ++ [file']
298+ let programArgs =
299+ if takeBaseName program == "latexmk"
300+ then ["-interaction=batchmode", "-halt-on-error", "-pdf",
301+ "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
302+ else ["-halt-on-error", "-interaction", "nonstopmode",
303+ "-output-directory", tmpDir] ++ args ++ [file]
293304 env' <- getEnvironment
294305 let sep = [searchPathSeparator]
295− let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
306+ let texinputs = maybe (tmpDir ++ sep) ((tmpDir ++ sep) ++)
296307 $ lookup "TEXINPUTS" env'
297308 let env'' = ("TEXINPUTS", texinputs) :
298− ("TEXMFOUTPUT", tmpDir') :
309+ ("TEXMFOUTPUT", tmpDir) :
299310 [(k,v) | (k,v) <- env'
300311 , k /= "TEXINPUTS" && k /= "TEXMFOUTPUT"]
301− when (verbosity >= INFO && runNumber == 1) $ do
302− putStrLn "[makePDF] temp dir:"
303− putStrLn tmpDir'
304− putStrLn "[makePDF] Command line:"
305− putStrLn $ program ++ " " ++ unwords (map show programArgs)
306− putStr "\n"
307− putStrLn "[makePDF] Environment:"
308− mapM_ print env''
309− putStr "\n"
310− putStrLn $ "[makePDF] Contents of " ++ file' ++ ":"
311− BL.readFile file' >>= BL.putStr
312− putStr "\n"
312+ when (runNumber == 1 && verbosity >= INFO) $
313+ UTF8.readFile file >>=
314+ showVerboseInfo (Just tmpDir) program programArgs env''
313315 (exit, out) <- pipeProcess (Just env'') program programArgs BL.empty
314316 when (verbosity >= INFO) $ do
315317 putStrLn $ "[makePDF] Run #" ++ show runNumber
@@ -335,23 +337,15 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
335337 else return out
336338 return (exit, log', pdf)
337339
338−ms2pdf :: Verbosity
339− -> String
340− -> [String]
341− -> Text
342− -> IO (Either ByteString ByteString)
343−ms2pdf verbosity program args source = do
340+generic2pdf :: Verbosity
341+ -> String
342+ -> [String]
343+ -> Text
344+ -> IO (Either ByteString ByteString)
345+generic2pdf verbosity program args source = do
344346 env' <- getEnvironment
345− when (verbosity >= INFO) $ do
346− putStrLn "[makePDF] Command line:"
347− putStrLn $ program ++ " " ++ unwords (map show args)
348− putStr "\n"
349− putStrLn "[makePDF] Environment:"
350− mapM_ print env'
351− putStr "\n"
352− putStrLn "[makePDF] Contents:\n"
353− putStr $ T.unpack source
354− putStr "\n"
347+ when (verbosity >= INFO) $
348+ showVerboseInfo Nothing program args env' (T.unpack source)
355349 (exit, out) <- E.catch
356350 (pipeProcess (Just env') program args
357351 (BL.fromStrict $ UTF8.fromText source))
@@ -359,13 +353,11 @@ ms2pdf verbosity program args source = do
359353 then E.throwIO $
360354 PandocPDFProgramNotFoundError program
361355 else E.throwIO e)
362− when (verbosity >= INFO) $ do
363− BL.hPutStr stdout out
364− putStr "\n"
365356 return $ case exit of
366357 ExitFailure _ -> Left out
367358 ExitSuccess -> Right out
368359
360+
369361html2pdf :: Verbosity -- ^ Verbosity level
370362 -> String -- ^ Program (wkhtmltopdf, weasyprint, prince, or path)
371363 -> [String] -- ^ Args to program
@@ -381,16 +373,9 @@ html2pdf verbosity program args source = do
381373 let pdfFileArgName = ["-o" | takeBaseName program == "prince"]
382374 let programArgs = args ++ [file] ++ pdfFileArgName ++ [pdfFile]
383375 env' <- getEnvironment
384− when (verbosity >= INFO) $ do
385− putStrLn "[makePDF] Command line:"
386− putStrLn $ program ++ " " ++ unwords (map show programArgs)
387− putStr "\n"
388− putStrLn "[makePDF] Environment:"
389− mapM_ print env'
390− putStr "\n"
391− putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
392− BL.readFile file >>= BL.putStr
393− putStr "\n"
376+ when (verbosity >= INFO) $
377+ UTF8.readFile file >>=
378+ showVerboseInfo Nothing program programArgs env'
394379 (exit, out) <- E.catch
395380 (pipeProcess (Just env') program programArgs BL.empty)
396381 (\(e :: IOError) -> if isDoesNotExistError e
@@ -418,32 +403,18 @@ html2pdf verbosity program args source = do
418403
419404context2pdf :: Verbosity -- ^ Verbosity level
420405 -> String -- ^ "context" or path to it
406+ -> [String] -- ^ extra arguments
421407 -> FilePath -- ^ temp directory for output
422408 -> Text -- ^ ConTeXt source
423409 -> IO (Either ByteString ByteString)
424−context2pdf verbosity program tmpDir source = inDirectory tmpDir $ do
410+context2pdf verbosity program pdfargs tmpDir source = inDirectory tmpDir $ do
425411 let file = "input.tex"
426412 BS.writeFile file $ UTF8.fromText source
427−#ifdef _WINDOWS
428− -- note: we want / even on Windows, for TexLive
429− let tmpDir' = changePathSeparators tmpDir
430−#else
431− let tmpDir' = tmpDir
432−#endif
433− let programArgs = "--batchmode" : [file]
413+ let programArgs = "--batchmode" : pdfargs ++ [file]
434414 env' <- getEnvironment
435− when (verbosity >= INFO) $ do
436− putStrLn "[makePDF] temp dir:"
437− putStrLn tmpDir'
438− putStrLn "[makePDF] Command line:"
439− putStrLn $ program ++ " " ++ unwords (map show programArgs)
440− putStr "\n"
441− putStrLn "[makePDF] Environment:"
442− mapM_ print env'
443− putStr "\n"
444− putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
445− BL.readFile file >>= BL.putStr
446− putStr "\n"
415+ when (verbosity >= INFO) $
416+ UTF8.readFile file >>=
417+ showVerboseInfo (Just tmpDir) program programArgs env'
447418 (exit, out) <- E.catch
448419 (pipeProcess (Just env') program programArgs BL.empty)
449420 (\(e :: IOError) -> if isDoesNotExistError e
@@ -467,3 +438,25 @@ context2pdf verbosity program tmpDir source = inDirectory tmpDir $ do
467438 return $ Left logmsg
468439 (ExitSuccess, Nothing) -> return $ Left ""
469440 (ExitSuccess, Just pdf) -> return $ Right pdf
441+
442+
443+showVerboseInfo :: Maybe FilePath
444+ -> String
445+ -> [String]
446+ -> [(String, String)]
447+ -> String
448+ -> IO ()
449+showVerboseInfo mbTmpDir program programArgs env source = do
450+ case mbTmpDir of
451+ Just tmpDir -> do
452+ putStrLn "[makePDF] temp dir:"
453+ putStrLn tmpDir
454+ Nothing -> return ()
455+ putStrLn "[makePDF] Command line:"
456+ putStrLn $ program ++ " " ++ unwords (map show programArgs)
457+ putStr "\n"
458+ putStrLn "[makePDF] Environment:"
459+ mapM_ print env
460+ putStr "\n"
461+ putStrLn $ "[makePDF] Source:"
462+ putStrLn source