{-# LANGUAGE GADTs #-} {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Fmt.Internal.Core where #if __GLASGOW_HASKELL__ < 804 import Data.Monoid ((<>)) #endif import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.IO as TL import qualified Data.Text.Lazy.Encoding as TL import Data.Text.Lazy.Builder hiding (fromString) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Builder as BB import Formatting.Buildable (Buildable(..)) ---------------------------------------------------------------------------- -- Class ---------------------------------------------------------------------------- class FromBuilder a where -- | Convert a 'Builder' to something else. fromBuilder :: Builder -> a instance FromBuilder Builder where fromBuilder = id {-# INLINE fromBuilder #-} instance (a ~ Char) => FromBuilder [a] where fromBuilder = TL.unpack . toLazyText {-# INLINE fromBuilder #-} instance FromBuilder T.Text where fromBuilder = TL.toStrict . toLazyText {-# INLINE fromBuilder #-} instance FromBuilder TL.Text where fromBuilder = toLazyText {-# INLINE fromBuilder #-} instance FromBuilder BS.ByteString where fromBuilder = T.encodeUtf8 . TL.toStrict . toLazyText {-# INLINE fromBuilder #-} instance FromBuilder BSL.ByteString where fromBuilder = TL.encodeUtf8 . toLazyText {-# INLINE fromBuilder #-} instance FromBuilder BB.Builder where fromBuilder = TL.encodeUtf8Builder . toLazyText {-# INLINE fromBuilder #-} instance (a ~ ()) => FromBuilder (IO a) where fromBuilder = TL.putStr . toLazyText {-# INLINE fromBuilder #-} ---------------------------------------------------------------------------- -- Operators ---------------------------------------------------------------------------- -- | Concatenate, then convert. (+|) :: (FromBuilder b) => Builder -> Builder -> b (+|) str rest = fromBuilder (str <> rest) -- | 'build' and concatenate, then convert. (|+) :: (Buildable a, FromBuilder b) => a -> Builder -> b (|+) a rest = fromBuilder (build a <> rest) infixr 1 +| infixr 1 |+ -- | Concatenate, then convert. (+||) :: (FromBuilder b) => Builder -> Builder -> b (+||) str rest = str +| rest {-# INLINE (+||) #-} -- | 'show' and concatenate, then convert. (||+) :: (Show a, FromBuilder b) => a -> Builder -> b (||+) a rest = show a |+ rest {-# INLINE (||+) #-} infixr 1 +|| infixr 1 ||+ (|++|) :: (Buildable a, FromBuilder b) => a -> Builder -> b (|++|) a rest = fromBuilder (build a <> rest) {-# INLINE (|++|) #-} (||++||) :: (Show a, FromBuilder b) => a -> Builder -> b (||++||) a rest = show a |+ rest {-# INLINE (||++||) #-} (|++||) :: (Buildable a, FromBuilder b) => a -> Builder -> b (|++||) a rest = a |++| rest {-# INLINE (|++||) #-} (||++|) :: (Show a, FromBuilder b) => a -> Builder -> b (||++|) a rest = a ||++|| rest {-# INLINE (||++|) #-} infixr 1 |++| infixr 1 ||++|| infixr 1 ||++| infixr 1 |++|| ---------------------------------------------------------------------------- -- Functions ---------------------------------------------------------------------------- {- | 'fmt' converts things to 'String', 'T.Text', 'BS.ByteString' or 'Builder'. Most of the time you won't need it, as strings produced with ('+|') and ('|+') can already be used as 'String', 'T.Text', etc. However, combinators like 'listF' can only produce 'Builder' (for better type inference), and you need to use 'fmt' on them. Also, 'fmt' can do printing: >>> fmt "Hello world!\n" Hello world! -} fmt :: FromBuilder b => Builder -> b fmt = fromBuilder {-# INLINE fmt #-} {- | Like 'fmt', but appends a newline. -} fmtLn :: FromBuilder b => Builder -> b fmtLn = fromBuilder . (<> "\n") {-# INLINE fmtLn #-} {- | 'pretty' shows a value using its 'Buildable' instance. -} pretty :: (Buildable a, FromBuilder b) => a -> b pretty = fmt . build {-# INLINE pretty #-} {- | Like 'pretty', but appends a newline. -} prettyLn :: (Buildable a, FromBuilder b) => a -> b prettyLn = fmtLn . build {-# INLINE prettyLn #-}