{-# LANGUAGE CPP                 #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections       #-}
{- |
   Module      : Text.Pandoc.App
   Copyright   : Copyright (C) 2006-2021 John MacFarlane
   License     : GNU GPL, version 2 or above

   Maintainer  : John MacFarlane <jgm@berkeley@edu>
   Stability   : alpha
   Portability : portable

Does a pandoc conversion based on command-line options.
-}
module Text.Pandoc.App.OutputSettings
  ( OutputSettings (..)
  , optToOutputSettings
  ) where
import qualified Data.Map as M
import qualified Data.Text as T
import Text.DocTemplates (toVal, Context(..), Val(..))
import qualified Control.Exception as E
import Control.Monad
import Control.Monad.Except (throwError)
import Control.Monad.Trans
import Data.Char (toLower)
import Data.List (find)
import Data.Maybe (fromMaybe)
import Skylighting (defaultSyntaxMap)
import Skylighting.Parser (addSyntaxDefinition, parseSyntaxDefinition)
import System.Directory (getCurrentDirectory)
import System.Exit (exitSuccess)
import System.FilePath
import System.IO (stdout)
import Text.Pandoc
import Text.Pandoc.App.FormatHeuristics (formatFromFilePaths)
import Text.Pandoc.App.Opt (Opt (..))
import Text.Pandoc.App.CommandLineOptions (engines, lookupHighlightStyle,
                                          setVariable)
import qualified Text.Pandoc.UTF8 as UTF8

readUtf8File :: PandocMonad m => FilePath -> m T.Text
readUtf8File :: FilePath -> m Text
readUtf8File = (ByteString -> Text) -> m ByteString -> m Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Text
UTF8.toText (m ByteString -> m Text)
-> (FilePath -> m ByteString) -> FilePath -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readFileStrict

-- | Settings specifying how document output should be produced.
data OutputSettings m = OutputSettings
  { OutputSettings m -> Text
outputFormat :: T.Text
  , OutputSettings m -> Writer m
outputWriter :: Writer m
  , OutputSettings m -> Text
outputWriterName :: T.Text
  , OutputSettings m -> WriterOptions
outputWriterOptions :: WriterOptions
  , OutputSettings m -> Maybe FilePath
outputPdfProgram :: Maybe String
  }

-- | Get output settings from command line options.
optToOutputSettings :: (PandocMonad m, MonadIO m) => Opt -> m (OutputSettings m)
optToOutputSettings :: Opt -> m (OutputSettings m)
optToOutputSettings Opt
opts = do
  let outputFile :: FilePath
outputFile = FilePath -> Maybe FilePath -> FilePath
forall a. a -> Maybe a -> a
fromMaybe FilePath
"-" (Opt -> Maybe FilePath
optOutputFile Opt
opts)

  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Opt -> Bool
optDumpArgs Opt
opts) (m () -> m ()) -> (IO () -> m ()) -> IO () -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ do
    Handle -> Text -> IO ()
UTF8.hPutStrLn Handle
stdout (FilePath -> Text
T.pack FilePath
outputFile)
    (FilePath -> IO ()) -> [FilePath] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Handle -> Text -> IO ()
UTF8.hPutStrLn Handle
stdout (Text -> IO ()) -> (FilePath -> Text) -> FilePath -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack) ([FilePath] -> Maybe [FilePath] -> [FilePath]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [FilePath] -> [FilePath]) -> Maybe [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ Opt -> Maybe [FilePath]
optInputFiles Opt
opts)
    IO ()
forall a. IO a
exitSuccess

  Maybe Text
epubMetadata <- (FilePath -> m Text) -> Maybe FilePath -> m (Maybe Text)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse FilePath -> m Text
forall (m :: * -> *). PandocMonad m => FilePath -> m Text
readUtf8File (Maybe FilePath -> m (Maybe Text))
-> Maybe FilePath -> m (Maybe Text)
forall a b. (a -> b) -> a -> b
$ Opt -> Maybe FilePath
optEpubMetadata Opt
opts

  let pdfOutput :: Bool
pdfOutput = (Char -> Char) -> FilePath -> FilePath
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (FilePath -> FilePath
takeExtension FilePath
outputFile) FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
".pdf" Bool -> Bool -> Bool
||
                  Opt -> Maybe Text
optTo Opt
opts Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"pdf"
  (Text
writerName, Maybe FilePath
maybePdfProg) <-
    if Bool
pdfOutput
       then IO (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Text, Maybe FilePath) -> m (Text, Maybe FilePath))
-> IO (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall a b. (a -> b) -> a -> b
$ Maybe Text -> Maybe FilePath -> IO (Text, Maybe FilePath)
pdfWriterAndProg
               (case Opt -> Maybe Text
optTo Opt
opts of
                  Just Text
"pdf" -> Maybe Text
forall a. Maybe a
Nothing
                  Maybe Text
x          -> Maybe Text
x)
               (Opt -> Maybe FilePath
optPdfEngine Opt
opts)
       else case Opt -> Maybe Text
optTo Opt
opts of
              Just Text
f -> (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
f, Maybe FilePath
forall a. Maybe a
Nothing)
              Maybe Text
Nothing
               | FilePath
outputFile FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"-" -> (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"html", Maybe FilePath
forall a. Maybe a
Nothing)
               | Bool
otherwise ->
                     case [FilePath] -> Maybe Text
formatFromFilePaths [FilePath
outputFile] of
                           Maybe Text
Nothing -> do
                             LogMessage -> m ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> m ()) -> LogMessage -> m ()
forall a b. (a -> b) -> a -> b
$ [Text] -> Text -> LogMessage
CouldNotDeduceFormat
                                [FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
takeExtension FilePath
outputFile] Text
"html"
                             (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"html", Maybe FilePath
forall a. Maybe a
Nothing)
                           Just Text
f  -> (Text, Maybe FilePath) -> m (Text, Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
f, Maybe FilePath
forall a. Maybe a
Nothing)

  let format :: Text
format = if Text
".lua" Text -> Text -> Bool
`T.isSuffixOf` Text
writerName
                  then Text
writerName
                  else Text -> Text
T.toLower (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
baseWriterName Text
writerName

  let makeSandboxed :: Writer PandocPure -> Writer m
makeSandboxed Writer PandocPure
pureWriter =
          let files :: [FilePath]
files = ([FilePath] -> [FilePath])
-> (FilePath -> [FilePath] -> [FilePath])
-> Maybe FilePath
-> [FilePath]
-> [FilePath]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilePath] -> [FilePath]
forall a. a -> a
id (:) (Opt -> Maybe FilePath
optReferenceDoc Opt
opts) ([FilePath] -> [FilePath])
-> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                      ([FilePath] -> [FilePath])
-> (FilePath -> [FilePath] -> [FilePath])
-> Maybe FilePath
-> [FilePath]
-> [FilePath]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilePath] -> [FilePath]
forall a. a -> a
id (:) (Opt -> Maybe FilePath
optEpubMetadata Opt
opts) ([FilePath] -> [FilePath])
-> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                      ([FilePath] -> [FilePath])
-> (FilePath -> [FilePath] -> [FilePath])
-> Maybe FilePath
-> [FilePath]
-> [FilePath]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilePath] -> [FilePath]
forall a. a -> a
id (:) (Opt -> Maybe FilePath
optEpubCoverImage Opt
opts) ([FilePath] -> [FilePath])
-> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                      ([FilePath] -> [FilePath])
-> (FilePath -> [FilePath] -> [FilePath])
-> Maybe FilePath
-> [FilePath]
-> [FilePath]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilePath] -> [FilePath]
forall a. a -> a
id (:) (Opt -> Maybe FilePath
optCSL Opt
opts) ([FilePath] -> [FilePath])
-> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                      ([FilePath] -> [FilePath])
-> (FilePath -> [FilePath] -> [FilePath])
-> Maybe FilePath
-> [FilePath]
-> [FilePath]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [FilePath] -> [FilePath]
forall a. a -> a
id (:) (Opt -> Maybe FilePath
optCitationAbbreviations Opt
opts) ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$
                      Opt -> [FilePath]
optEpubFonts Opt
opts [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++
                      Opt -> [FilePath]
optBibliography Opt
opts
           in  case Writer PandocPure
pureWriter of
                 TextWriter WriterOptions -> Pandoc -> PandocPure Text
w -> (WriterOptions -> Pandoc -> m Text) -> Writer m
forall (m :: * -> *).
(WriterOptions -> Pandoc -> m Text) -> Writer m
TextWriter ((WriterOptions -> Pandoc -> m Text) -> Writer m)
-> (WriterOptions -> Pandoc -> m Text) -> Writer m
forall a b. (a -> b) -> a -> b
$ \WriterOptions
o Pandoc
d -> [FilePath] -> PandocPure Text -> m Text
forall (m :: * -> *) a.
(PandocMonad m, MonadIO m) =>
[FilePath] -> PandocPure a -> m a
sandbox [FilePath]
files (WriterOptions -> Pandoc -> PandocPure Text
w WriterOptions
o Pandoc
d)
                 ByteStringWriter WriterOptions -> Pandoc -> PandocPure ByteString
w
                            -> (WriterOptions -> Pandoc -> m ByteString) -> Writer m
forall (m :: * -> *).
(WriterOptions -> Pandoc -> m ByteString) -> Writer m
ByteStringWriter ((WriterOptions -> Pandoc -> m ByteString) -> Writer m)
-> (WriterOptions -> Pandoc -> m ByteString) -> Writer m
forall a b. (a -> b) -> a -> b
$ \WriterOptions
o Pandoc
d -> [FilePath] -> PandocPure ByteString -> m ByteString
forall (m :: * -> *) a.
(PandocMonad m, MonadIO m) =>
[FilePath] -> PandocPure a -> m a
sandbox [FilePath]
files (WriterOptions -> Pandoc -> PandocPure ByteString
w WriterOptions
o Pandoc
d)


  (Writer m
writer, Extensions
writerExts) <-
            if Text
".lua" Text -> Text -> Bool
`T.isSuffixOf` Text
format
               then (Writer m, Extensions) -> m (Writer m, Extensions)
forall (m :: * -> *) a. Monad m => a -> m a
return ((WriterOptions -> Pandoc -> m Text) -> Writer m
forall (m :: * -> *).
(WriterOptions -> Pandoc -> m Text) -> Writer m
TextWriter
                       (\WriterOptions
o Pandoc
d -> FilePath -> WriterOptions -> Pandoc -> m Text
forall (m :: * -> *).
(PandocMonad m, MonadIO m) =>
FilePath -> WriterOptions -> Pandoc -> m Text
writeCustom (Text -> FilePath
T.unpack Text
writerName) WriterOptions
o Pandoc
d), Extensions
forall a. Monoid a => a
mempty)
               else if Opt -> Bool
optSandbox Opt
opts
                       then
                         case PandocPure (Writer PandocPure, Extensions)
-> Either PandocError (Writer PandocPure, Extensions)
forall a. PandocPure a -> Either PandocError a
runPure (Text -> PandocPure (Writer PandocPure, Extensions)
forall (m :: * -> *).
PandocMonad m =>
Text -> m (Writer m, Extensions)
getWriter Text
writerName) of
                           Left PandocError
e -> PandocError -> m (Writer m, Extensions)
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError PandocError
e
                           Right (Writer PandocPure
w, Extensions
wexts) ->
                                  (Writer m, Extensions) -> m (Writer m, Extensions)
forall (m :: * -> *) a. Monad m => a -> m a
return (Writer PandocPure -> Writer m
forall (m :: * -> *).
(PandocMonad m, MonadIO m) =>
Writer PandocPure -> Writer m
makeSandboxed Writer PandocPure
w, Extensions
wexts)
                       else Text -> m (Writer m, Extensions)
forall (m :: * -> *).
PandocMonad m =>
Text -> m (Writer m, Extensions)
getWriter (Text -> Text
T.toLower Text
writerName)

  let standalone :: Bool
standalone = Opt -> Bool
optStandalone Opt
opts Bool -> Bool -> Bool
|| Bool -> Bool
not (Text -> Bool
isTextFormat Text
format) Bool -> Bool -> Bool
|| Bool
pdfOutput

  let addSyntaxMap :: SyntaxMap -> FilePath -> m SyntaxMap
addSyntaxMap SyntaxMap
existingmap FilePath
f = do
        Either FilePath Syntax
res <- IO (Either FilePath Syntax) -> m (Either FilePath Syntax)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (FilePath -> IO (Either FilePath Syntax)
parseSyntaxDefinition FilePath
f)
        case Either FilePath Syntax
res of
              Left FilePath
errstr -> PandocError -> m SyntaxMap
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (PandocError -> m SyntaxMap) -> PandocError -> m SyntaxMap
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocSyntaxMapError (Text -> PandocError) -> Text -> PandocError
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack FilePath
errstr
              Right Syntax
syn   -> SyntaxMap -> m SyntaxMap
forall (m :: * -> *) a. Monad m => a -> m a
return (SyntaxMap -> m SyntaxMap) -> SyntaxMap -> m SyntaxMap
forall a b. (a -> b) -> a -> b
$ Syntax -> SyntaxMap -> SyntaxMap
addSyntaxDefinition Syntax
syn SyntaxMap
existingmap

  SyntaxMap
syntaxMap <- (SyntaxMap -> FilePath -> m SyntaxMap)
-> SyntaxMap -> [FilePath] -> m SyntaxMap
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM SyntaxMap -> FilePath -> m SyntaxMap
forall (m :: * -> *).
(MonadIO m, MonadError PandocError m) =>
SyntaxMap -> FilePath -> m SyntaxMap
addSyntaxMap SyntaxMap
defaultSyntaxMap
                     (Opt -> [FilePath]
optSyntaxDefinitions Opt
opts)

  Maybe Style
hlStyle <- (Text -> m Style) -> Maybe Text -> m (Maybe Style)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (FilePath -> m Style
forall (m :: * -> *). PandocMonad m => FilePath -> m Style
lookupHighlightStyle (FilePath -> m Style) -> (Text -> FilePath) -> Text -> m Style
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack) (Maybe Text -> m (Maybe Style)) -> Maybe Text -> m (Maybe Style)
forall a b. (a -> b) -> a -> b
$ Opt -> Maybe Text
optHighlightStyle Opt
opts

  let setVariableM :: Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
k Text
v = Context Text -> m (Context Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Context Text -> m (Context Text))
-> (Context Text -> Context Text)
-> Context Text
-> m (Context Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> Context Text -> Context Text
setVariable Text
k Text
v

  let setListVariableM :: Text -> [b] -> Context a -> m (Context a)
setListVariableM Text
_ [] Context a
ctx = Context a -> m (Context a)
forall (m :: * -> *) a. Monad m => a -> m a
return Context a
ctx
      setListVariableM Text
k [b]
vs Context a
ctx = do
        let ctxMap :: Map Text (Val a)
ctxMap = Context a -> Map Text (Val a)
forall a. Context a -> Map Text (Val a)
unContext Context a
ctx
        Context a -> m (Context a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Context a -> m (Context a)) -> Context a -> m (Context a)
forall a b. (a -> b) -> a -> b
$ Map Text (Val a) -> Context a
forall a. Map Text (Val a) -> Context a
Context (Map Text (Val a) -> Context a) -> Map Text (Val a) -> Context a
forall a b. (a -> b) -> a -> b
$
          case Text -> Map Text (Val a) -> Maybe (Val a)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
k Map Text (Val a)
ctxMap of
              Just (ListVal [Val a]
xs) -> Text -> Val a -> Map Text (Val a) -> Map Text (Val a)
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Text
k
                                  ([Val a] -> Val a
forall a. [Val a] -> Val a
ListVal ([Val a] -> Val a) -> [Val a] -> Val a
forall a b. (a -> b) -> a -> b
$ [Val a]
xs [Val a] -> [Val a] -> [Val a]
forall a. [a] -> [a] -> [a]
++ (b -> Val a) -> [b] -> [Val a]
forall a b. (a -> b) -> [a] -> [b]
map b -> Val a
forall a b. ToContext a b => b -> Val a
toVal [b]
vs) Map Text (Val a)
ctxMap
              Just Val a
v -> Text -> Val a -> Map Text (Val a) -> Map Text (Val a)
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Text
k
                         ([Val a] -> Val a
forall a. [Val a] -> Val a
ListVal ([Val a] -> Val a) -> [Val a] -> Val a
forall a b. (a -> b) -> a -> b
$ Val a
v Val a -> [Val a] -> [Val a]
forall a. a -> [a] -> [a]
: (b -> Val a) -> [b] -> [Val a]
forall a b. (a -> b) -> [a] -> [b]
map b -> Val a
forall a b. ToContext a b => b -> Val a
toVal [b]
vs) Map Text (Val a)
ctxMap
              Maybe (Val a)
Nothing -> Text -> Val a -> Map Text (Val a) -> Map Text (Val a)
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Text
k ([b] -> Val a
forall a b. ToContext a b => b -> Val a
toVal [b]
vs) Map Text (Val a)
ctxMap

  let getTextContents :: FilePath -> f Text
getTextContents FilePath
fp = ByteString -> Text
UTF8.toText (ByteString -> Text)
-> ((ByteString, Maybe Text) -> ByteString)
-> (ByteString, Maybe Text)
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString, Maybe Text) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, Maybe Text) -> Text)
-> f (ByteString, Maybe Text) -> f Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> f (ByteString, Maybe Text)
forall (m :: * -> *).
PandocMonad m =>
Text -> m (ByteString, Maybe Text)
fetchItem (FilePath -> Text
T.pack FilePath
fp)

  let setFilesVariableM :: Text -> [FilePath] -> Context a -> m (Context a)
setFilesVariableM Text
k [FilePath]
fps Context a
ctx = do
        [Text]
xs <- (FilePath -> m Text) -> [FilePath] -> m [Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> m Text
forall (m :: * -> *). PandocMonad m => FilePath -> m Text
getTextContents [FilePath]
fps
        Text -> [Text] -> Context a -> m (Context a)
forall (m :: * -> *) a b.
(Monad m, ToContext a b, ToContext a [b]) =>
Text -> [b] -> Context a -> m (Context a)
setListVariableM Text
k [Text]
xs Context a
ctx

  FilePath
curdir <- IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO FilePath
getCurrentDirectory

  Context Text
variables <-
    Context Text -> m (Context Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Opt -> Context Text
optVariables Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> [Text] -> Context Text -> m (Context Text)
forall (m :: * -> *) a b.
(Monad m, ToContext a b, ToContext a [b]) =>
Text -> [b] -> Context a -> m (Context a)
setListVariableM Text
"sourcefile"
      ([Text] -> ([FilePath] -> [Text]) -> Maybe [FilePath] -> [Text]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Text
"-"] ((FilePath -> Text) -> [FilePath] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> Text
T.pack) (Opt -> Maybe [FilePath]
optInputFiles Opt
opts))
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> Text -> Context Text -> m (Context Text)
forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"outputfile" (FilePath -> Text
T.pack FilePath
outputFile)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> [FilePath] -> Context Text -> m (Context Text)
forall (m :: * -> *) a.
(PandocMonad m, ToContext a [Text], ToContext a Text) =>
Text -> [FilePath] -> Context a -> m (Context a)
setFilesVariableM Text
"include-before" (Opt -> [FilePath]
optIncludeBeforeBody Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> [FilePath] -> Context Text -> m (Context Text)
forall (m :: * -> *) a.
(PandocMonad m, ToContext a [Text], ToContext a Text) =>
Text -> [FilePath] -> Context a -> m (Context a)
setFilesVariableM Text
"include-after" (Opt -> [FilePath]
optIncludeAfterBody Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> [FilePath] -> Context Text -> m (Context Text)
forall (m :: * -> *) a.
(PandocMonad m, ToContext a [Text], ToContext a Text) =>
Text -> [FilePath] -> Context a -> m (Context a)
setFilesVariableM Text
"header-includes" (Opt -> [FilePath]
optIncludeInHeader Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> [Text] -> Context Text -> m (Context Text)
forall (m :: * -> *) a b.
(Monad m, ToContext a b, ToContext a [b]) =>
Text -> [b] -> Context a -> m (Context a)
setListVariableM Text
"css" ((FilePath -> Text) -> [FilePath] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Text
T.pack ([FilePath] -> [Text]) -> [FilePath] -> [Text]
forall a b. (a -> b) -> a -> b
$ Opt -> [FilePath]
optCss Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    (Context Text -> m (Context Text))
-> (Text -> Context Text -> m (Context Text))
-> Maybe Text
-> Context Text
-> m (Context Text)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Context Text -> m (Context Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Text -> Context Text -> m (Context Text)
forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"title-prefix") (Opt -> Maybe Text
optTitlePrefix Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    (Context Text -> m (Context Text))
-> (Text -> Context Text -> m (Context Text))
-> Maybe Text
-> Context Text
-> m (Context Text)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Context Text -> m (Context Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Text -> Context Text -> m (Context Text)
forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"epub-cover-image")
                 (FilePath -> Text
T.pack (FilePath -> Text) -> Maybe FilePath -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Opt -> Maybe FilePath
optEpubCoverImage Opt
opts)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    Text -> Text -> Context Text -> m (Context Text)
forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"curdir" (FilePath -> Text
T.pack FilePath
curdir)
    m (Context Text)
-> (Context Text -> m (Context Text)) -> m (Context Text)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    (\Context Text
vars ->  if Text
format Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"dzslides"
                  then do
                      Text
dztempl <- ByteString -> Text
UTF8.toText (ByteString -> Text) -> m ByteString -> m Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> m ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readDataFile
                                   (FilePath
"dzslides" FilePath -> FilePath -> FilePath
</> FilePath
"template.html")
                      let dzline :: Text
dzline = Text
"<!-- {{{{ dzslides core"
                      let dzcore :: Text
dzcore = [Text] -> Text
T.unlines
                                 ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
dzline Text -> Text -> Bool
`T.isPrefixOf`))
                                 ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines Text
dztempl
                      Text -> Text -> Context Text -> m (Context Text)
forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"dzslides-core" Text
dzcore Context Text
vars
                  else Context Text -> m (Context Text)
forall (m :: * -> *) a. Monad m => a -> m a
return Context Text
vars)

  Maybe (Template Text)
templ <- case Opt -> Maybe FilePath
optTemplate Opt
opts of
                  Maybe FilePath
_ | Bool -> Bool
not Bool
standalone -> Maybe (Template Text) -> m (Maybe (Template Text))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Template Text)
forall a. Maybe a
Nothing
                  Maybe FilePath
Nothing -> Template Text -> Maybe (Template Text)
forall a. a -> Maybe a
Just (Template Text -> Maybe (Template Text))
-> m (Template Text) -> m (Maybe (Template Text))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> m (Template Text)
forall (m :: * -> *). PandocMonad m => Text -> m (Template Text)
compileDefaultTemplate Text
format
                  Just FilePath
tp -> do
                    -- strip off extensions
                    let tp' :: FilePath
tp' = case FilePath -> FilePath
takeExtension FilePath
tp of
                                   FilePath
"" -> FilePath
tp FilePath -> FilePath -> FilePath
<.> Text -> FilePath
T.unpack Text
format
                                   FilePath
_  -> FilePath
tp
                    Either FilePath (Template Text)
res <- FilePath -> m Text
forall (m :: * -> *). PandocMonad m => FilePath -> m Text
getTemplate FilePath
tp' m Text
-> (Text -> m (Either FilePath (Template Text)))
-> m (Either FilePath (Template Text))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= WithPartials m (Either FilePath (Template Text))
-> m (Either FilePath (Template Text))
forall (m :: * -> *) a. WithPartials m a -> m a
runWithPartials (WithPartials m (Either FilePath (Template Text))
 -> m (Either FilePath (Template Text)))
-> (Text -> WithPartials m (Either FilePath (Template Text)))
-> Text
-> m (Either FilePath (Template Text))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath
-> Text -> WithPartials m (Either FilePath (Template Text))
forall (m :: * -> *) a.
(TemplateMonad m, TemplateTarget a) =>
FilePath -> Text -> m (Either FilePath (Template a))
compileTemplate FilePath
tp'
                    case Either FilePath (Template Text)
res of
                      Left  FilePath
e -> PandocError -> m (Maybe (Template Text))
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (PandocError -> m (Maybe (Template Text)))
-> PandocError -> m (Maybe (Template Text))
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocTemplateError (Text -> PandocError) -> Text -> PandocError
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack FilePath
e
                      Right Template Text
t -> Maybe (Template Text) -> m (Maybe (Template Text))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Template Text) -> m (Maybe (Template Text)))
-> Maybe (Template Text) -> m (Maybe (Template Text))
forall a b. (a -> b) -> a -> b
$ Template Text -> Maybe (Template Text)
forall a. a -> Maybe a
Just Template Text
t

  let writerOpts :: WriterOptions
writerOpts = WriterOptions
forall a. Default a => a
def {
          writerTemplate :: Maybe (Template Text)
writerTemplate         = Maybe (Template Text)
templ
        , writerVariables :: Context Text
writerVariables        = Context Text
variables
        , writerTabStop :: Int
writerTabStop          = Opt -> Int
optTabStop Opt
opts
        , writerTableOfContents :: Bool
writerTableOfContents  = Opt -> Bool
optTableOfContents Opt
opts
        , writerHTMLMathMethod :: HTMLMathMethod
writerHTMLMathMethod   = Opt -> HTMLMathMethod
optHTMLMathMethod Opt
opts
        , writerIncremental :: Bool
writerIncremental      = Opt -> Bool
optIncremental Opt
opts
        , writerCiteMethod :: CiteMethod
writerCiteMethod       = Opt -> CiteMethod
optCiteMethod Opt
opts
        , writerNumberSections :: Bool
writerNumberSections   = Opt -> Bool
optNumberSections Opt
opts
        , writerNumberOffset :: [Int]
writerNumberOffset     = Opt -> [Int]
optNumberOffset Opt
opts
        , writerSectionDivs :: Bool
writerSectionDivs      = Opt -> Bool
optSectionDivs Opt
opts
        , writerExtensions :: Extensions
writerExtensions       = Extensions
writerExts
        , writerReferenceLinks :: Bool
writerReferenceLinks   = Opt -> Bool
optReferenceLinks Opt
opts
        , writerReferenceLocation :: ReferenceLocation
writerReferenceLocation = Opt -> ReferenceLocation
optReferenceLocation Opt
opts
        , writerDpi :: Int
writerDpi              = Opt -> Int
optDpi Opt
opts
        , writerWrapText :: WrapOption
writerWrapText         = Opt -> WrapOption
optWrap Opt
opts
        , writerColumns :: Int
writerColumns          = Opt -> Int
optColumns Opt
opts
        , writerEmailObfuscation :: ObfuscationMethod
writerEmailObfuscation = Opt -> ObfuscationMethod
optEmailObfuscation Opt
opts
        , writerIdentifierPrefix :: Text
writerIdentifierPrefix = Opt -> Text
optIdentifierPrefix Opt
opts
        , writerHtmlQTags :: Bool
writerHtmlQTags        = Opt -> Bool
optHtmlQTags Opt
opts
        , writerTopLevelDivision :: TopLevelDivision
writerTopLevelDivision = Opt -> TopLevelDivision
optTopLevelDivision Opt
opts
        , writerListings :: Bool
writerListings         = Opt -> Bool
optListings Opt
opts
        , writerSlideLevel :: Maybe Int
writerSlideLevel       = Opt -> Maybe Int
optSlideLevel Opt
opts
        , writerHighlightStyle :: Maybe Style
writerHighlightStyle   = Maybe Style
hlStyle
        , writerSetextHeaders :: Bool
writerSetextHeaders    = Opt -> Bool
optSetextHeaders Opt
opts
        , writerEpubSubdirectory :: Text
writerEpubSubdirectory = FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ Opt -> FilePath
optEpubSubdirectory Opt
opts
        , writerEpubMetadata :: Maybe Text
writerEpubMetadata     = Maybe Text
epubMetadata
        , writerEpubFonts :: [FilePath]
writerEpubFonts        = Opt -> [FilePath]
optEpubFonts Opt
opts
        , writerEpubChapterLevel :: Int
writerEpubChapterLevel = Opt -> Int
optEpubChapterLevel Opt
opts
        , writerTOCDepth :: Int
writerTOCDepth         = Opt -> Int
optTOCDepth Opt
opts
        , writerReferenceDoc :: Maybe FilePath
writerReferenceDoc     = Opt -> Maybe FilePath
optReferenceDoc Opt
opts
        , writerSyntaxMap :: SyntaxMap
writerSyntaxMap        = SyntaxMap
syntaxMap
        , writerPreferAscii :: Bool
writerPreferAscii      = Opt -> Bool
optAscii Opt
opts
        }
  OutputSettings m -> m (OutputSettings m)
forall (m :: * -> *) a. Monad m => a -> m a
return (OutputSettings m -> m (OutputSettings m))
-> OutputSettings m -> m (OutputSettings m)
forall a b. (a -> b) -> a -> b
$ OutputSettings :: forall (m :: * -> *).
Text
-> Writer m
-> Text
-> WriterOptions
-> Maybe FilePath
-> OutputSettings m
OutputSettings
    { outputFormat :: Text
outputFormat = Text
format
    , outputWriter :: Writer m
outputWriter = Writer m
writer
    , outputWriterName :: Text
outputWriterName = Text
writerName
    , outputWriterOptions :: WriterOptions
outputWriterOptions = WriterOptions
writerOpts
    , outputPdfProgram :: Maybe FilePath
outputPdfProgram = Maybe FilePath
maybePdfProg
    }

baseWriterName :: T.Text -> T.Text
baseWriterName :: Text -> Text
baseWriterName = (Char -> Bool) -> Text -> Text
T.takeWhile (\Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'+' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'-')

pdfWriterAndProg :: Maybe T.Text              -- ^ user-specified writer name
                 -> Maybe String              -- ^ user-specified pdf-engine
                 -> IO (T.Text, Maybe String) -- ^ IO (writerName, maybePdfEngineProg)
pdfWriterAndProg :: Maybe Text -> Maybe FilePath -> IO (Text, Maybe FilePath)
pdfWriterAndProg Maybe Text
mWriter Maybe FilePath
mEngine =
  case Maybe Text -> Maybe FilePath -> Either Text (Text, FilePath)
go Maybe Text
mWriter Maybe FilePath
mEngine of
      Right (Text
writ, FilePath
prog) -> (Text, Maybe FilePath) -> IO (Text, Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
writ, FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
prog)
      Left Text
err           -> IO (Text, Maybe FilePath) -> IO (Text, Maybe FilePath)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Text, Maybe FilePath) -> IO (Text, Maybe FilePath))
-> IO (Text, Maybe FilePath) -> IO (Text, Maybe FilePath)
forall a b. (a -> b) -> a -> b
$ PandocError -> IO (Text, Maybe FilePath)
forall e a. Exception e => e -> IO a
E.throwIO (PandocError -> IO (Text, Maybe FilePath))
-> PandocError -> IO (Text, Maybe FilePath)
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocAppError Text
err
    where
      go :: Maybe Text -> Maybe FilePath -> Either Text (Text, FilePath)
go Maybe Text
Nothing Maybe FilePath
Nothing       = (Text, FilePath) -> Either Text (Text, FilePath)
forall a b. b -> Either a b
Right (Text
"latex", FilePath
"pdflatex")
      go (Just Text
writer) Maybe FilePath
Nothing = (Text
writer,) (FilePath -> (Text, FilePath))
-> Either Text FilePath -> Either Text (Text, FilePath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Either Text FilePath
engineForWriter Text
writer
      go Maybe Text
Nothing (Just FilePath
engine) = (,FilePath
engine) (Text -> (Text, FilePath))
-> Either Text Text -> Either Text (Text, FilePath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> Either Text Text
writerForEngine (FilePath -> FilePath
takeBaseName FilePath
engine)
      go (Just Text
writer) (Just FilePath
engine) =
           case ((Text, FilePath) -> Bool)
-> [(Text, FilePath)] -> Maybe (Text, FilePath)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((Text, FilePath) -> (Text, FilePath) -> Bool
forall a. Eq a => a -> a -> Bool
== (Text -> Text
baseWriterName Text
writer, FilePath -> FilePath
takeBaseName FilePath
engine)) [(Text, FilePath)]
engines of
                Just (Text, FilePath)
_  -> (Text, FilePath) -> Either Text (Text, FilePath)
forall a b. b -> Either a b
Right (Text
writer, FilePath
engine)
                Maybe (Text, FilePath)
Nothing -> Text -> Either Text (Text, FilePath)
forall a b. a -> Either a b
Left (Text -> Either Text (Text, FilePath))
-> Text -> Either Text (Text, FilePath)
forall a b. (a -> b) -> a -> b
$ Text
"pdf-engine " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
T.pack FilePath
engine Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
                           Text
" is not compatible with output format " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
writer

      writerForEngine :: FilePath -> Either Text Text
writerForEngine FilePath
eng = case [Text
f | (Text
f,FilePath
e) <- [(Text, FilePath)]
engines, FilePath
e FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
eng] of
                                 Text
fmt : [Text]
_ -> Text -> Either Text Text
forall a b. b -> Either a b
Right Text
fmt
                                 []      -> Text -> Either Text Text
forall a b. a -> Either a b
Left (Text -> Either Text Text) -> Text -> Either Text Text
forall a b. (a -> b) -> a -> b
$
                                   Text
"pdf-engine " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
T.pack FilePath
eng Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" not known"

      engineForWriter :: Text -> Either Text FilePath
engineForWriter Text
"pdf" = Text -> Either Text FilePath
forall a b. a -> Either a b
Left Text
"pdf writer"
      engineForWriter Text
w = case [FilePath
e |  (Text
f,FilePath
e) <- [(Text, FilePath)]
engines, Text
f Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Text
baseWriterName Text
w] of
                                FilePath
eng : [FilePath]
_ -> FilePath -> Either Text FilePath
forall a b. b -> Either a b
Right FilePath
eng
                                []      -> Text -> Either Text FilePath
forall a b. a -> Either a b
Left (Text -> Either Text FilePath) -> Text -> Either Text FilePath
forall a b. (a -> b) -> a -> b
$
                                   Text
"cannot produce pdf output from " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
w

isTextFormat :: T.Text -> Bool
isTextFormat :: Text -> Bool
isTextFormat Text
s =
  Text
s Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Text
"odt",Text
"docx",Text
"epub2",Text
"epub3",Text
"epub",Text
"pptx",Text
"pdf"]