git.iko.soy/typeable/pandoc
on master help sign in
pandoc.mediabag module: add items function iterating over mediabag
3097ee1Albert Krewinkel
doc/lua-filters.md+27
@@ -2475,6 +2475,33 @@ Usage:
2475 local contents = "Hello, World!"
2475 local contents = "Hello, World!"
2476 pandoc.mediabag(fp, mt, contents)
2476 pandoc.mediabag(fp, mt, contents)
2477
2477
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+
2478### list {#mediabag-list}
2505### list {#mediabag-list}
2479
2506
2480`list ()`
2507`list ()`
pandoc.cabal+1
@@ -591,6 +591,7 @@ library
591 Text.Pandoc.Lua.Marshaling.AST,
591 Text.Pandoc.Lua.Marshaling.AST,
592 Text.Pandoc.Lua.Marshaling.AnyValue,
592 Text.Pandoc.Lua.Marshaling.AnyValue,
593 Text.Pandoc.Lua.Marshaling.CommonState,
593 Text.Pandoc.Lua.Marshaling.CommonState,
594+ Text.Pandoc.Lua.Marshaling.MediaBag,
594 Text.Pandoc.Lua.Marshaling.ReaderOptions,
595 Text.Pandoc.Lua.Marshaling.ReaderOptions,
595 Text.Pandoc.Lua.Marshaling.Version,
596 Text.Pandoc.Lua.Marshaling.Version,
596 Text.Pandoc.Lua.Module.MediaBag,
597 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)
20import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
20import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
21 runIOorExplode, setMediaBag)
21 runIOorExplode, setMediaBag)
22import Text.Pandoc.Lua.Marshaling ()
22import Text.Pandoc.Lua.Marshaling ()
23+import Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator)
23import Text.Pandoc.Lua.Util (addFunction)
24import Text.Pandoc.Lua.Util (addFunction)
24import Text.Pandoc.MIME (MimeType)
25import Text.Pandoc.MIME (MimeType)
25
26
@@ -34,6 +35,7 @@ pushModule :: Lua NumResults
34pushModule = do
35pushModule = do
35 Lua.newtable
36 Lua.newtable
36 addFunction "insert" insertMediaFn
37 addFunction "insert" insertMediaFn
38+ addFunction "items" items
37 addFunction "lookup" lookupMediaFn
39 addFunction "lookup" lookupMediaFn
38 addFunction "list" mediaDirectoryFn
40 addFunction "list" mediaDirectoryFn
39 addFunction "fetch" fetch
41 addFunction "fetch" fetch
@@ -66,9 +68,13 @@ insertMediaFn fp optionalMime contents = do
66 modifyCommonState $ \st ->
68 modifyCommonState $ \st ->
67 let mb = MB.insertMedia fp (Lua.fromOptional optionalMime) contents
69 let mb = MB.insertMedia fp (Lua.fromOptional optionalMime) contents
68 (stMediaBag st)
70 (stMediaBag st)
69− in st { stMediaBag = mb}
71+ in st { stMediaBag = mb }
70 return 0
72 return 0
71
73
74+-- | Returns iterator values to be used with a Lua @for@ loop.
75+items :: Lua NumResults
76+items = stMediaBag <$> getCommonState >>= pushIterator
77+
72lookupMediaFn :: FilePath
78lookupMediaFn :: FilePath
73 -> Lua NumResults
79 -> Lua NumResults
74lookupMediaFn fp = do
80lookupMediaFn fp = do
src/Text/Pandoc/MediaBag.hs+6
@@ -19,6 +19,7 @@ module Text.Pandoc.MediaBag (
19 lookupMedia,
19 lookupMedia,
20 insertMedia,
20 insertMedia,
21 mediaDirectory,
21 mediaDirectory,
22+ mediaItems
22 ) where
23 ) where
23import Prelude
24import Prelude
24import qualified Data.ByteString.Lazy as BL
25import qualified Data.ByteString.Lazy as BL
@@ -66,3 +67,8 @@ mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
66mediaDirectory (MediaBag mediamap) =
67mediaDirectory (MediaBag mediamap) =
67 M.foldrWithKey (\fp (mime,contents) ->
68 M.foldrWithKey (\fp (mime,contents) ->
68 ((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
69 ((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