@@ -1,93 +1,93 @@
1−{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
1+{-# LANGUAGE TemplateHaskell #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE FlexibleInstances #-}
2{-# OPTIONS_GHC -fno-warn-missing-fields #-}
5{-# OPTIONS_GHC -fno-warn-missing-fields #-}
7+-- | This module contains Shakespearean (see "Text.Shakespeare") templates for Elm.
8+-- It introduces type-safe compile-time variable and URL interpolation. A typeclass
9+-- @'ToElm'@ is provided for interpolated variables.
11+-- Further reading on Shakespearean templates: <http://www.yesodweb.com/book/templates>
13+-- Further reading on Elm: <http://elm-lang.org>
4−module Language.Elm.Quasi (elm, elmFile) where
14+module Language.Elm.Quasi
16+ -- ** Template-Reading Functions
17+ -- |These QuasiQuoters return functions of the type @(t -> 'Elm')@
18+ -- where @t@ is the URL rendering function if type-safe URLs are used.
20+ -- A usage example for both type-safe (Yesod) and standard path segment (Happstack)
21+ -- URLs is provided in the Examples folder in the Git repository.
29+ -- * Typeclass for interpolated variables
32+ -- ** Rendering Functions
6−import Language.Haskell.TH.Quote
37+import Language.Haskell.TH.Quote (QuasiQuoter (..))
7−import Language.Haskell.TH
38+import Language.Haskell.TH.Syntax
8−import Language.Haskell.Meta (parseExp)
39+import Data.Text.Lazy.Builder (Builder, fromText, toLazyText, fromLazyText)
10−import Data.Attoparsec.Text
40+import Data.Monoid
41+import qualified Data.Text as TS
11−import Data.Text as T (Text, pack, unpack, strip)
42+import qualified Data.Text.Lazy as TL
12−
43+import Text.Shakespeare
13−{- | This QuasiQuoter allows for literal embedding of elm source code within
44+
14− Haskell files. It is not responsible for the actual compilation Process.
45+-- | Render Elm to lazy Text.
15− Usage:
46+renderElm :: Elm -> TL.Text
16−
47+renderElm (Elm b) = toLazyText b
18− elmPage = [elm|
49+-- | Newtype wrapper of 'Builder'.
19− main = image \"someImage.jpg\"
50+newtype Elm = Elm { unElm :: Builder }
20− |]
51+ deriving Monoid
22−
53+-- | A typeclass for types that can be interpolated in Elm templates.
23− It also allows for simple variable interpolation using the ^{...} syntax.
54+class ToElm a where
24− This is intended for e.g. embedding pre-rendered type-safe URLs.
55+ toElm :: a -> Builder
25− All interpolated variables must be a member of the Show typeclass. This
56+instance ToElm [Char] where toElm = fromLazyText . TL.pack
26− is not tested with more complicated expressions, so it is recommended to
57+instance ToElm TS.Text where toElm = fromText
27− restrict usage of interpolation to pre-calculated variables.
58+instance ToElm TL.Text where toElm = fromLazyText
29− Example:
60+elmSettings :: Q ShakespeareSettings
31− > let google = "http://google.com"
62+ toJExp <- [|toElm|]
32− > in [elm|
63+ wrapExp <- [|Elm|]
33− > main = text $ link ^{google} (toText "Google")
64+ unWrapExp <- [|unElm|]
34− > |]
65+ return $ defaultShakespeareSettings { toBuilder = toJExp
36−
67+ , unwrap = unWrapExp
37− How the elm code is compiled depends on how you intend to use it.
38− Example uses are the included 'generateHtml' function as well as the
39− "Language.Elm.Yesod" module.
44− let chunks = flip map (getQChunks s) $ \c ->
47− E t -> let Right e = parseExp t in appE [| show |] (return e)
48− in appE [| concat |] (listE chunks)
51−{- | elmFile is a quoteFile wrapper around the 'elm' QuasiQuoter and allows for
70+-- |QuasiQuoter for embedding Elm code inside of Haskell code.
52− external elm source files to be embedded.
71+--
73+-- @[elm|main = plaintext "Some elm code"|]@
75+elm = QuasiQuoter { quoteExp = \s -> do
77+ quoteExp (shakespeare rs) s
80+-- |A Template Haskell function for embedding Elm code from external
56− [elmFile|elm-source/page.elm|]
84+-- @$(elmFile "elm_source/index.elm")@
57− @
85+elmFile :: FilePath -> Q Exp
59− Please note that no spaces should be added before and after the filename.
87+ rs <- elmSettings
60−-}
88+ shakespeareFile rs fp
61−elmFile :: QuasiQuoter
89+
62−elmFile = quoteFile elm
90+elmFileReload :: FilePath -> Q Exp
63−
91+elmFileReload fp = do
64−data QChunk =
92+ rs <- elmSettings
65− S String -- ^ A literal string
93+ shakespeareFileReload rs fp
66− | E String -- ^ An expression (must be of the Show typeclass)
70−{- thanks to mikeplus64 for providing an example QuasiQuoter that I could look at while writing this :) -}
71−getQChunks :: String -> [QChunk]
72−getQChunks si = let i = T.pack si
73− Right m = parseOnly parser (strip i) in m
78− txt <- takeTill (== '^')
79− evt <- choice [expression, fmap (S . T.unpack) takeText]
82− then return $ filter (not . blank) $ reverse (evt:(S . T.unpack) txt:s)
83− else go (evt:(S . T.unpack) txt:s)
91− expr <- takeTill (== '}')
93− return $ (E . T.unpack) expr