基于多路径的自定义zsh完成
我想为接受目录作为参数的命令编写一个自定义完成。我认为用一个例子来解释它应该如何工作是最容易的 假设我在某处定义了一个目录列表:基于多路径的自定义zsh完成,zsh,Zsh,我想为接受目录作为参数的命令编写一个自定义完成。我认为用一个例子来解释它应该如何工作是最容易的 假设我在某处定义了一个目录列表: d=(~/somedir/foo ~/somedir/foo/bar ~/other/dir/baz) 对该命令的有效调用为 mycmd foo mycmd bar mycmd baz mycmd baz/and/some/subdir 完成应该可以做到 mycmd f<TAB> => mycmd foo mycmd b
d=(~/somedir/foo ~/somedir/foo/bar ~/other/dir/baz)
对该命令的有效调用为
mycmd foo
mycmd bar
mycmd baz
mycmd baz/and/some/subdir
完成应该可以做到
mycmd f<TAB> => mycmd foo
mycmd baz/and/some/s<TAB> => mycmd baz/and/some/subdir
不知何故,我对zshcompsys的复杂性有点迷茫,所以我真的不知道如何才能做到最好。1。预定义目录作为参数。
如果您事先知道mycmd的参数可以是什么,您可以使用一个非常简单的完成函数,其中的值是硬编码的:
#compdef _mycmd
_arguments "1: :(foo bar baz baz/and/some/subdir)"
这就产生了以下结果:
zsh% mycmd<TAB>
bar baz baz/some/other/subdir foo
zsh% mycmd baz<TAB>
baz baz/some/other/subdir
zsh% mycmd baz/<TAB>
zsh% mycmd baz/some/other/subdir
您可以告诉compctl完成foo中的任何目录,作为mycmd的参数:
我不知道这将如何与您编写的mycmd的任何其他完成函数配合使用,例如,如果mycmd也使用非文件名参数。它是这样完成的:
zsh% mycmd<TAB>
bar/ baz/ caz/
zsh% mycmd baz/s<TAB>
zsh% mycmd baz/subdir/
4.数组的子目录。
使用以下目录结构:
~/.../somedir
~/.../somedir/bar
~/.../somedir/foo
~/.../somedir/foo/invalid
~/.../otherdir
~/.../otherdir/subdir
~/.../otherdir/subdir/baz
compctl的-W选项还将数组作为参数,允许:
→ compctl -/ -W "(/.../otherdir /.../somedir)" mycmd
→ mycmd <TAB>
bar/ foo/ subdir/
我们不需要foo的子目录,只需要baz的子目录。我们可以通过混合-k和-/-W来实现这一点:
1.预定义目录作为参数。
如果您事先知道mycmd的参数可以是什么,您可以使用一个非常简单的完成函数,其中的值是硬编码的:
#compdef _mycmd
_arguments "1: :(foo bar baz baz/and/some/subdir)"
这就产生了以下结果:
zsh% mycmd<TAB>
bar baz baz/some/other/subdir foo
zsh% mycmd baz<TAB>
baz baz/some/other/subdir
zsh% mycmd baz/<TAB>
zsh% mycmd baz/some/other/subdir
您可以告诉compctl完成foo中的任何目录,作为mycmd的参数:
我不知道这将如何与您编写的mycmd的任何其他完成函数配合使用,例如,如果mycmd也使用非文件名参数。它是这样完成的:
zsh% mycmd<TAB>
bar/ baz/ caz/
zsh% mycmd baz/s<TAB>
zsh% mycmd baz/subdir/
4.数组的子目录。
使用以下目录结构:
~/.../somedir
~/.../somedir/bar
~/.../somedir/foo
~/.../somedir/foo/invalid
~/.../otherdir
~/.../otherdir/subdir
~/.../otherdir/subdir/baz
compctl的-W选项还将数组作为参数,允许:
→ compctl -/ -W "(/.../otherdir /.../somedir)" mycmd
→ mycmd <TAB>
bar/ foo/ subdir/
我们不需要foo的子目录,只需要baz的子目录。我们可以通过混合-k和-/-W来实现这一点:
谢谢你的帮助,西蒙特,但我采用了另一种方法,使用完成函数。它主要基于尝试和错误,而不是阅读文档,因此我不知道这是否是正确的方法[tm],但它可以工作,并且不需要太多代码
function _foo {
setopt LOCALOPTIONS
unsetopt AUTOPUSHD
local paths
paths=(/home/dani '/var/log' '/usr/share' '/etc')
if [[ $PREFIX == *'/'* ]] {
for p ($paths) {
if [[ ${PREFIX[(ws:/:)1]} == ${p:t} ]] {
local oldpwd=$PWD
cd -q ${p:h}
local matches
matches=($PREFIX*(/))
if [[ ${#matches} -gt 0 ]] {
compadd -p ${matches[1]:h}'/' -q -S '/' -- ${matches:t}
}
cd -q $oldpwd
return
}
}
} else {
compadd -q -S '/' -- ${^paths:t}
}
}
compdef _foo foo
谢谢你的帮助,西蒙特,但我采用了另一种方法,使用完成函数。它主要基于尝试和错误,而不是阅读文档,因此我不知道这是否是正确的方法[tm],但它可以工作,并且不需要太多代码
function _foo {
setopt LOCALOPTIONS
unsetopt AUTOPUSHD
local paths
paths=(/home/dani '/var/log' '/usr/share' '/etc')
if [[ $PREFIX == *'/'* ]] {
for p ($paths) {
if [[ ${PREFIX[(ws:/:)1]} == ${p:t} ]] {
local oldpwd=$PWD
cd -q ${p:h}
local matches
matches=($PREFIX*(/))
if [[ ${#matches} -gt 0 ]] {
compadd -p ${matches[1]:h}'/' -q -S '/' -- ${matches:t}
}
cd -q $oldpwd
return
}
}
} else {
compadd -q -S '/' -- ${^paths:t}
}
}
compdef _foo foo
d中定义的目录列表是否与完成相关?你的例子在这方面不是很清楚。参数是否已修复,以便您可以将其硬写入完成函数或基于目录内容的变量?很抱歉,这不清楚。d确实定义了某种搜索路径。例如,条目~/other/dir/baz意味着baz是一个有效的参数,但是假设~/other/dir/baz/subdir存在,baz/subdir也是有效的参数。这意味着我需要使用某种两级方法。对于第一部分,提供一个尾部部分的列表就足够了==$entry:d。对于第二部分,即要完成baz/s,我首先需要找出baz实际上指的是~/other/dir/baz,并根据其中找到的子目录完成。我希望这能让它更清楚一点。在d中定义的目录列表与完成有关系吗?你的例子在这方面不是很清楚。参数是否已修复,以便您可以将其硬写入完成函数或基于目录内容的变量?很抱歉,这不清楚。d确实定义了某种搜索路径。例如,条目~/other/dir/baz意味着baz是一个有效的参数,但是假设~/other/dir/baz/subdir存在,baz/subdir也是有效的参数。这意味着我需要使用某种两级方法。对于第一部分,提供一个尾部部分的列表就足够了==$entry:d。对于第二部分,即要完成baz/s,我首先需要找出baz实际上指的是~/other/dir/baz,并根据其中找到的子目录完成。我希望这能让事情变得更清楚一点。谢谢你迄今为止的帮助!:不幸的是,我需要一种结合这两种方法的方法。有关详细信息,请参阅对您其他评论的回复。@dani_l希望这对您有用。我已经学会了很多-以前从未玩过compctl。感谢您迄今为止的帮助!:不幸的是,我需要一种结合这两种方法的方法。有关详细信息,请参阅对您其他评论的回复。@dani_l希望这对您有用。我学到了很多东西——以前从未玩过compctl。