zshのzstyleでの補完時の挙動について

f:id:voidy21:20090903034650p:image

zshというシェルはデフォルトでも素晴らしいのですが、あまりに拡張性が高いので全ての機能を使いこなすのは逆に難しいと思います。
特にzstyleというコマンドの文脈に応じた補完候補への設定関数は、使用するとどうなるのかヘルプを見てもWeb上を見てもよく分かりません。
そんなわけでzstyleの挙動について調べてみました。

準備

色の定義をしておくと後々楽だと思います。
補完キーはCtrl-iに設定しました。
以下を($HOME)/.zshrcに書いておきます(必要なのは色の設定だけなので、別に全部書く必要は無いです。)
自分はこんな感じにしています。(.zshrcの一部を抜粋)

#色の定義
local DEFAULT=$'%{^[[m%}'$
local RED=$'%{^[[1;31m%}'$
local GREEN=$'%{^[[1;32m%}'$
local YELLOW=$'%{^[[1;33m%}'$
local BLUE=$'%{^[[1;34m%}'$
local PURPLE=$'%{^[[1;35m%}'$
local LIGHT_BLUE=$'%{^[[1;36m%}'$
local WHITE=$'%{^[[1;37m%}'$
#補完に関するオプション
setopt auto_param_slash      # ディレクトリ名の補完で末尾の / を自動的に付加し、次の補完に備える
setopt mark_dirs             # ファイル名の展開でディレクトリにマッチした場合 末尾に / を付加
setopt list_types            # 補完候補一覧でファイルの種別を識別マーク表示 (訳注:ls -F の記号)
setopt auto_menu             # 補完キー連打で順に補完候補を自動で補完
setopt auto_param_keys       # カッコの対応などを自動的に補完
setopt interactive_comments  # コマンドラインでも # 以降をコメントと見なす
setopt magic_equal_subst     # コマンドラインの引数で --prefix=/usr などの = 以降でも補完できる

setopt complete_in_word      # 語の途中でもカーソル位置で補完
setopt always_last_prompt    # カーソル位置は保持したままファイル名一覧を順次その場で表示

setopt print_eight_bit  #日本語ファイル名等8ビットを通す
setopt extended_glob  # 拡張グロブで補完(~とか^とか。例えばless *.txt~memo.txt ならmemo.txt 以外の *.txt にマッチ)
setopt globdots     # 明確なドットの指定なしで.から始まるファイルをマッチ

bindkey "^I" menu-complete   # 展開する前に補完候補を出させる(Ctrl-iで補完するようにする)

zstyleのフォーマットについて

これがまたすごくいい感じに意味不明なんですが、

zstyle ':completion:*:*:コマンド:*:タグ' スタイル

のような感じで定義していきます。
細かいことはとりあえずhttp://www.gentei.org/~yuuji/rec/pc/zsh/zshcompsys.txtを見ればちょっとだけ分かったような気になります。
ヘルプを読むためのヘルプが必要な時点で完全に理解するのはたぶん無理です!
書いて試してみれば割となんとかなるので、気にせず書いていきましょう。

zstyleをどんどん書いていく

補完候補を ←↓↑→ でも選択出来るようにする

zstyle ':completion:*:default' menu select=2

自分の場合はCtrl-iをゴリゴリ押すか、Ctrl-f,Ctrl-bでたまに横方向に移動させてます。
そしてCtrl-m(Enterと同じ)で決定させます。

補完関数の表示を過剰にする編

zstyle ':completion:*' verbose yes
zstyle ':completion:*' completer _expand _complete _match _prefix _approximate _list _history
zstyle ':completion:*:messages' format $YELLOW'%d'$DEFAULT
zstyle ':completion:*:warnings' format $RED'No matches for:'$YELLOW' %d'$DEFAULT
zstyle ':completion:*:descriptions' format $YELLOW'completing %B%d%b'$DEFAULT
zstyle ':completion:*:corrections' format $YELLOW'%B%d '$RED'(errors: %e)%b'$DEFAULT
zstyle ':completion:*:options' description 'yes'
# グループ名に空文字列を指定すると,マッチ対象のタグ名がグループ名に使われる。
# したがって,すべての マッチ種別を別々に表示させたいなら以下のようにする
zstyle ':completion:*' group-name ''

補完するときに、ただ補完候補を出すだけでなく、コマンドの文脈に応じて何の補完をするか表示してくれます。
2行目のCompleter(補完システム)は色々種類があって、

_complete
普通の補完関数
_approximate
ミススペルを訂正した上で補完を行う。
_match
*などのグロブによってコマンドを補完できる(例えばvi* と打つとviとかvimとか補完候補が表示される)
_expand
グロブや変数の展開を行う。もともとあった展開と比べて、細かい制御が可能
_history
履歴から補完を行う。_history_complete_wordから使われる
_prefix
カーソルの位置で補完を行う

などのような補完候補を表示できます。
f:id:voidy21:20090903034753p:image
この場合、_approximateコンプリータによってミススペルが修正されて補完されているのがわかりますね!


また、グロブによっての補完もできます。
f:id:voidy21:20090903034926p:image
この場合、通常のzshならばここで補完しようとすると全てのファイルが展開されてしまうのですが、
展開する前に補完する設定にしたので次のように表示されます
f:id:voidy21:20090903034921p:image
個人的にはこちらの挙動の方が好きです。(実はCtrl-dでも展開せずに補完できるけど、全てCtrl-iにやらせるのがポイント)

オブジェクトファイルとか中間ファイルとかはfileとして補完させない

zstyle ':completion:*:*files' ignored-patterns '*?.o' '*?~' '*\#'

補完してほしくないファイルを表示させないようにできるので便利

ディレクトリを切り替える時の色々な補完スタイル

#あらかじめcdpathを適当に設定しておく
cdpath=(~ ~/myapp/gae/ ~/myapp/gae/google_appengine/demos/)
# カレントディレクトリに候補がない場合のみ cdpath 上のディレクトリを候補に出す
zstyle ':completion:*:cd:*' tag-order local-directories path-directories
#cd は親ディレクトリからカレントディレクトリを選択しないので表示させないようにする (例: cd ../<TAB>):
zstyle ':completion:*:cd:*' ignore-parents parent pwd
#LS_COLORSを設定しておく
export LS_COLORS='di=34:ln=35:so=32:pi=33:ex=31:bd=46;34:cd=43;34:su=41;30:sg=46;30:tw=42;30:ow=43;30'
#ファイル補完候補に色を付ける
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}

例えばcdpathを設定しておいて、上のzstyleを適用させると
f:id:voidy21:20090903035130p:image
lsをしたところaから始まるディレクトリは無いみたいですが・・・
ここで補完キーを押すと
f:id:voidy21:20090903035127p:image
cdpath上のディレクトリを勝手に補完してくれます!


あと、cdしたらいちいちlsするのがめんどくさいので、

#cdを打ったら自動的にlsを打ってくれる関数
function cd(){
    builtin cd $@ && ls;
}

を定義しておくと
f:id:voidy21:20090903040742p:image

のようになります!

apt-getとかdpkgコマンドをキャッシュを使って速くする

zstyle ':completion:*' use-cache true

特にsudo apt-get updateがめちゃめちゃ速くなります!

セパレータを設定する

zstyle ':completion:*' list-separator '-->'

オプションとかを表示するときのセパレータを指定します。(デフォルトは'--'です。)
別に設定しなくてもいいですが、zshはここまでも設定できるということで!
f:id:voidy21:20090903035715p:image
例えば、ここで補完ボタンを押すと・・・
f:id:voidy21:20090903035714p:image
のようになります。

変数の添字を補完する

zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters

別に補完できなくてもいいんですが、そういう機能もあると紹介してみます。
f:id:voidy21:20090903035538p:image
こういう配列を定義しておいて、ここで補完ボタンを押すと・・・
f:id:voidy21:20090903035537p:image
のようになります。
zshの配列の添字は1から始まるのか!!!?

manの補完をセクション番号別に表示させる

zstyle ':completion:*:manuals' separate-sections true

一番どうでもいいかもしれない補完ですね!
manのセクション番号についてはhttp://www.linux.or.jp/JF/JFdocs/Man-Page-2.htmlに載っています。
これを適用すると・・・
f:id:voidy21:20090903035750p:image

のようになります。

最後に

まとめて紹介しすぎたので今回はこれで締めますが、
他にも色々とあるので、また別の機会に紹介します!