@@ -32,50 +32,50 @@ Pandoc lua utils.
3232-}
3333module Text.Pandoc.Lua (LuaException (..), pushPandocModule, runLuaFilter) where
3434
35−import Control.Monad (unless, when, (>=>), mplus)
35+import Control.Monad (mplus, unless, when, (>=>))
3636import Control.Monad.Trans (MonadIO (..))
37−import Data.Data (toConstr, showConstr, dataTypeOf, dataTypeConstrs, Data)
37+import Data.Data (DataType, Data, toConstr, showConstr, dataTypeOf,
38+ dataTypeConstrs)
39+import Data.Foldable (foldrM)
3840import Data.Map (Map)
3941import Data.Maybe (isJust)
4042import Foreign.Lua (Lua, FromLuaStack (peek), LuaException (..), StackIndex,
41− Status(OK), ToLuaStack (push), call, isnil, dofile,
42− getglobal', gettop, isfunction, newtable, openlibs, pcall,
43− peekEither, pop, pushvalue, rawgeti, rawseti, ref,
44− registryindex, runLua, setglobal, throwLuaError)
43+ Status(OK), ToLuaStack (push))
4544import Text.Pandoc.Definition
4645import Text.Pandoc.Lua.PandocModule (pushPandocModule)
4746import Text.Pandoc.Walk (Walkable (walkM))
4847
4948import qualified Data.Map as Map
49+import qualified Foreign.Lua as Lua
5050
5151runLuaFilter :: (MonadIO m)
5252 => Maybe FilePath -> FilePath -> [String] -> Pandoc -> m Pandoc
53−runLuaFilter datadir filterPath args pd = liftIO . runLua $ do
54− openlibs
53+runLuaFilter datadir filterPath args pd = liftIO . Lua.runLua $ do
54+ Lua.openlibs
5555 -- store module in global "pandoc"
5656 pushPandocModule datadir
57− setglobal "pandoc"
58− top <- gettop
59− stat<- dofile filterPath
57+ Lua.setglobal "pandoc"
58+ top <- Lua.gettop
59+ stat<- Lua.dofile filterPath
6060 if stat /= OK
6161 then do
62− luaErrMsg <- peek (-1) <* pop 1
63− throwLuaError luaErrMsg
62+ luaErrMsg <- peek (-1) <* Lua.pop 1
63+ Lua.throwLuaError luaErrMsg
6464 else do
65− newtop <- gettop
65+ newtop <- Lua.gettop
6666 -- Use the implicitly defined global filter if nothing was returned
6767 when (newtop - top < 1) $ pushGlobalFilter
6868 luaFilters <- peek (-1)
6969 push args
70− setglobal "PandocParameters"
70+ Lua.setglobal "PandocParameters"
7171 runAll luaFilters pd
7272
7373pushGlobalFilter :: Lua ()
7474pushGlobalFilter = do
75− newtable
76− getglobal' "pandoc.global_filter"
77− call 0 1
78− rawseti (-2) 1
75+ Lua.newtable
76+ Lua.getglobal' "pandoc.global_filter"
77+ Lua.call 0 1
78+ Lua.rawseti (-2) 1
7979
8080runAll :: [LuaFilter] -> Pandoc -> Lua Pandoc
8181runAll = foldr ((>=>) . walkMWithLuaFilter) return
@@ -85,29 +85,42 @@ walkMWithLuaFilter (LuaFilter fnMap) = walkLua
8585 where
8686 walkLua :: Pandoc -> Lua Pandoc
8787 walkLua =
88− (if hasOneOf (constructorsFor (dataTypeOf (Str [])))
89− then walkM (tryFilter fnMap :: Inline -> Lua Inline)
90− else return)
91− >=>
92− (if hasOneOf (constructorsFor (dataTypeOf (Para [])))
93− then walkM (tryFilter fnMap :: Block -> Lua Block)
94− else return)
95− >=>
96− (case Map.lookup "Meta" fnMap of
97− Just fn -> walkM (\(Pandoc meta blocks) -> do
98− meta' <- runFilterFunction fn meta
99− return $ Pandoc meta' blocks)
100− Nothing -> return)
101− >=>
102− (case Map.lookup "Pandoc" fnMap `mplus` Map.lookup "Doc" fnMap of
103− Just fn -> runFilterFunction fn :: Pandoc -> Lua Pandoc
104− Nothing -> return)
88+ (if hasOneOf inlineFilterNames
89+ then walkM (tryFilter fnMap :: Inline -> Lua Inline)
90+ else return)
91+ >=>
92+ (if hasOneOf blockFilterNames
93+ then walkM (tryFilter fnMap :: Block -> Lua Block)
94+ else return)
95+ >=>
96+ (case Map.lookup "Meta" fnMap of
97+ Just fn -> walkM (\(Pandoc meta blocks) -> do
98+ meta' <- runFilterFunction fn meta
99+ return $ Pandoc meta' blocks)
100+ Nothing -> return)
101+ >=>
102+ (case foldl mplus Nothing (map (`Map.lookup` fnMap) pandocFilterNames) of
103+ Just fn -> runFilterFunction fn :: Pandoc -> Lua Pandoc
104+ Nothing -> return)
105105 hasOneOf = any (\k -> isJust (Map.lookup k fnMap))
106− constructorsFor x = map show (dataTypeConstrs x)
107106
108−type FunctionMap = Map String LuaFilterFunction
109−data LuaFilter = LuaFilter FunctionMap
107+constructorsFor :: DataType -> [String]
108+constructorsFor x = map show (dataTypeConstrs x)
109+
110+inlineFilterNames :: [String]
111+inlineFilterNames = constructorsFor (dataTypeOf (Str []))
112+
113+blockFilterNames :: [String]
114+blockFilterNames = constructorsFor (dataTypeOf (Para []))
110115
116+metaFilterName :: String
117+metaFilterName = "Meta"
118+
119+pandocFilterNames :: [String]
120+pandocFilterNames = ["Pandoc", "Doc"]
121+
122+type FunctionMap = Map String LuaFilterFunction
123+newtype LuaFilter = LuaFilter FunctionMap
111124newtype LuaFilterFunction = LuaFilterFunction { functionIndex :: Int }
112125
113126-- | Try running a filter for the given element
@@ -119,7 +132,18 @@ tryFilter fnMap x =
119132 Just fn -> runFilterFunction fn x
120133
121134instance FromLuaStack LuaFilter where
122− peek idx = LuaFilter <$> peek idx
135+ peek idx =
136+ let constrs = metaFilterName : pandocFilterNames
137+ ++ blockFilterNames
138+ ++ inlineFilterNames
139+ fn c acc = do
140+ Lua.getfield idx c
141+ filterFn <- Lua.tryLua (peek (-1))
142+ Lua.pop 1
143+ return $ case filterFn of
144+ Left _ -> acc
145+ Right f -> (c, f) : acc
146+ in LuaFilter . Map.fromList <$> foldrM fn [] constrs
123147
124148-- | Push a value to the stack via a lua filter function. The filter function is
125149-- called with given element as argument and is expected to return an element.
@@ -130,36 +154,36 @@ runFilterFunction :: (FromLuaStack a, ToLuaStack a)
130154runFilterFunction lf x = do
131155 pushFilterFunction lf
132156 push x
133− z <- pcall 1 1 Nothing
157+ z <- Lua.pcall 1 1 Nothing
134158 if z /= OK
135159 then do
136160 msg <- peek (-1)
137161 let prefix = "Error while running filter function: "
138− throwLuaError $ prefix ++ msg
162+ Lua.throwLuaError $ prefix ++ msg
139163 else do
140− noExplicitFilter <- isnil (-1)
164+ noExplicitFilter <- Lua.isnil (-1)
141165 if noExplicitFilter
142− then pop 1 *> return x
166+ then Lua.pop 1 *> return x
143167 else do
144− mbres <- peekEither (-1)
168+ mbres <- Lua.peekEither (-1)
145169 case mbres of
146− Left err -> throwLuaError
170+ Left err -> Lua.throwLuaError
147171 ("Error while trying to get a filter's return "
148172 ++ "value from lua stack.\n" ++ err)
149− Right res -> res <$ pop 1
173+ Right res -> res <$ Lua.pop 1
150174
151175-- | Push the filter function to the top of the stack.
152176pushFilterFunction :: LuaFilterFunction -> Lua ()
153177pushFilterFunction lf =
154178 -- The function is stored in a lua registry table, retrieve it from there.
155− rawgeti registryindex (functionIndex lf)
179+ Lua.rawgeti Lua.registryindex (functionIndex lf)
156180
157181registerFilterFunction :: StackIndex -> Lua LuaFilterFunction
158182registerFilterFunction idx = do
159− isFn <- isfunction idx
160− unless isFn . throwLuaError $ "Not a function at index " ++ show idx
161− pushvalue idx
162− refIdx <- ref registryindex
183+ isFn <- Lua.isfunction idx
184+ unless isFn . Lua.throwLuaError $ "Not a function at index " ++ show idx
185+ Lua.pushvalue idx
186+ refIdx <- Lua.ref Lua.registryindex
163187 return $ LuaFilterFunction refIdx
164188
165189instance ToLuaStack LuaFilterFunction where