{- |
   Module      : Text.Pandoc.Filter.Lua
   Copyright   : Copyright (C) 2006-2022 John MacFarlane
   License     : GNU GPL, version 2 or above

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

Apply Lua filters to modify a pandoc documents programmatically.
-}
module Text.Pandoc.Filter.Lua (apply) where

import Control.Exception (throw)
import Control.Monad ((>=>))
import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad)
import Control.Monad.Trans (MonadIO)
import Text.Pandoc.Definition (Pandoc)
import Text.Pandoc.Error (PandocError (PandocFilterError, PandocLuaError))
import Text.Pandoc.Filter.Environment (Environment (..))
import Text.Pandoc.Lua (Global (..), runLua, runFilterFile, setGlobals)

-- | Run the Lua filter in @filterPath@ for a transformation to the
-- target format (first element in args). Pandoc uses Lua init files to
-- setup the Lua interpreter.
apply :: (PandocMonad m, MonadIO m)
      => Environment
      -> [String]
      -> FilePath
      -> Pandoc
      -> m Pandoc
apply :: Environment -> [String] -> String -> Pandoc -> m Pandoc
apply Environment
fenv [String]
args String
fp Pandoc
doc = do
  let format :: String
format = case [String]
args of
                 (String
x:[String]
_) -> String
x
                 [String]
_     -> String -> String
forall a. HasCallStack => String -> a
error String
"Format not supplied for Lua filter"
  LuaE PandocError Pandoc -> m (Either PandocError Pandoc)
forall (m :: * -> *) a.
(PandocMonad m, MonadIO m) =>
LuaE PandocError a -> m (Either PandocError a)
runLua (LuaE PandocError Pandoc -> m (Either PandocError Pandoc))
-> (Either PandocError Pandoc -> m Pandoc)
-> LuaE PandocError Pandoc
-> m Pandoc
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> String -> Either PandocError Pandoc -> m Pandoc
forall (m :: * -> *).
(PandocMonad m, MonadIO m) =>
String -> Either PandocError Pandoc -> m Pandoc
forceResult String
fp (LuaE PandocError Pandoc -> m Pandoc)
-> LuaE PandocError Pandoc -> m Pandoc
forall a b. (a -> b) -> a -> b
$ do
    [Global] -> LuaE PandocError ()
setGlobals [ Text -> Global
FORMAT (Text -> Global) -> Text -> Global
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
format
               , ReaderOptions -> Global
PANDOC_READER_OPTIONS (Environment -> ReaderOptions
envReaderOptions Environment
fenv)
               , WriterOptions -> Global
PANDOC_WRITER_OPTIONS (Environment -> WriterOptions
envWriterOptions Environment
fenv)
               , String -> Global
PANDOC_SCRIPT_FILE String
fp
               ]
    String -> Pandoc -> LuaE PandocError Pandoc
runFilterFile String
fp Pandoc
doc

forceResult :: (PandocMonad m, MonadIO m)
            => FilePath -> Either PandocError Pandoc -> m Pandoc
forceResult :: String -> Either PandocError Pandoc -> m Pandoc
forceResult String
fp Either PandocError Pandoc
eitherResult = case Either PandocError Pandoc
eitherResult of
  Right Pandoc
x  -> Pandoc -> m Pandoc
forall (m :: * -> *) a. Monad m => a -> m a
return Pandoc
x
  Left PandocError
err -> PandocError -> m Pandoc
forall a e. Exception e => e -> a
throw (PandocError -> m Pandoc)
-> (Text -> PandocError) -> Text -> m Pandoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> PandocError
PandocFilterError (String -> Text
T.pack String
fp) (Text -> m Pandoc) -> Text -> m Pandoc
forall a b. (a -> b) -> a -> b
$ case PandocError
err of
    PandocLuaError Text
msg -> Text
msg
    PandocError
_                  -> String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ PandocError -> String
forall a. Show a => a -> String
show PandocError
err