2017-04-22

zshの補完関数を作ってみた

zshの補完関数を作ったときの備忘録

作成方法

zshは以下のような記述をすると対象のコマンドに対して補完をかけてくれるようになります。
function fuga() {
  _values '' 'foo' 'bar'
}

compdef fuga hoge # hogeコマンドに対して関数fugaを使って補完する

compdefを直接呼び出す場合は補完関数の名前は何でもOKで、慣習的には_{コマンド名}という関数名にします。

また、zshには$fpathや$FPATHという環境変数が定義されていて、そのパスにあるシェル関数を自動で読み込んでくれます。zsh補完関数もfpathに設置することができ、その場合は以下のように記述して_{コマンド名}のファイル名でfpathに置けば補完が効くようになります。

#compdef hoge

_values '' 'foo' 'bar'

macOSの場合は、/usr/local/share/zsh/site-functionsがfpathの一つになっているので、迷ったらここに置けばOKです。

補完関数のリロード

以下のスクリプトで補完関数をリロードできます
unfunction _hoge && autoload -U _hoge

_values

事前に決まっている値や特定のディレクトリ 内のファイルを表示する場合には_values関数で補完可能です。
_values 'group1' 'foo[aaa bbb]' 'bar'

最初の引数はグループ名、[]内は補完候補の説明文になります。

特定のディレクトリ内のファイルを表示する場合は以下のように記述します

_values 'group1' ~/hoge/*

-sオプションを指定すると、補完候補から選択した文字列をセパレータで連結してくれるようになります。

_values -s , '' "a" "b" "c" "d"

_files

_files関数を使えばファイルを補完候補として表示することが可能です。具体的には以下のように使います。
_files -W ~/hoge

これでhoge直下のファイル/ディレクトリ名が補完候補として表示されます。

_arguments

複雑な補完処理をする場合は_argumentsを使います。
_arguments '-h[hoge]: :->foo' \
   '-f[fuga]: :->bar' \
   '1: :->first'

case "$state" in
  foo)
    _files -W ~/foo
    ;;
  bar)
    _files -W ~/bar
    ;;
  first)
    _values '' '-h' '-f' 'aaa' 'bbb' 'ccc'
    ;;
esac

上記の例だと-hを入力したあとには~/foo直下のファイル/ディレクトリが補完候補になり、-fだと~/barが補完候補になります。また、1番目の引数の補完対象を明示的に指定しています。_argumentsの引数はTAG:DESCRIPTION:ACTIONで記述します。アクションで->{state}と記述するとstate変数に値がセットされるので、後続の処理で補完候補を切り替えることができます。アクションに関数名を記述すると、その関数に処理が渡ります。

homebrewで補完関数をインストールしたい

zsh_completion.installで補完関数のファイルのリンクを/usr/local/share/zsh/site-functionsのディレクトリ直下に置いてくれます。
option "without-completions", "Disable zsh completions"
...
def install
  bin.install 'hoge'
  if build.with? 'completions'
    zsh_completion.install '_hoge'
  end
end
...

optionとbuild.with?は付けなくても動きますが、自前で補完したい人もいそうなので、補完関数をインストールしないという選択肢をFormulaに入れておいた方が良さそうです。

参考URL

このエントリーをはてなブックマークに追加