如何在终端中使用漂亮打印库添加颜色,同时“刷新”最后一行输出?

6

有一个程序通过重复覆盖stderr中的最后一行文本来与用户进行交互。具体做法如下:

  • There is a state monad that remembers the length of the last line printed.
  • When It wants to overwrite a line s with another line s', It pads s' with spaces until it is at least as long as s 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
    

这个程序完全有效。(虽然我个人只在通常的Linux终端环境下进行了测试。)

我改进了这个程序,通过从ansi-wl-pprint中使用Doc类型替换普通的String,以便我可以像最近版本的GHC一样用颜色来渲染文本。像这样的库可能过于复杂,因为我只需要一次输出几行,而且没有缩进,但是我想尝试一下其抽象着色功能。但是,我不认为这个库(或任何漂亮的打印库)会具有旨在擦除先前打印的Doc的函数。

我心目中的一个解决方案是将Doc呈现为String并测量其长度。但是,我必须排除颜色代码;此外,这总体上是对库提供的抽象的干扰:特别是,我必须依赖于手动完成的渲染与hPutDoc隐式完成的渲染相匹配的假设。

我应该完全放弃库并继续使用String,手动添加ANSI转义序列和回车吗?是否有更好的方式来覆盖先前的输出?我欢迎任何建议。

1个回答

7

ansi-wl-pprint 依赖于 ansi-terminal,后者具有 clearLine 方法和其他在控制台中移动和记录位置的实用程序。

在幕后,clearLine 发送一个特定的 ANSI 控制序列 来擦除当前行。还有一个控制序列将光标倒回到当前行(或任何行)。这是一种相对隐晦的技术,但你会惊讶地发现有 多少个控制序列 存在。

你可以手动操纵控制序列。例如,如果你使用putStr "\ESC[2K\ESC[0G" ,它会擦除当前行并将光标放置在开头 - 类似于你的代码所做的,但更简洁。但如果你依赖于ansi-terminal并使用定义在其中的hClearLinehSetCursorColumn操作,那么这可能是最好的选择。如果你已经通过ansi-wl-pprint间接依赖于ansi-terminal,则不应产生额外的构建时间成本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接