unite.vimより高速なdenite.nvimを使う

# [Denite](https://github.com/Shougo/denite.nvim)
> Denite.nvim is a dark powered Neovim unite all interfaces. It resolves unite.vim problems. It is 10 times faster than unite.vim.

暗黒の力を手に入れた云々。早い
パッと動かしたい人は操作方法の項まで見れば動かせる文章構成にしています。

## こんな感じ

[![asciicast](https://asciinema.org/a/bhe0zxf3ol38h29nakfdi74i6.png)](https://asciinema.org/a/bhe0zxf3ol38h29nakfdi74i6)

## インストール
python3を持ってないといけません。
pyenvとpyenv-virtualenvを使っている場合

```bash
# pyenv install 3.5.2
# 2016/9/22 update 後述するcpsmを利用する場合動的リンクを含む以下の方法でインストールしてください。
env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.5.2
pyenv virtualenv 3.5.2 neovim3
pyenv activate neovim3
pip install neovim
```

生のpython3を使っている方は

```bash
pip3 install neovim
```

とかでいいかもしれません。
ここら辺は詳しくは[Neovim Wiki](https://github.com/neovim/neovim/wiki/Installing-Neovim)に懇切丁寧にかいてあるので、こちらを見てみると良いです。

python3のbinを指定してあげます。

```vim:.vimrc
let g:python3_host_prog = expand('~/.pyenv/versions/neovim3/bin/python')
" 上に記載した方法を取っていない方は which python3 とかしてそのPATHを設定してください。
```

neovimを起動して:echo has('python3')で1が返ってきた場合、設定できています。

0が返ってきた場合はどっかの設定が間違っています。vim-jpの方はみなさん優しいので問い合わせましょう。

本体のインストールは使っているプラグインマネージャーによって違うかと思いますが、

```toml:.dein.toml
[[plugins]]
repo = 'Shougo/denite.nvim'
```

こんな感じです。
:UpdateRemotePlugins
をneovimないで呼び出してください。

> remote/host: python3 host registered plugins ['denite', 'deoplete']
> remote/host: generated rplugin manifest: /Users/okamos/.local/share/nvim/rplugin.vim

こんな感じのメッセージが出てくると思います。deniteがあれば成功しています。

## 用例
ここでは大半の人が使うであろうdenite.nvimの実行集をみていきます。
実際に実行してみて、次項の「操作方法」をみながら操作してみてください。

コマンド|候補|候補選択時のアクション
---|---|---
:Denite file_rec|カレントディレクトリ以下のファイル|ファイルを開く
:Denite -auto_preview grep|検索結果（プレビュー付き）|検索結果の行を開く
:DeniteCursorWord grep|検索結果（カーソル以下の文字をインプットにする）|検索結果の行を開く
:Denite -resume|前回のDeniteバッファを再表示する|前回の動作に準ずる
:Denite file_mru|最近開いたバッファ（[neomru.vim](https://github.com/Shougo/neomru.vim)依存）|ファイルを開く
:Denite neoyank|ヤンクの履歴（[neoyank.vim](https://github.com/Shougo/neoyank.vim)依存）|ペースト

file_recやgrepをagに変更する場合はdeniteのプラグイン読み込み終了後に以下のコマンドを実行します。dein.vimを使っている場合`hook_post_source`内に記述すると良いです。

```vim
call denite#custom#var('file_rec', 'command', ['ag', '--follow', '--nocolor', '--nogroup', '-g', ''])
call denite#custom#var('grep', 'command', ['ag'])
call denite#custom#var('grep', 'recursive_opts', [])
call denite#custom#var('grep', 'pattern_opt', [])
call denite#custom#var('grep', 'default_opts', ['--follow', '--no-group', '--no-color'])
```

## 操作方法

### 共通
キー|マップ
---|---
\<Esc\>|以前のモードに戻るか、Deniteのバッファを閉じます
\<C-c\>|Deniteのバッファを閉じます
\<CR\>(Enter)|デフォルトのアクションを実行します
\<C-z\>|Deniteを中断します、CRで再開します

### 挿入モード

キー|マップ
---|---
\<C-h\>|一文字消します
\<BS\>|一文字消します
\<C-w\>|一単語消します
\<C-u\>|一行消します
\<C-g\>|次の行に移動します
\<Tab\>|次の行に移動します
\<C-t\>|前の行に移動します
\<S-Tab\>|前の行に移動します
\<C-j\>|Vimのコマンドラインから文字を入力します
\<C-r\>|レジスタから貼り付けします
\<C-o\>|ノーマルモードに切り替えます
\<C-v\>|プレビューを表示します

### ノーマルモード
キー|マップ
---|---
i|挿入モードに切り替えます
j|次の行に移動します
k|前の行に移動します
g|最初の行に移動します
G|最後の行に移動します
\<C-d\>|ウィンドウの下方向に移動します
\<C-u\>|ウィンドウの上方向に移動します
\<C-f\>|次のページに移動します
\<C-b\>|前のページに移動します
p|プレビューを表示します
q|Deniteのバッファを閉じます
\<Tab\>|アクションを選択します

こうなっています。マッピングは変更可能で、

```vim
call denite#custom#map('insert', "<C-d>", '<denite:delete_char_under_caret>', 'noremap')
```

のようにして追加・修正することが可能です。
`<C-c>`は変更することができません。

## コマンド

コマンド|概要
---|---
:Denite|標準のコマンドです
:DeniteBufferDir|現在開いているバッファのディレクトリをターゲットとして:Deniteを実行します。私は絞り込んでfile_recしたい時によく使います
:DeniteCursorWord|カーソル配下にある言葉をターゲットにして:Deniteを実行します。私はgrepする時によく使います
:DeniteProjectDir|プロジェクトのルートディレクトリ（と思われる箇所）をターゲットとして:Deniteを実行します

## オプション
オプションは`:Denite -options file_rec`のように指定します。
例えば`:Denite -auto_preview -mode=normal file_rec`とするとノーマルモードで自動的にプレビューが開く設定でfile_recを実行します
オプションは頭に`-no-`をつけることで無効化することができます。あまり使う必要は無いでしょうが...

オプション|概要|デフォルト値
---|---|---
-auto-preview|別の候補へ移動した際に自動的にプレビューを開きます|false
-default-action={action}|指定したアクションをデフォルトアクションとします。後述するsplitなどのアクションを指定します|"default"
-immediately|候補が存在する場合デフォルトのアクションを直ちに実行します|false
-input={text}|指定したテキストを入力済みの状態で実行します|""
-mode={mode}|normalかinsertを指定します|"insert"
-quit|アクションを実行後にDeniteのバッファを閉じます。|true
-resume|以前のバッファを使います。|false
-cursor-pos|+1や-1といった番号で指定した候補に移動します。|""
-statusline|ステータスを表示します。デフォルトでオンの機能です|true

## ソース
いわゆる選択候補です

ソース|候補|選択時の動作
---|---|---
buffer|バッファ|バッファに飛びます
colorscheme|カラースキーマ|カラースキーマを変更します
directory_rec|ディレクトリ|チェンジディレクトリします（バッファローカル）
file_rec|ファイル|開きます
filetype|ファイルの種類|filetypeを変更します
command|vimのコマンド|exモードで挿入します
grep|grepの結果|行へ飛びます
help|Vimドキュメント内のタグ|タグに飛びます
menu|予め設定した項目（後述）|デフォルトアクション
file_mru|neomruのmru|ファイルを開く
neo_yank|neoyank.vimのヤンク履歴|ペースト

### menu
以下のように`:call denite#custom#var('menu', 'menus', var)`で設定した項目を列挙して絞り込みアクションできます。

```vim
let s:menus = {}
let s:menus.zsh = { 'description': 'zsh configuration' }
let s:menus.zsh.file_candidates = [
\ ['zshrc', '~/.zshrc'], ['zplug', '~/.init.zplug']]
let s:menus.my_commands = { 'description': 'my commands' }
let s:menus.my_commands.command_candidates = [
\ ['Split the window', 'vnew'], ['Open zsh menu', 'Denite menu:zsh']]

call denite#custom#var('menu', 'menus', s:menus)
```

設定したものは`:Denite menu:zsh`のように呼び出すことができます。
二重の配列になっている配列の一個目が一覧に列挙されます。
`file_candidates`の場合は配列の二個目をファイルとして開き、`command_candidates`では配列の二個目をvimのコマンドとして実行します。
をかけて、アクション（ペースト）します。

## アクションの候補
候補の種類によって実行できるアクションが違います

候補の種類|アクション|概要
---|---|---
コマンド|execute|実行する
ディレクトリ|cd|チェンジディレクトリ
ファイル|open|開く(default)
ファイル|preview|プレビュー
ファイル|tabopen|新しいタブで開く
ファイル|split|水平分割で開く
ファイル|vsplit|垂直分割で開く

## フィルター
候補を絞り込む際に候補と入力のマッチング -> 並び替え -> 出力を整形しているようです。

```vim
call denite#custom#source('file_rec', 'matchers', ['mather_fuzzy'])
```

のようにソース、フィルター、値（配列）で設定します。

フィルター|概要
---|---
matcher_cpsm|高速に絞り込み検索をおこなう[cpsm](https://github.com/nixprime/cpsm)を利用します。詳しくは後述
matcher_fuzzy|いわゆるあいまい検索します(default)
matcher_ignore_globs|globのパターン（複数）を弾いた状態で検索します
matcher_regexp|正規表現で検索します。正規表現を利用する場合はcpsmとfuzzyとチェーンしても意図した結果は得られません
sorter_rank|[selecta](https://github.com/garybernhardt/selecta)というスコアリングアルゴリズムを使って並び替えます。詳しくは知りません
sorter_sublime|おそらく[sublime](https://bit.ly/reverse-engineering-sublime-text-s-fuzzy-match)に使われているスコアリングアルゴリズムを使って並び替えるのでしょう。
converter_relative_word|相対パスを使って候補を出力します

### matcher_cpsmについて
表にあるリンクを見れば大体わかるかと思いますが、一応導入方法を記載しておきます。
OS Xでは依存としてboostがあるので

```bash
brew install boost
```

しておきます。

dein.vimを利用しているなら

```toml:dein.toml
[[plugins]]
repo = 'nixprime/cpsm'
build = 'env PY3=ON ./install.sh'
```

で大丈夫です。env PY3=ONはpython3でビルドするためのオプションでVimが+python3になっている場合は自動検出されてpython3でビルドされるようです。（私はneovimしか使っていないので使っています）
ここで動的リンクが検出されるのですが、pyenvだと上述の `env PYTHON_CONFIGURE_OPTS="--enable-framework"` でpythonをインストールしている必要があるそうです。
動的リンクが必要なことまでは理解していたのですが、よくわからなくなってIssue立てちゃいました...作者であるnixprime氏が数時間後にこの回答をしてくれてすごく助かりました。

```vim
call denite#custom#source('file_rec', 'matcher', ['matcher_cpsm'])
```

matcherを変更する場合は上述のように書きます。

## 応用
リンクされた記事からの受け売りですが、

```vim
:Denite -resume -immediately -cursor-pos=+1 "以前のバッファで次の候補を即座に開く
:Denite -resume -immediately -cursor-pos=-1 "以前のバッファで前の候補を即座に開く
```

@pocariさんありがとうございます

## 私の設定

dein.vimにおける設定

```toml:dein_lazy.toml
repo = 'Shougo/denite.nvim'
depends = ['neomru.vim']
on_event = 'BufRead'
hook_add = '''
nmap <silent> <C-u><C-t> :<C-u>Denite filetype<CR>
nmap <silent> <C-u><C-p> :<C-u>Denite file_rec<CR>
nmap <silent> <C-u><C-j> :<C-u>Denite line<CR>
nmap <silent> <C-u><C-g> :<C-u>Denite grep<CR>
nmap <silent> <C-u><C-]> :<C-u>DeniteCursorWord grep<CR>
nmap <silent> <C-u><C-u> :<C-u>Denite file_mru<CR>
nmap <silent> <C-u><C-y> :<C-u>Denite neoyank<CR>
nmap <silent> <C-u><C-r> :<C-u>Denite -resume<CR>
nmap <silent> <C-u>; :<C-u>Denite -resume -immediately -select=+1<CR>
nmap <silent> <C-u>- :<C-u>Denite -resume -immediately -select=-1<CR>
nmap <silent> <C-u><C-d> :<C-u>call denite#start([{'name': 'file_rec', 'args': ['~/dotfiles']}])<CR>
nnoremap ml :<C-u>call denite#start([{'name': 'file_rec', 'args': [g:memolist_path]}])<CR>
'''
hook_post_source = '''
call denite#custom#var('file_rec', 'command',
\ ['pt', '--follow', '--nocolor', '--nogroup', '--hidden', '-g', ''])
call denite#custom#var('grep', 'command',
\ ['pt', '--nogroup', '--nocolor', '--smart-case', '--hidden'])
call denite#custom#var('grep', 'default_opts', [])
call denite#custom#var('grep', 'recursive_opts', [])
'''
```
こんな感じでマッピングしています。
denite#custom#*はプラグイン読み込みが終わってからじゃないと動作しないので注意してください。
file_recはデフォルトはfindですがagやackなどに変えることができます。
grepのdefault_optsやrecursive_optsは不要であれば配列だけを渡しておけば大丈夫です。(ptはデフォルトでrecursiveです)

個人的にcolorschemeやmenuはあまり頻繁に使うもののように思えず設定しておりません。

## 余談

なぜかカーソルラインのfgが設定されていなかったので、最初選択行がどれなのか全くわかりませんでした。
現在はドキュメントのFAQに記載されているので戸惑うこともないかと思います。

```vim:.vimrc
hi CursorLine guifg=#E19972
```


Shougoさんへの感謝の気持ちで溺れそう。