Vim
neovim

[vim]denite.nvimのgrepの検索結果をquickfixみたいに移動する

More than 1 year has passed since last update.

denite.nvim

uniteからの移行

neovimに移行したのをきっかけにuniteから徐々にdenite.nvimに移行してきました。
ここ2,3ヶ月ぐらいでものすごい勢いで機能が追加されていってるので、もう完全uniteには捨ててdeniteに移行完了出来ました。

で、最近追加された機能でDenite grepがさらに便利になったので、設定のメモ代わりに残しておこうと思います。

インストール

denite.nvimの導入自体は

が分かりやすかったので、これを参考にするのがいいと思います。ここで紹介されているcpsmなども入れるととても快適です。

一応この記事で使っているvimrcファイルも最後の方に載せておきます。

Denite grepがvim標準のgrepより不便だった点

Denite grep使ってますか?便利ですね。
でも、一回grepした後もう一回その結果を見たい場合や、マッチしたファイルに次々飛んでいくのはちょっと不便でしたね。

例えば、標準のvimgrepならquickfixと連動できるので、

:vimgrep dark * | cw

などとすれば、

スクリーンショット 2016-11-16 18.21.28.png

な感じでquickfixのウィンドウが表示されて:cnext, :cpreviousでどんどん移動できます。
denite.nvimでもこれをしたかったわけです。

resume, select, immediatelyオプション

で、ちょっと前にresume, そして(2016/11/16現在)つい2,3日前select, immediatelyというオプションがDenite.nvimに追加されました。
(select, immediatelyに関しては、作者のShougoさんによると、まさに上記の問題を解消するために追加したオプションだそうです)

  • resume
    buffer-nameオプションで起動されたdeniteの候補ウィンドウの名称を指定すると再度その候補ウィンドウを開く

  • select
    候補ウィンドウの中の任意の行に移動する

  • immediately
    Denite起動時にこのオプション付きで実行すると候補が1件でもあればその候補を選択して実行し、Deniteを終了する

resumeオプション

resumeオプションはuniteのときも同等の機能があり私もunite grepで便利に使っていました。
どう動くかというと、通常であれば、

  1. Denite grep実行
  2. grepでマッチした結果の候補ウィンドウが表示される
  3. 候補ウィンドウから選択して実行
  4. Denite終了(候補ウィンドウも消える)

となって、grepの検索結果をもう一度見たい場合にその方法がありませんでした。

で、それを解消するために、buffer-nameオプションというのが用意されていて、上記の1.のときにDeniteに対してbuffer-nameオプションで候補ウィンドウに名前を指定することができます。
さらに、resumeオプションというものが 用意されており、これが指定されていて、buffer-nameオプションが指定されている場合、既に存在しているそのbuffer-nameの候補ウィンドウを再表示することができます。
これを組み合わせてgrepの時に名前を指定して実行, resumeでその名前のバッファを再表示とすればDenite grepの結果をいつでも参照できます。

下記のようになるわけです。

  1. Denite grep -buffer-name=search-buffer-denite
  2. grepでマッチした結果の候補ウィンドウが表示される(この時候補ウィンドウにはsearch-buffer-deniteという名前がつけられる)
  3. 候補ウィンドウから選択して実行
  4. Denite終了(候補ウィンドウも一旦見えなくなる)
  5. Denite -resume -buffer-name=search-buffer-denite で再度候補ウィンドウを表示
  6. 3.に戻る

を繰り返してgrepの検索結果を何度も参照出来るようになります。

select, immediately

・・・が、それでもまだメンドイわけです。
いちいち候補ウィンドウを再表示して候補を次に進めてEnterカッシャーンの繰り返し。

そう思っているところに、select, immediatelyオプションというのが同時に追加されました。
概要は↑で書いたとおりですが、これらのオプションとresumeを組み合わせることで、

1.grepの検索結果を再表示して(resume)
2.次の検索結果にカーソルを移動して(select)
3.しかもそれらをDeniteの候補ウィンドウを見ること無く自動的にそのファイルを開く(immediately)

ということが出来るようになりました。

具体的には、selectオプションは候補ウィンドウの中の指定された行数に移動した状態でDeniteウィンドウを開くというものなのですが、特別に+1, -1という指定が出来るようになっており、それぞれ今のカーソル位置から次の行, 前の行に移動できます。普通は1行目からになるのですが、
resumeを使って再表示する場合そこからの, になるので、どんどん移動していけるようになります。
これらを考慮して、キーマップしておくと、まるでquickfixcn, cpしているかのようにサクサク移動できます。

でそのキーマップのサンプルが下記です。
ここでは<C-u>Deniteの用のプレフィックスキーとして、

  • <C-u>gでgrep検索
  • <C-u>rでgrep検索結果の再表示
  • <C-u>nの検索結果へ移動
  • <C-u>pの検索結果へ移動

というマッピングにしています。

おそらくこれ1つでいけるであろう最小のvimrcです。neovimpython3環境が整ってないと動かないかもしれません。
前半がdeniteのインストールで後半がdeniteの設定です。

vimrc
let g:python3_host_prog = '/usr/local/bin/python3'

let s:dein_dir = expand('~/.cache/dein2')
let s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo/dein.vim'

if &runtimepath !~# '/dein.vim'
  if !isdirectory(s:dein_repo_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_repo_dir
  endif
  execute 'set runtimepath^=' . fnamemodify(s:dein_repo_dir, ':p')
endif

call dein#begin(s:dein_dir)

call dein#add('Shougo/denite.nvim')

call dein#end()
call dein#save_state()

if dein#check_install()
  call dein#install()
endif

" Deniteの設定
nnoremap [denite] <Nop>
nmap <C-u> [denite]

" -buffer-name=
nnoremap <silent> [denite]g  :<C-u>Denite grep -buffer-name=search-buffer-denite<CR>

" Denite grep検索結果を再表示する
nnoremap <silent> [denite]r :<C-u>Denite -resume -buffer-name=search-buffer-denite<CR>
" resumeした検索結果の次の行の結果へ飛ぶ
nnoremap <silent> [denite]n :<C-u>Denite -resume -buffer-name=search-buffer-denite -select=+1 -immediately<CR>
" resumeした検索結果の前の行の結果へ飛ぶ
nnoremap <silent> [denite]p :<C-u>Denite -resume -buffer-name=search-buffer-denite -select=-1 -immediately<CR>

サンプル

カレントディレクトリに下記のような4ファイルがある状態でdarkというワードをgrepしたときの様子を動画にしてみました。

% find . -name '*.txt' -print -exec cat {} \;
./1.txt
dark powered in 1.txt
./2.txt
dark powered in 2.txt
./3.txt
dark powered in 3.txt
./4.txt
dark powered in 4.txt

https://asciinema.org/a/92959

んーあんまり移動している感がわかりにくいですが。。

追記

Shougoさんより、-resume=true, -immediately=trueではなく、 -resume, -immediately、とするのが正しいとの指摘を受けたので修正しました。