{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Snap.Snaplet.HeistNoClass
( Heist
, DefaultMode(..)
, heistInit
, heistInit'
, heistReloader
, setInterpreted
, getCurHeistConfig
, clearHeistCache
, addTemplates
, addTemplatesAt
, getHeistState
, modifyHeistState
, modifyHeistState'
, withHeistState
, withHeistState'
, gRender
, gRenderAs
, gHeistServe
, gHeistServeSingle
, chooseMode
, addConfig
, cRender
, cRenderAs
, cHeistServe
, cHeistServeSingle
, render
, renderAs
, heistServe
, heistServeSingle
, heistLocal
, withSplices
, renderWithSplices
, heistLocal'
, withSplices'
, renderWithSplices'
, SnapletHeist
, SnapletISplice
, SnapletCSplice
) where
import Prelude hiding ((.), id)
import Control.Applicative
import Control.Category
import Control.Lens
import Control.Monad.Reader
import Control.Monad.State
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.DList (DList)
import qualified Data.HashMap.Strict as Map
import Data.IORef
import Data.Maybe
import qualified Data.Text as T
import Data.Text.Encoding
import System.FilePath.Posix
import Heist
import qualified Heist.Compiled as C
import qualified Heist.Interpreted as I
import Heist.Splices.Cache
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
import Snap.Snaplet
import Snap.Snaplet.Heist.Internal
import Snap.Core
import Snap.Util.FileServe
changeState :: (HeistState (Handler a a) -> HeistState (Handler a a))
-> Heist a
-> Heist a
changeState _ (Configuring _) =
error "changeState: HeistState has not been initialized"
changeState f (Running hc hs cts dm) = Running hc (f hs) cts dm
clearHeistCache :: Heist b -> IO ()
clearHeistCache = clearCacheTagState . _heistCTS
instance MonadSnap m => MonadSnap (HeistT n m) where
liftSnap = lift . liftSnap
type SnapletHeist b m a = HeistT (Handler b b) m a
type SnapletCSplice b = SnapletHeist b IO (DList (Chunk (Handler b b)))
type SnapletISplice b = SnapletHeist b (Handler b b) Template
heistInit :: FilePath
-> SnapletInit b (Heist b)
heistInit = gHeistInit heistServe
heistInit' :: FilePath
-> HeistConfig (Handler b b)
-> SnapletInit b (Heist b)
heistInit' templateDir initialConfig =
makeSnaplet "heist" "" Nothing $ heistInitWorker templateDir initialConfig
setInterpreted :: Snaplet (Heist b) -> Initializer b v ()
setInterpreted h =
liftIO $ atomicModifyIORef (_heistConfig $ view snapletValue h)
(\(hc,_) -> ((hc,Interpreted),()))
addTemplates :: Snaplet (Heist b)
-> ByteString
-> Initializer b (Heist b) ()
addTemplates h urlPrefix = do
snapletPath <- getSnapletFilePath
addTemplatesAt h urlPrefix (snapletPath </> "templates")
addTemplatesAt :: Snaplet (Heist b)
-> ByteString
-> FilePath
-> Initializer b (Heist b) ()
addTemplatesAt h urlPrefix templateDir = do
rootUrl <- getSnapletRootURL
let fullPrefix = (T.unpack $ decodeUtf8 rootUrl) </>
(T.unpack $ decodeUtf8 urlPrefix)
addPrefix = addTemplatePathPrefix
(encodeUtf8 $ T.pack fullPrefix)
ts <- liftIO $ (loadTemplates templateDir) >>=
either (error . concat) return
printInfo $ T.pack $ unwords
[ "...adding"
, (show $ Map.size ts)
, "templates from"
, templateDir
, "with route prefix"
, fullPrefix ++ "/"
]
let locations = [fmap addPrefix <$> loadTemplates templateDir]
add (hc, dm) =
((over hcTemplateLocations (mappend locations) hc, dm), ())
liftIO $ atomicModifyIORef (_heistConfig $ view snapletValue h) add
getCurHeistConfig :: Snaplet (Heist b)
-> Initializer b v (HeistConfig (Handler b b))
getCurHeistConfig h = case view snapletValue h of
Configuring ref -> do
(hc, _) <- liftIO $ readIORef ref
return hc
Running _ _ _ _ ->
error "Can't get HeistConfig after heist is initialized."
getHeistState :: SnapletLens (Snaplet b) (Heist b)
-> Handler b v (HeistState (Handler b b))
getHeistState heist = withTop' heist $ gets _heistState
modifyHeistState' :: SnapletLens (Snaplet b) (Heist b)
-> (HeistState (Handler b b) -> HeistState (Handler b b))
-> Initializer b v ()
modifyHeistState' heist f = do
withTop' heist $ addPostInitHook $ return . Right . changeState f
modifyHeistState :: SnapletLens b (Heist b)
-> (HeistState (Handler b b) -> HeistState (Handler b b))
-> Initializer b v ()
modifyHeistState heist f = modifyHeistState' (subSnaplet heist) f
withHeistState' :: SnapletLens (Snaplet b) (Heist b)
-> (HeistState (Handler b b) -> a)
-> Handler b v a
withHeistState' heist f = do
hs <- withTop' heist $ gets _heistState
return $ f hs
withHeistState :: SnapletLens b (Heist b)
-> (HeistState (Handler b b) -> a)
-> Handler b v a
withHeistState heist f = withHeistState' (subSnaplet heist) f
addConfig :: Snaplet (Heist b)
-> SpliceConfig (Handler b b)
-> Initializer b v ()
addConfig h sc = case view snapletValue h of
Configuring ref ->
liftIO $ atomicModifyIORef ref add
Running _ _ _ _ -> do
printInfo "finalLoadHook called while running"
error "this shouldn't happen"
where
add (hc, dm) =
((over hcSpliceConfig (`mappend` sc) hc, dm), ())
iRenderHelper :: Maybe MIMEType
-> ByteString
-> Handler b (Heist b) ()
iRenderHelper c t = do
(Running _ hs _ _) <- get
withTop' id $ I.renderTemplate hs t >>= maybe pass serve
where
serve (b, mime) = do
modifyResponse $ setContentType $ fromMaybe mime c
writeBuilder b
cRenderHelper :: Maybe MIMEType
-> ByteString
-> Handler b (Heist b) ()
cRenderHelper c t = do
(Running _ hs _ _) <- get
withTop' id $ maybe pass serve $ C.renderTemplate hs t
where
serve (b, mime) = do
modifyResponse $ setContentType $ fromMaybe mime c
writeBuilder =<< b
serveURI :: Handler b (Heist b) ByteString
serveURI = do
p <- getSafePath
if take 1 p == "_" then pass else return $ B.pack p
render :: ByteString
-> Handler b (Heist b) ()
render t = iRenderHelper Nothing t
renderAs :: ByteString
-> ByteString
-> Handler b (Heist b) ()
renderAs ct t = iRenderHelper (Just ct) t
heistServe :: Handler b (Heist b) ()
heistServe =
ifTop (render "index") <|> (render =<< serveURI)
heistServeSingle :: ByteString -> Handler b (Heist b) ()
heistServeSingle t =
render t <|> error ("Template " ++ show t ++ " not found.")
cRender :: ByteString
-> Handler b (Heist b) ()
cRender t = cRenderHelper Nothing t
cRenderAs :: ByteString
-> ByteString
-> Handler b (Heist b) ()
cRenderAs ct t = cRenderHelper (Just ct) t
cHeistServe :: Handler b (Heist b) ()
cHeistServe =
ifTop (cRender "index") <|> (cRender =<< serveURI)
cHeistServeSingle :: ByteString -> Handler b (Heist b) ()
cHeistServeSingle t =
cRender t <|> error ("Template " ++ show t ++ " not found.")
chooseMode :: MonadState (Heist b1) m
=> m b
-> m b
-> m b
chooseMode cAction iAction = do
mode <- gets _defMode
case mode of
Compiled -> cAction
Interpreted -> iAction
gRender :: ByteString
-> Handler b (Heist b) ()
gRender t = chooseMode (cRender t) (render t)
gRenderAs :: ByteString
-> ByteString
-> Handler b (Heist b) ()
gRenderAs ct t = chooseMode (cRenderAs ct t) (renderAs ct t)
gHeistServe :: Handler b (Heist b) ()
gHeistServe = chooseMode cHeistServe heistServe
gHeistServeSingle :: ByteString -> Handler b (Heist b) ()
gHeistServeSingle t = chooseMode (cHeistServeSingle t) (heistServeSingle t)
heistLocal' :: SnapletLens (Snaplet b) (Heist b)
-> (HeistState (Handler b b) -> HeistState (Handler b b))
-> Handler b v a
-> Handler b v a
heistLocal' heist f m = do
hs <- withTop' heist get
withTop' heist $ modify $ changeState f
res <- m
withTop' heist $ put hs
return res
heistLocal :: SnapletLens b (Heist b)
-> (HeistState (Handler b b) -> HeistState (Handler b b))
-> Handler b v a
-> Handler b v a
heistLocal heist f m = heistLocal' (subSnaplet heist) f m
withSplices' :: SnapletLens (Snaplet b) (Heist b)
-> Splices (SnapletISplice b)
-> Handler b v a
-> Handler b v a
withSplices' heist splices m = do
heistLocal' heist (I.bindSplices splices) m
withSplices :: SnapletLens b (Heist b)
-> Splices (SnapletISplice b)
-> Handler b v a
-> Handler b v a
withSplices heist splices m = withSplices' (subSnaplet heist) splices m
renderWithSplices' :: SnapletLens (Snaplet b) (Heist b)
-> ByteString
-> Splices (SnapletISplice b)
-> Handler b v ()
renderWithSplices' heist t splices =
withSplices' heist splices $ withTop' heist $ render t
renderWithSplices :: SnapletLens b (Heist b)
-> ByteString
-> Splices (SnapletISplice b)
-> Handler b v ()
renderWithSplices heist t splices =
renderWithSplices' (subSnaplet heist) t splices