aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua-filters.md27
-rw-r--r--pandoc.cabal1
-rw-r--r--src/Text/Pandoc/Lua/Marshaling/MediaBag.hs75
-rw-r--r--src/Text/Pandoc/Lua/Module/MediaBag.hs8
-rw-r--r--src/Text/Pandoc/MediaBag.hs6
5 files changed, 116 insertions, 1 deletions
diff --git a/doc/lua-filters.md b/doc/lua-filters.md
index 45abe8ac8..667a58bcc 100644
--- a/doc/lua-filters.md
+++ b/doc/lua-filters.md
@@ -2475,6 +2475,33 @@ Usage:
local contents = "Hello, World!"
pandoc.mediabag(fp, mt, contents)
+### iter {#mediabag-iter}
+
+`items ()`
+
+Returns an iterator triple to be used with Lua's generic `for`
+statement. The iterator returns the filepath, MIME type, and
+content of a media bag item on each invocation. Items are
+processed one-by-one to avoid excessive memory use.
+
+This function should be used only when full access to all items,
+including their contents, is required. For all other cases,
+[`list`](#mediabag-list) should be preferred.
+
+Returns:
+
+ - The iterator function; must be called with the iterator state
+ and the current iterator value.
+ - Iterator state – an opaque value to be passed to the iterator
+ function.
+ - Initial iterator value.
+
+Usage:
+
+ for fp, mt, contents in pandoc.mediabag.items() do
+ -- print(fp, mt, contents)
+ end
+
### list {#mediabag-list}
`list ()`
diff --git a/pandoc.cabal b/pandoc.cabal
index ab67b5697..af509b2fd 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -591,6 +591,7 @@ library
Text.Pandoc.Lua.Marshaling.AST,
Text.Pandoc.Lua.Marshaling.AnyValue,
Text.Pandoc.Lua.Marshaling.CommonState,
+ Text.Pandoc.Lua.Marshaling.MediaBag,
Text.Pandoc.Lua.Marshaling.ReaderOptions,
Text.Pandoc.Lua.Marshaling.Version,
Text.Pandoc.Lua.Module.MediaBag,
diff --git a/src/Text/Pandoc/Lua/Marshaling/MediaBag.hs b/src/Text/Pandoc/Lua/Marshaling/MediaBag.hs
new file mode 100644
index 000000000..816843c1d
--- /dev/null
+++ b/src/Text/Pandoc/Lua/Marshaling/MediaBag.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{- |
+ Module : Text.Pandoc.Lua.Marshaling.MediaBag
+ Copyright : © 2012-2019 John MacFarlane
+ © 2017-2019 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+ Stability : alpha
+
+Instances to marshal (push) and unmarshal (peek) media data.
+-}
+module Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator) where
+
+import Prelude
+import Foreign.Ptr (Ptr)
+import Foreign.StablePtr (StablePtr, deRefStablePtr, newStablePtr)
+import Foreign.Lua (Lua, NumResults, Peekable, Pushable, StackIndex)
+import Foreign.Lua.Types.Peekable (reportValueOnFailure)
+import Foreign.Lua.Userdata (ensureUserdataMetatable, pushAnyWithMetatable,
+ toAnyWithName)
+import Text.Pandoc.MediaBag (MediaBag, mediaItems)
+import Text.Pandoc.MIME (MimeType)
+import Text.Pandoc.Lua.Marshaling.AnyValue (AnyValue (..))
+
+import qualified Data.ByteString.Lazy as BL
+import qualified Foreign.Lua as Lua
+import qualified Foreign.Storable as Storable
+
+-- | A list of 'MediaBag' items.
+newtype MediaItems = MediaItems [(String, MimeType, BL.ByteString)]
+
+instance Pushable MediaItems where
+ push = pushMediaItems
+
+instance Peekable MediaItems where
+ peek = peekMediaItems
+
+-- | Push an iterator triple to be used with Lua's @for@ loop construct.
+-- Each iterator invokation returns a tripple consisting of an item's
+-- filename, MIME type, and content.
+pushIterator :: MediaBag -> Lua NumResults
+pushIterator mb = do
+ Lua.pushHaskellFunction nextItem
+ Lua.push (MediaItems $ mediaItems mb)
+ Lua.pushnil
+ return 3
+
+-- | Lua type name for @'MediaItems'@.
+mediaItemsTypeName :: String
+mediaItemsTypeName = "pandoc MediaItems"
+
+-- | Push a @MediaItems@ element to the stack.
+pushMediaItems :: MediaItems -> Lua ()
+pushMediaItems xs = pushAnyWithMetatable pushMT xs
+ where
+ pushMT = ensureUserdataMetatable mediaItemsTypeName (return ())
+
+-- | Retrieve a @MediaItems@ element from the stack.
+peekMediaItems :: StackIndex -> Lua MediaItems
+peekMediaItems = reportValueOnFailure mediaItemsTypeName
+ (`toAnyWithName` mediaItemsTypeName)
+
+-- | Retrieve a list of items from an iterator state, return the first
+-- item (if present), and advance the state.
+nextItem :: Ptr (StablePtr MediaItems) -> AnyValue -> Lua NumResults
+nextItem ptr _ = do
+ (MediaItems items) <- Lua.liftIO $ deRefStablePtr =<< Storable.peek ptr
+ case items of
+ [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
+ (key, mt, content):xs -> do
+ Lua.liftIO $ Storable.poke ptr =<< newStablePtr (MediaItems xs)
+ Lua.push key
+ Lua.push mt
+ Lua.push content
+ return 3
diff --git a/src/Text/Pandoc/Lua/Module/MediaBag.hs b/src/Text/Pandoc/Lua/Module/MediaBag.hs
index 52aeaa1af..ce6303ec6 100644
--- a/src/Text/Pandoc/Lua/Module/MediaBag.hs
+++ b/src/Text/Pandoc/Lua/Module/MediaBag.hs
@@ -20,6 +20,7 @@ import Foreign.Lua (Lua, NumResults, Optional, liftIO)
import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
runIOorExplode, setMediaBag)
import Text.Pandoc.Lua.Marshaling ()
+import Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator)
import Text.Pandoc.Lua.Util (addFunction)
import Text.Pandoc.MIME (MimeType)
@@ -34,6 +35,7 @@ pushModule :: Lua NumResults
pushModule = do
Lua.newtable
addFunction "insert" insertMediaFn
+ addFunction "items" items
addFunction "lookup" lookupMediaFn
addFunction "list" mediaDirectoryFn
addFunction "fetch" fetch
@@ -66,9 +68,13 @@ insertMediaFn fp optionalMime contents = do
modifyCommonState $ \st ->
let mb = MB.insertMedia fp (Lua.fromOptional optionalMime) contents
(stMediaBag st)
- in st { stMediaBag = mb}
+ in st { stMediaBag = mb }
return 0
+-- | Returns iterator values to be used with a Lua @for@ loop.
+items :: Lua NumResults
+items = stMediaBag <$> getCommonState >>= pushIterator
+
lookupMediaFn :: FilePath
-> Lua NumResults
lookupMediaFn fp = do
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index f1e811232..94512b71d 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -19,6 +19,7 @@ module Text.Pandoc.MediaBag (
lookupMedia,
insertMedia,
mediaDirectory,
+ mediaItems
) where
import Prelude
import qualified Data.ByteString.Lazy as BL
@@ -66,3 +67,8 @@ mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
mediaDirectory (MediaBag mediamap) =
M.foldrWithKey (\fp (mime,contents) ->
((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
+
+mediaItems :: MediaBag -> [(String, MimeType, BL.ByteString)]
+mediaItems (MediaBag mediamap) =
+ M.foldrWithKey (\fp (mime,contents) ->
+ ((Posix.joinPath fp, mime, contents):)) [] mediamap