module System.Console.AsciiProgress
( ProgressBar(..)
, Options(..)
, Stats(..)
, isComplete
, newProgressBar
, complete
, tick
, tickN
, tickNI
, getProgressStrIO
, getProgressStats
, getProgressStr
, Default(..)
, module System.Console.Regions
)
where
import Control.Applicative ((<$>))
import Control.Concurrent (modifyMVar_, readChan,
readMVar, writeChan)
import Control.Concurrent.Async (Async (..), async, poll,
wait)
import Data.Default (Default (..))
import Data.Maybe (fromMaybe, isJust)
import System.Console.AsciiProgress.Internal
import System.Console.Regions
data ProgressBar = ProgressBar { pgInfo :: ProgressBarInfo
, pgFuture :: Async ()
, pgRegion :: ConsoleRegion
}
newProgressBar :: Options -> IO ProgressBar
newProgressBar opts = do
region <- openConsoleRegion Linear
info <- newProgressBarInfo opts
pgStr <- pgGetProgressStr opts opts <$> getInfoStats info
setConsoleRegion region pgStr
future <- async $ start info region
return $ ProgressBar info future region
where
start info@ProgressBarInfo{..} region = do
c <- readMVar pgCompleted
unlessDone c $ do
n <- readChan pgChannel
_ <- handleMessage info region n
unlessDone (c + n) $ start info region
where
unlessDone c action | c < pgTotal opts = action
unlessDone _ _ = do
let fmt = fromMaybe (pgFormat opts) (pgOnCompletion opts)
onCompletion <- pgGetProgressStr opts opts { pgFormat = fmt } <$> getInfoStats info
setConsoleRegion region onCompletion
handleMessage info region n = do
modifyMVar_ (pgCompleted info) (\c -> return (c + n))
stats <- getInfoStats info
let progressStr = pgGetProgressStr opts opts stats
setConsoleRegion region progressStr
tick :: ProgressBar -> IO ()
tick pg = tickN pg 1
tickN :: ProgressBar -> Int -> IO ()
tickN (ProgressBar info _ _) = writeChan (pgChannel info) . fromIntegral
tickNI :: ProgressBar -> Integer -> IO ()
tickNI (ProgressBar info _ _) = writeChan (pgChannel info)
isComplete :: ProgressBar -> IO Bool
isComplete (ProgressBar _ future _) = isJust <$> poll future
complete :: ProgressBar -> IO ()
complete pg@(ProgressBar info future _) = do
let total = pgTotal (pgOptions info)
tickNI pg total
wait future
getProgressStats :: ProgressBar -> IO Stats
getProgressStats (ProgressBar info _ _) = getInfoStats info
getProgressStrIO :: ProgressBar -> IO String
getProgressStrIO (ProgressBar info _ _) =
getProgressStr (pgOptions info) <$> getInfoStats info