CtrlPのヘルプのカスタム・コマンドの項に記載があるように、Gitのls-files
サブコマンドを使ったカスタム・コマンドを定義すると、.gitignore
を考慮してファイルをリストアップすることができる。ただ常にこちらである必要はないので、Git管理下だけでそうなるようにしたい。その場合、ラッパー関数を作成して、その中でb:ctrlp_user_command
を設定してやると良さそうだ。
Git配下のファイルかどうかでCtrlPを切り替えるで作成した関数を元にして、v:shell_error
が0
の時も特別視してやるようにすることで実装した。カスタム・コマンドはヘルプのまま、Gitリポジトリーのルートへ移動してls-files
サブコマンドを呼んでいる。
nnoremap <Leader>f :call <SID>CallCtrlPBasedOnGitStatus()<Return>
function! s:CallCtrlPBasedOnGitStatus()
if exists('b:ctrlp_user_command')
unlet b:ctrlp_user_command
endif
let s:git_status = system('git rev-parse --is-inside-git-dir')
if v:shell_error == 0
let b:ctrlp_user_command = ['.git', 'cd %s && git ls-files']
execute 'CtrlP'
elseif v:shell_error == 128
execute 'CtrlPCurFile'
else
execute 'CtrlP'
endif
endfunction
まずバッファー・ローカルの変数にカスタム・コマンドの設定があったら削除しておく。そうしないと変数の型の問題で、定義を上書き出来なかったりすることがあるからだ。
その後、Gitのrev-parse
サブコマンドを--is-inside-git-dir
オプションを指定して呼ぶことで、カレント・ディレクトリーがGit管理下かどうかをチェックする。一応標準出力は拾っておくが、判断は終了コードのみで行う。
終了コードが0
の場合はls-files
サブコマンドを呼ぶようにバッファー・ローカルの変数を設定してやり、普通にCtrlPを呼ぶ。128
は管理下でなかった場合なので、その時は編集中のファイルのディレクトリーを使ってCtrlPを呼ぶようにCtrlPCurFile
を呼ぶ。変な終了コードが返ってきた場合のフォールバックとして、カスタム・コマンドを設定せずにCtrlPを呼ぶようにもしておいた。
うまく動いている気がする。autocommandを使ってバッファーを読み込んだ時にb:ctrlp_user_command
を設定しても良さそうだったが、バッファー開く度にGitが呼ばれるのはちょっとコストが高い。なのでCtrlPを呼ぼうとした時にフックするように作った。CtrlPをつかう頻度によってはautocommandの方が効率的かもしれない。
ただし、WindowsのVimでset shell=sh
かつset shellslash
している場合、CtrlPがカスタム・コマンドを呼ぶ時にカレント・ディレクトリーのパス情報をバックスラッシュに変換してしまうためうまく動かない。CtrlPの修正が必要になるようだ。僕はとりあえずautoload/ctrlp.vim
の405行目をコメントアウトして凌いでみている。
コマンドの短縮形ばかりで書かれているVimスクリプト読みづらいな。