Ответ 1
Самый простой способ - сделать то, что делают wget и другие программы: распечатать возврат каретки и код стирания ANSI перед информацией о ходе работы, возвращая курсор к началу строки и заменяя существующий текст. Например:
import Control.Monad
import Control.Concurrent
import System.IO
import Text.Printf
putProgress :: String -> IO ()
putProgress s = hPutStr stderr $ "\r\ESC[K" ++ s
drawProgressBar :: Int -> Rational -> String
drawProgressBar width progress =
"[" ++ replicate bars '=' ++ replicate spaces ' ' ++ "]"
where bars = round (progress * fromIntegral width)
spaces = width - bars
drawPercentage :: Rational -> String
drawPercentage progress = printf "%3d%%" (truncate (progress * 100) :: Int)
main :: IO ()
main = do
forM_ [0..10] $ \i -> do
let progress = fromIntegral i / 10
putProgress $ drawProgressBar 40 progress ++ " " ++ drawPercentage progress
threadDelay 250000
putProgress "All done."
hPutChar stderr '\n'
Ключевая вещь здесь заключается в том, чтобы не печатать новую строку, чтобы вы могли вернуться к началу строки в следующем обновлении прогресса.
Конечно, вы можете просто распечатать процент здесь и отбросить панель, но панель более крутая:)