使用 tmux 实现无缝鼠标滚动

使用 tmux 实现无缝鼠标滚动

编辑:这个答案是针对 Windows 终端编写的,但我认为这是一个更普遍的 xterm 问题。

默认情况下,在 Windows 终端中运行 tmux 不会显示滚动条,并且不允许您使用鼠标滚轮滚动。

作为一种解决方案,人们通常建议打开 tmux 的鼠标模式,例如通过添加到set -g mouse on~/.tmux.conf这可以重新启用使用鼠标滚轮的滚动,但会干扰选择文本并禁用右键单击粘贴,并且仍然不会启用右侧滚动条。

幸运的是,您可以按照建议,通过添加到set -g terminal-overrides 'xterm*:smcup@:rmcup@'来启用 tmux 中的原生 xterm 滚动~/.tmux.conf这里和(略有不同)这里。这将恢复通常的滚动行为。根据第二个链接,它的工作原理是“欺骗 [tmux] 认为终端没有‘备用屏幕’模式”,如果您不使用 xterm,则xterm*应该用 的输出替换。echo $TERM

但是,它存在一些问题:当连接到现有 tmux 会话(tmux atmux attach)时,向上滚动会显示您连接之前的父终端会话的内容,而不是 tmux 会话的过去内容。第一个链接的评论之一抱怨说,此解决方案“在(重新)连接后不会保留回滚缓冲区” - 但事实并非如此,因为如果您缩小很多(例如使用 Ctrl + 鼠标滚轮)然后再次放大,您可以看到 tmux 会话的全部过去内容,或者至少可以看到缩小时屏幕上可以容纳的行数。缩小得越远,放大时可以滚动得越远。

有没有办法跳过这个放大/缩小技巧,让 Windows 终端在连接时重新渲染整个 tmux 回滚缓冲区?老实说,这set -g terminal-overrides 'xterm*:smcup@:rmcup@'似乎是一种黑客行为,所以也许有一种更强大的方法来重新启用原生 xterm 滚动?

答案1

重新连接后,在最顶部窗格中的 shell 中调用此命令:

tmux capture-pane -pqeS -

我认为上述命令只会为占据整个终端宽度的顶部窗格填充终端的回滚缓冲区。从任何其他窗格调用该命令都没有意义。一般来说,您想要执行的操作无法很好地适用于任意窗格布局。如果您选择另一个 tmux 窗口,则需要在新窗口的最顶部窗格中重复该命令,否则您仍会看到旧窗口的缓冲区。这是强制回滚缓冲区tmux无法完全轻松控制所带来的痛苦。

我认为一个终端仿真器可以与tmux(使用控制模式tmux例子) 或许也能在tmux不采用任何技巧的情况下整合其滚动行为。即便如此,它也可能受到限制。

您要使用的回滚缓冲区通常非常简单。它的工作原理是保存那些本来会移动(滚动)到屏幕顶部边缘并消失的行。程序可能会重写(部分)屏幕,因此不会出现新行,也没有什么可滚动的,也没有什么可保存的;或者它们可能在某个时候写入“超出底部”,因此终端仿真器会自动滚动文本,顶部的行是要添加到回滚缓冲区的行。程序也可能尝试清除缓冲区(它是有点复杂)。他们没有太多办法来改变缓冲区。

想象一下 中的 2x2 窗格网格tmux。理论上,可以为回滚缓冲区制作内容,使其看起来像两个顶部窗格的历史记录。但是,如果在左上窗格的底部添加了一行,并且窗格中的文本需要滚动,则不能简单地将顶部行保存在缓冲区中,因为它还会滚动缓冲区中右上窗格的历史记录。为了让缓冲区现在看起来正常,必须完全重建它,其左半部分相对于“静态”的右侧部分向上移动。调整窗格大小也需要重建缓冲区。

显然,两个底部窗格根本无法理智地将其历史记录保存在终端仿真器的回滚缓冲区中。

看来tmux,当与这个terminal-overrides技巧一起使用时,它可以合理地运行并(重新)写入,只允许将来自全宽最顶部窗格(如果有)的行保存在回滚缓冲区中。

这就是你所追求的痛苦。:) 也许你tmux只用来重新连接到一个单身的单个窗口中的窗格。在这种情况下,在我们修复相关问题后,使用终端仿真器的回滚缓冲区可能会有点用处。

以下钩子(在 中.tmux.conf)将尝试capture-pane …自动运行:

set-hook -g client-attached        'run-shell -t {top} "tmux capture-pane -t {top} -pqeS - | head -c -1 >\"#{pane_tty}\"'
set-hook -g session-window-changed 'run-shell -t {top} "tmux capture-pane -t {top} -pqeS - | head -c -1 >\"#{pane_tty}\"'

它们并不完美;head -c -1不可移植;您可能需要更多钩子。将它们视为概念证明。我在 Linux 上进行了测试。

补充笔记:

  • 如果您总是使用 中的单个窗口tmux,那么您实际上并不需要此session-window-changed挂钩。不过,拥有它并没有什么坏处,以防您将来开始使用更多窗口。
  • 如果您在 中始终使用每个窗口的单个窗格tmux,那么您可以-t {top}从代码中删除 的所有实例。如果您tmux年纪大了并且不理解 ,这将特别有用-t {top}

相关内容