Skip to content

Commit

Permalink
Lua filters: load module pandoc before calling init.lua
Browse files Browse the repository at this point in the history
The file `init.lua` in pandoc's data directory is run as part of
pandoc's Lua initialization process. Previously, the `pandoc` module was
loaded in `init.lua`, and the structure for marshaling was set-up after.
This allowed simple patching of element marshaling, but made using
`init.lua` more difficult:

  - it encouraged mixing essential initialization with user-defined
    customization;

  - upstream changes to init.lua had to be merged manually;

  - accidentally breaking marshaling by removing required modules was
    possible;

Instead, all required modules are now loaded before calling `init.lua`.
The file can be used entirely for user customization. Patching
marshaling functions, while discouraged, is still possible via the
`debug` module.
  • Loading branch information
tarleb committed Feb 9, 2019
1 parent ba61dc3 commit 7964e4a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
2 changes: 0 additions & 2 deletions data/init.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
-- This Lua script is run every time the Lua interpreter is started when running
-- a Lua filter. It can be customized to load additional modules or to alter the
-- default modules.

pandoc = require 'pandoc'
33 changes: 27 additions & 6 deletions src/Text/Pandoc/Lua/Init.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import Text.Pandoc.Lua.Util (loadScriptFromDataDir)
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

-- | Lua error message
newtype LuaException = LuaException String deriving (Show)
Expand Down Expand Up @@ -95,16 +96,37 @@ luaPackageParams = do

-- | Initialize the lua state with all required values
initLuaState :: LuaPackageParams -> Lua ()
initLuaState luaPkgParams = do
initLuaState pkgParams = do
Lua.openlibs
Lua.preloadTextModule "text"
installPandocPackageSearcher luaPkgParams
loadScriptFromDataDir (luaPkgDataDir luaPkgParams) "init.lua"
putConstructorsInRegistry
installPandocPackageSearcher pkgParams
initPandocModule
loadScriptFromDataDir (luaPkgDataDir pkgParams) "init.lua"
where
initPandocModule :: Lua ()
initPandocModule = do
-- Push module table
ModulePandoc.pushModule (luaPkgDataDir pkgParams)
-- register as loaded module
Lua.pushvalue Lua.stackTop
Lua.getfield Lua.registryindex Lua.loadedTableRegistryField
Lua.setfield (Lua.nthFromTop 2) "pandoc"
Lua.pop 1
-- copy constructors into registry
putConstructorsInRegistry
-- assign module to global variable
Lua.setglobal "pandoc"

-- | AST elements are marshaled via normal constructor functions in the
-- @pandoc@ module. However, accessing Lua globals from Haskell is
-- expensive (due to error handling). Accessing the Lua registry is much
-- cheaper, which is why the constructor functions are copied into the
-- Lua registry and called from there.
--
-- This function expects the @pandoc@ module to be at the top of the
-- stack.
putConstructorsInRegistry :: Lua ()
putConstructorsInRegistry = do
Lua.getglobal "pandoc"
constrsToReg $ Pandoc.Pandoc mempty mempty
constrsToReg $ Pandoc.Str mempty
constrsToReg $ Pandoc.Para mempty
Expand All @@ -113,7 +135,6 @@ putConstructorsInRegistry = do
constrsToReg $ Pandoc.Citation mempty mempty mempty Pandoc.AuthorInText 0 0
putInReg "Attr" -- used for Attr type alias
putInReg "ListAttributes" -- used for ListAttributes type alias
Lua.pop 1
where
constrsToReg :: Data a => a -> Lua ()
constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
Expand Down

0 comments on commit 7964e4a

Please sign in to comment.