{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Text.Hamlet.Runtime
( HamletTemplate
, HamletSettings
, defaultHamletSettings
, HamletData
, ToHamletData (..)
, parseHamletTemplate
, readHamletTemplateFile
, renderHamletTemplate
) where
import Control.Arrow ((***))
import Control.Monad.Catch (MonadThrow)
import Text.Hamlet (HamletSettings, defaultHamletSettings)
import qualified Text.Hamlet.RT as RT
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Text (Text)
import Data.String
import Text.Blaze.Html (Html, toHtml)
import Control.Monad (liftM)
import Control.Monad.IO.Class
import Data.Text.Encoding (decodeUtf8With)
import Data.Text.Encoding.Error (lenientDecode)
import qualified Data.ByteString as S
import qualified Data.Text as T
data Void
absurd :: Void -> a
absurd _ = error "absurd"
newtype HamletTemplate = HamletTemplate RT.HamletRT
newtype HamletData = HamletData { unHamletData :: RT.HamletData Void }
instance IsString HamletData where
fromString = HamletData . RT.HDHtml . fromString
class ToHamletData a where
toHamletData :: a -> HamletData
instance ToHamletData HamletData where
toHamletData = id
instance a ~ HamletData => ToHamletData [a] where
toHamletData = HamletData . RT.HDList . map (\x -> [([], unHamletData x)])
instance a ~ HamletData => ToHamletData (Maybe a) where
toHamletData = HamletData . RT.HDMaybe . fmap (\x -> [([], unHamletData x)])
instance ToHamletData Text where
toHamletData = toHamletData . toHtml
instance ToHamletData Html where
toHamletData = HamletData . RT.HDHtml
instance ToHamletData Bool where
toHamletData = HamletData . RT.HDBool
parseHamletTemplate :: MonadThrow m => HamletSettings -> String -> m HamletTemplate
parseHamletTemplate set str = HamletTemplate `liftM` RT.parseHamletRT set str
readHamletTemplateFile :: (MonadThrow m, MonadIO m) => HamletSettings -> FilePath -> m HamletTemplate
readHamletTemplateFile set fp = do
bs <- liftIO $ S.readFile fp
parseHamletTemplate set $ T.unpack $ decodeUtf8With lenientDecode bs
renderHamletTemplate :: MonadThrow m => HamletTemplate -> Map Text HamletData -> m Html
renderHamletTemplate (HamletTemplate rt) m =
RT.renderHamletRT' True rt m' renderUrl
where
m' = map (return . T.unpack *** unHamletData) $ Map.toList m
renderUrl url _ = absurd url