{-# 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"