module Text.Pandoc.Lua.Init
( LuaException (..)
, LuaPackageParams (..)
, runLua
, luaPackageParams
) where
import Control.Monad.Trans (MonadIO (..))
import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
import Foreign.Lua (Lua)
import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8)
import Text.Pandoc.Class.PandocIO (PandocIO)
import Text.Pandoc.Class.PandocMonad (getCommonState, getUserDataDir,
putCommonState)
import Text.Pandoc.Lua.Global (Global (..), setGlobals)
import Text.Pandoc.Lua.Packages (LuaPackageParams (..),
installPandocPackageSearcher)
import Text.Pandoc.Lua.Util (loadScriptFromDataDir)
import qualified Data.Text as Text
import qualified Foreign.Lua as Lua
import qualified Foreign.Lua.Module.Text as Lua
import qualified Text.Pandoc.Definition as Pandoc
import qualified Text.Pandoc.Lua.Module.Pandoc as ModulePandoc
newtype LuaException = LuaException Text.Text deriving (Show)
runLua :: Lua a -> PandocIO (Either LuaException a)
runLua luaOp = do
luaPkgParams <- luaPackageParams
globals <- defaultGlobals
enc <- liftIO $ getForeignEncoding <* setForeignEncoding utf8
res <- liftIO . Lua.runEither $ do
setGlobals globals
initLuaState luaPkgParams
opResult <- luaOp
Lua.getglobal "PANDOC_STATE"
st <- Lua.peek Lua.stackTop
Lua.pop 1
return (opResult, st)
liftIO $ setForeignEncoding enc
case res of
Left (Lua.Exception msg) -> return $ Left (LuaException $ Text.pack msg)
Right (x, newState) -> do
putCommonState newState
return $ Right x
defaultGlobals :: PandocIO [Global]
defaultGlobals = do
commonState <- getCommonState
return
[ PANDOC_API_VERSION
, PANDOC_STATE commonState
, PANDOC_VERSION
]
luaPackageParams :: PandocIO LuaPackageParams
luaPackageParams = do
datadir <- getUserDataDir
return LuaPackageParams { luaPkgDataDir = datadir }
initLuaState :: LuaPackageParams -> Lua ()
initLuaState pkgParams = do
Lua.openlibs
Lua.preloadTextModule "text"
installPandocPackageSearcher pkgParams
initPandocModule
loadScriptFromDataDir (luaPkgDataDir pkgParams) "init.lua"
where
initPandocModule :: Lua ()
initPandocModule = do
ModulePandoc.pushModule (luaPkgDataDir pkgParams)
Lua.pushvalue Lua.stackTop
Lua.getfield Lua.registryindex Lua.loadedTableRegistryField
Lua.setfield (Lua.nthFromTop 2) "pandoc"
Lua.pop 1
putConstructorsInRegistry
Lua.setglobal "pandoc"
putConstructorsInRegistry :: Lua ()
putConstructorsInRegistry = do
constrsToReg $ Pandoc.Pandoc mempty mempty
constrsToReg $ Pandoc.Str mempty
constrsToReg $ Pandoc.Para mempty
constrsToReg $ Pandoc.Meta mempty
constrsToReg $ Pandoc.MetaList mempty
constrsToReg $ Pandoc.Citation mempty mempty mempty Pandoc.AuthorInText 0 0
putInReg "Attr"
putInReg "ListAttributes"
putInReg "List"
where
constrsToReg :: Data a => a -> Lua ()
constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
putInReg :: String -> Lua ()
putInReg name = do
Lua.push ("pandoc." ++ name)
Lua.push name
Lua.rawget (Lua.nthFromTop 3)
Lua.rawset Lua.registryindex