aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/PDF.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Text/Pandoc/PDF.hs')
-rw-r--r--src/Text/Pandoc/PDF.hs173
1 files changed, 89 insertions, 84 deletions
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index c4e30af34..9ff4bfb09 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
{- |
Module : Text.Pandoc.PDF
Copyright : Copyright (C) 2012-2021 John MacFarlane
@@ -50,13 +51,13 @@ import Text.Pandoc.Shared (inDirectory, stringify, tshow)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Walk (walkM)
import Text.Pandoc.Writers.Shared (getField, metaToContext)
+import Control.Monad.Catch (MonadMask)
#ifdef _WINDOWS
import Data.List (intercalate)
#endif
import Data.List (isPrefixOf, find)
-import Text.Pandoc.Class.PandocIO (PandocIO, extractMedia, runIOorExplode)
-import Text.Pandoc.Class.PandocMonad (fillMediaBag, getCommonState, getVerbosity,
- putCommonState, report, setVerbosity)
+import Text.Pandoc.Class (fillMediaBag, getVerbosity,
+ report, extractMedia, PandocMonad)
import Text.Pandoc.Logging
#ifdef _WINDOWS
@@ -67,14 +68,15 @@ changePathSeparators =
intercalate "/" . map (filter (/='\\')) . splitDirectories
#endif
-makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex,
+makePDF :: (PandocMonad m, MonadIO m, MonadMask m)
+ => String -- ^ pdf creator (pdflatex, lualatex, xelatex,
-- wkhtmltopdf, weasyprint, prince, context, pdfroff,
-- or path to executable)
-> [String] -- ^ arguments to pass to pdf creator
- -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer
+ -> (WriterOptions -> Pandoc -> m Text) -- ^ writer
-> WriterOptions -- ^ options
-> Pandoc -- ^ document
- -> PandocIO (Either ByteString ByteString)
+ -> m (Either ByteString ByteString)
makePDF program pdfargs writer opts doc =
case takeBaseName program of
"wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc
@@ -86,57 +88,52 @@ makePDF program pdfargs writer opts doc =
source <- writer opts doc
let args = ["-ms", "-mpdfmark", "-mspdf",
"-e", "-t", "-k", "-KUTF-8", "-i"] ++ pdfargs
- verbosity <- getVerbosity
- liftIO $ generic2pdf verbosity program args source
+ generic2pdf program args source
baseProg -> do
- commonState <- getCommonState
- verbosity <- getVerbosity
- -- latex has trouble with tildes in paths, which
- -- you find in Windows temp dir paths with longer
- -- user names (see #777)
- let withTempDir templ action = do
- tmp <- getTemporaryDirectory
- uname <- E.catch
- (do (ec, sout, _) <- readProcessWithExitCode "uname" ["-o"] ""
- if ec == ExitSuccess
- then return $ Just $ filter (not . isSpace) sout
- else return Nothing)
- (\(_ :: E.SomeException) -> return Nothing)
- if '~' `elem` tmp || uname == Just "Cygwin" -- see #5451
- then withTempDirectory "." templ action
- else withSystemTempDirectory templ action
- (newCommonState, res) <- liftIO $ withTempDir "tex2pdf." $ \tmpdir' -> do
+ withTempDir "tex2pdf." $ \tmpdir' -> do
#ifdef _WINDOWS
-- note: we want / even on Windows, for TexLive
let tmpdir = changePathSeparators tmpdir'
#else
let tmpdir = tmpdir'
#endif
- runIOorExplode $ do
- putCommonState commonState
- doc' <- handleImages opts tmpdir doc
- source <- writer opts{ writerExtensions = -- disable use of quote
- -- ligatures to avoid bad ligatures like ?`
- disableExtension Ext_smart
- (writerExtensions 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
- $ "Unknown program " ++ program
- cs <- getCommonState
- return (cs, res)
- putCommonState newCommonState
- return res
+ doc' <- handleImages opts tmpdir doc
+ source <- writer opts{ writerExtensions = -- disable use of quote
+ -- ligatures to avoid bad ligatures like ?`
+ disableExtension Ext_smart
+ (writerExtensions opts) } doc'
+ case baseProg of
+ "context" -> context2pdf program pdfargs tmpdir source
+ "tectonic" -> tectonic2pdf program pdfargs tmpdir source
+ prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"]
+ -> tex2pdf program pdfargs tmpdir source
+ _ -> return $ Left $ UTF8.fromStringLazy
+ $ "Unknown program " ++ program
+
+-- latex has trouble with tildes in paths, which
+-- you find in Windows temp dir paths with longer
+-- user names (see #777)
+withTempDir :: (PandocMonad m, MonadMask m, MonadIO m)
+ => FilePath -> (FilePath -> m a) -> m a
+withTempDir templ action = do
+ tmp <- liftIO getTemporaryDirectory
+ uname <- liftIO $ E.catch
+ (do (ec, sout, _) <- readProcessWithExitCode "uname" ["-o"] ""
+ if ec == ExitSuccess
+ then return $ Just $ filter (not . isSpace) sout
+ else return Nothing)
+ (\(_ :: E.SomeException) -> return Nothing)
+ if '~' `elem` tmp || uname == Just "Cygwin" -- see #5451
+ then withTempDirectory "." templ action
+ else withSystemTempDirectory templ action
-makeWithWkhtmltopdf :: String -- ^ wkhtmltopdf or path
+makeWithWkhtmltopdf :: (PandocMonad m, MonadIO m)
+ => String -- ^ wkhtmltopdf or path
-> [String] -- ^ arguments
- -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer
+ -> (WriterOptions -> Pandoc -> m Text) -- ^ writer
-> WriterOptions -- ^ options
-> Pandoc -- ^ document
- -> PandocIO (Either ByteString ByteString)
+ -> m (Either ByteString ByteString)
makeWithWkhtmltopdf program pdfargs writer opts doc@(Pandoc meta _) = do
let mathArgs = case writerHTMLMathMethod opts of
-- with MathJax, wait til all math is rendered:
@@ -167,16 +164,18 @@ makeWithWkhtmltopdf program pdfargs writer opts doc@(Pandoc meta _) = do
verbosity <- getVerbosity
liftIO $ html2pdf verbosity program args source
-handleImages :: WriterOptions
+handleImages :: (PandocMonad m, MonadIO m)
+ => WriterOptions
-> FilePath -- ^ temp dir to store images
-> Pandoc -- ^ document
- -> PandocIO Pandoc
+ -> m Pandoc
handleImages opts tmpdir doc =
fillMediaBag doc >>=
extractMedia tmpdir >>=
walkM (convertImages opts tmpdir)
-convertImages :: WriterOptions -> FilePath -> Inline -> PandocIO Inline
+convertImages :: (PandocMonad m, MonadIO m)
+ => WriterOptions -> FilePath -> Inline -> m Inline
convertImages opts tmpdir (Image attr ils (src, tit)) = do
img <- liftIO $ convertImage opts tmpdir $ T.unpack src
newPath <-
@@ -221,33 +220,32 @@ convertImage opts tmpdir fname = do
mime = getMimeType fname
doNothing = return (Right fname)
-tectonic2pdf :: Verbosity -- ^ Verbosity level
- -> String -- ^ tex program
+tectonic2pdf :: (PandocMonad m, MonadIO m)
+ => 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
+ -> m (Either ByteString ByteString)
+tectonic2pdf program args tmpDir source = do
+ (exit, log', mbPdf) <- runTectonic program args tmpDir source
case (exit, mbPdf) of
(ExitFailure _, _) -> return $ Left $ extractMsg log'
(ExitSuccess, Nothing) -> return $ Left ""
(ExitSuccess, Just pdf) -> do
- missingCharacterWarnings verbosity log'
+ missingCharacterWarnings log'
return $ Right pdf
-tex2pdf :: Verbosity -- ^ Verbosity level
- -> String -- ^ tex program
+tex2pdf :: (PandocMonad m, MonadIO m)
+ => String -- ^ tex program
-> [String] -- ^ Arguments to the latex-engine
-> FilePath -- ^ temp directory for output
-> Text -- ^ tex source
- -> PandocIO (Either ByteString ByteString)
-tex2pdf verbosity program args tmpDir source = do
+ -> m (Either ByteString ByteString)
+tex2pdf program args tmpDir source = do
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 numruns
- tmpDir source
+ (exit, log', mbPdf) <- runTeXProgram program args numruns tmpDir source
case (exit, mbPdf) of
(ExitFailure _, _) -> do
let logmsg = extractMsg log'
@@ -260,11 +258,11 @@ tex2pdf verbosity program args tmpDir source = do
return $ Left $ logmsg <> extramsg
(ExitSuccess, Nothing) -> return $ Left ""
(ExitSuccess, Just pdf) -> do
- missingCharacterWarnings verbosity log'
+ missingCharacterWarnings log'
return $ Right pdf
-missingCharacterWarnings :: Verbosity -> ByteString -> PandocIO ()
-missingCharacterWarnings verbosity log' = do
+missingCharacterWarnings :: PandocMonad m => ByteString -> m ()
+missingCharacterWarnings log' = do
let ls = BC.lines log'
let isMissingCharacterWarning = BC.isPrefixOf "Missing character: "
let toCodePoint c
@@ -275,7 +273,6 @@ missingCharacterWarnings verbosity log' = do
| l <- ls
, isMissingCharacterWarning l
]
- setVerbosity verbosity
mapM_ (report . MissingCharacter) warnings
-- parsing output
@@ -299,9 +296,10 @@ extractConTeXtMsg log' = do
-- running tex programs
-runTectonic :: Verbosity -> String -> [String] -> FilePath
- -> Text -> PandocIO (ExitCode, ByteString, Maybe ByteString)
-runTectonic verbosity program args' tmpDir' source = do
+runTectonic :: (PandocMonad m, MonadIO m)
+ => String -> [String] -> FilePath
+ -> Text -> m (ExitCode, ByteString, Maybe ByteString)
+runTectonic 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
@@ -313,6 +311,7 @@ runTectonic verbosity program args' tmpDir' source = do
let sourceBL = BL.fromStrict $ UTF8.fromText source
let programArgs = ["--outdir", tmpDir] ++ args ++ ["-"]
env <- liftIO getEnvironment
+ verbosity <- getVerbosity
when (verbosity >= INFO) $ liftIO $
showVerboseInfo (Just tmpDir) program programArgs env
(utf8ToText sourceBL)
@@ -329,7 +328,9 @@ runTectonic verbosity program args' tmpDir' source = do
-- 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 :: (PandocMonad m, MonadIO m)
+ => Maybe String -> String
+ -> m (Maybe ByteString, Maybe ByteString)
getResultingPDF logFile pdfFile = do
pdfExists <- liftIO $ doesFileExist pdfFile
pdf <- if pdfExists
@@ -353,9 +354,10 @@ getResultingPDF logFile pdfFile = do
-- 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.
-runTeXProgram :: Verbosity -> String -> [String] -> Int -> FilePath
- -> Text -> PandocIO (ExitCode, ByteString, Maybe ByteString)
-runTeXProgram verbosity program args numRuns tmpDir' source = do
+runTeXProgram :: (PandocMonad m, MonadIO m)
+ => String -> [String] -> Int -> FilePath
+ -> Text -> m (ExitCode, ByteString, Maybe ByteString)
+runTeXProgram program args numRuns tmpDir' source = do
let isOutdirArg x = "-outdir=" `isPrefixOf` x ||
"-output-directory=" `isPrefixOf` x
let tmpDir =
@@ -378,6 +380,7 @@ runTeXProgram verbosity program args numRuns tmpDir' source = do
("TEXMFOUTPUT", tmpDir) :
[(k,v) | (k,v) <- env'
, k /= "TEXINPUTS" && k /= "TEXMFOUTPUT"]
+ verbosity <- getVerbosity
when (verbosity >= INFO) $ liftIO $
UTF8.readFile file >>=
showVerboseInfo (Just tmpDir) program programArgs env''
@@ -398,16 +401,17 @@ runTeXProgram verbosity program args numRuns tmpDir' source = do
return (exit, fromMaybe out log', pdf)
runTeX 1
-generic2pdf :: Verbosity
- -> String
+generic2pdf :: (PandocMonad m, MonadIO m)
+ => String
-> [String]
-> Text
- -> IO (Either ByteString ByteString)
-generic2pdf verbosity program args source = do
- env' <- getEnvironment
+ -> m (Either ByteString ByteString)
+generic2pdf program args source = do
+ env' <- liftIO getEnvironment
+ verbosity <- getVerbosity
when (verbosity >= INFO) $
- showVerboseInfo Nothing program args env' source
- (exit, out) <- E.catch
+ liftIO $ showVerboseInfo Nothing program args env' source
+ (exit, out) <- liftIO $ E.catch
(pipeProcess (Just env') program args
(BL.fromStrict $ UTF8.fromText source))
(handlePDFProgramNotFound program)
@@ -454,19 +458,20 @@ html2pdf verbosity program args source =
(ExitSuccess, Nothing) -> Left ""
(ExitSuccess, Just pdf) -> Right pdf
-context2pdf :: Verbosity -- ^ Verbosity level
- -> String -- ^ "context" or path to it
+context2pdf :: (PandocMonad m, MonadIO m)
+ => String -- ^ "context" or path to it
-> [String] -- ^ extra arguments
-> FilePath -- ^ temp directory for output
-> Text -- ^ ConTeXt source
- -> PandocIO (Either ByteString ByteString)
-context2pdf verbosity program pdfargs tmpDir source =
+ -> m (Either ByteString ByteString)
+context2pdf program pdfargs tmpDir source = do
+ verbosity <- getVerbosity
liftIO $ inDirectory tmpDir $ do
let file = "input.tex"
BS.writeFile file $ UTF8.fromText source
let programArgs = "--batchmode" : pdfargs ++ [file]
env' <- getEnvironment
- when (verbosity >= INFO) $
+ when (verbosity >= INFO) $ liftIO $
UTF8.readFile file >>=
showVerboseInfo (Just tmpDir) program programArgs env'
(exit, out) <- E.catch