{-# LANGUAGE OverloadedStrings, RelaxedPolyRec #-}
module Data.Text.Format
(
Format
, Only(..)
, Shown(..)
, format
, print
, hprint
, build
, left
, right
, hex
, expt
, fixed
, prec
, shortest
) where
import Data.Semigroup ((<>))
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.Text.Format.Params (Params(..))
import Data.Text.Format.Types.Internal (Format(..), Only(..), Shown(..))
import Data.Text.Format.Types.Internal (Hex(..))
import Data.Text.Lazy.Builder
import Prelude hiding (exp, print)
import System.IO (Handle)
import qualified Data.Double.Conversion.Text as C
import qualified Data.Text as ST
import qualified Data.Text.Buildable as B
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.IO as LT
build :: Params ps => Format -> ps -> Builder
build fmt ps = zipParams (crack fmt) (buildParams ps)
{-# INLINE build #-}
zipParams :: [Builder] -> [Builder] -> Builder
zipParams fragments params = go fragments params
where go (f:fs) (y:ys) = f <> y <> go fs ys
go [f] [] = f
go _ _ = error . LT.unpack $ format
"Data.Text.Format.build: {} sites, but {} parameters"
(length fragments - 1, length params)
crack :: Format -> [Builder]
crack = map fromText . ST.splitOn "{}" . fromFormat
format :: Params ps => Format -> ps -> LT.Text
format fmt ps = toLazyText $ build fmt ps
{-# INLINE format #-}
print :: (MonadIO m, Params ps) => Format -> ps -> m ()
print fmt ps = liftIO . LT.putStr . toLazyText $ build fmt ps
{-# INLINE print #-}
hprint :: (MonadIO m, Params ps) => Handle -> Format -> ps -> m ()
hprint h fmt ps = liftIO . LT.hPutStr h . toLazyText $ build fmt ps
{-# INLINE hprint #-}
left :: B.Buildable a => Int -> Char -> a -> Builder
left k c =
fromLazyText . LT.justifyRight (fromIntegral k) c . toLazyText . B.build
right :: B.Buildable a => Int -> Char -> a -> Builder
right k c =
fromLazyText . LT.justifyLeft (fromIntegral k) c . toLazyText . B.build
prec :: (Real a) =>
Int
-> a -> Builder
{-# RULES "prec/Double"
forall d x. prec d (x::Double) = B.build (C.toPrecision d x) #-}
prec digits = B.build . C.toPrecision digits . realToFrac
{-# NOINLINE[0] prec #-}
fixed :: (Real a) =>
Int
-> a -> Builder
fixed decs = B.build . C.toFixed decs . realToFrac
{-# RULES "fixed/Double"
forall d x. fixed d (x::Double) = B.build (C.toFixed d x) #-}
{-# NOINLINE[0] fixed #-}
expt :: (Real a) =>
Int
-> a -> Builder
expt decs = B.build . C.toExponential decs . realToFrac
{-# RULES "expt/Double"
forall d x. expt d (x::Double) = B.build (C.toExponential d x) #-}
{-# NOINLINE[0] expt #-}
shortest :: (Real a) => a -> Builder
shortest = B.build . C.toShortest . realToFrac
{-# RULES "shortest/Double"
forall x. shortest (x::Double) = B.build (C.toShortest x) #-}
{-# NOINLINE[0] shortest #-}
hex :: Integral a => a -> Builder
hex = B.build . Hex
{-# INLINE hex #-}