packages feed

formatting 6.2.5 → 6.3.0

raw patch · 13 files changed

+648/−98 lines, 13 filesdep +arraydep +bytestringdep +formattingdep −text-formatdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: array, bytestring, formatting, ghc-prim, hspec, integer-gmp, transformers

Dependencies removed: text-format

Dependency ranges changed: base

API changes (from Hackage documentation)

- Formatting.Formatters: expt :: Real a => Int -> Format r (a -> r)
- Formatting.Formatters: prec :: Real a => Int -> Format r (a -> r)
- Formatting.ShortFormatters: ef :: Real a => Int -> Format r (a -> r)
- Formatting.ShortFormatters: pf :: Real a => Int -> Format r (a -> r)
+ Formatting.Buildable: build :: Buildable p => p -> Builder
+ Formatting.Buildable: class Buildable p
+ Formatting.Buildable: instance (GHC.Real.Integral a, Formatting.Buildable.Buildable a) => Formatting.Buildable.Buildable (GHC.Real.Ratio a)
+ Formatting.Buildable: instance Data.Fixed.HasResolution a => Formatting.Buildable.Buildable (Data.Fixed.Fixed a)
+ Formatting.Buildable: instance Formatting.Buildable.Buildable (GHC.Ptr.Ptr a)
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Text.Internal.Builder.Builder
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Text.Internal.Lazy.Text
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Text.Internal.Text
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.Calendar.Days.Day
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.Clock.Internal.DiffTime.DiffTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.Clock.Internal.NominalDiffTime.NominalDiffTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.Clock.Internal.UTCTime.UTCTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.Clock.Internal.UniversalTime.UniversalTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.LocalTime.Internal.TimeZone.TimeZone
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Time.LocalTime.Internal.ZonedTime.ZonedTime
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Data.Void.Void
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Foreign.Ptr.IntPtr
+ Formatting.Buildable: instance Formatting.Buildable.Buildable Foreign.Ptr.WordPtr
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Int.Int16
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Int.Int32
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Int.Int64
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Int.Int8
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Integer.Type.Integer
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Bool
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Char
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Double
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Float
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Int
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Types.Word
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Word.Word16
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Word.Word32
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Word.Word64
+ Formatting.Buildable: instance Formatting.Buildable.Buildable GHC.Word.Word8
+ Formatting.Buildable: instance Formatting.Buildable.Buildable [GHC.Types.Char]
+ Formatting.Buildable: instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (GHC.Base.Maybe a)
+ Formatting.Buildable: instance GHC.Real.Integral a => Formatting.Buildable.Buildable (Data.Text.Format.Types.Hex a)
+ Formatting.Buildable: instance GHC.Show.Show a => Formatting.Buildable.Buildable (Data.Text.Format.Types.Shown a)
- Formatting.Formatters: int :: Integral a => Format r (a -> r)
+ Formatting.Formatters: int :: (Integral a, Buildable a) => Format r (a -> r)
- Formatting.ShortFormatters: d :: Integral a => Format r (a -> r)
+ Formatting.ShortFormatters: d :: (Integral a, Buildable a) => Format r (a -> r)

Files

CHANGELOG.md view
@@ -1,3 +1,15 @@+6.3.0++* Folded the `text-format` package into this package, removed the+  `double-conversion` dependency. Lost the following functions in+  this:+  * `prec`+  * `expt`+* Added a test suite with regression tests:+  * Fixed: https://github.com/chrisdone/formatting/issues/31+  * Fixed: https://github.com/chrisdone/formatting/issues/28+  * Fixed: https://github.com/bos/text-format/issues/18+ 6.2.5  * Changed microseconds to display as "us" to avoid unicode issues.
formatting.cabal view
@@ -1,34 +1,58 @@ name:                formatting-version:             6.2.5+version:             6.3.0 synopsis:            Combinator-based type-safe formatting (like printf() or FORMAT) description:         Combinator-based type-safe formatting (like printf() or FORMAT), modelled from the HoleyMonoids package. license:             BSD3 license-file:        LICENSE-author:              Chris Done, Shachaf Ben-Kiki, Martijn van Steenbergen, Mike Meyer+author:              Chris Done, Shachaf Ben-Kiki, Martijn van Steenbergen, Mike Meyer, Bryan O'Sullivan maintainer:          chrisdone@gmail.com-copyright:           2013 Chris Done, Shachaf Ben-Kiki, Martijn van Steenbergen, Mike Meyer+copyright:           2013 Chris Done, Shachaf Ben-Kiki, Martijn van Steenbergen, Mike Meyer, 2011 MailRank, Inc. category:            Text build-type:          Simple cabal-version:       >=1.8 extra-source-files:  CHANGELOG.md  library-  exposed-modules:   Formatting,-                     Formatting.Formatters,-                     Formatting.ShortFormatters,-                     Formatting.Examples,-                     Formatting.Time,-                     Formatting.Clock,-                     Formatting.Internal-  build-depends:     base >= 4.5 && < 5,-                     text-format,-                     text >= 0.11.0.8,-                     time,-                     old-locale,-                     scientific >= 0.3.0.0,-                     clock >= 0.4+  exposed-modules:+    Formatting+    Formatting.Formatters+    Formatting.ShortFormatters+    Formatting.Examples+    Formatting.Time+    Formatting.Clock+    Formatting.Internal+    Formatting.Buildable++  other-modules:+    Data.Text.Format.Functions+    Data.Text.Format.Types+    Data.Text.Format+    Data.Text.Format.Int++  build-depends:+    base >= 4.5 && < 5,+    text >= 0.11.0.8,+    time,+    old-locale,+    scientific >= 0.3.0.0,+    clock >= 0.4,+    array,+    ghc-prim,+    text >= 0.11.0.8,+    transformers,+    bytestring,+    integer-gmp >= 0.2+   hs-source-dirs:    src   ghc-options:       -O2+  cpp-options: -DINTEGER_GMP++test-suite formatting-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:       base, formatting, hspec+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N  source-repository head   type:     git
+ src/Data/Text/Format.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings, RelaxedPolyRec #-}++-- |+-- 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++import           Control.Monad.IO.Class (MonadIO(liftIO))+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Builder as L+import           Data.Text (Text)+import qualified Data.Text as ST+import qualified Data.Text as T+import qualified Formatting.Buildable as B+import qualified Data.Text.Encoding as T+import           Data.Text.Format.Functions ((<>))+import           Data.Text.Format.Types (Shown(..), Hex(..))+import qualified Data.Text.Lazy as LT+import           Data.Text.Lazy.Builder+import qualified Data.Text.Lazy.IO as LT+import           Prelude hiding (exp, print)+import           System.IO (Handle)+import           Text.Printf++-- | 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 k c =+    fromLazyText . LT.justifyRight (fromIntegral k) c . toLazyText . 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 k c =+    fromLazyText . LT.justifyLeft (fromIntegral k) c . toLazyText . 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+fixed decs = B.build . T.pack . (printf ("%." ++ show decs ++ "f") :: Double->String) . realToFrac+{-# NOINLINE[0] fixed #-}++-- | Render a floating point number using the smallest number of+-- digits that correctly represent it.+shortest :: (Real a) => a -> Builder+shortest = B.build . T.decodeUtf8 . L.toStrict . L.toLazyByteString . L.doubleDec . realToFrac+{-# NOINLINE[0] shortest #-}++-- | Render an integer using hexadecimal notation.  (No leading "0x"+-- is added.)+hex :: Integral a => a -> Builder+hex = B.build . Hex+{-# INLINE hex #-}
+ src/Data/Text/Format/Functions.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE MagicHash #-}++-- |+-- Module      : Data.Text.Format.Functions+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Useful functions and combinators.++module Data.Text.Format.Functions+    (+      (<>)+    , i2d+    ) where++import Data.Monoid (mappend)+import Data.Text.Lazy.Builder (Builder)+import GHC.Base++-- | Unsafe conversion for decimal digits.+{-# INLINE i2d #-}+i2d :: Int -> Char+i2d (I# i#) = C# (chr# (ord# '0'# +# i#))++-- | The normal 'mappend' function with right associativity instead of+-- left.+(<>) :: Builder -> Builder -> Builder+(<>) = mappend+{-# INLINE (<>) #-}++infixr 4 <>
+ src/Data/Text/Format/Int.hs view
@@ -0,0 +1,163 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}++-- Module:      Data.Text.Format.Int+-- Copyright:   (c) 2011 MailRank, Inc.+-- License:     BSD3+-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>+-- Stability:   experimental+-- Portability: portable+--+-- Efficiently serialize an integral value to a 'Builder'.++module Data.Text.Format.Int+    (+      decimal+    , integer+    , hexadecimal+    , minus+    ) where++import Data.Int (Int8, Int16, Int32, Int64)+import Data.Monoid (mempty)+import Data.Text.Format.Functions ((<>), i2d)+import Data.Text.Lazy.Builder+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Base (quotInt, remInt)+import GHC.Num (quotRemInteger)+import GHC.Types (Int(..))++#ifdef  __GLASGOW_HASKELL__+# if __GLASGOW_HASKELL__ < 611+import GHC.Integer.Internals+# else+import GHC.Integer.GMP.Internals+# endif+#endif++#ifdef INTEGER_GMP+# define PAIR(a,b) (# a,b #)+#else+# define PAIR(a,b) (a,b)+#endif++decimal :: (Integral a, Bounded a) => a -> Builder+{-# SPECIALIZE decimal :: Int -> Builder #-}+{-# SPECIALIZE decimal :: Int8 -> Builder #-}+{-# SPECIALIZE decimal :: Int16 -> Builder #-}+{-# SPECIALIZE decimal :: Int32 -> Builder #-}+{-# SPECIALIZE decimal :: Int64 -> Builder #-}+{-# SPECIALIZE decimal :: Word -> Builder #-}+{-# SPECIALIZE decimal :: Word8 -> Builder #-}+{-# SPECIALIZE decimal :: Word16 -> Builder #-}+{-# SPECIALIZE decimal :: Word32 -> Builder #-}+{-# SPECIALIZE decimal :: Word64 -> Builder #-}+{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}+decimal i+    | i == minBound =+        -- special case, since (-i) would not be representable assuming two's+        -- compliment:+        minus <> integer 10 (negate $ fromIntegral i)+    | i < 0     = minus <> go (-i)+    | otherwise = go i+  where+    go n | n < 10    = digit n+         | otherwise = go (n `quot` 10) <> digit (n `rem` 10)+{-# NOINLINE[0] decimal #-}++hexadecimal :: Integral a => a -> Builder+{-# SPECIALIZE hexadecimal :: Int -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int64 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}+{-# RULES "hexadecimal/Integer" hexadecimal = integer 16 :: Integer -> Builder #-}+hexadecimal i+    | i < 0     = minus <> go (-i)+    | otherwise = go i+  where+    go n | n < 16    = hexDigit n+         | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)+{-# NOINLINE[0] hexadecimal #-}++digit :: Integral a => a -> Builder+digit n = singleton $! i2d (fromIntegral n)+{-# INLINE digit #-}++hexDigit :: Integral a => a -> Builder+hexDigit n+    | n <= 9    = singleton $! i2d (fromIntegral n)+    | otherwise = singleton $! toEnum (fromIntegral n + 87)+{-# INLINE hexDigit #-}++minus :: Builder+minus = singleton '-'++int :: Int -> Builder+int = decimal+{-# INLINE int #-}++data T = T !Integer !Int++integer :: Int -> Integer -> Builder+integer 10 (S# i#) = decimal (I# i#)+integer 16 (S# i#) = hexadecimal (I# i#)+integer base i+    | i < 0     = minus <> go (-i)+    | otherwise = go i+  where+    go n | n < maxInt = int (fromInteger n)+         | otherwise  = putH (splitf (maxInt * maxInt) n)++    splitf p n+      | p > n       = [n]+      | otherwise   = splith p (splitf (p*p) n)++    splith p (n:ns) = case n `quotRemInteger` p of+                        PAIR(q,r) | q > 0     -> q : r : splitb p ns+                                  | otherwise -> r : splitb p ns+    splith _ _      = error "splith: the impossible happened."++    splitb p (n:ns) = case n `quotRemInteger` p of+                        PAIR(q,r) -> q : r : splitb p ns+    splitb _ _      = []++    T maxInt10 maxDigits10 =+        until ((>mi) . (*10) . fstT) (\(T n d) -> T (n*10) (d+1)) (T 10 1)+      where mi = fromIntegral (maxBound :: Int)+    T maxInt16 maxDigits16 =+        until ((>mi) . (*16) . fstT) (\(T n d) -> T (n*16) (d+1)) (T 16 1)+      where mi = fromIntegral (maxBound :: Int)++    fstT (T a _) = a++    maxInt | base == 10 = maxInt10+           | otherwise  = maxInt16+    maxDigits | base == 10 = maxDigits10+              | otherwise  = maxDigits16++    putH (n:ns) = case n `quotRemInteger` maxInt of+                    PAIR(x,y)+                        | q > 0     -> int q <> pblock r <> putB ns+                        | otherwise -> int r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putH _ = error "putH: the impossible happened"++    putB (n:ns) = case n `quotRemInteger` maxInt of+                    PAIR(x,y) -> pblock q <> pblock r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putB _ = mempty++    pblock = loop maxDigits+      where+        loop !d !n+            | d == 1    = digit n+            | otherwise = loop (d-1) q <> digit r+            where q = n `quotInt` base+                  r = n `remInt` base
+ src/Data/Text/Format/Types.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-}++-- |+-- Module      : Data.Text.Format.Types.Internal+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Types for text mangling.++module Data.Text.Format.Types+    (++     Shown(..)+    -- * Integer format control+    , Hex(..)+    ) where++import Data.Monoid (Monoid(..))+import Data.String (IsString(..))+import Data.Text (Text)+import Data.Typeable (Typeable)++-- | Render an integral type in hexadecimal.+newtype Hex a = Hex a+    deriving (Eq, Ord, Read, Show, Num, Real, Enum, Integral)++-- | Render a value using its 'Show' instance.+newtype Shown a = Shown {+      shown :: a+    } deriving (Eq, Show, Read, Ord, Num, Fractional, Real, RealFrac,+                Floating, RealFloat, Enum, Integral, Bounded)
+ src/Formatting/Buildable.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE CPP, FlexibleInstances, OverloadedStrings #-}++-- |+-- Module      : Data.Text.Buildable+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Types that can be rendered to a 'Builder'.++module Formatting.Buildable+    (+      Buildable(..)+    ) where++#if MIN_VERSION_base(4,8,0)+import qualified Data.ByteString.Lazy as L+import           Data.Void (Void, absurd)+#endif++import           Data.Monoid (mempty)+import           Data.Int (Int8, Int16, Int32, Int64)+import           Data.Fixed (Fixed, HasResolution, showFixed)+import           Data.Ratio (Ratio, denominator, numerator)+import           Data.Text.Format.Functions ((<>))+import           Data.Text.Format.Int (decimal, hexadecimal, integer)+import           Data.Text.Format.Types (Hex(..), Shown(..))+import           Data.Text.Lazy.Builder+import           Data.Time.Calendar (Day, showGregorian)+import           Data.Time.Clock (DiffTime, NominalDiffTime, UTCTime, UniversalTime)+import           Data.Time.Clock (getModJulianDate)+import           Data.Time.LocalTime (LocalTime, TimeOfDay, TimeZone, ZonedTime)+import           Data.Word (Word, Word8, Word16, Word32, Word64)+import           Foreign.Ptr (IntPtr, WordPtr, Ptr, ptrToWordPtr)+import qualified Data.Text as ST+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Encoding as T+import qualified Data.ByteString.Lazy.Builder as L++-- | The class of types that can be rendered to a 'Builder'.+class Buildable p where+    build :: p -> Builder++instance Buildable Builder where+    build = id++#if MIN_VERSION_base(4,8,0)+instance Buildable Void where+    build = absurd+#endif++instance Buildable LT.Text where+    build = fromLazyText+    {-# INLINE build #-}++instance Buildable ST.Text where+    build = fromText+    {-# INLINE build #-}++instance Buildable Char where+    build = singleton+    {-# INLINE build #-}++instance Buildable [Char] where+    build = fromString+    {-# INLINE build #-}++instance (Integral a) => Buildable (Hex a) where+    build = hexadecimal+    {-# INLINE build #-}++instance Buildable Int8 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Int16 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Int32 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Int where+    build = decimal+    {-# INLINE build #-}++instance Buildable Int64 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Integer where+    build = integer 10+    {-# INLINE build #-}++instance (HasResolution a) => Buildable (Fixed a) where+    build = build . showFixed False+    {-# INLINE build #-}++instance Buildable Word8 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Word16 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Word32 where+    build = decimal+    {-# INLINE build #-}++instance Buildable Word where+    build = decimal+    {-# INLINE build #-}++instance Buildable Word64 where+    build = decimal+    {-# INLINE build #-}++instance (Integral a, Buildable a) => Buildable (Ratio a) where+    {-# SPECIALIZE instance Buildable (Ratio Integer) #-}+    build a = build (numerator a) <> singleton '/' <> build (denominator a)++instance Buildable Float where+    build = fromText . T.decodeUtf8 . L.toStrict . L.toLazyByteString . L.floatDec+    {-# INLINE build #-};++instance Buildable Double where+    build = fromText . T.decodeUtf8 . L.toStrict . L.toLazyByteString . L.doubleDec+    {-# INLINE build #-}++instance Buildable DiffTime where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable NominalDiffTime where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable UTCTime where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable UniversalTime where+    build = build . Shown . getModJulianDate+    {-# INLINE build #-}++instance Buildable Day where+    build = fromString . showGregorian+    {-# INLINE build #-}++instance (Show a) => Buildable (Shown a) where+    build = fromString . show . shown+    {-# INLINE build #-}++instance (Buildable a) => Buildable (Maybe a) where+    build Nothing = mempty+    build (Just v) = build v+    {-# INLINE build #-}++instance Buildable TimeOfDay where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable TimeZone where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable LocalTime where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable ZonedTime where+    build = build . Shown+    {-# INLINE build #-}++instance Buildable IntPtr where+    build p = fromText "0x" <> hexadecimal p++instance Buildable WordPtr where+    build p = fromText "0x" <> hexadecimal p++instance Buildable (Ptr a) where+    build = build . ptrToWordPtr++instance Buildable Bool where+    build True = fromText "True"+    build False = fromText "False"
src/Formatting/Clock.hs view
@@ -4,37 +4,36 @@  -- | Formatters for high-res, real-time and timer clock values from "System.Clock". -module Formatting.Clock where+module Formatting.Clock (timeSpecs) where +import Data.Text.Lazy.Builder import Formatting import Formatting.Internal import System.Clock --- | Format the duration from start to end (args passed in that order).------ Examples:------ @--- 4.00 s--- 500.69 ms--- 1.20 ms--- 19.38 µs--- @+fmt :: Integer -> Builder+fmt diff+  | Just i <- scale ((10 ^ 9) * 60 * 60 * 24) = bprint (fixed 2 % " d") i+  | Just i <- scale ((10 ^ 9) * 60 * 60) = bprint (fixed 2 % " h") i+  | Just i <- scale ((10 ^ 9) * 60) = bprint (fixed 2 % " m") i+  | Just i <- scale (10 ^ 9) = bprint (fixed 2 % " s") i+  | Just i <- scale (10 ^ 6) = bprint (fixed 2 % " ms") i+  | Just i <- scale (10 ^ 3) = bprint (fixed 2 % " us") i+  | otherwise = bprint (int % " ns") diff+  where+    scale :: Integer -> Maybe Double+    scale i =+      if diff >= i+        then Just (fromIntegral diff / fromIntegral i)+        else Nothing++-- | Same as @durationNS@ but works on `TimeSpec` from the clock package. timeSpecs :: Format r (TimeSpec -> TimeSpec -> r)-timeSpecs = Format (\g x y -> g (fmt x y))-  where fmt (TimeSpec s1 n1) (TimeSpec s2 n2)-          | Just i <- scale ((10 ^ 9) * 60 * 60 * 24) = bprint (fixed 2 % " d") i-          | Just i <- scale ((10 ^ 9) * 60 * 60) = bprint (fixed 2 % " h") i-          | Just i <- scale ((10 ^ 9) * 60) = bprint (fixed 2 % " m") i-          | Just i <- scale (10 ^ 9) = bprint (fixed 2 % " s") i-          | Just i <- scale (10 ^ 6) = bprint (fixed 2 % " ms") i-          | Just i <- scale (10 ^ 3) = bprint (fixed 2 % " us") i-          | otherwise = bprint (int % " ns") diff-          where scale :: Integer -> Maybe Double-                scale i = if diff >= i-                             then Just (fromIntegral diff / fromIntegral i)-                             else Nothing-                diff :: Integer-                diff = a2 - a1-                a1 = (fromIntegral s1 * 10 ^ 9) + fromIntegral n1-                a2 = (fromIntegral s2 * 10 ^ 9) + fromIntegral n2+timeSpecs = Format (\g x y -> g (fmt0 x y))+  where+    fmt0 (TimeSpec s1 n1) (TimeSpec s2 n2) = fmt diff+      where+        diff :: Integer+        diff = a2 - a1+        a1 = (fromIntegral s1 * 10 ^ 9) + fromIntegral n1+        a2 = (fromIntegral s2 * 10 ^ 9) + fromIntegral n2
src/Formatting/Examples.hs view
@@ -44,9 +44,8 @@ -- | Printing floating points. floats :: Text floats =-  format ("Here comes a float: " % float % " and a double with sci notation: " % prec 6)+  format ("Here comes a float: " % float)          (123.2342 :: Float)-         (13434242423.23420000 :: Double)  -- | Printing integrals in hex (base-16). hexes :: Text
src/Formatting/Formatters.hs view
@@ -25,9 +25,7 @@   -- * Numbers   int,   float,-  expt,   fixed,-  prec,   sci,   scifmt,   shortest,@@ -63,8 +61,8 @@ import           Data.Scientific import qualified Data.Text as S import qualified Data.Text as T-import           Data.Text.Buildable (Buildable)-import qualified Data.Text.Buildable as B (build)+import           Formatting.Buildable (Buildable)+import qualified Formatting.Buildable as B (build) import qualified Data.Text.Format as T import           Data.Text.Lazy (Text) import qualified Data.Text.Lazy as LT@@ -110,29 +108,18 @@ build = later B.build  -- | Render an integral e.g. 123 -> \"123\", 0 -> \"0\".-int :: Integral a => Format r (a -> r)-int = later T.shortest+int :: (Integral a, Buildable a) => Format r (a -> r)+int = later B.build  -- | Render some floating point with the usual notation, e.g. 123.32 => \"123.32\" float :: Real a => Format r (a -> r) float = later (T.shortest) --- | Render a floating point number using scientific/engineering--- notation (e.g. 2.3e123), with the given number of decimal places.-expt :: Real a => Int -> Format r (a -> r)-expt i = later (T.expt i)- -- | Render a floating point number using normal notation, with the -- given number of decimal places. fixed :: Real a => Int -> Format r (a -> r) fixed i = later (T.fixed i) --- | Render a floating point number, with the given number of digits--- of precision. Uses decimal notation for values between 0.1 and--- 9,999,999, and scientific notation otherwise.-prec :: Real a => Int -> Format r (a -> r)-prec i = later (T.prec i)- -- | Render a floating point number using the smallest number of -- digits that correctly represent it. shortest :: Real a => Format r (a -> r)@@ -172,22 +159,24 @@ -- | Group integral numbers, e.g. groupInt 2 '.' on 123456 -> \"12.34.56\". groupInt :: (Buildable n,Integral n) => Int -> Char -> Format r (n -> r) groupInt 0 _ = later B.build-groupInt i c = later (commaize)-  where commaize =-          T.fromLazyText . LT.reverse .-          foldr merge "" .-          LT.zip (zeros <> cycle' zeros') .-          LT.reverse .-          T.toLazyText .-          B.build-        zeros =-          LT.replicate (fromIntegral i)-                       (LT.singleton '0')-        zeros' = LT.singleton c <> LT.tail zeros-        merge (f,c') rest-          | f == c = LT.singleton c <> LT.singleton c' <> rest-          | otherwise = LT.singleton c' <> rest-        cycle' xs = xs <> cycle' xs+groupInt i c =+  later+    (\n ->+       if n < 0+         then "-" <> commaize (negate n)+         else commaize n)+  where+    commaize =+      T.fromLazyText .+      LT.reverse .+      foldr merge "" .+      LT.zip (zeros <> cycle' zeros') . LT.reverse . T.toLazyText . B.build+    zeros = LT.replicate (fromIntegral i) (LT.singleton '0')+    zeros' = LT.singleton c <> LT.tail zeros+    merge (f, c') rest+      | f == c = LT.singleton c <> LT.singleton c' <> rest+      | otherwise = LT.singleton c' <> rest+    cycle' xs = xs <> cycle' xs  -- | Fit in the given length, truncating on the left. fitLeft :: Buildable a => Int -> Format r (a -> r)@@ -310,4 +299,3 @@                   n' < 1024 || numDivs == (length bytesSuffixes - 1)         bytesSuffixes =           ["B","KB","MB","GB","TB","PB","EB","ZB","YB"]-
src/Formatting/ShortFormatters.hs view
@@ -17,20 +17,20 @@ import           Formatting.Formatters (bin, int, oct) import           Formatting.Internal -import qualified Data.Text.Buildable as B (build) import qualified Data.Text as S import qualified Data.Text as T-import           Data.Text.Buildable    (Buildable)-import qualified Data.Text.Format       as T+import qualified Data.Text.Format as T import           Data.Text.Lazy (Text) import qualified Data.Text.Lazy.Builder as T+import           Formatting.Buildable (Buildable)+import qualified Formatting.Buildable as B (build)  -- | Output a lazy text. t :: Format r (Text -> r) t = later T.fromLazyText  -- | Render an integral e.g. 123 -> \"123\", 0 -> \"0\".-d :: Integral a => Format r (a -> r)+d :: (Integral a, Buildable a) => Format r (a -> r) d = int  -- | Render an integer using binary notation. (No leading 0b is@@ -64,21 +64,10 @@ c :: Format r (Char -> r) c = later B.build --- | Render a floating point number using scientific/engineering--- notation (e.g. 2.3e123), with the given number of decimal places.-ef :: Real a => Int -> Format r (a -> r)-ef i = later (T.expt i)- -- | Render a floating point number using normal notation, with the -- given number of decimal places. f :: Real a => Int -> Format r (a -> r) f i = later (T.fixed i)---- | Render a floating point number, with the given number of digits--- of precision. Uses decimal notation for values between 0.1 and--- 9,999,999, and scientific notation otherwise.-pf :: Real a => Int -> Format r (a -> r)-pf i = later (T.prec i)  -- | Render a floating point number using the smallest number of -- digits that correctly represent it.
src/Formatting/Time.hs view
@@ -13,7 +13,7 @@  import           Data.Text              (Text) import qualified Data.Text              as T-import           Data.Text.Buildable+import           Formatting.Buildable import           Data.Time #if MIN_VERSION_time(1,5,0) import           System.Locale hiding (defaultTimeLocale)@@ -226,7 +226,7 @@         Just (_,f,base) -> bprint (prefix % f % suffix) (toInt ts base)       where prefix = now (if fix && ts > 0 then "in " else "")             suffix = now (if fix && ts < 0 then " ago" else "")-    toInt ts base = abs (round (ts / base))+    toInt ts base = abs (round (ts / base)) :: Int     ranges =       [(0,int % " milliseconds",0.001)       ,(1,int % " seconds",1)
+ test/Spec.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE OverloadedStrings #-}++import Data.Int+import Formatting as F+import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe+    "Regression tests"+    (do describe+          "https://github.com/chrisdone/formatting/issues/31"+          (do it+                "10^6-1"+                (shouldBe+                   (F.format F.int (10 ^ (16 :: Int) - 1 :: Int))+                   "9999999999999999"))+        describe+          "https://github.com/chrisdone/formatting/issues/28"+          (do it+                "-100"+                (shouldBe (sformat (groupInt 3 ',') (-100 :: Int)) "-100")+              it+                "-100,000,000"+                (shouldBe+                   (sformat (groupInt 3 ',') (-100000000 :: Int))+                   "-100,000,000")+              it+                "100,000,000"+                (shouldBe+                   (sformat (groupInt 3 ',') (-100000000 :: Int))+                   "-100,000,000"))+        describe+          "https://github.com/bos/text-format/issues/18"+          (do it+                "build (minBound :: Int)"+                (shouldBe (format build (minBound :: Int64))+                          "-9223372036854775808")))