packages feed

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