pgdl-9.0: src/Utils.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Utils
where
import qualified Data.ByteString as B
import qualified Data.Text as T
import Data.Text (Text)
import Text.Printf
import Data.Text.Encoding
-- | give a file size in bytes, return pretty file size
-- represent in KB, MB, GB or TB
friendlySize :: Integer -> String
friendlySize b
| fb < 1024 = s2s fb ++ " B "
| kb < 1024 = s2s kb ++ " KB"
| mb < 1024 = s2s mb ++ " MB"
| gb < 1024 = s2s gb ++ " GB"
| otherwise = s2s tb ++ " TB"
where
fb :: Double
fb = fromIntegral b
kb = fb / 1024.0
mb = kb / 1024.0
gb = mb / 1024.0
tb = gb / 1024.0
s2s :: Double -> String
s2s = printf "%6s" . (printf "%.1f" :: Double -> String)
terminalWidth :: Num a => a
terminalWidth = 80
-- | return the estimated display length of a Text
displayLength :: Text -> Integer
displayLength = sum . map charDisplayLen . T.unpack
-- | charDisplayLen determine a unicode character is a wide character or not
-- (a wide character occupy 2 space in the terminal)
-- this method may seem unreliable, but have no better idea.
charDisplayLen :: Char -> Integer
charDisplayLen c
| (B.length . encodeUtf8 . T.pack $ [c]) > 1 = 2
| otherwise = 1
-- | given a line of Text, cut it to a group of Text
-- which have 'len' display length
cutTextByDisplayLength :: Integer -> Text -> [Text]
cutTextByDisplayLength len = map T.pack . gp . T.unpack
where
gp :: String -> [String]
gp = go 0 "" . map (\c -> (c, charDisplayLen c))
where
go :: Integer -> String -> [(Char, Integer)] -> [String]
go _ acc []
| null acc = []
| otherwise = [reverse acc]
go lsum acc str@(x:xs)
| lsum + snd x <= len = go (lsum + snd x) (fst x : acc) xs
| otherwise = reverse acc : go 0 "" str