{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Lua.Module.Template
   Copyright   : Copyright © 2022-2024 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 Data.Version (makeVersion)
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 (typeTemplate, peekTemplate, pushTemplate)
import Text.Pandoc.Lua.PandocLua (PandocLua (unPandocLua), liftPandocLua)
import Text.Pandoc.Writers.Shared (metaToContext')
import Text.Pandoc.Templates
  ( compileTemplate, getDefaultTemplate, getTemplate, 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
"Handle pandoc templates."
    ]
  , moduleFields :: [Field PandocError]
moduleFields = []
  , moduleOperations :: [(Operation, DocumentedFunction PandocError)]
moduleOperations = []
  , moduleFunctions :: [DocumentedFunction PandocError]
moduleFunctions = [DocumentedFunction PandocError]
functions
  , moduleTypeInitializers :: [LuaE PandocError Name]
moduleTypeInitializers = [DocumentedTypeWithList PandocError (Template Text) Void
-> LuaE PandocError Name
forall e a itemtype.
LuaError e =>
DocumentedTypeWithList e a itemtype -> LuaE e Name
initType DocumentedTypeWithList PandocError (Template Text) Void
forall e. LuaError e => DocumentedType e (Template Text)
typeTemplate]
  }

-- | Template module functions.
functions :: [DocumentedFunction PandocError]
functions :: [DocumentedFunction PandocError]
functions =
  [ Name
-> (Template Text -> Context Text -> LuaE PandocError (Doc Text))
-> HsFnPrecursor
     PandocError
     (Template Text -> Context Text -> LuaE PandocError (Doc Text))
forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"apply"
     ### liftPure2 renderTemplate
     HsFnPrecursor
  PandocError
  (Template Text -> Context Text -> LuaE PandocError (Doc Text))
-> Parameter PandocError (Template Text)
-> HsFnPrecursor
     PandocError (Context Text -> LuaE PandocError (Doc Text))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError (Template Text)
-> TypeSpec
-> Text
-> Text
-> Parameter PandocError (Template Text)
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError (Template Text)
peekTemplate TypeSpec
"Template" Text
"template" Text
"template to apply"
     HsFnPrecursor
  PandocError (Context Text -> LuaE PandocError (Doc Text))
-> Parameter PandocError (Context Text)
-> HsFnPrecursor PandocError (LuaE PandocError (Doc Text))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError (Context Text)
-> TypeSpec -> Text -> Text -> Parameter PandocError (Context Text)
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError (Context Text)
forall e. LuaError e => Peeker e (Context Text)
peekContext TypeSpec
"table" Text
"context" Text
"variable values"
     HsFnPrecursor PandocError (LuaE PandocError (Doc Text))
-> FunctionResults PandocError (Doc Text)
-> DocumentedFunction PandocError
forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> Pusher PandocError (Doc Text)
-> TypeSpec -> Text -> FunctionResults PandocError (Doc Text)
forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
functionResult Pusher PandocError (Doc Text)
forall e. LuaError e => Pusher e (Doc Text)
pushDoc TypeSpec
"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."
     ]
    DocumentedFunction PandocError
-> Version -> DocumentedFunction PandocError
forall e. DocumentedFunction e -> Version -> DocumentedFunction e
`since` [Int] -> Version
makeVersion [Int
3,Int
0]

  , Name
-> (Text
    -> Maybe FilePath
    -> LuaE PandocError (Either FilePath (Template Text)))
-> HsFnPrecursor
     PandocError
     (Text
      -> Maybe FilePath
      -> LuaE PandocError (Either FilePath (Template Text)))
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))
     HsFnPrecursor
  PandocError
  (Text
   -> Maybe FilePath
   -> LuaE PandocError (Either FilePath (Template Text)))
-> Parameter PandocError Text
-> HsFnPrecursor
     PandocError
     (Maybe FilePath
      -> LuaE PandocError (Either FilePath (Template Text)))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError Text
-> TypeSpec -> Text -> Text -> Parameter PandocError Text
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError Text
forall e. Peeker e Text
peekText TypeSpec
"string" Text
"template" Text
"template string"
     HsFnPrecursor
  PandocError
  (Maybe FilePath
   -> LuaE PandocError (Either FilePath (Template Text)))
-> Parameter PandocError (Maybe FilePath)
-> HsFnPrecursor
     PandocError (LuaE PandocError (Either FilePath (Template Text)))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Parameter PandocError FilePath
-> Parameter PandocError (Maybe FilePath)
forall e a. Parameter e a -> Parameter e (Maybe a)
opt (Text -> Text -> Parameter PandocError FilePath
forall e. Text -> Text -> Parameter e FilePath
stringParam Text
"templates_path"
              (Text
"parameter to determine a default path and extension for " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
               Text
"partials; uses the data files templates path by default."))
     HsFnPrecursor
  PandocError (LuaE PandocError (Either FilePath (Template Text)))
-> FunctionResults PandocError (Either FilePath (Template Text))
-> DocumentedFunction PandocError
forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> Pusher PandocError (Either FilePath (Template Text))
-> TypeSpec
-> Text
-> FunctionResults PandocError (Either FilePath (Template Text))
forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
functionResult ((FilePath -> LuaE PandocError ())
-> (Template Text -> LuaE PandocError ())
-> Pusher PandocError (Either FilePath (Template Text))
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either FilePath -> LuaE PandocError ()
forall e a. LuaError e => FilePath -> LuaE e a
failLua Template Text -> LuaE PandocError ()
forall e. LuaError e => Pusher e (Template Text)
pushTemplate) TypeSpec
"Template"
           Text
"compiled template"
     #? T.unlines
     [ "Compiles a template string into a [[Template]] object usable by"
     , "pandoc."
     , ""
     , "If the `templates_path` parameter is specified, then it should be the"
     , "file path associated with the template. It is used when checking"
     , "for partials. Partials will be taken only from the default data"
     , "files if this parameter is omitted."
     , ""
     , "An error is raised if compilation fails."
     ]
    DocumentedFunction PandocError
-> Version -> DocumentedFunction PandocError
forall e. DocumentedFunction e -> Version -> DocumentedFunction e
`since` [Int] -> Version
makeVersion [Int
2,Int
17]

  , Name
-> (Maybe Text -> LuaE PandocError Text)
-> HsFnPrecursor PandocError (Maybe Text -> LuaE PandocError Text)
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)
     HsFnPrecursor PandocError (Maybe Text -> LuaE PandocError Text)
-> Parameter PandocError (Maybe Text)
-> HsFnPrecursor PandocError (LuaE PandocError Text)
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Parameter PandocError Text -> Parameter PandocError (Maybe Text)
forall e a. Parameter e a -> Parameter e (Maybe a)
opt (Text -> Text -> Parameter PandocError Text
forall e. Text -> Text -> Parameter e Text
textParam Text
"writer"
              (Text
"name of the writer for which the template should be " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
               Text
"retrieved; defaults to the global `FORMAT`."))
     HsFnPrecursor PandocError (LuaE PandocError Text)
-> FunctionResults PandocError Text
-> DocumentedFunction PandocError
forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> Pusher PandocError Text
-> TypeSpec -> Text -> FunctionResults PandocError Text
forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
functionResult Pusher PandocError Text
forall e. Pusher e Text
pushText TypeSpec
"string" Text
"raw template"
    #? T.unlines
    [ "Returns the default template for a given writer as a string. An"
    , "error is thrown if no such template can be found."
    ]
    DocumentedFunction PandocError
-> Version -> DocumentedFunction PandocError
forall e. DocumentedFunction e -> Version -> DocumentedFunction e
`since` [Int] -> Version
makeVersion [Int
2,Int
17]

  , Name
-> (FilePath -> LuaE PandocError Text)
-> HsFnPrecursor PandocError (FilePath -> LuaE PandocError Text)
forall a e. Name -> a -> HsFnPrecursor e a
defun Name
"get"
     ### (unPandocLua . getTemplate)
     HsFnPrecursor PandocError (FilePath -> LuaE PandocError Text)
-> Parameter PandocError FilePath
-> HsFnPrecursor PandocError (LuaE PandocError Text)
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Text -> Text -> Parameter PandocError FilePath
forall e. Text -> Text -> Parameter e FilePath
stringParam Text
"filename" Text
"name of the template"
     HsFnPrecursor PandocError (LuaE PandocError Text)
-> FunctionResults PandocError Text
-> DocumentedFunction PandocError
forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> Text -> FunctionResults PandocError Text
forall e. Text -> FunctionResults e Text
textResult Text
"content of template file"
     #? T.unlines
     [ "Retrieve text for a template."
     , ""
     , "This function first checks the resource paths for a file of this"
     , "name; if none is found, the `templates` directory in the user data"
     , "directory is checked.  Returns the content of the file, or throws"
     , "an error if no file is found."
     ]
    DocumentedFunction PandocError
-> Version -> DocumentedFunction PandocError
forall e. DocumentedFunction e -> Version -> DocumentedFunction e
`since` [Int] -> Version
makeVersion [Int
3,Int
2,Int
1]

  , Name
-> (Meta
    -> StackIndex -> StackIndex -> LuaE PandocError (Context Text))
-> HsFnPrecursor
     PandocError
     (Meta
      -> StackIndex -> StackIndex -> LuaE PandocError (Context Text))
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)
     HsFnPrecursor
  PandocError
  (Meta
   -> StackIndex -> StackIndex -> LuaE PandocError (Context Text))
-> Parameter PandocError Meta
-> HsFnPrecursor
     PandocError
     (StackIndex -> StackIndex -> LuaE PandocError (Context Text))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError Meta
-> TypeSpec -> Text -> Text -> Parameter PandocError Meta
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError Meta
forall e. LuaError e => Peeker e Meta
peekMeta TypeSpec
"Meta" Text
"meta" Text
"document metadata"
     HsFnPrecursor
  PandocError
  (StackIndex -> StackIndex -> LuaE PandocError (Context Text))
-> Parameter PandocError StackIndex
-> HsFnPrecursor
     PandocError (StackIndex -> LuaE PandocError (Context Text))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError StackIndex
-> TypeSpec -> Text -> Text -> Parameter PandocError StackIndex
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError StackIndex
forall a. a -> Peek PandocError a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TypeSpec
"function" Text
"blocks_writer"
           Text
"converter from [[Blocks]] to [[Doc]] values"
     HsFnPrecursor
  PandocError (StackIndex -> LuaE PandocError (Context Text))
-> Parameter PandocError StackIndex
-> HsFnPrecursor PandocError (LuaE PandocError (Context Text))
forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> Peeker PandocError StackIndex
-> TypeSpec -> Text -> Text -> Parameter PandocError StackIndex
forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
parameter Peeker PandocError StackIndex
forall a. a -> Peek PandocError a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TypeSpec
"function" Text
"inlines_writer"
           Text
"converter from [[Inlines]] to [[Doc]] values"
     HsFnPrecursor PandocError (LuaE PandocError (Context Text))
-> FunctionResults PandocError (Context Text)
-> DocumentedFunction PandocError
forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> Pusher PandocError (Context Text)
-> TypeSpec -> Text -> FunctionResults PandocError (Context Text)
forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
functionResult Pusher PandocError (Context Text)
forall e. LuaError e => Pusher e (Context Text)
pushContext TypeSpec
"table" Text
"template context"
     #? T.unlines
     [ "Creates template context from the document's [[Meta]] data, using the"
     , "given functions to convert [[Blocks]] and [[Inlines]] to [[Doc]]"
     , "values."
     ]
    DocumentedFunction PandocError
-> Version -> DocumentedFunction PandocError
forall e. DocumentedFunction e -> Version -> DocumentedFunction e
`since` [Int] -> Version
makeVersion [Int
3,Int
0]
  ]