vimのファイル検索プラグインctrlp.vimの設定

vimのファイル検索用のプラグインctrlpを紹介します。
数あるvimのプラグインの中でも私の特にお気に入りのプラグインの1つです。

参考:私が使用している便利なプラグイン一覧
vim とても強力なプラグインたち

ctrlp.vimとは?

vimファイル検索用のプラグイン。
シンプルかつ高速にファイルを検索し、開くことができます。
検索には正規表現や曖昧検索による絞り込みもでき、隠しファイルの検索のオンオフを切り替えることができるなど、色々な機能が備わっていてとても重宝しています。

vimには色々なファイル検索用のプラグインがありますが、ctrlpは特にファイル検索が高速なように思います。

githubのkien/ctrlp.vimというかリポジトリで開発、管理されています。
現在は ctrlpvim/ctrlp.vim に移行して管理されています。

ctrlpvim/ctrlp.vimのgithubページはこちら。
https://github.com/ctrlpvim/ctrlp.vim

ちょっとした注意点

ctrlp.vimはファイルのキャッシュを作成し、そのキャッシュをもとにファイル検索を行います。
キャッシュを利用することで高速検索を実現しているのですね。

これが非常にありがたいのですが、ちょっとした弊害も。
新しいファイルを作成した場合、そのファイルはキャッシュに登録されていない訳です。
つまり、そのファイルはctrlpの検索で引っかからない訳です。

そこで、新しいファイルも探したい場合は以下のコマンドで一度キャッシュを消去する必要があります。

:CtrlPClearCache

CtrlPの”P”は大文字です。お間違えのないように。

カスタマイズ

私はプラグイン管理にdeinを使用しているため、deinでの設定(dein.toml内での設定)を以下に記述します。
deinを使用していない方は,hook_add = ”’ ~ ”’ で囲まれた部分を.vimrc等にコピーしてみてください。

特にお勧めの設定は、ファイル名を指定しないでvimを立ち上げた時に自動的にctrlpを起動する設定です。
この設定を使い、キーボードショートカットにvimの起動をわりあてようもんなら、一瞬で狙ったファイルをvimで開けるようになります。

[[plugins]]
repo = 'kien/ctrlp.vim'
hook_add = '''
    " # ctrlpに入るときに呼ばれる関数を定義します。この関数を後に紹介する
    " # g:ctrlp_buffer_funcにセットすることで、ctrlpバッファに入る直前に呼び出されます。
    " # ステータスラインをctrlpで表示しないように、laststatusを0にセットします。
    function! CtrlPEnter()
        set laststatus=0
    endfunction

    " # ctrlpから出るとき,ステータスラインの表示をonにします
    function! CtrlPLeave()
        set laststatus=2
    endfunction

    " # ctrlpバッファに入る時と出るときに使用する関数を定義します。
    " # 先ほど定義した関数名をそれぞれenter,exitにセットします。
    let g:ctrlp_buffer_func = {
        \ 'enter': 'CtrlPEnter',
        \ 'exit': 'CtrlPLeave',
    \ }

    " # ファイルを指定せずにvimを立ち上げた時に,自動的にctrlpを起動する関数を定義
    function CtrlPIfEmpty()
        if @% == ""
            CtrlP ~/
        endif
    endfunction

    " # auto command にて先ほど定義した関数をvim起動時に呼び出し。
    augroup AutoCtrlP
        autocmd! autocmd VimEnter * call CtrlPIfEmpty()
    augroup END

    " # ctrlpのキーマッピングを <C-p>から<Leader>eに変更
    " # 私の場合、yankround.vimで<C-p>を使用しているため、衝突回避
    let g:ctrlp_map = '<nop>'
    nnoremap <Leader>e :CtrlP ~/<CR>

    " # 日本語検索をoff(私は基本的にディレクトリやファイル名に日本語を使用しないので)
    let g:ctrlp_use_migemo = 0
    " # あいまい検索をoff
    let g:ctrlp_regexp = 1
    " # キャッシュを使用して検索を高速化
    let g:ctrlp_use_caching = 1
    " # vim終了時にキャッシュをクリアしない
    let g:ctrlp_clear_cache_on_exit = 0
    " # <C-r>でキャッシュをクリアして再検索
    let g:ctrlp_prompt_mappings = { 'PrtClearCache()': ['<C-r>'] }
    " # 検索の際に200[ms]のウェイトを入れる(1文字入力の度に検索結果がコロコロ変わるのが気に入らないため)
    let g:ctrlp_lazy_update = 200
    " # 検索結果の表示ウィンドウの設定,10件分を表示(それ以上になってもスクロールされる)
    let g:ctrlp_match_window = 'bottom,order:btt,min:1,max:10,results:50'
    " # 隠しファイルを表示しない
    let g:ctrlp_show_hidden = 0
    " # 検索してほしくないファイルやディレクトリを除外
    " # ブログの仕様上、半角ドルマークを使用すると編集時に不具合が生じるため、
    " # 以下では全角のドルマークを使用しています。コピーの際にはご注意ください。
    let g:ctrlp_custom_ignore = {
        \ 'dir': '\v[\/]\.(git|hg|svn)$',
        \ 'file': '\v\.(exe|so|dll|o)$',
        \ 'link': 'some_bad_symbolic_links'
        \ }
    " # ctrlpの検索アルゴリズムを変更してみる。コマンド内の %s は検索対象ディレクトリにctrlp内で置き換えられる。
    " # macにてfindコマンドを使用する場合。
    let g:ctrlp_user_command = "find -E %s -type f -regex " . g:ctrlp_my_regexp . " 2>/dev/null"
    " # rcコマンド(ripgrep)が使用できる場合、そちらを使用。
    if executable('rg')
        let g:ctrlp_user_command = 'rg --color never --no-messages --files %s | rg --color never ' . g:ctrlp_my_regexp
    " # agコマンド(the silver searcher)が使用できる場合、そちらを使用。
    elseif executable('ag')
        let g:ctrlp_user_command = "ag --nocolor --silent -g " . g:ctrlp_my_regexp . " %s"
    endif

補足説明

function! CtrlPEnter(), CtrlpLeave()
lightline.vimで
私はステータスラインを表示し、lightline.vimというプラグインにてステータスラインをカスタマイズしているのですが、このステータスラインはCtrlPウィンドウで表示されて欲しくないので、 set laststatus=0 にて表示をオフにしています。

CtrlPEnter()・ CtrlpLeave()という関数はg:ctrlp_buffer_funcという変数にセットすることで、ctrlpに入る・抜けるタイミングで実行されるようになっています。定

function! CtrlPIfEmpty()
ファイル名が空の場合にCtrlPを立ち上げてくれる関数を定義しています。
if @% == ""という条件分岐にて、vimがファイル名の指定なしで起動した場合にctrlpを呼び出します。

この関数をautocmdにてvim起動時に呼ばれるように設定することで、ファイルを指定せずにvimを起動した際に、開きたいファイルを高速で絞り込めるようになります。

let g:ctrlp_use_caching=1
let g:ctrlp_clear_cache_on_exit = 0
この設定は好みが分かれる部分かとは思います。まず、ctrlp_use_cachingを1にセットすると、ctrlpはキャッシュを利用してファイル検索を実行します。キャッシュ生成のため、初回の検索のみ処理に時間がかかりますが、以降は高速検索が可能です。
ctrlp_clear_cache_on_exitを1にセットすると、vim終了時にctrlpはキャッシュを破棄しますので、次回vim起動時の最初のctrlp検索時に再度キャッシュ生成が必要となります。
ctrlp_clear_cache_on_exitを0にセットするとキャッシュが使いまわされますが、検索ディレクトリのファイル数が増えたり減ったりした場合に正しく反映されなくなるので、ファイルの増減があった際には :CtrlPClearCache を呼ぶ必要が出てきます。

毎度タイプするのは面倒なので、私は以下のようにマッピングしています。

nnoremap <silent> <Leader>e :CtrlP ~/<CR>
nnoremap <silent> <Leader>E :CtrlPClearCache<CR>:CtrlP ~/<CR>

g:ctrlp_user_command
この変数に検索時に使用したいコマンド文字列をセットすると、ファイル検索アルゴリズムがCtrlPのデフォルトのものからセットした検索コマンドに置き換わります。筆者はデフォルトのものからripgrepという爆速検索コマンドに置き換えています。

キーマッピングの変更
Ctrl + p というキーマッピングが私の使用しているyankround.vimというプラグインの設定とバッティングしているため、キーマッピングを <C-p> から <Leader>e に変更しています。

<C-p>コマンドが他の設定と被っている場合にはctrlpの(もしくは被っている他のコマンド)のマッピングを変更してあげましょう。

検索時に表示される先頭の文字列を変更する
小ネタですが、こんなのもあります。デフォルトでの検索結果は > [ファイル名] ですが、 * [ファイル名] とかに変更することも可能です。

 let g:ctrlp_line_prefix = '* '

この部分をアイコンフォントにしてみると、見栄えがよくなりそうですね。

追記(管理リポジトリの変更)

記事の上部でも少し記述しましたが、ctrlp.vimを管理しているリポジトリに変更がありました。
以前まではkein/ctrlp.vimというgithubのページで管理されていましたが、現在は

kein/ctrlp.vim   →   ctrlpvim/ctrlp.vim

というリポジトリに変更されています。

古いリポジトリ、kien/ctrlp.vimのreadmeに以下のような記述があります。

#This project is unmaintained You should use this fork instead.
このプロジェクトはもうメンテナンスされた無いから代わりにこっちをつかってね。

今後の更新はctrlpvim/ctrlp.vimというリポジトリで行われるようですので、
古いリポジトリのプラグインをお使いの方は早いうちに新しいリポジトリのものに更新した方が良いでしょう。

参考:私が使用している便利なプラグイン一覧
vim とても強力なプラグインたち