有一个程序通过重复覆盖stderr
中的最后一行文本来与用户交互。其做法如下:
- 有一个状态单子(monad)会记住最后打印的一行的长度。
当它想用另一行
s'
覆盖一行s
时,它会用空格填充s'
,直到它被覆盖。至少与s
一样长,并在其前面添加“回车符” 字符:n <- gets lastLineLength let s'Padded | 0 < n = '\r': s' ++ replicate (n - length s') ' ' | otherwise = s' hPutStr stderr s'Padded
这工作得很好。 (尽管我个人没有在通常的 Linux 终端以外的环境中测试过它。)
我开始改进这个程序,用 ansi-wl-pprint
中的 Doc
类型替换普通的 String
。这样我就可以用颜色来绘制文本,就像最近的 GHC 运动一样。像这样的库可能有点矫枉过正,因为我只需要一次输出几行,并且没有任何缩进,但我想尝试一下它的抽象着色功能。但是,我不认为这个库(或任何 pretty-print 库)会具有旨在删除以前打印的文档的功能。
我想到的一个解决方案是将Doc
渲染为String
并测量其长度。但是,我将不得不对颜色代码打折扣;此外,这总体上是对库提供的抽象的侵入:具体来说,我必须依赖这样的假设:我手动执行的渲染将与 hPutDoc
隐式完成的渲染相匹配。
我是否应该完全放弃该库并继续处理String
,手动添加 ANSI 转义序列和回车符?有没有更好的方法来覆盖以前的输出?我欢迎任何建议。
最佳答案
ansi-wl-pprint
依赖于 ansi-terminal
,它有 clearLine
方法和其他实用程序来移动并记录控制台中的位置。
在底层,clearLine
发送特定的ANSI 控制序列来删除当前行。还有一个控制序列可将光标倒回到当前行(或任何行)的开头。这有点晦涩难懂,但你会惊讶地看到 how many control sequences有。
您可以手动操纵控制序列。例如,如果您putStr“\ESC[2K\ESC[0G”
,它应该删除当前行,然后将光标置于其开头 - 类似于您的代码正在执行的操作,但是清洁工。但如果您依赖 ansi-terminal
并使用其中定义的操作 hClearLine
和 hSetCursorColumn
,它可能会为您提供最好的服务。如果您已经通过 ansi-wl-pprint
间接依赖于 ansi-terminal
,则不应产生额外的构建时间成本。
关于haskell - 如果我想使用 pretty-print 库来添加颜色,如何将终端中的最后一行输出设为 "refresh"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48975919/