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

# denite.nvim

## uniteからの移行

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

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

## インストール

`denite.nvim`の導入自体は

 - [unite.vimより高速な発達中のdenite.nvimを使う](http://qiita.com/okamos/items/4e1665ecd416ef77df7c)

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

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

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

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

  `:vimgrep dark * | cw`

などとすれば、

<img width="318" alt="スクリーンショット 2016-11-16 18.21.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/34692/c974f003-8295-676c-9e1f-fc1d5c60b066.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`を使って再表示する場合そこからの`次`, `前`になるので、どんどん移動していけるようになります。
これらを考慮して、キーマップしておくと、まるで`quickfix`で`cn`, `cp`しているかのようにサクサク移動できます。

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

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

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

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

```vim: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`、とするのが正しいとの指摘を受けたので修正しました。