基于多路径的自定义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。