mirror of
https://github.com/jgm/pandoc.git
synced 2026-08-28 17:20:47 +08:00
Lua: use proper interface functions to access the CommonState.
- The `PANDOC_STATE` is no longer a userdata object, but a table that behaves like the old object. - Log messages in `PANDOC_STATE.log` are now in temporal order.
This commit is contained in:
committed by
John MacFarlane
parent
57e7d895db
commit
75aee7a23c
+1
-2
@@ -2397,8 +2397,7 @@ Fields:
|
||||
: Output file from command line (string or nil)
|
||||
|
||||
`log`
|
||||
: A list of log messages in reverse order ([List] of
|
||||
[LogMessage]s)
|
||||
: A list of log messages ([List] of [LogMessage]s)
|
||||
|
||||
`request_headers`
|
||||
: Headers to add for HTTP requests; table with header names as
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{- |
|
||||
Module : Text.Pandoc.Lua
|
||||
@@ -16,14 +17,18 @@ module Text.Pandoc.Lua.Global
|
||||
|
||||
import HsLua as Lua
|
||||
import HsLua.Module.Version (pushVersion)
|
||||
import Text.Pandoc.Class (CommonState)
|
||||
import Text.Pandoc.Class ( getInputFiles, getOutputFile, getLog
|
||||
, getRequestHeaders, getResourcePath, getSourceURL
|
||||
, getUserDataDir, getTrace, getVerbosity
|
||||
)
|
||||
import Text.Pandoc.Definition (Pandoc, pandocTypesVersion)
|
||||
import Text.Pandoc.Error (PandocError)
|
||||
import Text.Pandoc.Lua.Marshal.CommonState (pushCommonState)
|
||||
import Text.Pandoc.Lua.Marshal.List (pushPandocList)
|
||||
import Text.Pandoc.Lua.Marshal.LogMessage (pushLogMessage)
|
||||
import Text.Pandoc.Lua.Marshal.Pandoc (pushPandoc)
|
||||
import Text.Pandoc.Lua.Marshal.ReaderOptions (pushReaderOptionsReadonly)
|
||||
import Text.Pandoc.Lua.Marshal.WriterOptions (pushWriterOptions)
|
||||
import Text.Pandoc.Lua.PandocLua ()
|
||||
import Text.Pandoc.Lua.PandocLua (unPandocLua)
|
||||
import Text.Pandoc.Options (ReaderOptions, WriterOptions)
|
||||
import Text.Pandoc.Version (pandocVersion)
|
||||
|
||||
@@ -37,7 +42,7 @@ data Global =
|
||||
| PANDOC_READER_OPTIONS ReaderOptions
|
||||
| PANDOC_WRITER_OPTIONS WriterOptions
|
||||
| PANDOC_SCRIPT_FILE FilePath
|
||||
| PANDOC_STATE CommonState
|
||||
| PANDOC_STATE
|
||||
| PANDOC_VERSION
|
||||
-- Cannot derive instance of Data because of CommonState
|
||||
|
||||
@@ -66,8 +71,47 @@ setGlobal global = case global of
|
||||
PANDOC_SCRIPT_FILE filePath -> do
|
||||
Lua.pushString filePath
|
||||
Lua.setglobal "PANDOC_SCRIPT_FILE"
|
||||
PANDOC_STATE commonState -> do
|
||||
pushCommonState commonState
|
||||
PANDOC_STATE -> do
|
||||
-- The common state is an opaque value. We provide a table that
|
||||
-- contains the values accessible through the PandocMonad API. This
|
||||
-- is for backwards compatibility, as the state used to be exposed
|
||||
-- as a read-only object.
|
||||
Lua.newtable
|
||||
Lua.newmetatable "CommonStateInterface"
|
||||
Lua.pushHaskellFunction $ do
|
||||
Lua.forcePeek (peekText (Lua.nthBottom 2)) >>= \case
|
||||
"input_files" -> do
|
||||
pushPandocList pushString =<< unPandocLua getInputFiles
|
||||
return 1
|
||||
"output_file" -> do
|
||||
maybe pushnil pushString =<< unPandocLua getOutputFile
|
||||
return 1
|
||||
"log" -> do
|
||||
pushPandocList pushLogMessage =<< unPandocLua getLog
|
||||
return 1
|
||||
"request_headers" -> do
|
||||
pushPandocList (pushPair pushText pushText)
|
||||
=<< unPandocLua getRequestHeaders
|
||||
return 1
|
||||
"resource_path" -> do
|
||||
pushPandocList pushString =<< unPandocLua getResourcePath
|
||||
return 1
|
||||
"source_url" -> do
|
||||
maybe pushnil pushText =<< unPandocLua getSourceURL
|
||||
return 1
|
||||
"user_data_dir" -> do
|
||||
maybe pushnil pushString =<< unPandocLua getUserDataDir
|
||||
return 1
|
||||
"trace" -> do
|
||||
pushBool =<< unPandocLua getTrace
|
||||
return 1
|
||||
"verbosity" -> do
|
||||
pushString . show =<< unPandocLua getVerbosity
|
||||
return 1
|
||||
_ ->
|
||||
failLua "Unknown key"
|
||||
Lua.setfield (Lua.nth 2) "__index"
|
||||
Lua.setmetatable (Lua.nth 2)
|
||||
Lua.setglobal "PANDOC_STATE"
|
||||
PANDOC_VERSION -> do
|
||||
pushVersion pandocVersion
|
||||
|
||||
@@ -16,41 +16,15 @@ module Text.Pandoc.Lua.Marshal.CommonState
|
||||
) where
|
||||
|
||||
import HsLua
|
||||
import Text.Pandoc.Class (CommonState (..))
|
||||
import Text.Pandoc.Lua.Marshal.List (pushPandocList)
|
||||
import Text.Pandoc.Lua.Marshal.LogMessage (pushLogMessage)
|
||||
import Text.Pandoc.Class (CommonState)
|
||||
|
||||
-- | Lua type used for the @CommonState@ object.
|
||||
--
|
||||
-- This is an opaque value that is required for the Lua interpreter
|
||||
-- to become an instance of "PandocMonad".
|
||||
--
|
||||
typeCommonState :: LuaError e => DocumentedType e CommonState
|
||||
typeCommonState = deftype "CommonState" []
|
||||
[ readonly "input_files" "input files passed to pandoc"
|
||||
(pushPandocList pushString, stInputFiles)
|
||||
|
||||
, readonly "output_file" "the file to which pandoc will write"
|
||||
(maybe pushnil pushString, stOutputFile)
|
||||
|
||||
, readonly "log" "list of log messages"
|
||||
(pushPandocList pushLogMessage, stLog)
|
||||
|
||||
, readonly "request_headers" "headers to add for HTTP requests"
|
||||
(pushPandocList (pushPair pushText pushText), stRequestHeaders)
|
||||
|
||||
, readonly "resource_path"
|
||||
"path to search for resources like included images"
|
||||
(pushPandocList pushString, stResourcePath)
|
||||
|
||||
, readonly "source_url" "absolute URL + dir of 1st source file"
|
||||
(maybe pushnil pushText, stSourceURL)
|
||||
|
||||
, readonly "user_data_dir" "directory to search for data files"
|
||||
(maybe pushnil pushString, stUserDataDir)
|
||||
|
||||
, readonly "trace" "controls whether tracing messages are issued"
|
||||
(pushBool, stTrace)
|
||||
|
||||
, readonly "verbosity" "verbosity level"
|
||||
(pushString . show, stVerbosity)
|
||||
]
|
||||
typeCommonState = deftype "CommonState" [] []
|
||||
|
||||
peekCommonState :: LuaError e => Peeker e CommonState
|
||||
peekCommonState = peekUD typeCommonState
|
||||
|
||||
@@ -14,14 +14,9 @@ module Text.Pandoc.Lua.Module.Log
|
||||
|
||||
import Data.Version (makeVersion)
|
||||
import HsLua
|
||||
import Text.Pandoc.Class
|
||||
( CommonState (stVerbosity, stLog)
|
||||
, PandocMonad (putCommonState, getCommonState)
|
||||
, report )
|
||||
import Text.Pandoc.Class (report, runSilently)
|
||||
import Text.Pandoc.Error (PandocError)
|
||||
import Text.Pandoc.Logging
|
||||
( Verbosity (ERROR)
|
||||
, LogMessage (ScriptingInfo, ScriptingWarning) )
|
||||
import Text.Pandoc.Logging (LogMessage (ScriptingInfo, ScriptingWarning))
|
||||
import Text.Pandoc.Lua.Marshal.List (pushPandocList)
|
||||
import Text.Pandoc.Lua.Marshal.LogMessage (pushLogMessage)
|
||||
import Text.Pandoc.Lua.PandocLua (liftPandocLua, unPandocLua)
|
||||
@@ -92,23 +87,12 @@ documentedModule = Module
|
||||
-- results of the function call after that.
|
||||
silence :: LuaE PandocError NumResults
|
||||
silence = unPandocLua $ do
|
||||
-- get current log messages
|
||||
origState <- getCommonState
|
||||
let origLog = stLog origState
|
||||
let origVerbosity = stVerbosity origState
|
||||
putCommonState (origState { stLog = [], stVerbosity = ERROR })
|
||||
|
||||
-- call function given as the first argument
|
||||
liftPandocLua $ do
|
||||
((), messages) <- runSilently . liftPandocLua $ do
|
||||
nargs <- (NumArgs . subtract 1 . fromStackIndex) <$> gettop
|
||||
call @PandocError nargs multret
|
||||
|
||||
-- restore original log messages
|
||||
newState <- getCommonState
|
||||
let newLog = stLog newState
|
||||
putCommonState (newState { stLog = origLog, stVerbosity = origVerbosity })
|
||||
|
||||
liftPandocLua $ do
|
||||
pushPandocList pushLogMessage newLog
|
||||
pushPandocList pushLogMessage messages
|
||||
insert 1
|
||||
(NumResults . fromStackIndex) <$> gettop
|
||||
|
||||
@@ -18,8 +18,7 @@ import Data.Version (makeVersion)
|
||||
import HsLua ( LuaE, DocumentedFunction, Module (..)
|
||||
, (<#>), (###), (=#>), (=?>), (#?), defun, functionResult
|
||||
, opt, parameter, since, stringParam, textParam)
|
||||
import Text.Pandoc.Class ( CommonState (..), fetchItem, fillMediaBag
|
||||
, getMediaBag, modifyCommonState, setMediaBag)
|
||||
import Text.Pandoc.Class ( fetchItem, fillMediaBag, getMediaBag, setMediaBag )
|
||||
import Text.Pandoc.Class.IO (writeMedia)
|
||||
import Text.Pandoc.Error (PandocError)
|
||||
import Text.Pandoc.Lua.Marshal.Pandoc (peekPandoc, pushPandoc)
|
||||
@@ -71,8 +70,9 @@ documentedModule = Module
|
||||
-- | Delete a single item from the media bag.
|
||||
delete :: DocumentedFunction PandocError
|
||||
delete = defun "delete"
|
||||
### (\fp -> unPandocLua $ modifyCommonState
|
||||
(\st -> st { stMediaBag = MB.deleteMedia fp (stMediaBag st) }))
|
||||
### (\fp -> unPandocLua $ do
|
||||
mb <- getMediaBag
|
||||
setMediaBag $ MB.deleteMedia fp mb)
|
||||
<#> stringParam "filepath"
|
||||
("Filename of the item to deleted. The media bag will be " <>
|
||||
"left unchanged if no entry with the given filename exists.")
|
||||
@@ -82,7 +82,7 @@ delete = defun "delete"
|
||||
-- | Delete all items from the media bag.
|
||||
empty :: DocumentedFunction PandocError
|
||||
empty = defun "empty"
|
||||
### unPandocLua (modifyCommonState (\st -> st { stMediaBag = mempty }))
|
||||
### unPandocLua (setMediaBag mempty)
|
||||
=#> []
|
||||
#? "Clear-out the media bag, deleting all items."
|
||||
|
||||
|
||||
@@ -81,9 +81,7 @@ instance PandocMonad PandocLua where
|
||||
forcePeek $ peekCommonState Lua.top `lastly` pop 1
|
||||
putCommonState cst = PandocLua $ do
|
||||
pushCommonState cst
|
||||
Lua.pushvalue Lua.top
|
||||
Lua.setfield registryindex "PANDOC_STATE"
|
||||
Lua.setglobal "PANDOC_STATE"
|
||||
|
||||
logOutput = IO.logOutput
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ runPandocLuaWith :: (PandocMonad m, MonadIO m)
|
||||
-> m a
|
||||
runPandocLuaWith runner pLua = do
|
||||
origState <- getCommonState
|
||||
globals <- defaultGlobals
|
||||
let globals = defaultGlobals
|
||||
(result, newState) <- liftIO . runner . unPandocLua $ do
|
||||
putCommonState origState
|
||||
liftPandocLua $ setGlobals globals
|
||||
@@ -72,11 +72,9 @@ runPandocLuaWith runner pLua = do
|
||||
return result
|
||||
|
||||
-- | Global variables which should always be set.
|
||||
defaultGlobals :: PandocMonad m => m [Global]
|
||||
defaultGlobals = do
|
||||
commonState <- getCommonState
|
||||
return
|
||||
[ PANDOC_API_VERSION
|
||||
, PANDOC_STATE commonState
|
||||
, PANDOC_VERSION
|
||||
]
|
||||
defaultGlobals :: [Global]
|
||||
defaultGlobals =
|
||||
[ PANDOC_API_VERSION
|
||||
, PANDOC_STATE
|
||||
, PANDOC_VERSION
|
||||
]
|
||||
|
||||
@@ -24,8 +24,7 @@ import Text.Pandoc.Builder (bulletList, definitionList, displayMath, divWith,
|
||||
linebreak, math, orderedList, para, plain, rawBlock,
|
||||
singleQuoted, space, str, strong,
|
||||
HasMeta (setMeta))
|
||||
import Text.Pandoc.Class ( CommonState (stVerbosity)
|
||||
, modifyCommonState, runIOorExplode, setUserDataDir)
|
||||
import Text.Pandoc.Class ( runIOorExplode, setUserDataDir, setVerbosity )
|
||||
import Text.Pandoc.Definition (Attr, Block (BlockQuote, Div, Para), Pandoc,
|
||||
Inline (Emph, Str), pandocTypesVersion)
|
||||
import Text.Pandoc.Error (PandocError (PandocLuaError))
|
||||
@@ -242,7 +241,7 @@ runLuaTest :: HasCallStack => Lua.LuaE PandocError a -> IO a
|
||||
runLuaTest op = runIOorExplode $ do
|
||||
-- Disable printing of warnings on stderr: some tests will generate
|
||||
-- warnings, we don't want to see those messages.
|
||||
modifyCommonState $ \st -> st { stVerbosity = ERROR }
|
||||
setVerbosity ERROR
|
||||
res <- runLua $ do
|
||||
setGlobals [ PANDOC_WRITER_OPTIONS def ]
|
||||
op
|
||||
|
||||
@@ -110,8 +110,8 @@ return {
|
||||
},
|
||||
|
||||
group 'PANDOC_STATE' {
|
||||
test('is a userdata object', function ()
|
||||
assert.are_equal(type(PANDOC_STATE), 'userdata')
|
||||
test('is a table object', function ()
|
||||
assert.are_equal(type(PANDOC_STATE), 'table')
|
||||
end),
|
||||
test('has property "input_files"', function ()
|
||||
assert.are_equal(type(PANDOC_STATE.input_files), 'table')
|
||||
|
||||
@@ -22,13 +22,13 @@ return {
|
||||
end),
|
||||
test('reports a warning', function ()
|
||||
log.info('info test')
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log[1]))
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log:at(-1)))
|
||||
assert.are_equal(msg.message, 'info test')
|
||||
assert.are_equal(msg.type, 'ScriptingInfo')
|
||||
end),
|
||||
test('info includes the correct number', function ()
|
||||
log.info('line number test')
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log[1]))
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log:at(-1)))
|
||||
-- THIS NEEDS UPDATING if lines above are shifted.
|
||||
assert.are_equal(msg.line, 30)
|
||||
end),
|
||||
@@ -40,7 +40,7 @@ return {
|
||||
end),
|
||||
test('reports a warning', function ()
|
||||
log.warn('testing')
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log[1]))
|
||||
local msg = json.decode(json.encode(PANDOC_STATE.log:at(-1)))
|
||||
assert.are_equal(msg.message, 'testing')
|
||||
assert.are_equal(msg.type, 'ScriptingWarning')
|
||||
end),
|
||||
|
||||
Reference in New Issue
Block a user