There is a program that interacts with the user by repeatedly overwriting the last line of text in stderr
. It is done as follows:
- There is a state monad that remembers the length of the last line printed.
When It wants to overwrite a line
s
with another lines'
, It padss'
with spaces until it is at least as long ass
and prepends it with "carriage return" character:n <- gets lastLineLength let s'Padded | 0 < n = '\r': s' ++ replicate (n - length s') ' ' | otherwise = s' hPutStr stderr s'Padded
This works just fine. (Though I personally have not tested it in circumstances other than the usual Linux terminal.)
I set about improving this program by replacing plain String
by a Doc
type from ansi-wl-pprint
so that I may paint the text in colours, in the same fashion as the recent GHC sports. A library such as this one may be overkill, as I only need to output a few lines at once, and without any indentation, but I wanted to give it a try for its abstract colouring facilities. However, I don't think this library (or any pretty printing library for that matter) would feature a function aimed at erasing previously printed Doc
s.
One solution I have in mind is rendering the Doc
to a String
and measuring its length. However, I will have to discount for colour codes; furthermore, this is overall an intrusion into the abstraction the library offers: specifically, I will have to rely on the assumption that the render I do manually will match the render implicitly done by hPutDoc
.
Should I forfeit the library altogether and keep dealing in String
s, manually throwing in ANSI escape sequences and carriage returns? Is there a nicer way to overwrite previous output? I welcome any advice.