zsh自动补全的复用
zsh的自动补全
zsh-completions
是zsh官方支持的自动补全包
使用antigen
管理zsh插件的话,zsh-completions
的路径在~/.antigen/bundles/zsh-users/zsh-completions/src
,其下有众多文件名如_xxx
,分别定义了xxx
命令的补全。
机理
zsh 有一数组 $fpath
,内容如
declare -p fpath
typeset -a fpath=( /usr/local/share/zsh/site-functions /Users/mac/.autojump/functions /usr/share/zsh/site-functions /usr/share/zsh/5.3/functions /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/lib /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/autojump /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/pip /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/svn-fast-info /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/colorize /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/github /Users/mac/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/python /Users/mac/.antigen/bundles/zsh-users/zsh-autosuggestions /Users/mac/.antigen/bundles/zsh-users/zsh-completions /Users/mac/.antigen/bundles/Vifon/deer /Users/mac/.antigen/bundles/willghatch/zsh-cdr /Users/mac/.antigen/bundles/zsh-users/zsh-syntax-highlighting /Users/mac/.antigen/bundles/zsh-users/zsh-completions/src )
表示zsh启动时会从这些路径下加载_xxx
文件,当zsh加载fpath所有文件后,会生成相应的_xxx
函数,例如
~/.antigen/bundles/zsh-users/zsh-completions/src/_tmuxp
文件定义了_tmuxp
自动补全函数,(未定义_tmux
函数),而zsh加载后会自动生成_tmux
函数
复用zsh的自动补全函数
基本原理
-
直接复用:
bar
函数 要 复用foo
函数的自动补全# 函数 bar的定义可写在其前 compdef _foo bar # 函数 bar的定义也可写在其后
-
复用带参的:
bar
函数 要 复用foo <一个或多个参数>
的自动补全# 创建一个空函数foo_copy_comp,使其补全与foo同 foo_copy_comp() { : } compdef _foo foo_copy_comp # zsh的自动补全支持alias,故而bar的自动补全与'foo <一个或多个参数>'命令同 alias bar='foo_copy_comp <一个或多个参数>' # 函数 bar的定义要写在其后 bar(){ # ... }
当bar函数定义后,alias bar与bar函数共存:
which bar
返回的是" alias bar=‘foo_copy_comp <一个或多个参数>’ "bar <TAB键>
会显示foo <一个或多个参数>
命令之后的自动补全- 运行
bar <其他参数>
命令,会执行bar
函数,而非alias bar
配置示例
-
关闭全局的
compinit
:在全局zshrc
文件( mac:/etc/zshrc
, linux:/etc/zsh/zshrc
) 中,搜compinit
,若发现如下内容,则将skip_global_compinit=1
解除注释;若没发现compinit
,则不管。# If you don't want compinit called here, place the line # skip_global_compinit=1 # 这行要解注释 # in your $ZDOTDIR/.zshenv or $ZDOTDIR/.zprofile if [[ -z "$skip_global_compinit" ]]; then autoload -U compinit compinit fi
这样设置的原因是:在
~/.zshrc
中需要运行autoload -U compinit && compinit
(如下一段),来使得compdef
有定义。但是运行这个比较花时间,全局zshrc
文件没必要也运行一遍。注: 每次启动zsh(不论登录、非登录,交互、非交互),先会运行全局
zshrc
文件,再运行~/.zshrc
。 -
配置自动补全:在
~/.zshrc
中写
# 初始化zsh的自动补全,从而conpdef函数有定义了
autoload -U compinit && compinit
# ----------直接复用--------------
# auto_rsync 函数 复用 rsync的补全函数
compdef _rsync auto_rsync
# ---------复用带参的--------------
# itm 函数 复用 'tmux -CC attach -t' 的补全函数
tmux_itm() { :; }
compdef _tmux tmux_itm
alias itm='tmux_itm -CC attach -t'
## 注意, 两个alias 不能共用同一个 tmux_itm, 不然这两个alias对应的函数会冲突
## 例如下面这样是不行的
# alias itm1='tmux_itm -CC attach -t'
# alias itm2='tmux_itm -CC attach -t'
## 后面定义 itm1函数 和 itm2函数,
# 则 itm1函数 和 itm2函数 会冲突, 即两个函数名, 对应到同一个函数体
# 允许在有`alias foo=...`时,再定义函数`foo() { .... }`
set -o ALIAS_FUNC_DEF > /dev/null 2>&1
- 定义补全函数:在
~/.zshrc
配置自动补全的后面,source ~/.aliases
, 而source ~/.aliases
中定义补全函数
# ----------直接复用--------------
# 带断点续传的rsync
auto_rsync() {
local retry_time=180
while [ 1 ]
do
rsync -aHhvzP $*
if [ "$?" = "0" ]
then
echo "rsync completed normally"
break
else
echo "Rsync failure. Backing off and retrying in $retry_time seconds..."
sleep $retry_time
fi
done
}
# ---------复用带参的--------------
# itm 函数覆盖 alias itm='tmux_itm -CC attach -t'
itm() {
# 注意:若已经定义了alias itm,需要把前三个参数`-CC attach -t`过掉
if [ "$(alias itm 2> /dev/null)" != '' ]; then
for i in {1..3}; do shift; done
fi
if [ $# = 0 ]; then
tmux -CC attach || tmux -CC new -s default
else
local session="$1"
tmux -CC attach -t "${session}" || tmux -CC new -s "${session}"
fi
}
注意:复用foo <n个参数>
,要仿照上面的代码,把前n个参数过掉。