如何在 zsh

问题描述

整个问题都在 herehere 中讨论。由于没有参与这些讨论的人对这个问题有 100% 的把握,我在这里寻求帮助。 (为了完整起见,我将从头开始。)

假设我们有两个脚本(源自 ~/.zshrc)为 ZSH 设置了一些完成逻辑。现在根据我学到的知识,在脚本中的某个时刻,您需要像这样调用 compinitbashcompinit(从 NVM 完成脚本复制)

if [[ -n ${ZSH_VERSION-} ]]; then
  autoload -U +X compinit && if [[ ${ZSH_disABLE_COMPFIX-} = true ]]; then
    compinit -u
  else
    compinit
  fi
  autoload -U +X bashcompinit && bashcompinit
fi

显然,根据 ZSH 手册,bashcompinit 必须在 compinit 之后调用,(不确定是否相关)。现在的问题是,当第二个脚本调用 compinit 时,来自第一个脚本的逻辑就消失了(即第一个脚本的完成不可用)。重现这一点的简单片段是(复制自 here):

complete -W "hello world" one
one <tab>   # to see autocomplete working
compinit 
one <tab>   # to see autocomplete NOT working

有人提出 (here) 类似下面的方法解决这个问题(通过在调用之前检查 compinit 是否已经被调用):

if [[ -n ${ZSH_VERSION-} ]]; then
  if ! command -v compinit > /dev/null; then
    autoload -U +X compinit && if [[ ${ZSH_disABLE_COMPFIX-} = true ]]; then
      compinit -u
    else
      compinit
    fi
  fi
  autoload -U +X bashcompinit && bashcompinit
fi

一个想法可能是不在自定义完成脚本中调用 compinitbashcompinit,而是在 ~/.zshrc调用(这会损害 NVM 等工具的自动安装过程)。

我想知道一般设置完成的正确方法是什么(或者特别是关于调用 compinit)。

谢谢。

解决方法

假设我们有两个脚本(来自 ~/.zshrc)为 ZSH 设置了一些完成逻辑。现在根据我学到的知识,在脚本中的某个时刻,您需要调用 compinitbashcompinit

不,这不是你的脚本应该做的。不是您的脚本,而是 user 应该在其 compinit 文件中调用 .zshrc 以启用 Zsh 的完成系统。此外,对于每个 shell 实例,它应该只调用一次

相反,第 3 方脚本有两种正确的方式向 Zsh 添加完成功能:

  • 如果用户应该为其 shell 的每个实例分别运行您的脚本(这似乎是您的情况),那么
    1. 指示您的用户在他们的 .zshrc 文件中找到他们执行 autoload -Uz compinit && compinit 的点(如果他们不这样做,则添加它)。
    2. 让他们在该行之前获取您的脚本。
    3. 让您的脚本将包含完成函数的目录添加到它们的 $fpath 中。
  • 但是,如果您还提供安装程序,则可以改为
    1. 让安装程序将您的完成功能复制到 /usr/local/share/zsh/site-functions(默认情况下在 Zsh 的 $fpath 中)。
    2. 指示用户确保他们的 autoload -Uz compinit && compinit 文件中有 .zshrc

(后者也是安装软件时包管理器应该做的。)

显然,根据 ZSH 手册,bashcompinit 必须在 compinit 之后调用,(不确定是否相关)。

是的,这是相关的,但不,不是您认为的那样。其中,bashcompinit 定义了 complete()用户可以使用它向 Zsh 添加 Bash 完成功能。与 compinit 一样,bashcompinit 旨在每个 shell 仅调用一次。

如果您的包没有提供原生 Zsh 补全功能,那么您应该指示用户执行以下操作:

  1. 在他们的 .zshrc 文件中找到他们执行 autoload -Uz compinit && compinit 的点。
  2. 在该行之后,添加 autoload -Uz bashcompinit && bashcompinit
  3. 然后,在该行之后,添加安装 Bash 补全的步骤。