{-# LANGUAGE OverloadedStrings #-} -- | Facilities for generating and otherwise handling text-based progress bars. module Futhark.Util.ProgressBar ( progressBar, ProgressBar (..), progressSpinner, ) where import qualified Data.Text as T -- | Information about a progress bar to render. The "progress space" -- spans from 0 and up to the `progressBarBound`, but can be -- visualised in any number of steps. data ProgressBar = ProgressBar { -- | Number of steps in the visualisation. progressBarSteps :: Int, -- | The logical upper bound. progressBarBound :: Double, -- | The current position in the progress bar, relative to the -- upper bound. progressBarElapsed :: Double } -- | Render the progress bar. progressBar :: ProgressBar -> T.Text progressBar (ProgressBar steps bound elapsed) = "|" <> T.pack (map cell [1 .. steps]) <> "| " where step_size :: Double step_size = bound / fromIntegral steps chars = " ▏▎▍▍▌▋▊▉█" num_chars = T.length chars char i | i >= 0 && i < num_chars = T.index chars i | otherwise = ' ' cell :: Int -> Char cell i | i' * step_size <= elapsed = char 9 | otherwise = char (floor (((elapsed - (i' - 1) * step_size) * fromIntegral num_chars) / step_size)) where i' = fromIntegral i -- | Render a spinner - a kind of progress bar where there is no upper -- bound because we don't know how long it'll take. You certainly -- know these from THE INTERNET. The non-negative integer is how many -- "steps" have been taken. The spinner looks best if this is -- incremented by one for every call. progressSpinner :: Int -> T.Text progressSpinner spin_idx = T.singleton $ T.index spin_load (spin_idx `rem` n) where spin_load = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" n = T.length spin_load