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

   Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
   Stability   : alpha

Pandoc module for Lua.
-}
module Text.Pandoc.Lua.Packages
  ( installPandocPackageSearcher
  ) where

import Control.Monad (forM_)
import HsLua (NumResults)
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Lua.PandocLua (PandocLua, liftPandocLua, loadDefaultModule)

import qualified HsLua as Lua
import qualified HsLua.Module.Path as Path
import qualified HsLua.Module.Text as Text
import qualified Text.Pandoc.Lua.Module.Pandoc as Pandoc
import qualified Text.Pandoc.Lua.Module.MediaBag as MediaBag
import qualified Text.Pandoc.Lua.Module.System as System
import qualified Text.Pandoc.Lua.Module.Types as Types
import qualified Text.Pandoc.Lua.Module.Utils as Utils

-- | Insert pandoc's package loader as the first loader, making it the default.
installPandocPackageSearcher :: PandocLua ()
installPandocPackageSearcher :: PandocLua ()
installPandocPackageSearcher = LuaE PandocError () -> PandocLua ()
forall a. LuaE PandocError a -> PandocLua a
liftPandocLua (LuaE PandocError () -> PandocLua ())
-> LuaE PandocError () -> PandocLua ()
forall a b. (a -> b) -> a -> b
$ do
  Name -> LuaE PandocError ()
forall e. LuaError e => Name -> LuaE e ()
Lua.getglobal' Name
"package.searchers"
  LuaE PandocError ()
shiftArray
  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
$ (String -> PandocLua NumResults) -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction String -> PandocLua NumResults
pandocPackageSearcher
  StackIndex -> Integer -> LuaE PandocError ()
forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
Lua.rawseti (CInt -> StackIndex
Lua.nth CInt
2) Integer
1
  Int -> LuaE PandocError ()
forall e. Int -> LuaE e ()
Lua.pop Int
1           -- remove 'package.searchers' from stack
 where
  shiftArray :: LuaE PandocError ()
shiftArray = [Integer]
-> (Integer -> LuaE PandocError ()) -> LuaE PandocError ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Integer
4, Integer
3, Integer
2, Integer
1] ((Integer -> LuaE PandocError ()) -> LuaE PandocError ())
-> (Integer -> LuaE PandocError ()) -> LuaE PandocError ()
forall a b. (a -> b) -> a -> b
$ \Integer
i -> do
    StackIndex -> Integer -> LuaE PandocError ()
forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
Lua.rawgeti (-StackIndex
1) Integer
i
    StackIndex -> Integer -> LuaE PandocError ()
forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
Lua.rawseti (-StackIndex
2) (Integer
i Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)

-- | Load a pandoc module.
pandocPackageSearcher :: String -> PandocLua NumResults
pandocPackageSearcher :: String -> PandocLua NumResults
pandocPackageSearcher String
pkgName =
  case String
pkgName of
    String
"pandoc"          -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ PandocLua NumResults -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction @PandocError PandocLua NumResults
Pandoc.pushModule
    String
"pandoc.mediabag" -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ PandocLua NumResults -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction @PandocError PandocLua NumResults
MediaBag.pushModule
    String
"pandoc.path"     -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun
      (CInt -> NumResults
Lua.NumResults CInt
1 NumResults -> LuaE PandocError () -> HaskellFunction PandocError
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Module PandocError -> LuaE PandocError ()
forall e. LuaError e => Module e -> LuaE e ()
Lua.pushModule @PandocError Module PandocError
forall e. LuaError e => Module e
Path.documentedModule)
    String
"pandoc.system"   -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ HaskellFunction PandocError -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction HaskellFunction PandocError
System.pushModule
    String
"pandoc.types"    -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ HaskellFunction PandocError -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction @PandocError HaskellFunction PandocError
Types.pushModule
    String
"pandoc.utils"    -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ HaskellFunction PandocError -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction @PandocError HaskellFunction PandocError
Utils.pushModule
    String
"text"            -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun
      (CInt -> NumResults
Lua.NumResults CInt
1 NumResults -> LuaE PandocError () -> HaskellFunction PandocError
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Module PandocError -> LuaE PandocError ()
forall e. LuaError e => Module e -> LuaE e ()
Lua.pushModule @PandocError Module PandocError
forall e. Module e
Text.documentedModule)
    String
"pandoc.List"     -> HaskellFunction PandocError -> PandocLua NumResults
forall a. Num a => HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ PandocLua NumResults -> HaskellFunction PandocError
forall e a. Exposable e a => a -> HaskellFunction e
Lua.toHaskellFunction @PandocError (String -> PandocLua NumResults
loadDefaultModule String
pkgName)
    String
_                 -> PandocLua NumResults
reportPandocSearcherFailure
 where
  pushWrappedHsFun :: HaskellFunction PandocError -> PandocLua a
pushWrappedHsFun HaskellFunction PandocError
f = LuaE PandocError a -> PandocLua a
forall a. LuaE PandocError a -> PandocLua a
liftPandocLua (LuaE PandocError a -> PandocLua a)
-> LuaE PandocError a -> PandocLua a
forall a b. (a -> b) -> a -> b
$ do
    HaskellFunction PandocError -> LuaE PandocError ()
forall e. LuaError e => HaskellFunction e -> LuaE e ()
Lua.pushHaskellFunction HaskellFunction PandocError
f
    a -> LuaE PandocError a
forall (m :: * -> *) a. Monad m => a -> m a
return a
1
  reportPandocSearcherFailure :: PandocLua NumResults
reportPandocSearcherFailure = HaskellFunction PandocError -> PandocLua NumResults
forall a. LuaE PandocError a -> PandocLua a
liftPandocLua (HaskellFunction PandocError -> PandocLua NumResults)
-> HaskellFunction PandocError -> PandocLua NumResults
forall a b. (a -> b) -> a -> b
$ do
    String -> LuaE PandocError ()
forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
Lua.push (String
"\n\t" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
pkgName String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"is not one of pandoc's default packages")
    NumResults -> HaskellFunction PandocError
forall (m :: * -> *) a. Monad m => a -> m a
return (NumResults
1 :: NumResults)