{-# language DeriveGeneric #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language OverloadedStrings #-}
{-# language PackageImports #-}
{-# language ScopedTypeVariables #-}
module System.ProgressBar
(
ProgressBar
, newProgressBar
, hNewProgressBar
, renderProgressBar
, updateProgress
, incProgress
, Style(..)
, EscapeCode
, OnComplete(..)
, defStyle
, ProgressBarWidth(..)
, Progress(..)
, Label(..)
, Timing(..)
, msg
, percentage
, exact
, elapsedTime
, remainingTime
, totalTime
, renderDuration
) where
import "base" Control.Concurrent.MVar ( MVar, newMVar, modifyMVar_)
import "base" Control.Monad ( when )
import "base" Data.Int ( Int64 )
import "base" Data.Monoid ( Monoid, mempty )
import "base" Data.Ratio ( Ratio, (%) )
import "base" Data.Semigroup ( Semigroup, (<>) )
import "base" Data.String ( IsString, fromString )
import "base" GHC.Generics ( Generic )
import "base" System.IO ( Handle, stderr, hFlush )
import "deepseq" Control.DeepSeq ( NFData, rnf )
import qualified "terminal-size" System.Console.Terminal.Size as TS
import qualified "text" Data.Text.Lazy as TL
import qualified "text" Data.Text.Lazy.Builder as TLB
import qualified "text" Data.Text.Lazy.Builder.Int as TLB
import qualified "text" Data.Text.Lazy.IO as TL
import "time" Data.Time.Clock ( UTCTime, NominalDiffTime, diffUTCTime, getCurrentTime )
data ProgressBar s
= ProgressBar
{ forall s. ProgressBar s -> Style s
pbStyle :: !(Style s)
, forall s. ProgressBar s -> MVar (State s)
pbStateMv :: !(MVar (State s))
, forall s. ProgressBar s -> Double
pbRefreshDelay :: !Double
, forall s. ProgressBar s -> UTCTime
pbStartTime :: !UTCTime
, forall s. ProgressBar s -> Handle
pbHandle :: !Handle
}
instance (NFData s) => NFData (ProgressBar s) where
rnf :: ProgressBar s -> ()
rnf ProgressBar s
pb = forall s. ProgressBar s -> Style s
pbStyle ProgressBar s
pb
seq :: forall a b. a -> b -> b
`seq` forall s. ProgressBar s -> MVar (State s)
pbStateMv ProgressBar s
pb
seq :: forall a b. a -> b -> b
`seq` forall s. ProgressBar s -> Double
pbRefreshDelay ProgressBar s
pb
seq :: forall a b. a -> b -> b
`seq` forall s. ProgressBar s -> UTCTime
pbStartTime ProgressBar s
pb
seq :: forall a b. a -> b -> b
`seq` ()
data State s
= State
{ forall s. State s -> Progress s
stProgress :: !(Progress s)
, forall s. State s -> UTCTime
stRenderTime :: !UTCTime
}
data Progress s
= Progress
{ forall s. Progress s -> Int
progressDone :: !Int
, forall s. Progress s -> Int
progressTodo :: !Int
, forall s. Progress s -> s
progressCustom :: !s
}
progressFinished :: Progress s -> Bool
progressFinished :: forall s. Progress s -> Bool
progressFinished Progress s
p = forall s. Progress s -> Int
progressDone Progress s
p forall a. Ord a => a -> a -> Bool
>= forall s. Progress s -> Int
progressTodo Progress s
p
newProgressBar
:: Style s
-> Double
-> Progress s
-> IO (ProgressBar s)
newProgressBar :: forall s. Style s -> Double -> Progress s -> IO (ProgressBar s)
newProgressBar = forall s.
Handle -> Style s -> Double -> Progress s -> IO (ProgressBar s)
hNewProgressBar Handle
stderr
hNewProgressBar
:: Handle
-> Style s
-> Double
-> Progress s
-> IO (ProgressBar s)
hNewProgressBar :: forall s.
Handle -> Style s -> Double -> Progress s -> IO (ProgressBar s)
hNewProgressBar Handle
hndl Style s
style Double
maxRefreshRate Progress s
initProgress = do
Style s
style' <- forall s. Style s -> IO (Style s)
updateWidth Style s
style
UTCTime
startTime <- IO UTCTime
getCurrentTime
forall s. Handle -> Style s -> Progress s -> Timing -> IO ()
hPutProgressBar Handle
hndl Style s
style' Progress s
initProgress (UTCTime -> UTCTime -> Timing
Timing UTCTime
startTime UTCTime
startTime)
MVar (State s)
stateMv <- forall a. a -> IO (MVar a)
newMVar
State
{ stProgress :: Progress s
stProgress = Progress s
initProgress
, stRenderTime :: UTCTime
stRenderTime = UTCTime
startTime
}
forall (f :: * -> *) a. Applicative f => a -> f a
pure ProgressBar
{ pbStyle :: Style s
pbStyle = Style s
style'
, pbStateMv :: MVar (State s)
pbStateMv = MVar (State s)
stateMv
, pbRefreshDelay :: Double
pbRefreshDelay = forall a. Fractional a => a -> a
recip Double
maxRefreshRate
, pbStartTime :: UTCTime
pbStartTime = UTCTime
startTime
, pbHandle :: Handle
pbHandle = Handle
hndl
}
updateWidth :: Style s -> IO (Style s)
updateWidth :: forall s. Style s -> IO (Style s)
updateWidth Style s
style =
case forall s. Style s -> ProgressBarWidth
styleWidth Style s
style of
ConstantWidth {} -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Style s
style
TerminalWidth {} -> do
Maybe (Window Int)
mbWindow <- forall n. Integral n => IO (Maybe (Window n))
TS.size
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ case Maybe (Window Int)
mbWindow of
Maybe (Window Int)
Nothing -> Style s
style
Just Window Int
window -> Style s
style{ styleWidth :: ProgressBarWidth
styleWidth = Int -> ProgressBarWidth
TerminalWidth (forall a. Window a -> a
TS.width Window Int
window) }
updateProgress
:: forall s
. ProgressBar s
-> (Progress s -> Progress s)
-> IO ()
updateProgress :: forall s. ProgressBar s -> (Progress s -> Progress s) -> IO ()
updateProgress ProgressBar s
progressBar Progress s -> Progress s
f = do
UTCTime
updateTime <- IO UTCTime
getCurrentTime
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ (forall s. ProgressBar s -> MVar (State s)
pbStateMv ProgressBar s
progressBar) forall a b. (a -> b) -> a -> b
$ UTCTime -> State s -> IO (State s)
renderAndUpdate UTCTime
updateTime
where
renderAndUpdate :: UTCTime -> State s -> IO (State s)
renderAndUpdate :: UTCTime -> State s -> IO (State s)
renderAndUpdate UTCTime
updateTime State s
state = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
shouldRender forall a b. (a -> b) -> a -> b
$
forall s. Handle -> Style s -> Progress s -> Timing -> IO ()
hPutProgressBar Handle
hndl (forall s. ProgressBar s -> Style s
pbStyle ProgressBar s
progressBar) Progress s
newProgress Timing
timing
forall (f :: * -> *) a. Applicative f => a -> f a
pure State
{ stProgress :: Progress s
stProgress = Progress s
newProgress
, stRenderTime :: UTCTime
stRenderTime = if Bool
shouldRender then UTCTime
updateTime else forall s. State s -> UTCTime
stRenderTime State s
state
}
where
timing :: Timing
timing = Timing
{ timingStart :: UTCTime
timingStart = forall s. ProgressBar s -> UTCTime
pbStartTime ProgressBar s
progressBar
, timingLastUpdate :: UTCTime
timingLastUpdate = UTCTime
updateTime
}
shouldRender :: Bool
shouldRender = Bool -> Bool
not Bool
tooFast Bool -> Bool -> Bool
|| Bool
finished
tooFast :: Bool
tooFast = Double
secSinceLastRender forall a. Ord a => a -> a -> Bool
<= forall s. ProgressBar s -> Double
pbRefreshDelay ProgressBar s
progressBar
finished :: Bool
finished = forall s. Progress s -> Bool
progressFinished Progress s
newProgress
newProgress :: Progress s
newProgress = Progress s -> Progress s
f forall a b. (a -> b) -> a -> b
$ forall s. State s -> Progress s
stProgress State s
state
secSinceLastRender :: Double
secSinceLastRender :: Double
secSinceLastRender = forall a b. (Real a, Fractional b) => a -> b
realToFrac forall a b. (a -> b) -> a -> b
$ UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime UTCTime
updateTime (forall s. State s -> UTCTime
stRenderTime State s
state)
hndl :: Handle
hndl = forall s. ProgressBar s -> Handle
pbHandle ProgressBar s
progressBar
incProgress
:: ProgressBar s
-> Int
-> IO ()
incProgress :: forall s. ProgressBar s -> Int -> IO ()
incProgress ProgressBar s
pb Int
n = forall s. ProgressBar s -> (Progress s -> Progress s) -> IO ()
updateProgress ProgressBar s
pb forall a b. (a -> b) -> a -> b
$ \Progress s
p -> Progress s
p{ progressDone :: Int
progressDone = forall s. Progress s -> Int
progressDone Progress s
p forall a. Num a => a -> a -> a
+ Int
n }
hPutProgressBar :: Handle -> Style s -> Progress s -> Timing -> IO ()
hPutProgressBar :: forall s. Handle -> Style s -> Progress s -> Timing -> IO ()
hPutProgressBar Handle
hndl Style s
style Progress s
progress Timing
timing = do
Handle -> Text -> IO ()
TL.hPutStr Handle
hndl forall a b. (a -> b) -> a -> b
$ forall s. Style s -> Progress s -> Timing -> Text
renderProgressBar Style s
style Progress s
progress Timing
timing
Handle -> Text -> IO ()
TL.hPutStr Handle
hndl forall a b. (a -> b) -> a -> b
$
if forall s. Progress s -> Bool
progressFinished Progress s
progress
then case forall s. Style s -> OnComplete
styleOnComplete Style s
style of
OnComplete
WriteNewline -> Text
"\n"
OnComplete
Clear -> Text
"\r\ESC[K"
else Text
"\r"
Handle -> IO ()
hFlush Handle
hndl
renderProgressBar
:: Style s
-> Progress s
-> Timing
-> TL.Text
renderProgressBar :: forall s. Style s -> Progress s -> Timing -> Text
renderProgressBar Style s
style Progress s
progress Timing
timing = [Text] -> Text
TL.concat
[ forall s. Style s -> EscapeCode s
styleEscapePrefix Style s
style Progress s
progress
, Text
prefixLabel
, Text
prefixPad
, forall s. Style s -> EscapeCode s
styleEscapeOpen Style s
style Progress s
progress
, forall s. Style s -> Text
styleOpen Style s
style
, forall s. Style s -> EscapeCode s
styleEscapeDone Style s
style Progress s
progress
, Int64 -> Text -> Text
TL.replicate Int64
completed forall a b. (a -> b) -> a -> b
$ Char -> Text
TL.singleton forall a b. (a -> b) -> a -> b
$ forall s. Style s -> Char
styleDone Style s
style
, forall s. Style s -> EscapeCode s
styleEscapeCurrent Style s
style Progress s
progress
, if Int64
remaining forall a. Eq a => a -> a -> Bool
/= Int64
0 Bool -> Bool -> Bool
&& Int64
completed forall a. Eq a => a -> a -> Bool
/= Int64
0
then Char -> Text
TL.singleton forall a b. (a -> b) -> a -> b
$ forall s. Style s -> Char
styleCurrent Style s
style
else Text
""
, forall s. Style s -> EscapeCode s
styleEscapeTodo Style s
style Progress s
progress
, Int64 -> Text -> Text
TL.replicate
(Int64
remaining forall a. Num a => a -> a -> a
- if Int64
completed forall a. Eq a => a -> a -> Bool
/= Int64
0 then Int64
1 else Int64
0)
(Char -> Text
TL.singleton forall a b. (a -> b) -> a -> b
$ forall s. Style s -> Char
styleTodo Style s
style)
, forall s. Style s -> EscapeCode s
styleEscapeClose Style s
style Progress s
progress
, forall s. Style s -> Text
styleClose Style s
style
, forall s. Style s -> EscapeCode s
styleEscapePostfix Style s
style Progress s
progress
, Text
postfixPad
, Text
postfixLabel
]
where
todo :: Int64
todo = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall s. Progress s -> Int
progressTodo Progress s
progress
done :: Int64
done = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall s. Progress s -> Int
progressDone Progress s
progress
width :: Int64
width = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ ProgressBarWidth -> Int
getProgressBarWidth forall a b. (a -> b) -> a -> b
$ forall s. Style s -> ProgressBarWidth
styleWidth Style s
style
fraction :: Ratio Int64
fraction :: Ratio Int64
fraction | Int64
todo forall a. Eq a => a -> a -> Bool
/= Int64
0 = Int64
done forall a. Integral a => a -> a -> Ratio a
% Int64
todo
| Bool
otherwise = Int64
0 forall a. Integral a => a -> a -> Ratio a
% Int64
1
effectiveWidth :: Int64
effectiveWidth = forall a. Ord a => a -> a -> a
max Int64
0 forall a b. (a -> b) -> a -> b
$ Int64
width forall a. Num a => a -> a -> a
- Int64
usedSpace
usedSpace :: Int64
usedSpace = Text -> Int64
TL.length (forall s. Style s -> Text
styleOpen Style s
style)
forall a. Num a => a -> a -> a
+ Text -> Int64
TL.length (forall s. Style s -> Text
styleClose Style s
style)
forall a. Num a => a -> a -> a
+ Text -> Int64
TL.length Text
prefixLabel
forall a. Num a => a -> a -> a
+ Text -> Int64
TL.length Text
postfixLabel
forall a. Num a => a -> a -> a
+ Text -> Int64
TL.length Text
prefixPad
forall a. Num a => a -> a -> a
+ Text -> Int64
TL.length Text
postfixPad
numCompletedChars :: Ratio Int64
numCompletedChars :: Ratio Int64
numCompletedChars = Ratio Int64
fraction forall a. Num a => a -> a -> a
* (Int64
effectiveWidth forall a. Integral a => a -> a -> Ratio a
% Int64
1)
completed, remaining :: Int64
completed :: Int64
completed = forall a. Ord a => a -> a -> a
min Int64
effectiveWidth forall a b. (a -> b) -> a -> b
$ forall a b. (RealFrac a, Integral b) => a -> b
floor Ratio Int64
numCompletedChars
remaining :: Int64
remaining = Int64
effectiveWidth forall a. Num a => a -> a -> a
- Int64
completed
prefixLabel, postfixLabel :: TL.Text
prefixLabel :: Text
prefixLabel = forall s. Label s -> Progress s -> Timing -> Text
runLabel (forall s. Style s -> Label s
stylePrefix Style s
style) Progress s
progress Timing
timing
postfixLabel :: Text
postfixLabel = forall s. Label s -> Progress s -> Timing -> Text
runLabel (forall s. Style s -> Label s
stylePostfix Style s
style) Progress s
progress Timing
timing
prefixPad, postfixPad :: TL.Text
prefixPad :: Text
prefixPad = Text -> Text
pad Text
prefixLabel
postfixPad :: Text
postfixPad = Text -> Text
pad Text
postfixLabel
pad :: TL.Text -> TL.Text
pad :: Text -> Text
pad Text
s | Text -> Bool
TL.null Text
s = Text
TL.empty
| Bool
otherwise = Char -> Text
TL.singleton Char
' '
data ProgressBarWidth
= ConstantWidth !Int
| TerminalWidth !Int
deriving (forall x. Rep ProgressBarWidth x -> ProgressBarWidth
forall x. ProgressBarWidth -> Rep ProgressBarWidth x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ProgressBarWidth x -> ProgressBarWidth
$cfrom :: forall x. ProgressBarWidth -> Rep ProgressBarWidth x
Generic)
instance NFData ProgressBarWidth
getProgressBarWidth :: ProgressBarWidth -> Int
getProgressBarWidth :: ProgressBarWidth -> Int
getProgressBarWidth (ConstantWidth Int
n) = Int
n
getProgressBarWidth (TerminalWidth Int
n) = Int
n
data Style s
= Style
{ forall s. Style s -> Text
styleOpen :: !TL.Text
, forall s. Style s -> Text
styleClose :: !TL.Text
, forall s. Style s -> Char
styleDone :: !Char
, forall s. Style s -> Char
styleCurrent :: !Char
, forall s. Style s -> Char
styleTodo :: !Char
, forall s. Style s -> Label s
stylePrefix :: Label s
, forall s. Style s -> Label s
stylePostfix :: Label s
, forall s. Style s -> ProgressBarWidth
styleWidth :: !ProgressBarWidth
, forall s. Style s -> EscapeCode s
styleEscapeOpen :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapeClose :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapeDone :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapeCurrent :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapeTodo :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapePrefix :: EscapeCode s
, forall s. Style s -> EscapeCode s
styleEscapePostfix :: EscapeCode s
, forall s. Style s -> OnComplete
styleOnComplete :: !OnComplete
} deriving (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall s x. Rep (Style s) x -> Style s
forall s x. Style s -> Rep (Style s) x
$cto :: forall s x. Rep (Style s) x -> Style s
$cfrom :: forall s x. Style s -> Rep (Style s) x
Generic)
instance (NFData s) => NFData (Style s)
type EscapeCode s
= Progress s
-> TL.Text
data OnComplete
= WriteNewline
| Clear
deriving (forall x. Rep OnComplete x -> OnComplete
forall x. OnComplete -> Rep OnComplete x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnComplete x -> OnComplete
$cfrom :: forall x. OnComplete -> Rep OnComplete x
Generic)
instance NFData OnComplete
defStyle :: Style s
defStyle :: forall s. Style s
defStyle =
Style
{ styleOpen :: Text
styleOpen = Text
"["
, styleClose :: Text
styleClose = Text
"]"
, styleDone :: Char
styleDone = Char
'='
, styleCurrent :: Char
styleCurrent = Char
'>'
, styleTodo :: Char
styleTodo = Char
'.'
, stylePrefix :: Label s
stylePrefix = forall a. Monoid a => a
mempty
, stylePostfix :: Label s
stylePostfix = forall s. Label s
percentage
, styleWidth :: ProgressBarWidth
styleWidth = Int -> ProgressBarWidth
TerminalWidth Int
50
, styleEscapeOpen :: EscapeCode s
styleEscapeOpen = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapeClose :: EscapeCode s
styleEscapeClose = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapeDone :: EscapeCode s
styleEscapeDone = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapeCurrent :: EscapeCode s
styleEscapeCurrent = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapeTodo :: EscapeCode s
styleEscapeTodo = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapePrefix :: EscapeCode s
styleEscapePrefix = forall a b. a -> b -> a
const Text
TL.empty
, styleEscapePostfix :: EscapeCode s
styleEscapePostfix = forall a b. a -> b -> a
const Text
TL.empty
, styleOnComplete :: OnComplete
styleOnComplete = OnComplete
WriteNewline
}
newtype Label s = Label{ forall s. Label s -> Progress s -> Timing -> Text
runLabel :: Progress s -> Timing -> TL.Text } deriving (Label s -> ()
forall s. Label s -> ()
forall a. (a -> ()) -> NFData a
rnf :: Label s -> ()
$crnf :: forall s. Label s -> ()
NFData)
instance Semigroup (Label s) where
Label Progress s -> Timing -> Text
f <> :: Label s -> Label s -> Label s
<> Label Progress s -> Timing -> Text
g = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall a b. (a -> b) -> a -> b
$ \Progress s
p Timing
t -> Progress s -> Timing -> Text
f Progress s
p Timing
t forall a. Semigroup a => a -> a -> a
<> Progress s -> Timing -> Text
g Progress s
p Timing
t
instance Monoid (Label s) where
mempty :: Label s
mempty = forall s. Text -> Label s
msg Text
TL.empty
mappend :: Label s -> Label s -> Label s
mappend = forall a. Semigroup a => a -> a -> a
(<>)
instance IsString (Label s) where
fromString :: String -> Label s
fromString = forall s. Text -> Label s
msg forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
TL.pack
data Timing
= Timing
{ Timing -> UTCTime
timingStart :: !UTCTime
, Timing -> UTCTime
timingLastUpdate :: !UTCTime
}
msg :: TL.Text -> Label s
msg :: forall s. Text -> Label s
msg Text
s = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall a b. (a -> b) -> a -> b
$ \Progress s
_ Timing
_ -> Text
s
percentage :: Label s
percentage :: forall s. Label s
percentage = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall {s} {p}. Progress s -> p -> Text
render
where
render :: Progress s -> p -> Text
render Progress s
progress p
_timing
| Int
todo forall a. Eq a => a -> a -> Bool
== Int
0 = Text
"100%"
| Bool
otherwise = Int64 -> Char -> Text -> Text
TL.justifyRight Int64
4 Char
' ' forall a b. (a -> b) -> a -> b
$ Builder -> Text
TLB.toLazyText forall a b. (a -> b) -> a -> b
$
forall a. Integral a => a -> Builder
TLB.decimal (forall a b. (RealFrac a, Integral b) => a -> b
round (Int
done forall a. Integral a => a -> a -> Ratio a
% Int
todo forall a. Num a => a -> a -> a
* Ratio Int
100) :: Int)
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
TLB.singleton Char
'%'
where
done :: Int
done = forall s. Progress s -> Int
progressDone Progress s
progress
todo :: Int
todo = forall s. Progress s -> Int
progressTodo Progress s
progress
exact :: Label s
exact :: forall s. Label s
exact = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall {s} {p}. Progress s -> p -> Text
render
where
render :: Progress s -> p -> Text
render Progress s
progress p
_timing =
Int64 -> Char -> Text -> Text
TL.justifyRight (Text -> Int64
TL.length Text
todoStr) Char
' ' Text
doneStr forall a. Semigroup a => a -> a -> a
<> Text
"/" forall a. Semigroup a => a -> a -> a
<> Text
todoStr
where
todoStr :: Text
todoStr = Builder -> Text
TLB.toLazyText forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Builder
TLB.decimal Int
todo
doneStr :: Text
doneStr = Builder -> Text
TLB.toLazyText forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Builder
TLB.decimal Int
done
done :: Int
done = forall s. Progress s -> Int
progressDone Progress s
progress
todo :: Int
todo = forall s. Progress s -> Int
progressTodo Progress s
progress
elapsedTime
:: (NominalDiffTime -> TL.Text)
-> Label s
elapsedTime :: forall s. (NominalDiffTime -> Text) -> Label s
elapsedTime NominalDiffTime -> Text
formatNDT = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall {p}. p -> Timing -> Text
render
where
render :: p -> Timing -> Text
render p
_progress Timing
timing = NominalDiffTime -> Text
formatNDT NominalDiffTime
dt
where
dt :: NominalDiffTime
dt :: NominalDiffTime
dt = UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime (Timing -> UTCTime
timingLastUpdate Timing
timing) (Timing -> UTCTime
timingStart Timing
timing)
remainingTime
:: (NominalDiffTime -> TL.Text)
-> TL.Text
-> Label s
remainingTime :: forall s. (NominalDiffTime -> Text) -> Text -> Label s
remainingTime NominalDiffTime -> Text
formatNDT Text
altMsg = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall {s}. Progress s -> Timing -> Text
render
where
render :: Progress s -> Timing -> Text
render Progress s
progress Timing
timing
| forall s. Progress s -> Int
progressDone Progress s
progress forall a. Ord a => a -> a -> Bool
<= Int
0 = Text
altMsg
| NominalDiffTime
dt forall a. Ord a => a -> a -> Bool
> NominalDiffTime
1 = NominalDiffTime -> Text
formatNDT NominalDiffTime
estimatedRemainingTime
| Bool
otherwise = Text
altMsg
where
estimatedRemainingTime :: NominalDiffTime
estimatedRemainingTime = NominalDiffTime
estimatedTotalTime forall a. Num a => a -> a -> a
- NominalDiffTime
dt
estimatedTotalTime :: NominalDiffTime
estimatedTotalTime = NominalDiffTime
dt forall a. Num a => a -> a -> a
* forall a. Fractional a => a -> a
recip NominalDiffTime
progressFraction
progressFraction :: NominalDiffTime
progressFraction :: NominalDiffTime
progressFraction
| forall s. Progress s -> Int
progressTodo Progress s
progress forall a. Ord a => a -> a -> Bool
<= Int
0 = NominalDiffTime
1
| Bool
otherwise = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall s. Progress s -> Int
progressDone Progress s
progress)
forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall s. Progress s -> Int
progressTodo Progress s
progress)
dt :: NominalDiffTime
dt :: NominalDiffTime
dt = UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime (Timing -> UTCTime
timingLastUpdate Timing
timing) (Timing -> UTCTime
timingStart Timing
timing)
totalTime
:: (NominalDiffTime -> TL.Text)
-> TL.Text
-> Label s
totalTime :: forall s. (NominalDiffTime -> Text) -> Text -> Label s
totalTime NominalDiffTime -> Text
formatNDT Text
altMsg = forall s. (Progress s -> Timing -> Text) -> Label s
Label forall {s}. Progress s -> Timing -> Text
render
where
render :: Progress s -> Timing -> Text
render Progress s
progress Timing
timing
| NominalDiffTime
dt forall a. Ord a => a -> a -> Bool
> NominalDiffTime
1 = NominalDiffTime -> Text
formatNDT NominalDiffTime
estimatedTotalTime
| forall s. Progress s -> Int
progressDone Progress s
progress forall a. Ord a => a -> a -> Bool
<= Int
0 = Text
altMsg
| Bool
otherwise = Text
altMsg
where
estimatedTotalTime :: NominalDiffTime
estimatedTotalTime = NominalDiffTime
dt forall a. Num a => a -> a -> a
* forall a. Fractional a => a -> a
recip NominalDiffTime
progressFraction
progressFraction :: NominalDiffTime
progressFraction :: NominalDiffTime
progressFraction
| forall s. Progress s -> Int
progressTodo Progress s
progress forall a. Ord a => a -> a -> Bool
<= Int
0 = NominalDiffTime
1
| Bool
otherwise = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall s. Progress s -> Int
progressDone Progress s
progress)
forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall s. Progress s -> Int
progressTodo Progress s
progress)
dt :: NominalDiffTime
dt :: NominalDiffTime
dt = UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime (Timing -> UTCTime
timingLastUpdate Timing
timing) (Timing -> UTCTime
timingStart Timing
timing)
renderDuration :: NominalDiffTime -> TL.Text
renderDuration :: NominalDiffTime -> Text
renderDuration NominalDiffTime
dt = Text
hTxt forall a. Semigroup a => a -> a -> a
<> Text
mTxt forall a. Semigroup a => a -> a -> a
<> Text
sTxt
where
hTxt :: Text
hTxt | Int
h forall a. Eq a => a -> a -> Bool
== Int
0 = forall a. Monoid a => a
mempty
| Bool
otherwise = forall {a}. Integral a => a -> Text
renderDecimal Int
h forall a. Semigroup a => a -> a -> a
<> Text
":"
mTxt :: Text
mTxt | Int
m forall a. Eq a => a -> a -> Bool
== Int
0 = forall a. Monoid a => a
mempty
| Bool
otherwise = forall {a}. Integral a => a -> Text
renderDecimal Int
m forall a. Semigroup a => a -> a -> a
<> Text
":"
sTxt :: Text
sTxt = forall {a}. Integral a => a -> Text
renderDecimal Int
s
(Int
h, Int
hRem) = Int
ts forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
3600
(Int
m, Int
s ) = Int
hRem forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
60
ts :: Int
ts :: Int
ts = forall a b. (RealFrac a, Integral b) => a -> b
round NominalDiffTime
dt
renderDecimal :: a -> Text
renderDecimal a
n = Int64 -> Char -> Text -> Text
TL.justifyRight Int64
2 Char
'0' forall a b. (a -> b) -> a -> b
$ Builder -> Text
TLB.toLazyText forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Builder
TLB.decimal a
n