我正在为一个命令编写一个 ZSH 完成文件,该文件是另一个已经具有 ZSH 完成支持的命令的包装器。我想使用其他命令完成中定义的“私有”辅助函数,但这种简单的方法不起作用。到目前为止,这是我正在尝试的:
#compdef wrapper
_arguments ':action:(foo bar baz)' ':target:_other_command_helper_func'
当我尝试在命令行完成时,我得到
_arguments:450: command not found: _other_command_helper_func
在这里可以做我想做的事吗?
答案1
没有私有函数,所以如果_other_command_helper_func
已经加载它就会工作。由于完成函数通常是自动加载的,这意味着,使用这种方法,wrapper
仅当已经尝试完成原始命令时,完成才能起作用。
一种解决方案是强制加载原始命令的完成函数文件,但这并不简单。您可以使用autoload -X +U
加载原始命令的完成程序,但实际上它的作用是创建一个函数_other_command
(假设这是原始命令的名称),其定义是文件的内容_other_command
,包括辅助函数的定义和其他初始化之后是对主函数的调用。
_other_command () {
_other_command_helper_func () {
…
}
_other_command () {
…
}
_other_command "$@"
}
你可以尝试解析一下。如果定义在您的控制之下,您可以对初始化代码做出一些假设。如果是第三方的,那就风险更大了。大多数复杂的完成函数定义文件遵循初始化后跟表单最后一行的模型_main_function "$@"
,因此这通常可以工作:
if ((!$+functions[_other_command_helper_func])); then
autoload +X +U _other_command
functions[_other_command]=${functions[_other_command]%$'\n'*}
_other_command
fi
如果您遇到奇怪的错误,这可能是由于影响解析器的选项造成的(我_git
以这种方式加载时遇到了这个问题)。这对我有用:
load_helper_functions () {
emulate -LR zsh
if ((!$+functions[$1])) || [[ $functions[$1] = 'builtin autoload'* ]]; then
autoload +X +U $1
functions[$1]=${functions[$1]%$'\n'*}
$1
fi
}
load_helper_functions _git
或者,您可以只在您的代码中运行完成函数.zshrc
,然后让它默默地阻塞,因为它不是在完成上下文中运行的。例如,我在使用 CVS 时就遇到了这个问题;我把_cvs 2>/dev/null
我的.zshrc
.
如果原始的定义在您的控制之下,那么就有更好的解决方案。您可以对原始命令和包装器使用相同的完成函数(检查$service
以查看正在完成哪些命令的参数)。或者您可以在单独的文件中定义辅助函数。