Neovim の設定を綺麗に整理してみた

## はじめに

Neovim の設定を一年以上サボっていたので、久しぶりに整理しました。
Neovim を導入した当初は、他の方の設定ファイルをコピペしたものだったので、今回はしっかりドキュメントなどを見て設定しました。


## やったこと

- init.vim の設定
- dein.vim の導入
- Vim プラグインの導入
- Vim プラグインごとの設定


## 環境

- **macOS Sierra**: v10.12.6
- **Neovim**: v0.3.0
- **Python2**: v2.7.10
- **Python3**: v3.7.0
- **Ruby**: v2.4.4p296
- **Node.js**: v10.6.0

## 設定ファイルだけ見たい方はこちら

GitHub に設定ファイルを共有しているので、設定ファイルだけ見たい方はそちらをご覧ください。

**repository**: https://github.com/tamago3keran/neovim-config/tree/master/plugins


## 久しぶりの Neovim 設定

### なぜ .config ディレクトリ？

Neovim の[ドキュメント](https://neovim.io/doc/user/vim_diff.html#nvim-configuration)にも明記されていますが、 `~/.config/nvim/init.vim` に設定を書きました。

> - Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for configuration.
> - Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files.

`.config` ディレクトリ直下に設定ファイルを置くのは、 Neovim が [XDG Base Directory Specification](https://wiki.archlinux.jp/index.php/XDG_Base_Directory_%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88)　に対応しているからのようです。

> - XDG_CONFIG_HOME
>   - ユーザー個別の設定が書き込まれるディレクトリ ( `/etc` と類似)。
>   - デフォルトは `$HOME/.config` です。

### init.vim の参考例

```vim:~/.config/nvim/init.vim

set number             "行番号を表示
set autoindent         "改行時に自動でインデントする
set tabstop=2          "タブを何文字の空白に変換するか
set shiftwidth=2       "自動インデント時に入力する空白の数
set expandtab          "タブ入力を空白に変換
set splitright         "画面を縦分割する際に右に開く
set clipboard=unnamed  "yank した文字列をクリップボードにコピー
set hls                "検索した文字をハイライトする
```


## dein.vim でプラグイン管理

`dein.vim` は Shougo さんによって作成された Vim / Neovim のプラグインマネージャです。
このツールを使って、Vim プラグインの管理を簡潔にしました。

### denite.vim の導入方法

`dein.vim` の導入方法も非常に簡単で、[ドキュメント](https://github.com/Shougo/dein.vim/blob/master/README.md)通りに行いました。

まずは以下のコマンドを実行しました。

```
% curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
% sh ./installer.sh ~/.cache/dein
```

コマンドを実行した後に `init.vim` に以下のコードを追記しました。

```vim:~/.config/nvim/init.vim
if &compatible
  set nocompatible
endif
set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim
if dein#load_state('~/.cache/dein')
  call dein#begin('~/.cache/dein')
  call dein#end()
  call dein#save_state()
endif
filetype plugin indent on
syntax enable
```

これでプラグインを入れる準備は完了です！


### プラグインの導入方法

いよいよ自分が好きなプラグインを入れていきます。
私は `init.vim` を膨らませたくなかったので、 toml ファイルに入れたいプラグインを書きました。

まずは `init.vim` に toml ファイルを読み込むコードを書きました。

```diff:~/.config/nvim/init.vim
 if &compatible
   set nocompatible
 endif
 set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim
 if dein#load_state('~/.cache/dein')
   call dein#begin('~/.cache/dein')
+  call dein#load_toml('~/.config/nvim/dein.toml', {'lazy': 0})
+  call dein#load_toml('~/.config/nvim/dein_lazy.toml', {'lazy': 1})
   call dein#end()
   call dein#save_state()
 endif
 filetype plugin indent on
 syntax enable
```

`dein.toml` と `dein_lazy.toml` という2つの toml ファイルを作成していますが、以下のような違いがあります。

- `dein.toml`
    - Neovim を起動した際にロードされる
- `dein_lazy.toml`
    - プラグインを使用する際にロードされる

では `dein.toml` というファイルを作って、以下の書式でプラグイン名を書いていきます。

```nvim:~/.config/nvim/dein.vim
[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
repo = 'tpope/vim-endwise'

[[plugins]]
repo = 'Townk/vim-autoclose'

[[plugins]]
repo = 'joshdick/onedark.vim'
hook_add = '''
  colorscheme onedark
'''

[[plugins]]
repo = 'w0rp/ale'

[[plugins]]
repo = 'airblade/vim-gitgutter'
hook_add = '''
  set signcolumn=yes
  set updatetime=1000
  nnoremap [gitgutter] <Nop>
  nmap <C-h> [gitgutter]
  nmap [gitgutter]j <Plug>GitGutterNextHunk
  nmap [gitgutter]k <Plug>GitGutterPrevHunk
  nmap [gitgutter]u <Plug>GitGutterUndoHunk
'''

[[plugins]]
repo = 'tpope/vim-fugitive'
hook_add = '''
  command Gst :Gstatus
  command Gdf :Gdiff
  command Gbl :Gblame
'''

[[plugins]]
repo = 'Shougo/denite.nvim'
hook_add = '''
  nnoremap [denite] <Nop>
  nmap <C-d> [denite]
  nnoremap <silent> [denite]g :<C-u>Denite grep -buffer-name=search-buffer-denite<CR>
  nnoremap <silent> [denite]r :<C-u>Denite -resume -buffer-name=search-buffer-denite<CR>
  nnoremap <silent> [denite]p :<C-u>Denite file_rec<CR>
  call denite#custom#option('default', 'prompt', '>')
  call denite#custom#option('_', 'highlight_matched_range', 'None')
  call denite#custom#option('_', 'highlight_matched_char', 'None')
  call denite#custom#map('insert', "<Tab>", '<denite:move_to_next_line>')
  call denite#custom#map('insert', "<S-Tab>", '<denite:move_to_previous_line>')
  call denite#custom#map('insert', "<C-t>", '<denite:do_action:tabopen>')
  call denite#custom#map('insert', "<C-v>", '<denite:do_action:vsplit>')
  call denite#custom#map('normal', "v", '<denite:do_action:vsplit>')
  call denite#custom#var('grep', 'command', ['pt', '--follow', '--nogroup', '--nocolor', '--hidden'])
  call denite#custom#var('grep', 'default_opts', [])
  call denite#custom#var('grep', 'recursive_opts', [])
  call denite#custom#var('file_rec', 'command', ['pt', '--follow', '--nocolor', '--nogroup', '--hidden', '-g', ''])
'''

[[plugins]]
repo = 'osyo-manga/vim-anzu'
hook_add = '''
  nmap n <Plug>(anzu-n-with-echo)
  nmap N <Plug>(anzu-N-with-echo)
  nmap * <Plug>(anzu-star)
  nmap # <Plug>(anzu-sharp)
'''
```

`dein_lazy.toml` ファイルにもプラグイン名を書きます。

```toml:~/.config/nvim/dein_lazy.toml
[[plugins]]
repo = 'Shougo/deoplete.nvim'
on_event = 'InsertEnter'
hook_add = '''
  let g:deoplete#enable_at_startup = 1
  inoremap <expr><Tab> pumvisible() ? "\<DOWN>" : "\<Tab>"
  inoremap <expr><S-Tab> pumvisible() ? "\<UP>" : "\<S-Tab>"
'''
```

最後に Vim を起動して、ノーマルモードで以下のコマンドを実行しました。このコマンドでプラグインが読み込まれました。

```
:call dein#install()
```

### プラグインのインストールを自動化

Vim プラグインを入れる度にインストールのコマンドを実行するのは面倒なので、　新しく入れたプラグインがあれば、Vim 起動時に自動でインストールするようにしました。

```diff:~/.config/nvim/init.vim
  if &compatible
    set nocompatible
  endif
  set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim
  if dein#load_state('~/.cache/dein')
    call dein#begin('~/.cache/dein')
    call dein#load_toml('~/.config/nvim/dein.toml', {'lazy': 0})
    call dein#load_toml('~/.config/nvim/dein_lazy.toml', {'lazy': 1})
    call dein#end()
    call dein#save_state()
  endif
+ if dein#check_install()
+  call dein#install()
+ endif
  filetype plugin indent on
  syntax enable
```

### プラグインごとに設定ファイルを分ける

プラグインごとにキーマップなどの設定を書いていくと、上記の `dein.toml` のように見づらくなってしまいました。
そこで設定ファイルをプラグインごとに分けて書く方法をとりました。

まずは `dein.toml` と `dein_lazy.toml` を修正しました。

```diff:~/.config/nvim/dein.vim
  [[plugins]]
  repo = 'Shougo/dein.vim'
  
  [[plugins]]
  repo = 'tpope/vim-endwise'
  
  [[plugins]]
  repo = 'Townk/vim-autoclose'
  
  [[plugins]]
  repo = 'joshdick/onedark.vim'
  hook_add = '''
    colorscheme onedark
  '''
  
  [[plugins]]
  repo = 'w0rp/ale'
  
  [[plugins]]
  repo = 'airblade/vim-gitgutter'
  hook_add = '''
-   set signcolumn=yes
-   set updatetime=1000
-   nnoremap [gitgutter] <Nop>
-   nmap <C-h> [gitgutter]
-   nmap [gitgutter]j <Plug>GitGutterNextHunk
-   nmap [gitgutter]k <Plug>GitGutterPrevHunk
-   nmap [gitgutter]u <Plug>GitGutterUndoHunk
+   source ~/.config/nvim/plugins/gitgutter.vim
  '''
  
  [[plugins]]
  repo = 'tpope/vim-fugitive'
  hook_add = '''
-   command Gst :Gstatus
-   command Gdf :Gdiff
-   command Gbl :Gblame
+   source ~/.config/nvim/plugins/fugitive.vim
  '''
  
  [[plugins]]
  repo = 'Shougo/denite.nvim'
  hook_add = '''
-   nnoremap [denite] <Nop>
-   nmap <C-d> [denite]
-   nnoremap <silent> [denite]g :<C-u>Denite grep -buffer-name=search-buffer-denite<CR>
-   nnoremap <silent> [denite]r :<C-u>Denite -resume -buffer-name=search-buffer-denite<CR>
-   nnoremap <silent> [denite]p :<C-u>Denite file_rec<CR>
-   call denite#custom#option('default', 'prompt', '>')
-   call denite#custom#option('_', 'highlight_matched_range', 'None')
-   call denite#custom#option('_', 'highlight_matched_char', 'None')
-   call denite#custom#map('insert', "<Tab>", '<denite:move_to_next_line>')
-   call denite#custom#map('insert', "<S-Tab>", '<denite:move_to_previous_line>')
-   call denite#custom#map('insert', "<C-t>", '<denite:do_action:tabopen>')
-   call denite#custom#map('insert', "<C-v>", '<denite:do_action:vsplit>')
-   call denite#custom#map('normal', "v", '<denite:do_action:vsplit>')
-   call denite#custom#var('grep', 'command', ['pt', '--follow', '--nogroup', '--nocolor', '--hidden'])
-   call denite#custom#var('grep', 'default_opts', [])
-   call denite#custom#var('grep', 'recursive_opts', [])
-   call denite#custom#var('file_rec', 'command', ['pt', '--follow', '--nocolor', '--nogroup', '--hidden', '-g', ''])
+   source ~/.config/nvim/plugins/denite.vim
  '''
  
  [[plugins]]
  repo = 'osyo-manga/vim-anzu'
  hook_add = '''
-   nmap n <Plug>(anzu-n-with-echo)
-   nmap N <Plug>(anzu-N-with-echo)
-   nmap * <Plug>(anzu-star)
-   nmap # <Plug>(anzu-sharp)
+   source ~/.config/nvim/plugins/anzu.vim
  '''
```

```diff:~/.config/nvim/dein_lazy.toml
  [[plugins]]
  repo = 'Shougo/deoplete.nvim'
  on_event = 'InsertEnter'
  hook_add = '''
-   let g:deoplete#enable_at_startup = 1
-   inoremap <expr><Tab> pumvisible() ? "\<DOWN>" : "\<Tab>"
-   inoremap <expr><S-Tab> pumvisible() ? "\<UP>" : "\<S-Tab>"
+   source ~/.config/nvim/plugins/deoplete.vim
  '''
```

次にプラグインごとの設定ファイルを作成しました。

```vim:~/.config/nvim/plugins/anzu.vim
nmap n <Plug>(anzu-n-with-echo)
nmap N <Plug>(anzu-N-with-echo)
nmap * <Plug>(anzu-star)
nmap # <Plug>(anzu-sharp)
```

```vim:~/.config/nvim/plugins/denite.vim
nnoremap [denite] <Nop>
nmap <C-d> [denite]
nnoremap <silent> [denite]g :<C-u>Denite grep -buffer-name=search-buffer-denite<CR>
nnoremap <silent> [denite]r :<C-u>Denite -resume -buffer-name=search-buffer-denite<CR>
nnoremap <silent> [denite]p :<C-u>Denite file_rec<CR>

call denite#custom#option('default', 'prompt', '>')
call denite#custom#option('_', 'highlight_matched_range', 'None')
call denite#custom#option('_', 'highlight_matched_char', 'None')
call denite#custom#map('insert', "<Tab>", '<denite:move_to_next_line>')
call denite#custom#map('insert', "<S-Tab>", '<denite:move_to_previous_line>')
call denite#custom#map('insert', "<C-t>", '<denite:do_action:tabopen>')
call denite#custom#map('insert', "<C-v>", '<denite:do_action:vsplit>')
call denite#custom#map('normal', "v", '<denite:do_action:vsplit>')
call denite#custom#var('grep', 'command', ['pt', '--follow', '--nogroup', '--nocolor', '--hidden'])
call denite#custom#var('grep', 'default_opts', [])
call denite#custom#var('grep', 'recursive_opts', [])
call denite#custom#var('file_rec', 'command', ['pt', '--follow', '--nocolor', '--nogroup', '--hidden', '-g', ''])
```

```vim:~/.config/nvim/plugins/deoplete.vim
let g:deoplete#enable_at_startup = 1
inoremap <expr><Tab> pumvisible() ? "\<DOWN>" : "\<Tab>"
inoremap <expr><S-Tab> pumvisible() ? "\<UP>" : "\<S-Tab>"
```

```vim:~/.config/nvim/plugins/fugitive.vim
command Gst :Gstatus
command Gdf :Gdiff
command Gbl :Gblame
```

```vim:~/.config/nvim/plugins/gitgutter.vim
set signcolumn=yes
set updatetime=1000

nnoremap [gitgutter] <Nop>
nmap <C-h> [gitgutter]
nmap [gitgutter]j <Plug>GitGutterNextHunk
nmap [gitgutter]k <Plug>GitGutterPrevHunk
nmap [gitgutter]u <Plug>GitGutterUndoHunk
```

これでだいぶ見やすくなりました！
Neovim を使ってみたいという方は、ぜひ参考にしてください！

私が現在使用しているプラグインの紹介と使い方についてまとめましたので、そちらもご覧ください。
=> [私が使う Vim プラグインまとめ](https://qiita.com/tamago3keran/items/37993c4206666259bd9f)