svnの補完関数を書こう(2) -サブコマンド-
svnは、第一引数にサブコマンドを取る。
$ svn add hoge.c $ svn commit
なので、まずはこのサブコマンドの補完関数を用意する。
完成するとこうなる。
$ svn ^D Subversion command ? cleanup diff log pe propedit rename switch add co export ls pedit propget resolved unlock ann commit h merge pg proplist revert up annotate copy help mkdir pget propset rm update blame cp import move pl ps st cat del info mv plist pset stat checkout delete list pd praise remove status ci di lock pdel propdel ren sw
KSH_AUTOLOADへの対応
まずは移植性を上げるための工夫を。
補完関数は自動的にロード(autoload)される必要がある。しかしその自動ロードの挙動は、KSH_AUTOLOADオプションが設定されているかどうかで異なる。
KSH_AUTOLOADが設定されていない場合、_fnの内容はファイル_fnに記述されてた内容となる。
しかし、設定されている場合は、_fnに記述された_fn関数の中身になる。
_fn(){ # KSH_AUTOLOADが設定されている場合 } # KSH_AUTOLOADが設定されていない場合
なので、KSH_AUTOLOADが設定されているかどうかにかかわらず動くようにするために、次のようにする。
#compdef svn colorsvn _svn(){ # 補完関数の中身 } _svn "$@"
サブコマンドの補完
まずは、サブコマンドを補完するべきかどうかを調べる必要がある。
そのためにCURRENTというパラメータを調べる。これには、今何個目の引数に対する補完を行っているかが格納されている。
# ((...))で算術演算が行える if ((CURRENT > 2)); then # サブコマンドに対する補完 else # サブコマンドの補完 fi
あとはサブコマンドのリストをシステムに渡してやればいい。そのために_describeという関数を用いる。これは、
_describe -t <タグ名> <説明> <補完リスト>
という形式をとる。ただし補完リストは実行時に展開されるので、候補のリストではなく、候補のリストを格納した変数名を渡してやる。
なので、次のようになる。
local -a cmd cmd=(add commit) _describe -t svn-command "Subversion command" cmd
ただし、全部のサブコマンドを列挙するのは面倒なのでsvn helpとsedをつかって横着する。
local line local -a cmd _call_program help-command svn help \ | sed -n '/^ /s/[(), ]/ /gp' \ | while read -A line; do cmd=($line $cmd) done _describe -t svn-command "Subversion command" cmd
_call_programを使えば、エキスパートはHackしやすくなるらしいですよ、奥さん。
結果
#compdef svn colorsvn _svn(){ if ((CURRENT > 2)); then # サブコマンドに対する補完 else # サブコマンドの補完 local line local -a cmd _call_program help-command svn help \ | sed -n '/^ /s/[(), ]/ /gp' \ | while read -A line; do cmd=($line $cmd) done _describe -t svn-command 'Subversion command' cmd fi } _svn "$@"