HORIZON HASKELLDocslts/ghc-9.14.xd82dee82026-10-12Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · d82dee8 · 2026-10-12

Moduleterminal-progress-bar-0.4.2Haskell2010

System.ProgressBar

A progress bar in the terminal.

A progress bar conveys the progress of a task. Use a progress bar to provide a visual cue that processing is underway.

  • 8 types
  • 13 values

Getting started

0 declarations

You want to perform some task which will take some time. You wish to show the progress of this task in the terminal.

  1. Determine the total amount of work

  2. Create a progress bar with newProgressBar

  3. For each unit of work:

    3a. Perform the work

    3b. Update the progress bar with incProgress

Explore the Style and the Label types to see various ways in which you can customize the progress bar.

You do not have to close the progress bar, or even finish the task. It is perfectly fine to stop half way (maybe your task throws an exception).

Just remember to avoid outputting text to the terminal while a progress bar is active. It will mess up the output a bit.

Example

0 declarations

Write a function which represents a unit of work. This could be a file copy operation, a network operation or some other expensive calculation. This example simply waits 1 second.

  work :: IO ()
  work = threadDelay 1000000 -- 1 second

And you define some work to be done. This could be a list of files to process or some jobs that need to be processed.

  toBeDone :: [()]
  toBeDone = replicate 20 ()

Now create the progress bar. Use the default style and choose a maximum refresh rate of 10 Hz. The initial progress is 0 work done out of 20.

  pb <- newProgressBar defStyle 10 (Progress 0 20 ())

Start performing the work while keeping the user informed of the progress:

  for_ toBeDone $ () -> do
    work             -- perform 1 unit of work
    incProgress pb 1 -- increment progress by 1

That's it! You get a nice animated progress bar in your terminal. It will look like this:

[==========>................................]  25%

Progress bars

6 declarations
valuerenderProgressBar
  1. :: Style s
  2. -> Progress s

    Current progress.

  3. -> Timing

    Timing information.

  4. -> Text

    Textual representation of the Progress in the given Style.

#

Renders a progress bar.

Example2 expressions
let t = UTCTime (ModifiedJulianDay 0) 0renderProgressBar defStyle (Progress 30 100 ()) (Timing t t)"[============>..............................]  30%"

Note that this function can not use TerminalWidth because it doesn't use IO. Use newProgressBar or hNewProgressBar to get automatic width.

valueupdateProgress
  1. :: ProgressBar s

    Progress bar to update.

  2. -> (Progress s -> Progress s)

    Function to change the progress.

  3. -> IO ()
#

Change the progress of a progress bar.

This function is thread safe. Multiple threads may update a single progress bar at the same time.

There is a maximum refresh rate. This means that some updates might not be drawn.

valueincProgress
  1. :: ProgressBar s

    Progress bar which needs an update.

  2. -> Int

    Amount by which to increment the progress.

  3. -> IO ()
#

Increment the progress of an existing progress bar.

See updateProgress for more information.

Options

5 declarations
datadata Style s
#

Visual style of a progress bar.

The style determines how a progress bar is rendered to text.

The textual representation of a progress bar follows the following template:

<prefix><open><done><current><todo><close><postfix>

Where <done> and <todo> are repeated as often as necessary.

Consider the following progress bar

"Working [=======>.................]  30%"

This bar can be specified using the following style:

Style
{ styleOpen    = "["
, styleClose   = "]"
, styleDone    = '='
, styleCurrent = '>'
, styleTodo    = '.'
, stylePrefix  = msg "Working"
, stylePostfix = percentage
, styleWidth   = ConstantWidth 40
, styleEscapeOpen    = const empty
, styleEscapeClose   = const empty
, styleEscapeDone    = const empty
, styleEscapeCurrent = const empty
, styleEscapeTodo    = const empty
, styleEscapePrefix  = const empty
, styleEscapePostfix = const empty
, styleOnComplete = WriteNewline
}

Constructors

Instances3Generic, NFData, Rep
typetype EscapeCode s = Progress s -> Text
#

An escape code is a sequence of bytes which the terminal looks for and interprets as commands, not as character codes.

It is vital that the output of this function, when send to the terminal, does not result in characters being drawn.

datadata OnComplete
#

What happens when a progress bar is finished.

Constructors

  • WriteNewline

    Write a new line when the progress bar is finished. The completed progress bar will remain visible.

  • Clear

    Clear the progress bar once it is finished.

Instances3Generic, NFData, Rep
valuedefStyle :: Style s
#

The default style.

This style shows the progress as a percentage. It does not use any escape sequences.

Override some fields of the default instead of specifying all the fields of a Style record.

datadata ProgressBarWidth
#

Width of progress bar in characters.

Constructors

Instances3Generic, NFData, Rep

Progress

1 declaration
datadata Progress s
#

An amount of progress.

Constructors

Labels

9 declarations
newtypenewtype Label s
#

A label is a part of a progress bar that changes based on the progress.

Labels can be at the front (prefix) or at the back (postfix) of a progress bar.

Labels can use both the current amount of progress and the timing information to generate some text.

Constructors

Instances4IsString, Semigroup, Monoid, NFData
  • IsString (Label s)Defined in terminal-progress-bar-0.4.2 · System.ProgressBar

    Every string is a label which ignores its input and just outputs that string.

  • Semigroup (Label s)Defined in terminal-progress-bar-0.4.2 · System.ProgressBar

    Combining labels combines their output.

  • Monoid (Label s)Defined in terminal-progress-bar-0.4.2 · System.ProgressBar

    The mempty label always outputs an empty text.

  • NFData (Label s)Defined in terminal-progress-bar-0.4.2 · System.ProgressBar
valuemsg :: Text -> Label s
#

Static text.

The output does not depend on the input.

Example1 expression
msg "foo" st"foo"
valuepercentage :: Label s
#

Progress as a percentage.

Example1 expression
runLabel $ percentage (Progress 30 100 ()) someTiming" 30%"

Note: if no work is to be done (todo == 0) the percentage will be shown as 100%.

valueexact :: Label s
#

Progress as a fraction of the total amount of work.

Example1 expression
runLabel $ exact (Progress 30 100 ()) someTiming" 30/100"
valueelapsedTime :: (NominalDiffTime -> Text) -> Label s
#

Amount of time that has elapsed.

Time starts when a progress bar is created.

The user must supply a function which actually renders the amount of time that has elapsed. You can use renderDuration or formatTime from time >= 1.9.

valueremainingTime
  1. :: (NominalDiffTime -> Text)
  2. -> Text

    Alternative message when remaining time can't be calculated (yet).

  3. -> Label s
#

Estimated remaining time.

Tells you how much longer some task is expected to take.

This label uses a simple estimation algorithm. It assumes progress is linear. To prevent nonsense results it won't estimate remaining time until at least 1 second of work has been done.

When it refuses to estimate the remaining time it will show an alternative message instead.

The user must supply a function which actually renders the amount of time that has elapsed. Use renderDuration or formatTime from the time >= 1.9 package.

valuetotalTime
  1. :: (NominalDiffTime -> Text)
  2. -> Text

    Alternative message when total time can't be calculated (yet).

  3. -> Label s
#

Estimated total time.

This label uses a simple estimation algorithm. It assumes progress is linear. To prevent nonsense results it won't estimate the total time until at least 1 second of work has been done.

When it refuses to estimate the total time it will show an alternative message instead.

The user must supply a function which actually renders the total amount of time that a task will take. You can use renderDuration or formatTime from the time >= 1.9 package.

Show amount of time.

renderDuration (fromInteger 42)

42

renderDuration (fromInteger $ 5 * 60 + 42)

05:42

renderDuration (fromInteger $ 8 * 60 * 60 + 5 * 60 + 42)

08:05:42

Use the time >= 1.9 package to get a formatTime function which accepts NominalDiffTime.