packages feed

codeforces-cli-0.1.0: src/Codeforces/App/Format.hs

--------------------------------------------------------------------------------

-- | Utility functions for formatting data.
module Codeforces.App.Format where

import           Codeforces.Types        hiding ( RankColor(..) )
import qualified Codeforces.Types.Rank         as R

import           Codeforces.App.Table

import           Data.Fixed
import           Data.Text                      ( Text )
import qualified Data.Text                     as T
import           Data.Time

import           System.Console.ANSI

--------------------------------------------------------------------------------

-- | 'showText' @x@ is a 'Data.Text' version of 'show'
showText :: Show a => a -> Text
showText = T.pack . show

-- | 'colored' @color text@ wraps some text around SGR codes to display it in
-- the given color.
colored :: Color -> Text -> Text
colored c s = T.concat
    [ T.pack $ setSGRCode [SetColor Foreground Dull c]
    , s
    , T.pack $ setSGRCode [Reset]
    ]

rankColored :: R.RankColor -> Text -> Text
rankColored = colored . convertRankColor

convertRankColor :: R.RankColor -> Color
convertRankColor R.Gray   = White
convertRankColor R.Green  = Green
convertRankColor R.Cyan   = Cyan
convertRankColor R.Blue   = Blue
convertRankColor R.Violet = Magenta
convertRankColor R.Orange = Yellow
convertRankColor R.Red    = Red

-- | Like 'differenceCell' but returns a 'Text' rather than a 'Cell'.
diffColored :: Int -> Text
diffColored x | x > 0     = colored Green $ "+" <> showText x
              | x == 0    = " " <> showText x
              | otherwise = colored Red $ showText x

indent :: Text
indent = T.replicate 6 " "

--------------------------------------------------------------------------------

fmtTimeConsumed :: Int -> Text
fmtTimeConsumed x = showText x <> " ms"

fmtMemoryConsumed :: Int -> Text
fmtMemoryConsumed x = showText (x `div` 1000) <> " KB"

-- | Returns an approximate and human-friendly time difference.
--
-- Possible options are:
--  * "just now"
--  * "5 seconds ago"
--  * "X seconds ago" where X is a multiple of 10
--  * "X minutes ago"
--
fmtDiffTime :: NominalDiffTime -> Text
fmtDiffTime diff = go (nominalDiffTimeToSeconds diff)
  where
    go x | x < 5     = "just now"
         | x < 10    = "5 seconds ago"
         | x < 60    = showText (x `div'` 10 :: Int) <> "0 seconds ago"
         | otherwise = showText (x `div'` 60 :: Int) <> " minutes ago"

--------------------------------------------------------------------------------

plainCell :: Text -> Cell
plainCell = Cell [Reset]

coloredCell :: Color -> Text -> Cell
coloredCell c = Cell [SetColor Foreground Dull c]

blankCell :: Cell
blankCell = plainCell ""

ratingCell :: Rating -> Cell
ratingCell x =
    let color = convertRankColor $ rankColor $ getRank x
    in  coloredCell color (showText x)

-- | 'differenceCell' @diff@ colors a number red, white or green, depending on
-- whether it's negative, 0, or positive.
differenceCell :: Int -> Cell
differenceCell x | x > 0     = coloredCell Green $ "+" <> showText x
                 | x == 0    = plainCell $ " " <> showText x
                 | otherwise = coloredCell Red $ showText x

-- | 'verdictCell' @testset passedTestCount points verdict@ returns a cell
-- displaying the status of a submission, such as "Accepted" or "Wrong answer on
-- pretest 2".
verdictCell :: Testset -> Int -> Maybe Points -> Maybe Verdict -> Cell
verdictCell _       _      _      Nothing  = plainCell "In queue"
verdictCell testset passed points (Just v) = case v of
    Ok -> case testset of
        Tests      -> coloredCell Green "Accepted"
        Samples    -> coloredCell Green "Samples passed"
        Pretests   -> coloredCell Green "Pretests passed"
        Challenges -> coloredCell Green "Challenges passed"
    Partial -> coloredCell Yellow $ maybe
        "Partial result"
        (\pts -> T.concat ["Partial result: ", showText pts, " points"])
        points
    Challenged              -> coloredCell Red "Hacked"
    CompilationError        -> plainCell $ verdictText v
    Skipped                 -> plainCell $ verdictText v
    SecurityViolated        -> plainCell $ verdictText v
    Crashed                 -> plainCell $ verdictText v
    InputPreparationCrashed -> plainCell $ verdictText v
    Rejected                -> plainCell $ verdictText v
    _ ->
        let currTest = passed + 1
            clr      = if v == Testing then White else Blue
            text     = T.concat
                [ verdictText v
                , " on "
                , T.toLower . T.init $ showText testset
                , " "
                , showText currTest
                ]
        in  coloredCell clr text

--------------------------------------------------------------------------------