{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE ScopedTypeVariables #-} {- | Module : Text.Pandoc.Lua.Packages Copyright : Copyright © 2017-2019 Albert Krewinkel License : GNU GPL, version 2 or above Maintainer : Albert Krewinkel Stability : alpha Pandoc module for lua. -} module Text.Pandoc.Lua.Packages ( LuaPackageParams (..) , installPandocPackageSearcher ) where import Prelude import Control.Monad (forM_) import Data.ByteString (ByteString) import Foreign.Lua (Lua, NumResults, liftIO) import Text.Pandoc.Class (readDataFile, runIO, 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.Utils as Utils -- | Parameters used to create lua packages/modules. data LuaPackageParams = LuaPackageParams { luaPkgDataDir :: Maybe FilePath } -- | Insert pandoc's package loader as the first loader, making it the default. installPandocPackageSearcher :: LuaPackageParams -> Lua () installPandocPackageSearcher luaPkgParams = do Lua.getglobal' "package.searchers" shiftArray Lua.pushHaskellFunction (pandocPackageSearcher luaPkgParams) Lua.rawseti (Lua.nthFromTop 2) 1 Lua.pop 1 -- remove 'package.searchers' from stack where shiftArray = forM_ [4, 3, 2, 1] $ \i -> do Lua.rawgeti (-1) i Lua.rawseti (-2) (i + 1) -- | Load a pandoc module. pandocPackageSearcher :: LuaPackageParams -> String -> Lua NumResults pandocPackageSearcher pkgParams pkgName = case pkgName of "pandoc" -> let datadir = luaPkgDataDir pkgParams in pushWrappedHsFun (Pandoc.pushModule datadir) "pandoc.mediabag" -> pushWrappedHsFun MediaBag.pushModule "pandoc.utils" -> let datadir = luaPkgDataDir pkgParams in pushWrappedHsFun (Utils.pushModule datadir) _ -> searchPureLuaLoader where pushWrappedHsFun f = do Lua.pushHaskellFunction f return 1 searchPureLuaLoader = do let filename = pkgName ++ ".lua" modScript <- liftIO (dataDirScript (luaPkgDataDir pkgParams) filename) case modScript of Just script -> pushWrappedHsFun (loadStringAsPackage pkgName script) Nothing -> do Lua.push ("\n\tno file '" ++ filename ++ "' in pandoc's datadir") return 1 loadStringAsPackage :: String -> ByteString -> Lua NumResults loadStringAsPackage pkgName script = do status <- Lua.dostring script if status == Lua.OK then return (1 :: NumResults) else do msg <- Lua.popValue Lua.raiseError ("Error while loading `" <> pkgName <> "`.\n" <> msg) -- | Get the ByteString representation of the pandoc module. dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe ByteString) dataDirScript datadir moduleFile = do res <- runIO $ setUserDataDir datadir >> readDataFile moduleFile return $ case res of Left _ -> Nothing Right s -> Just s