template-hsml-0.1.0.0: src/Template/HSML/Internal/Types.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Template.HSML.Internal.Types
( HSMLTemplate(..)
, Options(..)
, defaultHSML
, defaultSHSML
, PTemplate(..)
, PSection(..)
, PAttribute(..)
, PAttributeName(..)
, PAttributeValue(..)
, Template
, Section
, Attribute
, AttributeName
, AttributeValue
, RTemplate
, RSection
, RAttribute
, RAttributeName
, RAttributeValue
, Arg(..)
, Dec(..)
, Exp(..)
, RArg(..)
, RDec(..)
, RExp(..)
) where
--------------------------------------------------------------------------------
import qualified Language.Haskell.Exts.Syntax as HE
--------------------------------------------------------------------------------
import Data.Char (toUpper, toLower)
import Data.Monoid ((<>))
--------------------------------------------------------------------------------
import qualified Text.Blaze as B (Markup)
--------------------------------------------------------------------------------
class HSMLTemplate a where
renderTemplate :: a -> B.Markup
defaultHSML :: String -> Options
defaultHSML name = Options
{ optSectionsToMarkup = True
, optTemplateName = firstUpper name
, optTemplateFieldName = \a -> firstLower name <> firstUpper a
}
where
firstUpper "" = ""
firstUpper (c:cs) = toUpper c : cs
firstLower "" = ""
firstLower (c:cs) = toLower c : cs
defaultSHSML :: Options
defaultSHSML = Options
{ optSectionsToMarkup = True
, optTemplateName = undefined
, optTemplateFieldName = undefined
}
-- | This type let's you customize some behaviour of the templating system.
data Options = Options
{
-- ^ If (and only if) set to True, applies `Blaze.Text.toMarkup` to
-- section expression
optSectionsToMarkup :: Bool
-- ^ The name of the generated record.
-- NOTE: Has no effect on s.HSML templates.
, optTemplateName :: String
-- ^ The name of the fields of the genrated record.
-- NOTE: Has no effect on sHTML templates.
, optTemplateFieldName :: String -> String
}
--------------------------------------------------------------------------------
-- | Handy synonyms
type Template = PTemplate Arg Dec Exp
type Section = PSection Exp
type Attribute = PAttribute Exp
type AttributeName = PAttributeName Exp
type AttributeValue = PAttributeValue Exp
type RTemplate = PTemplate RArg RDec RExp
type RSection = PSection RExp
type RAttribute = PAttribute RExp
type RAttributeName = PAttributeName RExp
type RAttributeValue = PAttributeValue RExp
--------------------------------------------------------------------------------
-- | The Template. This includes arguments, declarations and sections
data PTemplate arg dec exp = Template
{ templateArgs :: [arg]
, templateDecs :: [dec]
, templateSections :: [PSection exp]
}
instance Show e => Show (PTemplate a d e) where
show tpl = unlines . map show $ templateSections tpl
data PSection exp = ElementNode String [PAttribute exp] [PSection exp]
| ElementLeaf String [PAttribute exp]
| Text String
| TextRaw String
| Expression exp
instance Show e => Show (PSection e) where
show (ElementNode name _ sections) = concat [ "<" <> name <> ">\n"
, unlines (map show sections)
, "</" <> name <> ">\n"
]
show (ElementLeaf name _) = "<" <> name <> "/>"
show (Text str) = hsmlEscape str
show (TextRaw str) = str
show (Expression e) = show e
hsmlEscape :: String -> String
hsmlEscape "" = ""
hsmlEscape (c:rest) =
if shouldEscape c
then '\\' : c : hsmlEscape rest
else c : hsmlEscape rest
where
shouldEscape = (`elem` "<{")
data PAttribute exp = Attribute (PAttributeName exp) (PAttributeValue exp)
data PAttributeName exp = AttributeNameText String
| AttributeNameExp exp
data PAttributeValue exp = AttributeValueText String
| AttributeValueExp exp
data Arg = Arg String (Maybe HE.Type)
newtype Dec = Dec HE.Decl
newtype Exp = Exp HE.Exp
data RArg = RArg String (Maybe String) deriving Show
newtype RDec = RDec String deriving Show
newtype RExp = RExp String deriving Show