    {-# LANGUAGE RelaxedPolyRec #-}
    {-# LANGUAGE CPP #-}

    -- |
    -- Module      : Data.Text.Format
    -- Copyright   : (c) 2011 MailRank, Inc.
    --
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- Fast, efficient, flexible support for formatting text strings.

    module Data.Text.Format
        (
        -- * Format control
         left
        , right
        -- ** Integers
        , hex
        -- ** Floating point numbers
        , fixed
        , shortest
        ) where

    #ifdef MIN_VERSION_double_conversion
    import           Data.Double.Conversion.Text (toFixed, toShortest)
    #else
    import           Numeric (showFFloat, showInt)
    #endif
    import qualified Formatting.Buildable as B
    import           Data.Text.Format.Types (Hex(..))
    import qualified Data.Text.Lazy as LT
    import           Data.Text.Lazy.Builder
    import           Prelude hiding (exp, print)

    -- | Pad the left hand side of a string until it reaches @k@
    -- characters wide, if necessary filling with character @c@.
    left :: B.Buildable a => Int -> Char -> a -> Builder
    left :: forall a. Buildable a => Int -> Char -> a -> Builder
    left Int
    k Char
    c =
        Text -> Builder
    fromLazyText (Text -> Builder) -> (a -> Text) -> a -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int64 -> Char -> Text -> Text
    LT.justifyRight (Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    k) Char
    c (Text -> Text) -> (a -> Text) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Builder -> Text
    toLazyText (Builder -> Text) -> (a -> Builder) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Builder
    forall p. Buildable p => p -> Builder
    B.build

    -- | Pad the right hand side of a string until it reaches @k@
    -- characters wide, if necessary filling with character @c@.
    right :: B.Buildable a => Int -> Char -> a -> Builder
    right :: forall a. Buildable a => Int -> Char -> a -> Builder
    right Int
    k Char
    c =
        Text -> Builder
    fromLazyText (Text -> Builder) -> (a -> Text) -> a -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int64 -> Char -> Text -> Text
    LT.justifyLeft (Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    k) Char
    c (Text -> Text) -> (a -> Text) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Builder -> Text
    toLazyText (Builder -> Text) -> (a -> Builder) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Builder
    forall p. Buildable p => p -> Builder
    B.build

    -- | Render a floating point number using normal notation, with the
    -- given number of decimal places.
    fixed :: (Real a) =>
             Int
          -- ^ Number of digits of precision after the decimal.
          -> a -> Builder
    #ifdef MIN_VERSION_double_conversion
    fixed :: forall a. Real a => Int -> a -> Builder
    fixed Int
    decs = Text -> Builder
    fromText (Text -> Builder) -> (a -> Text) -> a -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Double -> Text
    toFixed Int
    decs (Double -> Text) -> (a -> Double) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Double
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac
    #else
    fixed decs = fromString . toFixed . realToFrac
      where
        toFixed :: Double -> String
        toFixed dbl = showFFloat (Just decs) dbl ""
    #endif
    {-# NOINLINE[0] fixed #-}

    -- | Render a floating point number using the smallest number of
    -- digits that correctly represent it.
    shortest :: Real a => a -> Builder
    #ifdef MIN_VERSION_double_conversion
    shortest :: forall a. Real a => a -> Builder
    shortest = Text -> Builder
    fromText (Text -> Builder) -> (a -> Text) -> a -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Double -> Text
    toShortest (Double -> Text) -> (a -> Double) -> a -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Double
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac
    #else
    shortest = fromString . toShortest . realToFrac
      where
        toShortest :: Double -> String
        toShortest dbl =
          -- `showFFloat (Just 0) "" 1.0` gives "1.", but we want "1"
          let intPart = (floor dbl :: Int) in
            if dbl == (fromIntegral intPart)
              then showInt intPart ""
              else showFFloat Nothing dbl ""
    #endif
    {-# INLINE shortest #-}

    -- | Render an integer using hexadecimal notation.  (No leading "0x"
    -- is added.)
    hex :: Integral a => a -> Builder
    hex :: forall a. Integral a => a -> Builder
    hex = Hex a -> Builder
    forall p. Buildable p => p -> Builder
    B.build (Hex a -> Builder) -> (a -> Hex a) -> a -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Hex a
    forall a. a -> Hex a
    Hex
    {-# INLINE hex #-}