git.iko.soy/typeable/pandoc
on master help sign in
Lua filter: use destructured functions for inline filters

Instead of taking the whole inline element, forcing users to destructure it themselves, the components of the elements are passed to the filtering functions.

commit2761a38e530735499f7ac0075b768feb101190a5 authorAlbert Krewinkel <albert@zeitkraut.de> dateWed 12 Apr 2017, 20:48 (10 years ago) parent624ccbd
2 files changed+63−37
src/Text/Pandoc/Lua.hs+58−33 test/lua/strmacro.lua+5−4
src/Text/Pandoc/Lua.hs+58−33
@@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License
1515along with this program; if not, write to the Free Software
1616Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1717-}
18+{-# LANGUAGE FlexibleContexts #-}
19+{-# LANGUAGE FlexibleInstances #-}
20+{-# LANGUAGE MultiParamTypeClasses #-}
1821{-# LANGUAGE OverloadedStrings #-}
1922{- |
2023 Module : Text.Pandoc.Lua
@@ -130,29 +133,35 @@ execInlineLuaFilter :: LuaState
130133 -> HashMap Text (LuaFilterFunction Inline)
131134 -> Inline -> IO Inline
132135execInlineLuaFilter lua fnMap x = do
133− let filterOrId constr = case HashMap.lookup constr fnMap of
134− Nothing -> return x
135− Just fn -> runLuaFilterFunction lua fn x
136+ let runFn :: PushViaFilterFunction Inline a => LuaFilterFunction Inline -> a
137+ runFn fn = runLuaFilterFunction lua fn
138+ let tryFilter :: Text -> (LuaFilterFunction Inline -> IO Inline) -> IO Inline
139+ tryFilter fnName callFilterFn =
140+ case HashMap.lookup fnName fnMap of
141+ Nothing -> return x
142+ Just fn -> callFilterFn fn
136143 case x of
137− Cite _ _ -> filterOrId "Cite"
138− Code _ _ -> filterOrId "Code"
139− Emph _ -> filterOrId "Emph"
140− Image _ _ _ -> filterOrId "Image"
141− LineBreak -> filterOrId "LineBreak"
142− Link _ _ _ -> filterOrId "Link"
143− Math _ _ -> filterOrId "Math"
144− Note _ -> filterOrId "Note"
145− Quoted _ _ -> filterOrId "Quoted"
146− RawInline _ _ -> filterOrId "RawInline"
147− SmallCaps _ -> filterOrId "SmallCaps"
148− SoftBreak -> filterOrId "SoftBreak"
149− Space -> filterOrId "Space"
150− Span _ _ -> filterOrId "Span"
151− Str _ -> filterOrId "Str"
152− Strikeout _ -> filterOrId "Strikeout"
153− Strong _ -> filterOrId "Strong"
154− Subscript _ -> filterOrId "Subscript"
155− Superscript _ -> filterOrId "Superscript"
144+ LineBreak -> tryFilter "LineBreak" runFn
145+ SoftBreak -> tryFilter "SoftBreak" runFn
146+ Space -> tryFilter "Space" runFn
147+ Cite cs lst -> tryFilter "Cite" $ \fn -> runFn fn lst cs
148+ Code attr str -> tryFilter "Code" $ \fn -> runFn fn str attr
149+ Emph lst -> tryFilter "Emph" $ \fn -> runFn fn lst
150+ Math mt lst -> tryFilter "Math" $ \fn -> runFn fn lst mt
151+ Note blks -> tryFilter "Note" $ \fn -> runFn fn blks
152+ Quoted qt lst -> tryFilter "Quoted" $ \fn -> runFn fn qt lst
153+ RawInline f str -> tryFilter "RawInline" $ \fn -> runFn fn f str
154+ SmallCaps lst -> tryFilter "SmallCaps" $ \fn -> runFn fn lst
155+ Span attr lst -> tryFilter "Span" $ \fn -> runFn fn lst attr
156+ Str str -> tryFilter "Str" $ \fn -> runFn fn str
157+ Strikeout lst -> tryFilter "Strikeout" $ \fn -> runFn fn lst
158+ Strong lst -> tryFilter "Strong" $ \fn -> runFn fn lst
159+ Subscript lst -> tryFilter "Subscript" $ \fn -> runFn fn lst
160+ Superscript lst -> tryFilter "Superscript" $ \fn -> runFn fn lst
161+ Link attr txt (src, tit) -> tryFilter "Link" $
162+ \fn -> runFn fn txt src tit attr
163+ Image attr alt (src, tit) -> tryFilter "Image" $
164+ \fn -> runFn fn alt src tit attr
156165
157166instance StackValue LuaFilter where
158167 valuetype _ = Lua.TTABLE
@@ -164,17 +173,33 @@ instance StackValue LuaFilter where
164173 docFnMap <- Lua.peek lua i
165174 return $ LuaFilter lua <$> inlineFnMap <*> blockFnMap <*> docFnMap
166175
167−runLuaFilterFunction :: (StackValue a)
168− => LuaState -> LuaFilterFunction a -> a -> IO a
169−runLuaFilterFunction lua lf inline = do
170− pushFilterFunction lua lf
171− Lua.push lua inline
172− Lua.call lua 1 1
173− mbres <- Lua.peek lua (-1)
174− case mbres of
175− Nothing -> error $ "Error while trying to get a filter's return "
176− ++ "value from lua stack."
177− Just res -> res <$ Lua.pop lua 1
176+-- | Helper class for pushing a single value to the stack via a lua function.
177+-- See @pushViaCall@.
178+class PushViaFilterFunction a b where
179+ pushViaFilterFunction' :: LuaState -> LuaFilterFunction a -> IO () -> Int -> b
180+
181+instance (StackValue a) => PushViaFilterFunction a (IO a) where
182+ pushViaFilterFunction' lua lf pushArgs num = do
183+ pushFilterFunction lua lf
184+ pushArgs
185+ Lua.call lua num 1
186+ mbres <- Lua.peek lua (-1)
187+ case mbres of
188+ Nothing -> error $ "Error while trying to get a filter's return "
189+ ++ "value from lua stack."
190+ Just res -> res <$ Lua.pop lua 1
191+
192+instance (PushViaFilterFunction a c, StackValue b) =>
193+ PushViaFilterFunction a (b -> c) where
194+ pushViaFilterFunction' lua lf pushArgs num x =
195+ pushViaFilterFunction' lua lf (pushArgs *> push lua x) (num + 1)
196+
197+-- | Push an value to the stack via a lua filter function. The function is
198+-- called with all arguments that are passed to this function and is expected to
199+-- return a single value.
200+runLuaFilterFunction :: (StackValue a, PushViaFilterFunction a b)
201+ => LuaState -> LuaFilterFunction a -> b
202+runLuaFilterFunction lua lf = pushViaFilterFunction' lua lf (return ()) 0
178203
179204-- | Push the filter function to the top of the stack.
180205pushFilterFunction :: Lua.LuaState -> LuaFilterFunction a -> IO ()
test/lua/strmacro.lua+5−4
@@ -1,10 +1,11 @@
11return {
2− { Str = function (inline)
3− if inline.c == "{{helloworld}}" then
2+ {
3+ Str = function (str)
4+ if str == "{{helloworld}}" then
45 return pandoc.Emph {pandoc.Str "Hello, World"}
56 else
6− return inline
7+ return pandoc.Str(str)
78 end
8− end,
9+ end,
910 }
1011}