tmux:在键绑定中链接 `send-key Enter` 和 `refresh -S`

tmux:在键绑定中链接 `send-key Enter` 和 `refresh -S`

我正在尝试配置 tmux,使其在按下“enter”键时始终刷新客户端(或客户端状态栏)。我目前正在使用

bind -n enter send-key Enter; refresh -S

但行为很奇怪。它确实Enter每次都发送,因此我可以正常使用密钥,但并不refresh -S总是执行。我使用状态栏设置测试配置

set -g status-left "#{pane_current_path}"

st 它应该在输入cd命令时立即更新。但这并没有发生。当输入cd到某个地方时,状态栏只会在标准周期内更新,即有时会延迟。如果我在输入另一个命令(或空白行)后不久输入另一个命令,cd状态栏确实会立即更新。

send-key KPEnter使用 而不是 ,也会发生同样的事情Enter

有人知道这里发生什么事吗?

答案1

这是一种竞争条件。

扩展#{pane_current_path}需要 tmux 服务器了解进程的当前工作目录是窗格中的“主目录”。tmux 服务器如何了解或已经知道这是哪个进程并不重要,重点是该进程不是 tmux 的一部分,它是一个单独的进程。

通常,就像您的情况一样,窗格中的“主进程”是一个交互式外壳。

Tmux 服务器可以通过检查 来了解此 shell 的当前工作目录/proc/<PID>/cwd,其中<PID>表示 shell 的 PID;或者通过一些等效方法。

当你输入cd whateverEntersend-key Enter; refresh -S运行后,send-key Entershell 开始解释cd whatever。重要的是send-key,它只发送键,不等待此操作的任何效果;而 shell 只是开始解释cd whatever、解释和执行需要一些时间;但是毫不拖延tmux 继续执行,refresh -S使 tmux 服务器开始刷新客户端的状态行,这涉及评估#{pane_current_path}。shell(由 触发send-key)和 tmux 服务器(由 触发refresh)执行其任务在平行下并且无法保证 shell 在#{pane_current_path}评估之前能够真正改变其当前工作目录。

如果首先评估格式字符串,那么您将在状态行中看到旧的工作目录。

cd在makes#{pane_current_path}返回新的当前工作目录后不久,另一个命令或一个空白行会因为Enter这里已经足够晚了,shell 已经设法改变了其工作目录。

cd在交互式 shell 中,促使状态行无竞争地刷新的一个好方法是,在它实际更改工作目录后cd触发自身:refresh -S

if [ -n "$TMUX" ]; then
   cd () {
      command cd "$@"
      (
         status="$?"
         tmux refresh -S
         return "$status"
      )
   }
fi

如果 shell 位于 tmux 内部,则上述代码片段将创建一个重载cd内置函数的 shell 函数。

笔记:

  1. shell 代码本身是可移植的。唯一不可移植的部分是 的调用tmux
  2. 的别名的存在cd将导致代码片段失败或行为异常。在 Bash 中,您可以通过将其替换cd ()为不可移植的来解决此问题function cd
  3. 该函数保留实际的退出状态cd
  4. 异步调用tmux( tmux refresh -S &) 将使 shell 不等待它,但不会破坏解决方案。我指出这一点是因为在你最初尝试使用bindshell 时,它也不会等待,所以或许这是您喜欢的。但是,如果异步tmux失败(虽然可能性很小)并打印错误消息,则该消息可能会在下一个 shell 提示符后出现,这会令人困惑。出于这个原因,在我看来更加优雅同步调用tmux。异步调用确实tmux可以节省几毫秒;不过在交互式 shell 中,您很可能不会注意到差异。

相关内容