{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE PackageImports             #-}
{-# LANGUAGE ScopedTypeVariables        #-}

module Heist.Interpreted.Internal where

------------------------------------------------------------------------------
import           Blaze.ByteString.Builder
import           Control.Monad
import           Control.Monad.State.Strict
import qualified Data.Attoparsec.Text          as AP
import           Data.ByteString               (ByteString)
import qualified Data.HashMap.Strict           as Map
import qualified Data.HeterogeneousEnvironment as HE
import           Data.Map.Syntax
import           Data.Maybe
import           Data.Text                     (Text)
import qualified Data.Text                     as T
import qualified Text.XmlHtml                  as X
------------------------------------------------------------------------------
import           Heist.Common
import           Heist.Internal.Types.HeistState
------------------------------------------------------------------------------


type Splice n = HeistT n n Template


------------------------------------------------------------------------------
-- HeistState functions
------------------------------------------------------------------------------


------------------------------------------------------------------------------
-- | Binds a new splice declaration to a tag name within a 'HeistState'.
bindSplice :: Text            -- ^ tag name
           -> Splice n        -- ^ splice action
           -> HeistState n    -- ^ source state
           -> HeistState n
bindSplice :: forall (n :: * -> *).
Text -> Splice n -> HeistState n -> HeistState n
bindSplice Text
n Splice n
v HeistState n
hs = HeistState n
hs {_spliceMap :: HashMap Text (Splice n)
_spliceMap = forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insert Text
n Splice n
v (forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m m Template)
_spliceMap HeistState n
hs)}


------------------------------------------------------------------------------
-- | Binds a set of new splice declarations within a 'HeistState'.
bindSplices :: Splices (Splice n) -- ^ splices to bind
            -> HeistState n       -- ^ start state
            -> HeistState n
bindSplices :: forall (n :: * -> *).
Splices (Splice n) -> HeistState n -> HeistState n
bindSplices Splices (Splice n)
ss HeistState n
hs =
    HeistState n
hs { _spliceMap :: HashMap Text (Splice n)
_spliceMap = forall (n :: * -> *) v a.
HeistState n
-> (HeistState n -> HashMap Text v)
-> MapSyntaxM Text v a
-> HashMap Text v
applySpliceMap HeistState n
hs forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m m Template)
_spliceMap Splices (Splice n)
ss }


------------------------------------------------------------------------------
-- | Converts 'Text' to a splice returning a single 'TextNode'.
textSplice :: Monad m => Text -> HeistT n m Template
textSplice :: forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m Template
textSplice Text
t = forall (m :: * -> *) a. Monad m => a -> m a
return [Text -> Node
X.TextNode Text
t]


------------------------------------------------------------------------------
-- | Runs the parameter node's children and returns the resulting node list.
-- By itself this function is a simple passthrough splice that makes the
-- spliced node disappear.  In combination with locally bound splices, this
-- function makes it easier to pass the desired view into your splices.
runChildren :: Monad n => Splice n
runChildren :: forall (n :: * -> *). Monad n => Splice n
runChildren = forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList forall b c a. (b -> c) -> (a -> b) -> a -> c
. Node -> Template
X.childNodes forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *) (n :: * -> *). Monad m => HeistT n m Node
getParamNode


------------------------------------------------------------------------------
-- | Binds a list of splices before using the children of the spliced node as
-- a view.
runChildrenWith :: (Monad n)
                => Splices (Splice n)
                -- ^ List of splices to bind before running the param nodes.
                -> Splice n
                -- ^ Returns the passed in view.
runChildrenWith :: forall (n :: * -> *). Monad n => Splices (Splice n) -> Splice n
runChildrenWith Splices (Splice n)
splices = forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m a -> HeistT n m a
localHS (forall (n :: * -> *).
Splices (Splice n) -> HeistState n -> HeistState n
bindSplices Splices (Splice n)
splices) forall (n :: * -> *). Monad n => Splice n
runChildren


------------------------------------------------------------------------------
-- | Wrapper around runChildrenWith that applies a transformation function to
-- the second item in each of the tuples before calling runChildrenWith.
runChildrenWithTrans :: (Monad n)
          => (b -> Splice n)
          -- ^ Splice generating function
          -> Splices b
          -- ^ List of tuples to be bound
          -> Splice n
runChildrenWithTrans :: forall (n :: * -> *) b.
Monad n =>
(b -> Splice n) -> Splices b -> Splice n
runChildrenWithTrans b -> Splice n
f = forall (n :: * -> *). Monad n => Splices (Splice n) -> Splice n
runChildrenWith forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV b -> Splice n
f


------------------------------------------------------------------------------
-- | Like runChildrenWith but using constant templates rather than dynamic
-- splices.
runChildrenWithTemplates :: (Monad n) => Splices Template -> Splice n
runChildrenWithTemplates :: forall (n :: * -> *). Monad n => Splices Template -> Splice n
runChildrenWithTemplates = forall (n :: * -> *) b.
Monad n =>
(b -> Splice n) -> Splices b -> Splice n
runChildrenWithTrans forall (m :: * -> *) a. Monad m => a -> m a
return


------------------------------------------------------------------------------
-- | Like runChildrenWith but using literal text rather than dynamic splices.
runChildrenWithText :: (Monad n) => Splices Text -> Splice n
runChildrenWithText :: forall (n :: * -> *). Monad n => Splices Text -> Splice n
runChildrenWithText = forall (n :: * -> *) b.
Monad n =>
(b -> Splice n) -> Splices b -> Splice n
runChildrenWithTrans forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m Template
textSplice


------------------------------------------------------------------------------
-- | Convenience function for looking up a splice.
lookupSplice :: Text
             -> HeistState n
             -> Maybe (Splice n)
lookupSplice :: forall (n :: * -> *). Text -> HeistState n -> Maybe (Splice n)
lookupSplice Text
nm HeistState n
hs = forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup Text
nm forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m m Template)
_spliceMap HeistState n
hs
{-# INLINE lookupSplice #-}


------------------------------------------------------------------------------
-- | Adds an HTML format template to the heist state.
addTemplate :: ByteString
            -- ^ Path that the template will be referenced by
            -> Template
            -- ^ The template's DOM nodes
            -> Maybe FilePath
            -- ^ An optional path to the actual file on disk where the
            -- template is stored
            -> HeistState n
            -> HeistState n
addTemplate :: forall (n :: * -> *).
ByteString
-> Template -> Maybe FilePath -> HeistState n -> HeistState n
addTemplate ByteString
n Template
t Maybe FilePath
mfp HeistState n
st =
    forall (n :: * -> *).
TPath -> DocumentFile -> HeistState n -> HeistState n
insertTemplate (ByteString -> TPath
splitTemplatePath ByteString
n) DocumentFile
doc HeistState n
st
  where
    doc :: DocumentFile
doc = Document -> Maybe FilePath -> DocumentFile
DocumentFile (Encoding -> Maybe DocType -> Template -> Document
X.HtmlDocument Encoding
X.UTF8 forall a. Maybe a
Nothing Template
t) Maybe FilePath
mfp


------------------------------------------------------------------------------
-- | Adds an XML format template to the heist state.
addXMLTemplate :: ByteString
               -- ^ Path that the template will be referenced by
               -> Template
               -- ^ The template's DOM nodes
               -> Maybe FilePath
               -- ^ An optional path to the actual file on disk where the
               -- template is stored
               -> HeistState n
               -> HeistState n
addXMLTemplate :: forall (n :: * -> *).
ByteString
-> Template -> Maybe FilePath -> HeistState n -> HeistState n
addXMLTemplate ByteString
n Template
t Maybe FilePath
mfp HeistState n
st =
    forall (n :: * -> *).
TPath -> DocumentFile -> HeistState n -> HeistState n
insertTemplate (ByteString -> TPath
splitTemplatePath ByteString
n) DocumentFile
doc HeistState n
st
  where
    doc :: DocumentFile
doc = Document -> Maybe FilePath -> DocumentFile
DocumentFile (Encoding -> Maybe DocType -> Template -> Document
X.XmlDocument Encoding
X.UTF8 forall a. Maybe a
Nothing Template
t) Maybe FilePath
mfp


------------------------------------------------------------------------------
-- | Stops the recursive processing of splices.  Consider the following
-- example:
--
--   > <foo>
--   >   <bar>
--   >     ...
--   >   </bar>
--   > </foo>
--
-- Assume that @\"foo\"@ is bound to a splice procedure. Running the @foo@
-- splice will result in a list of nodes @L@.  Normally @foo@ will recursively
-- scan @L@ for splices and run them.  If @foo@ calls @stopRecursion@, @L@
-- will be included in the output verbatim without running any splices.
stopRecursion :: Monad m => HeistT n m ()
stopRecursion :: forall (m :: * -> *) (n :: * -> *). Monad m => HeistT n m ()
stopRecursion = forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (\HeistState n
st -> HeistState n
st { _recurse :: Bool
_recurse = Bool
False })


------------------------------------------------------------------------------
-- | Performs splice processing on a single node.
runNode :: Monad n => X.Node -> Splice n
runNode :: forall (n :: * -> *). Monad n => Node -> Splice n
runNode (X.Element Text
nm [(Text, Text)]
at Template
ch) = do
    [(Text, Text)]
newAtts <- forall (n :: * -> *).
Monad n =>
[(Text, Text)] -> HeistT n n [(Text, Text)]
runAttributes [(Text, Text)]
at
    let n :: Node
n = Text -> [(Text, Text)] -> Template -> Node
X.Element Text
nm [(Text, Text)]
newAtts Template
ch
    Maybe (Splice n)
s <- forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (n :: * -> *). Text -> HeistState n -> Maybe (Splice n)
lookupSplice Text
nm) forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall {n :: * -> *}.
Monad n =>
[(Text, Text)] -> HeistT n n Template
runKids [(Text, Text)]
newAtts) (forall (n :: * -> *). Monad n => Node -> Splice n -> Splice n
recurseSplice Node
n) Maybe (Splice n)
s
  where
    runKids :: [(Text, Text)] -> HeistT n n Template
runKids [(Text, Text)]
newAtts = do
        Template
newKids <- forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList Template
ch
        forall (m :: * -> *) a. Monad m => a -> m a
return [Text -> [(Text, Text)] -> Template -> Node
X.Element Text
nm [(Text, Text)]
newAtts Template
newKids]
runNode Node
n                    = forall (m :: * -> *) a. Monad m => a -> m a
return [Node
n]


------------------------------------------------------------------------------
-- | Performs splice processing on a list of attributes.  This is useful in
-- situations where you need to stop recursion, but still run splice
-- processing on the node's attributes.
runAttributes :: Monad n => [(Text, Text)] -> HeistT n n [(Text, Text)]
runAttributes :: forall (n :: * -> *).
Monad n =>
[(Text, Text)] -> HeistT n n [(Text, Text)]
runAttributes [(Text, Text)]
attrs = (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall (n :: * -> *).
Monad n =>
(Text, Text) -> HeistT n n [(Text, Text)]
runAttrSplice [(Text, Text)]
attrs


------------------------------------------------------------------------------
-- | Runs the attribute splice if it exists, otherwise it does inline $()
-- substitution.
runAttrSplice :: (Monad n) => (Text, Text) -> HeistT n n [(Text, Text)]
runAttrSplice :: forall (n :: * -> *).
Monad n =>
(Text, Text) -> HeistT n n [(Text, Text)]
runAttrSplice a :: (Text, Text)
a@(Text
k,Text
v) = do
    Maybe (AttrSplice n)
splice <- forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS (forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup Text
k forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). HeistState m -> HashMap Text (AttrSplice m)
_attrSpliceMap)
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a. a -> [a] -> [a]
:[]) forall a b. (a -> b) -> a -> b
$ forall (n :: * -> *) t.
Monad n =>
(t, Text) -> HeistT n n (t, Text)
attSubst (Text, Text)
a)
          (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT HeterogeneousEnvironment
HE.empty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
RuntimeSplice m a -> StateT HeterogeneousEnvironment m a
unRT forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a b. (a -> b) -> a -> b
$ Text
v)) Maybe (AttrSplice n)
splice


------------------------------------------------------------------------------
-- | Helper function for substituting a parsed attribute into an attribute
-- tuple.
attSubst :: (Monad n) => (t, Text) -> HeistT n n (t, Text)
attSubst :: forall (n :: * -> *) t.
Monad n =>
(t, Text) -> HeistT n n (t, Text)
attSubst (t
n,Text
v) = do
    Text
v' <- forall (n :: * -> *). Monad n => Text -> HeistT n n Text
parseAtt Text
v
    forall (m :: * -> *) a. Monad m => a -> m a
return (t
n,Text
v')


------------------------------------------------------------------------------
-- | Parses an attribute for any identifier expressions and performs
-- appropriate substitution.
parseAtt :: (Monad n) => Text -> HeistT n n Text
parseAtt :: forall (n :: * -> *). Monad n => Text -> HeistT n n Text
parseAtt Text
bs = do
    let ast :: [AttAST]
ast = case forall i r. Monoid i => IResult i r -> i -> IResult i r
AP.feed (forall a. Parser a -> Text -> Result a
AP.parse Parser [AttAST]
attParser Text
bs) Text
"" of
                (AP.Done Text
_ [AttAST]
res) -> [AttAST]
res
                (AP.Fail Text
_ [FilePath]
_ FilePath
_) -> []
                (AP.Partial Text -> IResult Text [AttAST]
_)  -> []
    [Text]
chunks <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall {m :: * -> *}. Monad m => AttAST -> HeistT m m Text
cvt [AttAST]
ast
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.concat [Text]
chunks
  where
    cvt :: AttAST -> HeistT m m Text
cvt (Literal Text
x) = forall (m :: * -> *) a. Monad m => a -> m a
return Text
x
    cvt (Ident Text
x)   =
        forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(Node -> Node) -> HeistT n m a -> HeistT n m a
localParamNode (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ Text -> [(Text, Text)] -> Template -> Node
X.Element Text
x [] []) forall a b. (a -> b) -> a -> b
$ forall (n :: * -> *). Monad n => Text -> HeistT n n Text
getAttributeSplice Text
x


------------------------------------------------------------------------------
-- | Gets the attribute value.  If the splice's result list contains non-text
-- nodes, this will translate them into text nodes with nodeText and
-- concatenate them together.
--
-- Originally, this only took the first node from the splices's result list,
-- and only if it was a text node. This caused problems when the splice's
-- result contained HTML entities, as they would split a text node. This was
-- then fixed to take the first consecutive bunch of text nodes, and return
-- their concatenation. This was seen as more useful than throwing an error,
-- and more intuitive than trying to render all the nodes as text.
--
-- However, it was decided in the end to render all the nodes as text, and
-- then concatenate them. If a splice returned
-- \"some \<b\>text\<\/b\> foobar\", the user would almost certainly want
-- \"some text foobar\" to be rendered, and Heist would probably seem
-- annoyingly limited for not being able to do this. If the user really did
-- want it to render \"some \", it would probably be easier for them to
-- accept that they were silly to pass more than that to be substituted than
-- it would be for the former user to accept that
-- \"some \<b\>text\<\/b\> foobar\" is being rendered as \"some \" because
-- it's \"more intuitive\".
getAttributeSplice :: Monad n => Text -> HeistT n n Text
getAttributeSplice :: forall (n :: * -> *). Monad n => Text -> HeistT n n Text
getAttributeSplice Text
name = do
    HeistState n
hs <- forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    let noSplice :: m Text
noSplice = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.concat [Text
"${", Text
name, Text
"}"]
        s :: Maybe (Splice n)
s = forall (n :: * -> *). Text -> HeistState n -> Maybe (Splice n)
lookupSplice Text
name HeistState n
hs
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall {m :: * -> *}. Monad m => m Text
noSplice (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ([Text] -> Text
T.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Node -> Text
X.nodeText)) Maybe (Splice n)
s

------------------------------------------------------------------------------
-- | Performs splice processing on a list of nodes.
runNodeList :: Monad n => [X.Node] -> Splice n
runNodeList :: forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList = forall (m :: * -> *) b a.
(Monad m, Monoid b) =>
(a -> m b) -> [a] -> m b
mapSplices forall (n :: * -> *). Monad n => Node -> Splice n
runNode
{-# INLINE runNodeList #-}


------------------------------------------------------------------------------
-- | The maximum recursion depth.  (Used to prevent infinite loops.)
mAX_RECURSION_DEPTH :: Int
mAX_RECURSION_DEPTH :: Int
mAX_RECURSION_DEPTH = Int
50


------------------------------------------------------------------------------
-- | Checks the recursion flag and recurses accordingly.  Does not recurse
-- deeper than mAX_RECURSION_DEPTH to avoid infinite loops.
recurseSplice :: Monad n => X.Node -> Splice n -> Splice n
recurseSplice :: forall (n :: * -> *). Monad n => Node -> Splice n -> Splice n
recurseSplice Node
node Splice n
splice = do
    Template
result <- forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(Node -> Node) -> HeistT n m a -> HeistT n m a
localParamNode (forall a b. a -> b -> a
const Node
node) Splice n
splice
    HeistState n
hs <- forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    if forall (m :: * -> *). HeistState m -> Bool
_recurse HeistState n
hs
        then if forall (m :: * -> *). HeistState m -> Int
_recursionDepth HeistState n
hs forall a. Ord a => a -> a -> Bool
< Int
mAX_RECURSION_DEPTH
               then do forall (m :: * -> *) (n :: * -> *).
Monad m =>
(Int -> Int) -> HeistT n m ()
modRecursionDepth (forall a. Num a => a -> a -> a
+Int
1)
                       Template
res <- forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList Template
result
                       forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistState n -> HeistT n m ()
restoreHS HeistState n
hs
                       forall (m :: * -> *) a. Monad m => a -> m a
return Template
res
               else forall (m :: * -> *) a. Monad m => a -> m a
return Template
result forall (m :: * -> *) (n :: * -> *) b.
Monad m =>
HeistT n m b -> FilePath -> HeistT n m b
`orError` FilePath
err
        else do forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (\HeistState n
st -> HeistState n
st { _recurse :: Bool
_recurse = Bool
True })
                forall (m :: * -> *) a. Monad m => a -> m a
return Template
result
  where
    err :: FilePath
err = [FilePath] -> FilePath
unwords
        [FilePath
"Recursion limit reached in node"
        ,FilePath
"<"forall a. [a] -> [a] -> [a]
++(Text -> FilePath
T.unpack forall a b. (a -> b) -> a -> b
$ Node -> Text
X.elementTag Node
node)forall a. [a] -> [a] -> [a]
++FilePath
">.  You"
        ,FilePath
"probably have infinite splice recursion!"
        ]



------------------------------------------------------------------------------
-- | Looks up a template name runs a 'HeistT' computation on it.
lookupAndRun :: Monad m
             => ByteString
             -> ((DocumentFile, TPath) -> HeistT n m (Maybe a))
             -> HeistT n m (Maybe a)
lookupAndRun :: forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
ByteString
-> ((DocumentFile, TPath) -> HeistT n m (Maybe a))
-> HeistT n m (Maybe a)
lookupAndRun ByteString
name (DocumentFile, TPath) -> HeistT n m (Maybe a)
k = do
    HeistState n
hs <- forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    let mt :: Maybe (DocumentFile, TPath)
mt = forall (n :: * -> *) t.
ByteString
-> HeistState n
-> (HeistState n -> HashMap TPath t)
-> Maybe (t, TPath)
lookupTemplate ByteString
name HeistState n
hs forall (m :: * -> *). HeistState m -> HashMap TPath DocumentFile
_templateMap
    let curPath :: Maybe FilePath
curPath = forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (DocumentFile -> Maybe FilePath
dfFile forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) Maybe (DocumentFile, TPath)
mt
    forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (forall (n :: * -> *).
Maybe FilePath -> HeistState n -> HeistState n
setCurTemplateFile Maybe FilePath
curPath)
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing) (DocumentFile, TPath) -> HeistT n m (Maybe a)
k Maybe (DocumentFile, TPath)
mt


------------------------------------------------------------------------------
-- | Looks up a template name evaluates it by calling runNodeList.
evalTemplate :: Monad n
             => ByteString
             -> HeistT n n (Maybe Template)
evalTemplate :: forall (n :: * -> *).
Monad n =>
ByteString -> HeistT n n (Maybe Template)
evalTemplate ByteString
name = forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
ByteString
-> ((DocumentFile, TPath) -> HeistT n m (Maybe a))
-> HeistT n m (Maybe a)
lookupAndRun ByteString
name
    (\(DocumentFile
t,TPath
ctx) -> forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m a -> HeistT n m a
localHS (\HeistState n
hs -> HeistState n
hs {_curContext :: TPath
_curContext = TPath
ctx})
                         (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList forall a b. (a -> b) -> a -> b
$ Document -> Template
X.docContent forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
t))


------------------------------------------------------------------------------
-- | Sets the document type of a 'X.Document' based on the 'HeistT'
-- value.
fixDocType :: Monad m => X.Document -> HeistT n m X.Document
fixDocType :: forall (m :: * -> *) (n :: * -> *).
Monad m =>
Document -> HeistT n m Document
fixDocType Document
d = do
    [DocType]
dts <- forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS forall (m :: * -> *). HeistState m -> [DocType]
_doctypes
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Document
d { docType :: Maybe DocType
X.docType = forall a. [a] -> Maybe a
listToMaybe [DocType]
dts }


------------------------------------------------------------------------------
-- | Runs a template and sets the doctype properly.  This is the right thing
-- to do if we are starting at the top level.
evalWithDoctypes :: Monad n
                 => ByteString
                 -> HeistT n n (Maybe X.Document)
evalWithDoctypes :: forall (n :: * -> *).
Monad n =>
ByteString -> HeistT n n (Maybe Document)
evalWithDoctypes ByteString
name = forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
ByteString
-> ((DocumentFile, TPath) -> HeistT n m (Maybe a))
-> HeistT n m (Maybe a)
lookupAndRun ByteString
name forall a b. (a -> b) -> a -> b
$ \(DocumentFile
t,TPath
ctx) -> do
    forall (m :: * -> *) (n :: * -> *).
Monad m =>
[DocType] -> HeistT n m ()
addDoctype forall a b. (a -> b) -> a -> b
$ forall a. Maybe a -> [a]
maybeToList forall a b. (a -> b) -> a -> b
$ Document -> Maybe DocType
X.docType forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
t
    HeistState n
hs <- forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    let nodes :: Template
nodes = Document -> Template
X.docContent forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
t
    forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistState n -> HeistT n m ()
putHS (HeistState n
hs {_curContext :: TPath
_curContext = TPath
ctx})
    Template
newNodes <- forall (n :: * -> *). Monad n => Template -> Splice n
runNodeList Template
nodes
    forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistState n -> HeistT n m ()
restoreHS HeistState n
hs
    Document
newDoc   <- forall (m :: * -> *) (n :: * -> *).
Monad m =>
Document -> HeistT n m Document
fixDocType forall a b. (a -> b) -> a -> b
$ (DocumentFile -> Document
dfDoc DocumentFile
t) { docContent :: Template
X.docContent = Template
newNodes }
    forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just Document
newDoc)


------------------------------------------------------------------------------
-- | Binds a list of constant string splices.
bindStrings :: Monad n
            => Splices Text
            -> HeistState n
            -> HeistState n
bindStrings :: forall (n :: * -> *).
Monad n =>
Splices Text -> HeistState n -> HeistState n
bindStrings Splices Text
splices = forall (n :: * -> *).
Splices (Splice n) -> HeistState n -> HeistState n
bindSplices (forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m Template
textSplice Splices Text
splices)


------------------------------------------------------------------------------
-- | Binds a single constant string splice.
bindString :: Monad n
           => Text
           -> Text
           -> HeistState n
           -> HeistState n
bindString :: forall (n :: * -> *).
Monad n =>
Text -> Text -> HeistState n -> HeistState n
bindString Text
n = forall (n :: * -> *).
Text -> Splice n -> HeistState n -> HeistState n
bindSplice Text
n forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m Template
textSplice


------------------------------------------------------------------------------
-- | Renders a template with the specified parameters.  This is the function
-- to use when you want to "call" a template and pass in parameters from
-- inside a splice.  If the template does not exist, this version simply
-- returns an empty list.
callTemplate :: Monad n
             => ByteString         -- ^ The name of the template
             -> Splices (Splice n) -- ^ Splices to call the template with
             -> HeistT n n Template
callTemplate :: forall (n :: * -> *).
Monad n =>
ByteString -> Splices (Splice n) -> Splice n
callTemplate ByteString
name Splices (Splice n)
splices = do
    forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS forall a b. (a -> b) -> a -> b
$ forall (n :: * -> *).
Splices (Splice n) -> HeistState n -> HeistState n
bindSplices Splices (Splice n)
splices
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] forall a. a -> a
id) forall a b. (a -> b) -> a -> b
$ forall (n :: * -> *).
Monad n =>
ByteString -> HeistT n n (Maybe Template)
evalTemplate ByteString
name


------------------------------------------------------------------------------
-- | Like callTemplate except the splices being bound are constant text
-- splices.
callTemplateWithText :: Monad n
                     => ByteString     -- ^ The name of the template
                     -> Splices Text -- ^ Splices to call the template with
                     -> HeistT n n Template
callTemplateWithText :: forall (n :: * -> *).
Monad n =>
ByteString -> Splices Text -> HeistT n n Template
callTemplateWithText ByteString
name Splices Text
splices = forall (n :: * -> *).
Monad n =>
ByteString -> Splices (Splice n) -> Splice n
callTemplate ByteString
name forall a b. (a -> b) -> a -> b
$ forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m Template
textSplice Splices Text
splices


------------------------------------------------------------------------------
-- | Renders a template from the specified HeistState to a 'Builder'.  The
-- MIME type returned is based on the detected character encoding, and whether
-- the root template was an HTML or XML format template.  It will always be
-- @text/html@ or @text/xml@.  If a more specific MIME type is needed for a
-- particular XML application, it must be provided by the application.
--
-- Note that template names should not include the .tpl extension:
--
-- @renderTemplate hs "index"@
renderTemplate :: Monad n
               => HeistState n
               -> ByteString
               -> n (Maybe (Builder, MIMEType))
renderTemplate :: forall (n :: * -> *).
Monad n =>
HeistState n -> ByteString -> n (Maybe (Builder, ByteString))
renderTemplate HeistState n
hs ByteString
name = forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
HeistT n m a -> Node -> HeistState n -> m a
evalHeistT forall {n :: * -> *}.
Monad n =>
HeistT n n (Maybe (Builder, ByteString))
tpl (Text -> Node
X.TextNode Text
"") HeistState n
hs
  where tpl :: HeistT n n (Maybe (Builder, ByteString))
tpl = do Maybe Document
mt <- forall (n :: * -> *).
Monad n =>
ByteString -> HeistT n n (Maybe Document)
evalWithDoctypes ByteString
name
                 case Maybe Document
mt of
                    Maybe Document
Nothing  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
                    Just Document
doc -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ (Document -> Builder
X.render Document
doc, Document -> ByteString
mimeType Document
doc)


------------------------------------------------------------------------------
-- | Renders a template with the specified arguments passed to it.  This is a
-- convenience function for the common pattern of calling renderTemplate after
-- using bindString, bindStrings, or bindSplice to set up the arguments to the
-- template.
renderWithArgs :: Monad n
               => Splices Text
               -> HeistState n
               -> ByteString
               -> n (Maybe (Builder, MIMEType))
renderWithArgs :: forall (n :: * -> *).
Monad n =>
Splices Text
-> HeistState n -> ByteString -> n (Maybe (Builder, ByteString))
renderWithArgs Splices Text
args HeistState n
hs = forall (n :: * -> *).
Monad n =>
HeistState n -> ByteString -> n (Maybe (Builder, ByteString))
renderTemplate (forall (n :: * -> *).
Monad n =>
Splices Text -> HeistState n -> HeistState n
bindStrings Splices Text
args HeistState n
hs)


renderTemplateToDoc :: Monad n
            => HeistState n
            -> ByteString
            -> n (Maybe X.Document)
renderTemplateToDoc :: forall (n :: * -> *).
Monad n =>
HeistState n -> ByteString -> n (Maybe Document)
renderTemplateToDoc HeistState n
hs ByteString
name =
    forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
HeistT n m a -> Node -> HeistState n -> m a
evalHeistT (forall (n :: * -> *).
Monad n =>
ByteString -> HeistT n n (Maybe Document)
evalWithDoctypes ByteString
name) (Text -> Node
X.TextNode Text
"") HeistState n
hs