pgdl-10.9: src/Utils.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Utils
where
import qualified Data.Text as T
import Data.Text (Text)
import Text.Printf
import System.IO
import qualified Graphics.Text.Width as TW
-- | 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 = 83
-- | charDisplayLen returns the display length of a character
charDisplayLen :: Char -> Integer
charDisplayLen c
| w > 0 = fromIntegral w
| otherwise = 2 -- assume unknown characters occupy 2 widths
where
w = TW.safeWcwidth c
-- | return the estimated display length of a Text
displayLength :: Text -> Integer
displayLength = sum . map charDisplayLen . T.unpack
-- | 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
askPassword :: IO Text
askPassword = do
putStr "please input password: "
hFlush stdout
hSetEcho stdin False
pass <- getLine
hSetEcho stdin True
putChar '\n'
return $ T.pack pass
placeTextIntoRectangle :: Int -> -- ^ height
Int -> -- ^ width
Text -> Text
placeTextIntoRectangle h w t
| l > w = error "placeTextIntoRectangle: text too long"
| otherwise = T.unlines $
replicate (h `div` 2) (T.replicate w " ") ++
[T.concat [T.replicate leftspace " ", t, T.replicate rightspace " "]] ++
replicate (h `div` 2) (T.replicate w " ")
where
l = fromIntegral $ displayLength t
leftspace = (w-l) `div` 2
rightspace = w - leftspace - l