{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
module Text.Pandoc.Lua.Packages
( LuaPackageParams (..)
, installPandocPackageSearcher
) where
import Prelude
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.Util (dostring')
import qualified Foreign.Lua as Lua
import Text.Pandoc.Lua.Module.Pandoc as Pandoc
import Text.Pandoc.Lua.Module.MediaBag as MediaBag
import Text.Pandoc.Lua.Module.Utils as Utils
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 (Pandoc.pushModule datadir)
"pandoc.mediabag" -> let st = luaPkgCommonState luaPkgParams
mbRef = luaPkgMediaBag luaPkgParams
in pushWrappedHsFun (MediaBag.pushModule st mbRef)
"pandoc.utils" -> let datadirMb = luaPkgDataDir luaPkgParams
in pushWrappedHsFun (Utils.pushModule datadirMb)
_ -> 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)