cascading-0.1.0: Data/CSS/Utils.hs
-- |
-- Module: Data.CSS.Utils
-- Copyright: (c) 2013 Ertugrul Soeylemez
-- License: BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
module Data.CSS.Utils
( -- * Builder utilities
commas,
commasBS,
cssString,
showHexInt,
showReal
)
where
import qualified Data.ByteString.Char8 as B
import qualified Data.Text as T
import Blaze.ByteString.Builder
import Blaze.ByteString.Builder.Char.Utf8
import Data.ByteString (ByteString)
import Data.Char
import Data.Foldable (fold)
import Data.List
import Data.Monoid
import Data.Text (Text)
-- | Render the given list of builders separated by commas.
commas :: [Builder] -> Builder
commas = fold . intersperse (fromChar ',')
-- | Render the given list of builders separated by commas.
commasBS :: [ByteString] -> Builder
commasBS = commas . map fromByteString
-- | Renders the given CSS string in double-quotes, escaped as
-- necessary.
cssString :: Text -> Builder
cssString s0 = fromChar '"' <> str s0 <> fromChar '"'
where
str s' =
case T.uncons s' of
Nothing -> mempty
Just ('"', s) -> fromByteString "\\\"" <> str s
Just ('\\', s) -> fromByteString "\\\\" <> str s
Just (c, s)
| isControl c -> fromChar '\\' <> showHexInt 6 (ord c) <> str s
| otherwise -> fromChar c <> str s
-- | @showHexInt p n@ builds the hexadecimal representation of @n@ with
-- at least @p@ digits. Prepends zeroes to fill.
showHexInt :: (Integral a) => Int -> a -> Builder
showHexInt p n | n < 0 = fromChar '-' <> showHexInt p (negate n)
showHexInt p 0 = fromByteString (B.replicate (max 0 p) '0')
showHexInt p' n' =
p `seq` showHexInt p n <>
fromChar (intToDigit $ fromIntegral r)
where
(n, r) = quotRem n' 16
p = max 0 (pred p')
-- | Lossily convert the given 'Real' number into a decimal
-- representation suitable for CSS.
showReal :: (Real a) => a -> Builder
showReal = showRat . toRational
where
showRat x | x < 0 = fromChar '-' <> showRat (negate x)
showRat x =
let (n, f) = properFraction x in
(if n == 0 then fromChar '0' else intP n) <>
(if f == 0 then mempty else fromChar '.' <> fromString (fracP 6 f))
intP :: Integer -> Builder
intP 0 = mempty
intP n = let (q, r) = quotRem n 10 in intP q <> fromChar (intToDigit $ fromInteger r)
fracP _ 0 = ""
fracP 0 _ = ""
fracP i f'
| all (== '0') res = ""
| otherwise = res
where
(n, f) = properFraction (10*f')
res = intToDigit n : fracP (pred i) f