git.iko.soy/typeable/pandoc
on master help sign in
pandoc.mediabag module: add items function iterating over mediabag

A new function `pandoc.mediabag.items` was added to Lua module pandoc.mediabag. This allows users to lazily iterate over all media bag items, loading items into Lua one-by-one. Example: for filename, mime_type, content in pandoc.mediabag.items() do -- use media bag item. end This is a convenient alternative to using `mediabag.list` in combination with `mediabag.lookup`.

commit3097ee100ed260a5c2cea7df5bf80c989687df44 authorAlbert Krewinkel <albert@zeitkraut.de> dateFri 15 Feb 2019, 17:13 (8 years ago) parent8507d98
5 files changed+116−1
doc/lua-filters.md+27 pandoc.cabal+1 src/Text/Pandoc/Lua/Marshaling/MediaBag.hs+75 src/Text/Pandoc/Lua/Module/MediaBag.hs+7−1 src/Text/Pandoc/MediaBag.hs+6
doc/lua-filters.md+27
@@ -2475,6 +2475,33 @@ Usage:
24752475 local contents = "Hello, World!"
24762476 pandoc.mediabag(fp, mt, contents)
24772477
2478+### iter {#mediabag-iter}
2479+
2480+`items ()`
2481+
2482+Returns an iterator triple to be used with Lua's generic `for`
2483+statement. The iterator returns the filepath, MIME type, and
2484+content of a media bag item on each invocation. Items are
2485+processed one-by-one to avoid excessive memory use.
2486+
2487+This function should be used only when full access to all items,
2488+including their contents, is required. For all other cases,
2489+[`list`](#mediabag-list) should be preferred.
2490+
2491+Returns:
2492+
2493+ - The iterator function; must be called with the iterator state
2494+ and the current iterator value.
2495+ - Iterator state – an opaque value to be passed to the iterator
2496+ function.
2497+ - Initial iterator value.
2498+
2499+Usage:
2500+
2501+ for fp, mt, contents in pandoc.mediabag.items() do
2502+ -- print(fp, mt, contents)
2503+ end
2504+
24782505### list {#mediabag-list}
24792506
24802507`list ()`
pandoc.cabal+1
@@ -591,6 +591,7 @@ library
591591 Text.Pandoc.Lua.Marshaling.AST,
592592 Text.Pandoc.Lua.Marshaling.AnyValue,
593593 Text.Pandoc.Lua.Marshaling.CommonState,
594+ Text.Pandoc.Lua.Marshaling.MediaBag,
594595 Text.Pandoc.Lua.Marshaling.ReaderOptions,
595596 Text.Pandoc.Lua.Marshaling.Version,
596597 Text.Pandoc.Lua.Module.MediaBag,
src/Text/Pandoc/Lua/Marshaling/MediaBag.hsnew file+75
@@ -0,0 +1,75 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{- |
3+ Module : Text.Pandoc.Lua.Marshaling.MediaBag
4+ Copyright : © 2012-2019 John MacFarlane
5+ © 2017-2019 Albert Krewinkel
6+ License : GNU GPL, version 2 or above
7+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
8+ Stability : alpha
9+
10+Instances to marshal (push) and unmarshal (peek) media data.
11+-}
12+module Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator) where
13+
14+import Prelude
15+import Foreign.Ptr (Ptr)
16+import Foreign.StablePtr (StablePtr, deRefStablePtr, newStablePtr)
17+import Foreign.Lua (Lua, NumResults, Peekable, Pushable, StackIndex)
18+import Foreign.Lua.Types.Peekable (reportValueOnFailure)
19+import Foreign.Lua.Userdata (ensureUserdataMetatable, pushAnyWithMetatable,
20+ toAnyWithName)
21+import Text.Pandoc.MediaBag (MediaBag, mediaItems)
22+import Text.Pandoc.MIME (MimeType)
23+import Text.Pandoc.Lua.Marshaling.AnyValue (AnyValue (..))
24+
25+import qualified Data.ByteString.Lazy as BL
26+import qualified Foreign.Lua as Lua
27+import qualified Foreign.Storable as Storable
28+
29+-- | A list of 'MediaBag' items.
30+newtype MediaItems = MediaItems [(String, MimeType, BL.ByteString)]
31+
32+instance Pushable MediaItems where
33+ push = pushMediaItems
34+
35+instance Peekable MediaItems where
36+ peek = peekMediaItems
37+
38+-- | Push an iterator triple to be used with Lua's @for@ loop construct.
39+-- Each iterator invokation returns a tripple consisting of an item's
40+-- filename, MIME type, and content.
41+pushIterator :: MediaBag -> Lua NumResults
42+pushIterator mb = do
43+ Lua.pushHaskellFunction nextItem
44+ Lua.push (MediaItems $ mediaItems mb)
45+ Lua.pushnil
46+ return 3
47+
48+-- | Lua type name for @'MediaItems'@.
49+mediaItemsTypeName :: String
50+mediaItemsTypeName = "pandoc MediaItems"
51+
52+-- | Push a @MediaItems@ element to the stack.
53+pushMediaItems :: MediaItems -> Lua ()
54+pushMediaItems xs = pushAnyWithMetatable pushMT xs
55+ where
56+ pushMT = ensureUserdataMetatable mediaItemsTypeName (return ())
57+
58+-- | Retrieve a @MediaItems@ element from the stack.
59+peekMediaItems :: StackIndex -> Lua MediaItems
60+peekMediaItems = reportValueOnFailure mediaItemsTypeName
61+ (`toAnyWithName` mediaItemsTypeName)
62+
63+-- | Retrieve a list of items from an iterator state, return the first
64+-- item (if present), and advance the state.
65+nextItem :: Ptr (StablePtr MediaItems) -> AnyValue -> Lua NumResults
66+nextItem ptr _ = do
67+ (MediaItems items) <- Lua.liftIO $ deRefStablePtr =<< Storable.peek ptr
68+ case items of
69+ [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
70+ (key, mt, content):xs -> do
71+ Lua.liftIO $ Storable.poke ptr =<< newStablePtr (MediaItems xs)
72+ Lua.push key
73+ Lua.push mt
74+ Lua.push content
75+ return 3
src/Text/Pandoc/Lua/Module/MediaBag.hs+7−1
@@ -20,6 +20,7 @@ import Foreign.Lua (Lua, NumResults, Optional, liftIO)
2020import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
2121 runIOorExplode, setMediaBag)
2222import Text.Pandoc.Lua.Marshaling ()
23+import Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator)
2324import Text.Pandoc.Lua.Util (addFunction)
2425import Text.Pandoc.MIME (MimeType)
2526
@@ -34,6 +35,7 @@ pushModule :: Lua NumResults
3435pushModule = do
3536 Lua.newtable
3637 addFunction "insert" insertMediaFn
38+ addFunction "items" items
3739 addFunction "lookup" lookupMediaFn
3840 addFunction "list" mediaDirectoryFn
3941 addFunction "fetch" fetch
@@ -66,9 +68,13 @@ insertMediaFn fp optionalMime contents = do
6668 modifyCommonState $ \st ->
6769 let mb = MB.insertMedia fp (Lua.fromOptional optionalMime) contents
6870 (stMediaBag st)
69− in st { stMediaBag = mb}
71+ in st { stMediaBag = mb }
7072 return 0
7173
74+-- | Returns iterator values to be used with a Lua @for@ loop.
75+items :: Lua NumResults
76+items = stMediaBag <$> getCommonState >>= pushIterator
77+
7278lookupMediaFn :: FilePath
7379 -> Lua NumResults
7480lookupMediaFn fp = do
src/Text/Pandoc/MediaBag.hs+6
@@ -19,6 +19,7 @@ module Text.Pandoc.MediaBag (
1919 lookupMedia,
2020 insertMedia,
2121 mediaDirectory,
22+ mediaItems
2223 ) where
2324import Prelude
2425import qualified Data.ByteString.Lazy as BL
@@ -66,3 +67,8 @@ mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
6667mediaDirectory (MediaBag mediamap) =
6768 M.foldrWithKey (\fp (mime,contents) ->
6869 ((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
70+
71+mediaItems :: MediaBag -> [(String, MimeType, BL.ByteString)]
72+mediaItems (MediaBag mediamap) =
73+ M.foldrWithKey (\fp (mime,contents) ->
74+ ((Posix.joinPath fp, mime, contents):)) [] mediamap