packages feed

xml-hamlet (empty) → 0.0.0

raw patch · 6 files changed

+672/−0 lines, 6 filesdep +HUnitdep +basedep +hspecsetup-changed

Dependencies added: HUnit, base, hspec, parsec, template-haskell, text, xml-enumerator

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Michael Snoyman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Michael Snoyman nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,7 @@+#!/usr/bin/env runhaskell++> module Main where+> import Distribution.Simple++> main :: IO ()+> main = defaultMain
+ Text/Hamlet/Parse.hs view
@@ -0,0 +1,282 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE CPP #-}+module Text.Hamlet.Parse+    ( Result (..)+    , Content (..)+    , Doc (..)+    , parseDoc+    )+    where++import Text.Shakespeare+import Control.Applicative ((<$>), Applicative (..))+import Control.Monad+import Data.Data+import Text.ParserCombinators.Parsec hiding (Line)++data Result v = Error String | Ok v+    deriving (Show, Eq, Read, Data, Typeable)+instance Monad Result where+    return = Ok+    Error s >>= _ = Error s+    Ok v >>= f = f v+    fail = Error+instance Functor Result where+    fmap = liftM+instance Applicative Result where+    pure = return+    (<*>) = ap++data Content = ContentRaw String+             | ContentVar Deref+             | ContentEmbed Deref+    deriving (Show, Eq, Read, Data, Typeable)++data Line = LineForall Deref Ident+          | LineIf Deref+          | LineElseIf Deref+          | LineElse+          | LineWith [(Deref, Ident)]+          | LineMaybe Deref Ident+          | LineNothing+          | LineTag+            { _lineTagName :: String+            , _lineAttr :: [(Maybe Deref, String, [Content])]+            , _lineContent :: [Content]+            }+          | LineContent [Content]+    deriving (Eq, Show, Read)++parseLines :: String -> Result [(Int, Line)]+parseLines s =+    case parse (many parseLine) s s of+        Left e -> Error $ show e+        Right x -> Ok x++parseLine :: Parser (Int, Line)+parseLine = do+    ss <- fmap sum $ many ((char ' ' >> return 1) <|>+                           (char '\t' >> return 4))+    x <- comment <|>+         htmlComment <|>+         backslash <|>+         controlIf <|>+         controlElseIf <|>+         (try (string "$else") >> spaceTabs >> eol >> return LineElse) <|>+         controlMaybe <|>+         (try (string "$nothing") >> spaceTabs >> eol >> return LineNothing) <|>+         controlForall <|>+         controlWith <|>+         angle <|>+         (eol' >> return (LineContent [])) <|>+         (do+            cs <- content InContent+            isEof <- (eof >> return True) <|> return False+            if null cs && ss == 0 && isEof+                then fail "End of Hamlet template"+                else return $ LineContent cs)+    return (ss, x)+  where+    eol' = (char '\n' >> return ()) <|> (string "\r\n" >> return ())+    eol = eof <|> eol'+    spaceTabs = many $ oneOf " \t"+    comment = do+        _ <- try $ string "$#"+        _ <- many $ noneOf "\r\n"+        eol+        return $ LineContent []+    htmlComment = do+        _ <- try $ string "<!--"+        _ <- manyTill anyChar $ try $ string "-->"+        x <- many nonComments+        eol+        return $ LineContent [ContentRaw $ concat x] -- FIXME handle variables?+    nonComments = (many1 $ noneOf "\r\n<") <|> (do+        _ <- char '<'+        (do+            _ <- try $ string "!--"+            _ <- manyTill anyChar $ try $ string "-->"+            return "") <|> return "<")+    backslash = do+        _ <- char '\\'+        (eol >> return (LineContent [ContentRaw "\n"]))+            <|> (LineContent <$> content InContent)+    controlIf = do+        _ <- try $ string "$if"+        spaces+        x <- parseDeref+        _ <- spaceTabs+        eol+        return $ LineIf x+    controlElseIf = do+        _ <- try $ string "$elseif"+        spaces+        x <- parseDeref+        _ <- spaceTabs+        eol+        return $ LineElseIf x+    binding = do+        y <- ident+        spaces+        _ <- string "<-"+        spaces+        x <- parseDeref+        _ <- spaceTabs+        return (x,y)+    bindingSep = char ',' >> spaceTabs+    controlMaybe = do+        _ <- try $ string "$maybe"+        spaces+        (x,y) <- binding+        eol+        return $ LineMaybe x y+    controlForall = do+        _ <- try $ string "$forall"+        spaces+        (x,y) <- binding+        eol+        return $ LineForall x y+    controlWith = do+        _ <- try $ string "$with"+        spaces+        bindings <- (binding `sepBy` bindingSep) `endBy` eol+        return $ LineWith $ concat bindings -- concat because endBy returns a [[(Deref,Ident)]]+    content cr = do+        x <- many $ content' cr+        case cr of+            InQuotes -> char '"' >> return ()+            NotInQuotes -> return ()+            NotInQuotesAttr -> return ()+            InContent -> eol+        return $ cc x+      where+        cc [] = []+        cc (ContentRaw a:ContentRaw b:c) = cc $ ContentRaw (a ++ b) : c+        cc (a:b) = a : cc b+    content' cr = contentHash <|> contentCaret <|> contentReg cr+    contentHash = do+        x <- parseHash+        case x of+            Left str -> return $ ContentRaw str+            Right deref -> return $ ContentVar deref+    contentCaret = do+        x <- parseCaret+        case x of+            Left str -> return $ ContentRaw str+            Right deref -> return $ ContentEmbed deref+    contentReg InContent = (ContentRaw . return) <$> noneOf "#@^\r\n"+    contentReg NotInQuotes = (ContentRaw . return) <$> noneOf "@^#. \t\n\r>"+    contentReg NotInQuotesAttr = (ContentRaw . return) <$> noneOf "@^ \t\n\r>"+    contentReg InQuotes = (ContentRaw . return) <$> noneOf "#@^\\\"\n\r>"+    tagAttribValue notInQuotes = do+        cr <- (char '"' >> return InQuotes) <|> return notInQuotes+        content cr+    tagCond = do+        _ <- char ':'+        d <- parseDeref+        _ <- char ':'+        tagAttrib (Just d)+    tagAttrib cond = do+        s <- many1 $ noneOf " \t=\r\n>"+        v <- (do+            _ <- char '='+            s' <- tagAttribValue NotInQuotesAttr+            return s') <|> return []+        return $ TagAttrib (cond, s, v)+    tag' = foldr tag'' ("div", [])+    tag'' (TagName s) (_, y) = (s, y)+    tag'' (TagAttrib s) (x, y) = (x, s : y)+    ident = Ident <$> many1 (alphaNum <|> char '_' <|> char '\'')+    angle = do+        _ <- char '<'+        name' <- many  $ noneOf " \t.#\r\n!>"+        let name = if null name' then "div" else name'+        xs <- many $ try ((many $ oneOf " \t") >>+              (tagCond <|> tagAttrib Nothing))+        _ <- many $ oneOf " \t"+        c <- (eol >> return []) <|> (do+            _ <- char '>'+            c <- content InContent+            return c)+        let (tn, attr) = tag' $ TagName name : xs+        return $ LineTag tn attr c++data TagPiece = TagName String+              | TagAttrib (Maybe Deref, String, [Content])+    deriving Show++data ContentRule = InQuotes | NotInQuotes | NotInQuotesAttr | InContent++data Nest = Nest Line [Nest]++nestLines :: [(Int, Line)] -> [Nest]+nestLines [] = []+nestLines ((i, l):rest) =+    let (deeper, rest') = span (\(i', _) -> i' > i) rest+     in Nest l (nestLines deeper) : nestLines rest'++data Doc = DocForall Deref Ident [Doc]+         | DocWith [(Deref,Ident)] [Doc]+         | DocCond [(Deref, [Doc])] (Maybe [Doc])+         | DocMaybe Deref Ident [Doc] (Maybe [Doc])+         | DocTag String [(Maybe Deref, String, [Content])] [Doc]+         | DocContent Content+         -- FIXME PIs+    deriving (Show, Eq, Read, Data, Typeable)++nestToDoc :: [Nest] -> Result [Doc]+nestToDoc [] = Ok []+nestToDoc (Nest (LineForall d i) inside:rest) = do+    inside' <- nestToDoc inside+    rest' <- nestToDoc rest+    Ok $ DocForall d i inside' : rest'+nestToDoc (Nest (LineWith dis) inside:rest) = do+    inside' <- nestToDoc inside+    rest' <- nestToDoc rest+    Ok $ DocWith dis inside' : rest'+nestToDoc (Nest (LineIf d) inside:rest) = do+    inside' <- nestToDoc inside+    (ifs, el, rest') <- parseConds ((:) (d, inside')) rest+    rest'' <- nestToDoc rest'+    Ok $ DocCond ifs el : rest''+nestToDoc (Nest (LineMaybe d i) inside:rest) = do+    inside' <- nestToDoc inside+    (nothing, rest') <-+        case rest of+            Nest LineNothing ninside:x -> do+                ninside' <- nestToDoc ninside+                return (Just ninside', x)+            _ -> return (Nothing, rest)+    rest'' <- nestToDoc rest'+    Ok $ DocMaybe d i inside' nothing : rest''+nestToDoc (Nest (LineTag tn attrs content) inside:rest) = do+    inside' <- nestToDoc inside+    rest' <- nestToDoc rest+    Ok $ (DocTag tn attrs $ map DocContent content ++ inside') : rest'+nestToDoc (Nest (LineContent content) inside:rest) = do+    inside' <- nestToDoc inside+    rest' <- nestToDoc rest+    Ok $ map DocContent content ++ inside' ++ rest'+nestToDoc (Nest (LineElseIf _) _:_) = Error "Unexpected elseif"+nestToDoc (Nest LineElse _:_) = Error "Unexpected else"+nestToDoc (Nest LineNothing _:_) = Error "Unexpected nothing"++parseDoc :: String -> Result [Doc]+parseDoc s = do+    ls <- parseLines s+    let notEmpty (_, LineContent []) = False+        notEmpty _ = True+    let ns = nestLines $ filter notEmpty ls+    ds <- nestToDoc ns+    return ds++parseConds :: ([(Deref, [Doc])] -> [(Deref, [Doc])])+           -> [Nest]+           -> Result ([(Deref, [Doc])], Maybe [Doc], [Nest])+parseConds front (Nest LineElse inside:rest) = do+    inside' <- nestToDoc inside+    Ok $ (front [], Just inside', rest)+parseConds front (Nest (LineElseIf d) inside:rest) = do+    inside' <- nestToDoc inside+    parseConds (front . (:) (d, inside')) rest+parseConds front rest = Ok (front [], Nothing, rest)
+ Text/Hamlet/XML.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE TemplateHaskell #-}+module Text.Hamlet.XML+    ( xml+    , xmlFile+    ) where++import Language.Haskell.TH.Syntax+import Language.Haskell.TH.Quote+import qualified Data.Text.Lazy as TL+import Control.Monad ((<=<))+import Text.Hamlet.Parse+import Text.Shakespeare (readUtf8File, derefToExp, Scope, Deref (DerefIdent), Ident (Ident))+import Data.Text (pack, unpack)+import qualified Data.Text as T+import qualified Text.XML.Enumerator.Resolved as X+import Data.String (fromString)+import qualified Data.Foldable as F+import Data.Maybe (fromMaybe)++xml :: QuasiQuoter+xml = QuasiQuoter { quoteExp = strToExp }++xmlFile :: FilePath -> Q Exp+xmlFile = strToExp . TL.unpack <=< qRunIO . readUtf8File++strToExp :: String -> Q Exp+strToExp s =+    case parseDoc s of+        Error e -> error e+        Ok x -> docsToExp [] x++docsToExp :: Scope -> [Doc] -> Q Exp+docsToExp scope docs = [| concat $(fmap ListE $ mapM (docToExp scope) docs) |]++docToExp :: Scope -> Doc -> Q Exp+docToExp scope (DocTag name attrs cs) =+    [| [ X.NodeElement (X.Element ($(liftName name)) $(mkAttrs scope attrs) $(docsToExp scope cs))+       ] |]+docToExp _ (DocContent (ContentRaw s)) = [| [ X.NodeContent (pack $(lift s)) ] |]+docToExp scope (DocContent (ContentVar d)) = [| [ X.NodeContent $(return $ derefToExp scope d) ] |]+docToExp scope (DocContent (ContentEmbed d)) = return $ derefToExp scope d+docToExp scope (DocForall deref ident@(Ident ident') inside) = do+    let list' = derefToExp scope deref+    name <- newName ident'+    let scope' = (ident, VarE name) : scope+    inside' <- docsToExp scope' inside+    let lam = LamE [VarP name] inside'+    [| F.concatMap $(return lam) $(return list') |]+docToExp scope (DocWith [] inside) = docsToExp scope inside+docToExp scope (DocWith ((deref, ident@(Ident name)):dis) inside) = do+    let deref' = derefToExp scope deref+    name' <- newName name+    let scope' = (ident, VarE name') : scope+    inside' <- docToExp scope' (DocWith dis inside)+    let lam = LamE [VarP name'] inside'+    return $ lam `AppE` deref'+docToExp scope (DocMaybe deref ident@(Ident name) just nothing) = do+    let deref' = derefToExp scope deref+    name' <- newName name+    let scope' = (ident, VarE name') : scope+    inside' <- docsToExp scope' just+    let inside'' = LamE [VarP name'] inside'+    nothing' <-+        case nothing of+            Nothing -> [| [] |]+            Just n -> docsToExp scope n+    [| maybe $(return nothing') $(return inside'') $(return deref') |]+docToExp scope (DocCond conds final) = do+    unit <- [| () |]+    body <- fmap GuardedB $ mapM go $ conds ++ [(DerefIdent $ Ident "otherwise", fromMaybe [] final)]+    return $ CaseE unit [Match (TupP []) body []]+  where+    go (deref, inside) = do+        inside' <- docsToExp scope inside+        return (NormalG $ derefToExp scope deref, inside')++mkAttrs :: Scope -> [(Maybe Deref, String, [Content])] -> Q Exp+mkAttrs _ [] = [| [] |]+mkAttrs scope ((mderef, name, value):rest) = do+    rest' <- mkAttrs scope rest+    this <- [| ($(liftName name), T.concat $(fmap ListE $ mapM go value)) |]+    let with = [| $(return this) : $(return rest') |]+    case mderef of+        Nothing -> with+        Just deref -> [| if $(return $ derefToExp scope deref) then $(with) else $(return rest') |]+  where+    go (ContentRaw s) = [| pack $(lift s) |]+    go (ContentVar d) = return $ derefToExp scope d+    go ContentEmbed{} = error "Cannot use embed interpolation in attribute value"++liftName :: String -> Q Exp+liftName s = do+    X.Name local mns _ <- return $ fromString s+    case mns of+        Nothing -> [| X.Name (pack $(lift $ unpack local)) Nothing Nothing |]+        Just ns -> [| X.Name (pack $(lift $ unpack local)) (Just $ pack $(lift $ unpack ns)) Nothing |]
+ Text/Shakespeare.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP #-}+-- | General parsers, functions and datatypes for all three languages.+module Text.Shakespeare+    ( Deref (..)+    , Ident (..)+    , Scope+    , parseDeref+    , parseHash+    , parseVar+    , parseAt+    , parseUrl+    , parseCaret+    , parseUnder+    , parseInt+    , derefToExp+    , flattenDeref+    , readUtf8File+    ) where++import Language.Haskell.TH.Syntax+import Language.Haskell.TH (appE)+import Data.Char (isUpper)+import Text.ParserCombinators.Parsec+import Data.List (intercalate)+import Data.Ratio (Ratio, numerator, denominator, (%))+import Data.Data (Data)+import Data.Typeable (Typeable)+import qualified Data.Text.Lazy as TL+import qualified System.IO as SIO+import qualified Data.Text.Lazy.IO as TIO++newtype Ident = Ident String+    deriving (Show, Eq, Read, Data, Typeable)++type Scope = [(Ident, Exp)]++data Deref = DerefModulesIdent [String] Ident+           | DerefIdent Ident+           | DerefIntegral Integer+           | DerefRational Rational+           | DerefString String+           | DerefBranch Deref Deref+    deriving (Show, Eq, Read, Data, Typeable)++instance Lift Ident where+    lift (Ident s) = [|Ident|] `appE` lift s+instance Lift Deref where+    lift (DerefModulesIdent v s) = do+        dl <- [|DerefModulesIdent|]+        v' <- lift v+        s' <- lift s+        return $ dl `AppE` v' `AppE` s'+    lift (DerefIdent s) = do+        dl <- [|DerefIdent|]+        s' <- lift s+        return $ dl `AppE` s'+    lift (DerefBranch x y) = do+        x' <- lift x+        y' <- lift y+        db <- [|DerefBranch|]+        return $ db `AppE` x' `AppE` y'+    lift (DerefIntegral i) = [|DerefIntegral|] `appE` lift i+    lift (DerefRational r) = do+        n <- lift $ numerator r+        d <- lift $ denominator r+        per <- [|(%) :: Int -> Int -> Ratio Int|]+        dr <- [|DerefRational|]+        return $ dr `AppE` (InfixE (Just n) per (Just d))+    lift (DerefString s) = [|DerefString|] `appE` lift s++parseDeref :: Parser Deref+parseDeref = do+    skipMany $ oneOf " \t"+    x <- derefSingle+    res <- deref' $ (:) x+    skipMany $ oneOf " \t"+    return res+  where+    delim = (many1 (char ' ') >> return())+            <|> lookAhead (char '(' >> return ())+    derefOp = try $ do+        _ <- char '('+        x <- many1 $ noneOf " \t\n\r()"+        _ <- char ')'+        return $ DerefIdent $ Ident x+    derefParens = between (char '(') (char ')') parseDeref+    derefSingle = derefOp <|> derefParens <|> numeric <|> strLit<|> ident+    deref' lhs =+        dollar <|> derefSingle'+               <|> return (foldl1 DerefBranch $ lhs [])+      where+        dollar = do+            _ <- try $ delim >> char '$'+            rhs <- parseDeref+            let lhs' = foldl1 DerefBranch $ lhs []+            return $ DerefBranch lhs' rhs+        derefSingle' = do+            x <- try $ delim >> derefSingle+            deref' $ lhs . (:) x+    numeric = do+        n <- (char '-' >> return "-") <|> return ""+        x <- many1 digit+        y <- (char '.' >> fmap Just (many1 digit)) <|> return Nothing+        return $ case y of+            Nothing -> DerefIntegral $ read' "Integral" $ n ++ x+            Just z -> DerefRational $ toRational+                       (read' "Rational" $ n ++ x ++ '.' : z :: Double)+    strLit = do+        _ <- char '"'+        chars <- many quotedChar+        _ <- char '"'+        return $ DerefString chars+    quotedChar = (char '\\' >> escapedChar) <|> noneOf "\""+    escapedChar =+        (char 'n' >> return '\n') <|>+        (char 'r' >> return '\r') <|>+        (char 'b' >> return '\b') <|>+        (char 't' >> return '\t') <|>+        (char '\\' >> return '\\') <|>+        (char '"' >> return '"') <|>+        (char '\'' >> return '\'')+    ident = do+        mods <- many modul+        func <- many1 (alphaNum <|> char '_' <|> char '\'')+        let func' = Ident func+        return $+            if null mods+                then DerefIdent func'+                else DerefModulesIdent mods func'+    modul = try $ do+        c <- upper+        cs <- many (alphaNum <|> char '_')+        _ <- char '.'+        return $ c : cs++read' :: Read a => String -> String -> a+read' t s =+    case reads s of+        (x, _):_ -> x+        [] -> error $ t ++ " read failed: " ++ s++expType :: Ident -> Name -> Exp+expType (Ident (c:_)) = if isUpper c || c == ':' then ConE else VarE+expType (Ident "") = error "Bad Ident"++derefToExp :: Scope -> Deref -> Exp+derefToExp s (DerefBranch x y) = derefToExp s x `AppE` derefToExp s y+derefToExp _ (DerefModulesIdent mods i@(Ident s)) =+    expType i $ Name (mkOccName s) (NameQ $ mkModName $ intercalate "." mods)+derefToExp scope (DerefIdent i@(Ident s)) =+    case lookup i scope of+        Just e -> e+        Nothing -> expType i $ mkName s+derefToExp _ (DerefIntegral i) = LitE $ IntegerL i+derefToExp _ (DerefRational r) = LitE $ RationalL r+derefToExp _ (DerefString s) = LitE $ StringL s++-- FIXME shouldn't we use something besides a list here?+flattenDeref :: Deref -> Maybe [String]+flattenDeref (DerefIdent (Ident x)) = Just [x]+flattenDeref (DerefBranch (DerefIdent (Ident x)) y) = do+    y' <- flattenDeref y+    Just $ y' ++ [x]+flattenDeref _ = Nothing++parseHash :: Parser (Either String Deref)+parseHash = parseVar '#'++parseVar :: Char -> Parser (Either String Deref)+parseVar c = do+    _ <- char c+    (char '\\' >> return (Left [c])) <|> (do+        _ <- char '{'+        deref <- parseDeref+        _ <- char '}'+        return $ Right deref) <|> (do+            -- Check for hash just before newline+            _ <- lookAhead (oneOf "\r\n" >> return ()) <|> eof+            return $ Left ""+            ) <|> return (Left [c])++parseAt :: Parser (Either String (Deref, Bool))+parseAt = parseUrl '@' '?'++parseUrl :: Char -> Char -> Parser (Either String (Deref, Bool))+parseUrl c d = do+    _ <- char c+    (char '\\' >> return (Left [c])) <|> (do+        x <- (char d >> return True) <|> return False+        (do+            _ <- char '{'+            deref <- parseDeref+            _ <- char '}'+            return $ Right (deref, x))+                <|> return (Left $ if x then [c, d] else [c]))++parseCaret :: Parser (Either String Deref)+parseCaret = parseInt '^'++parseInt :: Char -> Parser (Either String Deref)+parseInt c = do+    _ <- char c+    (char '\\' >> return (Left [c])) <|> (do+        _ <- char '{'+        deref <- parseDeref+        _ <- char '}'+        return $ Right deref) <|> return (Left [c])++parseUnder :: Parser (Either String Deref)+parseUnder = do+    _ <- char '_'+    (char '\\' >> return (Left "_")) <|> (do+        _ <- char '{'+        deref <- parseDeref+        _ <- char '}'+        return $ Right deref) <|> return (Left "_")++readUtf8File :: FilePath -> IO TL.Text+readUtf8File fp = do+    h <- SIO.openFile fp SIO.ReadMode+    SIO.hSetEncoding h SIO.utf8_bom+    TIO.hGetContents h
+ xml-hamlet.cabal view
@@ -0,0 +1,32 @@+Name:                xml-hamlet+Version:             0.0.0+Synopsis:            Hamlet-style quasiquoter for XML content+Homepage:            http://www.yesodweb.com/+License:             BSD3+License-file:        LICENSE+Author:              Michael Snoyman+Maintainer:          michael@snoyman.com+Category:            Text+Build-type:          Simple++Cabal-version:       >=1.8++Library+  Exposed-modules:     Text.Hamlet.XML+  Other-modules:       Text.Hamlet.Parse+                       Text.Shakespeare+  +  Build-depends:       base                       >= 4        && < 5+                     , xml-enumerator             >= 0.3.4    && < 0.4+                     , text                       >= 0.10     && < 1.0+                     , template-haskell+                     , parsec                     >= 2.0      && < 3.2++  Ghc-options:         -Wall++test-suite runtests+  main-is:             runtests.hs+  type:                exitcode-stdio-1.0+  ghc-options:         -Wall+  build-depends:       hspec                      >= 0.6      && < 0.7+                     , HUnit                      >= 1.2      && < 1.3