gro*_*taj 5 ubuntu zsh autocomplete oh-my-zsh
如果我在这里做了一些愚蠢的事情,请原谅我,文档很大而且搜索还没有找到任何东西。
我正在尝试为我的自定义脚本创建 shell 完成fab
。对于 bash 来说,这很容易,只需将它们放入即可/etc/bash_completion.d
工作。但是,天哪,zsh 是 PITA 吗...
我有完成功能_fab
,当使用compdef _fab fab
. 我把它放在/usr/share/zsh/vendor-completions/_fab
已经在我的$fpath
. 该文件#compdef fab
以compdef _fab fab
. 看起来挺好的:
$ type _fab
_fab is an autoload shell function
Run Code Online (Sandbox Code Playgroud)
但是每当我启动一个新的 shell 时,fab
补全都不起作用(来自 的其他函数vendor-completions
,如_docker
,很好)。compinit
针对该特定外壳修复了此问题。我发现rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit
它可以永久工作(5.1.1 = 我的 zsh 版本)。
问题:
~/.zcompdump
以设置初始完成?man zshall
说:
下一次调用 compinit 将读取转储文件而不是执行完全初始化。
如果是这样,compinit
在我删除之前不会修复我的完成~/.zcompdump
,对吗?我错过了什么吗?
~/.zcompdump-$(hostname)-5.1.1
它与什么以及如何相关.zcompdump
?唯一的区别是在~/.oh-my-zsh/completions
(因为$ZSH
指向~/.oh-my-zsh
) 中的一个完成。这是 oh-my-zsh 的事情吗?我的目标是 Ubuntu 16.04、18.04 和 19.04,但欢迎提供非发行版特定信息。我正在使用 zsh 5.1.1 和最近的 oh-my-zsh 在 Ubuntu 16.04 上对此进行测试。
TL、DR:在正常操作中,只需将文件放入适当的目录即可。测试时,需要删除缓存文件(.zcompdump
默认情况下,但用户可以将其放在不同的位置,oh-my-zsh 确实将其放在不同的位置)。
简单的答案是在第一行是#compdef fab
. 该文件必须位于 上的目录中$fpath
。
该文件可以包含函数体,也可以包含函数的定义,然后是对函数的调用。也就是说,要么文件包含类似
#compdef fab
_arguments …
Run Code Online (Sandbox Code Playgroud)
或者
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
Run Code Online (Sandbox Code Playgroud)
该文件必须$fpath
在compinit
运行前存在。这意味着您需要注意事物的顺序.zshrc
:首先将任何自定义目录添加到$fpath
,然后调用compinit
. 如果您使用诸如 oh-my-zsh 之类的框架,请确保$fpath
在 oh-my-zsh 代码之前添加任何自定义目录。
compinit
是初始化完成系统的函数。它读取所有文件$fpath
并检查它们的第一行是否有魔术指令#autoload
和#compdef
.
.zcompdump
是使用的缓存文件compinit
。~/.zcompdump
是默认位置;跑步时可以选择不同的位置compinit
。Oh-my-zsh 调用时compinit
可以-d
选择使用变量指定的不同缓存文件名ZSH_COMPDUMP
,默认为
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
Run Code Online (Sandbox Code Playgroud)
包含主机名是为了那些在机器之间共享主目录并且可能在不同机器上安装不同软件的人。包含 zsh 版本是因为缓存文件在版本之间不兼容(它包含从版本到版本更改的代码)。
我认为您的所有问题都是由于陈旧的缓存文件造成的(这使您的情况过于复杂)。不幸的是,zsh 确定缓存文件是否陈旧的算法并不完美,大概是为了速度。它不检查 上文件的内容或时间戳$fpath
,它只是对它们进行计数。一个.zcompdump
文件以这样的行开头
#files: 858 version: 5.1.1
Run Code Online (Sandbox Code Playgroud)
如果zsh版本和文件数正确,zsh加载缓存文件。
缓存文件只包含命令名称之间的关联,不包含完成函数的代码。以下是缓存透明工作的一些常见场景:
$fpath
,则缓存无效。$fpath
,并且删除的文件总数与删除的文件总数不同,这会使缓存无效。$fpath
而不更改其名称,这不会影响缓存中的任何内容,因此缓存保持正确。$fpath
不更改文件第一行的情况下修改文件,这不会影响缓存中的任何内容,因此缓存保持正确。下面是一些缓存失效的常见场景,但 zsh 没有意识到。
$fpath
和删除的文件数量完全相同。$fpath
.#compdef
(或#autoload
) 行。最后一点是在测试过程中往往会咬人的东西。如果更改该#compdef
行,则需要删除该.zcompdump
文件并重新启动 zsh(或重新运行compinit
)。
如果您将完成放在可再发行包中,只需将完成文件放入系统范围内的$fpath
. 对于 Ubuntu 包,合适的位置是/usr/share/zsh/vendor-completions
. 对于安装在 下的东西/usr/local
,那就是/usr/local/share/zsh/site-functions
. 这就是你需要做的。
不透明的一件事是,如果您需要#compdef
在升级中更改行,或者您删除或重命名某些文件。在这种情况下,用户将需要删除他们的缓存文件,而这不是您可以从安装在多用户计算机上的包中执行的操作。