LoginSignup
26
26

More than 5 years have passed since last update.

zshの補完ファイルの中で呼ばれているコマンドを差し替えてカスタマイズする

Last updated at Posted at 2014-10-04

何がしたいか

Qiitaに次の投稿がありました。

Capistranoのタスクをzshで補完したい - Qiita

zsh-completions/_capを使うと、zshでcapコマンドの補完ができるようになります。しかし、capコマンドをグローバルにインストールしたのではなくbundle installでインストールしている状態ではうまく補完ができない、という問題です。これを解決します。

なんでだめなのか

なぜうまくいかないのでしょうか。_capの中身を見てみると分かります。

src/_cap
cmds=( ${(f)"$(_call_program commands cap -T 2> /dev/null | sed -e '/ # /!d; s/:/\\:/g; s/cap \([A-Za-z0-9\\:_-]*\) .*# /\1:/')"} )

このcap -Tという箇所がポイントです。cap -Tは、Capistranoのタスク一覧を表示するコマンドです。

% cap -T
cap deploy                         # Deploy a new release
cap deploy:check                   # Check required files and directories exist
cap deploy:check:directories       # Check shared and release directories exist
(...以下省略...)

_capファイルの中では、cap -Tを呼び出してタスク一覧を取得して、それを元に補完候補を作成しています。capがグローバルにインストールされているときはこれで問題ないのですが、bundle installでインストールしているときはcap -Tを実行してもエラーで実行できません(bundle exec cap -Tとしないと実行できません)。そのために補完候補が作成できていなかったのです。

どうやって対応するか

それでは、この問題にどうやって対応すればよいのでしょうか。一つは_capファイルの中身のcap -Tbundle exec cap -Tに書き換えることです。ただし、この修正をしても将来_capファイルが更新されたときに上書きされてしまうので、その都度改めて直す必要があります。

実は、これには別の修正方法があります。元の_capファイルをもう一度よく見てみると、_call_program commands cap -Tというふうに書かれています。この_call_programは、補完関数から呼び出す外部コマンドを差し替え出来るようにするための仕組みです。

_call_programは「_call_program <タグ名> <コマンド>」という形式で使います。そして、<コマンド>を呼び出すが、もし<タグ名>によって別のコマンドが指定されていたら代わりにそれを呼び出す、という処理を行います。

今回の例の場合は、タグ名は「commands」、コマンドは「cap -T」です。このコマンドを「bundle exec cap -T」に差し替えればうまくいきます。

具体的には、次の行を.zshrcに書きます。

.zshrc
zstyle ':completion::*:cap:*:commands' command 'bundle exec cap -T'

これで_call_programで呼び出されるコマンドがbundle exec cap -Tに置き換わります。さっそく試してみましょう。

zsh_cap.png

うまく補完されています。

指定方法についてのもう少し詳しい説明

さきほどのコマンドを差し替える方法について、もう少し詳しく説明します。この指定方法は、補完対象となるコマンド名などによって書き方が変わります。具体的には、次の形式で指定します。

zstyle ':completion::*:<補完コマンド名>:*:<タグ名>' command <呼び出したいコマンド>

タグ名は補完ファイルの中を見て確認します。今回の例の場合は<補完コマンド名>はcap、タグ名はcommandsです。<呼び出したいコマンド>は、使用している環境によって変わります。今回の例はbundle exec capでcapコマンドを起動するようになっているので「bundle exec cap -T」と指定しました。

他の例を見てみましょう。rakeの補完ファイルはzshに標準で含まれています。たとえば僕のUbuntu環境では、/usr/share/zsh/functions/Completion/Unix/_rakeに補完ファイルがあります。これもcapコマンドと同じように、bundle installでインストールしているとrakeのタスクが補完されません。

_rakeファイルの中を見ると、次のように書かれています($words[1]は現在のコマンドラインの先頭の単語を表します)。

_rake
targets=( ${${(f)"$(_call_program targets $words[1] -sT $opt_args[(I)(-N|--nosearch)] ${(kv)opt_args[(I)(-f|--rakefile)]} 2>/dev/null)"}/(#b)rake ([^ ]##) ##\# (*)/${${match[1]}//:/\\:}:${match[2]:l}} 

_call_programが使われているので、_capのときと同じ要領でコマンドを差し替えできます。次の行を.zshrcに追加します。

.zshrc
zstyle ':completion::*:rake:*:targets' command 'bundle exec rake -sT $opt_args[(I)(-N|--nosearch)] ${(kv)opt_args[(I)(-f|--rakefile)]}'

少し長いですが、元の$words[1]のところをbundle exec rakeに置き換えただけです。これでbundle installしているときにうまく補完できるようになりました。

zshはこうやって補完の動作をカスタマイズできるようになっているので、試してみてください。

26
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
26