{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE CPP                        #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NoMonomorphismRestriction  #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeSynonymInstances       #-}

module Heist.Compiled.Internal where


------------------------------------------------------------------------------
import           Blaze.ByteString.Builder
import           Blaze.ByteString.Builder.Char.Utf8
import           Control.Arrow
import           Control.Exception
import           Control.Monad
import           Control.Monad.RWS.Strict
import           Control.Monad.State.Strict
import qualified Data.Attoparsec.Text               as AP
import           Data.ByteString                    (ByteString)
import           Data.DList                         (DList)
import qualified Data.DList                         as DL
import qualified Data.HashMap.Strict                as H
import qualified Data.HashSet                       as S
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 Data.Text.Encoding                 as T
import qualified Data.Vector                        as V
import           Text.Printf
import qualified Text.XmlHtml                       as X
import qualified Text.XmlHtml.HTML.Meta             as X
------------------------------------------------------------------------------
#if !MIN_VERSION_base(4,8,0)
import           Data.Foldable                      (Foldable)
#endif
import qualified Data.Foldable                      as Foldable
------------------------------------------------------------------------------
import           Heist.Common
import           Heist.Internal.Types.HeistState
------------------------------------------------------------------------------


------------------------------------------------------------------------------
-- | A compiled Splice is a HeistT computation that returns a @DList
-- (Chunk m)@.
--
-- The more interesting part of the type signature is what comes before the
-- return value.  The first type parameter in @'HeistT' n IO@ is the runtime
-- monad.  This reveals that the Chunks know about the runtime monad.  The
-- second type parameter in @HeistT n IO@ is @IO@.  This tells us that the
-- compiled splices themselves are run in the IO monad, which will usually
-- mean at load time.  Compiled splices run at load time, and they return
-- computations that run at runtime.
type Splice n = HeistT n IO (DList (Chunk n))


------------------------------------------------------------------------------
-- | Runs the parameter node's children and returns the resulting compiled
-- chunks.  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 :: Splice n
runChildren = [Node] -> Splice n
forall (n :: * -> *). Monad n => [Node] -> Splice n
runNodeList ([Node] -> Splice n) -> (Node -> [Node]) -> Node -> Splice n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Node -> [Node]
X.childNodes (Node -> Splice n) -> HeistT n IO Node -> Splice n
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< HeistT n IO Node
forall (m :: * -> *) (n :: * -> *). Monad m => HeistT n m Node
getParamNode
{-# INLINE runChildren #-}


renderFragment :: Markup -> [X.Node] -> Builder
renderFragment :: Markup -> [Node] -> Builder
renderFragment Markup
markup [Node]
ns =
    case Markup
markup of
      Markup
Html -> Encoding -> [Node] -> Builder
X.renderHtmlFragment Encoding
X.UTF8 [Node]
ns
      Markup
Xml  -> Encoding -> [Node] -> Builder
X.renderXmlFragment Encoding
X.UTF8 [Node]
ns


------------------------------------------------------------------------------
-- | Yields pure text known at load time.
pureTextChunk :: Text -> Chunk n
pureTextChunk :: Text -> Chunk n
pureTextChunk Text
t = ByteString -> Chunk n
forall (m :: * -> *). ByteString -> Chunk m
Pure (ByteString -> Chunk n) -> ByteString -> Chunk n
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 Text
t
{-# INLINE pureTextChunk #-}


------------------------------------------------------------------------------
-- | Yields a pure Builder known at load time.  You should use this and
-- 'yieldPureText' as much as possible to maximize the parts of your page that
-- can be compiled to static ByteStrings.
yieldPure :: Builder -> DList (Chunk n)
yieldPure :: Builder -> DList (Chunk n)
yieldPure = Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n))
-> (Builder -> Chunk n) -> Builder -> DList (Chunk n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Chunk n
forall (m :: * -> *). ByteString -> Chunk m
Pure (ByteString -> Chunk n)
-> (Builder -> ByteString) -> Builder -> Chunk n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
toByteString
{-# INLINE yieldPure #-}


------------------------------------------------------------------------------
-- | Yields a runtime action that returns a builder.
yieldRuntime :: RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime :: RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime = Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n))
-> (RuntimeSplice n Builder -> Chunk n)
-> RuntimeSplice n Builder
-> DList (Chunk n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RuntimeSplice n Builder -> Chunk n
forall (m :: * -> *). RuntimeSplice m Builder -> Chunk m
RuntimeHtml
{-# INLINE yieldRuntime #-}


------------------------------------------------------------------------------
-- | Yields a runtime action that returns no value and is only needed for its
-- side effect.
yieldRuntimeEffect :: Monad n => RuntimeSplice n () -> DList (Chunk n)
yieldRuntimeEffect :: RuntimeSplice n () -> DList (Chunk n)
yieldRuntimeEffect = Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n))
-> (RuntimeSplice n () -> Chunk n)
-> RuntimeSplice n ()
-> DList (Chunk n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RuntimeSplice n () -> Chunk n
forall (m :: * -> *). RuntimeSplice m () -> Chunk m
RuntimeAction
{-# INLINE yieldRuntimeEffect #-}


------------------------------------------------------------------------------
-- | A convenience wrapper around yieldPure for working with Text.  Roughly
-- equivalent to 'textSplice' from Heist.Interpreted.
yieldPureText :: Text -> DList (Chunk n)
yieldPureText :: Text -> DList (Chunk n)
yieldPureText = Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n))
-> (Text -> Chunk n) -> Text -> DList (Chunk n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk
{-# INLINE yieldPureText #-}


------------------------------------------------------------------------------
-- | Convenience wrapper around yieldRuntime allowing you to work with Text.
yieldRuntimeText :: Monad n => RuntimeSplice n Text -> DList (Chunk n)
yieldRuntimeText :: RuntimeSplice n Text -> DList (Chunk n)
yieldRuntimeText = RuntimeSplice n Builder -> DList (Chunk n)
forall (n :: * -> *). RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime (RuntimeSplice n Builder -> DList (Chunk n))
-> (RuntimeSplice n Text -> RuntimeSplice n Builder)
-> RuntimeSplice n Text
-> DList (Chunk n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  (Text -> Builder)
-> RuntimeSplice n Text -> RuntimeSplice n Builder
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Text -> Builder
fromText
{-# INLINE yieldRuntimeText #-}


------------------------------------------------------------------------------
-- | Returns a computation that performs load-time splice processing on the
-- supplied list of nodes.
runNodeList :: Monad n => [X.Node] -> Splice n
runNodeList :: [Node] -> Splice n
runNodeList = (Node -> Splice n) -> [Node] -> Splice n
forall (m :: * -> *) b a.
(Monad m, Monoid b) =>
(a -> m b) -> [a] -> m b
mapSplices Node -> Splice n
forall (n :: * -> *). Monad n => Node -> Splice n
runNode


------------------------------------------------------------------------------
-- | Runs a DocumentFile with the appropriate template context set.
runDocumentFile :: Monad n
                => TPath
                -> DocumentFile
                -> Splice n
runDocumentFile :: TPath -> DocumentFile -> Splice n
runDocumentFile TPath
tpath DocumentFile
df = do
    let markup :: Markup
markup = case DocumentFile -> Document
dfDoc DocumentFile
df of
                   X.XmlDocument Encoding
_ Maybe DocType
_ [Node]
_ -> Markup
Xml
                   X.HtmlDocument Encoding
_ Maybe DocType
_ [Node]
_ -> Markup
Html
    (HeistState n -> HeistState n) -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (\HeistState n
hs -> HeistState n
hs { _curMarkup :: Markup
_curMarkup = Markup
markup })
    let inDoctype :: Maybe DocType
inDoctype = Document -> Maybe DocType
X.docType (Document -> Maybe DocType) -> Document -> Maybe DocType
forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
df
    [DocType] -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
[DocType] -> HeistT n m ()
addDoctype ([DocType] -> HeistT n IO ()) -> [DocType] -> HeistT n IO ()
forall a b. (a -> b) -> a -> b
$ Maybe DocType -> [DocType]
forall a. Maybe a -> [a]
maybeToList Maybe DocType
inDoctype
    (HeistState n -> HeistState n) -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (Maybe FilePath -> HeistState n -> HeistState n
forall (n :: * -> *).
Maybe FilePath -> HeistState n -> HeistState n
setCurTemplateFile Maybe FilePath
curPath (HeistState n -> HeistState n)
-> (HeistState n -> HeistState n) -> HeistState n -> HeistState n
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  TPath -> HeistState n -> HeistState n
forall (n :: * -> *). TPath -> HeistState n -> HeistState n
setCurContext TPath
tpath)
    DList (Chunk n)
res <- [Node] -> Splice n
forall (n :: * -> *). Monad n => [Node] -> Splice n
runNodeList [Node]
nodes
    Maybe DocType
dt <- (HeistState n -> Maybe DocType) -> HeistT n IO (Maybe DocType)
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS ([DocType] -> Maybe DocType
forall a. [a] -> Maybe a
listToMaybe ([DocType] -> Maybe DocType)
-> (HeistState n -> [DocType]) -> HeistState n -> Maybe DocType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeistState n -> [DocType]
forall (m :: * -> *). HeistState m -> [DocType]
_doctypes)
    let enc :: Encoding
enc = Document -> Encoding
X.docEncoding (Document -> Encoding) -> Document -> Encoding
forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
df
    DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$! (Builder -> DList (Chunk n)
forall (n :: * -> *). Builder -> DList (Chunk n)
yieldPure (Encoding -> Maybe DocType -> Builder
X.renderDocType Encoding
enc Maybe DocType
dt) DList (Chunk n) -> DList (Chunk n) -> DList (Chunk n)
forall a. Monoid a => a -> a -> a
`mappend` DList (Chunk n)
res)
  where
    curPath :: Maybe FilePath
curPath     = DocumentFile -> Maybe FilePath
dfFile DocumentFile
df
    nodes :: [Node]
nodes       = Document -> [Node]
X.docContent (Document -> [Node]) -> Document -> [Node]
forall a b. (a -> b) -> a -> b
$! DocumentFile -> Document
dfDoc DocumentFile
df


------------------------------------------------------------------------------
compileTemplate
    :: Monad n
    => TPath
    -> DocumentFile
    -> HeistT n IO [Chunk n]
compileTemplate :: TPath -> DocumentFile -> HeistT n IO [Chunk n]
compileTemplate TPath
tpath DocumentFile
df = do
    !DList (Chunk n)
chunks <- TPath -> DocumentFile -> Splice n
forall (n :: * -> *). Monad n => TPath -> DocumentFile -> Splice n
runDocumentFile TPath
tpath DocumentFile
df
    [Chunk n] -> HeistT n IO [Chunk n]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Chunk n] -> HeistT n IO [Chunk n])
-> [Chunk n] -> HeistT n IO [Chunk n]
forall a b. (a -> b) -> a -> b
$! DList (Chunk n) -> [Chunk n]
forall (n :: * -> *). Monad n => DList (Chunk n) -> [Chunk n]
consolidate DList (Chunk n)
chunks


------------------------------------------------------------------------------
compileTemplates
    :: Monad n
    => (TPath -> Bool)
    -> HeistState n
    -> IO (Either [String] (HeistState n))
compileTemplates :: (TPath -> Bool)
-> HeistState n -> IO (Either [FilePath] (HeistState n))
compileTemplates TPath -> Bool
f HeistState n
hs = do
    (HashMap TPath ([Chunk n], ByteString)
tmap, HeistState n
hs') <- HeistT n IO (HashMap TPath ([Chunk n], ByteString))
-> Node
-> HeistState n
-> IO (HashMap TPath ([Chunk n], ByteString), HeistState n)
forall (n :: * -> *) (m :: * -> *) a.
HeistT n m a -> Node -> HeistState n -> m (a, HeistState n)
runHeistT ((TPath -> Bool)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
forall (n :: * -> *).
Monad n =>
(TPath -> Bool)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
compileTemplates' TPath -> Bool
f) (Text -> Node
X.TextNode Text
"") HeistState n
hs
    let pre :: Text
pre = HeistState n -> Text
forall (m :: * -> *). HeistState m -> Text
_splicePrefix HeistState n
hs'
    let canError :: Bool
canError = HeistState n -> Bool
forall (m :: * -> *). HeistState m -> Bool
_errorNotBound HeistState n
hs'
    let errs :: [SpliceError]
errs = HeistState n -> [SpliceError]
forall (m :: * -> *). HeistState m -> [SpliceError]
_spliceErrors HeistState n
hs'
    let nsErr :: Either [FilePath] ()
nsErr = if Bool -> Bool
not (Text -> Bool
T.null Text
pre) Bool -> Bool -> Bool
&& (HeistState n -> Int
forall (m :: * -> *). HeistState m -> Int
_numNamespacedTags HeistState n
hs' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0)
                  then [FilePath] -> Either [FilePath] ()
forall a b. a -> Either a b
Left [FilePath -> FilePath
noNamespaceSplicesMsg (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ Text -> FilePath
T.unpack Text
pre]
                  else () -> Either [FilePath] ()
forall a b. b -> Either a b
Right ()
    Either [FilePath] (HeistState n)
-> IO (Either [FilePath] (HeistState n))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [FilePath] (HeistState n)
 -> IO (Either [FilePath] (HeistState n)))
-> Either [FilePath] (HeistState n)
-> IO (Either [FilePath] (HeistState n))
forall a b. (a -> b) -> a -> b
$ if Bool
canError
               then case [SpliceError]
errs of
                     [] -> Either [FilePath] ()
nsErr Either [FilePath] ()
-> Either [FilePath] (HeistState n)
-> Either [FilePath] (HeistState n)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
                           (HeistState n -> Either [FilePath] (HeistState n)
forall a b. b -> Either a b
Right (HeistState n -> Either [FilePath] (HeistState n))
-> HeistState n -> Either [FilePath] (HeistState n)
forall a b. (a -> b) -> a -> b
$! HeistState n
hs { _compiledTemplateMap :: HashMap TPath ([Chunk n], ByteString)
_compiledTemplateMap = HashMap TPath ([Chunk n], ByteString)
tmap })
                     [SpliceError]
es -> [FilePath] -> Either [FilePath] (HeistState n)
forall a b. a -> Either a b
Left ([FilePath] -> Either [FilePath] (HeistState n))
-> [FilePath] -> Either [FilePath] (HeistState n)
forall a b. (a -> b) -> a -> b
$ ([FilePath] -> [FilePath] -> [FilePath])
-> (() -> [FilePath] -> [FilePath])
-> Either [FilePath] ()
-> [FilePath]
-> [FilePath]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
(++) (([FilePath] -> [FilePath]) -> () -> [FilePath] -> [FilePath]
forall a b. a -> b -> a
const [FilePath] -> [FilePath]
forall a. a -> a
id) Either [FilePath] ()
nsErr ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$
                           (SpliceError -> FilePath) -> [SpliceError] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> FilePath
T.unpack (Text -> FilePath)
-> (SpliceError -> Text) -> SpliceError -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SpliceError -> Text
spliceErrorText) [SpliceError]
es
               else Either [FilePath] ()
nsErr Either [FilePath] ()
-> Either [FilePath] (HeistState n)
-> Either [FilePath] (HeistState n)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (HeistState n -> Either [FilePath] (HeistState n)
forall a b. b -> Either a b
Right (HeistState n -> Either [FilePath] (HeistState n))
-> HeistState n -> Either [FilePath] (HeistState n)
forall a b. (a -> b) -> a -> b
$! HeistState n
hs { _compiledTemplateMap :: HashMap TPath ([Chunk n], ByteString)
_compiledTemplateMap = HashMap TPath ([Chunk n], ByteString)
tmap
                                          , _spliceErrors :: [SpliceError]
_spliceErrors = [SpliceError]
errs
                                          })


------------------------------------------------------------------------------
noNamespaceSplicesMsg :: String -> String
noNamespaceSplicesMsg :: FilePath -> FilePath
noNamespaceSplicesMsg FilePath
pre = [FilePath] -> FilePath
unwords
    [ FilePath -> FilePath -> FilePath
forall r. PrintfType r => FilePath -> r
printf FilePath
"You are using a namespace of '%s', but you don't have any" FilePath
ns
    , FilePath -> FilePath -> FilePath
forall r. PrintfType r => FilePath -> r
printf FilePath
"tags starting with '%s'.  If you have not defined any" FilePath
pre
    , FilePath
"splices, then change your namespace to the empty string to get rid"
    , FilePath
"of this message."
    ]
  where
    ns :: FilePath
ns = FilePath -> FilePath
forall a. [a] -> [a]
reverse (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ Int -> FilePath -> FilePath
forall a. Int -> [a] -> [a]
drop Int
1 (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
forall a. [a] -> [a]
reverse FilePath
pre


------------------------------------------------------------------------------
compileTemplates'
    :: Monad n
    => (TPath -> Bool)
    -> HeistT n IO (H.HashMap TPath ([Chunk n], MIMEType))
compileTemplates' :: (TPath -> Bool)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
compileTemplates' TPath -> Bool
f = do
    HeistState n
hs <- HeistT n IO (HeistState n)
forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    let tpathDocfiles :: [(TPath, DocumentFile)]
        tpathDocfiles :: [(TPath, DocumentFile)]
tpathDocfiles = ((TPath, DocumentFile) -> Bool)
-> [(TPath, DocumentFile)] -> [(TPath, DocumentFile)]
forall a. (a -> Bool) -> [a] -> [a]
filter (TPath -> Bool
f (TPath -> Bool)
-> ((TPath, DocumentFile) -> TPath)
-> (TPath, DocumentFile)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TPath, DocumentFile) -> TPath
forall a b. (a, b) -> a
fst)
                            (HashMap TPath DocumentFile -> [(TPath, DocumentFile)]
forall k v. HashMap k v -> [(k, v)]
H.toList (HashMap TPath DocumentFile -> [(TPath, DocumentFile)])
-> HashMap TPath DocumentFile -> [(TPath, DocumentFile)]
forall a b. (a -> b) -> a -> b
$ HeistState n -> HashMap TPath DocumentFile
forall (m :: * -> *). HeistState m -> HashMap TPath DocumentFile
_templateMap HeistState n
hs)
    (HashMap TPath ([Chunk n], ByteString)
 -> (TPath, DocumentFile)
 -> HeistT n IO (HashMap TPath ([Chunk n], ByteString)))
-> HashMap TPath ([Chunk n], ByteString)
-> [(TPath, DocumentFile)]
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM HashMap TPath ([Chunk n], ByteString)
-> (TPath, DocumentFile)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
forall (n :: * -> *).
Monad n =>
HashMap TPath ([Chunk n], ByteString)
-> (TPath, DocumentFile)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
runOne HashMap TPath ([Chunk n], ByteString)
forall k v. HashMap k v
H.empty [(TPath, DocumentFile)]
tpathDocfiles
  where
    runOne :: HashMap TPath ([Chunk n], ByteString)
-> (TPath, DocumentFile)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
runOne HashMap TPath ([Chunk n], ByteString)
tmap (TPath
tpath, DocumentFile
df) = do
        (HeistState n -> HeistState n) -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m ()
modifyHS (\HeistState n
hs -> HeistState n
hs { _doctypes :: [DocType]
_doctypes = []})
        ![Chunk n]
mHtml <- TPath -> DocumentFile -> HeistT n IO [Chunk n]
forall (n :: * -> *).
Monad n =>
TPath -> DocumentFile -> HeistT n IO [Chunk n]
compileTemplate TPath
tpath DocumentFile
df
        HashMap TPath ([Chunk n], ByteString)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
forall (m :: * -> *) a. Monad m => a -> m a
return (HashMap TPath ([Chunk n], ByteString)
 -> HeistT n IO (HashMap TPath ([Chunk n], ByteString)))
-> HashMap TPath ([Chunk n], ByteString)
-> HeistT n IO (HashMap TPath ([Chunk n], ByteString))
forall a b. (a -> b) -> a -> b
$! TPath
-> ([Chunk n], ByteString)
-> HashMap TPath ([Chunk n], ByteString)
-> HashMap TPath ([Chunk n], ByteString)
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
H.insert TPath
tpath ([Chunk n]
mHtml, Document -> ByteString
mimeType (Document -> ByteString) -> Document -> ByteString
forall a b. (a -> b) -> a -> b
$! DocumentFile -> Document
dfDoc DocumentFile
df) HashMap TPath ([Chunk n], ByteString)
tmap


------------------------------------------------------------------------------
-- | Consolidate consecutive Pure Chunks.
consolidate :: (Monad n) => DList (Chunk n) -> [Chunk n]
consolidate :: DList (Chunk n) -> [Chunk n]
consolidate = [Chunk n] -> [Chunk n]
forall (m :: * -> *). Monad m => [Chunk m] -> [Chunk m]
consolidateL ([Chunk n] -> [Chunk n])
-> (DList (Chunk n) -> [Chunk n]) -> DList (Chunk n) -> [Chunk n]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList (Chunk n) -> [Chunk n]
forall a. DList a -> [a]
DL.toList
  where
    consolidateL :: [Chunk m] -> [Chunk m]
consolidateL []     = []
    consolidateL (Chunk m
y:[Chunk m]
ys) = [Chunk m] -> [Chunk m] -> [Chunk m]
forall (m :: * -> *). [Chunk m] -> [Chunk m] -> [Chunk m]
boilDown [] ([Chunk m] -> [Chunk m]) -> [Chunk m] -> [Chunk m]
forall a b. (a -> b) -> a -> b
$! [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
forall (m :: * -> *).
Monad m =>
[Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [] Chunk m
y [Chunk m]
ys
      where
        ----------------------------------------------------------------------
        go :: [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar Chunk m
x [] = Chunk m
x Chunk m -> [Chunk m] -> [Chunk m]
forall a. a -> [a] -> [a]
: [Chunk m]
soFar

        go [Chunk m]
soFar (Pure ByteString
a) ((Pure ByteString
b) : [Chunk m]
xs) =
            [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar (ByteString -> Chunk m
forall (m :: * -> *). ByteString -> Chunk m
Pure (ByteString -> Chunk m) -> ByteString -> Chunk m
forall a b. (a -> b) -> a -> b
$! ByteString
a ByteString -> ByteString -> ByteString
forall a. Monoid a => a -> a -> a
`mappend` ByteString
b) [Chunk m]
xs

        go [Chunk m]
soFar (RuntimeHtml RuntimeSplice m Builder
a) ((RuntimeHtml RuntimeSplice m Builder
b) : [Chunk m]
xs) =
            [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar (RuntimeSplice m Builder -> Chunk m
forall (m :: * -> *). RuntimeSplice m Builder -> Chunk m
RuntimeHtml (RuntimeSplice m Builder -> Chunk m)
-> RuntimeSplice m Builder -> Chunk m
forall a b. (a -> b) -> a -> b
$! RuntimeSplice m Builder
a RuntimeSplice m Builder
-> RuntimeSplice m Builder -> RuntimeSplice m Builder
forall a. Monoid a => a -> a -> a
`mappend` RuntimeSplice m Builder
b) [Chunk m]
xs

        go [Chunk m]
soFar (RuntimeHtml RuntimeSplice m Builder
a) ((RuntimeAction RuntimeSplice m ()
b) : [Chunk m]
xs) =
            [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar (RuntimeSplice m Builder -> Chunk m
forall (m :: * -> *). RuntimeSplice m Builder -> Chunk m
RuntimeHtml (RuntimeSplice m Builder -> Chunk m)
-> RuntimeSplice m Builder -> Chunk m
forall a b. (a -> b) -> a -> b
$! RuntimeSplice m Builder
a RuntimeSplice m Builder
-> (Builder -> RuntimeSplice m Builder) -> RuntimeSplice m Builder
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Builder
x -> RuntimeSplice m ()
b RuntimeSplice m ()
-> RuntimeSplice m Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a. Monad m => a -> m a
return Builder
x) [Chunk m]
xs

        go [Chunk m]
soFar (RuntimeAction RuntimeSplice m ()
a) ((RuntimeHtml RuntimeSplice m Builder
b) : [Chunk m]
xs) =
            [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar (RuntimeSplice m Builder -> Chunk m
forall (m :: * -> *). RuntimeSplice m Builder -> Chunk m
RuntimeHtml (RuntimeSplice m Builder -> Chunk m)
-> RuntimeSplice m Builder -> Chunk m
forall a b. (a -> b) -> a -> b
$! RuntimeSplice m ()
a RuntimeSplice m ()
-> RuntimeSplice m Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> RuntimeSplice m Builder
b) [Chunk m]
xs

        go [Chunk m]
soFar (RuntimeAction RuntimeSplice m ()
a) ((RuntimeAction RuntimeSplice m ()
b) : [Chunk m]
xs) =
            [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go [Chunk m]
soFar (RuntimeSplice m () -> Chunk m
forall (m :: * -> *). RuntimeSplice m () -> Chunk m
RuntimeAction (RuntimeSplice m () -> Chunk m) -> RuntimeSplice m () -> Chunk m
forall a b. (a -> b) -> a -> b
$! RuntimeSplice m ()
a RuntimeSplice m () -> RuntimeSplice m () -> RuntimeSplice m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> RuntimeSplice m ()
b) [Chunk m]
xs

        go [Chunk m]
soFar Chunk m
a (Chunk m
b : [Chunk m]
xs) = [Chunk m] -> Chunk m -> [Chunk m] -> [Chunk m]
go (Chunk m
a Chunk m -> [Chunk m] -> [Chunk m]
forall a. a -> [a] -> [a]
: [Chunk m]
soFar) Chunk m
b [Chunk m]
xs

        ----------------------------------------------------------------------
        boilDown :: [Chunk m] -> [Chunk m] -> [Chunk m]
boilDown [Chunk m]
soFar []              = [Chunk m]
soFar

        boilDown [Chunk m]
soFar ((Pure ByteString
h) : [Chunk m]
xs) = [Chunk m] -> [Chunk m] -> [Chunk m]
boilDown ((ByteString -> Chunk m
forall (m :: * -> *). ByteString -> Chunk m
Pure (ByteString -> Chunk m) -> ByteString -> Chunk m
forall a b. (a -> b) -> a -> b
$! ByteString
h) Chunk m -> [Chunk m] -> [Chunk m]
forall a. a -> [a] -> [a]
: [Chunk m]
soFar) [Chunk m]
xs

        boilDown [Chunk m]
soFar (Chunk m
x : [Chunk m]
xs) = [Chunk m] -> [Chunk m] -> [Chunk m]
boilDown (Chunk m
x Chunk m -> [Chunk m] -> [Chunk m]
forall a. a -> [a] -> [a]
: [Chunk m]
soFar) [Chunk m]
xs


------------------------------------------------------------------------------
-- | Given a list of output chunks, codeGen turns consecutive runs of
-- @Pure Html@ values into maximally-efficient pre-rendered strict
-- 'ByteString' chunks.
codeGen :: Monad n => DList (Chunk n) -> RuntimeSplice n Builder
codeGen :: DList (Chunk n) -> RuntimeSplice n Builder
codeGen DList (Chunk n)
l = (RuntimeSplice n Builder
 -> RuntimeSplice n Builder -> RuntimeSplice n Builder)
-> RuntimeSplice n Builder
-> Vector (RuntimeSplice n Builder)
-> RuntimeSplice n Builder
forall a b. (a -> b -> b) -> b -> Vector a -> b
V.foldr RuntimeSplice n Builder
-> RuntimeSplice n Builder -> RuntimeSplice n Builder
forall a. Monoid a => a -> a -> a
mappend RuntimeSplice n Builder
forall a. Monoid a => a
mempty (Vector (RuntimeSplice n Builder) -> RuntimeSplice n Builder)
-> Vector (RuntimeSplice n Builder) -> RuntimeSplice n Builder
forall a b. (a -> b) -> a -> b
$!
            (Chunk n -> RuntimeSplice n Builder)
-> Vector (Chunk n) -> Vector (RuntimeSplice n Builder)
forall a b. (a -> b) -> Vector a -> Vector b
V.map Chunk n -> RuntimeSplice n Builder
forall (m :: * -> *). Monad m => Chunk m -> RuntimeSplice m Builder
toAct (Vector (Chunk n) -> Vector (RuntimeSplice n Builder))
-> Vector (Chunk n) -> Vector (RuntimeSplice n Builder)
forall a b. (a -> b) -> a -> b
$! [Chunk n] -> Vector (Chunk n)
forall a. [a] -> Vector a
V.fromList ([Chunk n] -> Vector (Chunk n)) -> [Chunk n] -> Vector (Chunk n)
forall a b. (a -> b) -> a -> b
$! DList (Chunk n) -> [Chunk n]
forall (n :: * -> *). Monad n => DList (Chunk n) -> [Chunk n]
consolidate DList (Chunk n)
l
  where
    toAct :: Chunk m -> RuntimeSplice m Builder
toAct !(RuntimeHtml !RuntimeSplice m Builder
m)   = RuntimeSplice m Builder
m
    toAct !(Pure !ByteString
h)          = Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a. Monad m => a -> m a
return (Builder -> RuntimeSplice m Builder)
-> Builder -> RuntimeSplice m Builder
forall a b. (a -> b) -> a -> b
$! ByteString -> Builder
fromByteString ByteString
h
    toAct !(RuntimeAction !RuntimeSplice m ()
m) = RuntimeSplice m ()
m RuntimeSplice m ()
-> RuntimeSplice m Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a. Monad m => a -> m a
return Builder
forall a. Monoid a => a
mempty
{-# INLINE codeGen #-}


------------------------------------------------------------------------------
-- | Looks up a splice in the compiled splice map.
lookupSplice :: Text -> HeistT n IO (Maybe (Splice n))
lookupSplice :: Text -> HeistT n IO (Maybe (Splice n))
lookupSplice Text
nm = do
    Text
pre <- (HeistState n -> Text) -> HeistT n IO Text
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS HeistState n -> Text
forall (m :: * -> *). HeistState m -> Text
_splicePrefix
    Maybe (Splice n)
res <- (HeistState n -> Maybe (Splice n))
-> HeistT n IO (Maybe (Splice n))
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS (Text -> HashMap Text (Splice n) -> Maybe (Splice n)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
H.lookup Text
nm (HashMap Text (Splice n) -> Maybe (Splice n))
-> (HeistState n -> HashMap Text (Splice n))
-> HeistState n
-> Maybe (Splice n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeistState n -> HashMap Text (Splice n)
forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m IO (DList (Chunk m)))
_compiledSpliceMap)
    if Maybe (Splice n) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (Splice n)
res Bool -> Bool -> Bool
&& Text -> Text -> Bool
T.isPrefixOf Text
pre Text
nm Bool -> Bool -> Bool
&& Bool -> Bool
not (Text -> Bool
T.null Text
pre)
      then do
          Text -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m ()
tellSpliceError (Text -> HeistT n IO ()) -> Text -> HeistT n IO ()
forall a b. (a -> b) -> a -> b
$ Text
"No splice bound for " Text -> Text -> Text
forall a. Monoid a => a -> a -> a
`mappend` Text
nm
          Maybe (Splice n) -> HeistT n IO (Maybe (Splice n))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Splice n)
forall a. Maybe a
Nothing
      else Maybe (Splice n) -> HeistT n IO (Maybe (Splice n))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Splice n)
res


------------------------------------------------------------------------------
-- | Runs a single node.  If there is no splice referenced anywhere in the
-- subtree, then it is rendered as a pure chunk, otherwise it calls
-- compileNode to generate the appropriate runtime computation.
runNode :: Monad n => X.Node -> Splice n
runNode :: Node -> Splice n
runNode Node
node = (Node -> Node) -> Splice n -> Splice n
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(Node -> Node) -> HeistT n m a -> HeistT n m a
localParamNode (Node -> Node -> Node
forall a b. a -> b -> a
const Node
node) (Splice n -> Splice n) -> Splice n -> Splice n
forall a b. (a -> b) -> a -> b
$ do
    HeistState n
hs <- HeistT n IO (HeistState n)
forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    let pre :: Text
pre = HeistState n -> Text
forall (m :: * -> *). HeistState m -> Text
_splicePrefix HeistState n
hs
    let hasPrefix :: Bool
hasPrefix = (Text -> Text -> Bool
T.isPrefixOf Text
pre (Text -> Bool) -> Maybe Text -> Maybe Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Node -> Maybe Text
X.tagName Node
node) Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
    Bool -> HeistT n IO () -> HeistT n IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Text -> Bool
T.null Text
pre) Bool -> Bool -> Bool
&& Bool
hasPrefix) HeistT n IO ()
forall (m :: * -> *) (n :: * -> *). Monad m => HeistT n m ()
incNamespacedTags
    HeistState n
hs' <- HeistT n IO (HeistState n)
forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    -- Plain rethrows for CompileException to avoid multiple annotations.
    (DList (Chunk n)
res, HeistState n
hs'') <- IO (DList (Chunk n), HeistState n)
-> HeistT n IO (DList (Chunk n), HeistState n)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (DList (Chunk n), HeistState n)
 -> HeistT n IO (DList (Chunk n), HeistState n))
-> IO (DList (Chunk n), HeistState n)
-> HeistT n IO (DList (Chunk n), HeistState n)
forall a b. (a -> b) -> a -> b
$ IO (DList (Chunk n), HeistState n)
-> [Handler (DList (Chunk n), HeistState n)]
-> IO (DList (Chunk n), HeistState n)
forall a. IO a -> [Handler a] -> IO a
catches (HeistState n -> IO (DList (Chunk n), HeistState n)
forall (n :: * -> *).
Monad n =>
HeistState n -> IO (DList (Chunk n), HeistState n)
compileIO HeistState n
hs')
                     [ (CompileException -> IO (DList (Chunk n), HeistState n))
-> Handler (DList (Chunk n), HeistState n)
forall a e. Exception e => (e -> IO a) -> Handler a
Handler (\(CompileException
ex :: CompileException) -> CompileException -> IO (DList (Chunk n), HeistState n)
forall e a. Exception e => e -> IO a
throwIO CompileException
ex)
                     , (SomeException -> IO (DList (Chunk n), HeistState n))
-> Handler (DList (Chunk n), HeistState n)
forall a e. Exception e => (e -> IO a) -> Handler a
Handler (\(SomeException
ex :: SomeException) -> SomeException -> HeistState n -> IO (DList (Chunk n), HeistState n)
forall e (n :: * -> *) b. Exception e => e -> HeistState n -> IO b
handleError SomeException
ex HeistState n
hs')]
    HeistState n -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistState n -> HeistT n m ()
putHS HeistState n
hs''
    DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return DList (Chunk n)
res
  where
    localSplicePath :: HeistT m m a -> HeistT m m a
localSplicePath =
        (HeistState m -> HeistState m) -> HeistT m m a -> HeistT m m a
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m a -> HeistT n m a
localHS (\HeistState m
hs -> HeistState m
hs {_splicePath :: [(TPath, Maybe FilePath, Text)]
_splicePath = (HeistState m -> TPath
forall (m :: * -> *). HeistState m -> TPath
_curContext HeistState m
hs,
                                           HeistState m -> Maybe FilePath
forall (m :: * -> *). HeistState m -> Maybe FilePath
_curTemplateFile HeistState m
hs,
                                           Node -> Text
X.elementTag Node
node)(TPath, Maybe FilePath, Text)
-> [(TPath, Maybe FilePath, Text)]
-> [(TPath, Maybe FilePath, Text)]
forall a. a -> [a] -> [a]
:
                                          (HeistState m -> [(TPath, Maybe FilePath, Text)]
forall (m :: * -> *).
HeistState m -> [(TPath, Maybe FilePath, Text)]
_splicePath HeistState m
hs)})
    compileIO :: HeistState n -> IO (DList (Chunk n), HeistState n)
compileIO HeistState n
hs = HeistT n IO (DList (Chunk n))
-> Node -> HeistState n -> IO (DList (Chunk n), HeistState n)
forall (n :: * -> *) (m :: * -> *) a.
HeistT n m a -> Node -> HeistState n -> m (a, HeistState n)
runHeistT HeistT n IO (DList (Chunk n))
forall (n :: * -> *). Monad n => HeistT n IO (DList (Chunk n))
compile Node
node HeistState n
hs
    compile :: HeistT n IO (DList (Chunk n))
compile = do
        Bool
isStatic <- Node -> HeistT n IO Bool
forall (n :: * -> *). Node -> HeistT n IO Bool
subtreeIsStatic Node
node
        DList (Chunk n)
dl <- Bool -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *).
Monad n =>
Bool -> HeistT n IO (DList (Chunk n))
compile' Bool
isStatic
        IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n)))
-> IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ DList (Chunk n) -> IO (DList (Chunk n))
forall a. a -> IO a
evaluate (DList (Chunk n) -> IO (DList (Chunk n)))
-> DList (Chunk n) -> IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ [Chunk n] -> DList (Chunk n)
forall a. [a] -> DList a
DL.fromList ([Chunk n] -> DList (Chunk n)) -> [Chunk n] -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! DList (Chunk n) -> [Chunk n]
forall (n :: * -> *). Monad n => DList (Chunk n) -> [Chunk n]
consolidate DList (Chunk n)
dl
    compile' :: Bool -> HeistT n IO (DList (Chunk n))
compile' Bool
True = do
        Markup
markup <- (HeistState n -> Markup) -> HeistT n IO Markup
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS HeistState n -> Markup
forall (m :: * -> *). HeistState m -> Markup
_curMarkup
        DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$! Builder -> DList (Chunk n)
forall (n :: * -> *). Builder -> DList (Chunk n)
yieldPure (Builder -> DList (Chunk n)) -> Builder -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Markup -> [Node] -> Builder
renderFragment Markup
markup [Node -> Node
parseAttrs Node
node]
    compile' Bool
False = HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) (m :: * -> *) a.
Monad m =>
HeistT m m a -> HeistT m m a
localSplicePath (HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n)))
-> HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Node -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *). Monad n => Node -> Splice n
compileNode Node
node
    handleError :: e -> HeistState n -> IO b
handleError e
ex HeistState n
hs = do
        [SpliceError]
errs <- HeistT n IO [SpliceError]
-> Node -> HeistState n -> IO [SpliceError]
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
HeistT n m a -> Node -> HeistState n -> m a
evalHeistT (do HeistT n IO () -> HeistT n IO ()
forall (m :: * -> *) (m :: * -> *) a.
Monad m =>
HeistT m m a -> HeistT m m a
localSplicePath (HeistT n IO () -> HeistT n IO ())
-> HeistT n IO () -> HeistT n IO ()
forall a b. (a -> b) -> a -> b
$ Text -> HeistT n IO ()
forall (m :: * -> *) (n :: * -> *).
Monad m =>
Text -> HeistT n m ()
tellSpliceError (Text -> HeistT n IO ()) -> Text -> HeistT n IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$
                                 FilePath
"Exception in splice compile: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ e -> FilePath
forall a. Show a => a -> FilePath
show e
ex
                               (HeistState n -> [SpliceError]) -> HeistT n IO [SpliceError]
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS HeistState n -> [SpliceError]
forall (m :: * -> *). HeistState m -> [SpliceError]
_spliceErrors) Node
node HeistState n
hs
        CompileException -> IO b
forall e a. Exception e => e -> IO a
throwIO (CompileException -> IO b) -> CompileException -> IO b
forall a b. (a -> b) -> a -> b
$ e -> [SpliceError] -> CompileException
forall e. Exception e => e -> [SpliceError] -> CompileException
CompileException e
ex [SpliceError]
errs


parseAttrs :: X.Node -> X.Node
parseAttrs :: Node -> Node
parseAttrs (X.Element Text
nm [(Text, Text)]
attrs [Node]
ch) = [(Text, Text)]
newAttrs [(Text, Text)] -> Node -> Node
`seq` Text -> [(Text, Text)] -> [Node] -> Node
X.Element Text
nm [(Text, Text)]
newAttrs [Node]
ch
  where
    newAttrs :: [(Text, Text)]
newAttrs = ((Text, Text) -> (Text, Text)) -> [(Text, Text)] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Text) -> (Text, Text)
parseAttr [(Text, Text)]
attrs
parseAttrs !Node
n = Node
n

parseAttr :: (Text, Text) -> (Text, Text)
parseAttr :: (Text, Text) -> (Text, Text)
parseAttr (Text
k,Text
v) = (Text
k, [Text] -> Text
T.concat ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$! (AttAST -> Text) -> [AttAST] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map AttAST -> Text
cvt [AttAST]
ast)
  where
    !ast :: [AttAST]
ast = case IResult Text [AttAST] -> Text -> IResult Text [AttAST]
forall i r. Monoid i => IResult i r -> i -> IResult i r
AP.feed (Parser [AttAST] -> Text -> IResult Text [AttAST]
forall a. Parser a -> Text -> Result a
AP.parse Parser [AttAST]
attParser Text
v) Text
"" of
            (AP.Done Text
_ [AttAST]
res) -> [AttAST]
res
            (AP.Fail Text
_ [FilePath]
_ FilePath
_) -> []
            (AP.Partial Text -> IResult Text [AttAST]
_ ) -> []
    cvt :: AttAST -> Text
cvt (Literal Text
x) = Text
x
    cvt (Ident Text
i) = [Text] -> Text
T.concat [Text
"${", Text
i, Text
"}"]

------------------------------------------------------------------------------
-- | Checks whether a node's subtree is static and can be rendered up front at
-- load time.
subtreeIsStatic :: X.Node -> HeistT n IO Bool
subtreeIsStatic :: Node -> HeistT n IO Bool
subtreeIsStatic (X.Element Text
nm [(Text, Text)]
attrs [Node]
ch) = do
    Bool
isNodeDynamic <- (Maybe (Splice n) -> Bool)
-> HeistT n IO (Maybe (Splice n)) -> HeistT n IO Bool
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Maybe (Splice n) -> Bool
forall a. Maybe a -> Bool
isJust (HeistT n IO (Maybe (Splice n)) -> HeistT n IO Bool)
-> HeistT n IO (Maybe (Splice n)) -> HeistT n IO Bool
forall a b. (a -> b) -> a -> b
$ Text -> HeistT n IO (Maybe (Splice n))
forall (n :: * -> *). Text -> HeistT n IO (Maybe (Splice n))
lookupSplice Text
nm
    HashMap Text (AttrSplice n)
attrSplices <- (HeistState n -> HashMap Text (AttrSplice n))
-> HeistT n IO (HashMap Text (AttrSplice n))
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS HeistState n -> HashMap Text (AttrSplice n)
forall (m :: * -> *). HeistState m -> HashMap Text (AttrSplice m)
_attrSpliceMap
    let hasSubstitutions :: (Text, Text) -> Bool
hasSubstitutions (Text
k,Text
v) = Text -> Bool
hasAttributeSubstitutions Text
v Bool -> Bool -> Bool
||
                                 Text -> HashMap Text (AttrSplice n) -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
H.member Text
k HashMap Text (AttrSplice n)
attrSplices
    if Bool
isNodeDynamic
      then Bool -> HeistT n IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
      else do
          let hasDynamicAttrs :: Bool
hasDynamicAttrs = ((Text, Text) -> Bool) -> [(Text, Text)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Text, Text) -> Bool
hasSubstitutions [(Text, Text)]
attrs
          if Bool
hasDynamicAttrs
            then Bool -> HeistT n IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
            else do
                [Bool]
staticSubtrees <- (Node -> HeistT n IO Bool) -> [Node] -> HeistT n IO [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Node -> HeistT n IO Bool
forall (n :: * -> *). Node -> HeistT n IO Bool
subtreeIsStatic [Node]
ch
                Bool -> HeistT n IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> HeistT n IO Bool) -> Bool -> HeistT n IO Bool
forall a b. (a -> b) -> a -> b
$ [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [Bool]
staticSubtrees

subtreeIsStatic Node
_ = Bool -> HeistT n IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True


------------------------------------------------------------------------------
-- | Checks whether a string has any attribute substitutions.
hasAttributeSubstitutions :: Text -> Bool
hasAttributeSubstitutions :: Text -> Bool
hasAttributeSubstitutions Text
txt = (AttAST -> Bool) -> [AttAST] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any AttAST -> Bool
isIdent [AttAST]
ast
  where
    ast :: [AttAST]
ast = case IResult Text [AttAST] -> Text -> IResult Text [AttAST]
forall i r. Monoid i => IResult i r -> i -> IResult i r
AP.feed (Parser [AttAST] -> Text -> IResult Text [AttAST]
forall a. Parser a -> Text -> Result a
AP.parse Parser [AttAST]
attParser Text
txt) Text
"" of
            (AP.Done Text
_ [AttAST]
res) -> [AttAST]
res
            (AP.Fail Text
_ [FilePath]
_ FilePath
_) -> []
            (AP.Partial Text -> IResult Text [AttAST]
_ ) -> []


------------------------------------------------------------------------------
-- | Given a 'X.Node' in the DOM tree, produces a \"runtime splice\" that will
-- generate html at runtime.
compileNode :: Monad n => X.Node -> Splice n
compileNode :: Node -> Splice n
compileNode (X.Element Text
nm [(Text, Text)]
attrs [Node]
ch) = do
    Maybe (Splice n)
msplice <- Text -> HeistT n IO (Maybe (Splice n))
forall (n :: * -> *). Text -> HeistT n IO (Maybe (Splice n))
lookupSplice Text
nm
    Splice n -> Maybe (Splice n) -> Splice n
forall a. a -> Maybe a -> a
fromMaybe Splice n
forall (n :: * -> *). Monad n => HeistT n IO (DList (Chunk n))
compileStaticElement Maybe (Splice n)
msplice
  where
    tag0 :: Text
tag0 = Text -> Text -> Text
T.append Text
"<" Text
nm
    end :: Text
end = [Text] -> Text
T.concat [ Text
"</" , Text
nm , Text
">"]
    -- If the tag is not a splice, but it contains dynamic children
    compileStaticElement :: HeistT n IO (DList (Chunk n))
compileStaticElement = do
        -- Parse the attributes: we have Left for static and Right for runtime
        [DList (Chunk n)]
compiledAttrs <- [(Text, Text)] -> HeistT n IO [DList (Chunk n)]
forall (n :: * -> *).
Monad n =>
[(Text, Text)] -> HeistT n IO [DList (Chunk n)]
runAttributes [(Text, Text)]
attrs

        DList (Chunk n)
childHtml <- [Node] -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *). Monad n => [Node] -> Splice n
runNodeList [Node]
ch

        DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$! if [Chunk n] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (DList (Chunk n) -> [Chunk n]
forall a. DList a -> [a]
DL.toList DList (Chunk n)
childHtml) Bool -> Bool -> Bool
&& Text
nm Text -> HashSet Text -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`S.member` HashSet Text
X.voidTags
          then [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat [ Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk (Text -> Chunk n) -> Text -> Chunk n
forall a b. (a -> b) -> a -> b
$! Text
tag0
                         , [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat [DList (Chunk n)]
compiledAttrs
                         , Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk Text
" />"
                         ]
          else [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat [ Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk (Text -> Chunk n) -> Text -> Chunk n
forall a b. (a -> b) -> a -> b
$! Text
tag0
                         , [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat [DList (Chunk n)]
compiledAttrs
                         , Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk Text
">"
                         , DList (Chunk n)
childHtml
                         , Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk (Text -> Chunk n) -> Text -> Chunk n
forall a b. (a -> b) -> a -> b
$! Text
end
                         ]
compileNode Node
_ = FilePath -> Splice n
forall a. HasCallStack => FilePath -> a
error FilePath
"impossible"


------------------------------------------------------------------------------
-- |
parseAtt :: Monad n => (Text, Text) -> HeistT n IO (DList (Chunk n))
parseAtt :: (Text, Text) -> HeistT n IO (DList (Chunk n))
parseAtt (Text
k,Text
v) = do
    Maybe (AttrSplice n)
mas <- (HeistState n -> Maybe (AttrSplice n))
-> HeistT n IO (Maybe (AttrSplice n))
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS (Text -> HashMap Text (AttrSplice n) -> Maybe (AttrSplice n)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
H.lookup Text
k (HashMap Text (AttrSplice n) -> Maybe (AttrSplice n))
-> (HeistState n -> HashMap Text (AttrSplice n))
-> HeistState n
-> Maybe (AttrSplice n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeistState n -> HashMap Text (AttrSplice n)
forall (m :: * -> *). HeistState m -> HashMap Text (AttrSplice m)
_attrSpliceMap)
    HeistT n IO (DList (Chunk n))
-> (AttrSplice n -> HeistT n IO (DList (Chunk n)))
-> Maybe (AttrSplice n)
-> HeistT n IO (DList (Chunk n))
forall b a. b -> (a -> b) -> Maybe a -> b
maybe HeistT n IO (DList (Chunk n))
forall (n :: * -> *). HeistT n IO (DList (Chunk n))
doInline (DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> (AttrSplice n -> DList (Chunk n))
-> AttrSplice n
-> HeistT n IO (DList (Chunk n))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AttrSplice n -> DList (Chunk n)
forall (m :: * -> *).
Monad m =>
(Text -> RuntimeSplice m [(Text, Text)]) -> DList (Chunk m)
doAttrSplice) Maybe (AttrSplice n)
mas

  where
    cvt :: AttAST -> HeistT n IO (DList (Chunk n))
cvt (Literal Text
x) = DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Text -> DList (Chunk n)
forall (n :: * -> *). Text -> DList (Chunk n)
yieldPureText Text
x
    cvt (Ident Text
x) =
        (Node -> Node)
-> HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(Node -> Node) -> HeistT n m a -> HeistT n m a
localParamNode (Node -> Node -> Node
forall a b. a -> b -> a
const (Node -> Node -> Node) -> Node -> Node -> Node
forall a b. (a -> b) -> a -> b
$ Text -> [(Text, Text)] -> [Node] -> Node
X.Element Text
x [] []) (HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n)))
-> HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Text -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *). Text -> HeistT n IO (DList (Chunk n))
getAttributeSplice Text
x

    -- Handles inline parsing of $() splice syntax in attributes
    doInline :: HeistT n IO (DList (Chunk n))
doInline = do
        let ast :: [AttAST]
ast = case IResult Text [AttAST] -> Text -> IResult Text [AttAST]
forall i r. Monoid i => IResult i r -> i -> IResult i r
AP.feed (Parser [AttAST] -> Text -> IResult Text [AttAST]
forall a. Parser a -> Text -> Result a
AP.parse Parser [AttAST]
attParser Text
v) Text
"" of
                    (AP.Done Text
_ [AttAST]
res) -> [AttAST]
res
                    (AP.Fail Text
_ [FilePath]
_ FilePath
_) -> []
                    (AP.Partial Text -> IResult Text [AttAST]
_ ) -> []
        [DList (Chunk n)]
chunks <- (AttAST -> HeistT n IO (DList (Chunk n)))
-> [AttAST] -> HeistT n IO [DList (Chunk n)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM AttAST -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *). AttAST -> HeistT n IO (DList (Chunk n))
cvt [AttAST]
ast
        let value :: DList (Chunk n)
value = [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat [DList (Chunk n)]
chunks
        DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Text -> DList (Chunk n) -> DList (Chunk n)
forall (n :: * -> *). Text -> DList (Chunk n) -> DList (Chunk n)
attrToChunk Text
k DList (Chunk n)
value

    -- Handles attribute splices
    doAttrSplice :: (Text -> RuntimeSplice m [(Text, Text)]) -> DList (Chunk m)
doAttrSplice Text -> RuntimeSplice m [(Text, Text)]
splice = Chunk m -> DList (Chunk m)
forall a. a -> DList a
DL.singleton (Chunk m -> DList (Chunk m)) -> Chunk m -> DList (Chunk m)
forall a b. (a -> b) -> a -> b
$ RuntimeSplice m Builder -> Chunk m
forall (m :: * -> *). RuntimeSplice m Builder -> Chunk m
RuntimeHtml (RuntimeSplice m Builder -> Chunk m)
-> RuntimeSplice m Builder -> Chunk m
forall a b. (a -> b) -> a -> b
$ do
        [(Text, Text)]
res <- Text -> RuntimeSplice m [(Text, Text)]
splice Text
v
        Builder -> RuntimeSplice m Builder
forall (m :: * -> *) a. Monad m => a -> m a
return (Builder -> RuntimeSplice m Builder)
-> Builder -> RuntimeSplice m Builder
forall a b. (a -> b) -> a -> b
$ [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ ((Text, Text) -> Builder) -> [(Text, Text)] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Text) -> Builder
attrToBuilder [(Text, Text)]
res


------------------------------------------------------------------------------
-- |
parseAtt2 :: Monad n
          => (Text, Text)
          -> HeistT n IO (RuntimeSplice n [(Text, Text)])
parseAtt2 :: (Text, Text) -> HeistT n IO (RuntimeSplice n [(Text, Text)])
parseAtt2 (Text
k,Text
v) = do
    Maybe (AttrSplice n)
mas <- (HeistState n -> Maybe (AttrSplice n))
-> HeistT n IO (Maybe (AttrSplice n))
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS (Text -> HashMap Text (AttrSplice n) -> Maybe (AttrSplice n)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
H.lookup Text
k (HashMap Text (AttrSplice n) -> Maybe (AttrSplice n))
-> (HeistState n -> HashMap Text (AttrSplice n))
-> HeistState n
-> Maybe (AttrSplice n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeistState n -> HashMap Text (AttrSplice n)
forall (m :: * -> *). HeistState m -> HashMap Text (AttrSplice m)
_attrSpliceMap)
    HeistT n IO (RuntimeSplice n [(Text, Text)])
-> (AttrSplice n -> HeistT n IO (RuntimeSplice n [(Text, Text)]))
-> Maybe (AttrSplice n)
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe HeistT n IO (RuntimeSplice n [(Text, Text)])
forall (n :: * -> *).
Monad n =>
HeistT n IO (RuntimeSplice n [(Text, Text)])
doInline (RuntimeSplice n [(Text, Text)]
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n [(Text, Text)]
 -> HeistT n IO (RuntimeSplice n [(Text, Text)]))
-> (AttrSplice n -> RuntimeSplice n [(Text, Text)])
-> AttrSplice n
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AttrSplice n -> RuntimeSplice n [(Text, Text)]
forall t. (Text -> t) -> t
doAttrSplice) Maybe (AttrSplice n)
mas

  where
    cvt :: AttAST -> HeistT n IO (RuntimeSplice n Text)
cvt (Literal Text
x) = RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text))
-> RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall a b. (a -> b) -> a -> b
$ Text -> RuntimeSplice n Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
x
    cvt (Ident Text
x) =
        (Node -> Node)
-> HeistT n IO (RuntimeSplice n Text)
-> HeistT n IO (RuntimeSplice n Text)
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(Node -> Node) -> HeistT n m a -> HeistT n m a
localParamNode (Node -> Node -> Node
forall a b. a -> b -> a
const (Node -> Node -> Node) -> Node -> Node -> Node
forall a b. (a -> b) -> a -> b
$ Text -> [(Text, Text)] -> [Node] -> Node
X.Element Text
x [] []) (HeistT n IO (RuntimeSplice n Text)
 -> HeistT n IO (RuntimeSplice n Text))
-> HeistT n IO (RuntimeSplice n Text)
-> HeistT n IO (RuntimeSplice n Text)
forall a b. (a -> b) -> a -> b
$ Text -> HeistT n IO (RuntimeSplice n Text)
forall (n :: * -> *).
Monad n =>
Text -> HeistT n IO (RuntimeSplice n Text)
getAttributeSplice2 Text
x

    -- Handles inline parsing of $() splice syntax in attributes
    doInline :: HeistT n IO (RuntimeSplice n [(Text, Text)])
doInline = do
        let ast :: [AttAST]
ast = case IResult Text [AttAST] -> Text -> IResult Text [AttAST]
forall i r. Monoid i => IResult i r -> i -> IResult i r
AP.feed (Parser [AttAST] -> Text -> IResult Text [AttAST]
forall a. Parser a -> Text -> Result a
AP.parse Parser [AttAST]
attParser Text
v) Text
"" of
                    (AP.Done Text
_ [AttAST]
res) -> [AttAST]
res
                    (AP.Fail Text
_ [FilePath]
_ FilePath
_) -> []
                    (AP.Partial Text -> IResult Text [AttAST]
_ ) -> []
        [RuntimeSplice n Text]
chunks <- (AttAST -> HeistT n IO (RuntimeSplice n Text))
-> [AttAST] -> HeistT n IO [RuntimeSplice n Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM AttAST -> HeistT n IO (RuntimeSplice n Text)
forall (n :: * -> *).
Monad n =>
AttAST -> HeistT n IO (RuntimeSplice n Text)
cvt [AttAST]
ast
        RuntimeSplice n [(Text, Text)]
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n [(Text, Text)]
 -> HeistT n IO (RuntimeSplice n [(Text, Text)]))
-> RuntimeSplice n [(Text, Text)]
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall a b. (a -> b) -> a -> b
$ do
            [Text]
list <- [RuntimeSplice n Text] -> RuntimeSplice n [Text]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [RuntimeSplice n Text]
chunks
            [(Text, Text)] -> RuntimeSplice n [(Text, Text)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(Text
k, [Text] -> Text
T.concat [Text]
list)]

    -- Handles attribute splices
    doAttrSplice :: (Text -> t) -> t
doAttrSplice Text -> t
splice = Text -> t
splice Text
v


------------------------------------------------------------------------------
-- | 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)] -- ^ List of attributes
              -> HeistT n IO [DList (Chunk n)]
runAttributes :: [(Text, Text)] -> HeistT n IO [DList (Chunk n)]
runAttributes = ((Text, Text) -> HeistT n IO (DList (Chunk n)))
-> [(Text, Text)] -> HeistT n IO [DList (Chunk n)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Text, Text) -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *).
Monad n =>
(Text, Text) -> HeistT n IO (DList (Chunk n))
parseAtt


------------------------------------------------------------------------------
-- | 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.
runAttributesRaw :: Monad n
                 -- Note that this parameter should not be changed to Splices
                 => [(Text, Text)] -- ^ List of attributes
                 -> HeistT n IO (RuntimeSplice n [(Text, Text)])
runAttributesRaw :: [(Text, Text)] -> HeistT n IO (RuntimeSplice n [(Text, Text)])
runAttributesRaw [(Text, Text)]
attrs = do
    [RuntimeSplice n [(Text, Text)]]
arrs <- ((Text, Text) -> HeistT n IO (RuntimeSplice n [(Text, Text)]))
-> [(Text, Text)] -> HeistT n IO [RuntimeSplice n [(Text, Text)]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Text, Text) -> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall (n :: * -> *).
Monad n =>
(Text, Text) -> HeistT n IO (RuntimeSplice n [(Text, Text)])
parseAtt2 [(Text, Text)]
attrs
    RuntimeSplice n [(Text, Text)]
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n [(Text, Text)]
 -> HeistT n IO (RuntimeSplice n [(Text, Text)]))
-> RuntimeSplice n [(Text, Text)]
-> HeistT n IO (RuntimeSplice n [(Text, Text)])
forall a b. (a -> b) -> a -> b
$ ([[(Text, Text)]] -> [(Text, Text)])
-> RuntimeSplice n [[(Text, Text)]]
-> RuntimeSplice n [(Text, Text)]
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [[(Text, Text)]] -> [(Text, Text)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (RuntimeSplice n [[(Text, Text)]]
 -> RuntimeSplice n [(Text, Text)])
-> RuntimeSplice n [[(Text, Text)]]
-> RuntimeSplice n [(Text, Text)]
forall a b. (a -> b) -> a -> b
$ [RuntimeSplice n [(Text, Text)]]
-> RuntimeSplice n [[(Text, Text)]]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [RuntimeSplice n [(Text, Text)]]
arrs


attrToChunk :: Text -> DList (Chunk n) -> DList (Chunk n)
attrToChunk :: Text -> DList (Chunk n) -> DList (Chunk n)
attrToChunk !Text
k !DList (Chunk n)
v = do
    [DList (Chunk n)] -> DList (Chunk n)
forall a. [DList a] -> DList a
DL.concat
        [ Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk (Text -> Chunk n) -> Text -> Chunk n
forall a b. (a -> b) -> a -> b
$! [Text] -> Text
T.concat [Text
" ", Text
k, Text
"=\""]
        , DList (Chunk n)
v, Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$! Text -> Chunk n
forall (n :: * -> *). Text -> Chunk n
pureTextChunk Text
"\"" ]


attrToBuilder :: (Text, Text) -> Builder
attrToBuilder :: (Text, Text) -> Builder
attrToBuilder (Text
k,Text
v)
  | Text -> Bool
T.null Text
v  = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat
    [ Text -> Builder
fromText Text
" "
    , Text -> Builder
fromText Text
k
    ]
  | Bool
otherwise = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat
    [ Text -> Builder
fromText Text
" "
    , Text -> Builder
fromText Text
k
    , Text -> Builder
fromText Text
"=\""
    , Text -> Builder
fromText Text
v
    , Text -> Builder
fromText Text
"\""
    ]


------------------------------------------------------------------------------
getAttributeSplice :: Text -> HeistT n IO (DList (Chunk n))
getAttributeSplice :: Text -> HeistT n IO (DList (Chunk n))
getAttributeSplice Text
name =
    Text -> HeistT n IO (Maybe (HeistT n IO (DList (Chunk n))))
forall (n :: * -> *). Text -> HeistT n IO (Maybe (Splice n))
lookupSplice Text
name HeistT n IO (Maybe (HeistT n IO (DList (Chunk n))))
-> (Maybe (HeistT n IO (DList (Chunk n)))
    -> HeistT n IO (DList (Chunk n)))
-> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HeistT n IO (DList (Chunk n))
-> Maybe (HeistT n IO (DList (Chunk n)))
-> HeistT n IO (DList (Chunk n))
forall a. a -> Maybe a -> a
fromMaybe
      (DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> HeistT n IO (DList (Chunk n)))
-> DList (Chunk n) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Chunk n -> DList (Chunk n)
forall a. a -> DList a
DL.singleton (Chunk n -> DList (Chunk n)) -> Chunk n -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$ ByteString -> Chunk n
forall (m :: * -> *). ByteString -> Chunk m
Pure (ByteString -> Chunk n) -> ByteString -> Chunk n
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$
       [Text] -> Text
T.concat [Text
"${", Text
name, Text
"}"])
{-# INLINE getAttributeSplice #-}


getAttributeSplice2 :: Monad n => Text -> HeistT n IO (RuntimeSplice n Text)
getAttributeSplice2 :: Text -> HeistT n IO (RuntimeSplice n Text)
getAttributeSplice2 Text
name = do
    Maybe (Splice n)
mSplice <- Text -> HeistT n IO (Maybe (Splice n))
forall (n :: * -> *). Text -> HeistT n IO (Maybe (Splice n))
lookupSplice Text
name
    case Maybe (Splice n)
mSplice of
      Maybe (Splice n)
Nothing -> RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text))
-> RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall a b. (a -> b) -> a -> b
$ Text -> RuntimeSplice n Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> RuntimeSplice n Text) -> Text -> RuntimeSplice n Text
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.concat [Text
"${", Text
name, Text
"}"]
      Just Splice n
splice -> do
        DList (Chunk n)
res <- Splice n
splice
        RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text))
-> RuntimeSplice n Text -> HeistT n IO (RuntimeSplice n Text)
forall a b. (a -> b) -> a -> b
$ (Builder -> Text)
-> RuntimeSplice n Builder -> RuntimeSplice n Text
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (ByteString -> Text
T.decodeUtf8 (ByteString -> Text) -> (Builder -> ByteString) -> Builder -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
toByteString) (RuntimeSplice n Builder -> RuntimeSplice n Text)
-> RuntimeSplice n Builder -> RuntimeSplice n Text
forall a b. (a -> b) -> a -> b
$ DList (Chunk n) -> RuntimeSplice n Builder
forall (n :: * -> *).
Monad n =>
DList (Chunk n) -> RuntimeSplice n Builder
codeGen DList (Chunk n)
res
{-# INLINE getAttributeSplice2 #-}


------------------------------------------------------------------------------
-- | Promises are used for referencing the results of future runtime
-- computations during load time splice processing.
newtype Promise a = Promise (HE.Key a)


------------------------------------------------------------------------------
-- | Gets the result of a promised runtime computation.
getPromise :: (Monad n) => Promise a -> RuntimeSplice n a
getPromise :: Promise a -> RuntimeSplice n a
getPromise (Promise Key a
k) = do
    Maybe a
mb <- (HeterogeneousEnvironment -> Maybe a) -> RuntimeSplice n (Maybe a)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Key a -> HeterogeneousEnvironment -> Maybe a
forall a. Key a -> HeterogeneousEnvironment -> Maybe a
HE.lookup Key a
k)
    a -> RuntimeSplice n a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> RuntimeSplice n a) -> a -> RuntimeSplice n a
forall a b. (a -> b) -> a -> b
$ a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
forall a. a
e Maybe a
mb

  where
    e :: a
e = FilePath -> a
forall a. HasCallStack => FilePath -> a
error (FilePath -> a) -> FilePath -> a
forall a b. (a -> b) -> a -> b
$ FilePath
"getPromise: dereferenced empty key (id "
                FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show (Key a -> Int
forall a. Key a -> Int
HE.getKeyId Key a
k) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
")"
{-# INLINE getPromise #-}


------------------------------------------------------------------------------
-- | Adds a promise to the runtime splice context.
putPromise :: (Monad n) => Promise a -> a -> RuntimeSplice n ()
putPromise :: Promise a -> a -> RuntimeSplice n ()
putPromise (Promise Key a
k) a
x = (HeterogeneousEnvironment -> HeterogeneousEnvironment)
-> RuntimeSplice n ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (Key a -> a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
forall a.
Key a -> a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
HE.insert Key a
k a
x)
{-# INLINE putPromise #-}


------------------------------------------------------------------------------
-- | Modifies a promise.
adjustPromise :: Monad n => Promise a -> (a -> a) -> RuntimeSplice n ()
adjustPromise :: Promise a -> (a -> a) -> RuntimeSplice n ()
adjustPromise (Promise Key a
k) a -> a
f = (HeterogeneousEnvironment -> HeterogeneousEnvironment)
-> RuntimeSplice n ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((a -> a)
-> Key a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
forall a.
(a -> a)
-> Key a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
HE.adjust a -> a
f Key a
k)
{-# INLINE adjustPromise #-}


------------------------------------------------------------------------------
-- | Creates an empty promise.
newEmptyPromise :: HeistT n IO (Promise a)
newEmptyPromise :: HeistT n IO (Promise a)
newEmptyPromise = do
    KeyGen
keygen <- (HeistState n -> KeyGen) -> HeistT n IO KeyGen
forall (m :: * -> *) (n :: * -> *) r.
Monad m =>
(HeistState n -> r) -> HeistT n m r
getsHS HeistState n -> KeyGen
forall (m :: * -> *). HeistState m -> KeyGen
_keygen
    Key a
key    <- IO (Key a) -> HeistT n IO (Key a)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Key a) -> HeistT n IO (Key a))
-> IO (Key a) -> HeistT n IO (Key a)
forall a b. (a -> b) -> a -> b
$ KeyGen -> IO (Key a)
forall a. KeyGen -> IO (Key a)
HE.makeKey KeyGen
keygen
    Promise a -> HeistT n IO (Promise a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Promise a -> HeistT n IO (Promise a))
-> Promise a -> HeistT n IO (Promise a)
forall a b. (a -> b) -> a -> b
$! Key a -> Promise a
forall a. Key a -> Promise a
Promise Key a
key
{-# INLINE newEmptyPromise #-}


-- ------------------------------------------------------------------------------
-- -- | Creates an empty promise with some error checking to help with debugging.
-- newEmptyPromiseWithError :: (Monad n)
--                          => String -> HeistT n IO (Promise a)
-- newEmptyPromiseWithError from = do
--     keygen <- getsHS _keygen
--     prom   <- liftM Promise $ liftIO $ HE.makeKey keygen
--     yieldRuntimeEffect $ putPromise prom
--                        $ error
--                        $ "deferenced empty promise created at" ++ from
--     return prom
-- {-# INLINE newEmptyPromiseWithError #-}


------------------------------------------------------------------------------
-- | Binds a compiled splice.  This function should not be exported.
bindSplice :: Text             -- ^ tag name
           -> Splice n         -- ^ splice action
           -> HeistState n     -- ^ source state
           -> HeistState n
bindSplice :: Text -> Splice n -> HeistState n -> HeistState n
bindSplice Text
n Splice n
v HeistState n
ts =
    HeistState n
ts { _compiledSpliceMap :: HashMap Text (Splice n)
_compiledSpliceMap = Text
-> Splice n -> HashMap Text (Splice n) -> HashMap Text (Splice n)
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
H.insert Text
n' Splice n
v (HeistState n -> HashMap Text (Splice n)
forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m IO (DList (Chunk m)))
_compiledSpliceMap HeistState n
ts) }
  where
    n' :: Text
n' = HeistState n -> Text
forall (m :: * -> *). HeistState m -> Text
_splicePrefix HeistState n
ts Text -> Text -> Text
forall a. Monoid a => a -> a -> a
`mappend` Text
n

------------------------------------------------------------------------------
-- | Binds a list of compiled splices.  This function should not be exported.
bindSplices :: Splices (Splice n)  -- ^ splices to bind
            -> HeistState n        -- ^ source state
            -> HeistState n
bindSplices :: Splices (Splice n) -> HeistState n -> HeistState n
bindSplices Splices (Splice n)
ss HeistState n
hs =
    HeistState n
hs { _compiledSpliceMap :: HashMap Text (Splice n)
_compiledSpliceMap = HeistState n
-> (HeistState n -> HashMap Text (Splice n))
-> Splices (Splice n)
-> HashMap Text (Splice n)
forall (n :: * -> *) v a.
HeistState n
-> (HeistState n -> HashMap Text v)
-> MapSyntaxM Text v a
-> HashMap Text v
applySpliceMap HeistState n
hs HeistState n -> HashMap Text (Splice n)
forall (m :: * -> *).
HeistState m -> HashMap Text (HeistT m IO (DList (Chunk m)))
_compiledSpliceMap Splices (Splice n)
ss }


------------------------------------------------------------------------------
-- | Adds a list of compiled splices to the splice map.  This function is
-- useful because it allows compiled splices to bind other compiled splices
-- during load-time splice processing.
withLocalSplices :: Splices (Splice n)
                 -> Splices (AttrSplice n)
                 -> HeistT n IO a
                 -> HeistT n IO a
withLocalSplices :: Splices (Splice n)
-> Splices (AttrSplice n) -> HeistT n IO a -> HeistT n IO a
withLocalSplices Splices (Splice n)
ss Splices (AttrSplice n)
as = (HeistState n -> HeistState n) -> HeistT n IO a -> HeistT n IO a
forall (m :: * -> *) (n :: * -> *) a.
Monad m =>
(HeistState n -> HeistState n) -> HeistT n m a -> HeistT n m a
localHS (Splices (Splice n) -> HeistState n -> HeistState n
forall (n :: * -> *).
Splices (Splice n) -> HeistState n -> HeistState n
bindSplices Splices (Splice n)
ss (HeistState n -> HeistState n)
-> (HeistState n -> HeistState n) -> HeistState n -> HeistState n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Splices (AttrSplice n) -> HeistState n -> HeistState n
forall (n :: * -> *).
Splices (AttrSplice n) -> HeistState n -> HeistState n
bindAttributeSplices Splices (AttrSplice n)
as)


------------------------------------------------------------------------------
-- | Looks up a compiled template and returns a runtime monad computation that
-- constructs a builder.
--
-- Note that template names should not include the .tpl extension:
--
-- @renderTemplate hs "index"@
renderTemplate :: Monad n
               => HeistState n
               -> ByteString
               -> Maybe (n Builder, MIMEType)
renderTemplate :: HeistState n -> ByteString -> Maybe (n Builder, ByteString)
renderTemplate HeistState n
hs ByteString
nm =
    ((([Chunk n], ByteString), TPath) -> (n Builder, ByteString))
-> Maybe (([Chunk n], ByteString), TPath)
-> Maybe (n Builder, ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([Chunk n] -> n Builder)
-> ([Chunk n], ByteString) -> (n Builder, ByteString)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (DList (Chunk n) -> n Builder
forall (n :: * -> *). Monad n => DList (Chunk n) -> n Builder
interpret (DList (Chunk n) -> n Builder)
-> ([Chunk n] -> DList (Chunk n)) -> [Chunk n] -> n Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Chunk n] -> DList (Chunk n)
forall a. [a] -> DList a
DL.fromList) (([Chunk n], ByteString) -> (n Builder, ByteString))
-> ((([Chunk n], ByteString), TPath) -> ([Chunk n], ByteString))
-> (([Chunk n], ByteString), TPath)
-> (n Builder, ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([Chunk n], ByteString), TPath) -> ([Chunk n], ByteString)
forall a b. (a, b) -> a
fst) (Maybe (([Chunk n], ByteString), TPath)
 -> Maybe (n Builder, ByteString))
-> Maybe (([Chunk n], ByteString), TPath)
-> Maybe (n Builder, ByteString)
forall a b. (a -> b) -> a -> b
$!
      ByteString
-> HeistState n
-> (HeistState n -> HashMap TPath ([Chunk n], ByteString))
-> Maybe (([Chunk n], ByteString), TPath)
forall (n :: * -> *) t.
ByteString
-> HeistState n
-> (HeistState n -> HashMap TPath t)
-> Maybe (t, TPath)
lookupTemplate ByteString
nm HeistState n
hs HeistState n -> HashMap TPath ([Chunk n], ByteString)
forall (m :: * -> *).
HeistState m -> HashMap TPath ([Chunk m], ByteString)
_compiledTemplateMap


------------------------------------------------------------------------------
-- | Looks up a compiled template and returns a compiled splice.
callTemplate :: Monad n
             => ByteString
             -> Splice n
callTemplate :: ByteString -> Splice n
callTemplate ByteString
nm = do
    HeistState n
hs <- HeistT n IO (HeistState n)
forall (m :: * -> *) (n :: * -> *).
Monad m =>
HeistT n m (HeistState n)
getHS
    Splice n
-> ((DocumentFile, TPath) -> Splice n)
-> Maybe (DocumentFile, TPath)
-> Splice n
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (FilePath -> Splice n
forall a. HasCallStack => FilePath -> a
error FilePath
err) (DocumentFile, TPath) -> Splice n
forall (n :: * -> *) b.
Monad n =>
(DocumentFile, b) -> HeistT n IO (DList (Chunk n))
call (Maybe (DocumentFile, TPath) -> Splice n)
-> Maybe (DocumentFile, TPath) -> Splice n
forall a b. (a -> b) -> a -> b
$ ByteString
-> HeistState n
-> (HeistState n -> HashMap TPath DocumentFile)
-> Maybe (DocumentFile, TPath)
forall (n :: * -> *) t.
ByteString
-> HeistState n
-> (HeistState n -> HashMap TPath t)
-> Maybe (t, TPath)
lookupTemplate ByteString
nm HeistState n
hs HeistState n -> HashMap TPath DocumentFile
forall (m :: * -> *). HeistState m -> HashMap TPath DocumentFile
_templateMap
  where
    err :: FilePath
err = FilePath
"callTemplate: "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++(Text -> FilePath
T.unpack (Text -> FilePath) -> Text -> FilePath
forall a b. (a -> b) -> a -> b
$ ByteString -> Text
T.decodeUtf8 ByteString
nm)FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++(FilePath
" does not exist")
    call :: (DocumentFile, b) -> HeistT n IO (DList (Chunk n))
call (DocumentFile
df,b
_) = (HeistState n -> HeistState n)
-> HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
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' {_curTemplateFile :: Maybe FilePath
_curTemplateFile = DocumentFile -> Maybe FilePath
dfFile DocumentFile
df}) (HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n)))
-> HeistT n IO (DList (Chunk n)) -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$
                    [Node] -> HeistT n IO (DList (Chunk n))
forall (n :: * -> *). Monad n => [Node] -> Splice n
runNodeList ([Node] -> HeistT n IO (DList (Chunk n)))
-> [Node] -> HeistT n IO (DList (Chunk n))
forall a b. (a -> b) -> a -> b
$ Document -> [Node]
X.docContent (Document -> [Node]) -> Document -> [Node]
forall a b. (a -> b) -> a -> b
$ DocumentFile -> Document
dfDoc DocumentFile
df


interpret :: Monad n => DList (Chunk n) -> n Builder
interpret :: DList (Chunk n) -> n Builder
interpret = (StateT HeterogeneousEnvironment n Builder
 -> HeterogeneousEnvironment -> n Builder)
-> HeterogeneousEnvironment
-> StateT HeterogeneousEnvironment n Builder
-> n Builder
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT HeterogeneousEnvironment n Builder
-> HeterogeneousEnvironment -> n Builder
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT HeterogeneousEnvironment
HE.empty (StateT HeterogeneousEnvironment n Builder -> n Builder)
-> (DList (Chunk n) -> StateT HeterogeneousEnvironment n Builder)
-> DList (Chunk n)
-> n Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RuntimeSplice n Builder
-> StateT HeterogeneousEnvironment n Builder
forall (m :: * -> *) a.
RuntimeSplice m a -> StateT HeterogeneousEnvironment m a
unRT (RuntimeSplice n Builder
 -> StateT HeterogeneousEnvironment n Builder)
-> (DList (Chunk n) -> RuntimeSplice n Builder)
-> DList (Chunk n)
-> StateT HeterogeneousEnvironment n Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList (Chunk n) -> RuntimeSplice n Builder
forall (n :: * -> *).
Monad n =>
DList (Chunk n) -> RuntimeSplice n Builder
codeGen


------------------------------------------------------------------------------
-- | Converts a pure text splice function to a pure Builder splice function.
textSplice :: (a -> Text) -> a -> Builder
textSplice :: (a -> Text) -> a -> Builder
textSplice a -> Text
f = Text -> Builder
fromText (Text -> Builder) -> (a -> Text) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Text
f


                               ---------------
                               -- New Stuff --
                               ---------------


------------------------------------------------------------------------------
-- | This is the same as htmlNodeSplice.  
nodeSplice :: (a -> [X.Node]) -> a -> Builder
nodeSplice :: (a -> [Node]) -> a -> Builder
nodeSplice a -> [Node]
f = Encoding -> [Node] -> Builder
X.renderHtmlFragment Encoding
X.UTF8 ([Node] -> Builder) -> (a -> [Node]) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> [Node]
f
{-# DEPRECATED nodeSplice
   "Use xmlNodeSplice or htmlNodeSplice, will be removed in Heist 1.1" #-}


------------------------------------------------------------------------------
-- | Converts a pure XML Node splice function to a pure Builder splice
-- function.
xmlNodeSplice :: (a -> [X.Node]) -> a -> Builder
xmlNodeSplice :: (a -> [Node]) -> a -> Builder
xmlNodeSplice a -> [Node]
f = Encoding -> [Node] -> Builder
X.renderXmlFragment Encoding
X.UTF8 ([Node] -> Builder) -> (a -> [Node]) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> [Node]
f


------------------------------------------------------------------------------
-- | Converts a pure HTML Node splice function to a pure Builder splice
-- function.
htmlNodeSplice :: (a -> [X.Node]) -> a -> Builder
htmlNodeSplice :: (a -> [Node]) -> a -> Builder
htmlNodeSplice a -> [Node]
f = Encoding -> [Node] -> Builder
X.renderHtmlFragment Encoding
X.UTF8 ([Node] -> Builder) -> (a -> [Node]) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> [Node]
f


------------------------------------------------------------------------------
-- | Converts a pure Builder splice function into a monadic splice function
-- of a RuntimeSplice.
pureSplice :: Monad n => (a -> Builder) -> RuntimeSplice n a -> Splice n
pureSplice :: (a -> Builder) -> RuntimeSplice n a -> Splice n
pureSplice a -> Builder
f RuntimeSplice n a
n = DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$ RuntimeSplice n Builder -> DList (Chunk n)
forall (n :: * -> *). RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime (Builder -> RuntimeSplice n Builder
forall (m :: * -> *) a. Monad m => a -> m a
return (Builder -> RuntimeSplice n Builder)
-> (a -> Builder) -> a -> RuntimeSplice n Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Builder
f (a -> RuntimeSplice n Builder)
-> RuntimeSplice n a -> RuntimeSplice n Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RuntimeSplice n a
n)


------------------------------------------------------------------------------
-- | Runs a splice, but first binds splices given by splice functions that
-- need some runtime data.
withSplices :: Monad n
            => Splice n
            -- ^ Splice to be run
            -> Splices (RuntimeSplice n a -> Splice n)
            -- ^ Splices to be bound first
            -> RuntimeSplice n a
            -- ^ Runtime data needed by the above splices
            -> Splice n
withSplices :: Splice n
-> Splices (RuntimeSplice n a -> Splice n)
-> RuntimeSplice n a
-> Splice n
withSplices Splice n
splice Splices (RuntimeSplice n a -> Splice n)
splices RuntimeSplice n a
runtimeAction =
    Splices (Splice n)
-> Splices (AttrSplice n) -> Splice n -> Splice n
forall (n :: * -> *) a.
Splices (Splice n)
-> Splices (AttrSplice n) -> HeistT n IO a -> HeistT n IO a
withLocalSplices Splices (Splice n)
splices' Splices (AttrSplice n)
forall a. Monoid a => a
mempty Splice n
splice
  where
    splices' :: Splices (Splice n)
splices' = ((RuntimeSplice n a -> Splice n) -> Splice n)
-> Splices (RuntimeSplice n a -> Splice n) -> Splices (Splice n)
forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV ((RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
forall a b. (a -> b) -> a -> b
$RuntimeSplice n a
runtimeAction) Splices (RuntimeSplice n a -> Splice n)
splices


------------------------------------------------------------------------------
{-# INLINE foldMapM #-}
foldMapM :: (Monad f, Monoid m, Foldable list)
         => (a -> f m)
         -> list a
         -> f m
foldMapM :: (a -> f m) -> list a -> f m
foldMapM a -> f m
f =
  (m -> a -> f m) -> m -> list a -> f m
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
Foldable.foldlM (\m
xs a
x -> m
xs m -> f m -> f m
`seq` (m -> m) -> f m -> f m
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (m
xs m -> m -> m
forall a. Semigroup a => a -> a -> a
<>) (a -> f m
f a
x)) m
forall a. Monoid a => a
mempty

------------------------------------------------------------------------------
-- | Like withSplices, but evaluates the splice repeatedly for each element in
-- a list generated at runtime.
manyWithSplices :: (Foldable f, Monad n)
                => Splice n
                -> Splices (RuntimeSplice n a -> Splice n)
                -> RuntimeSplice n (f a)
                -> Splice n
manyWithSplices :: Splice n
-> Splices (RuntimeSplice n a -> Splice n)
-> RuntimeSplice n (f a)
-> Splice n
manyWithSplices Splice n
splice Splices (RuntimeSplice n a -> Splice n)
splices RuntimeSplice n (f a)
runtimeAction =
    Splice n
-> Splices (RuntimeSplice n a -> Splice n)
-> Splices (RuntimeSplice n a -> AttrSplice n)
-> RuntimeSplice n (f a)
-> Splice n
forall (f :: * -> *) (n :: * -> *) a.
(Foldable f, Monad n) =>
Splice n
-> Splices (RuntimeSplice n a -> Splice n)
-> Splices (RuntimeSplice n a -> AttrSplice n)
-> RuntimeSplice n (f a)
-> Splice n
manyWith Splice n
splice Splices (RuntimeSplice n a -> Splice n)
splices Splices (RuntimeSplice n a -> AttrSplice n)
forall a. Monoid a => a
mempty RuntimeSplice n (f a)
runtimeAction


------------------------------------------------------------------------------
-- | More powerful version of manyWithSplices that lets you also define
-- attribute splices.
manyWith :: (Foldable f, Monad n)
         => Splice n
         -> Splices (RuntimeSplice n a -> Splice n)
         -> Splices (RuntimeSplice n a -> AttrSplice n)
         -> RuntimeSplice n (f a)
         -> Splice n
manyWith :: Splice n
-> Splices (RuntimeSplice n a -> Splice n)
-> Splices (RuntimeSplice n a -> AttrSplice n)
-> RuntimeSplice n (f a)
-> Splice n
manyWith Splice n
splice Splices (RuntimeSplice n a -> Splice n)
splices Splices (RuntimeSplice n a -> AttrSplice n)
attrSplices RuntimeSplice n (f a)
runtimeAction = do
    Promise a
p <- HeistT n IO (Promise a)
forall (n :: * -> *) a. HeistT n IO (Promise a)
newEmptyPromise
    let splices' :: MapSyntax Text (Splice n)
splices' = ((RuntimeSplice n a -> Splice n) -> Splice n)
-> Splices (RuntimeSplice n a -> Splice n)
-> MapSyntax Text (Splice n)
forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV ((RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
forall a b. (a -> b) -> a -> b
$ Promise a -> RuntimeSplice n a
forall (n :: * -> *) a. Monad n => Promise a -> RuntimeSplice n a
getPromise Promise a
p) Splices (RuntimeSplice n a -> Splice n)
splices
    let attrSplices' :: MapSyntax Text (AttrSplice n)
attrSplices' = ((RuntimeSplice n a -> AttrSplice n) -> AttrSplice n)
-> Splices (RuntimeSplice n a -> AttrSplice n)
-> MapSyntax Text (AttrSplice n)
forall v1 v2 k a. (v1 -> v2) -> MapSyntaxM k v1 a -> MapSyntax k v2
mapV ((RuntimeSplice n a -> AttrSplice n)
-> RuntimeSplice n a -> AttrSplice n
forall a b. (a -> b) -> a -> b
$ Promise a -> RuntimeSplice n a
forall (n :: * -> *) a. Monad n => Promise a -> RuntimeSplice n a
getPromise Promise a
p) Splices (RuntimeSplice n a -> AttrSplice n)
attrSplices
    DList (Chunk n)
chunks <- MapSyntax Text (Splice n)
-> MapSyntax Text (AttrSplice n) -> Splice n -> Splice n
forall (n :: * -> *) a.
Splices (Splice n)
-> Splices (AttrSplice n) -> HeistT n IO a -> HeistT n IO a
withLocalSplices MapSyntax Text (Splice n)
splices' MapSyntax Text (AttrSplice n)
attrSplices' Splice n
splice
    DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$ RuntimeSplice n Builder -> DList (Chunk n)
forall (n :: * -> *). RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime (RuntimeSplice n Builder -> DList (Chunk n))
-> RuntimeSplice n Builder -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$ do
        f a
items <- RuntimeSplice n (f a)
runtimeAction
        (a -> RuntimeSplice n Builder) -> f a -> RuntimeSplice n Builder
forall (f :: * -> *) m (list :: * -> *) a.
(Monad f, Monoid m, Foldable list) =>
(a -> f m) -> list a -> f m
foldMapM (\a
item -> Promise a -> a -> RuntimeSplice n ()
forall (n :: * -> *) a.
Monad n =>
Promise a -> a -> RuntimeSplice n ()
putPromise Promise a
p a
item RuntimeSplice n ()
-> RuntimeSplice n Builder -> RuntimeSplice n Builder
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DList (Chunk n) -> RuntimeSplice n Builder
forall (n :: * -> *).
Monad n =>
DList (Chunk n) -> RuntimeSplice n Builder
codeGen DList (Chunk n)
chunks) f a
items


------------------------------------------------------------------------------
-- | Similar to 'mapSplices' in interpreted mode.  Gets a runtime list of
-- items and applies a compiled runtime splice function to each element of the
-- list.
deferMany :: (Foldable f, Monad n)
          => (RuntimeSplice n a -> Splice n)
          -> RuntimeSplice n (f a)
          -> Splice n
deferMany :: (RuntimeSplice n a -> Splice n)
-> RuntimeSplice n (f a) -> Splice n
deferMany RuntimeSplice n a -> Splice n
f RuntimeSplice n (f a)
getItems = do
    Promise a
promise <- HeistT n IO (Promise a)
forall (n :: * -> *) a. HeistT n IO (Promise a)
newEmptyPromise
    DList (Chunk n)
chunks <- RuntimeSplice n a -> Splice n
f (RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
forall a b. (a -> b) -> a -> b
$ Promise a -> RuntimeSplice n a
forall (n :: * -> *) a. Monad n => Promise a -> RuntimeSplice n a
getPromise Promise a
promise
    DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$ RuntimeSplice n Builder -> DList (Chunk n)
forall (n :: * -> *). RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime (RuntimeSplice n Builder -> DList (Chunk n))
-> RuntimeSplice n Builder -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$ do
        f a
items <- RuntimeSplice n (f a)
getItems
        (a -> RuntimeSplice n Builder) -> f a -> RuntimeSplice n Builder
forall (f :: * -> *) m (list :: * -> *) a.
(Monad f, Monoid m, Foldable list) =>
(a -> f m) -> list a -> f m
foldMapM (\a
item -> Promise a -> a -> RuntimeSplice n ()
forall (n :: * -> *) a.
Monad n =>
Promise a -> a -> RuntimeSplice n ()
putPromise Promise a
promise a
item RuntimeSplice n ()
-> RuntimeSplice n Builder -> RuntimeSplice n Builder
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DList (Chunk n) -> RuntimeSplice n Builder
forall (n :: * -> *).
Monad n =>
DList (Chunk n) -> RuntimeSplice n Builder
codeGen DList (Chunk n)
chunks) f a
items


------------------------------------------------------------------------------
-- | Saves the results of a runtime computation in a 'Promise' so they don't
-- get recalculated if used more than once.
--
-- Note that this is just a specialized version of function application ($)
-- done for the side effect in runtime splice.
defer :: Monad n
      => (RuntimeSplice n a -> Splice n)
      -> RuntimeSplice n a -> Splice n
defer :: (RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
defer RuntimeSplice n a -> Splice n
pf RuntimeSplice n a
n = do
    Promise a
p2 <- HeistT n IO (Promise a)
forall (n :: * -> *) a. HeistT n IO (Promise a)
newEmptyPromise
    let action :: DList (Chunk n)
action = RuntimeSplice n () -> DList (Chunk n)
forall (n :: * -> *).
Monad n =>
RuntimeSplice n () -> DList (Chunk n)
yieldRuntimeEffect (RuntimeSplice n () -> DList (Chunk n))
-> RuntimeSplice n () -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$ Promise a -> a -> RuntimeSplice n ()
forall (n :: * -> *) a.
Monad n =>
Promise a -> a -> RuntimeSplice n ()
putPromise Promise a
p2 (a -> RuntimeSplice n ())
-> RuntimeSplice n a -> RuntimeSplice n ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RuntimeSplice n a
n
    DList (Chunk n)
res <- RuntimeSplice n a -> Splice n
pf (RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
forall a b. (a -> b) -> a -> b
$ Promise a -> RuntimeSplice n a
forall (n :: * -> *) a. Monad n => Promise a -> RuntimeSplice n a
getPromise Promise a
p2
    DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$ DList (Chunk n)
action DList (Chunk n) -> DList (Chunk n) -> DList (Chunk n)
forall a. Monoid a => a -> a -> a
`mappend` DList (Chunk n)
res


------------------------------------------------------------------------------
-- | A version of defer which applies a function on the runtime value.
deferMap :: Monad n
         => (a -> RuntimeSplice n b)
         -> (RuntimeSplice n b -> Splice n)
         -> RuntimeSplice n a -> Splice n
deferMap :: (a -> RuntimeSplice n b)
-> (RuntimeSplice n b -> Splice n) -> RuntimeSplice n a -> Splice n
deferMap a -> RuntimeSplice n b
f RuntimeSplice n b -> Splice n
pf RuntimeSplice n a
n = (RuntimeSplice n b -> Splice n) -> RuntimeSplice n b -> Splice n
forall (n :: * -> *) a.
Monad n =>
(RuntimeSplice n a -> Splice n) -> RuntimeSplice n a -> Splice n
defer RuntimeSplice n b -> Splice n
pf (RuntimeSplice n b -> Splice n) -> RuntimeSplice n b -> Splice n
forall a b. (a -> b) -> a -> b
$ a -> RuntimeSplice n b
f (a -> RuntimeSplice n b) -> RuntimeSplice n a -> RuntimeSplice n b
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RuntimeSplice n a
n


------------------------------------------------------------------------------
-- | Like deferMap, but only runs the result if a Maybe function of the
-- runtime value returns Just.  If it returns Nothing, then no output is
-- generated.
mayDeferMap :: Monad n
            => (a -> RuntimeSplice n (Maybe b))
            -> (RuntimeSplice n b -> Splice n)
            -> RuntimeSplice n a -> Splice n
mayDeferMap :: (a -> RuntimeSplice n (Maybe b))
-> (RuntimeSplice n b -> Splice n) -> RuntimeSplice n a -> Splice n
mayDeferMap a -> RuntimeSplice n (Maybe b)
f RuntimeSplice n b -> Splice n
pf RuntimeSplice n a
n = (RuntimeSplice n b -> Splice n)
-> RuntimeSplice n (Maybe b) -> Splice n
forall (f :: * -> *) (n :: * -> *) a.
(Foldable f, Monad n) =>
(RuntimeSplice n a -> Splice n)
-> RuntimeSplice n (f a) -> Splice n
deferMany RuntimeSplice n b -> Splice n
pf (RuntimeSplice n (Maybe b) -> Splice n)
-> RuntimeSplice n (Maybe b) -> Splice n
forall a b. (a -> b) -> a -> b
$ a -> RuntimeSplice n (Maybe b)
f (a -> RuntimeSplice n (Maybe b))
-> RuntimeSplice n a -> RuntimeSplice n (Maybe b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RuntimeSplice n a
n


------------------------------------------------------------------------------
-- | Converts an RuntimeSplice into a Splice, given a helper function that
-- generates a Builder.
bindLater :: (Monad n)
          => (a -> RuntimeSplice n Builder)
          -> RuntimeSplice n a
          -> Splice n
bindLater :: (a -> RuntimeSplice n Builder) -> RuntimeSplice n a -> Splice n
bindLater a -> RuntimeSplice n Builder
f RuntimeSplice n a
p = DList (Chunk n) -> Splice n
forall (m :: * -> *) a. Monad m => a -> m a
return (DList (Chunk n) -> Splice n) -> DList (Chunk n) -> Splice n
forall a b. (a -> b) -> a -> b
$ RuntimeSplice n Builder -> DList (Chunk n)
forall (n :: * -> *). RuntimeSplice n Builder -> DList (Chunk n)
yieldRuntime (RuntimeSplice n Builder -> DList (Chunk n))
-> RuntimeSplice n Builder -> DList (Chunk n)
forall a b. (a -> b) -> a -> b
$ a -> RuntimeSplice n Builder
f (a -> RuntimeSplice n Builder)
-> RuntimeSplice n a -> RuntimeSplice n Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RuntimeSplice n a
p