2

ディレクトリを引数として受け入れるコマンドのカスタム補完を書きたいです。例を使用してどのように機能するかを説明するのが最も簡単だと思います。

どこかに定義されたディレクトリのリストがあるとしましょう:

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 の複雑さに少し戸惑っているので、これに最善の方法でアプローチする方法が本当にわかりません。

4

2 に答える 2

7

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 

2. ディレクトリ内のすべてのサブディレクトリへの完了

fooのサブディレクトリが の有効なパスであると仮定するとmycmd:

~/foo/bar         # Valid path
~/foo/subdir/baz  # Valid path
~/baz/bar         # Invalid path

への引数としてcompctl内の任意のディレクトリを完了するように指示できます。foomycmd

# In your ~/.zshrc
compctl -/ -W ~/foo mycmd

これがあなたが書いた他の補完関数とどれだけうまく機能するかわかりませんmycmd(たとえば、mycmdファイル名以外の引数も取る場合)。次のように完了します。

zsh% mycmd<TAB>
bar/  baz/  caz/
zsh% mycmd baz/s<TAB>
zsh% mycmd baz/subdir/

注: パス / コマンドが少し長くなりました。以下のペーストの一部を切り取りました ( に置き換えました...)。

3. 定義済み配列の使用。

配列d=(foo bar baz)があり、各要素が の有効な補完である場合mycmd、次を使用できます-k

→ compctl -k "(foo bar baz)" mycmd
→ mycmd
bar  baz  foo

4. 配列のサブディレクトリ。

次のディレクトリ構造を使用します。

~/.../somedir
~/.../somedir/bar
~/.../somedir/foo
~/.../somedir/foo/invalid
~/.../otherdir
~/.../otherdir/subdir
~/.../otherdir/subdir/baz

-Wオプションcompctlも引数として配列を取り、これを可能にします:

→ compctl -/ -W "(/.../otherdir /.../somedir)" mycmd
→ mycmd <TAB>
bar/     foo/     subdir/

これはあなたが望むものと一致すると確信しています。
注:この-Wオプションは-/( のマニュアル ページを参照zshcompctl) で動作します --W単独では動作しません。

5. 部分的なサブディレクトリを持つ配列

有効な引数が次のとおりであると仮定しましょう。

mycmd foo  # Valid
mycmd baz  # Valid
mycmd baz/and/some/subdir # Valid - subdirectory of `baz`
mycmd foo/subdir # Invalid!! 

のサブディレクトリは必要ありませ。これは、とを混合することで実現できます。foobaz-k-/ -W

→ compctl -/ -W "(/.../otherdir)" -k "(/.../somedir/foo)" mycmd
→ mycmd <TAB>
/Users/simont/sandbox/completion/somedir/foo  subdir/ 
→ mycmd foo/<TAB> # No further completion - we can't complete foo/invalid. 
→ mycmd subdir/<TAB>
→ mycmd subdir/baz/

ただし、これは完全なパスを残します(それを削除するfooとは異なります)。-Wこれを修正するには、 の配列に入れないでください-k:

compctl -/ -W "(/.../otherdir)" -k "(foo)" mycmd
于 2013-01-12T07:13:11.087 に答える
2

助けてくれてありがとう、シモント、しかし私は補完機能を使って別のアプローチを取りました。ほとんどの場合、ドキュメントを読むのではなく試行錯誤に基づいているため、これが正しい方法[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
于 2013-01-12T22:02:23.053 に答える