module Text.Pandoc.Lua.Packages
( LuaPackageParams (..)
, installPandocPackageSearcher
) where
import Control.Monad (forM_)
import Data.ByteString.Char8 (unpack)
import Data.IORef (IORef)
import Foreign.Lua (Lua, NumResults, liftIO)
import Text.Pandoc.Class (CommonState, readDataFile, runIO, setUserDataDir)
import Text.Pandoc.MediaBag (MediaBag)
import Text.Pandoc.Lua.PandocModule (pushPandocModule, pushMediaBagModule)
import Text.Pandoc.Lua.Util (dostring')
import qualified Foreign.Lua as Lua
data LuaPackageParams = LuaPackageParams
{ luaPkgCommonState :: CommonState
, luaPkgDataDir :: Maybe FilePath
, luaPkgMediaBag :: IORef MediaBag
}
installPandocPackageSearcher :: LuaPackageParams -> Lua ()
installPandocPackageSearcher luaPkgParams = do
luaVersion <- Lua.getglobal "_VERSION" *> Lua.peek (1)
if luaVersion == "Lua 5.1"
then Lua.getglobal' "package.loaders"
else Lua.getglobal' "package.searchers"
shiftArray
Lua.pushHaskellFunction (pandocPackageSearcher luaPkgParams)
Lua.wrapHaskellFunction
Lua.rawseti (2) 1
Lua.pop 1
where
shiftArray = forM_ [4, 3, 2, 1] $ \i -> do
Lua.rawgeti (1) i
Lua.rawseti (2) (i + 1)
pandocPackageSearcher :: LuaPackageParams -> String -> Lua NumResults
pandocPackageSearcher luaPkgParams pkgName =
case pkgName of
"pandoc" -> let datadir = luaPkgDataDir luaPkgParams
in pushWrappedHsFun (pushPandocModule datadir)
"pandoc.mediabag" -> let st = luaPkgCommonState luaPkgParams
mbRef = luaPkgMediaBag luaPkgParams
in pushWrappedHsFun (pushMediaBagModule st mbRef)
_ -> searchPureLuaLoader
where
pushWrappedHsFun f = do
Lua.pushHaskellFunction f
Lua.wrapHaskellFunction
return 1
searchPureLuaLoader = do
let filename = pkgName ++ ".lua"
modScript <- liftIO (dataDirScript (luaPkgDataDir luaPkgParams) filename)
case modScript of
Just script -> pushWrappedHsFun (loadStringAsPackage pkgName script)
Nothing -> do
Lua.push ("no file '" ++ filename ++ "' in pandoc's datadir")
return 1
loadStringAsPackage :: String -> String -> Lua NumResults
loadStringAsPackage pkgName script = do
status <- dostring' script
if status == Lua.OK
then return (1 :: NumResults)
else do
msg <- Lua.peek (1) <* Lua.pop 1
Lua.push ("Error while loading ``" ++ pkgName ++ "`.\n" ++ msg)
Lua.lerror
return (2 :: NumResults)
dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe String)
dataDirScript datadir moduleFile = do
res <- runIO $ setUserDataDir datadir >> readDataFile moduleFile
return $ case res of
Left _ -> Nothing
Right s -> Just (unpack s)