packages feed

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