@@ -38,14 +38,18 @@ import Prelude
3838import Control.Applicative ((<|>))
3939import Data.Data (showConstr, toConstr)
4040import Foreign.Lua (Lua, Peekable, Pushable, StackIndex)
41+import Foreign.Lua.Types.Peekable (reportValueOnFailure)
4142import Foreign.Lua.Userdata ( ensureUserdataMetatable, pushAnyWithMetatable
42− , metatableName)
43+ , toAnyWithName, metatableName)
44+import Text.Pandoc.Class (CommonState (..))
4345import Text.Pandoc.Definition
4446import Text.Pandoc.Extensions (Extensions)
47+import Text.Pandoc.Logging (LogMessage, showLogMessage)
4548import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor)
4649import Text.Pandoc.Options (ReaderOptions (..), TrackChanges)
4750import Text.Pandoc.Shared (Element (Blk, Sec))
4851
52+import qualified Data.Map as Map
4953import qualified Data.Set as Set
5054import qualified Foreign.Lua as Lua
5155import qualified Text.Pandoc.Lua.Util as LuaUtil
@@ -386,5 +390,85 @@ instance Pushable ReaderOptions where
386390-- | Dummy type to allow values of arbitrary Lua type.
387391newtype AnyValue = AnyValue StackIndex
388392
393+--
394+-- TODO: Much of the following should be abstracted, factored out
395+-- and go into HsLua.
396+--
397+
389398instance Peekable AnyValue where
390399 peek = return . AnyValue
400+
401+-- | Name used by Lua for the @CommonState@ type.
402+commonStateTypeName :: String
403+commonStateTypeName = "Pandoc CommonState"
404+
405+instance Peekable CommonState where
406+ peek idx = reportValueOnFailure commonStateTypeName
407+ (`toAnyWithName` commonStateTypeName) idx
408+
409+instance Pushable CommonState where
410+ push st = pushAnyWithMetatable pushCommonStateMetatable st
411+ where
412+ pushCommonStateMetatable = ensureUserdataMetatable commonStateTypeName $ do
413+ LuaUtil.addFunction "__index" indexCommonState
414+ LuaUtil.addFunction "__pairs" pairsCommonState
415+
416+indexCommonState :: CommonState -> AnyValue -> Lua Lua.NumResults
417+indexCommonState st (AnyValue idx) = Lua.ltype idx >>= \case
418+ Lua.TypeString -> 1 <$ (Lua.peek idx >>= pushField)
419+ _ -> 1 <$ Lua.pushnil
420+ where
421+ pushField :: String -> Lua ()
422+ pushField name = case lookup name commonStateFields of
423+ Just pushValue -> pushValue st
424+ Nothing -> Lua.pushnil
425+
426+pairsCommonState :: CommonState -> Lua Lua.NumResults
427+pairsCommonState st = do
428+ Lua.pushHaskellFunction nextFn
429+ Lua.pushnil
430+ Lua.pushnil
431+ return 3
432+ where
433+ nextFn :: AnyValue -> AnyValue -> Lua Lua.NumResults
434+ nextFn _ (AnyValue idx) =
435+ Lua.ltype idx >>= \case
436+ Lua.TypeNil -> case commonStateFields of
437+ [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
438+ (key, pushValue):_ -> 2 <$ (Lua.push key *> pushValue st)
439+ Lua.TypeString -> do
440+ key <- Lua.peek idx
441+ case tail $ dropWhile ((/= key) . fst) commonStateFields of
442+ [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
443+ (nextKey, pushValue):_ -> 2 <$ (Lua.push nextKey *> pushValue st)
444+ _ -> 2 <$ (Lua.pushnil *> Lua.pushnil)
445+
446+commonStateFields :: [(String, CommonState -> Lua ())]
447+commonStateFields =
448+ [ ("input_files", Lua.push . stInputFiles)
449+ , ("output_file", Lua.push . Lua.Optional . stOutputFile)
450+ , ("log", Lua.push . stLog)
451+ , ("request_headers", Lua.push . Map.fromList . stRequestHeaders)
452+ , ("resource_path", Lua.push . stResourcePath)
453+ , ("source_url", Lua.push . Lua.Optional . stSourceURL)
454+ , ("user_data_dir", Lua.push . Lua.Optional . stUserDataDir)
455+ , ("trace", Lua.push . stTrace)
456+ , ("verbosity", Lua.push . show . stVerbosity)
457+ ]
458+
459+-- | Name used by Lua for the @CommonState@ type.
460+logMessageTypeName :: String
461+logMessageTypeName = "Pandoc LogMessage"
462+
463+instance Peekable LogMessage where
464+ peek idx = reportValueOnFailure logMessageTypeName
465+ (`toAnyWithName` logMessageTypeName) idx
466+
467+instance Pushable LogMessage where
468+ push msg = pushAnyWithMetatable pushLogMessageMetatable msg
469+ where
470+ pushLogMessageMetatable = ensureUserdataMetatable logMessageTypeName $
471+ LuaUtil.addFunction "__tostring" tostringLogMessage
472+
473+tostringLogMessage :: LogMessage -> Lua String
474+tostringLogMessage = return . showLogMessage