如何从 Linux 终端解释 \e[H\e[2J ANSI 转义序列?

如何从 Linux 终端解释 \e[H\e[2J ANSI 转义序列?

我再次询问 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 代码是在哪里处理的。

但解决方案是这个算法:

  1. 当有[H代码时保存光标位置。
  2. 当有一个[2J代码且前一个代码被H恢复到光标位置时。
  3. 向前移动一行并将 x 移至 0。
  4. 将 y 位置保存为scroll_top。
  5. 现在,每次您有[x;yHor[H代码时,都使用scroll_top 作为 y 光标位置的偏移量。

这比 Linux 终端效果更好,因为它清除了很多行,因此下一行位于屏幕顶部。 macOS 上的 iTerm2 与我的算法类似,但它仅滚动窗口,因此 1 1 位置位于终端窗口的左上角。

相关内容