我维护了一个名为Basta的 Bash 环境扩展。Basta 在 ANSI/VT100 终端底部提供了滚动保护的状态行。
当 Basta 自行设置时,内核中的 termios 内容和 shellLINES
变量所知道的有效行数会减少 1。调整终端大小处理得很好。几乎。trap
信号会SIGWINCH
调用更新例程,该例程也会在每个命令之后调用,然后再返回提示符。
然而,我时不时会看到滚动区域丢失的情况。提示被绘制在底线(用户正在编辑命令和命令输出出现的位置)上,导致一片混乱。
我对于这种情况如何发生有一个假设,并且有可靠的重现步骤。
我们运行一个等待输入的程序,而 Bash 在后台运行,例如
cat
。当这个程序运行时,我们调整窗口大小,将其缩小一行。
终止该
cat
程序。
如果在运行时调整终端的大小cat
,Bash 将无法获得该信息SIGWINCH
(因为我认为,SIGWINCH
该信息仅发送给终端会话前台进程组中的进程,而 Bash 当时处于后台)。我们的信息trap
不会执行。
Basta 的更新功能还依赖于将之前的终端尺寸与当前的终端尺寸进行比较来检测尺寸变化。
问题在于:在这种具有滚动保护状态的终端缩小了一行的情况下,行数似乎没有改变。
例如,40 行屏幕,39 行滚动区域:LINES=39
。将终端大小调整为 39 行长。滚动区域LINES=39
再次消失。对于软件来说,它看起来大小相同,因此它得出结论,没有调整大小。状态行现在被绘制在底行的顶部,在用户输入的顶部,因为 Basta 想把它放在第 40 行,而第 40 行已经不存在了,所以光标被限制在第 39 行。
如果 Basta 知道发生了窗口大小变化,它就不会进行大小比较;在这种情况下,它会选择一条慢速路径,即查询终端本身来确定大小。(每次更新都这样做是不可取的,因为向终端发送查询是不可靠的。如果用户快速打字,终端响应可能会与他们的按键混淆,并且通过滞后的远程连接从终端获取响应可能会有明显的延迟。)
有没有巧妙的方法可以知道终端已经发生变化(或至少以相当低的误报率怀疑它),在没有收到陷阱的情况下WINCH
,由于一直在后台,没有与终端对话?