在自定义Bash补全中,资源之后,如何防止对fzf的递归调用?
我在为自己的一个项目编写一个我自己的小型补全框架,结果对~/.bashrc执行两次会破坏补全。
在我的~/.bashrc中,我为foo设置了fzf的路径补全:
# ~/.bashrc
...
_fzf_setup_completion path foo
我决定让foo具备一个标志--bar,并在文件~/foo_completion.sh中定义它。为了保留现有的fzf补全(以及它可能具备的其他补全),我解析当前的补全函数,调用它,并用--bar更新COMPREPLY。
# ~/foo_completion.sh
__orig_foo_completion="$(complete -p foo 2>/dev/null)"
__orig_foo_completion_func="$(echo "$__orig_foo_completion" | sed -r 's/.*\s+-F\s+([a-zA-Z_]+)\s+[a-zA-Z_]+/\1/')"
_foo_comp() {
"$__orig_foo_completion_func"
COMPREPLY+=($(compgen -W '--bar'))
}
complete -F _foo_comp foo
为了让它生效,我把我的~/.bashrc改为在fzf完成补全之后对这个文件执行source。
# ~/.bashrc
_fzf_setup_completion path foo
source ~/foo_completion.sh
可用,现已同时拥有两种补全。
问题在于,当我再次对~/.bashrc执行source时,尝试对foo进行补全看起来像是递归调用,导致会话崩溃。
# Start session: ~/.bashrc has been sourced
# Test fzf completion: shows fzf completion
foo **[tab]
# Test custom completion: shows `--bar`
foo[tab]
# Now resource ~/.bashrc: crash
source ~/.bashrc
foo[tab]
这是正确的做法吗? 也尝试把顺序颠倒,先对我的补全文件执行source,然后再执行fzf的补全,但问题仍然存在。
解决方案
正如与 @muru的评论交流所述,为了避免_foo_comp自调用自身,我本应该使用一个守卫,检查它是否已经被声明。
下面是带有该守卫的版本:
# ~/foo_completion.sh
if declare -F _foo_comp >/dev/null; then
return
fi
__orig_foo_completion="$(complete -p foo 2>/dev/null)"
__orig_foo_completion_func="$(echo "$__orig_foo_completion" | sed -r 's/.*\s+-F\s+([a-zA-Z_]+)\s+[a-zA-Z_]+/\1/')"
_foo_comp() {
$__orig_foo_completion_func
COMPREPLY+=($(compgen -W '--bar'))
}
complete -F _foo_comp foo
问题在于即使这样,终端仍然会崩溃,似乎还存在另一种递归。
为解决这个问题,fzf的补全必须在自定义补全源之后。
# ~/.bashrc
source ~/foo_completion.sh
eval "$(fzf --bash)"
_fzf_setup_completion path foo
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。