在 tmux 中拆分窗格时保持旧的 conda env 处于激活状态

Keeping the old conda env activated upon splitting panes in tmux

我使用的是 tmux 2.6 并且正在使用几个不同的 conda 环境。拆分后 panes/windows 我希望 tmux 也能在子窗格中激活父窗格的环境。

我知道我可以在 split-window 命令的键绑定中添加要执行的代码,并且当前活动的 conda env 的名称存储在 $CONDA_DEFAULT_ENV 中。但是,我尝试的任何命令都失败了。

为了我的尝试,我在 /some_path/bla.sh 中设置了 conda activate $CONDA_DEFAULT_ENV 并使用

设置了窗格拆分命令
bind \ split-window -h -c "#{pane_current_path}" '/some_path/bla.sh'

在我的 tmux 配置文件中,但新创建的窗格在拆分后立即消失。

然而,即使它没有,我猜它也会重新激活基本环境,因为 $CONDA_DEFAULT_ENV 环境变量随着新 shell 的启动而改变。

我想一个可行的解决方案必须首先存储旧的 $CONDA_DEFAULT_ENV 环境变量,将其转移到新的 tmux 面板,然后使用它来设置 conda 环境,但我不知道如何实现这一目标。

我已经使用 tmux 3.1b 完成了这项工作。我看到你在发布问题时是 运行 tmux 2.6,但是如果可以的话,请尝试至少更新到 v3.0,因为我的回答依赖于使用 -e 标志来new-windowsplit-window 并且该标志仅根据 their changelog 从 v3.0 引入。假设你可以使用前面提到的-e标志,步骤如下:

步骤 1(使用 tmux/tmux.conf):

在 运行 tmux new-windowtmux split-window 时传递 -e "TMUX_PARENT_PANE_ID=#{pane_id}",以及您可能已经使用的任何其他标志。这会在新(子)pane/window 的环境中创建一个变量 TMUX_PARENT_PANE_ID,其中包含由 tmux 分配给初始(父)窗格的唯一 ID。

如果您使用键绑定,那么您需要使用 tmux 的 run 以一种不太直观的方式(重新)编写它们。例如,为了将字母 "c" 绑定到 tmux new-window,tmux.conf 文件中的相应行必须如下所示:

bind c run 'tmux new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}"'

其中 YOUR_CURRENT_OPTIONS 代表您在添加 -e 选项之前可能已经存在的任何选项。如果您只使用 bind c new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}",那么 #{pane_id} 将作为文字 "#{pane_id}" 传递,接下来的步骤将不起作用。

设置 2 [在您的 bashrc(或等效文件)文件中]:

重新定义 conda 命令以便:

  1. 在每个窗格的本地环境中复制 anaconda 的 CONDA_DEFAULT_ENV 环境变量。在接下来的代码中,这个副本将被命名为 CONDA_DEFAULT_ENV_COPY。如果再次获取 bashrc(或相应的等效文件),这将有助于在窗格中调用 conda 环境。
  2. 跟踪 tmux 会话所有面板的 conda 环境变化。我们通过 defining/updating a TMUX_SESSION_CONDA_ENVS tmux session 环境变量来做到这一点。与每个窗格的本地环境中定义的变量相反,会话中的所有窗格都可以访问 tmux 会话变量。

完成上述内容的代码是:

# Redefine conda command, part a: Keep copy of original conda command/function
eval "original_$(declare -f conda)" 2> /dev/null
if [ $? -ne 0 ]; then
    original_conda () {
      command conda "$@"
    }
fi
# Redefine conda command, part b: Add new functionality related to items (i) and (ii).
conda () {
  # Run the regular conda
  original_conda "$@"
  local CONDA_RTN_CODE=$?

  # Keep a copy of CONDA_DEFAULT_ENV to restore the environment if, e.g.,
  # 'source ~/.bashrc' is run
  CONDA_DEFAULT_ENV_COPY=$CONDA_DEFAULT_ENV

  # Stop and return original_conda's return code if it fails
  [ $CONDA_RTN_CODE -ne 0 ] && return $CONDA_RTN_CODE

  # Do tmux-related stuff, but only if tmux is running and "$@" contains substring "activate"
  if [[ -n "$TMUX" ]] && [[ "$@" =~ .*"activate".* ]]; then
    # Create/update the *tmux* session env var "TMUX_SESSION_CONDA_ENVS"
    local TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
    if [[ $? -eq 0 ]]; then
      # Get list of conda envs for all panes except the current one
      local OLD_VALUES=$(echo $TMUX_SESSION_CONDA_ENVS | sed "s/TMUX_SESSION_CONDA_ENVS=//")
      local CONDA_ENV_OTHER_PANES=$(echo $OLD_VALUES | sed "s/$TMUX_PANE:\w*[[:space:]]*//g")
    fi
    # Include current pane's conda env info
    tmux setenv TMUX_SESSION_CONDA_ENVS "$TMUX_PANE:$CONDA_DEFAULT_ENV $CONDA_ENV_OTHER_PANES"
  fi
}

步骤 3 [也在您的 bashrc(或等效文件)文件中]:

查询创建child时父pane的conda环境,最后激活child中的conda环境。我目前使用的代码如下:

if [[ -n "$TMUX_PARENT_PANE_ID" ]]; then
    # Remember: "TMUX_SESSION_CONDA_ENVS", as per our redefined "conda" command, carries
    # info about changes in the the conda environments in all the session's panes.
    # TMUX_PARENT_PANE_ID makes it thus possible to query, from any child
    # pane, its parent's conda environment at the time the child was created.
    # This is exactly what will be done now.
    TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
    if [ $? -eq 0 ]; then
        PATT="(?<=${TMUX_PARENT_PANE_ID}:).*?(?=([[:space:]]|$))"
        PARENT_CONDA_ENV=$(echo $TMUX_SESSION_CONDA_ENVS | grep -oP "$PATT" | head -1)
        echo "Activate conda env '$PARENT_CONDA_ENV' of parent tmux pane '$TMUX_PARENT_PANE_ID'"
        conda activate $PARENT_CONDA_ENV
    fi
    # Clean up the pane's env (TMUX_SESSION_CONDA_ENVS remains in the tmux session env)
    unset TMUX_SESSION_CONDA_ENVS PATT PARENT_CONDA_ENV
    # Erase memory of parent tmux pane's ID so that the 'else' block below
    # is run if we re-source bashrc
    unset TMUX_PARENT_PANE_ID
else
    # Triger update of TMUX_SESSION_CONDA_ENVS and CONDA_DEFAULT_ENV_COPY
    # when the pane has no parent (very first pane or a pane where bashrc was
    # re-sourced after creation).
    [[ -n "$CONDA_DEFAULT_ENV_COPY" ]] && echo "Activate previous conda env '$CONDA_DEFAULT_ENV_COPY'"
    conda activate $CONDA_DEFAULT_ENV_COPY
fi

完成这些步骤后,只需关闭您的终端,再次打开它们并重新启动 tmux。希望对您有所帮助。