如何在 zsh 中正确调用 compinit(和 bashcompinit)

How to properly call compinit (and bashcompinit) in zsh

讨论了整个问题 here and here。由于参与这些讨论的人都不能 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)。

谢谢。

Let's say we have two scripts (sourced in ~/.zshrc) that set up some completion logic for ZSH. Now based on what I learned, at some point in the script you need to call compinit and bashcompinit

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

相反,3rd 方脚本有两种正确的方法来为 Zsh 添加补全功能:

  • 如果用户应该为他们的每个 shell 实例分别 运行 您的脚本(这似乎是您的情况),那么:
    1. 告诉用户确保从他们的点文件中调用 autoload -Uz compinitcompinit
    2. 告诉他们在这些行之前获取您的脚本。
    3. 当你的脚本 运行s 时,让它将包含你的完成函数的目录添加到用户的 $fpath
  • 但是,如果您还提供了安装程序,那么您可以:
    1. 告诉用户确保从他们的点文件中调用 autoload -Uz compinitcompinit
    2. 让安装程序将您的完成函数复制到 /usr/local/share/zsh/site-functions(默认情况下在 Zsh 的 $fpath 中)。

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

Apparently, according to ZSH manual, bashcompinit must be called after compinit, (not sure if it's relevant).

是的,它是相关的,但不,不是您认为的那样。除此之外,bashcompinit 定义了函数 complete,然后(就像 Bash 中的 complete 内置)可以用来向 Zsh 添加 Bash 完成函数.像 compinit 一样,bashcompinit 意味着每个 shell.

只调用一次

如果您的包提供原生 Zsh 完成功能,那么您应该执行以下操作:

  1. 告诉用户确保从他们的点文件中调用 autoload -Uz compinitcompinit
  2. 告诉用户确保以上行之后,autoload -Uz bashcompinitbashcompinit被调用。
  3. 然后,在这些行之后,他们应该按照您在 Bash.
  4. 中给出的安装完成的相同说明进行操作