Lua: use hslua module abstraction where possible
This will make it easier to generate module documentation in the future.
This commit is contained in:
parent
e1cf0ad1be
commit
f4d9b443d8
13 changed files with 382 additions and 409 deletions
120
data/pandoc.lua
120
data/pandoc.lua
|
@ -45,125 +45,19 @@ local utils = M.utils
|
||||||
-- @section
|
-- @section
|
||||||
-- @local
|
-- @local
|
||||||
|
|
||||||
--- Create a new indexing function.
|
|
||||||
-- @param template function template
|
|
||||||
-- @param indices list of indices, starting with the most deeply nested
|
|
||||||
-- @return newly created function
|
|
||||||
-- @local
|
|
||||||
function make_indexing_function(template, ...)
|
|
||||||
local indices = {...}
|
|
||||||
local loadstring = loadstring or load
|
|
||||||
local bracketed = {}
|
|
||||||
for i = 1, #indices do
|
|
||||||
local idx = indices[#indices - i + 1]
|
|
||||||
bracketed[i] = type(idx) == 'number'
|
|
||||||
and string.format('[%d]', idx)
|
|
||||||
or string.format('.%s', idx)
|
|
||||||
end
|
|
||||||
local fnstr = string.format('return ' .. template, table.concat(bracketed))
|
|
||||||
return assert(loadstring(fnstr))()
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Create accessor functions using a function template.
|
|
||||||
-- @param fn_template function template in which '%s' is replacd with indices
|
|
||||||
-- @param accessors list of accessors
|
|
||||||
-- @return mapping from accessor names to accessor functions
|
|
||||||
-- @local
|
|
||||||
local function create_accessor_functions (fn_template, accessors)
|
|
||||||
local res = {}
|
|
||||||
function add_accessors(acc, ...)
|
|
||||||
if type(acc) == 'string' then
|
|
||||||
res[acc] = make_indexing_function(fn_template, ...)
|
|
||||||
elseif type(acc) == 'table' and #acc == 0 and next(acc) then
|
|
||||||
-- Named substructure: the given names are accessed via the substructure,
|
|
||||||
-- but the accessors are also added to the result table, enabling direct
|
|
||||||
-- access from the parent element. Mainly used for `attr`.
|
|
||||||
local name, substructure = next(acc)
|
|
||||||
res[name] = make_indexing_function(fn_template, ...)
|
|
||||||
for _, subname in ipairs(substructure) do
|
|
||||||
res[subname] = make_indexing_function(fn_template, subname, ...)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i = 1, #(acc or {}) do
|
|
||||||
add_accessors(acc[i], i, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
add_accessors(accessors)
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get list of top-level fields from field descriptor table.
|
|
||||||
-- E.g.: `top_level_fields{'foo', {bar='baz'}, {'qux', 'quux'}}`
|
|
||||||
-- gives {'foo, 'bar', 'qux', 'quux'}
|
|
||||||
-- @local
|
|
||||||
local function top_level_fields (fields)
|
|
||||||
local result = List:new{}
|
|
||||||
for _, v in ipairs(fields) do
|
|
||||||
if type(v) == 'string' then
|
|
||||||
table.insert(result, v)
|
|
||||||
elseif type(v) == 'table' and #v == 0 and next(v) then
|
|
||||||
table.insert(result, (next(v)))
|
|
||||||
else
|
|
||||||
result:extend(top_level_fields(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Creates a function which behaves like next, but respects field names.
|
|
||||||
-- @local
|
|
||||||
local function make_next_function (fields)
|
|
||||||
local field_indices = {}
|
|
||||||
for i, f in ipairs(fields) do
|
|
||||||
field_indices[f] = i
|
|
||||||
end
|
|
||||||
|
|
||||||
return function (t, field)
|
|
||||||
local raw_idx = field == nil and 0 or field_indices[field]
|
|
||||||
local next_field = fields[raw_idx + 1]
|
|
||||||
return next_field, t[next_field]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Create a new table which allows to access numerical indices via accessor
|
--- Create a new table which allows to access numerical indices via accessor
|
||||||
-- functions.
|
-- functions.
|
||||||
-- @local
|
-- @local
|
||||||
local function create_accessor_behavior (tag, accessors)
|
local function create_accessor_behavior (tag)
|
||||||
local behavior = {tag = tag}
|
local behavior = {tag = tag}
|
||||||
behavior.getters = create_accessor_functions(
|
|
||||||
'function (x) return x.c%s end',
|
|
||||||
accessors
|
|
||||||
)
|
|
||||||
behavior.setters = create_accessor_functions(
|
|
||||||
'function (x, v) x.c%s = v end',
|
|
||||||
accessors
|
|
||||||
)
|
|
||||||
behavior.__eq = utils.equals
|
behavior.__eq = utils.equals
|
||||||
behavior.__index = function(t, k)
|
behavior.__index = function(t, k)
|
||||||
if getmetatable(t).getters[k] then
|
if k == "t" then
|
||||||
return getmetatable(t).getters[k](t)
|
|
||||||
elseif k == "t" then
|
|
||||||
return getmetatable(t)["tag"]
|
return getmetatable(t)["tag"]
|
||||||
else
|
|
||||||
return getmetatable(t)[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
behavior.__newindex = function(t, k, v)
|
|
||||||
if getmetatable(t).setters[k] then
|
|
||||||
getmetatable(t).setters[k](t, v)
|
|
||||||
else
|
|
||||||
rawset(t, k, v)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
behavior.__pairs = function (t)
|
behavior.__pairs = function (t)
|
||||||
if accessors == nil then
|
return next, t
|
||||||
return next, t
|
|
||||||
end
|
|
||||||
local iterable_fields = type(accessors) == 'string'
|
|
||||||
and {accessors}
|
|
||||||
or top_level_fields(accessors)
|
|
||||||
return make_next_function(iterable_fields), t
|
|
||||||
end
|
end
|
||||||
return behavior
|
return behavior
|
||||||
end
|
end
|
||||||
|
@ -242,8 +136,8 @@ end
|
||||||
-- @param fn Function to be called when constructing a new element
|
-- @param fn Function to be called when constructing a new element
|
||||||
-- @param accessors names to use as accessors for numerical fields
|
-- @param accessors names to use as accessors for numerical fields
|
||||||
-- @return function that constructs a new element
|
-- @return function that constructs a new element
|
||||||
function AstElement:create_constructor(tag, fn, accessors)
|
function AstElement:create_constructor(tag, fn)
|
||||||
local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
|
local constr = self:make_subtype(tag, create_accessor_behavior(tag))
|
||||||
function constr:new(...)
|
function constr:new(...)
|
||||||
return setmetatable(fn(...), self.behavior)
|
return setmetatable(fn(...), self.behavior)
|
||||||
end
|
end
|
||||||
|
@ -348,8 +242,4 @@ function M.MetaBool(bool)
|
||||||
return bool
|
return bool
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
-- Functions which have moved to different modules
|
|
||||||
M.sha1 = utils.sha1
|
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
@ -14,6 +14,7 @@ Types and functions for running Lua filters.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Filter ( LuaFilterFunction
|
module Text.Pandoc.Lua.Filter ( LuaFilterFunction
|
||||||
, LuaFilter
|
, LuaFilter
|
||||||
|
, peekLuaFilter
|
||||||
, runFilterFile
|
, runFilterFile
|
||||||
, walkInlines
|
, walkInlines
|
||||||
, walkInlineLists
|
, walkInlineLists
|
||||||
|
@ -68,20 +69,24 @@ newtype LuaFilterFunction = LuaFilterFunction Lua.Reference
|
||||||
newtype LuaFilter = LuaFilter (Map Name LuaFilterFunction)
|
newtype LuaFilter = LuaFilter (Map Name LuaFilterFunction)
|
||||||
|
|
||||||
instance Peekable LuaFilter where
|
instance Peekable LuaFilter where
|
||||||
peek idx = do
|
peek = Lua.forcePeek . peekLuaFilter
|
||||||
let constrs = listOfInlinesFilterName
|
|
||||||
: listOfBlocksFilterName
|
-- | Retrieves a LuaFilter object from the stack.
|
||||||
: metaFilterName
|
peekLuaFilter :: LuaError e => Peeker e LuaFilter
|
||||||
: pandocFilterNames
|
peekLuaFilter idx = do
|
||||||
++ blockElementNames
|
let constrs = listOfInlinesFilterName
|
||||||
++ inlineElementNames
|
: listOfBlocksFilterName
|
||||||
let go constr acc = do
|
: metaFilterName
|
||||||
Lua.getfield idx constr
|
: pandocFilterNames
|
||||||
filterFn <- registerFilterFunction
|
++ blockElementNames
|
||||||
return $ case filterFn of
|
++ inlineElementNames
|
||||||
Nothing -> acc
|
let go constr acc = Lua.liftLua $ do
|
||||||
Just fn -> Map.insert constr fn acc
|
Lua.getfield idx constr
|
||||||
LuaFilter <$!> foldrM go Map.empty constrs
|
filterFn <- registerFilterFunction
|
||||||
|
return $ case filterFn of
|
||||||
|
Nothing -> acc
|
||||||
|
Just fn -> Map.insert constr fn acc
|
||||||
|
LuaFilter <$!> foldrM go Map.empty constrs
|
||||||
|
|
||||||
-- | Register the function at the top of the stack as a filter function in the
|
-- | Register the function at the top of the stack as a filter function in the
|
||||||
-- registry.
|
-- registry.
|
||||||
|
|
|
@ -45,6 +45,7 @@ module Text.Pandoc.Lua.Marshaling.AST
|
||||||
, pushCitation
|
, pushCitation
|
||||||
, pushInline
|
, pushInline
|
||||||
, pushListAttributes
|
, pushListAttributes
|
||||||
|
, pushMeta
|
||||||
, pushMetaValue
|
, pushMetaValue
|
||||||
, pushPandoc
|
, pushPandoc
|
||||||
) where
|
) where
|
||||||
|
|
|
@ -204,26 +204,30 @@ peekAttrTable idx = do
|
||||||
return $ ident `seq` classes `seq` attribs `seq`
|
return $ ident `seq` classes `seq` attribs `seq`
|
||||||
(ident, classes, attribs)
|
(ident, classes, attribs)
|
||||||
|
|
||||||
mkAttr :: LuaError e => LuaE e NumResults
|
-- | Constructor for 'Attr'.
|
||||||
mkAttr = do
|
mkAttr :: LuaError e => DocumentedFunction e
|
||||||
attr <- ltype (nthBottom 1) >>= \case
|
mkAttr = defun "Attr"
|
||||||
TypeString -> forcePeek $ do
|
### (ltype (nthBottom 1) >>= \case
|
||||||
mident <- optional (peekText (nthBottom 1))
|
TypeString -> forcePeek $ do
|
||||||
mclass <- optional (peekList peekText (nthBottom 2))
|
mident <- optional (peekText (nthBottom 1))
|
||||||
mattribs <- optional (peekAttribs (nthBottom 3))
|
mclass <- optional (peekList peekText (nthBottom 2))
|
||||||
return (fromMaybe "" mident, fromMaybe [] mclass, fromMaybe [] mattribs)
|
mattribs <- optional (peekAttribs (nthBottom 3))
|
||||||
TypeTable -> forcePeek $ peekAttrTable (nthBottom 1)
|
return ( fromMaybe "" mident
|
||||||
TypeUserdata -> forcePeek $ peekUD typeAttr (nthBottom 1) <|> do
|
, fromMaybe [] mclass
|
||||||
attrList <- peekUD typeAttributeList (nthBottom 1)
|
, fromMaybe [] mattribs)
|
||||||
return ("", [], attrList)
|
TypeTable -> forcePeek $ peekAttrTable (nthBottom 1)
|
||||||
TypeNil -> pure nullAttr
|
TypeUserdata -> forcePeek $ peekUD typeAttr (nthBottom 1) <|> do
|
||||||
TypeNone -> pure nullAttr
|
attrList <- peekUD typeAttributeList (nthBottom 1)
|
||||||
x -> failLua $ "Cannot create Attr from " ++ show x
|
return ("", [], attrList)
|
||||||
pushAttr attr
|
TypeNil -> pure nullAttr
|
||||||
return 1
|
TypeNone -> pure nullAttr
|
||||||
|
x -> failLua $ "Cannot create Attr from " ++ show x)
|
||||||
|
=#> functionResult pushAttr "Attr" "new Attr object"
|
||||||
|
|
||||||
mkAttributeList :: LuaError e => LuaE e NumResults
|
-- | Constructor for 'AttributeList'.
|
||||||
mkAttributeList = do
|
mkAttributeList :: LuaError e => DocumentedFunction e
|
||||||
attribs <- forcePeek $ peekAttribs (nthBottom 1)
|
mkAttributeList = defun "AttributeList"
|
||||||
pushUD typeAttributeList attribs
|
### return
|
||||||
return 1
|
<#> parameter peekAttribs "table|AttributeList" "attribs" "an attribute list"
|
||||||
|
=#> functionResult (pushUD typeAttributeList) "AttributeList"
|
||||||
|
"new AttributeList object"
|
||||||
|
|
|
@ -1,112 +1,126 @@
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{- |
|
{- |
|
||||||
Module : Text.Pandoc.Lua.Module.MediaBag
|
Module : Text.Pandoc.Lua.Module.MediaBag
|
||||||
Copyright : Copyright © 2017-2021 Albert Krewinkel
|
Copyright : Copyright © 2017-2021 Albert Krewinkel
|
||||||
License : GNU GPL, version 2 or above
|
License : GNU GPL, version 2 or above
|
||||||
|
|
||||||
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
|
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
|
||||||
Stability : alpha
|
|
||||||
|
|
||||||
The lua module @pandoc.mediabag@.
|
The Lua module @pandoc.mediabag@.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Module.MediaBag
|
module Text.Pandoc.Lua.Module.MediaBag
|
||||||
( pushModule
|
( documentedModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude hiding (lookup)
|
import Prelude hiding (lookup)
|
||||||
import Control.Monad (zipWithM_)
|
import Data.Maybe (fromMaybe)
|
||||||
import HsLua (LuaE, NumResults, Optional)
|
import HsLua ( LuaE, DocumentedFunction, Module (..)
|
||||||
import HsLua.Marshalling (pushIterator)
|
, (<#>), (###), (=#>), (=?>), defun, functionResult
|
||||||
|
, optionalParameter , parameter)
|
||||||
import Text.Pandoc.Class.CommonState (CommonState (..))
|
import Text.Pandoc.Class.CommonState (CommonState (..))
|
||||||
import Text.Pandoc.Class.PandocMonad (fetchItem, getMediaBag, modifyCommonState,
|
import Text.Pandoc.Class.PandocMonad (fetchItem, getMediaBag, modifyCommonState,
|
||||||
setMediaBag)
|
setMediaBag)
|
||||||
import Text.Pandoc.Error (PandocError)
|
import Text.Pandoc.Error (PandocError)
|
||||||
import Text.Pandoc.Lua.Marshaling ()
|
import Text.Pandoc.Lua.Marshaling ()
|
||||||
import Text.Pandoc.Lua.PandocLua (PandocLua (..), liftPandocLua, addFunction)
|
import Text.Pandoc.Lua.Marshaling.List (pushPandocList)
|
||||||
|
import Text.Pandoc.Lua.PandocLua (unPandocLua)
|
||||||
import Text.Pandoc.MIME (MimeType)
|
import Text.Pandoc.MIME (MimeType)
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified HsLua as Lua
|
import qualified HsLua as Lua
|
||||||
import qualified Text.Pandoc.MediaBag as MB
|
import qualified Text.Pandoc.MediaBag as MB
|
||||||
|
|
||||||
--
|
--
|
||||||
-- MediaBag submodule
|
-- MediaBag submodule
|
||||||
--
|
--
|
||||||
pushModule :: PandocLua NumResults
|
documentedModule :: Module PandocError
|
||||||
pushModule = do
|
documentedModule = Module
|
||||||
liftPandocLua Lua.newtable
|
{ moduleName = "pandoc.mediabag"
|
||||||
addFunction "delete" delete
|
, moduleDescription = "mediabag access"
|
||||||
addFunction "empty" empty
|
, moduleFields = []
|
||||||
addFunction "insert" insert
|
, moduleFunctions =
|
||||||
addFunction "items" items
|
[ delete
|
||||||
addFunction "lookup" lookup
|
, empty
|
||||||
addFunction "list" list
|
, fetch
|
||||||
addFunction "fetch" fetch
|
, insert
|
||||||
return 1
|
, items
|
||||||
|
, list
|
||||||
|
, lookup
|
||||||
|
]
|
||||||
|
, moduleOperations = []
|
||||||
|
}
|
||||||
|
|
||||||
-- | Delete a single item from the media bag.
|
-- | Delete a single item from the media bag.
|
||||||
delete :: FilePath -> PandocLua NumResults
|
delete :: DocumentedFunction PandocError
|
||||||
delete fp = 0 <$ modifyCommonState
|
delete = defun "delete"
|
||||||
(\st -> st { stMediaBag = MB.deleteMedia fp (stMediaBag st) })
|
### (\fp -> unPandocLua $ modifyCommonState
|
||||||
|
(\st -> st { stMediaBag = MB.deleteMedia fp (stMediaBag st) }))
|
||||||
|
<#> parameter Lua.peekString "string" "filepath" "filename of item to delete"
|
||||||
|
=#> []
|
||||||
|
|
||||||
|
|
||||||
-- | Delete all items from the media bag.
|
-- | Delete all items from the media bag.
|
||||||
empty :: PandocLua NumResults
|
empty :: DocumentedFunction PandocError
|
||||||
empty = 0 <$ modifyCommonState (\st -> st { stMediaBag = mempty })
|
empty = defun "empty"
|
||||||
|
### unPandocLua (modifyCommonState (\st -> st { stMediaBag = mempty }))
|
||||||
|
=#> []
|
||||||
|
|
||||||
-- | Insert a new item into the media bag.
|
-- | Insert a new item into the media bag.
|
||||||
insert :: FilePath
|
insert :: DocumentedFunction PandocError
|
||||||
-> Optional MimeType
|
insert = defun "insert"
|
||||||
-> BL.ByteString
|
### (\fp mmime contents -> unPandocLua $ do
|
||||||
-> PandocLua NumResults
|
mb <- getMediaBag
|
||||||
insert fp optionalMime contents = do
|
setMediaBag $ MB.insertMedia fp mmime contents mb
|
||||||
mb <- getMediaBag
|
return (Lua.NumResults 0))
|
||||||
setMediaBag $ MB.insertMedia fp (Lua.fromOptional optionalMime) contents mb
|
<#> parameter Lua.peekString "string" "filepath" "item file path"
|
||||||
return (Lua.NumResults 0)
|
<#> optionalParameter Lua.peekText "string" "mimetype" "the item's MIME type"
|
||||||
|
<#> parameter Lua.peekLazyByteString "string" "contents" "binary contents"
|
||||||
|
=?> "Nothing"
|
||||||
|
|
||||||
-- | Returns iterator values to be used with a Lua @for@ loop.
|
-- | Returns iterator values to be used with a Lua @for@ loop.
|
||||||
items :: PandocLua NumResults
|
items :: DocumentedFunction PandocError
|
||||||
items = do
|
items = defun "items"
|
||||||
mb <- getMediaBag
|
### (do
|
||||||
liftPandocLua $ do
|
mb <-unPandocLua getMediaBag
|
||||||
let pushItem (fp, mimetype, contents) = do
|
let pushItem (fp, mimetype, contents) = do
|
||||||
Lua.pushString fp
|
Lua.pushString fp
|
||||||
Lua.pushText mimetype
|
Lua.pushText mimetype
|
||||||
Lua.pushByteString $ BL.toStrict contents
|
Lua.pushByteString $ BL.toStrict contents
|
||||||
return (Lua.NumResults 3)
|
return (Lua.NumResults 3)
|
||||||
pushIterator pushItem (MB.mediaItems mb)
|
Lua.pushIterator pushItem (MB.mediaItems mb))
|
||||||
|
=?> "Iterator triple"
|
||||||
|
|
||||||
lookup :: FilePath
|
-- | Function to lookup a value in the mediabag.
|
||||||
-> PandocLua NumResults
|
lookup :: DocumentedFunction PandocError
|
||||||
lookup fp = do
|
lookup = defun "lookup"
|
||||||
res <- MB.lookupMedia fp <$> getMediaBag
|
### (\fp -> unPandocLua (MB.lookupMedia fp <$> getMediaBag) >>= \case
|
||||||
liftPandocLua $ case res of
|
Nothing -> 1 <$ Lua.pushnil
|
||||||
Nothing -> 1 <$ Lua.pushnil
|
Just item -> 2 <$ do
|
||||||
Just item -> do
|
Lua.pushText $ MB.mediaMimeType item
|
||||||
Lua.push $ MB.mediaMimeType item
|
Lua.pushLazyByteString $ MB.mediaContents item)
|
||||||
Lua.push $ MB.mediaContents item
|
<#> parameter Lua.peekString "string" "filepath" "path of item to lookup"
|
||||||
return 2
|
=?> "MIME type and contents"
|
||||||
|
|
||||||
list :: PandocLua NumResults
|
-- | Function listing all mediabag items.
|
||||||
list = do
|
list :: DocumentedFunction PandocError
|
||||||
dirContents <- MB.mediaDirectory <$> getMediaBag
|
list = defun "list"
|
||||||
liftPandocLua $ do
|
### (unPandocLua (MB.mediaDirectory <$> getMediaBag))
|
||||||
Lua.newtable
|
=#> functionResult (pushPandocList pushEntry) "table" "list of entry triples"
|
||||||
zipWithM_ addEntry [1..] dirContents
|
|
||||||
return 1
|
|
||||||
where
|
where
|
||||||
addEntry :: Lua.Integer -> (FilePath, MimeType, Int) -> LuaE PandocError ()
|
pushEntry :: (FilePath, MimeType, Int) -> LuaE PandocError ()
|
||||||
addEntry idx (fp, mimeType, contentLength) = do
|
pushEntry (fp, mimeType, contentLength) = do
|
||||||
Lua.newtable
|
Lua.newtable
|
||||||
Lua.push ("path" :: T.Text) *> Lua.push fp *> Lua.rawset (-3)
|
Lua.pushName "path" *> Lua.pushString fp *> Lua.rawset (-3)
|
||||||
Lua.push ("type" :: T.Text) *> Lua.push mimeType *> Lua.rawset (-3)
|
Lua.pushName "type" *> Lua.pushText mimeType *> Lua.rawset (-3)
|
||||||
Lua.push ("length" :: T.Text) *> Lua.push contentLength *> Lua.rawset (-3)
|
Lua.pushName "length" *> Lua.pushIntegral contentLength *> Lua.rawset (-3)
|
||||||
Lua.rawseti (-2) idx
|
|
||||||
|
|
||||||
fetch :: T.Text
|
-- | Lua function to retrieve a new item.
|
||||||
-> PandocLua NumResults
|
fetch :: DocumentedFunction PandocError
|
||||||
fetch src = do
|
fetch = defun "fetch"
|
||||||
(bs, mimeType) <- fetchItem src
|
### (\src -> do
|
||||||
liftPandocLua . Lua.push $ maybe "" T.unpack mimeType
|
(bs, mimeType) <- unPandocLua $ fetchItem src
|
||||||
liftPandocLua $ Lua.push bs
|
Lua.pushText $ fromMaybe "" mimeType
|
||||||
return 2 -- returns 2 values: contents, mimetype
|
Lua.pushByteString bs
|
||||||
|
return 2)
|
||||||
|
<#> parameter Lua.peekText "string" "src" "URI to fetch"
|
||||||
|
=?> "Returns two string values: the fetched contents and the mimetype."
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
@ -14,11 +15,12 @@ Pandoc module for lua.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Module.Pandoc
|
module Text.Pandoc.Lua.Module.Pandoc
|
||||||
( pushModule
|
( pushModule
|
||||||
|
, documentedModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude hiding (read)
|
import Prelude hiding (read)
|
||||||
import Control.Applicative ((<|>), optional)
|
import Control.Applicative ((<|>))
|
||||||
import Control.Monad ((>=>), (<$!>), forM_, when)
|
import Control.Monad ((<$!>), forM_, when)
|
||||||
import Control.Monad.Catch (catch, throwM)
|
import Control.Monad.Catch (catch, throwM)
|
||||||
import Control.Monad.Except (throwError)
|
import Control.Monad.Except (throwError)
|
||||||
import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
|
import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
|
||||||
|
@ -26,13 +28,14 @@ import Data.Default (Default (..))
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Proxy (Proxy (Proxy))
|
import Data.Proxy (Proxy (Proxy))
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import HsLua as Lua hiding (Div, pushModule)
|
import HsLua hiding (Div, pushModule)
|
||||||
import HsLua.Class.Peekable (PeekError)
|
import HsLua.Class.Peekable (PeekError)
|
||||||
import System.Exit (ExitCode (..))
|
import System.Exit (ExitCode (..))
|
||||||
import Text.Pandoc.Class.PandocIO (runIO)
|
import Text.Pandoc.Class.PandocIO (runIO)
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Lua.Filter (SingletonsList (..), walkInlines,
|
import Text.Pandoc.Lua.Filter (SingletonsList (..), LuaFilter, peekLuaFilter,
|
||||||
walkInlineLists, walkBlocks, walkBlockLists)
|
walkInlines, walkInlineLists,
|
||||||
|
walkBlocks, walkBlockLists)
|
||||||
import Text.Pandoc.Lua.Marshaling ()
|
import Text.Pandoc.Lua.Marshaling ()
|
||||||
import Text.Pandoc.Lua.Marshaling.AST
|
import Text.Pandoc.Lua.Marshaling.AST
|
||||||
import Text.Pandoc.Lua.Marshaling.Attr (mkAttr, mkAttributeList)
|
import Text.Pandoc.Lua.Marshaling.Attr (mkAttr, mkAttributeList)
|
||||||
|
@ -40,13 +43,15 @@ import Text.Pandoc.Lua.Marshaling.List (List (..))
|
||||||
import Text.Pandoc.Lua.Marshaling.ListAttributes ( mkListAttributes
|
import Text.Pandoc.Lua.Marshaling.ListAttributes ( mkListAttributes
|
||||||
, peekListAttributes)
|
, peekListAttributes)
|
||||||
import Text.Pandoc.Lua.Marshaling.SimpleTable (mkSimpleTable)
|
import Text.Pandoc.Lua.Marshaling.SimpleTable (mkSimpleTable)
|
||||||
import Text.Pandoc.Lua.PandocLua (PandocLua, addFunction, liftPandocLua,
|
import Text.Pandoc.Lua.Module.Utils (sha1)
|
||||||
|
import Text.Pandoc.Lua.PandocLua (PandocLua, liftPandocLua,
|
||||||
loadDefaultModule)
|
loadDefaultModule)
|
||||||
import Text.Pandoc.Options (ReaderOptions (readerExtensions))
|
import Text.Pandoc.Options (ReaderOptions (readerExtensions))
|
||||||
import Text.Pandoc.Process (pipeProcess)
|
import Text.Pandoc.Process (pipeProcess)
|
||||||
import Text.Pandoc.Readers (Reader (..), getReader)
|
import Text.Pandoc.Readers (Reader (..), getReader)
|
||||||
import Text.Pandoc.Walk (Walkable)
|
import Text.Pandoc.Walk (Walkable)
|
||||||
|
|
||||||
|
import qualified HsLua as Lua
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified Data.ByteString.Lazy.Char8 as BSL
|
import qualified Data.ByteString.Lazy.Char8 as BSL
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
@ -57,45 +62,74 @@ import Text.Pandoc.Error
|
||||||
-- module to be loadable.
|
-- module to be loadable.
|
||||||
pushModule :: PandocLua NumResults
|
pushModule :: PandocLua NumResults
|
||||||
pushModule = do
|
pushModule = do
|
||||||
|
liftPandocLua $ Lua.pushModule documentedModule
|
||||||
loadDefaultModule "pandoc"
|
loadDefaultModule "pandoc"
|
||||||
addFunction "read" read
|
let copyNext = do
|
||||||
addFunction "pipe" pipe
|
hasNext <- next (nth 2)
|
||||||
addFunction "walk_block" (walkElement peekBlock pushBlock)
|
if not hasNext
|
||||||
addFunction "walk_inline" (walkElement peekInline pushInline)
|
then return ()
|
||||||
-- Constructors
|
else do
|
||||||
addFunction "Attr" (liftPandocLua mkAttr)
|
pushvalue (nth 2)
|
||||||
addFunction "AttributeList" (liftPandocLua mkAttributeList)
|
insert (nth 2)
|
||||||
addFunction "Pandoc" mkPandoc
|
rawset (nth 5) -- pandoc module
|
||||||
|
copyNext
|
||||||
liftPandocLua $ do
|
liftPandocLua $ do
|
||||||
let addConstr fn = do
|
pushnil -- initial key
|
||||||
pushName (functionName fn)
|
copyNext
|
||||||
pushDocumentedFunction fn
|
pop 1
|
||||||
rawset (nth 3)
|
|
||||||
forM_ otherConstructors addConstr
|
|
||||||
forM_ blockConstructors addConstr
|
|
||||||
forM_ inlineConstructors addConstr
|
|
||||||
let addConstructorTable constructors = do
|
|
||||||
-- add constructors to Inlines.constructor
|
|
||||||
newtable -- constructor
|
|
||||||
forM_ constructors $ \fn -> do
|
|
||||||
let name = functionName fn
|
|
||||||
pushName name
|
|
||||||
pushName name
|
|
||||||
rawget (nth 4)
|
|
||||||
rawset (nth 3)
|
|
||||||
-- set as pandoc.Inline.constructor
|
|
||||||
pushName "Inline"
|
|
||||||
newtable *> pushName "constructor" *>
|
|
||||||
pushvalue (nth 4) *> rawset (nth 3)
|
|
||||||
rawset (nth 4)
|
|
||||||
pop 1 -- remaining constructor table
|
|
||||||
addConstructorTable (blockConstructors @PandocError)
|
|
||||||
addConstructorTable (inlineConstructors @PandocError)
|
|
||||||
-- Add string constants
|
|
||||||
forM_ stringConstants $ \c -> do
|
|
||||||
pushString c *> pushString c *> rawset (nth 3)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
documentedModule :: Module PandocError
|
||||||
|
documentedModule = Module
|
||||||
|
{ moduleName = "pandoc"
|
||||||
|
, moduleDescription = T.unlines
|
||||||
|
[ "Lua functions for pandoc scripts; includes constructors for"
|
||||||
|
, "document elements, functions to parse text in a given"
|
||||||
|
, "format, and functions to filter and modify a subtree."
|
||||||
|
]
|
||||||
|
, moduleFields = stringConstants ++ [inlineField, blockField]
|
||||||
|
, moduleOperations = []
|
||||||
|
, moduleFunctions = mconcat
|
||||||
|
[ functions
|
||||||
|
, otherConstructors
|
||||||
|
, blockConstructors
|
||||||
|
, inlineConstructors
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Inline table field
|
||||||
|
inlineField :: Field PandocError
|
||||||
|
inlineField = Field
|
||||||
|
{ fieldName = "Inline"
|
||||||
|
, fieldDescription = "Inline constructors, nested under 'constructors'."
|
||||||
|
-- the nesting happens for historical reasons and should probably be
|
||||||
|
-- changed.
|
||||||
|
, fieldPushValue = pushWithConstructorsSubtable inlineConstructors
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | @Block@ module field
|
||||||
|
blockField :: Field PandocError
|
||||||
|
blockField = Field
|
||||||
|
{ fieldName = "Block"
|
||||||
|
, fieldDescription = "Inline constructors, nested under 'constructors'."
|
||||||
|
-- the nesting happens for historical reasons and should probably be
|
||||||
|
-- changed.
|
||||||
|
, fieldPushValue = pushWithConstructorsSubtable blockConstructors
|
||||||
|
}
|
||||||
|
|
||||||
|
pushWithConstructorsSubtable :: [DocumentedFunction PandocError]
|
||||||
|
-> LuaE PandocError ()
|
||||||
|
pushWithConstructorsSubtable constructors = do
|
||||||
|
newtable -- Field table
|
||||||
|
newtable -- constructor table
|
||||||
|
pushName "constructor" *> pushvalue (nth 2) *> rawset (nth 4)
|
||||||
|
forM_ constructors $ \fn -> do
|
||||||
|
pushName (functionName fn)
|
||||||
|
pushDocumentedFunction fn
|
||||||
|
rawset (nth 3)
|
||||||
|
pop 1 -- pop constructor table
|
||||||
|
|
||||||
inlineConstructors :: LuaError e => [DocumentedFunction e]
|
inlineConstructors :: LuaError e => [DocumentedFunction e]
|
||||||
inlineConstructors =
|
inlineConstructors =
|
||||||
[ defun "Cite"
|
[ defun "Cite"
|
||||||
|
@ -291,7 +325,13 @@ mkInlinesConstr name constr = defun name
|
||||||
|
|
||||||
otherConstructors :: LuaError e => [DocumentedFunction e]
|
otherConstructors :: LuaError e => [DocumentedFunction e]
|
||||||
otherConstructors =
|
otherConstructors =
|
||||||
[ defun "Citation"
|
[ defun "Pandoc"
|
||||||
|
### liftPure2 (\blocks mMeta -> Pandoc (fromMaybe nullMeta mMeta) blocks)
|
||||||
|
<#> parameter peekBlocksFuzzy "Blocks" "blocks" "document contents"
|
||||||
|
<#> optionalParameter peekMeta "Meta" "meta" "document metadata"
|
||||||
|
=#> functionResult pushPandoc "Pandoc" "new Pandoc document"
|
||||||
|
|
||||||
|
, defun "Citation"
|
||||||
### (\cid mode mprefix msuffix mnote_num mhash ->
|
### (\cid mode mprefix msuffix mnote_num mhash ->
|
||||||
cid `seq` mode `seq` mprefix `seq` msuffix `seq`
|
cid `seq` mode `seq` mprefix `seq` msuffix `seq`
|
||||||
mnote_num `seq` mhash `seq` return $! Citation
|
mnote_num `seq` mhash `seq` return $! Citation
|
||||||
|
@ -311,68 +351,93 @@ otherConstructors =
|
||||||
=#> functionResult pushCitation "Citation" "new citation object"
|
=#> functionResult pushCitation "Citation" "new citation object"
|
||||||
#? "Creates a single citation."
|
#? "Creates a single citation."
|
||||||
|
|
||||||
|
, mkAttr
|
||||||
|
, mkAttributeList
|
||||||
, mkListAttributes
|
, mkListAttributes
|
||||||
, mkSimpleTable
|
, mkSimpleTable
|
||||||
]
|
]
|
||||||
|
|
||||||
stringConstants :: [String]
|
stringConstants :: [Field e]
|
||||||
stringConstants =
|
stringConstants =
|
||||||
let constrs :: forall a. Data a => Proxy a -> [String]
|
let constrs :: forall a. Data a => Proxy a -> [String]
|
||||||
constrs _ = map showConstr . dataTypeConstrs . dataTypeOf @a $ undefined
|
constrs _ = map showConstr . dataTypeConstrs . dataTypeOf @a $ undefined
|
||||||
in constrs (Proxy @ListNumberStyle)
|
nullaryConstructors = mconcat
|
||||||
++ constrs (Proxy @ListNumberDelim)
|
[ constrs (Proxy @ListNumberStyle)
|
||||||
++ constrs (Proxy @QuoteType)
|
, constrs (Proxy @ListNumberDelim)
|
||||||
++ constrs (Proxy @MathType)
|
, constrs (Proxy @QuoteType)
|
||||||
++ constrs (Proxy @Alignment)
|
, constrs (Proxy @MathType)
|
||||||
++ constrs (Proxy @CitationMode)
|
, constrs (Proxy @Alignment)
|
||||||
|
, constrs (Proxy @CitationMode)
|
||||||
|
]
|
||||||
|
toField s = Field
|
||||||
|
{ fieldName = T.pack s
|
||||||
|
, fieldDescription = T.pack s
|
||||||
|
, fieldPushValue = pushString s
|
||||||
|
}
|
||||||
|
in map toField nullaryConstructors
|
||||||
|
|
||||||
walkElement :: (Walkable (SingletonsList Inline) a,
|
walkElement :: (Walkable (SingletonsList Inline) a,
|
||||||
Walkable (SingletonsList Block) a,
|
Walkable (SingletonsList Block) a,
|
||||||
Walkable (List Inline) a,
|
Walkable (List Inline) a,
|
||||||
Walkable (List Block) a)
|
Walkable (List Block) a)
|
||||||
=> Peeker PandocError a -> Pusher PandocError a
|
=> a -> LuaFilter -> LuaE PandocError a
|
||||||
-> LuaE PandocError NumResults
|
walkElement x f = walkInlines f x
|
||||||
walkElement peek' push' = do
|
>>= walkInlineLists f
|
||||||
x <- forcePeek $ peek' (nthBottom 1)
|
>>= walkBlocks f
|
||||||
f <- peek (nthBottom 2)
|
>>= walkBlockLists f
|
||||||
let walk' = walkInlines f
|
|
||||||
>=> walkInlineLists f
|
|
||||||
>=> walkBlocks f
|
|
||||||
>=> walkBlockLists f
|
|
||||||
walk' x >>= push'
|
|
||||||
return (NumResults 1)
|
|
||||||
|
|
||||||
read :: T.Text -> Optional T.Text -> PandocLua NumResults
|
functions :: [DocumentedFunction PandocError]
|
||||||
read content formatSpecOrNil = liftPandocLua $ do
|
functions =
|
||||||
let formatSpec = fromMaybe "markdown" (Lua.fromOptional formatSpecOrNil)
|
[ defun "pipe"
|
||||||
res <- Lua.liftIO . runIO $
|
### (\command args input -> do
|
||||||
getReader formatSpec >>= \(rdr,es) ->
|
(ec, output) <- Lua.liftIO $ pipeProcess Nothing command args input
|
||||||
case rdr of
|
`catch` (throwM . PandocIOError "pipe")
|
||||||
TextReader r ->
|
case ec of
|
||||||
r def{ readerExtensions = es } content
|
ExitSuccess -> 1 <$ Lua.pushLazyByteString output
|
||||||
_ -> throwError $ PandocSomeError
|
ExitFailure n -> do
|
||||||
"Only textual formats are supported"
|
pushPipeError (PipeError (T.pack command) n output)
|
||||||
case res of
|
Lua.error)
|
||||||
Right pd -> (1 :: NumResults) <$ Lua.push pd -- success, push Pandoc
|
<#> parameter peekString "string" "command" "path to executable"
|
||||||
Left (PandocUnknownReaderError f) -> Lua.raiseError $
|
<#> parameter (peekList peekString) "{string,...}" "args"
|
||||||
"Unknown reader: " <> f
|
"list of arguments"
|
||||||
Left (PandocUnsupportedExtensionError e f) -> Lua.raiseError $
|
<#> parameter peekLazyByteString "string" "input"
|
||||||
"Extension " <> e <> " not supported for " <> f
|
"input passed to process via stdin"
|
||||||
Left e -> Lua.raiseError $ show e
|
=?> "output string, or error triple"
|
||||||
|
|
||||||
-- | Pipes input through a command.
|
, defun "read"
|
||||||
pipe :: String -- ^ path to executable
|
### (\content mformatspec -> do
|
||||||
-> [String] -- ^ list of arguments
|
let formatSpec = fromMaybe "markdown" mformatspec
|
||||||
-> BL.ByteString -- ^ input passed to process via stdin
|
res <- Lua.liftIO . runIO $ getReader formatSpec >>= \case
|
||||||
-> PandocLua NumResults
|
(TextReader r, es) -> r def{ readerExtensions = es } content
|
||||||
pipe command args input = liftPandocLua $ do
|
_ -> throwError $ PandocSomeError
|
||||||
(ec, output) <- Lua.liftIO $ pipeProcess Nothing command args input
|
"Only textual formats are supported"
|
||||||
`catch` (throwM . PandocIOError "pipe")
|
case res of
|
||||||
case ec of
|
Right pd -> return pd -- success, got a Pandoc document
|
||||||
ExitSuccess -> 1 <$ Lua.push output
|
Left (PandocUnknownReaderError f) ->
|
||||||
ExitFailure n -> do
|
Lua.failLua . T.unpack $ "Unknown reader: " <> f
|
||||||
pushPipeError (PipeError (T.pack command) n output)
|
Left (PandocUnsupportedExtensionError e f) ->
|
||||||
Lua.error
|
Lua.failLua . T.unpack $
|
||||||
|
"Extension " <> e <> " not supported for " <> f
|
||||||
|
Left e ->
|
||||||
|
throwM e)
|
||||||
|
<#> parameter peekText "string" "content" "text to parse"
|
||||||
|
<#> optionalParameter peekText "string" "formatspec" "format and extensions"
|
||||||
|
=#> functionResult pushPandoc "Pandoc" "result document"
|
||||||
|
|
||||||
|
, sha1
|
||||||
|
|
||||||
|
, defun "walk_block"
|
||||||
|
### walkElement
|
||||||
|
<#> parameter peekBlockFuzzy "Block" "block" "element to traverse"
|
||||||
|
<#> parameter peekLuaFilter "LuaFilter" "filter" "filter functions"
|
||||||
|
=#> functionResult pushBlock "Block" "modified Block"
|
||||||
|
|
||||||
|
, defun "walk_inline"
|
||||||
|
### walkElement
|
||||||
|
<#> parameter peekInlineFuzzy "Inline" "inline" "element to traverse"
|
||||||
|
<#> parameter peekLuaFilter "LuaFilter" "filter" "filter functions"
|
||||||
|
=#> functionResult pushInline "Inline" "modified Inline"
|
||||||
|
]
|
||||||
|
|
||||||
data PipeError = PipeError
|
data PipeError = PipeError
|
||||||
{ pipeErrorCommand :: T.Text
|
{ pipeErrorCommand :: T.Text
|
||||||
|
@ -416,12 +481,3 @@ pushPipeError pipeErr = do
|
||||||
, if output == mempty then BSL.pack "<no output>" else output
|
, if output == mempty then BSL.pack "<no output>" else output
|
||||||
]
|
]
|
||||||
return (NumResults 1)
|
return (NumResults 1)
|
||||||
|
|
||||||
mkPandoc :: PandocLua NumResults
|
|
||||||
mkPandoc = liftPandocLua $ do
|
|
||||||
doc <- forcePeek $ do
|
|
||||||
blks <- peekBlocksFuzzy (nthBottom 1)
|
|
||||||
mMeta <- optional $ peekMeta (nthBottom 2)
|
|
||||||
pure $ Pandoc (fromMaybe nullMeta mMeta) blks
|
|
||||||
pushPandoc doc
|
|
||||||
return 1
|
|
||||||
|
|
|
@ -11,34 +11,28 @@
|
||||||
Pandoc's system Lua module.
|
Pandoc's system Lua module.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Module.System
|
module Text.Pandoc.Lua.Module.System
|
||||||
( pushModule
|
( documentedModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import HsLua hiding (pushModule)
|
import HsLua
|
||||||
import HsLua.Module.System
|
import HsLua.Module.System
|
||||||
(arch, env, getwd, os, with_env, with_tmpdir, with_wd)
|
(arch, env, getwd, os, with_env, with_tmpdir, with_wd)
|
||||||
import Text.Pandoc.Error (PandocError)
|
|
||||||
import Text.Pandoc.Lua.ErrorConversion ()
|
|
||||||
|
|
||||||
import qualified HsLua as Lua
|
|
||||||
|
|
||||||
-- | Push the pandoc.system module on the Lua stack.
|
-- | Push the pandoc.system module on the Lua stack.
|
||||||
pushModule :: LuaE PandocError NumResults
|
documentedModule :: LuaError e => Module e
|
||||||
pushModule = do
|
documentedModule = Module
|
||||||
Lua.pushModule $ Module
|
{ moduleName = "pandoc.system"
|
||||||
{ moduleName = "system"
|
, moduleDescription = "system functions"
|
||||||
, moduleDescription = "system functions"
|
, moduleFields =
|
||||||
, moduleFields =
|
[ arch
|
||||||
[ arch
|
, os
|
||||||
, os
|
]
|
||||||
]
|
, moduleFunctions =
|
||||||
, moduleFunctions =
|
[ setName "environment" env
|
||||||
[ setName "environment" env
|
, setName "get_working_directory" getwd
|
||||||
, setName "get_working_directory" getwd
|
, setName "with_environment" with_env
|
||||||
, setName "with_environment" with_env
|
, setName "with_temporary_directory" with_tmpdir
|
||||||
, setName "with_temporary_directory" with_tmpdir
|
, setName "with_working_directory" with_wd
|
||||||
, setName "with_working_directory" with_wd
|
]
|
||||||
]
|
, moduleOperations = []
|
||||||
, moduleOperations = []
|
}
|
||||||
}
|
|
||||||
return 1
|
|
||||||
|
|
|
@ -10,34 +10,52 @@
|
||||||
Pandoc data type constructors.
|
Pandoc data type constructors.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Module.Types
|
module Text.Pandoc.Lua.Module.Types
|
||||||
( pushModule
|
( documentedModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import HsLua (LuaE, NumResults, Peeker, Pusher)
|
import HsLua ( LuaE, NumResults, Peeker, Pusher, Module (..), Field (..)
|
||||||
|
, defun, functionResult, parameter, (###), (<#>), (=#>))
|
||||||
|
import HsLua.Module.Version (peekVersionFuzzy, pushVersion)
|
||||||
import Text.Pandoc.Error (PandocError)
|
import Text.Pandoc.Error (PandocError)
|
||||||
import Text.Pandoc.Lua.ErrorConversion ()
|
import Text.Pandoc.Lua.ErrorConversion ()
|
||||||
import Text.Pandoc.Lua.Marshaling.AST
|
import Text.Pandoc.Lua.Marshaling.AST
|
||||||
import Text.Pandoc.Lua.Util (addFunction)
|
|
||||||
|
|
||||||
import qualified HsLua as Lua
|
import qualified HsLua as Lua
|
||||||
import qualified HsLua.Module.Version as Version
|
|
||||||
|
|
||||||
-- | Push the pandoc.types module on the Lua stack.
|
-- | Push the pandoc.types module on the Lua stack.
|
||||||
pushModule :: LuaE PandocError NumResults
|
documentedModule :: Module PandocError
|
||||||
pushModule = do
|
documentedModule = Module
|
||||||
Lua.newtable
|
{ moduleName = "pandoc.types"
|
||||||
Lua.pushName "Version" *> Lua.pushModule Version.documentedModule
|
, moduleDescription =
|
||||||
*> Lua.rawset (Lua.nth 3)
|
"Constructors for types that are not part of the pandoc AST."
|
||||||
pushCloneTable
|
, moduleFields =
|
||||||
Lua.setfield (Lua.nth 2) "clone"
|
[ Field
|
||||||
return 1
|
{ fieldName = "clone"
|
||||||
|
, fieldDescription = "DEPRECATED! Helper functions for element cloning."
|
||||||
pushCloneTable :: LuaE PandocError NumResults
|
, fieldPushValue = do
|
||||||
pushCloneTable = do
|
Lua.newtable
|
||||||
Lua.newtable
|
addFunction "Meta" $ cloneWith peekMeta pushMeta
|
||||||
addFunction "Meta" $ cloneWith peekMeta Lua.push
|
addFunction "MetaValue" $ cloneWith peekMetaValue pushMetaValue
|
||||||
addFunction "MetaValue" $ cloneWith peekMetaValue pushMetaValue
|
}
|
||||||
return 1
|
]
|
||||||
|
, moduleFunctions =
|
||||||
|
[ defun "Version"
|
||||||
|
### return
|
||||||
|
<#> parameter peekVersionFuzzy "string|integer|{integer,...}|Version"
|
||||||
|
"version_specifier"
|
||||||
|
(mconcat [ "either a version string like `'2.7.3'`, "
|
||||||
|
, "a single integer like `2`, "
|
||||||
|
, "list of integers like `{2,7,3}`, "
|
||||||
|
, "or a Version object"
|
||||||
|
])
|
||||||
|
=#> functionResult pushVersion "Version" "A new Version object."
|
||||||
|
]
|
||||||
|
, moduleOperations = []
|
||||||
|
}
|
||||||
|
where addFunction name fn = do
|
||||||
|
Lua.pushName name
|
||||||
|
Lua.pushHaskellFunction fn
|
||||||
|
Lua.rawset (Lua.nth 3)
|
||||||
|
|
||||||
cloneWith :: Peeker PandocError a
|
cloneWith :: Peeker PandocError a
|
||||||
-> Pusher PandocError a
|
-> Pusher PandocError a
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
Utility module for Lua, exposing internal helper functions.
|
Utility module for Lua, exposing internal helper functions.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Lua.Module.Utils
|
module Text.Pandoc.Lua.Module.Utils
|
||||||
( pushModule
|
( documentedModule
|
||||||
|
, sha1
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
|
@ -21,7 +22,7 @@ import Control.Monad ((<$!>))
|
||||||
import Data.Data (showConstr, toConstr)
|
import Data.Data (showConstr, toConstr)
|
||||||
import Data.Default (def)
|
import Data.Default (def)
|
||||||
import Data.Version (Version)
|
import Data.Version (Version)
|
||||||
import HsLua as Lua hiding (pushModule)
|
import HsLua as Lua
|
||||||
import HsLua.Class.Peekable (PeekError)
|
import HsLua.Class.Peekable (PeekError)
|
||||||
import HsLua.Module.Version (peekVersionFuzzy, pushVersion)
|
import HsLua.Module.Version (peekVersionFuzzy, pushVersion)
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
|
@ -39,7 +40,6 @@ import Text.Pandoc.Lua.PandocLua (PandocLua (unPandocLua))
|
||||||
import qualified Data.Digest.Pure.SHA as SHA
|
import qualified Data.Digest.Pure.SHA as SHA
|
||||||
import qualified Data.ByteString.Lazy as BSL
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified HsLua.Packaging as Lua
|
|
||||||
import qualified Text.Pandoc.Builder as B
|
import qualified Text.Pandoc.Builder as B
|
||||||
import qualified Text.Pandoc.Filter.JSON as JSONFilter
|
import qualified Text.Pandoc.Filter.JSON as JSONFilter
|
||||||
import qualified Text.Pandoc.Shared as Shared
|
import qualified Text.Pandoc.Shared as Shared
|
||||||
|
@ -47,8 +47,8 @@ import qualified Text.Pandoc.UTF8 as UTF8
|
||||||
import qualified Text.Pandoc.Writers.Shared as Shared
|
import qualified Text.Pandoc.Writers.Shared as Shared
|
||||||
|
|
||||||
-- | Push the "pandoc.utils" module to the Lua stack.
|
-- | Push the "pandoc.utils" module to the Lua stack.
|
||||||
pandocUtilsModule :: Module PandocError
|
documentedModule :: Module PandocError
|
||||||
pandocUtilsModule = Module
|
documentedModule = Module
|
||||||
{ moduleName = "pandoc.utils"
|
{ moduleName = "pandoc.utils"
|
||||||
, moduleDescription = "pandoc utility functions"
|
, moduleDescription = "pandoc utility functions"
|
||||||
, moduleFields = []
|
, moduleFields = []
|
||||||
|
@ -92,12 +92,7 @@ pandocUtilsModule = Module
|
||||||
, "Returns nil instead of a string if the conversion failed."
|
, "Returns nil instead of a string if the conversion failed."
|
||||||
]
|
]
|
||||||
|
|
||||||
, defun "sha1"
|
, sha1
|
||||||
### liftPure (SHA.showDigest . SHA.sha1)
|
|
||||||
<#> parameter (fmap BSL.fromStrict . peekByteString) "string"
|
|
||||||
"input" ""
|
|
||||||
=#> functionResult pushString "string" "hexadecimal hash value"
|
|
||||||
#? "Compute the hash of the given string value."
|
|
||||||
|
|
||||||
, defun "Version"
|
, defun "Version"
|
||||||
### liftPure (id @Version)
|
### liftPure (id @Version)
|
||||||
|
@ -146,8 +141,13 @@ pandocUtilsModule = Module
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pushModule :: LuaE PandocError NumResults
|
-- | Documented Lua function to compute the hash of a string.
|
||||||
pushModule = 1 <$ Lua.pushModule pandocUtilsModule
|
sha1 :: DocumentedFunction e
|
||||||
|
sha1 = defun "sha1"
|
||||||
|
### liftPure (SHA.showDigest . SHA.sha1)
|
||||||
|
<#> parameter (fmap BSL.fromStrict . peekByteString) "string" "input" ""
|
||||||
|
=#> functionResult pushString "string" "hexadecimal hash value"
|
||||||
|
#? "Compute the hash of the given string value."
|
||||||
|
|
||||||
|
|
||||||
-- | Convert pandoc structure to a string with formatting removed.
|
-- | Convert pandoc structure to a string with formatting removed.
|
||||||
|
|
|
@ -16,7 +16,6 @@ module Text.Pandoc.Lua.Packages
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (forM_)
|
import Control.Monad (forM_)
|
||||||
import HsLua (NumResults)
|
|
||||||
import Text.Pandoc.Error (PandocError)
|
import Text.Pandoc.Error (PandocError)
|
||||||
import Text.Pandoc.Lua.PandocLua (PandocLua, liftPandocLua, loadDefaultModule)
|
import Text.Pandoc.Lua.PandocLua (PandocLua, liftPandocLua, loadDefaultModule)
|
||||||
|
|
||||||
|
@ -43,24 +42,27 @@ installPandocPackageSearcher = liftPandocLua $ do
|
||||||
Lua.rawseti (-2) (i + 1)
|
Lua.rawseti (-2) (i + 1)
|
||||||
|
|
||||||
-- | Load a pandoc module.
|
-- | Load a pandoc module.
|
||||||
pandocPackageSearcher :: String -> PandocLua NumResults
|
pandocPackageSearcher :: String -> PandocLua Lua.NumResults
|
||||||
pandocPackageSearcher pkgName =
|
pandocPackageSearcher pkgName =
|
||||||
case pkgName of
|
case pkgName of
|
||||||
"pandoc" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError Pandoc.pushModule
|
"pandoc" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError Pandoc.pushModule
|
||||||
"pandoc.mediabag" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError MediaBag.pushModule
|
"pandoc.mediabag" -> pushModuleLoader MediaBag.documentedModule
|
||||||
"pandoc.path" -> pushWrappedHsFun
|
"pandoc.path" -> pushModuleLoader Path.documentedModule
|
||||||
(Lua.NumResults 1 <$ Lua.pushModule @PandocError Path.documentedModule)
|
"pandoc.system" -> pushModuleLoader System.documentedModule
|
||||||
"pandoc.system" -> pushWrappedHsFun $ Lua.toHaskellFunction System.pushModule
|
"pandoc.types" -> pushModuleLoader Types.documentedModule
|
||||||
"pandoc.types" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError Types.pushModule
|
"pandoc.utils" -> pushModuleLoader Utils.documentedModule
|
||||||
"pandoc.utils" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError Utils.pushModule
|
"text" -> pushModuleLoader Text.documentedModule
|
||||||
"text" -> pushWrappedHsFun
|
"pandoc.List" -> pushWrappedHsFun . Lua.toHaskellFunction @PandocError $
|
||||||
(Lua.NumResults 1 <$ Lua.pushModule @PandocError Text.documentedModule)
|
loadDefaultModule pkgName
|
||||||
"pandoc.List" -> pushWrappedHsFun $ Lua.toHaskellFunction @PandocError (loadDefaultModule pkgName)
|
|
||||||
_ -> reportPandocSearcherFailure
|
_ -> reportPandocSearcherFailure
|
||||||
where
|
where
|
||||||
|
pushModuleLoader mdl = liftPandocLua $ do
|
||||||
|
Lua.pushHaskellFunction $
|
||||||
|
Lua.NumResults 1 <$ Lua.pushModule @PandocError mdl
|
||||||
|
return (Lua.NumResults 1)
|
||||||
pushWrappedHsFun f = liftPandocLua $ do
|
pushWrappedHsFun f = liftPandocLua $ do
|
||||||
Lua.pushHaskellFunction f
|
Lua.pushHaskellFunction f
|
||||||
return 1
|
return 1
|
||||||
reportPandocSearcherFailure = liftPandocLua $ do
|
reportPandocSearcherFailure = liftPandocLua $ do
|
||||||
Lua.push ("\n\t" <> pkgName <> "is not one of pandoc's default packages")
|
Lua.push ("\n\t" <> pkgName <> "is not one of pandoc's default packages")
|
||||||
return (1 :: NumResults)
|
return (Lua.NumResults 1)
|
||||||
|
|
|
@ -22,7 +22,6 @@ module Text.Pandoc.Lua.PandocLua
|
||||||
( PandocLua (..)
|
( PandocLua (..)
|
||||||
, runPandocLua
|
, runPandocLua
|
||||||
, liftPandocLua
|
, liftPandocLua
|
||||||
, addFunction
|
|
||||||
, loadDefaultModule
|
, loadDefaultModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -76,13 +75,6 @@ instance {-# OVERLAPPING #-} Exposable PandocError (PandocLua NumResults) where
|
||||||
instance Pushable a => Exposable PandocError (PandocLua a) where
|
instance Pushable a => Exposable PandocError (PandocLua a) where
|
||||||
partialApply _narg x = 1 <$ (unPandocLua x >>= Lua.push)
|
partialApply _narg x = 1 <$ (unPandocLua x >>= Lua.push)
|
||||||
|
|
||||||
-- | Add a function to the table at the top of the stack, using the given name.
|
|
||||||
addFunction :: Exposable PandocError a => Name -> a -> PandocLua ()
|
|
||||||
addFunction name fn = liftPandocLua $ do
|
|
||||||
Lua.pushName name
|
|
||||||
Lua.pushHaskellFunction $ toHaskellFunction fn
|
|
||||||
Lua.rawset (-3)
|
|
||||||
|
|
||||||
-- | Load a pure Lua module included with pandoc. Leaves the result on
|
-- | Load a pure Lua module included with pandoc. Leaves the result on
|
||||||
-- the stack and returns @NumResults 1@.
|
-- the stack and returns @NumResults 1@.
|
||||||
--
|
--
|
||||||
|
|
|
@ -18,7 +18,6 @@ Lua utility functions.
|
||||||
module Text.Pandoc.Lua.Util
|
module Text.Pandoc.Lua.Util
|
||||||
( getTag
|
( getTag
|
||||||
, addField
|
, addField
|
||||||
, addFunction
|
|
||||||
, callWithTraceback
|
, callWithTraceback
|
||||||
, dofileWithTraceback
|
, dofileWithTraceback
|
||||||
, pushViaConstr'
|
, pushViaConstr'
|
||||||
|
@ -35,14 +34,6 @@ addField key value = do
|
||||||
Lua.push value
|
Lua.push value
|
||||||
Lua.rawset (Lua.nth 3)
|
Lua.rawset (Lua.nth 3)
|
||||||
|
|
||||||
-- | Add a function to the table at the top of the stack, using the
|
|
||||||
-- given name.
|
|
||||||
addFunction :: Exposable e a => String -> a -> LuaE e ()
|
|
||||||
addFunction name fn = do
|
|
||||||
Lua.push name
|
|
||||||
Lua.pushHaskellFunction $ toHaskellFunction fn
|
|
||||||
Lua.rawset (-3)
|
|
||||||
|
|
||||||
-- | Get the tag of a value. This is an optimized and specialized version of
|
-- | Get the tag of a value. This is an optimized and specialized version of
|
||||||
-- @Lua.getfield idx "tag"@. It only checks for the field on the table at index
|
-- @Lua.getfield idx "tag"@. It only checks for the field on the table at index
|
||||||
-- @idx@ and on its metatable, also ignoring any @__index@ value on the
|
-- @idx@ and on its metatable, also ignoring any @__index@ value on the
|
||||||
|
|
|
@ -408,6 +408,12 @@ return {
|
||||||
})
|
})
|
||||||
assert.are_same(expected, pandoc.read(valid_markdown))
|
assert.are_same(expected, pandoc.read(valid_markdown))
|
||||||
end),
|
end),
|
||||||
|
test('unsupported extension', function ()
|
||||||
|
assert.error_matches(
|
||||||
|
function () pandoc.read('foo', 'gfm+empty_paragraphs') end,
|
||||||
|
'Extension empty_paragraphs not supported for gfm'
|
||||||
|
)
|
||||||
|
end),
|
||||||
test('failing read', function ()
|
test('failing read', function ()
|
||||||
assert.error_matches(
|
assert.error_matches(
|
||||||
function () pandoc.read('foo', 'nosuchreader') end,
|
function () pandoc.read('foo', 'nosuchreader') end,
|
||||||
|
|
Loading…
Add table
Reference in a new issue