{-# LANGUAGE CPP                 #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE LambdaCase          #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections       #-}
{- |
   Module      : Text.Pandoc.App
   Copyright   : Copyright (C) 2006-2023 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.Chunks (PathTemplate(..))
import Text.Pandoc
import Text.Pandoc.App.Opt (Opt (..))
import Text.Pandoc.App.CommandLineOptions (engines)
import Text.Pandoc.Format (FlavoredFormat (..), applyExtensionsDiff,
                           parseFlavoredFormat, formatFromFilePaths)
import Text.Pandoc.Highlighting (lookupHighlightingStyle)
import Text.Pandoc.Scripting (ScriptingEngine (engineLoadCustom),
                              CustomComponents(..))
import qualified Text.Pandoc.UTF8 as UTF8

readUtf8File :: PandocMonad m => FilePath -> m T.Text
readUtf8File :: forall (m :: * -> *). PandocMonad m => FilePath -> m Text
readUtf8File FilePath
fp = forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readFileStrict FilePath
fp forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *).
PandocMonad m =>
FilePath -> ByteString -> m Text
toTextM FilePath
fp

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

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

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

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

  let pdfOutput :: Bool
pdfOutput = forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (FilePath -> FilePath
takeExtension FilePath
outputFile) forall a. Eq a => a -> a -> Bool
== FilePath
".pdf" Bool -> Bool -> Bool
||
                  Opt -> Maybe Text
optTo Opt
opts forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just Text
"pdf"
  let defaultOutput :: Text
defaultOutput = Text
"html"
  FlavoredFormat
defaultOutputFlavor <- forall (m :: * -> *). PandocMonad m => Text -> m FlavoredFormat
parseFlavoredFormat Text
defaultOutput
  (flvrd :: FlavoredFormat
flvrd@(FlavoredFormat Text
format ExtensionsDiff
_extsDiff), Maybe FilePath
maybePdfProg) <-
    if Bool
pdfOutput
       then do
         Maybe FlavoredFormat
outflavor <- case Opt -> Maybe Text
optTo Opt
opts of
                        Just Text
x | Text
x forall a. Eq a => a -> a -> Bool
/= Text
"pdf" -> forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). PandocMonad m => Text -> m FlavoredFormat
parseFlavoredFormat Text
x
                        Maybe Text
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Maybe a
Nothing
         forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Maybe FlavoredFormat
-> Maybe FilePath -> IO (FlavoredFormat, Maybe FilePath)
pdfWriterAndProg Maybe FlavoredFormat
outflavor (Opt -> Maybe FilePath
optPdfEngine Opt
opts)
       else case Opt -> Maybe Text
optTo Opt
opts of
              Just Text
f -> (, forall a. Maybe a
Nothing) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). PandocMonad m => Text -> m FlavoredFormat
parseFlavoredFormat Text
f
              Maybe Text
Nothing
               | FilePath
outputFile forall a. Eq a => a -> a -> Bool
== FilePath
"-" ->
                   forall (m :: * -> *) a. Monad m => a -> m a
return (FlavoredFormat
defaultOutputFlavor, forall a. Maybe a
Nothing)
               | Bool
otherwise -> case [FilePath] -> Maybe FlavoredFormat
formatFromFilePaths [FilePath
outputFile] of
                   Maybe FlavoredFormat
Nothing -> do
                     forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report forall a b. (a -> b) -> a -> b
$ [Text] -> Text -> LogMessage
CouldNotDeduceFormat
                       [FilePath -> Text
T.pack forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
takeExtension FilePath
outputFile] Text
defaultOutput
                     forall (m :: * -> *) a. Monad m => a -> m a
return (FlavoredFormat
defaultOutputFlavor,forall a. Maybe a
Nothing)
                   Just FlavoredFormat
f  -> forall (m :: * -> *) a. Monad m => a -> m a
return (FlavoredFormat
f, forall a. Maybe a
Nothing)

  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text
format forall a. Eq a => a -> a -> Bool
== Text
"asciidoctor") forall a b. (a -> b) -> a -> b
$ do
    forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report forall a b. (a -> b) -> a -> b
$ Text -> Text -> LogMessage
Deprecated Text
"asciidoctor" Text
"use asciidoc instead"

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

  let standalone :: Bool
standalone = Opt -> Bool
optStandalone Opt
opts Bool -> Bool -> Bool
|| Text -> Bool
isBinaryFormat Text
format Bool -> Bool -> Bool
|| Bool
pdfOutput
  let templateOrThrow :: Either FilePath a -> m a
templateOrThrow = \case
        Left  FilePath
e -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocTemplateError (FilePath -> Text
T.pack FilePath
e)
        Right a
t -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
t
  let processCustomTemplate :: m (Template a) -> m (Maybe (Template a))
processCustomTemplate m (Template a)
getDefault =
        case Opt -> Maybe FilePath
optTemplate Opt
opts of
          Maybe FilePath
_ | Bool -> Bool
not Bool
standalone -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
          Maybe FilePath
Nothing -> forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Template a)
getDefault
          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
            forall (m :: * -> *). PandocMonad m => FilePath -> m Text
getTemplate FilePath
tp'
              forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a. WithPartials m a -> m a
runWithPartials forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(TemplateMonad m, TemplateTarget a) =>
FilePath -> Text -> m (Either FilePath (Template a))
compileTemplate FilePath
tp'
              forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}. Either FilePath a -> m a
templateOrThrow

  (Writer m
writer, Extensions
writerExts, Maybe (Template Text)
mtemplate) <-
    if Text
"lua" Text -> Text -> Bool
`T.isSuffixOf` Text
format
    then do
      let path :: FilePath
path = Text -> FilePath
T.unpack Text
format
      CustomComponents m
components <- ScriptingEngine
-> forall (m :: * -> *).
   (PandocMonad m, MonadIO m) =>
   FilePath -> m (CustomComponents m)
engineLoadCustom ScriptingEngine
scriptingEngine FilePath
path
      Writer m
w <- case forall (m :: * -> *). CustomComponents m -> Maybe (Writer m)
customWriter CustomComponents m
components of
             Maybe (Writer m)
Nothing -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocAppError forall a b. (a -> b) -> a -> b
$
                         Text
format forall a. Semigroup a => a -> a -> a
<> Text
" does not contain a custom writer"
             Just Writer m
w -> forall (m :: * -> *) a. Monad m => a -> m a
return Writer m
w
      let extsConf :: ExtensionsConfig
extsConf = forall a. a -> Maybe a -> a
fromMaybe forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CustomComponents m -> Maybe ExtensionsConfig
customExtensions CustomComponents m
components
      Extensions
wexts <- forall (m :: * -> *).
PandocMonad m =>
ExtensionsConfig -> FlavoredFormat -> m Extensions
applyExtensionsDiff ExtensionsConfig
extsConf FlavoredFormat
flvrd
      Maybe (Template Text)
templ <- forall {a}.
(HasChars a, ToText a, FromText a) =>
m (Template a) -> m (Maybe (Template a))
processCustomTemplate forall a b. (a -> b) -> a -> b
$
               case forall (m :: * -> *). CustomComponents m -> Maybe Text
customTemplate CustomComponents m
components of
                 Maybe Text
Nothing -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocNoTemplateError Text
format
                 Just Text
t -> (forall (m :: * -> *) a. WithDefaultPartials m a -> m a
runWithDefaultPartials forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(TemplateMonad m, TemplateTarget a) =>
FilePath -> Text -> m (Either FilePath (Template a))
compileTemplate FilePath
path Text
t) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
                           forall {a}. Either FilePath a -> m a
templateOrThrow
      forall (m :: * -> *) a. Monad m => a -> m a
return (Writer m
w, Extensions
wexts, Maybe (Template Text)
templ)
    else
      if Opt -> Bool
optSandbox Opt
opts
      then do
        Maybe (Template Text)
tmpl <- forall {a}.
(HasChars a, ToText a, FromText a) =>
m (Template a) -> m (Maybe (Template a))
processCustomTemplate (forall (m :: * -> *). PandocMonad m => Text -> m (Template Text)
compileDefaultTemplate Text
format)
        case forall a. PandocPure a -> Either PandocError a
runPure (forall (m :: * -> *).
PandocMonad m =>
FlavoredFormat -> m (Writer m, Extensions)
getWriter FlavoredFormat
flvrd) of
             Right (Writer PandocPure
w, Extensions
wexts) -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall {m :: * -> *}.
(PandocMonad m, MonadIO m) =>
Writer PandocPure -> Writer m
makeSandboxed Writer PandocPure
w, Extensions
wexts, Maybe (Template Text)
tmpl)
             Left PandocError
e           -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError PandocError
e
      else do
        (Writer m
w, Extensions
wexts) <- forall (m :: * -> *).
PandocMonad m =>
FlavoredFormat -> m (Writer m, Extensions)
getWriter FlavoredFormat
flvrd
        Maybe (Template Text)
tmpl <- forall {a}.
(HasChars a, ToText a, FromText a) =>
m (Template a) -> m (Maybe (Template a))
processCustomTemplate (forall (m :: * -> *). PandocMonad m => Text -> m (Template Text)
compileDefaultTemplate Text
format)
        forall (m :: * -> *) a. Monad m => a -> m a
return (Writer m
w, Extensions
wexts, Maybe (Template Text)
tmpl)


  let addSyntaxMap :: SyntaxMap -> FilePath -> m SyntaxMap
addSyntaxMap SyntaxMap
existingmap FilePath
f = do
        Either FilePath Syntax
res <- 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 -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocSyntaxMapError forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack FilePath
errstr
              Right Syntax
syn   -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Syntax -> SyntaxMap -> SyntaxMap
addSyntaxDefinition Syntax
syn SyntaxMap
existingmap

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

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

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

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

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

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

  Context Text
variables <-
    forall (m :: * -> *) a. Monad m => a -> m a
return (Opt -> Context Text
optVariables Opt
opts)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall {m :: * -> *} {a} {a}.
(Monad m, ToContext a a, ToContext a [a]) =>
Text -> [a] -> Context a -> m (Context a)
setListVariableM Text
"sourcefile"
      (forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Text
"-"] (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> Text
T.pack) (Opt -> Maybe [FilePath]
optInputFiles Opt
opts))
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"outputfile" (FilePath -> Text
T.pack FilePath
outputFile)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"pandoc-version" Text
pandocVersionText
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    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)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    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)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    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)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall {m :: * -> *} {a} {a}.
(Monad m, ToContext a a, ToContext a [a]) =>
Text -> [a] -> Context a -> m (Context a)
setListVariableM Text
"css" (forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Text
T.pack forall a b. (a -> b) -> a -> b
$ Opt -> [FilePath]
optCss Opt
opts)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall (m :: * -> *) a. Monad m => a -> m a
return (forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"title-prefix") (Opt -> Maybe Text
optTitlePrefix Opt
opts)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall (m :: * -> *) a. Monad m => a -> m a
return (forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"epub-cover-image" forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack)
                 (Opt -> Maybe FilePath
optEpubCoverImage Opt
opts)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"curdir" (FilePath -> Text
T.pack FilePath
curdir)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    (\Context Text
vars ->  if Text
format forall a. Eq a => a -> a -> Bool
== Text
"dzslides"
                  then do
                      Text
dztempl <-
                        let fp :: FilePath
fp = FilePath
"dzslides" FilePath -> FilePath -> FilePath
</> FilePath
"template.html"
                         in forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readDataFile FilePath
fp forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *).
PandocMonad m =>
FilePath -> ByteString -> m Text
toTextM FilePath
fp
                      let dzline :: Text
dzline = Text
"<!-- {{{{ dzslides core"
                      let dzcore :: Text
dzcore = [Text] -> Text
T.unlines
                                 forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
dzline Text -> Text -> Bool
`T.isPrefixOf`))
                                 forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines Text
dztempl
                      forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
"dzslides-core" Text
dzcore Context Text
vars
                  else forall (m :: * -> *) a. Monad m => a -> m a
return Context Text
vars)

  let writerOpts :: WriterOptions
writerOpts = forall a. Default a => a
def {
          writerTemplate :: Maybe (Template Text)
writerTemplate         = Maybe (Template Text)
mtemplate
        , 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
        , writerListTables :: Bool
writerListTables       = Opt -> Bool
optListTables Opt
opts
        , writerEpubSubdirectory :: Text
writerEpubSubdirectory = FilePath -> Text
T.pack 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
        , writerEpubTitlePage :: Bool
writerEpubTitlePage    = Opt -> Bool
optEpubTitlePage Opt
opts
        , writerSplitLevel :: Int
writerSplitLevel       = Opt -> Int
optSplitLevel Opt
opts
        , writerChunkTemplate :: PathTemplate
writerChunkTemplate    = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Text -> PathTemplate
PathTemplate Text
"%s-%i.html")
                                     Text -> PathTemplate
PathTemplate
                                     (Opt -> Maybe Text
optChunkTemplate 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
        }
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ OutputSettings
    { outputFormat :: Text
outputFormat = Text
format
    , outputWriter :: Writer m
outputWriter = Writer m
writer
    , outputWriterOptions :: WriterOptions
outputWriterOptions = WriterOptions
writerOpts
    , outputPdfProgram :: Maybe FilePath
outputPdfProgram = Maybe FilePath
maybePdfProg
    }

-- | Set text value in text context unless it is already set.
setVariableM :: Monad m
             => T.Text -> T.Text -> Context T.Text -> m (Context T.Text)
setVariableM :: forall (m :: * -> *).
Monad m =>
Text -> Text -> Context Text -> m (Context Text)
setVariableM Text
key Text
val (Context Map Text (Val Text)
ctx) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Map Text (Val a) -> Context a
Context forall a b. (a -> b) -> a -> b
$ forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
M.alter forall {a}. ToContext a Text => Maybe (Val a) -> Maybe (Val a)
go Text
key Map Text (Val Text)
ctx
  where go :: Maybe (Val a) -> Maybe (Val a)
go Maybe (Val a)
Nothing             = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. ToContext a b => b -> Val a
toVal Text
val
        go (Just Val a
x)            = forall a. a -> Maybe a
Just Val a
x

pdfWriterAndProg :: Maybe FlavoredFormat      -- ^ user-specified format
                 -> Maybe String              -- ^ user-specified pdf-engine
                 -> IO (FlavoredFormat, Maybe String) -- ^ format, pdf-engine
pdfWriterAndProg :: Maybe FlavoredFormat
-> Maybe FilePath -> IO (FlavoredFormat, Maybe FilePath)
pdfWriterAndProg Maybe FlavoredFormat
mWriter Maybe FilePath
mEngine =
  case Maybe FlavoredFormat
-> Maybe FilePath -> Either Text (FlavoredFormat, FilePath)
go Maybe FlavoredFormat
mWriter Maybe FilePath
mEngine of
      Right (FlavoredFormat
writ, FilePath
prog) -> forall (m :: * -> *) a. Monad m => a -> m a
return (FlavoredFormat
writ, forall a. a -> Maybe a
Just FilePath
prog)
      Left Text
err           -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall e a. Exception e => e -> IO a
E.throwIO forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocAppError Text
err
    where
      go :: Maybe FlavoredFormat
-> Maybe FilePath -> Either Text (FlavoredFormat, FilePath)
go Maybe FlavoredFormat
Nothing Maybe FilePath
Nothing       = forall a b. b -> Either a b
Right
                                 (Text -> ExtensionsDiff -> FlavoredFormat
FlavoredFormat Text
"latex" forall a. Monoid a => a
mempty, FilePath
"pdflatex")
      go (Just FlavoredFormat
writer) Maybe FilePath
Nothing = (FlavoredFormat
writer,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FlavoredFormat -> Either Text FilePath
engineForWriter FlavoredFormat
writer
      go Maybe FlavoredFormat
Nothing (Just FilePath
engine) = (,FilePath
engine) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> Either Text FlavoredFormat
writerForEngine (FilePath -> FilePath
takeBaseName FilePath
engine)
      go (Just FlavoredFormat
writer) (Just FilePath
engine) | FlavoredFormat -> Bool
isCustomWriter FlavoredFormat
writer =
           -- custom writers can produce any format, so assume the user knows
           -- what they are doing.
           forall a b. b -> Either a b
Right (FlavoredFormat
writer, FilePath
engine)
      go (Just FlavoredFormat
writer) (Just FilePath
engine) =
           case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (forall a. Eq a => a -> a -> Bool
== (FlavoredFormat -> Text
formatName FlavoredFormat
writer, FilePath -> FilePath
takeBaseName FilePath
engine)) [(Text, FilePath)]
engines of
                Just (Text, FilePath)
_  -> forall a b. b -> Either a b
Right (FlavoredFormat
writer, FilePath
engine)
                Maybe (Text, FilePath)
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Text
"pdf-engine " forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
T.pack FilePath
engine forall a. Semigroup a => a -> a -> a
<>
                           Text
" is not compatible with output format " forall a. Semigroup a => a -> a -> a
<>
                           FlavoredFormat -> Text
formatName FlavoredFormat
writer

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

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

      isCustomWriter :: FlavoredFormat -> Bool
isCustomWriter FlavoredFormat
w = Text
".lua" Text -> Text -> Bool
`T.isSuffixOf` FlavoredFormat -> Text
formatName FlavoredFormat
w

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