{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
module Formatting.Formatters
(
text,
stext,
string,
shown,
char,
builder,
fconst,
int,
float,
fixed,
sci,
scifmt,
shortest,
groupInt,
commas,
ords,
plural,
asInt,
left,
right,
center,
fitLeft,
fitRight,
base,
bin,
oct,
hex,
prefixBin,
prefixOct,
prefixHex,
bytes,
build,
Buildable,
) where
import Formatting.Internal
import Data.Char (chr, ord)
import Data.Scientific
import qualified Data.Text as S
import qualified Data.Text as T
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
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as T
import Data.Text.Lazy.Builder.Scientific
import Numeric (showIntAtBase)
text :: Format r (Text -> r)
text :: Format r (Text -> r)
text = (Text -> Builder) -> Format r (Text -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later Text -> Builder
T.fromLazyText
stext :: Format r (S.Text -> r)
stext :: Format r (Text -> r)
stext = (Text -> Builder) -> Format r (Text -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later Text -> Builder
T.fromText
string :: Format r (String -> r)
string :: Format r (String -> r)
string = (String -> Builder) -> Format r (String -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Text -> Builder
T.fromText (Text -> Builder) -> (String -> Text) -> String -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack)
shown :: Show a => Format r (a -> r)
shown :: Format r (a -> r)
shown = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Text -> Builder
T.fromText (Text -> Builder) -> (a -> Text) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show)
char :: Format r (Char -> r)
char :: Format r (Char -> r)
char = (Char -> Builder) -> Format r (Char -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later Char -> Builder
forall p. Buildable p => p -> Builder
B.build
builder :: Format r (Builder -> r)
builder :: Format r (Builder -> r)
builder = (Builder -> Builder) -> Format r (Builder -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later Builder -> Builder
forall a. a -> a
id
fconst :: Builder -> Format r (a -> r)
fconst :: Builder -> Format r (a -> r)
fconst m :: Builder
m = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Builder -> a -> Builder
forall a b. a -> b -> a
const Builder
m)
build :: Buildable a => Format r (a -> r)
build :: Format r (a -> r)
build = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
forall p. Buildable p => p -> Builder
B.build
int :: Integral a => Format r (a -> r)
int :: Format r (a -> r)
int = Int -> Format r (a -> r)
forall a r. Integral a => Int -> Format r (a -> r)
base 10
float :: Real a => Format r (a -> r)
float :: Format r (a -> r)
float = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
forall a. Real a => a -> Builder
T.shortest
fixed :: Real a => Int -> Format r (a -> r)
fixed :: Int -> Format r (a -> r)
fixed i :: Int
i = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int -> a -> Builder
forall a. Real a => Int -> a -> Builder
T.fixed Int
i)
shortest :: Real a => Format r (a -> r)
shortest :: Format r (a -> r)
shortest = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
forall a. Real a => a -> Builder
T.shortest
sci :: Format r (Scientific -> r)
sci :: Format r (Scientific -> r)
sci = (Scientific -> Builder) -> Format r (Scientific -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later Scientific -> Builder
scientificBuilder
scifmt :: FPFormat -> Maybe Int -> Format r (Scientific -> r)
scifmt :: FPFormat -> Maybe Int -> Format r (Scientific -> r)
scifmt f :: FPFormat
f i :: Maybe Int
i = (Scientific -> Builder) -> Format r (Scientific -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (FPFormat -> Maybe Int -> Scientific -> Builder
formatScientificBuilder FPFormat
f Maybe Int
i)
asInt :: Enum a => Format r (a -> r)
asInt :: Format r (a -> r)
asInt = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int -> Builder
forall a. Real a => a -> Builder
T.shortest (Int -> Builder) -> (a -> Int) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. Enum a => a -> Int
fromEnum)
left :: Buildable a => Int -> Char -> Format r (a -> r)
left :: Int -> Char -> Format r (a -> r)
left i :: Int
i c :: Char
c = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int -> Char -> a -> Builder
forall a. Buildable a => Int -> Char -> a -> Builder
T.left Int
i Char
c)
right :: Buildable a => Int -> Char -> Format r (a -> r)
right :: Int -> Char -> Format r (a -> r)
right i :: Int
i c :: Char
c = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int -> Char -> a -> Builder
forall a. Buildable a => Int -> Char -> a -> Builder
T.right Int
i Char
c)
center :: Buildable a => Int -> Char -> Format r (a -> r)
center :: Int -> Char -> Format r (a -> r)
center i :: Int
i c :: Char
c = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
centerT where
centerT :: a -> Builder
centerT = Text -> Builder
T.fromLazyText (Text -> Builder) -> (a -> Text) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Char -> Text -> Text
LT.center (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) Char
c (Text -> Text) -> (a -> Text) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
T.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
groupInt :: (Buildable n,Integral n) => Int -> Char -> Format r (n -> r)
groupInt :: Int -> Char -> Format r (n -> r)
groupInt 0 _ = (n -> Builder) -> Format r (n -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later n -> Builder
forall p. Buildable p => p -> Builder
B.build
groupInt i :: Int
i c :: Char
c =
(n -> Builder) -> Format r (n -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later
(\n :: n
n ->
if n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< 0
then "-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> n -> Builder
commaize (n -> n
forall a. Num a => a -> a
negate n
n)
else n -> Builder
commaize n
n)
where
commaize :: n -> Builder
commaize =
Text -> Builder
T.fromLazyText (Text -> Builder) -> (n -> Text) -> n -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Text -> Text
LT.reverse (Text -> Text) -> (n -> Text) -> n -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
((Char, Char) -> Text -> Text) -> Text -> [(Char, Char)] -> Text
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Char, Char) -> Text -> Text
merge "" ([(Char, Char)] -> Text) -> (n -> [(Char, Char)]) -> n -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Text -> Text -> [(Char, Char)]
LT.zip (Text
zeros Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
forall t. Semigroup t => t -> t
cycle' Text
zeros') (Text -> [(Char, Char)]) -> (n -> Text) -> n -> [(Char, Char)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
LT.reverse (Text -> Text) -> (n -> Text) -> n -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
T.toLazyText (Builder -> Text) -> (n -> Builder) -> n -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. n -> Builder
forall p. Buildable p => p -> Builder
B.build
zeros :: Text
zeros = Int64 -> Text -> Text
LT.replicate (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) (Char -> Text
LT.singleton '0')
zeros' :: Text
zeros' = Char -> Text
LT.singleton Char
c Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
LT.tail Text
zeros
merge :: (Char, Char) -> Text -> Text
merge (f :: Char
f, c' :: Char
c') rest :: Text
rest
| Char
f Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = Char -> Text
LT.singleton Char
c Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Char -> Text
LT.singleton Char
c' Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
rest
| Bool
otherwise = Char -> Text
LT.singleton Char
c' Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
rest
cycle' :: t -> t
cycle' xs :: t
xs = t
xs t -> t -> t
forall a. Semigroup a => a -> a -> a
<> t -> t
cycle' t
xs
fitLeft :: Buildable a => Int -> Format r (a -> r)
fitLeft :: Int -> Format r (a -> r)
fitLeft size :: Int
size = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int64 -> a -> Builder
forall p. Buildable p => Int64 -> p -> Builder
fit (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
size)) where
fit :: Int64 -> p -> Builder
fit i :: Int64
i = Text -> Builder
T.fromLazyText (Text -> Builder) -> (p -> Text) -> p -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Text -> Text
LT.take Int64
i (Text -> Text) -> (p -> Text) -> p -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
T.toLazyText (Builder -> Text) -> (p -> Builder) -> p -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. p -> Builder
forall p. Buildable p => p -> Builder
B.build
fitRight :: Buildable a => Int -> Format r (a -> r)
fitRight :: Int -> Format r (a -> r)
fitRight size :: Int
size = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (Int64 -> a -> Builder
forall p. Buildable p => Int64 -> p -> Builder
fit (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
size)) where
fit :: Int64 -> p -> Builder
fit i :: Int64
i = Text -> Builder
T.fromLazyText (Text -> Builder) -> (p -> Text) -> p -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
(\t :: Text
t -> Int64 -> Text -> Text
LT.drop (Text -> Int64
LT.length Text
t Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int64
i) Text
t)
(Text -> Text) -> (p -> Text) -> p -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
T.toLazyText
(Builder -> Text) -> (p -> Builder) -> p -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. p -> Builder
forall p. Buildable p => p -> Builder
B.build
commas :: (Buildable n,Integral n) => Format r (n -> r)
commas :: Format r (n -> r)
commas = Int -> Char -> Format r (n -> r)
forall n r.
(Buildable n, Integral n) =>
Int -> Char -> Format r (n -> r)
groupInt 3 ','
ords :: Integral n => Format r (n -> r)
ords :: Format r (n -> r)
ords = (n -> Builder) -> Format r (n -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later n -> Builder
forall a. Integral a => a -> Builder
go
where go :: a -> Builder
go n :: a
n
| a
tens a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> 3 Bool -> Bool -> Bool
&& a
tens a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< 21 = Int -> a -> Builder
forall a. Real a => Int -> a -> Builder
T.fixed 0 a
n Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> "th"
| Bool
otherwise =
Int -> a -> Builder
forall a. Real a => Int -> a -> Builder
T.fixed 0 a
n Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
case a
n a -> a -> a
forall a. Integral a => a -> a -> a
`mod` 10 of
1 -> "st"
2 -> "nd"
3 -> "rd"
_ -> "th"
where tens :: a
tens = a
n a -> a -> a
forall a. Integral a => a -> a -> a
`mod` 100
plural :: (Num a, Eq a) => Text -> Text -> Format r (a -> r)
plural :: Text -> Text -> Format r (a -> r)
plural s :: Text
s p :: Text
p = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (\i :: a
i -> if a
i a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== 1 then Text -> Builder
forall p. Buildable p => p -> Builder
B.build Text
s else Text -> Builder
forall p. Buildable p => p -> Builder
B.build Text
p)
base :: Integral a => Int -> Format r (a -> r)
base :: Int -> Format r (a -> r)
base numBase :: Int
numBase = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later (String -> Builder
forall p. Buildable p => p -> Builder
B.build (String -> Builder) -> (a -> String) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> a -> String
forall a. Integral a => Int -> a -> String
atBase Int
numBase)
bin :: Integral a => Format r (a -> r)
bin :: Format r (a -> r)
bin = Int -> Format r (a -> r)
forall a r. Integral a => Int -> Format r (a -> r)
base 2
{-# INLINE bin #-}
oct :: Integral a => Format r (a -> r)
oct :: Format r (a -> r)
oct = Int -> Format r (a -> r)
forall a r. Integral a => Int -> Format r (a -> r)
base 8
{-# INLINE oct #-}
hex :: Integral a => Format r (a -> r)
hex :: Format r (a -> r)
hex = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
forall a. Integral a => a -> Builder
T.hex
{-# INLINE hex #-}
prefixBin :: Integral a => Format r (a -> r)
prefixBin :: Format r (a -> r)
prefixBin = "0b" Format (a -> r) (a -> r) -> Format r (a -> r) -> Format r (a -> r)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Format r (a -> r)
forall a r. Integral a => Format r (a -> r)
bin
{-# INLINE prefixBin #-}
prefixOct :: Integral a => Format r (a -> r)
prefixOct :: Format r (a -> r)
prefixOct = "0o" Format (a -> r) (a -> r) -> Format r (a -> r) -> Format r (a -> r)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Format r (a -> r)
forall a r. Integral a => Format r (a -> r)
oct
{-# INLINE prefixOct #-}
prefixHex :: Integral a => Format r (a -> r)
prefixHex :: Format r (a -> r)
prefixHex = "0x" Format (a -> r) (a -> r) -> Format r (a -> r) -> Format r (a -> r)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Format r (a -> r)
forall a r. Integral a => Format r (a -> r)
hex
{-# INLINE prefixHex #-}
atBase :: Integral a => Int -> a -> String
atBase :: Int -> a -> String
atBase b :: Int
b _ | Int
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 2 Bool -> Bool -> Bool
|| Int
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 36 = String -> String
forall a. HasCallStack => String -> a
error ("base: Invalid base " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
b)
atBase b :: Int
b n :: a
n =
(Integer -> String -> String) -> Integer -> String -> String
forall a.
Real a =>
(a -> String -> String) -> a -> String -> String
showSigned' (Integer -> (Int -> Char) -> Integer -> String -> String
forall a.
(Integral a, Show a) =>
a -> (Int -> Char) -> a -> String -> String
showIntAtBase (Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
b) Int -> Char
intToDigit') (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n) ""
{-# INLINE atBase #-}
showSigned' :: Real a => (a -> ShowS) -> a -> ShowS
showSigned' :: (a -> String -> String) -> a -> String -> String
showSigned' f :: a -> String -> String
f n :: a
n
| a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = Char -> String -> String
showChar '-' (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String -> String
f (a -> a
forall a. Num a => a -> a
negate a
n)
| Bool
otherwise = a -> String -> String
f a
n
intToDigit' :: Int -> Char
intToDigit' :: Int -> Char
intToDigit' i :: Int
i
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 0 Bool -> Bool -> Bool
&& Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 10 = Int -> Char
chr (Char -> Int
ord '0' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i)
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 10 Bool -> Bool -> Bool
&& Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 36 = Int -> Char
chr (Char -> Int
ord 'a' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- 10)
| Bool
otherwise = String -> Char
forall a. HasCallStack => String -> a
error ("intToDigit': Invalid int " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i)
bytes :: (Ord f,Integral a,Fractional f)
=> Format Builder (f -> Builder)
-> Format r (a -> r)
bytes :: Format Builder (f -> Builder) -> Format r (a -> r)
bytes d :: Format Builder (f -> Builder)
d = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
later a -> Builder
forall a. Integral a => a -> Builder
go
where go :: a -> Builder
go bs :: a
bs =
Format Builder (f -> Builder) -> f -> Builder
forall a. Format Builder a -> a
bprint Format Builder (f -> Builder)
d (a -> f
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a
forall a. Num a => a -> a
signum a
bs) f -> f -> f
forall a. Num a => a -> a -> a
* f
dec) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder]
bytesSuffixes [Builder] -> Int -> Builder
forall a. [a] -> Int -> a
!!
Int
i
where (dec :: f
dec,i :: Int
i) = a -> (f, Int)
forall a a. (Fractional a, Integral a, Ord a) => a -> (a, Int)
getSuffix (a -> a
forall a. Num a => a -> a
abs a
bs)
getSuffix :: a -> (a, Int)
getSuffix n :: a
n =
((a, Int) -> Bool)
-> ((a, Int) -> (a, Int)) -> (a, Int) -> (a, Int)
forall a. (a -> Bool) -> (a -> a) -> a -> a
until (a, Int) -> Bool
forall a. (Ord a, Num a) => (a, Int) -> Bool
p
(\(x :: a
x,y :: Int
y) -> (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ 1024,Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1))
(a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n,0)
where p :: (a, Int) -> Bool
p (n' :: a
n',numDivs :: Int
numDivs) =
a
n' a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< 1024 Bool -> Bool -> Bool
|| Int
numDivs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== ([Builder] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Builder]
bytesSuffixes Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1)
bytesSuffixes :: [Builder]
bytesSuffixes =
["B","KB","MB","GB","TB","PB","EB","ZB","YB"]