{-# LANGUAGE CPP                  #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE TypeSynonymInstances #-}
-- | BlazeMarkup is a markup combinator library. It provides a way to embed
-- markup languages like HTML and SVG in Haskell in an efficient and convenient
-- way, with a light-weight syntax.
--
-- To use the library, one needs to import a set of combinators. For example,
-- you can use HTML 4 Strict from BlazeHtml package.
--
-- > {-# LANGUAGE OverloadedStrings #-}
-- > import Prelude hiding (head, id, div)
-- > import Text.Blaze.Html4.Strict hiding (map)
-- > import Text.Blaze.Html4.Strict.Attributes hiding (title)
--
-- To render the page later on, you need a so called Renderer. The recommended
-- renderer is an UTF-8 renderer which produces a lazy bytestring.
--
-- > import Text.Blaze.Renderer.Utf8 (renderMarkup)
--
-- Now, you can describe pages using the imported combinators.
--
-- > page1 :: Markup
-- > page1 = html $ do
-- >     head $ do
-- >         title "Introduction page."
-- >         link ! rel "stylesheet" ! type_ "text/css" ! href "screen.css"
-- >     body $ do
-- >         div ! id "header" $ "Syntax"
-- >         p "This is an example of BlazeMarkup syntax."
-- >         ul $ mapM_ (li . toMarkup . show) [1, 2, 3]
--
-- The resulting HTML can now be extracted using:
--
-- > renderMarkup page1
--
module Text.Blaze
    (
      -- * Important types.
      Markup
    , Tag
    , Attribute
    , AttributeValue

      -- * Creating attributes.
    , dataAttribute
    , customAttribute

      -- * Converting values to Markup.
    , ToMarkup (..)
    , text
    , preEscapedText
    , lazyText
    , preEscapedLazyText
    , string
    , preEscapedString
    , unsafeByteString
    , unsafeLazyByteString

      -- * Comments
    , textComment
    , lazyTextComment
    , stringComment
    , unsafeByteStringComment
    , unsafeLazyByteStringComment

      -- * Creating tags.
    , textTag
    , stringTag

      -- * Converting values to attribute values.
    , ToValue (..)
    , textValue
    , preEscapedTextValue
    , lazyTextValue
    , preEscapedLazyTextValue
    , stringValue
    , preEscapedStringValue
    , unsafeByteStringValue
    , unsafeLazyByteStringValue

      -- * Setting attributes
    , (!)
    , (!?)

      -- * Modifying Markup trees
    , contents
    ) where

import           Data.Int               (Int32, Int64)
import           Data.Monoid            (mconcat)
import           Data.Word              (Word, Word32, Word64)
#if MIN_VERSION_base(4,8,0)
import           Numeric.Natural        (Natural)
#endif
#if MIN_VERSION_base(4,9,0)
import           Data.List.NonEmpty     (NonEmpty (..))
#endif

import           Data.Text              (Text)
import qualified Data.Text.Lazy         as LT
import qualified Data.Text.Lazy.Builder as LTB

import           Text.Blaze.Internal

-- | Class allowing us to use a single function for Markup values
--
class ToMarkup a where
    -- | Convert a value to Markup.
    --
    toMarkup :: a -> Markup

    -- | Convert a value to Markup without escaping
    --
    preEscapedToMarkup :: a -> Markup
    preEscapedToMarkup = a -> Markup
forall a. ToMarkup a => a -> Markup
toMarkup
    {-# INLINE preEscapedToMarkup #-}

instance ToMarkup Markup where
    toMarkup :: Markup -> Markup
toMarkup = Markup -> Markup
forall a. a -> a
id
    {-# INLINE toMarkup #-}

instance ToMarkup [Markup] where
    toMarkup :: [Markup] -> Markup
toMarkup = [Markup] -> Markup
forall a. Monoid a => [a] -> a
mconcat
    {-# INLINE toMarkup #-}

instance ToMarkup Text where
    toMarkup :: Text -> Markup
toMarkup = Text -> Markup
text
    {-# INLINE toMarkup #-}
    preEscapedToMarkup :: Text -> Markup
preEscapedToMarkup = Text -> Markup
preEscapedText
    {-# INLINE preEscapedToMarkup #-}

instance ToMarkup LT.Text where
    toMarkup :: Text -> Markup
toMarkup = Text -> Markup
lazyText
    {-# INLINE toMarkup #-}
    preEscapedToMarkup :: Text -> Markup
preEscapedToMarkup = Text -> Markup
preEscapedLazyText
    {-# INLINE preEscapedToMarkup #-}

instance ToMarkup LTB.Builder where
    toMarkup :: Builder -> Markup
toMarkup = Builder -> Markup
textBuilder
    {-# INLINE toMarkup #-}
    preEscapedToMarkup :: Builder -> Markup
preEscapedToMarkup = Builder -> Markup
preEscapedTextBuilder
    {-# INLINE preEscapedToMarkup #-}

instance ToMarkup String where
    toMarkup :: String -> Markup
toMarkup = String -> Markup
string
    {-# INLINE toMarkup #-}
    preEscapedToMarkup :: String -> Markup
preEscapedToMarkup = String -> Markup
preEscapedString
    {-# INLINE preEscapedToMarkup #-}

instance ToMarkup Int where
    toMarkup :: Int -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Int -> String) -> Int -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Int32 where
    toMarkup :: Int32 -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Int32 -> String) -> Int32 -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Int64 where
    toMarkup :: Int64 -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Int64 -> String) -> Int64 -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

#if MIN_VERSION_base(4,8,0)
instance ToMarkup Natural where
    toMarkup :: Natural -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Natural -> String) -> Natural -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Natural -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}
#endif

instance ToMarkup Char where
    toMarkup :: Char -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Char -> String) -> Char -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> String
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return
    {-# INLINE toMarkup #-}

instance ToMarkup Bool where
    toMarkup :: Bool -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Bool -> String) -> Bool -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Integer where
    toMarkup :: Integer -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Integer -> String) -> Integer -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Float where
    toMarkup :: Float -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Float -> String) -> Float -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Double where
    toMarkup :: Double -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Double -> String) -> Double -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Word where
    toMarkup :: Word -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Word -> String) -> Word -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Word32 where
    toMarkup :: Word32 -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Word32 -> String) -> Word32 -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

instance ToMarkup Word64 where
    toMarkup :: Word64 -> Markup
toMarkup = String -> Markup
string (String -> Markup) -> (Word64 -> String) -> Word64 -> Markup
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> String
forall a. Show a => a -> String
show
    {-# INLINE toMarkup #-}

-- | Class allowing us to use a single function for attribute values
--
class ToValue a where
    -- | Convert a value to an attribute value
    --
    toValue :: a -> AttributeValue

    -- | Convert a value to an attribute value without escaping
    --
    preEscapedToValue :: a -> AttributeValue
    preEscapedToValue = a -> AttributeValue
forall a. ToValue a => a -> AttributeValue
toValue
    {-# INLINE preEscapedToValue #-}

instance ToValue AttributeValue where
    toValue :: AttributeValue -> AttributeValue
toValue = AttributeValue -> AttributeValue
forall a. a -> a
id
    {-# INLINE toValue #-}

instance ToValue Text where
    toValue :: Text -> AttributeValue
toValue = Text -> AttributeValue
textValue
    {-# INLINE toValue #-}
    preEscapedToValue :: Text -> AttributeValue
preEscapedToValue = Text -> AttributeValue
preEscapedTextValue
    {-# INLINE preEscapedToValue #-}

instance ToValue LT.Text where
    toValue :: Text -> AttributeValue
toValue = Text -> AttributeValue
lazyTextValue
    {-# INLINE toValue #-}
    preEscapedToValue :: Text -> AttributeValue
preEscapedToValue = Text -> AttributeValue
preEscapedLazyTextValue
    {-# INLINE preEscapedToValue #-}

instance ToValue LTB.Builder where
    toValue :: Builder -> AttributeValue
toValue = Builder -> AttributeValue
textBuilderValue
    {-# INLINE toValue #-}
    preEscapedToValue :: Builder -> AttributeValue
preEscapedToValue = Builder -> AttributeValue
preEscapedTextBuilderValue
    {-# INLINE preEscapedToValue #-}

instance ToValue String where
    toValue :: String -> AttributeValue
toValue = String -> AttributeValue
stringValue
    {-# INLINE toValue #-}
    preEscapedToValue :: String -> AttributeValue
preEscapedToValue = String -> AttributeValue
preEscapedStringValue
    {-# INLINE preEscapedToValue #-}

instance ToValue Int where
    toValue :: Int -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Int -> String) -> Int -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Int32 where
    toValue :: Int32 -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Int32 -> String) -> Int32 -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Int64 where
    toValue :: Int64 -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Int64 -> String) -> Int64 -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Char where
    toValue :: Char -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Char -> String) -> Char -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> String
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return
    {-# INLINE toValue #-}

instance ToValue Bool where
    toValue :: Bool -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Bool -> String) -> Bool -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Integer where
    toValue :: Integer -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Integer -> String) -> Integer -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Float where
    toValue :: Float -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Float -> String) -> Float -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Double where
    toValue :: Double -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Double -> String) -> Double -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Word where
    toValue :: Word -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Word -> String) -> Word -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Word32 where
    toValue :: Word32 -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Word32 -> String) -> Word32 -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

instance ToValue Word64 where
    toValue :: Word64 -> AttributeValue
toValue = String -> AttributeValue
stringValue (String -> AttributeValue)
-> (Word64 -> String) -> Word64 -> AttributeValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> String
forall a. Show a => a -> String
show
    {-# INLINE toValue #-}

-- Non-empty strings
#if MIN_VERSION_base(4,9,0)
instance ToMarkup (NonEmpty Char) where
    toMarkup :: NonEmpty Char -> Markup
toMarkup           (Char
x :| String
xs) = String -> Markup
string           (Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs)
    preEscapedToMarkup :: NonEmpty Char -> Markup
preEscapedToMarkup (Char
x :| String
xs) = String -> Markup
preEscapedString (Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs)

instance ToValue (NonEmpty Char) where
    toValue :: NonEmpty Char -> AttributeValue
toValue (Char
x :| String
xs) = String -> AttributeValue
stringValue (Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs)
#endif