{-# LANGUAGE NoImplicitPrelude   #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE CPP                 #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
   Module      : Text.Pandoc.App
   Copyright   : Copyright (C) 2006-2019 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 (
            convertWithOpts
          , Opt(..)
          , LineEnding(..)
          , Filter(..)
          , defaultOpts
          , parseOptions
          , options
          , applyFilters
          ) where
import Prelude
import qualified Control.Exception as E
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Except (throwError)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.Char (toLower)
import Data.Maybe (fromMaybe, isJust, isNothing)
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TE
import qualified Data.Text.Encoding.Error as TE
import qualified Data.Text.Encoding.Error as TSE
import Network.URI (URI (..), parseURI)
import System.Directory (doesDirectoryExist)
import System.Exit (exitSuccess)
import System.FilePath
import System.IO (nativeNewline, stdout)
import qualified System.IO as IO (Newline (..))
import Text.Pandoc
import Text.Pandoc.App.FormatHeuristics (formatFromFilePaths)
import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts,
                            IpynbOutput (..) )
import Text.Pandoc.App.CommandLineOptions (parseOptions, options)
import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings)
import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
import Text.Pandoc.Builder (setMeta)
import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters)
import Text.Pandoc.PDF (makePDF)
import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
         headerShift, isURI, tabFilter, uriPathToPath, filterIpynbOutput,
         defaultUserDataDirs, tshow)
import Text.Pandoc.Writers.Shared (lookupMetaString)
import Text.Pandoc.Readers.Markdown (yamlToMeta)
import qualified Text.Pandoc.UTF8 as UTF8
#ifndef _WINDOWS
import System.Posix.IO (stdOutput)
import System.Posix.Terminal (queryTerminal)
#endif

convertWithOpts :: Opt -> IO ()
convertWithOpts :: Opt -> IO ()
convertWithOpts opts :: Opt
opts = do
  let outputFile :: FilePath
outputFile = FilePath -> Maybe FilePath -> FilePath
forall a. a -> Maybe a -> a
fromMaybe "-" (Opt -> Maybe FilePath
optOutputFile Opt
opts)
  let filters :: [Filter]
filters = Opt -> [Filter]
optFilters Opt
opts
  let verbosity :: Verbosity
verbosity = Opt -> Verbosity
optVerbosity Opt
opts

  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Opt -> Bool
optDumpArgs Opt
opts) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    do Handle -> FilePath -> IO ()
UTF8.hPutStrLn Handle
stdout FilePath
outputFile
       (FilePath -> IO ()) -> [FilePath] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Handle -> FilePath -> IO ()
UTF8.hPutStrLn Handle
stdout) ([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

  let isPandocCiteproc :: Filter -> Bool
isPandocCiteproc (JSONFilter f :: FilePath
f) = FilePath -> FilePath
takeBaseName FilePath
f FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== "pandoc-citeproc"
      isPandocCiteproc _              = Bool
False
  -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
  let needsCiteproc :: Bool
needsCiteproc = Maybe MetaValue -> Bool
forall a. Maybe a -> Bool
isJust (Text -> Meta -> Maybe MetaValue
lookupMeta "bibliography"
                                (Opt -> Meta
optMetadata Opt
opts)) Bool -> Bool -> Bool
&&
                      Opt -> CiteMethod
optCiteMethod Opt
opts CiteMethod -> [CiteMethod] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [CiteMethod
Natbib, CiteMethod
Biblatex] Bool -> Bool -> Bool
&&
                      (Filter -> Bool) -> [Filter] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
not (Bool -> Bool) -> (Filter -> Bool) -> Filter -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Filter -> Bool
isPandocCiteproc) [Filter]
filters
  let filters' :: [Filter]
filters' = [Filter]
filters [Filter] -> [Filter] -> [Filter]
forall a. [a] -> [a] -> [a]
++ [ FilePath -> Filter
JSONFilter "pandoc-citeproc" | Bool
needsCiteproc ]

  let sources :: [FilePath]
sources = case Opt -> Maybe [FilePath]
optInputFiles Opt
opts of
                     Nothing -> ["-"]
                     Just xs :: [FilePath]
xs | Opt -> Bool
optIgnoreArgs Opt
opts -> ["-"]
                             | Bool
otherwise  -> [FilePath]
xs

  Maybe FilePath
datadir <- case Opt -> Maybe FilePath
optDataDir Opt
opts of
                  Nothing   -> do
                    [FilePath]
ds <- IO [FilePath]
defaultUserDataDirs
                    let selectUserDataDir :: [FilePath] -> IO (Maybe FilePath)
selectUserDataDir [] = Maybe FilePath -> IO (Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FilePath
forall a. Maybe a
Nothing
                        selectUserDataDir (dir :: FilePath
dir:dirs :: [FilePath]
dirs) = do
                              Bool
exists <- FilePath -> IO Bool
doesDirectoryExist FilePath
dir
                              if Bool
exists
                                 then Maybe FilePath -> IO (Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
dir)
                                 else [FilePath] -> IO (Maybe FilePath)
selectUserDataDir [FilePath]
dirs
                    [FilePath] -> IO (Maybe FilePath)
selectUserDataDir [FilePath]
ds
                  Just _    -> Maybe FilePath -> IO (Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath -> IO (Maybe FilePath))
-> Maybe FilePath -> IO (Maybe FilePath)
forall a b. (a -> b) -> a -> b
$ Opt -> Maybe FilePath
optDataDir Opt
opts

  let runIO' :: PandocIO a -> IO a
      runIO' :: PandocIO a -> IO a
runIO' f :: PandocIO a
f = do
        (res :: a
res, reports :: [LogMessage]
reports) <- PandocIO (a, [LogMessage]) -> IO (a, [LogMessage])
forall a. PandocIO a -> IO a
runIOorExplode (PandocIO (a, [LogMessage]) -> IO (a, [LogMessage]))
-> PandocIO (a, [LogMessage]) -> IO (a, [LogMessage])
forall a b. (a -> b) -> a -> b
$ do
                             Bool -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Bool -> m ()
setTrace (Opt -> Bool
optTrace Opt
opts)
                             Verbosity -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Verbosity -> m ()
setVerbosity Verbosity
verbosity
                             a
x <- PandocIO a
f
                             [LogMessage]
rs <- PandocIO [LogMessage]
forall (m :: * -> *). PandocMonad m => m [LogMessage]
getLog
                             (a, [LogMessage]) -> PandocIO (a, [LogMessage])
forall (m :: * -> *) a. Monad m => a -> m a
return (a
x, [LogMessage]
rs)
        case Opt -> Maybe FilePath
optLogFile Opt
opts of
             Nothing      -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
             Just logfile :: FilePath
logfile -> FilePath -> ByteString -> IO ()
BL.writeFile FilePath
logfile ([LogMessage] -> ByteString
encodeLogMessages [LogMessage]
reports)
        let isWarning :: LogMessage -> Bool
isWarning msg :: LogMessage
msg = LogMessage -> Verbosity
messageVerbosity LogMessage
msg Verbosity -> Verbosity -> Bool
forall a. Eq a => a -> a -> Bool
== Verbosity
WARNING
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Opt -> Bool
optFailIfWarnings Opt
opts Bool -> Bool -> Bool
&& (LogMessage -> Bool) -> [LogMessage] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any LogMessage -> Bool
isWarning [LogMessage]
reports) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
            PandocError -> IO ()
forall e a. Exception e => e -> IO a
E.throwIO PandocError
PandocFailOnWarningError
        a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
res

  let eol :: Newline
eol = case Opt -> LineEnding
optEol Opt
opts of
                 CRLF   -> Newline
IO.CRLF
                 LF     -> Newline
IO.LF
                 Native -> Newline
nativeNewline
#ifdef _WINDOWS
  let istty = True
#else
  Bool
istty <- IO Bool -> IO Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ Fd -> IO Bool
queryTerminal Fd
stdOutput
#endif

  PandocIO () -> IO ()
forall a. PandocIO a -> IO a
runIO' (PandocIO () -> IO ()) -> PandocIO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Maybe FilePath -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Maybe FilePath -> m ()
setUserDataDir Maybe FilePath
datadir
    [FilePath] -> PandocIO ()
forall (m :: * -> *). PandocMonad m => [FilePath] -> m ()
setInputFiles ([FilePath] -> Maybe [FilePath] -> [FilePath]
forall a. a -> Maybe a -> a
fromMaybe ["-"] (Opt -> Maybe [FilePath]
optInputFiles Opt
opts))
    Maybe FilePath -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Maybe FilePath -> m ()
setOutputFile (Opt -> Maybe FilePath
optOutputFile Opt
opts)

    -- assign reader and writer based on options and filenames
    Text
readerName <- case Opt -> Maybe Text
optFrom Opt
opts of
                       Just f :: Text
f  -> Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
f
                       Nothing -> case [FilePath] -> Maybe Text
formatFromFilePaths [FilePath]
sources of
                           Just f' :: Text
f' -> Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
f'
                           Nothing | [FilePath]
sources [FilePath] -> [FilePath] -> Bool
forall a. Eq a => a -> a -> Bool
== ["-"] -> Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return "markdown"
                                   | (FilePath -> Bool) -> [FilePath] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Text -> Bool
isURI (Text -> Bool) -> (FilePath -> Text) -> FilePath -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack) [FilePath]
sources -> Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return "html"
                                   | Bool
otherwise -> do
                             LogMessage -> PandocIO ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> PandocIO ()) -> LogMessage -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ [Text] -> Text -> LogMessage
CouldNotDeduceFormat
                                 ((FilePath -> Text) -> [FilePath] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> Text
T.pack (FilePath -> Text) -> (FilePath -> FilePath) -> FilePath -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
takeExtension) [FilePath]
sources) "markdown"
                             Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return "markdown"

    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
== ".pdf"

    Bool -> PandocIO () -> PandocIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
pdfOutput Bool -> Bool -> Bool
&& Text
readerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "latex") (PandocIO () -> PandocIO ()) -> PandocIO () -> PandocIO ()
forall a b. (a -> b) -> a -> b
$
      case (Opt -> Maybe [FilePath]
optInputFiles Opt
opts) of
        Just (inputFile :: FilePath
inputFile:_) -> LogMessage -> PandocIO ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> PandocIO ()) -> LogMessage -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> LogMessage
UnusualConversion (Text -> LogMessage) -> Text -> LogMessage
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$
          "to convert a .tex file to PDF, you get better results by using pdflatex "
            FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> "(or lualatex or xelatex) directly, try `pdflatex " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
inputFile
            FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> "` instead of `pandoc " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
inputFile FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> " -o " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
outputFile FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> "`."
        _ -> () -> PandocIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    (Reader PandocIO
reader :: Reader PandocIO, readerExts :: Extensions
readerExts) <- Text -> PandocIO (Reader PandocIO, Extensions)
forall (m :: * -> *).
PandocMonad m =>
Text -> m (Reader m, Extensions)
getReader Text
readerName

    let convertTabs :: Text -> Text
convertTabs = Int -> Text -> Text
tabFilter (if Opt -> Bool
optPreserveTabs Opt
opts Bool -> Bool -> Bool
||
                                      Text
readerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "t2t" Bool -> Bool -> Bool
||
                                      Text
readerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "man"
                                    then 0
                                    else Opt -> Int
optTabStop Opt
opts)


    let readSources :: [FilePath] -> PandocIO Text
        readSources :: [FilePath] -> PandocIO Text
readSources srcs :: [FilePath]
srcs = Text -> Text
convertTabs (Text -> Text) -> ([Text] -> Text) -> [Text] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text] -> Text
T.intercalate (FilePath -> Text
T.pack "\n") ([Text] -> Text) -> PandocIO [Text] -> PandocIO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
                              (FilePath -> PandocIO Text) -> [FilePath] -> PandocIO [Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> PandocIO Text
readSource [FilePath]
srcs


    OutputSettings
outputSettings <- Opt -> PandocIO OutputSettings
optToOutputSettings Opt
opts
    let format :: Text
format = OutputSettings -> Text
outputFormat OutputSettings
outputSettings
    let writer :: Writer PandocIO
writer = OutputSettings -> Writer PandocIO
outputWriter OutputSettings
outputSettings
    let writerName :: Text
writerName = OutputSettings -> Text
outputWriterName OutputSettings
outputSettings
    let writerOptions :: WriterOptions
writerOptions = OutputSettings -> WriterOptions
outputWriterOptions OutputSettings
outputSettings

    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

    -- We don't want to send output to the terminal if the user
    -- does 'pandoc -t docx input.txt'; though we allow them to
    -- force this with '-o -'.  On posix systems, we detect
    -- when stdout is being piped and allow output to stdout
    -- in that case, but on Windows we can't.
    Bool -> PandocIO () -> PandocIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ((Bool
pdfOutput Bool -> Bool -> Bool
|| Bool -> Bool
not (Text -> Bool
isTextFormat Text
format)) Bool -> Bool -> Bool
&&
             Bool
istty Bool -> Bool -> Bool
&& Maybe FilePath -> Bool
forall a. Maybe a -> Bool
isNothing ( Opt -> Maybe FilePath
optOutputFile Opt
opts)) (PandocIO () -> PandocIO ()) -> PandocIO () -> PandocIO ()
forall a b. (a -> b) -> a -> b
$
      PandocError -> PandocIO ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (PandocError -> PandocIO ()) -> PandocError -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocAppError (Text -> PandocError) -> Text -> PandocError
forall a b. (a -> b) -> a -> b
$
              "Cannot write " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
format Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " output to terminal.\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
              "Specify an output file using the -o option, or " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
              "use '-o -' to force output to stdout."


    Set Text
abbrevs <- [Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text) -> (Text -> [Text]) -> Text -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null) ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines (Text -> Set Text) -> PandocIO Text -> PandocIO (Set Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
               case Opt -> Maybe FilePath
optAbbreviations Opt
opts of
                    Nothing -> ByteString -> Text
UTF8.toText (ByteString -> Text) -> PandocIO ByteString -> PandocIO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> PandocIO ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readDataFile "abbreviations"
                    Just f :: FilePath
f  -> ByteString -> Text
UTF8.toText (ByteString -> Text) -> PandocIO ByteString -> PandocIO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> PandocIO ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readFileStrict FilePath
f

    Meta
metadata <- if Text
format Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "jats" Bool -> Bool -> Bool
&&
                   Maybe MetaValue -> Bool
forall a. Maybe a -> Bool
isNothing (Text -> Meta -> Maybe MetaValue
lookupMeta "csl" (Opt -> Meta
optMetadata Opt
opts)) Bool -> Bool -> Bool
&&
                   Maybe MetaValue -> Bool
forall a. Maybe a -> Bool
isNothing (Text -> Meta -> Maybe MetaValue
lookupMeta "citation-style"
                                               (Opt -> Meta
optMetadata Opt
opts))
                   then do
                     ByteString
jatsCSL <- FilePath -> PandocIO ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readDataFile "jats.csl"
                     let jatsEncoded :: Text
jatsEncoded = (Text, ByteString) -> Text
makeDataURI
                                         ("application/xml", ByteString
jatsCSL)
                     Meta -> PandocIO Meta
forall (m :: * -> *) a. Monad m => a -> m a
return (Meta -> PandocIO Meta) -> Meta -> PandocIO Meta
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Meta -> Meta
forall a b. (HasMeta a, ToMetaValue b) => Text -> b -> a -> a
setMeta "csl" Text
jatsEncoded (Meta -> Meta) -> Meta -> Meta
forall a b. (a -> b) -> a -> b
$ Opt -> Meta
optMetadata Opt
opts
                   else Meta -> PandocIO Meta
forall (m :: * -> *) a. Monad m => a -> m a
return (Meta -> PandocIO Meta) -> Meta -> PandocIO Meta
forall a b. (a -> b) -> a -> b
$ Opt -> Meta
optMetadata Opt
opts

    case Text -> Meta -> Text
lookupMetaString "lang" (Opt -> Meta
optMetadata Opt
opts) of
           ""      -> Lang -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Lang -> m ()
setTranslations (Lang -> PandocIO ()) -> Lang -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Text -> [Text] -> Lang
Lang "en" "" "US" []
           l :: Text
l       -> case Text -> Either Text Lang
parseBCP47 Text
l of
                           Left _   -> LogMessage -> PandocIO ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> PandocIO ()) -> LogMessage -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> LogMessage
InvalidLang Text
l
                           Right l' :: Lang
l' -> Lang -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Lang -> m ()
setTranslations Lang
l'

    let readerOpts :: ReaderOptions
readerOpts = ReaderOptions
forall a. Default a => a
def{
            readerStandalone :: Bool
readerStandalone = Bool
standalone
          , readerColumns :: Int
readerColumns = Opt -> Int
optColumns Opt
opts
          , readerTabStop :: Int
readerTabStop = Opt -> Int
optTabStop Opt
opts
          , readerIndentedCodeClasses :: [Text]
readerIndentedCodeClasses = Opt -> [Text]
optIndentedCodeClasses Opt
opts
          , readerDefaultImageExtension :: Text
readerDefaultImageExtension =
             Opt -> Text
optDefaultImageExtension Opt
opts
          , readerTrackChanges :: TrackChanges
readerTrackChanges = Opt -> TrackChanges
optTrackChanges Opt
opts
          , readerAbbreviations :: Set Text
readerAbbreviations = Set Text
abbrevs
          , readerExtensions :: Extensions
readerExtensions = Extensions
readerExts
          , readerStripComments :: Bool
readerStripComments = Opt -> Bool
optStripComments Opt
opts
          }

    Meta
metadataFromFile <-
      case Opt -> [FilePath]
optMetadataFiles Opt
opts of
        []    -> Meta -> PandocIO Meta
forall (m :: * -> *) a. Monad m => a -> m a
return Meta
forall a. Monoid a => a
mempty
        paths :: [FilePath]
paths -> (FilePath -> PandocIO ByteString)
-> [FilePath] -> PandocIO [ByteString]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> PandocIO ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readFileLazy [FilePath]
paths PandocIO [ByteString]
-> ([ByteString] -> PandocIO Meta) -> PandocIO Meta
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
                    ([Meta] -> Meta) -> PandocIO [Meta] -> PandocIO Meta
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Meta] -> Meta
forall a. Monoid a => [a] -> a
mconcat (PandocIO [Meta] -> PandocIO Meta)
-> ([ByteString] -> PandocIO [Meta])
-> [ByteString]
-> PandocIO Meta
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> PandocIO Meta) -> [ByteString] -> PandocIO [Meta]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (ReaderOptions -> ByteString -> PandocIO Meta
forall (m :: * -> *).
PandocMonad m =>
ReaderOptions -> ByteString -> m Meta
yamlToMeta ReaderOptions
readerOpts)

    let transforms :: [Pandoc -> Pandoc]
transforms = (case Opt -> Int
optShiftHeadingLevelBy Opt
opts of
                          0             -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> a
id
                          x :: Int
x             -> (Int -> Pandoc -> Pandoc
headerShift Int
x (Pandoc -> Pandoc) -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> [a] -> [a]
:)) ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> [Pandoc -> Pandoc]
-> [Pandoc -> Pandoc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                     (if Opt -> Bool
optStripEmptyParagraphs Opt
opts
                         then (Pandoc -> Pandoc
stripEmptyParagraphs (Pandoc -> Pandoc) -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> [a] -> [a]
:)
                         else [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> a
id) ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> [Pandoc -> Pandoc]
-> [Pandoc -> Pandoc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                     (if Extension -> Extensions -> Bool
extensionEnabled Extension
Ext_east_asian_line_breaks
                            Extensions
readerExts Bool -> Bool -> Bool
&&
                         Bool -> Bool
not (Extension -> Extensions -> Bool
extensionEnabled Extension
Ext_east_asian_line_breaks
                              (WriterOptions -> Extensions
writerExtensions WriterOptions
writerOptions) Bool -> Bool -> Bool
&&
                              WriterOptions -> WrapOption
writerWrapText WriterOptions
writerOptions WrapOption -> WrapOption -> Bool
forall a. Eq a => a -> a -> Bool
== WrapOption
WrapPreserve)
                         then (Pandoc -> Pandoc
eastAsianLineBreakFilter (Pandoc -> Pandoc) -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> [a] -> [a]
:)
                         else [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> a
id) ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> [Pandoc -> Pandoc]
-> [Pandoc -> Pandoc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                     (case Opt -> IpynbOutput
optIpynbOutput Opt
opts of
                       IpynbOutputAll  -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> a
id
                       IpynbOutputNone -> (Maybe Format -> Pandoc -> Pandoc
filterIpynbOutput Maybe Format
forall a. Maybe a
Nothing (Pandoc -> Pandoc) -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> [a] -> [a]
:)
                       IpynbOutputBest -> (Maybe Format -> Pandoc -> Pandoc
filterIpynbOutput (Format -> Maybe Format
forall a. a -> Maybe a
Just (Format -> Maybe Format) -> Format -> Maybe Format
forall a b. (a -> b) -> a -> b
$
                                     if Text -> Bool
htmlFormat Text
format
                                        then Text -> Format
Format "html"
                                        else
                                          case Text
format of
                                            "latex"  -> Text -> Format
Format "latex"
                                            "beamer" -> Text -> Format
Format "latex"
                                            _        -> Text -> Format
Format Text
format) (Pandoc -> Pandoc) -> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a. a -> [a] -> [a]
:))
                     ([Pandoc -> Pandoc] -> [Pandoc -> Pandoc])
-> [Pandoc -> Pandoc] -> [Pandoc -> Pandoc]
forall a b. (a -> b) -> a -> b
$ []

    let sourceToDoc :: [FilePath] -> PandocIO Pandoc
        sourceToDoc :: [FilePath] -> PandocIO Pandoc
sourceToDoc sources' :: [FilePath]
sources' =
           case Reader PandocIO
reader of
                TextReader r :: ReaderOptions -> Text -> PandocIO Pandoc
r
                  | Opt -> Bool
optFileScope Opt
opts Bool -> Bool -> Bool
|| Text
readerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "json" ->
                      [Pandoc] -> Pandoc
forall a. Monoid a => [a] -> a
mconcat ([Pandoc] -> Pandoc) -> PandocIO [Pandoc] -> PandocIO Pandoc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FilePath -> PandocIO Pandoc) -> [FilePath] -> PandocIO [Pandoc]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (FilePath -> PandocIO Text
readSource (FilePath -> PandocIO Text)
-> (Text -> PandocIO Pandoc) -> FilePath -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> ReaderOptions -> Text -> PandocIO Pandoc
r ReaderOptions
readerOpts) [FilePath]
sources'
                  | Bool
otherwise ->
                      [FilePath] -> PandocIO Text
readSources [FilePath]
sources' PandocIO Text -> (Text -> PandocIO Pandoc) -> PandocIO Pandoc
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ReaderOptions -> Text -> PandocIO Pandoc
r ReaderOptions
readerOpts
                ByteStringReader r :: ReaderOptions -> ByteString -> PandocIO Pandoc
r ->
                  [Pandoc] -> Pandoc
forall a. Monoid a => [a] -> a
mconcat ([Pandoc] -> Pandoc) -> PandocIO [Pandoc] -> PandocIO Pandoc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FilePath -> PandocIO Pandoc) -> [FilePath] -> PandocIO [Pandoc]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (FilePath -> PandocIO ByteString
forall (m :: * -> *). MonadIO m => FilePath -> m ByteString
readFile' (FilePath -> PandocIO ByteString)
-> (ByteString -> PandocIO Pandoc) -> FilePath -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> ReaderOptions -> ByteString -> PandocIO Pandoc
r ReaderOptions
readerOpts) [FilePath]
sources'


    Bool -> PandocIO () -> PandocIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text
readerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "markdown_github" Bool -> Bool -> Bool
||
          Text
writerName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "markdown_github") (PandocIO () -> PandocIO ()) -> PandocIO () -> PandocIO ()
forall a b. (a -> b) -> a -> b
$
      LogMessage -> PandocIO ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> PandocIO ()) -> LogMessage -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> Text -> LogMessage
Deprecated "markdown_github" "Use gfm instead."

    [FilePath] -> PandocIO ()
forall (m :: * -> *). PandocMonad m => [FilePath] -> m ()
setResourcePath (Opt -> [FilePath]
optResourcePath Opt
opts)
    ((Text, Text) -> PandocIO ()) -> [(Text, Text)] -> PandocIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ((Text -> Text -> PandocIO ()) -> (Text, Text) -> PandocIO ()
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Text -> Text -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Text -> Text -> m ()
setRequestHeader) (Opt -> [(Text, Text)]
optRequestHeaders Opt
opts)

    Pandoc
doc <- [FilePath] -> PandocIO Pandoc
sourceToDoc [FilePath]
sources PandocIO Pandoc -> (Pandoc -> PandocIO Pandoc) -> PandocIO Pandoc
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
              (   (if Maybe FilePath -> Bool
forall a. Maybe a -> Bool
isJust (Opt -> Maybe FilePath
optExtractMedia Opt
opts)
                      then Pandoc -> PandocIO Pandoc
forall (m :: * -> *). PandocMonad m => Pandoc -> m Pandoc
fillMediaBag
                      else Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return)
              (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> PandocIO Pandoc) -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> Pandoc) -> Pandoc -> PandocIO Pandoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Meta -> Meta) -> Pandoc -> Pandoc
adjustMetadata (Meta
metadataFromFile Meta -> Meta -> Meta
forall a. Semigroup a => a -> a -> a
<>)
              (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> PandocIO Pandoc) -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> Pandoc) -> Pandoc -> PandocIO Pandoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Meta -> Meta) -> Pandoc -> Pandoc
adjustMetadata (Meta -> Meta -> Meta
forall a. Semigroup a => a -> a -> a
<> Meta
metadata)
              (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> PandocIO Pandoc) -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [Pandoc -> Pandoc] -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *).
Monad m =>
[Pandoc -> Pandoc] -> Pandoc -> m Pandoc
applyTransforms [Pandoc -> Pandoc]
transforms
              (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> PandocIO Pandoc) -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> ReaderOptions
-> [Filter] -> [FilePath] -> Pandoc -> PandocIO Pandoc
applyFilters ReaderOptions
readerOpts [Filter]
filters' [Text -> FilePath
T.unpack Text
format]
              (Pandoc -> PandocIO Pandoc)
-> (Pandoc -> PandocIO Pandoc) -> Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> (Pandoc -> PandocIO Pandoc)
-> (FilePath -> Pandoc -> PandocIO Pandoc)
-> Maybe FilePath
-> Pandoc
-> PandocIO Pandoc
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Pandoc -> PandocIO Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath -> Pandoc -> PandocIO Pandoc
extractMedia (Opt -> Maybe FilePath
optExtractMedia Opt
opts)
              )

    case Writer PandocIO
writer of
      ByteStringWriter f :: WriterOptions -> Pandoc -> PandocIO ByteString
f -> WriterOptions -> Pandoc -> PandocIO ByteString
f WriterOptions
writerOptions Pandoc
doc PandocIO ByteString -> (ByteString -> PandocIO ()) -> PandocIO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> ByteString -> PandocIO ()
forall (m :: * -> *). MonadIO m => FilePath -> ByteString -> m ()
writeFnBinary FilePath
outputFile
      TextWriter f :: WriterOptions -> Pandoc -> PandocIO Text
f -> case OutputSettings -> Maybe FilePath
outputPdfProgram OutputSettings
outputSettings of
        Just pdfProg :: FilePath
pdfProg -> do
                Either ByteString ByteString
res <- FilePath
-> [FilePath]
-> (WriterOptions -> Pandoc -> PandocIO Text)
-> WriterOptions
-> Pandoc
-> PandocIO (Either ByteString ByteString)
makePDF FilePath
pdfProg (Opt -> [FilePath]
optPdfEngineOpts Opt
opts) WriterOptions -> Pandoc -> PandocIO Text
f
                        WriterOptions
writerOptions Pandoc
doc
                case Either ByteString ByteString
res of
                     Right pdf :: ByteString
pdf -> FilePath -> ByteString -> PandocIO ()
forall (m :: * -> *). MonadIO m => FilePath -> ByteString -> m ()
writeFnBinary FilePath
outputFile ByteString
pdf
                     Left err' :: ByteString
err' -> PandocError -> PandocIO ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (PandocError -> PandocIO ()) -> PandocError -> PandocIO ()
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocPDFError (Text -> PandocError) -> Text -> PandocError
forall a b. (a -> b) -> a -> b
$
                                     Text -> Text
TL.toStrict (OnDecodeError -> ByteString -> Text
TE.decodeUtf8With OnDecodeError
TE.lenientDecode ByteString
err')

        Nothing -> do
                let ensureNl :: Text -> Text
ensureNl t :: Text
t
                      | Bool
standalone = Text
t
                      | Text -> Bool
T.null Text
t Bool -> Bool -> Bool
|| Text -> Char
T.last Text
t Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '\n' = Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Char -> Text
T.singleton '\n'
                      | Bool
otherwise = Text
t
                Text
output <- Text -> Text
ensureNl (Text -> Text) -> PandocIO Text -> PandocIO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> WriterOptions -> Pandoc -> PandocIO Text
f WriterOptions
writerOptions Pandoc
doc
                Newline -> FilePath -> Text -> PandocIO ()
forall (m :: * -> *).
MonadIO m =>
Newline -> FilePath -> Text -> m ()
writerFn Newline
eol FilePath
outputFile (Text -> PandocIO ()) -> PandocIO Text -> PandocIO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<
                  if Opt -> Bool
optSelfContained Opt
opts Bool -> Bool -> Bool
&& Text -> Bool
htmlFormat Text
format
                     then Text -> PandocIO Text
forall (m :: * -> *). PandocMonad m => Text -> m Text
makeSelfContained Text
output
                     else Text -> PandocIO Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
output

type Transform = Pandoc -> Pandoc

htmlFormat :: Text -> Bool
htmlFormat :: Text -> Bool
htmlFormat = (Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ["html","html4","html5","s5","slidy",
                      "slideous","dzslides","revealjs"])

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

adjustMetadata :: (Meta -> Meta) -> Pandoc -> Pandoc
adjustMetadata :: (Meta -> Meta) -> Pandoc -> Pandoc
adjustMetadata f :: Meta -> Meta
f (Pandoc meta :: Meta
meta bs :: [Block]
bs) = Meta -> [Block] -> Pandoc
Pandoc (Meta -> Meta
f Meta
meta) [Block]
bs

-- Transformations of a Pandoc document post-parsing:

applyTransforms :: Monad m => [Transform] -> Pandoc -> m Pandoc
applyTransforms :: [Pandoc -> Pandoc] -> Pandoc -> m Pandoc
applyTransforms transforms :: [Pandoc -> Pandoc]
transforms d :: Pandoc
d = Pandoc -> m Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return (Pandoc -> m Pandoc) -> Pandoc -> m Pandoc
forall a b. (a -> b) -> a -> b
$ ((Pandoc -> Pandoc) -> Pandoc -> Pandoc)
-> Pandoc -> [Pandoc -> Pandoc] -> Pandoc
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Pandoc -> Pandoc) -> Pandoc -> Pandoc
forall a b. (a -> b) -> a -> b
($) Pandoc
d [Pandoc -> Pandoc]
transforms

readSource :: FilePath -> PandocIO Text
readSource :: FilePath -> PandocIO Text
readSource src :: FilePath
src = case FilePath -> Maybe URI
parseURI FilePath
src of
                      Just u :: URI
u | URI -> FilePath
uriScheme URI
u FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ["http:","https:"] ->
                                 FilePath -> PandocIO Text
readURI FilePath
src
                             | URI -> FilePath
uriScheme URI
u FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== "file:" -> IO Text -> PandocIO Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> PandocIO Text) -> IO Text -> PandocIO Text
forall a b. (a -> b) -> a -> b
$
                                 FilePath -> IO Text
readTextFile (Text -> FilePath
uriPathToPath (Text -> FilePath) -> Text -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ URI -> FilePath
uriPath URI
u)
                      _       -> IO Text -> PandocIO Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> PandocIO Text) -> IO Text -> PandocIO Text
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Text
readTextFile FilePath
src
  where readTextFile :: FilePath -> IO Text
        readTextFile :: FilePath -> IO Text
readTextFile fp :: FilePath
fp = do
          ByteString
bs <- if FilePath
src FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== "-"
                   then IO ByteString
BS.getContents
                   else FilePath -> IO ByteString
BS.readFile FilePath
fp
          IO Text -> (UnicodeException -> IO Text) -> IO Text
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
E.catch (Text -> IO Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> IO Text) -> Text -> IO Text
forall a b. (a -> b) -> a -> b
$! ByteString -> Text
UTF8.toText ByteString
bs)
             (\e :: UnicodeException
e -> case UnicodeException
e of
                         TSE.DecodeError _ (Just w :: Word8
w) -> do
                           case Word8 -> ByteString -> Maybe Int
BS.elemIndex Word8
w ByteString
bs of
                             Just offset :: Int
offset -> PandocError -> IO Text
forall e a. Exception e => e -> IO a
E.throwIO (PandocError -> IO Text) -> PandocError -> IO Text
forall a b. (a -> b) -> a -> b
$
                                  Text -> Int -> Word8 -> PandocError
PandocUTF8DecodingError (FilePath -> Text
T.pack FilePath
fp) Int
offset Word8
w
                             _ -> PandocError -> IO Text
forall e a. Exception e => e -> IO a
E.throwIO (PandocError -> IO Text) -> PandocError -> IO Text
forall a b. (a -> b) -> a -> b
$ Text -> Int -> Word8 -> PandocError
PandocUTF8DecodingError (FilePath -> Text
T.pack FilePath
fp) 0 Word8
w
                         _ -> PandocError -> IO Text
forall e a. Exception e => e -> IO a
E.throwIO (PandocError -> IO Text) -> PandocError -> IO Text
forall a b. (a -> b) -> a -> b
$ Text -> PandocError
PandocAppError (UnicodeException -> Text
forall a. Show a => a -> Text
tshow UnicodeException
e))

readURI :: FilePath -> PandocIO Text
readURI :: FilePath -> PandocIO Text
readURI src :: FilePath
src = 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)
-> PandocIO (ByteString, Maybe Text) -> PandocIO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> PandocIO (ByteString, Maybe Text)
forall (m :: * -> *).
PandocMonad m =>
Text -> m (ByteString, Maybe Text)
openURL (FilePath -> Text
T.pack FilePath
src)

readFile' :: MonadIO m => FilePath -> m BL.ByteString
readFile' :: FilePath -> m ByteString
readFile' "-" = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ByteString
BL.getContents
readFile' f :: FilePath
f   = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString) -> IO ByteString -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ByteString
BL.readFile FilePath
f

writeFnBinary :: MonadIO m => FilePath -> BL.ByteString -> m ()
writeFnBinary :: FilePath -> ByteString -> m ()
writeFnBinary "-" = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO ()
BL.putStr
writeFnBinary f :: FilePath
f   = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString -> IO ()
BL.writeFile (FilePath -> FilePath
UTF8.encodePath FilePath
f)

writerFn :: MonadIO m => IO.Newline -> FilePath -> Text -> m ()
-- TODO this implementation isn't maximally efficient:
writerFn :: Newline -> FilePath -> Text -> m ()
writerFn eol :: Newline
eol "-" = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Newline -> FilePath -> IO ()
UTF8.putStrWith Newline
eol (FilePath -> IO ()) -> (Text -> FilePath) -> Text -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack
writerFn eol :: Newline
eol f :: FilePath
f   = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Newline -> FilePath -> FilePath -> IO ()
UTF8.writeFileWith Newline
eol FilePath
f (FilePath -> IO ()) -> (Text -> FilePath) -> Text -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack