    {-# LANGUAGE LambdaCase         #-}
    {-# LANGUAGE OverloadedStrings  #-}
    {- |
       Module      : Text.Pandoc.Lua
       Copyright   : Copyright © 2017-2024 Albert Krewinkel
       License     : GNU GPL, version 2 or above

       Maintainer  : Albert Krewinkel <albert+pandoc@tarleb.com>
       Stability   : alpha

    Pandoc's Lua globals.
    -}
    module Text.Pandoc.Lua.Global
      ( Global (..)
      , setGlobals
      ) where

    import HsLua as Lua
    import HsLua.Module.Version (pushVersion)
    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.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 (unPandocLua)
    import Text.Pandoc.Options (ReaderOptions, WriterOptions)
    import Text.Pandoc.Version (pandocVersion)

    import qualified Data.Text as Text

    -- | Permissible global Lua variables.
    data Global =
        FORMAT Text.Text
      | PANDOC_API_VERSION
      | PANDOC_DOCUMENT Pandoc
      | PANDOC_READER_OPTIONS ReaderOptions
      | PANDOC_WRITER_OPTIONS WriterOptions
      | PANDOC_SCRIPT_FILE FilePath
      | PANDOC_STATE
      | PANDOC_VERSION
      -- Cannot derive instance of Data because of CommonState

    -- | Set all given globals.
    setGlobals :: [Global] -> LuaE PandocError ()
    setGlobals :: [Global] -> LuaE PandocError ()
    setGlobals = (Global -> LuaE PandocError ()) -> [Global] -> LuaE PandocError ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Global -> LuaE PandocError ()
    setGlobal

    setGlobal :: Global -> LuaE PandocError ()
    setGlobal :: Global -> LuaE PandocError ()
    setGlobal Global
    global = case Global
    global of
      -- This could be simplified if Global was an instance of Data.
      FORMAT Text
    format -> do
        Pusher PandocError Text
    forall e. Pusher e Text
    Lua.pushText Text
    format
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "FORMAT"
      Global
    PANDOC_API_VERSION -> do
        Pusher PandocError Version
    forall e. LuaError e => Pusher e Version
    pushVersion Version
    pandocTypesVersion
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_API_VERSION"
      PANDOC_DOCUMENT Pandoc
    doc -> do
        Pusher PandocError Pandoc
    forall e. LuaError e => Pusher e Pandoc
    pushPandoc Pandoc
    doc
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_DOCUMENT"
      PANDOC_READER_OPTIONS ReaderOptions
    ropts -> do
        Pusher PandocError ReaderOptions
    forall e. LuaError e => Pusher e ReaderOptions
    pushReaderOptionsReadonly ReaderOptions
    ropts
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_READER_OPTIONS"
      PANDOC_WRITER_OPTIONS WriterOptions
    wopts -> do
        Pusher PandocError WriterOptions
    pushWriterOptions WriterOptions
    wopts
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_WRITER_OPTIONS"
      PANDOC_SCRIPT_FILE String
    filePath -> do
        String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    Lua.pushString String
    filePath
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_SCRIPT_FILE"
      Global
    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.
        LuaE PandocError ()
    forall e. LuaE e ()
    Lua.newtable
        Name -> LuaE PandocError Bool
    forall e. Name -> LuaE e Bool
    Lua.newmetatable Name
    "CommonStateInterface"
        HaskellFunction PandocError -> LuaE PandocError ()
    forall e. LuaError e => HaskellFunction e -> LuaE e ()
    Lua.pushHaskellFunction (HaskellFunction PandocError -> LuaE PandocError ())
    -> HaskellFunction PandocError -> LuaE PandocError ()
    forall a b. (a -> b) -> a -> b
    $ do
          Peek PandocError Text -> LuaE PandocError Text
    forall e a. LuaError e => Peek e a -> LuaE e a
    Lua.forcePeek (Peeker PandocError Text
    forall e. Peeker e Text
    peekText (CInt -> StackIndex
    Lua.nthBottom CInt
    2)) LuaE PandocError Text
    -> (Text -> HaskellFunction PandocError)
    -> HaskellFunction PandocError
    forall a b.
    LuaE PandocError a
    -> (a -> LuaE PandocError b) -> LuaE PandocError b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \case
            Text
    "input_files" -> do
              (String -> LuaE PandocError ()) -> Pusher PandocError [String]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    pushString Pusher PandocError [String]
    -> LuaE PandocError [String] -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua [String] -> LuaE PandocError [String]
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua [String]
    forall (m :: * -> *). PandocMonad m => m [String]
    getInputFiles
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "output_file" -> do
              LuaE PandocError ()
    -> (String -> LuaE PandocError ())
    -> Maybe String
    -> LuaE PandocError ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe LuaE PandocError ()
    forall e. LuaE e ()
    pushnil String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    pushString (Maybe String -> LuaE PandocError ())
    -> LuaE PandocError (Maybe String) -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua (Maybe String) -> LuaE PandocError (Maybe String)
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua (Maybe String)
    forall (m :: * -> *). PandocMonad m => m (Maybe String)
    getOutputFile
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "log" -> do
              Pusher PandocError LogMessage -> Pusher PandocError [LogMessage]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher PandocError LogMessage
    forall e. LuaError e => Pusher e LogMessage
    pushLogMessage Pusher PandocError [LogMessage]
    -> LuaE PandocError [LogMessage] -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua [LogMessage] -> LuaE PandocError [LogMessage]
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua [LogMessage]
    forall (m :: * -> *). PandocMonad m => m [LogMessage]
    getLog
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "request_headers" -> do
              Pusher PandocError (Text, Text)
    -> Pusher PandocError [(Text, Text)]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList (Pusher PandocError Text
    -> Pusher PandocError Text -> Pusher PandocError (Text, Text)
    forall e a b.
    LuaError e =>
    Pusher e a -> Pusher e b -> (a, b) -> LuaE e ()
    pushPair Pusher PandocError Text
    forall e. Pusher e Text
    pushText Pusher PandocError Text
    forall e. Pusher e Text
    pushText)
                       Pusher PandocError [(Text, Text)]
    -> LuaE PandocError [(Text, Text)] -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua [(Text, Text)] -> LuaE PandocError [(Text, Text)]
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua [(Text, Text)]
    forall (m :: * -> *). PandocMonad m => m [(Text, Text)]
    getRequestHeaders
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "resource_path" -> do
              (String -> LuaE PandocError ()) -> Pusher PandocError [String]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    pushString Pusher PandocError [String]
    -> LuaE PandocError [String] -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua [String] -> LuaE PandocError [String]
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua [String]
    forall (m :: * -> *). PandocMonad m => m [String]
    getResourcePath
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "source_url" -> do
              LuaE PandocError ()
    -> Pusher PandocError Text -> Maybe Text -> LuaE PandocError ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe LuaE PandocError ()
    forall e. LuaE e ()
    pushnil Pusher PandocError Text
    forall e. Pusher e Text
    pushText (Maybe Text -> LuaE PandocError ())
    -> LuaE PandocError (Maybe Text) -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua (Maybe Text) -> LuaE PandocError (Maybe Text)
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua (Maybe Text)
    forall (m :: * -> *). PandocMonad m => m (Maybe Text)
    getSourceURL
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "user_data_dir" -> do
              LuaE PandocError ()
    -> (String -> LuaE PandocError ())
    -> Maybe String
    -> LuaE PandocError ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe LuaE PandocError ()
    forall e. LuaE e ()
    pushnil String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    pushString (Maybe String -> LuaE PandocError ())
    -> LuaE PandocError (Maybe String) -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua (Maybe String) -> LuaE PandocError (Maybe String)
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua (Maybe String)
    forall (m :: * -> *). PandocMonad m => m (Maybe String)
    getUserDataDir
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "trace" -> do
              Pusher PandocError Bool
    forall e. Pusher e Bool
    pushBool Pusher PandocError Bool
    -> LuaE PandocError Bool -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua Bool -> LuaE PandocError Bool
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua Bool
    forall (m :: * -> *). PandocMonad m => m Bool
    getTrace
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    "verbosity" -> do
              String -> LuaE PandocError ()
    forall e. String -> LuaE e ()
    pushString (String -> LuaE PandocError ())
    -> (Verbosity -> String) -> Verbosity -> LuaE PandocError ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Verbosity -> String
    forall a. Show a => a -> String
    show (Verbosity -> LuaE PandocError ())
    -> LuaE PandocError Verbosity -> LuaE PandocError ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< PandocLua Verbosity -> LuaE PandocError Verbosity
    forall a. PandocLua a -> LuaE PandocError a
    unPandocLua PandocLua Verbosity
    forall (m :: * -> *). PandocMonad m => m Verbosity
    getVerbosity
              NumResults -> HaskellFunction PandocError
    forall a. a -> LuaE PandocError a
    forall (m :: * -> *) a. Monad m => a -> m a
    return NumResults
    1
            Text
    _ ->
              String -> HaskellFunction PandocError
    forall e a. LuaError e => String -> LuaE e a
    failLua String
    "Unknown key"
        StackIndex -> Name -> LuaE PandocError ()
    forall e. LuaError e => StackIndex -> Name -> LuaE e ()
    Lua.setfield (CInt -> StackIndex
    Lua.nth CInt
    2) Name
    "__index"
        StackIndex -> LuaE PandocError ()
    forall e. StackIndex -> LuaE e ()
    Lua.setmetatable (CInt -> StackIndex
    Lua.nth CInt
    2)
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_STATE"
      Global
    PANDOC_VERSION              -> do
        Pusher PandocError Version
    forall e. LuaError e => Pusher e Version
    pushVersion Version
    pandocVersion
        Name -> LuaE PandocError ()
    forall e. LuaError e => Name -> LuaE e ()
    Lua.setglobal Name
    "PANDOC_VERSION"