packages feed

ascii-progress 0.2.0.0 → 0.2.1.0

raw patch · 4 files changed

+108/−33 lines, 4 filesdep +QuickChecknew-component:exe:multi-examplePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: QuickCheck

API changes (from Hackage documentation)

- System.Console.AsciiProgress.Internal: instance Eq Options
- System.Console.AsciiProgress.Internal: instance Eq ProgressBarInfo
- System.Console.AsciiProgress.Internal: instance Ord Options
- System.Console.AsciiProgress.Internal: instance Show Options
+ System.Console.AsciiProgress: pgFuture :: ProgressBar -> Async ()
+ System.Console.AsciiProgress: pgInfo :: ProgressBar -> ProgressBarInfo
+ System.Console.AsciiProgress: pgOnCompletion :: Options -> IO ()
+ System.Console.AsciiProgress: registerLn :: IO ()
+ System.Console.AsciiProgress.Internal: pgOnCompletion :: Options -> IO ()
- System.Console.AsciiProgress: Options :: String -> Char -> Char -> Int -> Int -> Options
+ System.Console.AsciiProgress: Options :: String -> Char -> Char -> Int -> Int -> IO () -> Options
- System.Console.AsciiProgress: ProgressBar :: ProgressBarInfo -> (Async ()) -> ProgressBar
+ System.Console.AsciiProgress: ProgressBar :: ProgressBarInfo -> Async () -> ProgressBar
- System.Console.AsciiProgress.Internal: Options :: String -> Char -> Char -> Int -> Int -> Options
+ System.Console.AsciiProgress.Internal: Options :: String -> Char -> Char -> Int -> Int -> IO () -> Options

Files

ascii-progress.cabal view
@@ -1,5 +1,5 @@ name:                ascii-progress-version:             0.2.0.0+version:             0.2.1.0 synopsis:            A simple progress bar for the console. description:     A simple Haskell progress bar for the console. Heavily borrows from TJ@@ -69,6 +69,21 @@    buildable: False   default-language:    Haskell2010 +executable multi-example+  main-is:             MultiExample.hs+  build-depends:       ansi-terminal+                     , async >= 2.0.1.5+                     , base >=4.7 && <4.8+                     , data-default >= 0.5.3+                     , time >= 1.4.2+  hs-source-dirs:      lib+                     , bin+  if flag(examples)+   buildable: True+  else+   buildable: False+  default-language:    Haskell2010+ test-suite hspec   type:                exitcode-stdio-1.0   main-is: Spec.hs@@ -78,6 +93,7 @@                      , data-default >= 0.5.3                      , hspec >=2.1 && <3                      , time >= 1.4.2+                     , QuickCheck >= 2.6   hs-source-dirs:      lib                      , test   default-language:    Haskell2010
+ bin/MultiExample.hs view
@@ -0,0 +1,33 @@+import Control.Concurrent (forkIO, threadDelay)+import Control.Concurrent.Async (wait)+import Control.Monad (unless)+import System.Console.AsciiProgress (ProgressBar(..), Options(..), isComplete,+                                     def, newProgressBar, tick)++main :: IO ()+main = do+    pg1 <- newProgressBar def { pgWidth = 100+                              , pgOnCompletion = putStr "pg 1 is Done!"+                              }+    _ <- forkIO $ loop pg1 (100 * 1000)++    pg2 <- newProgressBar def { pgWidth = 100+                              , pgOnCompletion = putStr "pg 2 is Done!"+                              }+    _ <- forkIO $ loop pg2 (400 * 1000)++    pg3 <- newProgressBar def { pgWidth = 100+                              , pgOnCompletion = putStr "pg 3 is Done!"+                              }+    _ <- forkIO $ loop pg3 (200 * 1000)++    wait $ pgFuture pg1+    wait $ pgFuture pg2+    wait $ pgFuture pg3+  where+    loop pg ts = do+        b <- isComplete pg+        unless b $ do+            threadDelay ts+            tick pg+            loop pg ts
lib/System/Console/AsciiProgress.hs view
@@ -11,53 +11,78 @@     , getProgressStrIO     , getProgressStats     , getProgressStr+    , registerLn     -- Re-exports:     , Default(..)     )   where  import Control.Applicative ((<$>))-import Control.Concurrent (readChan, readMVar, writeChan, modifyMVar_)+import Control.Concurrent -- (readChan, readMVar, writeChan, modifyMVar_) import Control.Concurrent.Async (Async, async, poll, wait) import Data.Default (Default(..)) import Data.Maybe (isJust)-import System.Console.ANSI (clearLine, setCursorColumn)+import System.Console.ANSI -- (clearLine, setCursorColumn) import System.IO (BufferMode(..), hSetBuffering, stdout)+import System.IO.Unsafe (unsafePerformIO)  import System.Console.AsciiProgress.Internal -data ProgressBar = ProgressBar ProgressBarInfo (Async ())+data ProgressBar = ProgressBar { pgInfo :: ProgressBarInfo+                               , pgFuture :: Async ()+                               } +nlines :: MVar Int+nlines = unsafePerformIO (newMVar 0)++writeLock :: MVar ()+writeLock = unsafePerformIO (newMVar ())+ -- |--- Creates a new progress bar with the given @Options@+-- Registers a new line for multiple progress bars+registerLn :: IO ()+registerLn = modifyMVar_ nlines (\n -> return $ n + 1)++-- |+-- Creates a new progress bar with the given @Options@. Multiple progress bars+-- may be created as long as everytime a line is outputted by your program,+-- while progress bars run is followed by a call to `registerLn` newProgressBar :: Options -> IO ProgressBar newProgressBar opts = do     hSetBuffering stdout NoBuffering     info <- newProgressBarInfo opts-    future <- async $ start info+    cnlines <- modifyMVar nlines $ \nl -> return (nl + 1, nl)+    putStrLn ""+    future <- async $ start info cnlines     return $ ProgressBar info future   where-    start info@ProgressBarInfo{..} = do-        c <- readMVar pgCompleted-        if c < pgTotal opts-            then do-                n <- readChan pgChannel-                handleMessage n-                if c + n < pgTotal opts-                    then start info-                    else reset-            else reset-      where-        reset = do-            clearLine-            setCursorColumn 0-        handleMessage n = do-            -- Update the completed tick count-            modifyMVar_ pgCompleted (\c -> return (c + n))-            -- Find and update the current and first tick times:-            stats <- getInfoStats info-            reset-            let progressStr = getProgressStr opts stats+    resetCursor = clearLine >> setCursorColumn 0+    unlessDone _ c action | c < pgTotal opts = action+    unlessDone cnlines _ _ = atProgressLine cnlines (pgOnCompletion opts)++    atProgressLine cnlines action = do+        diff <- (\nl -> nl - cnlines) <$> readMVar nlines+        cursorUp diff+        resetCursor+        action+        cursorDown diff+        resetCursor++    start info@ProgressBarInfo{..} cnlines = do+       c <- readMVar pgCompleted+       unlessDone cnlines c $ do+           n <- readChan pgChannel+           handleMessage info cnlines n+           unlessDone cnlines (c + n) $+               start info cnlines++    handleMessage info cnlines n = modifyMVar_ writeLock $ const $ do+        -- Update the completed tick count+        modifyMVar_ (pgCompleted info) (\c -> return (c + n))+        -- Find and update the current and first tick times:+        stats <- getInfoStats info+        let progressStr = getProgressStr opts stats+        atProgressLine cnlines $             putStr progressStr  -- |
lib/System/Console/AsciiProgress/Internal.hs view
@@ -29,8 +29,10 @@                        -- ^ Total amount of ticks expected                        , pgWidth :: Int                        -- ^ The progress bar's width+                       , pgOnCompletion :: IO ()+                       -- ^ An IO action to be executed on completion, with the+                       -- cursor set at progress bar's line                        }-  deriving(Eq, Ord, Show)  instance Default Options where     def = Options { pgFormat = "Working :percent [:bar] :current/:total " ++@@ -39,6 +41,7 @@                   , pgPendingChar = ' '                   , pgTotal = 20                   , pgWidth = 80+                  , pgOnCompletion = return ()                   }  -- |@@ -49,7 +52,6 @@                                        , pgCompleted :: MVar Int                                        , pgFirstTick :: MVar UTCTime                                        }-  deriving(Eq)  -- | -- Represents a point in time for the progress bar.@@ -77,11 +79,11 @@ getProgressStr Options{..} Stats{..} = replace ":bar" barStr statsStr   where     statsStr = replaceMany-        [ (":elapsed", printf "%3.1f" stElapsed)+        [ (":elapsed", printf "%5.1f" stElapsed)         , (":current", printf "%3d"   stCompleted)         , (":total"  , printf "%3d"   stTotal)         , (":percent", printf "%3d%%" (floor (100 * stPercent) :: Int))-        , (":eta"    , printf "%3.1f" stEta)+        , (":eta"    , printf "%5.1f" stEta)         ]         pgFormat     barWidth = pgWidth - length (replace ":bar" "" statsStr)@@ -110,10 +112,9 @@ getBar completedChar pendingChar width percent =     replicate bcompleted completedChar ++ replicate bremaining pendingChar   where-    percentRemaining = 1 - percent     fwidth = fromIntegral width     bcompleted = ceiling $ fwidth * percent-    bremaining = floor   $ fwidth * percentRemaining+    bremaining = width - bcompleted  -- | -- Gets the amount of seconds elapsed between two @UTCTime@s as a double.