vformat-0.14.0.0: src/Text/Format/TH.hs
{-# LANGUAGE DeriveLift #-}
{-# LANGUAGE StandaloneDeriving #-}
module Text.Format.TH ( formatQQ, format1QQ ) where
import Data.String
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Text.Format.ArgFmt
import Text.Format.ArgKey
import Text.Format.Format
deriving instance Lift ArgKey
deriving instance Lift ArgFmt
deriving instance Lift FmtAlign
deriving instance Lift FmtSign
deriving instance Lift FmtNumSep
deriving instance Lift FmtItem
deriving instance Lift Format
deriving instance Lift Format1
{-| A QuasiQuoter for 'Format' with which you can write multi-line 'Format'.
Note: @">>>"@ after @"[formatQQ|"@ means starting from the next line,
@"<<<"@ before @"|]"@ means ending from the previous line.
==== Example
>>> :set -XTemplateHaskell
>>> :set -XQuasiQuotes
>>> import Text.Format
>>> import Text.Format.TH
>>> :{
fmt1 :: Format
fmt1 = [formatQQ|>>>
first line {hi}
newline {words}
last line {bye}
<<<|]
fmt2 :: Format
fmt2 = [formatQQ|first line {hi}
newline {words}
last line {bye}|]
fmt3 :: Format
fmt3 = "first line {hi}\nnewline {words}\nlast line {bye}"
:}
>>> format fmt1 ("hi" := "hi") ("words" := "say something") ("bye" := "bye")
"first line hi\nnewline say something\nlast line bye"
>>> format fmt2 ("hi" := "hi") ("words" := "say something") ("bye" := "bye")
"first line hi\nnewline say something\nlast line bye"
>>> format fmt3 ("hi" := "hi") ("words" := "say something") ("bye" := "bye")
"first line hi\nnewline say something\nlast line bye"
@since 0.14.0
-}
formatQQ :: QuasiQuoter
formatQQ = QuasiQuoter { quoteExp = formatExp
, quotePat = undefined
, quoteType = undefined
, quoteDec = undefined
}
formatExp :: String -> Q Exp
formatExp fs = lift $ (fromString (fixEnd $ fixBegin fs) :: Format)
{-| Same as 'formatQQ', but for 'Format1'.
@since 0.14.0
-}
format1QQ :: QuasiQuoter
format1QQ = QuasiQuoter { quoteExp = format1Exp
, quotePat = undefined
, quoteType = undefined
, quoteDec = undefined
}
format1Exp :: String -> Q Exp
format1Exp fs = lift $ (fromString (fixEnd $ fixBegin fs) :: Format1)
fixBegin :: String -> String
fixBegin ('>':'>':'>':"") = ""
fixBegin ('>':'>':'>':'\n':fs) = fs
fixBegin fs = fs
fixEnd :: String -> String
fixEnd ('<':'<':'<':"") = ""
fixEnd fs | ('<':'<':'<':'\n':fs') <- reverse fs = reverse fs'
fixEnd fs = fs