terminal-progress-bar-0.0.1.3/0000755000000000000000000000000012130237273014256 5ustar0000000000000000terminal-progress-bar-0.0.1.3/README.markdown0000644000000000000000000000000012130237273016745 0ustar0000000000000000terminal-progress-bar-0.0.1.3/LICENSE0000644000000000000000000000274512130237273015273 0ustar0000000000000000Copyright 2012 Roel van Dijk All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of Roel van Dijk and the names of contributors may NOT be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. terminal-progress-bar-0.0.1.3/Setup.hs0000644000000000000000000000005612130237273015713 0ustar0000000000000000import Distribution.Simple main = defaultMain terminal-progress-bar-0.0.1.3/terminal-progress-bar.cabal0000644000000000000000000000474612130237273021474 0ustar0000000000000000name: terminal-progress-bar version: 0.0.1.3 cabal-version: >=1.8 build-type: Simple stability: provisional author: Roel van Dijk maintainer: Roel van Dijk copyright: 2012 Roel van Dijk license: BSD3 license-file: LICENSE category: System, User Interfaces homepage: https://github.com/roelvandijk/terminal-progress-bar bug-reports: https://github.com/roelvandijk/terminal-progress-bar/issues synopsis: A simple progress bar in the terminal description: A progress bar is used to convey the progress of a task. This package implements a very simple textual progress bar. . See the module 'System.ProgressBar' on how to use the progress bar or build the package with the -fexample flag for a small example program. . The animated progress bar depends entirely on the interpretation of the carriage return character (\'\r\'). If your terminal interprets it as something else then "move cursor to beginning of line", the animation won't work. . Note: Due to a bug in \"cabal haddock\" you will have to manually uncomment the example section in the cabal file. But uncommenting that section will result in \"cabal haddock\" failing. extra-source-files: LICENSE, README.markdown source-repository head type: git location: git://github.com/roelvandijk/terminal-progress-bar.git flag example description: Build a small example program. default: False library hs-source-dirs: src build-depends: base >= 3.0.3.1 && < 4.7 , base-unicode-symbols >= 0.2.2.3 && < 0.3 exposed-modules: System.ProgressBar ghc-options: -Wall test-suite test-terminal-progress-bar type: exitcode-stdio-1.0 main-is: test.hs hs-source-dirs: test ghc-options: -Wall build-depends: base >= 3.0.3.1 && < 4.7 , base-unicode-symbols >= 0.2.2.3 && < 0.3 , HUnit >= 1.2.4.2 && < 1.3 , terminal-progress-bar , test-framework >= 0.3.3 && < 0.9 , test-framework-hunit >= 0.2.6 && < 0.4 -- executable example -- main-is: example.hs -- hs-source-dirs: . -- if flag(example) -- build-depends: base >= 3.0.3.1 && < 4.6 -- , base-unicode-symbols >= 0.2.2.3 && < 0.3 -- , terminal-progress-bar == 0.0.1 -- buildable: True -- else -- buildable: False terminal-progress-bar-0.0.1.3/src/0000755000000000000000000000000012130237273015045 5ustar0000000000000000terminal-progress-bar-0.0.1.3/src/System/0000755000000000000000000000000012130237273016331 5ustar0000000000000000terminal-progress-bar-0.0.1.3/src/System/ProgressBar.hs0000644000000000000000000001127112130237273021120 0ustar0000000000000000{-# LANGUAGE NoImplicitPrelude, PackageImports, UnicodeSyntax #-} module System.ProgressBar ( -- * Progress bars progressBar , mkProgressBar -- * Labels , Label , noLabel , msg , percentage , exact ) where import "base" Data.Bool ( otherwise ) import "base" Data.Function ( ($) ) import "base" Data.List ( null, length, genericLength, genericReplicate ) import "base" Data.Ord ( min, max ) import "base" Data.Ratio ( (%) ) import "base" Data.String ( String ) import "base" Prelude ( (+), (-), round, floor ) import "base" System.IO ( IO, putStr, putChar ) import "base" Text.Printf ( printf ) import "base" Text.Show ( show ) import "base-unicode-symbols" Data.Bool.Unicode ( (∧) ) import "base-unicode-symbols" Data.Eq.Unicode ( (≢) ) import "base-unicode-symbols" Prelude.Unicode ( ℤ, ℚ, (⋅) ) -- | Print a progress bar -- -- Erases the current line! (by outputting '\r') Does not print a -- newline '\n'. Subsequent invocations will overwrite the previous -- output. -- -- Remember to set the correct buffering mode for stdout: -- -- > import System.IO ( hSetBuffering, BufferMode(NoBuffering), stdout ) -- > hSetBuffering stdout NoBuffering progressBar ∷ Label -- ^ Prefixed label. → Label -- ^ Postfixed label. → ℤ -- ^ Total progress bar width in characters. → ℤ -- ^ Amount of work completed. → ℤ -- ^ Total amount of work. → IO () progressBar mkPreLabel mkPostLabel width todo done = do putChar '\r' putStr $ mkProgressBar mkPreLabel mkPostLabel width todo done -- | Renders a progress bar -- -- >>> mkProgressBar (msg "Working") percentage 40 30 100 -- "Working [=======>.................] 30%" mkProgressBar ∷ Label -- ^ Prefixed label. → Label -- ^ Postfixed label. → ℤ -- ^ Total progress bar width in characters. → ℤ -- ^ Amount of work completed. → ℤ -- ^ Total amount of work. → String mkProgressBar mkPreLabel mkPostLabel width todo done = printf "%s%s[%s%s%s]%s%s" preLabel prePad (genericReplicate completed '=') (if remaining ≢ 0 ∧ completed ≢ 0 then ">" else "") (genericReplicate (remaining - if completed ≢ 0 then 1 else 0) '.' ) postPad postLabel where -- Amount of work completed. fraction ∷ ℚ fraction | done ≢ 0 = todo % done | otherwise = 0 % 1 -- Amount of characters available to visualize the progress. effectiveWidth = max 0 $ width - usedSpace usedSpace = 2 + genericLength preLabel + genericLength postLabel + genericLength prePad + genericLength postPad -- Number of characters needed to represent the amount of work -- that is completed. Note that this can not always be represented -- by an integer. numCompletedChars ∷ ℚ numCompletedChars = fraction ⋅ (effectiveWidth % 1) completed, remaining ∷ ℤ completed = min effectiveWidth $ floor numCompletedChars remaining = effectiveWidth - completed preLabel, postLabel ∷ String preLabel = mkPreLabel todo done postLabel = mkPostLabel todo done prePad, postPad ∷ String prePad = pad preLabel postPad = pad postLabel pad ∷ String → String pad s | null s = "" | otherwise = " " -- | A label that can be pre- or postfixed to a progress bar. type Label = ℤ → ℤ → String -- | The empty label. -- -- >>> noLabel 30 100 -- "" noLabel ∷ Label noLabel = msg "" -- | A label consisting of a static string. -- -- >>> msg "foo" 30 100 -- "foo" msg ∷ String → Label msg s _ _ = s -- | A label which displays the progress as a percentage. -- -- Constant width property: -- ∀ d t : ℕ. d ≤ t → length (percentage d t) ≡ 4 -- -- >>> percentage 30 100 -- " 30%" -- ∀ d t : ℕ. d ≤ t → length (percentage d t) ≡ 3 percentage ∷ Label percentage done todo = printf "%3i%%" (round (done % todo ⋅ 100) ∷ ℤ) -- | A label which displays the progress as a fraction of the total -- amount of work. -- -- Equal width property: -- ∀ d₁ d₂ t : ℕ. d₁ ≤ d₂ ≤ t → length (exact d₁ t) ≡ length (exact d₂ t) -- -- >>> exact 30 100 -- " 30/100" -- ∀ d₁ d₂ t : ℕ. d₁ ≤ d₂ ≤ t → length (exact d₁ t) ≡ length (exact d₂ t) exact ∷ Label exact done total = printf "%*i/%s" (length totalStr) done totalStr where totalStr = show total terminal-progress-bar-0.0.1.3/test/0000755000000000000000000000000012130237273015235 5ustar0000000000000000terminal-progress-bar-0.0.1.3/test/test.hs0000644000000000000000000000535612130237273016561 0ustar0000000000000000{-# LANGUAGE NoImplicitPrelude, PackageImports, UnicodeSyntax #-} module Main where -------------------------------------------------------------------------------- -- Imports -------------------------------------------------------------------------------- import "base" Control.Monad ( (=<<) ) import "base" Data.Function ( ($) ) import "base" Prelude ( String ) import "base" System.Environment ( getArgs ) import "base" System.IO ( IO ) import "base-unicode-symbols" Prelude.Unicode ( ℤ ) import "HUnit" Test.HUnit.Base ( assertEqual ) import "test-framework" Test.Framework ( defaultMainWithOpts, interpretArgsOrExit, Test, testGroup ) import "test-framework-hunit" Test.Framework.Providers.HUnit ( testCase ) import "terminal-progress-bar" System.ProgressBar ( mkProgressBar, Label, noLabel, msg, percentage, exact ) -------------------------------------------------------------------------------- -- Test suite -------------------------------------------------------------------------------- main ∷ IO () main = do opts ← interpretArgsOrExit =<< getArgs defaultMainWithOpts tests opts tests ∷ [Test] tests = [ testGroup "Label padding" [ eqTest "no labels" "[]" noLabel noLabel 0 0 0 , eqTest "pre" "pre []" (msg "pre") noLabel 0 0 0 , eqTest "post" "[] post" noLabel (msg "post") 0 0 0 , eqTest "pre & post" "pre [] post" (msg "pre") (msg "post") 0 0 0 ] , testGroup "Bar fill" [ eqTest "empty" "[....]" noLabel noLabel 6 0 1 , eqTest "almost half" "[=>..]" noLabel noLabel 6 49 100 , eqTest "half" "[==>.]" noLabel noLabel 6 1 2 , eqTest "almost full" "[===>]" noLabel noLabel 6 99 100 , eqTest "full" "[====]" noLabel noLabel 6 1 1 , eqTest "overfull" "[====]" noLabel noLabel 6 2 1 ] , testGroup "Labels" [ testGroup "Percentage" [ eqTest " 0%" " 0% [....]" percentage noLabel 11 0 1 , eqTest "100%" "100% [====]" percentage noLabel 11 1 1 , eqTest " 50%" " 50% [==>.]" percentage noLabel 11 1 2 , eqTest "200%" "200% [====]" percentage noLabel 11 2 1 ] , testGroup "Exact" [ eqTest "0/0" "0/0 [....]" exact noLabel 10 0 0 , eqTest "1/1" "1/1 [====]" exact noLabel 10 1 1 , eqTest "1/2" "1/2 [==>.]" exact noLabel 10 1 2 , eqTest "2/1" "2/1 [====]" exact noLabel 10 2 1 ] ] ] eqTest ∷ String → String → Label → Label → ℤ → ℤ → ℤ → Test eqTest name expected mkPreLabel mkPostLabel width todo done = testCase name $ assertEqual errMsg expected actual where actual = mkProgressBar mkPreLabel mkPostLabel width todo done errMsg = "Expected result doesn't match actual result"