@@ -15,6 +15,10 @@ You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+#if !MIN_VERSION_hslua(0,9,0)
20+{-# OPTIONS_GHC -fno-warn-orphans #-}
19 Module : Text.Pandoc.Lua.PandocModule
23 Module : Text.Pandoc.Lua.PandocModule
20 Copyright : Copyright © 2017 Albert Krewinkel
24 Copyright : Copyright © 2017 Albert Krewinkel
@@ -25,28 +29,37 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26Pandoc module for lua.
30Pandoc module for lua.
28−module Text.Pandoc.Lua.PandocModule ( pushPandocModule ) where
32+module Text.Pandoc.Lua.PandocModule
30−import Control.Monad (unless)
37+import Control.Monad (unless, zipWithM_)
31import Data.ByteString.Char8 (unpack)
38import Data.ByteString.Char8 (unpack)
32import Data.Default (Default (..))
39import Data.Default (Default (..))
33import Data.Text (pack)
41import Data.Text (pack)
34−import Foreign.Lua (Lua, Status (OK), NumResults, call, loadstring, liftIO,
42+import Foreign.Lua (Lua, FromLuaStack, ToLuaStack, NumResults, liftIO)
35− push, pushHaskellFunction, rawset)
36−import Text.Pandoc.Class (readDataFile, runIO, runIOorExplode, setUserDataDir)
43+import Text.Pandoc.Class (fetchMediaResource, readDataFile, runIO,
44+ runIOorExplode, setUserDataDir)
37import Text.Pandoc.Options (ReaderOptions(readerExtensions))
45import Text.Pandoc.Options (ReaderOptions(readerExtensions))
38import Text.Pandoc.Lua.StackInstances ()
46import Text.Pandoc.Lua.StackInstances ()
39import Text.Pandoc.Readers (Reader (..), getReader)
47import Text.Pandoc.Readers (Reader (..), getReader)
48+import Text.Pandoc.MIME (MimeType)
50+import qualified Foreign.Lua as Lua
51+import qualified Data.ByteString.Lazy as BL
52+import qualified Text.Pandoc.MediaBag as MB
41-- | Push the "pandoc" on the lua stack.
54-- | Push the "pandoc" on the lua stack.
42pushPandocModule :: Maybe FilePath -> Lua ()
55pushPandocModule :: Maybe FilePath -> Lua ()
43pushPandocModule datadir = do
56pushPandocModule datadir = do
44 script <- liftIO (pandocModuleScript datadir)
57 script <- liftIO (pandocModuleScript datadir)
45− status <- loadstring script
58+ status <- Lua.loadstring script
46− unless (status /= OK) $ call 0 1
59+ unless (status /= Lua.OK) $ Lua.call 0 1
47− push "__read"
60+ Lua.push "__read"
48− pushHaskellFunction readDoc
61+ Lua.pushHaskellFunction readDoc
49− rawset (-3)
62+ Lua.rawset (-3)
51-- | Get the string representation of the pandoc module
64-- | Get the string representation of the pandoc module
52pandocModuleScript :: Maybe FilePath -> IO String
65pandocModuleScript :: Maybe FilePath -> IO String
@@ -56,14 +69,98 @@ pandocModuleScript datadir = unpack <$>
56readDoc :: String -> String -> Lua NumResults
69readDoc :: String -> String -> Lua NumResults
57readDoc formatSpec content = do
70readDoc formatSpec content = do
58 case getReader formatSpec of
71 case getReader formatSpec of
59− Left s -> push s -- Unknown reader
72+ Left s -> Lua.push s -- Unknown reader
60 Right (reader, es) ->
73 Right (reader, es) ->
61 case reader of
74 case reader of
62 TextReader r -> do
75 TextReader r -> do
63 res <- liftIO $ runIO $ r def{ readerExtensions = es } (pack content)
76 res <- liftIO $ runIO $ r def{ readerExtensions = es } (pack content)
64 case res of
77 case res of
65− Left s -> push $ show s -- error while reading
78+ Left s -> Lua.push $ show s -- error while reading
66− Right pd -> push pd -- success, push Pandoc
79+ Right pd -> Lua.push pd -- success, push Pandoc
67− _ -> push "Only string formats are supported at the moment."
80+ _ -> Lua.push "Only string formats are supported at the moment."
86+pushMediaBagModule :: IORef MB.MediaBag -> Lua ()
87+pushMediaBagModule mediaBagRef = do
89+ addFunction "insert" (insertMediaFn mediaBagRef)
90+ addFunction "lookup" (lookupMediaFn mediaBagRef)
91+ addFunction "list" (mediaDirectoryFn mediaBagRef)
92+ addFunction "fetch" (insertResource mediaBagRef)
95+ addFunction name fn = do
97+ Lua.pushHaskellFunction fn
100+insertMediaFn :: IORef MB.MediaBag
105+insertMediaFn mbRef fp nilOrMime contents = do
106+ liftIO . modifyIORef' mbRef $ MB.insertMedia fp (toMaybe nilOrMime) contents
109+lookupMediaFn :: IORef MB.MediaBag
112+lookupMediaFn mbRef fp = do
113+ res <- MB.lookupMedia fp <$> liftIO (readIORef mbRef)
115+ Nothing -> Lua.pushnil *> return 1
116+ Just (mimeType, contents) -> do
121+mediaDirectoryFn :: IORef MB.MediaBag
123+mediaDirectoryFn mbRef = do
124+ dirContents <- MB.mediaDirectory <$> liftIO (readIORef mbRef)
126+ zipWithM_ addEntry [1..] dirContents
129+ addEntry :: Int -> (FilePath, MimeType, Int) -> Lua ()
130+ addEntry idx (fp, mimeType, contentLength) = do
132+ Lua.push "path" *> Lua.push fp *> Lua.rawset (-3)
133+ Lua.push "type" *> Lua.push mimeType *> Lua.rawset (-3)
134+ Lua.push "length" *> Lua.push contentLength *> Lua.rawset (-3)
135+ Lua.rawseti (-2) idx
137+insertResource :: IORef MB.MediaBag
141+insertResource mbRef src sourceUrlOrNil = do
142+ (fp, mimeType, bs) <- liftIO . runIOorExplode $
143+ fetchMediaResource (toMaybe sourceUrlOrNil) src
144+ liftIO $ print (fp, mimeType)
145+ insertMediaFn mbRef fp (OrNil mimeType) bs
148+-- Helper types and orphan instances
151+newtype OrNil a = OrNil { toMaybe :: Maybe a }
153+instance FromLuaStack a => FromLuaStack (OrNil a) where
155+ noValue <- Lua.isnil idx
157+ then return (OrNil Nothing)
158+ else OrNil . Just <$> Lua.peek idx
160+#if !MIN_VERSION_hslua(0,9,0)
161+instance ToLuaStack BL.ByteString where
162+ push = Lua.push . BL.toStrict
164+instance FromLuaStack BL.ByteString where
165+ peek = fmap BL.fromStrict . Lua.peek