我再次询问 StackOverflow 上提出的问题,但没有答案,我事件添加了赏金但没有效果(我刚刚删除了该赏金)。我认为这里的人们可能对正在发生的事情有更好的了解。
我正在为我的 JavaScript 库开发一个更好的 ANSI 转义代码解释器,但在处理命令时遇到问题top
(使用script
将终端输出转储到文件中的命令)。
我有一个来自 MacOS 的示例文件,它使用替代屏幕ESC [ ? 1049 h
,并且l
作为记录在这里。
问题是 Linux 版本的命令top
不仅仅使用替代屏幕:\e[H\e[2J
顺序是:转到 1,1 并清除屏幕。根据我的理解,这实际上应该擦除该命令之前打印在终端上的所有内容。这就是我在解析器/解释器中所做的。但这不是 Linux 终端所做的(我使用 XFce 终端)。它以某种方式清除部分屏幕并向下滚动页面。
所以我的问题是处理 top 命令(\e[H\e[2J
序列)以像在 Linux 终端上一样呈现它的确切步骤(算法)是什么?我需要有一个字符串作为会话的输出,就像它在我的终端上看到的那样。
以下是脚本命令的示例输出:https://jcubic.pl/screen_dump_linux_top.txt
我有测试代码代码笔:
使用此代码:
$.terminal.format($.terminal.overtyping($.terminal.from_ansi(text)));
如果您查看 Linux 上 top 命令的输出。您将看到该命令之前没有任何输出。与打印所有内容的 macOS 文件相比(我知道真正的终端在切换回主屏幕时不会打印替代屏幕,但我决定在那里输出该输出,也许我添加一个选项来切换它) 。
我知道我可以检查终端模拟器源代码,但这可能比仅仅询问这个要花费更多的时间。
答案1
\e[H
将光标移至主页(左上角)并\e[2J
清除屏幕(经常查看的部分,但不是回滚部分)。
在许多终端模拟器中,\e[2J
只是简单地就地清除屏幕上经常查看的部分。结果是:如果您执行一个产生一些输出的命令(例如seq 100
用于测试目的),然后执行,top
则前一个程序的输出的开头将保留在回滚缓冲区中,但其输出的结尾将永远丢失。
为了解决这种不合逻辑的行为,一些终端模拟器(包括 Xfce 终端使用的 VTE 小部件)修改了 的行为\e[2J
:它将屏幕滚动到回滚缓冲区中。 “常规区域”中的结果是相同的:您会看到一个空白屏幕。回滚缓冲区的内容可以说更有意义:前一个命令的整个输出都被保留。
\e[3J
如果您想这样做,您可以使用它来清除回滚缓冲区。发出这个后 \e[2J
,否则一屏数据会滚动到那里。 (这就是该clear
命令的作用。)
所以我的问题是处理 top 命令(
\e[H\e[2J
序列)以像在 Linux 终端上一样呈现它的确切步骤(算法)是什么?
答案是:这取决于哪个终端。
答案2
但这不是 Linux 终端所做的(我使用 XFce 终端)。它以某种方式清除部分屏幕并向下滚动页面。
实际上,echo -e "\033[H\033[2J"
它完全符合您的预期 - 转到左上角,清除屏幕缓冲区的其余部分。
您看到的向下滚动是因为您的屏幕缓冲区的行数比终端的行数多。
看看stty size
你有多少行和列。做stty rows X cols Y
改变它。
答案3
我想我已经自己解决了这个问题。我无法在 XFce 终端源代码中找到有关 ANSI 转义码的任何信息。我不确定 ANSI 代码是在哪里处理的。
但解决方案是这个算法:
- 当有
[H
代码时保存光标位置。 - 当有一个
[2J
代码且前一个代码被H
恢复到光标位置时。 - 向前移动一行并将 x 移至 0。
- 将 y 位置保存为scroll_top。
- 现在,每次您有
[x;yH
or[H
代码时,都使用scroll_top 作为 y 光标位置的偏移量。
这比 Linux 终端效果更好,因为它清除了很多行,因此下一行位于屏幕顶部。 macOS 上的 iTerm2 与我的算法类似,但它仅滚动窗口,因此 1 1 位置位于终端窗口的左上角。