aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/Lua/Module/MediaBag.hs
blob: a1fc4073262e85741da8c0899f4ea44ae70fce7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Lua.Module.MediaBag
   Copyright   : Copyright © 2017-2021 Albert Krewinkel
   License     : GNU GPL, version 2 or above

   Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
   Stability   : alpha

The lua module @pandoc.mediabag@.
-}
module Text.Pandoc.Lua.Module.MediaBag
  ( pushModule
  ) where

import Prelude hiding (lookup)
import Control.Monad (zipWithM_)
import HsLua (LuaE, NumResults, Optional)
import HsLua.Marshalling (pushIterator)
import Text.Pandoc.Class.CommonState (CommonState (..))
import Text.Pandoc.Class.PandocMonad (fetchItem, getMediaBag, modifyCommonState,
                                      setMediaBag)
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Lua.Marshaling ()
import Text.Pandoc.Lua.PandocLua (PandocLua (..), liftPandocLua, addFunction)
import Text.Pandoc.MIME (MimeType)

import qualified Data.ByteString.Lazy as BL
import qualified Data.Text as T
import qualified HsLua as Lua
import qualified Text.Pandoc.MediaBag as MB

--
-- MediaBag submodule
--
pushModule :: PandocLua NumResults
pushModule = do
  liftPandocLua Lua.newtable
  addFunction "delete" delete
  addFunction "empty" empty
  addFunction "insert" insert
  addFunction "items" items
  addFunction "lookup" lookup
  addFunction "list" list
  addFunction "fetch" fetch
  return 1

-- | Delete a single item from the media bag.
delete :: FilePath -> PandocLua NumResults
delete fp = 0 <$ modifyCommonState
  (\st -> st { stMediaBag = MB.deleteMedia fp (stMediaBag st) })

-- | Delete all items from the media bag.
empty :: PandocLua NumResults
empty = 0 <$ modifyCommonState (\st -> st { stMediaBag = mempty })

-- | Insert a new item into the media bag.
insert :: FilePath
       -> Optional MimeType
       -> BL.ByteString
       -> PandocLua NumResults
insert fp optionalMime contents = do
  mb <- getMediaBag
  setMediaBag $ MB.insertMedia fp (Lua.fromOptional optionalMime) contents mb
  return (Lua.NumResults 0)

-- | Returns iterator values to be used with a Lua @for@ loop.
items :: PandocLua NumResults
items = do
  mb <- getMediaBag
  liftPandocLua $ do
    let pushItem (fp, mimetype, contents) = do
          Lua.pushString fp
          Lua.pushText mimetype
          Lua.pushByteString $ BL.toStrict contents
          return (Lua.NumResults 3)
    pushIterator pushItem (MB.mediaItems mb)

lookup :: FilePath
       -> PandocLua NumResults
lookup fp = do
  res <- MB.lookupMedia fp <$> getMediaBag
  liftPandocLua $ case res of
    Nothing -> 1 <$ Lua.pushnil
    Just item -> do
      Lua.push $ MB.mediaMimeType item
      Lua.push $ MB.mediaContents item
      return 2

list :: PandocLua NumResults
list = do
  dirContents <- MB.mediaDirectory <$> getMediaBag
  liftPandocLua $ do
    Lua.newtable
    zipWithM_ addEntry [1..] dirContents
  return 1
 where
  addEntry :: Lua.Integer -> (FilePath, MimeType, Int) -> LuaE PandocError ()
  addEntry idx (fp, mimeType, contentLength) = do
    Lua.newtable
    Lua.push ("path" :: T.Text) *> Lua.push fp *> Lua.rawset (-3)
    Lua.push ("type" :: T.Text) *> Lua.push mimeType *> Lua.rawset (-3)
    Lua.push ("length" :: T.Text) *> Lua.push contentLength *> Lua.rawset (-3)
    Lua.rawseti (-2) idx

fetch :: T.Text
      -> PandocLua NumResults
fetch src = do
  (bs, mimeType) <- fetchItem src
  liftPandocLua . Lua.push $ maybe "" T.unpack mimeType
  liftPandocLua $ Lua.push bs
  return 2 -- returns 2 values: contents, mimetype