{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Pandoc.Lua.Packages
( LuaPackageParams (..)
, installPandocPackageSearcher
) where
import Control.Monad (forM_)
import Data.ByteString (ByteString)
import Foreign.Lua (Lua, NumResults, liftIO)
import Text.Pandoc.Class.PandocIO (runIO)
import Text.Pandoc.Class.PandocMonad (readDataFile, setUserDataDir)
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.System as System
import Text.Pandoc.Lua.Module.Types as Types
import Text.Pandoc.Lua.Module.Utils as Utils
data LuaPackageParams = LuaPackageParams
{ LuaPackageParams -> Maybe FilePath
luaPkgDataDir :: Maybe FilePath
}
installPandocPackageSearcher :: LuaPackageParams -> Lua ()
installPandocPackageSearcher :: LuaPackageParams -> Lua ()
installPandocPackageSearcher LuaPackageParams
luaPkgParams = do
FilePath -> Lua ()
Lua.getglobal' FilePath
"package.searchers"
Lua ()
shiftArray
(FilePath -> Lua NumResults) -> Lua ()
forall a. ToHaskellFunction a => a -> Lua ()
Lua.pushHaskellFunction (LuaPackageParams -> FilePath -> Lua NumResults
pandocPackageSearcher LuaPackageParams
luaPkgParams)
StackIndex -> Integer -> Lua ()
Lua.rawseti (CInt -> StackIndex
Lua.nthFromTop CInt
2) Integer
1
StackIndex -> Lua ()
Lua.pop StackIndex
1
where
shiftArray :: Lua ()
shiftArray = [Integer] -> (Integer -> Lua ()) -> Lua ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Integer
4, Integer
3, Integer
2, Integer
1] ((Integer -> Lua ()) -> Lua ()) -> (Integer -> Lua ()) -> Lua ()
forall a b. (a -> b) -> a -> b
$ \Integer
i -> do
StackIndex -> Integer -> Lua ()
Lua.rawgeti (-StackIndex
1) Integer
i
StackIndex -> Integer -> Lua ()
Lua.rawseti (-StackIndex
2) (Integer
i Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)
pandocPackageSearcher :: LuaPackageParams -> String -> Lua NumResults
pandocPackageSearcher :: LuaPackageParams -> FilePath -> Lua NumResults
pandocPackageSearcher LuaPackageParams
pkgParams FilePath
pkgName =
case FilePath
pkgName of
FilePath
"pandoc" -> let datadir :: Maybe FilePath
datadir = LuaPackageParams -> Maybe FilePath
luaPkgDataDir LuaPackageParams
pkgParams
in Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun (Maybe FilePath -> Lua NumResults
Pandoc.pushModule Maybe FilePath
datadir)
FilePath
"pandoc.mediabag" -> Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun Lua NumResults
MediaBag.pushModule
FilePath
"pandoc.system" -> Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun Lua NumResults
System.pushModule
FilePath
"pandoc.types" -> Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun Lua NumResults
Types.pushModule
FilePath
"pandoc.utils" -> let datadir :: Maybe FilePath
datadir = LuaPackageParams -> Maybe FilePath
luaPkgDataDir LuaPackageParams
pkgParams
in Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun (Maybe FilePath -> Lua NumResults
Utils.pushModule Maybe FilePath
datadir)
FilePath
_ -> Lua NumResults
searchPureLuaLoader
where
pushWrappedHsFun :: a -> Lua b
pushWrappedHsFun a
f = do
a -> Lua ()
forall a. ToHaskellFunction a => a -> Lua ()
Lua.pushHaskellFunction a
f
b -> Lua b
forall (m :: * -> *) a. Monad m => a -> m a
return b
1
searchPureLuaLoader :: Lua NumResults
searchPureLuaLoader = do
let filename :: FilePath
filename = FilePath
pkgName FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
".lua"
Maybe ByteString
modScript <- IO (Maybe ByteString) -> Lua (Maybe ByteString)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Maybe FilePath -> FilePath -> IO (Maybe ByteString)
dataDirScript (LuaPackageParams -> Maybe FilePath
luaPkgDataDir LuaPackageParams
pkgParams) FilePath
filename)
case Maybe ByteString
modScript of
Just ByteString
script -> Lua NumResults -> Lua NumResults
forall a b. (ToHaskellFunction a, Num b) => a -> Lua b
pushWrappedHsFun (FilePath -> ByteString -> Lua NumResults
loadStringAsPackage FilePath
pkgName ByteString
script)
Maybe ByteString
Nothing -> do
FilePath -> Lua ()
forall a. Pushable a => a -> Lua ()
Lua.push (FilePath
"\n\tno file '" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
filename FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"' in pandoc's datadir")
NumResults -> Lua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return NumResults
1
loadStringAsPackage :: String -> ByteString -> Lua NumResults
loadStringAsPackage :: FilePath -> ByteString -> Lua NumResults
loadStringAsPackage FilePath
pkgName ByteString
script = do
Status
status <- ByteString -> Lua Status
Lua.dostring ByteString
script
if Status
status Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
== Status
Lua.OK
then NumResults -> Lua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return (NumResults
1 :: NumResults)
else do
FilePath
msg <- Lua FilePath
forall a. Peekable a => Lua a
Lua.popValue
FilePath -> Lua NumResults
forall a. Pushable a => a -> Lua NumResults
Lua.raiseError (FilePath
"Error while loading `" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
pkgName FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
"`.\n" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
msg)
dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe ByteString)
dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe ByteString)
dataDirScript Maybe FilePath
datadir FilePath
moduleFile = do
Either PandocError ByteString
res <- PandocIO ByteString -> IO (Either PandocError ByteString)
forall a. PandocIO a -> IO (Either PandocError a)
runIO (PandocIO ByteString -> IO (Either PandocError ByteString))
-> PandocIO ByteString -> IO (Either PandocError ByteString)
forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> PandocIO ()
forall (m :: * -> *). PandocMonad m => Maybe FilePath -> m ()
setUserDataDir Maybe FilePath
datadir PandocIO () -> PandocIO ByteString -> PandocIO ByteString
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FilePath -> PandocIO ByteString
forall (m :: * -> *). PandocMonad m => FilePath -> m ByteString
readDataFile FilePath
moduleFile
Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ByteString -> IO (Maybe ByteString))
-> Maybe ByteString -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ case Either PandocError ByteString
res of
Left PandocError
_ -> Maybe ByteString
forall a. Maybe a
Nothing
Right ByteString
s -> ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
s