{-# LANGUAGE Safe #-}

{-
Copyright (c) 2006-2011 John Goerzen <jgoerzen@complete.org>

All rights reserved.

For license and copyright information, see the file LICENSE
-}

{- |
   Module     : Data.Progress.Meter
   Copyright  : Copyright (C) 2006-2011 John Goerzen
   SPDX-License-Identifier: BSD-3-Clause

   Stability  : stable
   Portability: portable

Tool for maintaining a status bar, supporting multiple simultaneous tasks,
as a layer atop "Data.Progress.Tracker".

Written by John Goerzen, jgoerzen\@complete.org -}

module Data.Progress.Meter (-- * Types
                               ProgressMeter,
                               -- * Creation and Configuration
                               simpleNewMeter,
                               newMeter,
                               setComponents,
                               addComponent,
                               removeComponent,
                               setWidth,

                               -- * Rendering and Output
                               renderMeter,
                               displayMeter,
                               clearMeter,
                               writeMeterString,
                               autoDisplayMeter,
                               killAutoDisplayMeter
                               ) where

import safe Data.Progress.Tracker
    ( ProgressStatuses(..),
      Progress,
      ProgressStatus(totalUnits, completedUnits, trackerName),
      getSpeed,
      getETR )
import safe Control.Concurrent
    ( modifyMVar_,
      withMVar,
      newMVar,
      MVar,
      threadDelay,
      forkIO,
      myThreadId,
      yield,
      ThreadId )
import Control.Monad (when)
import Data.String.Utils (join)
import System.Time.Utils (renderSecs)
import Data.Quantity (renderNums, binaryOpts)
import safe System.IO ( Handle, hFlush, hPutStr )
import Control.Monad (filterM)

{- | The main data type for the progress meter. -}
data ProgressMeterR =
    ProgressMeterR {ProgressMeterR -> Progress
masterP :: Progress, -- ^ The master 'Progress' object for overall status
                    ProgressMeterR -> [Progress]
components :: [Progress], -- ^ Individual component statuses
                    ProgressMeterR -> Int
width :: Int, -- ^ Width of the meter
                    ProgressMeterR -> [Char]
unit :: String, -- ^ Units of display
                    ProgressMeterR -> [Integer] -> [[Char]]
renderer :: [Integer] -> [String], -- ^ Function to render numbers
                    ProgressMeterR -> [ThreadId]
autoDisplayers :: [ThreadId] -- ^ Auto-updating display
                   }

type ProgressMeter = MVar ProgressMeterR

{- | Set up a new status bar using defaults:

* The given tracker

* Width 80

* Data.Quantity.renderNums binaryOpts 1

* Unit inticator @"B"@

-}
simpleNewMeter :: Progress -> IO ProgressMeter
simpleNewMeter :: Progress -> IO ProgressMeter
simpleNewMeter Progress
pt = Progress
-> [Char] -> Int -> ([Integer] -> [[Char]]) -> IO ProgressMeter
newMeter Progress
pt [Char]
"B" Int
80 (SizeOpts -> Int -> [Integer] -> [[Char]]
forall a. (Ord a, Real a) => SizeOpts -> Int -> [a] -> [[Char]]
renderNums SizeOpts
binaryOpts Int
1)

{- | Set up a new status bar. -}
newMeter :: Progress           -- ^ The top-level 'Progress'
         -> String              -- ^ Unit indicator string
          -> Int                -- ^ Width of the terminal -- usually 80
          -> ([Integer] -> [String])-- ^ A function to render sizes
          -> IO ProgressMeter
newMeter :: Progress
-> [Char] -> Int -> ([Integer] -> [[Char]]) -> IO ProgressMeter
newMeter Progress
tracker [Char]
u Int
w [Integer] -> [[Char]]
rfunc =
    ProgressMeterR -> IO ProgressMeter
forall a. a -> IO (MVar a)
newMVar (ProgressMeterR -> IO ProgressMeter)
-> ProgressMeterR -> IO ProgressMeter
forall a b. (a -> b) -> a -> b
$ ProgressMeterR :: Progress
-> [Progress]
-> Int
-> [Char]
-> ([Integer] -> [[Char]])
-> [ThreadId]
-> ProgressMeterR
ProgressMeterR {masterP :: Progress
masterP = Progress
tracker, components :: [Progress]
components = [],
                         width :: Int
width = Int
w, renderer :: [Integer] -> [[Char]]
renderer = [Integer] -> [[Char]]
rfunc, autoDisplayers :: [ThreadId]
autoDisplayers = [],
                         unit :: [Char]
unit = [Char]
u}

{- | Adjust the list of components of this 'ProgressMeter'. -}
setComponents :: ProgressMeter -> [Progress] -> IO ()
setComponents :: ProgressMeter -> [Progress] -> IO ()
setComponents ProgressMeter
meter [Progress]
componentlist = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = [Progress]
componentlist})

{- | Add a new component to the list of components. -}
addComponent :: ProgressMeter -> Progress -> IO ()
addComponent :: ProgressMeter -> Progress -> IO ()
addComponent ProgressMeter
meter Progress
component =
    ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = Progress
component Progress -> [Progress] -> [Progress]
forall a. a -> [a] -> [a]
: ProgressMeterR -> [Progress]
components ProgressMeterR
m})

{- | Remove a component by name. -}
removeComponent :: ProgressMeter -> String -> IO ()
removeComponent :: ProgressMeter -> [Char] -> IO ()
removeComponent ProgressMeter
meter [Char]
componentname = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter ((ProgressMeterR -> IO ProgressMeterR) -> IO ())
-> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
m ->
   do [Progress]
newc <- (Progress -> IO Bool) -> [Progress] -> IO [Progress]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (\Progress
x -> Progress -> (ProgressStatus -> IO Bool) -> IO Bool
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus Progress
x (\ProgressStatus
y -> Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ ProgressStatus -> [Char]
trackerName ProgressStatus
y [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char]
componentname))
              (ProgressMeterR -> [Progress]
components ProgressMeterR
m)
      ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = [Progress]
newc}

{- | Adjusts the width of this 'ProgressMeter'. -}
setWidth :: ProgressMeter -> Int -> IO ()
setWidth :: ProgressMeter -> Int -> IO ()
setWidth ProgressMeter
meter Int
w = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {width :: Int
width = Int
w})

{- | Like renderMeter, but prints it to the screen instead of returning it.

This function will output CR, then the meter.

Pass stdout as the handle for regular display to the screen. -}
displayMeter :: Handle -> ProgressMeter -> IO ()
displayMeter :: Handle -> ProgressMeter -> IO ()
displayMeter Handle
h ProgressMeter
r = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
r ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
meter ->
    do [Char]
s <- ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter
       Handle -> [Char] -> IO ()
hPutStr Handle
h ([Char]
"\r" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
s)
       Handle -> IO ()
hFlush Handle
h
       -- By placing this whole thing under withMVar, we can effectively
       -- lock the IO and prevent IO from stomping on each other.

{- | Clears the meter -- outputs CR, spaces equal to the width - 1,
then another CR.

Pass stdout as the handle for regular display to the screen. -}
clearMeter :: Handle -> ProgressMeter -> IO ()
clearMeter :: Handle -> ProgressMeter -> IO ()
clearMeter Handle
h ProgressMeter
pm = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
m ->
                     do Handle -> [Char] -> IO ()
hPutStr Handle
h (ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
m)
                        Handle -> IO ()
hFlush Handle
h

{- | Clears the meter, writes the given string, then restores the meter.
The string is assumed to contain a trailing newline.

Pass stdout as the handle for regular display to the screen. -}
writeMeterString :: Handle -> ProgressMeter -> String -> IO ()
writeMeterString :: Handle -> ProgressMeter -> [Char] -> IO ()
writeMeterString Handle
h ProgressMeter
pm [Char]
msg = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
meter ->
                            do [Char]
s <- ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter
                               Handle -> [Char] -> IO ()
hPutStr Handle
h (ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
meter)
                               Handle -> [Char] -> IO ()
hPutStr Handle
h [Char]
msg
                               Handle -> [Char] -> IO ()
hPutStr Handle
h [Char]
s
                               Handle -> IO ()
hFlush Handle
h

clearmeterstr :: ProgressMeterR -> String
clearmeterstr :: ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
m = [Char]
"\r" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate (ProgressMeterR -> Int
width ProgressMeterR
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Char
' ' [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\r"

{- | Starts a thread that updates the meter every n seconds by calling
the specified function.  Note: @displayMeter stdout@
is an ideal function here.

Save this threadID and use it later to call 'stopAutoDisplayMeter'.
-}
autoDisplayMeter :: ProgressMeter -- ^ The meter to display
                 -> Int         -- ^ Update interval in seconds
                 -> (ProgressMeter -> IO ()) -- ^ Function to display it
                 -> IO ThreadId -- ^ Resulting thread id
autoDisplayMeter :: ProgressMeter -> Int -> (ProgressMeter -> IO ()) -> IO ThreadId
autoDisplayMeter ProgressMeter
pm Int
delay ProgressMeter -> IO ()
displayfunc =
    do ThreadId
thread <- IO () -> IO ThreadId
forkIO IO ()
workerthread
       ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
pm (\ProgressMeterR
p -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
p {autoDisplayers :: [ThreadId]
autoDisplayers = ThreadId
thread ThreadId -> [ThreadId] -> [ThreadId]
forall a. a -> [a] -> [a]
: ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p})
       ThreadId -> IO ThreadId
forall (m :: * -> *) a. Monad m => a -> m a
return ThreadId
thread
    where workerthread :: IO ()
workerthread = do ThreadId
tid <- IO ThreadId
myThreadId
                            -- Help fix a race condition so that the above
                            -- modifyMVar can run before a check ever does
                            IO ()
yield
                            ThreadId -> IO ()
loop ThreadId
tid
          loop :: ThreadId -> IO ()
loop ThreadId
tid = do ProgressMeter -> IO ()
displayfunc ProgressMeter
pm
                        Int -> IO ()
threadDelay (Int
delay Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000)
                        Bool
c <- ThreadId -> IO Bool
doIContinue ThreadId
tid
                        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
c (ThreadId -> IO ()
loop ThreadId
tid)
          doIContinue :: ThreadId -> IO Bool
doIContinue ThreadId
tid = ProgressMeter -> (ProgressMeterR -> IO Bool) -> IO Bool
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO Bool) -> IO Bool)
-> (ProgressMeterR -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
p ->
                               if ThreadId
tid ThreadId -> [ThreadId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p
                                  then Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                                  else Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

{- | Stops the specified meter from displaying.

You should probably call 'clearMeter' after a call to this. -}
killAutoDisplayMeter :: ProgressMeter -> ThreadId -> IO ()
killAutoDisplayMeter :: ProgressMeter -> ThreadId -> IO ()
killAutoDisplayMeter ProgressMeter
pm ThreadId
t =
    ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
pm (\ProgressMeterR
p -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
p {autoDisplayers :: [ThreadId]
autoDisplayers = (ThreadId -> Bool) -> [ThreadId] -> [ThreadId]
forall a. (a -> Bool) -> [a] -> [a]
filter (ThreadId -> ThreadId -> Bool
forall a. Eq a => a -> a -> Bool
/= ThreadId
t) (ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p)})

{- | Render the current status. -}
renderMeter :: ProgressMeter -> IO String
renderMeter :: ProgressMeter -> IO [Char]
renderMeter ProgressMeter
r = ProgressMeter -> (ProgressMeterR -> IO [Char]) -> IO [Char]
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
r ((ProgressMeterR -> IO [Char]) -> IO [Char])
-> (ProgressMeterR -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> IO [Char]
renderMeterR

renderMeterR :: ProgressMeterR -> IO String
renderMeterR :: ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter =
    do [Char]
overallpct <- Progress -> IO [Char]
forall {a} {m :: * -> *}.
(ProgressStatuses a (m [Char]), Monad m) =>
a -> m [Char]
renderpct (Progress -> IO [Char]) -> Progress -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> Progress
masterP ProgressMeterR
meter
       [[Char]]
compnnts <- (Progress -> IO [Char]) -> [Progress] -> IO [[Char]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (([Integer] -> [[Char]]) -> Progress -> IO [Char]
rendercomponent (([Integer] -> [[Char]]) -> Progress -> IO [Char])
-> ([Integer] -> [[Char]]) -> Progress -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> [Integer] -> [[Char]]
renderer ProgressMeterR
meter)
                     (ProgressMeterR -> [Progress]
components ProgressMeterR
meter)
       let componentstr :: [Char]
componentstr = case [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
join [Char]
" " [[Char]]
compnnts of
                            [] -> [Char]
""
                            [Char]
x -> [Char]
x [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" "
       [Char]
rightpart <- ([Integer] -> [[Char]]) -> Progress -> IO [Char]
forall a.
ProgressStatuses a (IO [Char]) =>
([Integer] -> [[Char]]) -> a -> IO [Char]
renderoverall (ProgressMeterR -> [Integer] -> [[Char]]
renderer ProgressMeterR
meter) (ProgressMeterR -> Progress
masterP ProgressMeterR
meter)
       let leftpart :: [Char]
leftpart = [Char]
overallpct [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
componentstr
       let padwidth :: Int
padwidth = (ProgressMeterR -> Int
width ProgressMeterR
meter) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ([Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
leftpart) Int -> Int -> Int
forall a. Num a => a -> a -> a
- ([Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
rightpart)
       if Int
padwidth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1
          then [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
take (ProgressMeterR -> Int
width ProgressMeterR
meter Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
leftpart [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
rightpart
          else [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
leftpart [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate Int
padwidth Char
' ' [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
rightpart

    where
      u :: [Char]
u = ProgressMeterR -> [Char]
unit ProgressMeterR
meter
      renderpct :: a -> m [Char]
renderpct a
pt =
              a -> (ProgressStatus -> m [Char]) -> m [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
pt ProgressStatus -> m [Char]
forall {m :: * -> *}. Monad m => ProgressStatus -> m [Char]
renderpctpts
      renderpctpts :: ProgressStatus -> m [Char]
renderpctpts ProgressStatus
pts =
                  if (ProgressStatus -> Integer
totalUnits ProgressStatus
pts Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0)
                     then [Char] -> m [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"0%"
                     else [Char] -> m [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ Integer -> [Char]
forall a. Show a => a -> [Char]
show (((ProgressStatus -> Integer
completedUnits ProgressStatus
pts) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
100) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` (ProgressStatus -> Integer
totalUnits ProgressStatus
pts)) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"%"
      rendercomponent :: ([Integer] -> [String]) -> Progress -> IO String
      rendercomponent :: ([Integer] -> [[Char]]) -> Progress -> IO [Char]
rendercomponent [Integer] -> [[Char]]
rfunc Progress
pt = Progress -> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus Progress
pt ((ProgressStatus -> IO [Char]) -> IO [Char])
-> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ \ProgressStatus
pts ->
              do [Char]
pct <- ProgressStatus -> IO [Char]
forall {m :: * -> *}. Monad m => ProgressStatus -> m [Char]
renderpctpts ProgressStatus
pts
                 let renders :: [[Char]]
renders = [Integer] -> [[Char]]
rfunc [ProgressStatus -> Integer
totalUnits ProgressStatus
pts, ProgressStatus -> Integer
completedUnits ProgressStatus
pts]
                 [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
"[" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ProgressStatus -> [Char]
trackerName ProgressStatus
pts [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                     ([[Char]]
renders [[Char]] -> Int -> [Char]
forall a. [a] -> Int -> a
!! Int
1) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                     [[Char]] -> [Char]
forall a. [a] -> a
head [[Char]]
renders [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
pct [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"]"

      renderoverall :: (ProgressStatuses a (IO [Char])) => ([Integer] -> [[Char]]) -> a -> IO [Char]
      renderoverall :: forall a.
ProgressStatuses a (IO [Char]) =>
([Integer] -> [[Char]]) -> a -> IO [Char]
renderoverall [Integer] -> [[Char]]
rfunc a
pt = a -> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
pt ((ProgressStatus -> IO [Char]) -> IO [Char])
-> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ \ProgressStatus
pts ->
                                         do Integer
etr <- ProgressStatus -> IO Integer
forall a.
(ProgressStatuses a (IO Integer),
 ProgressStatuses a (IO Rational)) =>
a -> IO Integer
getETR ProgressStatus
pts
                                            Double
speed <- ProgressStatus -> IO Double
forall a b. (ProgressStatuses a (IO b), Fractional b) => a -> IO b
getSpeed ProgressStatus
pts
                                            [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
forall a. [a] -> a
head ([Integer] -> [[Char]]
rfunc [Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double
speed :: Double)]) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                                                       [Char]
"/s " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Integer -> [Char]
renderSecs Integer
etr