diff options
-rw-r--r-- | src/Text/Pandoc/Lua/Filter.hs | 30 | ||||
-rw-r--r-- | src/Text/Pandoc/Lua/Module/Pandoc.hs | 5 | ||||
-rw-r--r-- | test/lua/module/pandoc.lua | 38 |
3 files changed, 62 insertions, 11 deletions
diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs index e8958347d..9efc2b9ae 100644 --- a/src/Text/Pandoc/Lua/Filter.hs +++ b/src/Text/Pandoc/Lua/Filter.hs @@ -20,6 +20,7 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction , walkBlocks , blockElementNames , inlineElementNames + , module Text.Pandoc.Lua.Walk ) where import Prelude import Control.Monad (mplus, (>=>)) @@ -31,7 +32,8 @@ import Data.Map (Map) import Foreign.Lua (Lua, Peekable, Pushable) import Text.Pandoc.Definition import Text.Pandoc.Lua.Marshaling () -import Text.Pandoc.Walk (walkM, Walkable) +import Text.Pandoc.Lua.Walk (SingletonsList (..)) +import Text.Pandoc.Walk (Walkable (walkM)) import qualified Data.Map.Strict as Map import qualified Foreign.Lua as Lua @@ -115,6 +117,12 @@ tryFilter (LuaFilter fnMap) x = Just fn -> runFilterFunction fn x *> elementOrList x Nothing -> return [x] +-- | Apply filter on a sequence of AST elements. +runOnSequence :: (Data a, Peekable a, Pushable a) + => LuaFilter -> SingletonsList a -> Lua (SingletonsList a) +runOnSequence lf (SingletonsList xs) = + SingletonsList <$> mconcatMapM (tryFilter lf) xs + -- | Push a value to the stack via a lua filter function. The filter function is -- called with given element as argument and is expected to return an element. -- Alternatively, the function can return nothing or nil, in which case the @@ -135,16 +143,20 @@ mconcatMapM f = fmap mconcat . mapM f hasOneOf :: LuaFilter -> [String] -> Bool hasOneOf (LuaFilter fnMap) = any (\k -> Map.member k fnMap) -walkInlines :: Walkable [Inline] a => LuaFilter -> a -> Lua a -walkInlines f = - if f `hasOneOf` inlineElementNames - then walkM (mconcatMapM (tryFilter f :: Inline -> Lua [Inline])) +walkInlines :: Walkable (SingletonsList Inline) a => LuaFilter -> a -> Lua a +walkInlines lf = + let f :: SingletonsList Inline -> Lua (SingletonsList Inline) + f = runOnSequence lf + in if lf `hasOneOf` inlineElementNames + then walkM f else return -walkBlocks :: Walkable [Block] a => LuaFilter -> a -> Lua a -walkBlocks f = - if f `hasOneOf` blockElementNames - then walkM (mconcatMapM (tryFilter f :: Block -> Lua [Block])) +walkBlocks :: Walkable (SingletonsList Block) a => LuaFilter -> a -> Lua a +walkBlocks lf = + let f :: SingletonsList Block -> Lua (SingletonsList Block) + f = runOnSequence lf + in if lf `hasOneOf` blockElementNames + then walkM f else return walkMeta :: LuaFilter -> Pandoc -> Lua Pandoc diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs index 09892db49..8950c4b7f 100644 --- a/src/Text/Pandoc/Lua/Module/Pandoc.hs +++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs @@ -23,7 +23,7 @@ import Foreign.Lua (Lua, NumResults, Optional, Peekable, Pushable) import System.Exit (ExitCode (..)) import Text.Pandoc.Class (runIO) import Text.Pandoc.Definition (Block, Inline) -import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter) +import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter, SingletonsList (..)) import Text.Pandoc.Lua.Marshaling () import Text.Pandoc.Walk (Walkable) import Text.Pandoc.Options (ReaderOptions (readerExtensions)) @@ -46,7 +46,8 @@ pushModule datadir = do LuaUtil.addFunction "walk_inline" walkInline return 1 -walkElement :: (Walkable [Inline] a, Walkable [Block] a) +walkElement :: (Walkable (SingletonsList Inline) a, + Walkable (SingletonsList Block) a) => a -> LuaFilter -> Lua a walkElement x f = walkInlines f x >>= walkBlocks f diff --git a/test/lua/module/pandoc.lua b/test/lua/module/pandoc.lua index ca2168805..1725d275b 100644 --- a/test/lua/module/pandoc.lua +++ b/test/lua/module/pandoc.lua @@ -171,4 +171,42 @@ return { ) end) }, + + group 'walk_block' { + test('block walking order', function () + local acc = {} + local nested_nums = pandoc.Div { + pandoc.Para{pandoc.Str'1'}, + pandoc.Div{ + pandoc.Para{pandoc.Str'2'}, + pandoc.Para{pandoc.Str'3'} + }, + pandoc.Para{pandoc.Str'4'} + } + pandoc.walk_block( + nested_nums, + {Para = function (p) table.insert(acc, p.content[1].text) end} + ) + assert.are_equal('1234', table.concat(acc)) + end) + }, + + group 'walk_inline' { + test('inline walking order', function () + local acc = {} + local nested_nums = pandoc.Span { + pandoc.Str'1', + pandoc.Emph { + pandoc.Str'2', + pandoc.Str'3' + }, + pandoc.Str'4' + } + pandoc.walk_inline( + nested_nums, + {Str = function (s) table.insert(acc, s.text) end} + ) + assert.are_equal('1234', table.concat(acc)) + end) + } } |