{-# 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