Neovim + Dark powered plugins + coc.nvim で最高の開発環境を構築する

大学の研究室の夏合宿でNeovimのプラグインの紹介LTを作成しました。([Neovim plugins - Google Slides](https://drive.google.com/open?id=1LYJZaipJeT0RJ0Yl51uYabrp0jBAVFOuQXA6MuHtJzs))
LT用に作った資料なのでプラグインのそれぞれの軽い紹介しかできなかったので、改めてプラグインの紹介と動作の様子、キーマップなどの設定を記事にしたいと思います。
dotfiles(設定ファイル)を見たい人は[こちら](https://github.com/pyama2000/dotfiles/blob/master/.config/nvim/plugins)です。

## Dork powered pluginsとは

Dork powered pluginsは[Shougo / 暗黒美無王さん](https://github.com/Shougo)がVim用に作成したとても使いやすいプラグインのことです。
このプラグインがなかったらVimmerになっていなかったです。
今回紹介するプラグインは以下の5つです。

- [dein.vim](https://github.com/Shougo/dein.vim): プラグインマネージャー
- [denite.nvim](https://github.com/Shougo/denite.nvim): Vimのインターフェースを統合したプラグイン
- [defx.nvim](https://github.com/Shougo/defx.nvim): シンプルかつ強力なファイルエクスプローラー
- [deol.nvim](https://github.com/Shougo/deol.nvim): Vimのターミナル機能を拡張したプラグイン
- [coc.nvim](https://github.com/neoclide/coc.nvim): NeovimでLSPを使えるようにするプラグイン

**coc.nvim**はShougoさんが作ったものではないですが、Neovimで自動補完や定義ジャンプを使えるようにする便利なプラグインなので紹介したいと思います。

## 環境

- macOS Mojave 10.14.5 / Ubuntu 18.04
- Neovim v0.4.0-dev
- Python 3.7.4

## Neovimをインストール

現時点(2019年9月4日)ではstable版のNeovimではfloat windowが使えないためunstable版をインストールする方法を紹介します。ただし、stable版でも今回取り上げるプラグインは利用可能なのでお好きな方をインストールしてください。

```bash
# For macOS
# stable版は --HEAD オプションを削除するとインストールできます
$ brew install --HEAD neovim

# For Ubuntu
# stable版は 1行目の最後 unstable を stable に変更するとインストールできます
$ sudo add-apt-repository -y ppa:neovim-ppa/unstable \
  sudo apt update -y \
  sudo apt install neovim
```

上記以外のインストール方法: [Installing Neovim](https://github.com/neovim/neovim/wiki/Installing-Neovim)

## Python 3.x系をインストール

Dork powered pluginsはPython 3.x系で動くため、ご自身の好きな方法でインストールしてください。
この記事では**pyenv**でPython 3.x系をインストールしたことを前提としているので、ご自身の環境で読み替えてください。

## dein.vimをインストール

以下のコマンドを実行すると**dein.vim**が自動でインストールされます。
インストールが完了したら`installer.sh`は削除して大丈夫です。

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

## Neovimを設定する

> ここでは最低限の設定しか記述しません。
> [こちら](https://github.com/pyama2000/dotfiles/blob/master/.config/nvim/plugins)に全て記述されているので参考にしてください。

### 設定ファイル構成

```bash
~/.config/nvim
├── init.vim            # Neovimの設定ファイル
└── plugins             # プラグイン用の設定ディレクトリ
   ├── coc.rc.vim
   ├── config
   │  └── dein.toml     # 起動時ロード用の設定ファイル
   ├── defx.rc.vim
   ├── dein.rc.vim
   ├── denite.rc.vim
   └── deol.rc.vim
```

### Neovim全体の設定

```vim:~/.config/nvim/init.vim
" Python 3.x系のPathを設定
let g:python3_host_prog = 'YOUR_PYTHON_PATH'

" dein.vim を使うために以下を記述
runtime! plugins/dein.rc.vim
```

私の環境では**pyenv**でPython 3.x系をインストールしているので以下のような設定になります。
`let g:python3_host_prog = '~/.pyenv/shims/python3/'`
Python 3.x系のPathがわからない場合はターミナルで`which python3`を実行し、出力されたPathを設定してください。

### dein.vimの設定

[dein.vimをインストール](#deinvimをインストール)の実行が完了すると、設定を`init.vim`に記述してくださいと出力されると思いますが、一旦それは無視します。
dein.vimの設定は以下の通りです。

```vim:~/.config/nvim/plugins/dein.rc.vim
" プラグインの設定ファイルPath
let s:plugin = '~/.config/nvim/plugins/config/dein.toml'

" Neovim起動時にdein.tomlファイルをチェックし、未インストールのプラグインがあった場合インストールする
if dein#check_install()
  call dein#install()
endif

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')
  " dein.tomlを起動時ロードの設定ファイルとして読み込む
  call dein#load_toml(s:plugin, {'lazy': 0})
  call dein#end()
  call dein#save_state()
endif

filetype plugin indent on
syntax enable
```

### プラグインのインストールと設定

TOMLファイルは以下のような構成となっています。`[[plugin]]`からつぎの`[[plugin]]`までが一つのテーブルとなっていて、その中の`repo`にプラグインのリポジトリ名を指定するとdein.vimでインストールすることができます。`hook_add`内でそのプラグインの設定を記述することができますが、ここでは設定ファイルを別の場所に分けて、その設定ファイルを読み込んでいます。

```toml:~/.config/nvim/plugins/config/dein.toml
[[plugins]]
repo = "neoclide/coc.nvim"
merge = 0
rev = "release"
hook_add = """
source ~/.config/nvim/plugins/coc.rc.vim
"""

[[plugins]]
repo = "Shougo/defx.nvim"
depends = ["defx-git"]
hook_add = """
source ~/.config/nvim/plugins/defx.rc.vim
"""

[[plugins]]
repo ="kristijanhusak/defx-git"
hook_add = """
source ~/.config/nvim/plugins/defx-git.rc.vim
"""

[[plugins]]
repo = "Shougo/denite.nvim"
hook_add = """
source ~/.config/nvim/plugins/denite.rc.vim
"""

[[plugins]]
repo = "shougo/deol.nvim"
hook_add = """
source ~/.config/nvim/plugins/deol.rc.vim
"""
```

TOMLファイルを保存し、Neovimで`:call dein#install()`を実行するか、もう一度Neovimを立ち上げるとプラグインのインストールが自動で開始されます。

## denite.nvim

**denite.nvim**はNeovimのインターフェースを統合するプラグインです。
個人的には主にファイル、バッファ、コマンドの検索・実行に利用しています。

<div>
  <img width="49%" alt="denite_all.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/270a9b7a-d4d5-34ea-3ab9-9a9f7d3896ae.png">
  <img width="49%" alt="denite_grep.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/0e22decf-7385-0dfd-9aeb-7a31f39d9971.png">
</div>

上の画像では、カレントディレクトリのファイルとバッファを表示しています。
Vim / Neovimで開いたファイルはバッファに保存されるため、バッファを活用することができれば目的のファイルを素早く開くことができます。**denite.nvim**はバッファの一覧も表示することができるためファイル操作が格段に向上します。
また、grep機能もあるため、指定した文字列を含むファイルの検索も容易に行うことができます。

以下が**denite.nvim**のキーマップなどを設定したファイルです。

```vim:~/.config/nvim/plugins/denite.rc.vim
" 【Ctrl + d + a】 カレントディレクトリとバッファを表示
nnoremap <silent><C-d>a :<C-u>Denite file buffer -split=floating file:new<CR>
" 【Ctrl + d + b】 バッファを表示
nnoremap <silent><C-d>b :<C-u>Denite buffer -split=floating file:new<CR>
" 【Ctrl + d + f】 カレントディレクトリを表示
nnoremap <silent><C-d>f :<C-u>Denite file -split=floating file:new<CR>
" 【Ctrl + d + r】 カレントディレクトリ以下を再帰的に表示
nnoremap <silent><C-d>r :<C-u>Denite file/rec -split=floating file:new<CR>
" 【Ctrl + d + gr】 カレントディレクトリ以下のファイルから指定した文字列を検索
nnoremap <silent><C-d>gr :<C-u>Denite grep -buffer-name=search<CR>
" 【Ctrl + d + ,】 カレントディレクトリ以下のファイルからカーソル下の文字列を検索
nnoremap <silent><C-d>, :<C-u>DeniteCursorWord grep -buffer-name=search line<CR>
" 【Ctrl + d + gs】 grepした結果を再表示
nnoremap <silent><C-d>gs :<C-u>Denite -resume -buffer-name=search<CR>
" 【Ctrl + d + c】 Neovim内で実行したコマンドを表示
nnoremap <silent><C-d>c :<C-u>Denite command_history -split=floating<CR>

autocmd FileType denite call s:denite_my_settings()
function! s:denite_my_settings() abort
  nnoremap <silent><buffer><expr> <CR>
  \ denite#do_map('do_action')
  " 【o】 ファイルを開く
  nnoremap <silent><buffer><expr> o
  \ denite#do_map('do_action')
  " 【s】 ウィンドウを水平分割してファイルを開く
  nnoremap <silent><buffer><expr> s
  \ denite#do_map('do_action', 'split')
  " 【v】 ウィンドウを垂直分割してファイルを開く
  nnoremap <silent><buffer><expr> v
  \ denite#do_map('do_action', 'vsplit')
  " 【d】 ファイルを削除する
  nnoremap <silent><buffer><expr> d
  \ denite#do_map('do_action', 'delete')
  " 【p】 ファイルをプレビュー画面で開く
  nnoremap <silent><buffer><expr> p
  \ denite#do_map('do_action', 'preview')
  " 【ESC】 / 【q】 denite.nvimを終了する
  nnoremap <silent><buffer><expr> <Esc>
  \ denite#do_map('quit')
  nnoremap <silent><buffer><expr> q
  \ denite#do_map('quit')
  " 【i】 ファイル名で検索する
  nnoremap <silent><buffer><expr> i
  \ denite#do_map('open_filter_buffer')
  " 【SPACE】 ファイルを複数選択する
  nnoremap <silent><buffer><expr> <Space>
  \ denite#do_map('toggle_select').'j'
endfunction

autocmd FileType denite-filter call s:denite_filter_my_settings()
function! s:denite_filter_my_settings() abort
  imap <silent><buffer> <C-o> <Plug>(denite_filter_quit)
endfunction
```

その他の詳しいコマンド等はNeovimで`:help denite.txt`を実行するか[ドキュメント](https://github.com/Shougo/denite.nvim/blob/master/doc/denite.txt)を参考にしてください。

## deol.nvim

**deol.nvim**はNeovim上でターミナルを実行できるプラグインです。ターミナルを実行できるため、Neovimを抜けることなくプログラムのデバッグ作業ができるためかなり重宝しています。
通常のNeovimでも`:terminal`を実行するとターミナルを起動できますが、**deol.nvim**の今後の開発によってさらに使いやすいプラグインになると信じて紹介します。

<img width="100%" alt="deol.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/4dbfafeb-7973-56a2-4f9c-e46f4ea985b8.png">

```vim:~/.config/nvim/plugins/deol.rc.vim
" 【Ctrl + o】 float windowでターミナルを表示
nnoremap <silent><C-o> :<C-u>Deol -split=floating<CR>
" 【ESC】 ターミナルモードから抜ける
tnoremap <ESC>   <C-\><C-n>
```

**deol.nvim**は【ESC】キーでターミナルモードから抜けることができないので上記のようにキーマップを設定しています。新しいターミナルウィンドウを立ち上げたいときはインサートモードになっていない状態で`【Ctrl + z】`で立ち上げることができます。
その他の詳しいコマンドやキーマップはNeovimで`:help deol.txt`を実行するか[ドキュメント](https://github.com/Shougo/deol.nvim/blob/master/doc/deol.txt)を参考にしてください。

## defx.nvim

**defx.nvim**はファイルエクスプローラーで、以前は**NERDTree**を使っていましたが、シンプルかつ多機能な**defx.nvim**に乗り換えました。プラグインを追加することで[アイコンの表示](https://github.com/kristijanhusak/defx-icons)や、[Gitのステータスを表示](https://github.com/kristijanhusak/defx-git)することができます。

<img width="100%" alt="defx.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/ba5b17a3-c2db-6769-7fd1-f43e3b774b16.png">

```vim:~/.config/nvim/plugins/defx.rc.vim
" 【Ctrl + f】 defx.nvimを起動
nnoremap <silent><C-f> :<C-u>Defx<CR>

call defx#custom#option('_', {
    \ 'columns': 'indent:git:icons:filename',
    \ 'show_ignored_files': 1,
    \ })

let g:defx_icons_enable_syntax_highlight = 1
let g:defx_icons_column_length = 2

autocmd FileType defx call s:defx_my_settings()
    function! s:defx_my_settings() abort
      nnoremap <silent><buffer><expr> <CR>
     \ defx#do_action('open')
      " 【o】 ファイルを開く
      nnoremap <silent><buffer><expr> o
      \ defx#do_action('open')
      " 【s】 ウィンドウを水平分割してファイルを開く
      nnoremap <silent><buffer><expr> s
      \ defx#do_action('open', 'split')
      " 【v】 ウィンドウを垂直分割してファイルを開く
      nnoremap <silent><buffer><expr> v
      \ defx#do_action('open', 'vsplit')
      " 【c】 ファイルをコピーする
      nnoremap <silent><buffer><expr> c
      \ defx#do_action('copy')
      " 【m】 ファイルを移動する
      nnoremap <silent><buffer><expr> m
      \ defx#do_action('move')
      " 【p】 ファイルを貼り付ける
      nnoremap <silent><buffer><expr> p
      \ defx#do_action('paste')
      " 【n】 新しいファイルを作成する
      nnoremap <silent><buffer><expr> n
      \ defx#do_action('new_file')
      " 【N】 新しいディレクトリを作成する
      nnoremap <silent><buffer><expr> N
      \ defx#do_action('new_directory')
      " 【d】 ファイルを削除する
      nnoremap <silent><buffer><expr> d
      \ defx#do_action('remove')
      " 【r】 ファイル名を変更する
      nnoremap <silent><buffer><expr> r
      \ defx#do_action('rename')
      " 【t】 ツリーを表示/非表示する
      nnoremap <silent><buffer><expr> t
      \ defx#do_action('open_or_close_tree')
      " 【x】 ファイルを実行する
      nnoremap <silent><buffer><expr> x
      \ defx#do_action('execute_system')
      " 【yy】 ファイル/ディレクトリのパスをコピーする
      nnoremap <silent><buffer><expr> yy
      \ defx#do_action('yank_path')
      nnoremap <silent><buffer><expr> .
      " 【.】 隠しファイルを表示/非表示する
      \ defx#do_action('toggle_ignored_files')
      nnoremap <silent><buffer><expr> ..
      " 【..】 親ディレクトリに移動する
      \ defx#do_action('cd', ['..'])
      nnoremap <silent><buffer><expr> ~
      " 【~】 ホームディレクトリに移動する
      \ defx#do_action('cd')
      " 【ESC】 / 【q】 defx.nvimを終了する
      nnoremap <silent><buffer><expr> <Esc> 
      \ defx#do_action('quit')
      nnoremap <silent><buffer><expr> q
      \ defx#do_action('quit')
      " 【j】 カーソルを下に移動する
      nnoremap <silent><buffer><expr> j
      \ line('.') == line('$') ? 'gg' : 'j'
      " 【k】 カーソルを上に移動する
      nnoremap <silent><buffer><expr> k
      \ line('.') == 1 ? 'G' : 'k'
      " 【cd】 Neovim上のカレントディレクトリを変更する
      nnoremap <silent><buffer><expr> cd
      \ defx#do_action('change_vim_cwd')
endfunction
```

その他の詳しいコマンドやキーマップはNeovimで`:help defx.txt`を実行するか[ドキュメント](https://github.com/Shougo/defx.nvim/blob/master/doc/defx.txt)を参考にしてください。

## coc.nvim

**coc.nvim**はNeovimでLSP(Language Server Protocol)を使えるようにするプラグインで、自動補完やエラーチェック、フォーマット、定義先に移動することができます。coc.nvimが対応しているLSPとその設定は方法は[こちら](https://github.com/neoclide/coc.nvim/wiki/Language-servers)に記載されているので確認してください。
また、**coc.nvim**の設定は[公式](https://github.com/neoclide/coc.nvim/wiki/Language-servers)の例をそのままコピーしてキーマップを少しいじるだけでいいと思います。
デフォルトのキーマップは以下のようになっています(よく使う機能のみ抜粋しています)。

- 【rn】 リネームする
- 【[c】 直前の警告/エラー部分に移動する
- 【[c】 直後の警告/エラー部分に移動する
- 【gd】 定義先に移動する
- 【gr】 参照されている部分を表示する
- 【K】 ドキュメントを表示する

![coc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/2780c9dd-0b16-c9d2-bd33-2eaf7ec9e257.png)

その他の詳しいコマンドやキーマップはNeovimで`:help coc-nvim`を実行するか[Wiki](https://github.com/neoclide/coc.nvim/wiki)を参考にしてください。


## おわりに

先日インターンに参加して刺激を受けて記事やらコードやらを書きたい欲が爆発しています。
そのインターンでいろんな方のターミナルを拝見する機会があったのですが、テーマを設定していなく見づらいなぁ、と感じたので次の記事ではターミナルとそのテーマなどを情熱が続いていたら紹介したいと思います。