{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Lua.Module.Template
   Copyright   : Copyright © 2022-2023 Albert Krewinkel, John MacFarlane
   License     : GNU GPL, version 2 or above
   Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>

Lua module to handle pandoc templates.
-}
module Text.Pandoc.Lua.Module.Template
  ( documentedModule
  ) where

import HsLua
import HsLua.Module.DocLayout (peekDoc, pushDoc)
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Lua.Marshal.AST (peekMeta, pushBlocks, pushInlines)
import Text.Pandoc.Lua.Marshal.Context (peekContext, pushContext)
import Text.Pandoc.Lua.Marshal.Template (peekTemplate, pushTemplate)
import Text.Pandoc.Lua.PandocLua (PandocLua (unPandocLua), liftPandocLua)
import Text.Pandoc.Writers.Shared (metaToContext')
import Text.Pandoc.Templates
  ( compileTemplate, getDefaultTemplate, renderTemplate
  , runWithPartials, runWithDefaultPartials )

import qualified Data.Text as T

-- | The "pandoc.template" module.
documentedModule :: Module PandocError
documentedModule :: Module PandocError
documentedModule = Module
  { moduleName :: Name
moduleName = Name
"pandoc.template"
  , moduleDescription :: Text
moduleDescription = [Text] -> Text
T.unlines
    [ Text
"Lua functions for pandoc templates."
    ]
  , moduleFields :: [Field PandocError]
moduleFields = []
  , moduleOperations :: [(Operation, DocumentedFunction PandocError)]
moduleOperations = []
  , moduleFunctions :: [DocumentedFunction PandocError]
moduleFunctions = [DocumentedFunction PandocError]
functions
  }

-- | Template module functions.
functions :: [DocumentedFunction PandocError]
functions :: [DocumentedFunction PandocError]
functions =
  [ forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"apply"
     ### liftPure2 renderTemplate
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter Peeker PandocError (Template Text)
peekTemplate Text
"Template" Text
"template" Text
"template to apply"
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter forall e. LuaError e => Peeker e (Context Text)
peekContext Text
"table" Text
"context" Text
"variable values"
     forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> forall e a. Pusher e a -> Text -> Text -> FunctionResults e a
functionResult forall e. LuaError e => Pusher e (Doc Text)
pushDoc Text
"Doc" Text
"rendered template"
     #? T.unlines
     [ "Applies a context with variable assignments to a template,"
     , "returning the rendered template. The `context` parameter must be a"
     , "table with variable names as keys and [Doc], string, boolean, or"
     , "table as values, where the table can be either be a list of the"
     , "aforementioned types, or a nested context."
     ]

  , forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"compile"
     ### (\template mfilepath -> unPandocLua $
           case mfilepath of
             Just fp -> runWithPartials (compileTemplate fp template)
             Nothing -> runWithDefaultPartials
                        (compileTemplate "templates/default" template))
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter forall e. Peeker e Text
peekText Text
"string" Text
"template" Text
"template string"
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Parameter e a -> Parameter e (Maybe a)
opt (forall e. Text -> Text -> Parameter e String
stringParam Text
"templ_path" Text
"template path")
     forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> forall e a. Pusher e a -> Text -> Text -> FunctionResults e a
functionResult (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e a. LuaError e => String -> LuaE e a
failLua forall e. LuaError e => Pusher e (Template Text)
pushTemplate) Text
"pandoc Template"
           Text
"compiled template"

  , forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"default"
     ### (\mformat -> unPandocLua $ do
           let getFORMAT = liftPandocLua $ do
                 getglobal "FORMAT"
                 forcePeek $ peekText top `lastly` pop 1
           format <- maybe getFORMAT pure mformat
           getDefaultTemplate format)
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Parameter e a -> Parameter e (Maybe a)
opt (forall e. Text -> Text -> Parameter e Text
textParam Text
"writer"
              Text
"writer for which the template should be returned.")
     forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> forall e a. Pusher e a -> Text -> Text -> FunctionResults e a
functionResult forall e. Pusher e Text
pushText Text
"string"
           Text
"string representation of the writer's default template"

  , forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"meta_to_context"
     ### (\meta blockWriterIdx inlineWriterIdx -> unPandocLua $ do
             let blockWriter blks = liftPandocLua $ do
                   pushvalue blockWriterIdx
                   pushBlocks blks
                   callTrace 1 1
                   forcePeek $ peekDoc top
             let inlineWriter blks = liftPandocLua $ do
                   pushvalue inlineWriterIdx
                   pushInlines blks
                   callTrace 1 1
                   forcePeek $ peekDoc top
             metaToContext' blockWriter inlineWriter meta)
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter forall e. LuaError e => Peeker e Meta
peekMeta Text
"Meta" Text
"meta" Text
"document metadata"
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"function" Text
"blocks_writer"
           Text
"converter from Blocks to Doc values"
     forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a. Peeker e a -> Text -> Text -> Text -> Parameter e a
parameter forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"function" Text
"inlines_writer"
           Text
"converter from Inlines to Doc values"
     forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> forall e a. Pusher e a -> Text -> Text -> FunctionResults e a
functionResult forall e. LuaError e => Pusher e (Context Text)
pushContext Text
"table" Text
"template context"
     #? T.unlines
     [ "Creates template context from the document's [Meta]{#type-meta}"
     , "data, using the given functions to convert [Blocks] and [Inlines]"
     , "to [Doc] values."
     ]
  ]