年末が近づいてきたのでRuby開発用に.vimrcとプラグインを大掃除した

こちらは[フロムスクラッチ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/fromscratch)の12日目の記事です。

# はじめに
[前回の記事](https://qiita.com/nrk_baby/items/c1bde4d4d9862e185c63)でdein.vimを使ってプラグインのTOML化まで行いました。
今回は普段開発しているRubyやJavaScript向けにプラグイン周りを整えたいと思います。
NeoVimではなく、Vim8を使用しています。

# ゴール
- vimをIDE化するつもりはない
- デフォルト機能を少しずつ強化するプラグインを中心に入れる
- 基本はRuby・JavaScript向けにプラグインを入れる
- ついでに.vimrcも整理する

# .vimrc
```vim:表示・設定系(.vimrc)
" 挿入モードでTABキーを押した際、対応する数のスペースを入力
set expandtab
" 画面上でタブ文字が占める幅の指定
set tabstop=2
" 自動インデントでずれる幅の指定
set shiftwidth=2
" 連続した空白に対してタブキーやバックスペースキーでカーソルが動く幅の指定
set softtabstop=2
" 改行時に前の行のインデントを継続する
set autoindent
" 改行時に入力された行の末尾に合わせて次の行のインデントを増減する
set smartindent
" 一旦ファイルタイプ関連を無効化
filetype off
" 256色対応
set t_Co=256
" エンコード, ファイルエンコード
set encoding=utf-8
set fileencoding=utf-8
" スクロールする時に下が見えるようにする
set scrolloff=5
" .swapファイルを作らない
set noswapfile
" バックアップファイルを作らない
set nowritebackup
" バックアップをしない
set nobackup
" ビープ音を消す
set belloff=all
" OSのクリップボードを使う
set clipboard=unnamed
" 行番号を表示
set number
" compatibleオプションをオフにする
set nocompatible
" 移動コマンドを使ったとき、行頭に移動しない
set nostartofline
" 対応括弧に<と>のペアを追加
set matchpairs& matchpairs+=<:>
" 対応括弧をハイライト表示する
set showmatch
" 対応括弧の表示秒数を3秒にする
set matchtime=3
" ウィンドウの幅より長い行は折り返され、次の行に続けて表示される
set wrap
" 入力されているテキストの最大幅を無効にする
set textwidth=0
" 不可視文字を表示
set list
set listchars=tab:»-,trail:-,extends:»,precedes:«,nbsp:%,eol:↲
" インデントをshiftwidthの倍数に丸める
set shiftround
" 補完の際の大文字小文字の区別しない
set infercase
" 行末1文字までカーソルを移動できるようにする
set virtualedit=onemore
" 変更中のファイルでも、保存しないで他のファイルを表示
set hidden
" 新しく開く代わりにすでに開いてあるバッファを開く
set switchbuf=useopen
" 小文字の検索でも大文字も見つかるようにする
set ignorecase
" ただし大文字も含めた検索の場合はその通りに検索する
set smartcase
" インクリメンタルサーチを行う
set incsearch
" 検索結果をハイライト表示
set hlsearch
" マウスモード有効
set mouse=a
" コマンドを画面最下部に表示する
set showcmd
" ◆や○文字が崩れる問題を解決"
set ambiwidth=double
```
表示や設定をいじるのはこれくらいで十分な気がしています。
`set cursorline`も好きですが、相当重くなるため使用していません。

```vim:操作・入力系(.vimrc)
" インサートモードでbackspaceを有効に
set backspace=indent,eol,start
" 入力モード中に素早くjjと入力した場合はESCとみなす
inoremap jj <Esc>
" ビジュアルモードの選択範囲を * で検索
vnoremap <silent> * "vy/\V<C-r>=substitute(escape(@v, '\/'), "\n", '\\n', 'g')<CR><CR>
" vを二回で行末まで選択
vnoremap v $h
" Ctrl + hjkl でウィンドウ間を移動
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" /{pattern}の入力中は「/」をタイプすると自動で「\/」が、
" ?{pattern}の入力中は「?」をタイプすると自動で「\?」が 入力されるようになる
cnoremap <expr> / getcmdtype() == '/' ? '\/' : '/'
cnoremap <expr> ? getcmdtype() == '?' ? '\?' : '?'
```
特にオススメなのはインサートモード中にjjをESCとする設定です。めちゃくちゃ使っています。
/での検索中に「/」をタイプすると自動で「\/」と入力される設定も地味に便利です。
閉じカッコ補完はあまり好きではないのと、プラグインと競合したりするので、入れていません。

```vim:dein.vim関連(.vimrc)
" dein.vimによるプラグイン管理
if &compatible
  set nocompatible
endif

" dein.vimのclone先を指定する
set runtimepath+=~/dotfiles/.vim/dein/repos/github.com/Shougo/dein.vim

let s:dein_dir = expand('~/dotfiles/.vim/dein')

if dein#load_state(s:dein_dir)
  call dein#begin(s:dein_dir)

  call dein#load_toml(s:dein_dir . '/plugins.toml', {'lazy': 0})
  call dein#load_toml(s:dein_dir . '/lazy.toml', {'lazy': 1})

  call dein#end()
  call dein#save_state()
endif
```

# プラグイン（plugins.toml）
## とりあえず
```toml:とりあえず入れる(plugins.toml)
# plugin管理
[[plugins]]
repo = 'Shougo/dein.vim'

# 非同期処理全般
[[plugins]]
repo = 'Shougo/vimproc.vim'
```
このあたりはMustで入れるものかと思います。

## 表示系プラグイン(plugins.toml)
```toml:カラースキーマ、ステータスライン(plugins.toml)
# colorschema
[[plugins]]
repo = 'chriskempson/vim-tomorrow-theme'

# statusline
[[plugins]]
repo = 'itchyny/lightline.vim'

# インデントを可視化
[[plugins]]
repo = 'Yggdroot/indentLine'

# 無駄な空白をハイライト
[[plugins]]
repo = 'bronson/vim-trailing-whitespace'
```
カラースキーマはお好みで。
statuslineはairlineやpowerlineなどありますが、lightlineが軽量でオススメです。
インデント可視化、無駄な空白のハイライトは地味に便利です。

```vim:カラースキーマ、ステータスライン設定(.vimrc)
" カラースキーマ
colorscheme Tomorrow-Night-Bright
" シンタックスハイライトの最大行数
set synmaxcol=200
" シンタックスハイライト
syntax on
" .vueシンタックスハイライト
autocmd BufNewFile,BufRead *.vue set filetype=html
" 全角スペースのハイライト
function! ZenkakuSpace()
    highlight ZenkakuSpace cterm=underline ctermfg=lightblue guibg=darkgray
endfunction
if has('syntax')
    augroup ZenkakuSpace
        autocmd!
        autocmd ColorScheme * call ZenkakuSpace()
        autocmd VimEnter,WinEnter,BufRead * let w:m1=matchadd('ZenkakuSpace', '　')
    augroup END
    call ZenkakuSpace()
endif

" for lightline.vim
set laststatus=2
let g:lightline = {
  \ 'colorscheme': 'wombat',
  \ 'active': {
  \   'left': [
  \     ['mode', 'paste'],
  \     ['readonly', 'filename', 'modified', 'anzu']
  \   ]
  \ },
  \ 'component_function': {
  \   'anzu': 'anzu#search_status'
  \ }
  \ }
```
趣味で.vueファイルをいじることがあるので、filetypeをhtmlにしてシンタックスハイライトを効かせています。
全角スペースのハイライトも便利です。
lightline.vimの設定の中にanzuとチラホラあるのは、後ほど登場するプラグインであるvim-anzuを前提にしています。

## 操作系プラグイン(plugins.toml)
```toml:操作系プラグイン(plugins.toml)
# j, k移動高速化
[[plugins]]
repo = 'rhysd/accelerated-jk'

# /検索強化
[[plugins]]
repo = 'osyo-manga/vim-anzu'

# f検索強化
[[plugins]]
repo = 'rhysd/clever-f.vim'
```
```vim:操作系プラグイン用設定(.vimrc)
" for accelerated-jk
nmap j <Plug>(accelerated_jk_gj)
nmap k <Plug>(accelerated_jk_gk)

" for vim-anzu
nmap n nzz<Plug>(anzu-update-search-status)
nmap N Nzz<Plug>(anzu-update-search-status)
nmap * <Plug>(anzu-star)
nmap # <Plug>(anzu-sharp)
nmap <silent> <ESC><ESC> :<C-u>nohlsearch<CR><Plug>(anzu-clear-search-status)
```
j, kでの移動が爆速になったり、検索ヒット数が表示されたり、f検索の結果がハイライトされ、検索の繰り返しが;ではなくｆの連打でいけるようになります。

# 遅延読み込みプラグイン（lazy.toml）
## シンタックスハイライト
```toml:シンタックスハイライト(lazy.toml)
# slimのシンタックスハイライト
[[plugins]]
repo = 'slim-template/vim-slim'
on_ft = ['slim']

# ES6のシンタックスハイライト
[[plugins]]
repo = 'othree/yajs.vim'
on_ft = ['javascript']
```
この辺は必要があれば。

## 自動補完
```toml:自動補完プラグイン(lazy.toml)
# コードの自動補完
[[plugins]]
repo = 'Shougo/deoplete.nvim'
on_i = 1
hook_add = 'let g:deoplete#enable_at_startup = 1'

# vim8でdeopleteを使うのに必要
[[plugins]]
repo = 'roxma/nvim-yarp'
on_ft = ['ruby']

# vim8でdeopleteを使うのに必要
[[plugins]]
repo = 'roxma/vim-hug-neovim-rpc'
on_ft = ['ruby']
```
deoplete.nvimの導入にめちゃめちゃハマりました。
python3付きのvim8を入れ直し、その他諸々設定を見直しつつ、今の状態でやっと動くようになりました。

```vim:自動補完用設定(.vimrc)
" for deoplete.vim
" 一つ目の候補を選択状態にする
set completeopt+=noinsert
```
これ地味に便利です。候補の一番上にあればEnterで補完されるようになります。

## Ruby用
```toml:Ruby補完用(lazy.toml)
# Rubyの自動補完
[[plugins]]
repo = 'Shougo/deoplete-rct'
on_ft = ['ruby']

# Rubyの自動補完
[[plugins]]
repo = 'fishbullet/deoplete-ruby'
on_ft = ['ruby']

# Rubyの自動補完
[[plugins]]
repo = 'osyo-manga/vim-monster'
on_i = 1
hook_add = '''
let g:monster#completion#rcodetools#backend = "async_rct_complete"
let g:deoplete#sources#omni#input_patterns = {
  \ "ruby" : '[^. *\t]\.\w*\|\h\w*::',
  \}
'''
```
とりあえずよくわからんので全部突っ込みました。どうやら動いているっぽい。
fastri, neovim, rcodetoolsというgemを入れる必要があるみたいです。

```toml:Ruby定番(lazy.toml)
# Rubyのend補完
[[plugins]]
repo = 'tpope/vim-endwise'
on_i = 1
on_ft = ['ruby']

# Rubyのメソッドの定義元にジャンプ
[[plugins]]
repo = 'szw/vim-tags'
```
Rubyの`end`補完と、メソッドの定義元にジャンプできるvim-tagsを入れました。
vim-tagsは`brew install ctags`が必要です。
他にも色々Ruby向けプラグインはありますが、重くなっても嫌ですし、これくらいで十分な気がしています。

# 最後に
Unite.vimとかNERDTreeとかvim-railsとか使いこなせば便利だとは思うんですけど、結局高機能すぎて操作覚えられないんですよね...
今使っているプラグインに慣れてきたら、また見直していきたいと思います。

# コピペして使い人用に
## .vimrc
```vim:.vimrc
" 表示・設定系
" 挿入モードでTABキーを押した際、対応する数のスペースを入力
set expandtab
" 画面上でタブ文字が占める幅の指定
set tabstop=2
" 自動インデントでずれる幅の指定
set shiftwidth=2
" 連続した空白に対してタブキーやバックスペースキーでカーソルが動く幅の指定
set softtabstop=2
" 改行時に前の行のインデントを継続する
set autoindent
" 改行時に入力された行の末尾に合わせて次の行のインデントを増減する
set smartindent
" 一旦ファイルタイプ関連を無効化
filetype off
" 256色対応
set t_Co=256
" エンコード, ファイルエンコード
set encoding=utf-8
set fileencoding=utf-8
" スクロールする時に下が見えるようにする
set scrolloff=5
" .swapファイルを作らない
set noswapfile
" バックアップファイルを作らない
set nowritebackup
" バックアップをしない
set nobackup
" ビープ音を消す
set belloff=all
" OSのクリップボードを使う
set clipboard=unnamed
" 行番号を表示
set number
" compatibleオプションをオフにする
set nocompatible
" 移動コマンドを使ったとき、行頭に移動しない
set nostartofline
" 対応括弧に<と>のペアを追加
set matchpairs& matchpairs+=<:>
" 対応括弧をハイライト表示する
set showmatch
" 対応括弧の表示秒数を3秒にする
set matchtime=3
" ウィンドウの幅より長い行は折り返され、次の行に続けて表示される
set wrap
" 入力されているテキストの最大幅を無効にする
set textwidth=0
" 不可視文字を表示
set list
set listchars=tab:»-,trail:-,extends:»,precedes:«,nbsp:%,eol:↲
" インデントをshiftwidthの倍数に丸める
set shiftround
" 補完の際の大文字小文字の区別しない
set infercase
" 行末1文字までカーソルを移動できるようにする
set virtualedit=onemore
" 変更中のファイルでも、保存しないで他のファイルを表示
set hidden
" 新しく開く代わりにすでに開いてあるバッファを開く
set switchbuf=useopen
" 小文字の検索でも大文字も見つかるようにする
set ignorecase
" ただし大文字も含めた検索の場合はその通りに検索する
set smartcase
" インクリメンタルサーチを行う
set incsearch
" 検索結果をハイライト表示
set hlsearch
" マウスモード有効
set mouse=a
" コマンドを画面最下部に表示する
set showcmd
" ◆や○文字が崩れる問題を解決"
set ambiwidth=double

" 操作系
" インサートモードでbackspaceを有効に
set backspace=indent,eol,start
" 入力モード中に素早くjjと入力した場合はESCとみなす
inoremap jj <Esc>
" ビジュアルモードの選択範囲を * で検索
vnoremap <silent> * "vy/\V<C-r>=substitute(escape(@v, '\/'), "\n", '\\n', 'g')<CR><CR>
" vを二回で行末まで選択
vnoremap v $h
" Ctrl + hjkl でウィンドウ間を移動
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" /{pattern}の入力中は「/」をタイプすると自動で「\/」が、
" ?{pattern}の入力中は「?」をタイプすると自動で「\?」が 入力されるようになる
cnoremap <expr> / getcmdtype() == '/' ? '\/' : '/'
cnoremap <expr> ? getcmdtype() == '?' ? '\?' : '?'

" dein.vimによるプラグイン管理
if &compatible
  set nocompatible
endif

" dein.vimのclone先を指定する
set runtimepath+=~/dotfiles/.vim/dein/repos/github.com/Shougo/dein.vim

let s:dein_dir = expand('~/dotfiles/.vim/dein')

if dein#load_state(s:dein_dir)
  call dein#begin(s:dein_dir)

  call dein#load_toml(s:dein_dir . '/plugins.toml', {'lazy': 0})
  call dein#load_toml(s:dein_dir . '/lazy.toml', {'lazy': 1})

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

" カラースキーマ
colorscheme Tomorrow-Night-Bright
" シンタックスハイライトの最大行数
set synmaxcol=200
" シンタックスハイライト
syntax on
" .vueシンタックスハイライト
autocmd BufNewFile,BufRead *.vue set filetype=html
" 全角スペースのハイライト
function! ZenkakuSpace()
    highlight ZenkakuSpace cterm=underline ctermfg=lightblue guibg=darkgray
endfunction
if has('syntax')
    augroup ZenkakuSpace
        autocmd!
        autocmd ColorScheme * call ZenkakuSpace()
        autocmd VimEnter,WinEnter,BufRead * let w:m1=matchadd('ZenkakuSpace', '　')
    augroup END
    call ZenkakuSpace()
endif

" for lightline.vim
set laststatus=2
let g:lightline = {
  \ 'colorscheme': 'wombat',
  \ 'active': {
  \   'left': [
  \     ['mode', 'paste'],
  \     ['readonly', 'filename', 'modified', 'anzu']
  \   ]
  \ },
  \ 'component_function': {
  \   'anzu': 'anzu#search_status'
  \ }
  \ }

" for accelerated-jk
nmap j <Plug>(accelerated_jk_gj)
nmap k <Plug>(accelerated_jk_gk)

" for vim-anzu
nmap n nzz<Plug>(anzu-update-search-status)
nmap N Nzz<Plug>(anzu-update-search-status)
nmap * <Plug>(anzu-star)
nmap # <Plug>(anzu-sharp)
nmap <silent> <ESC><ESC> :<C-u>nohlsearch<CR><Plug>(anzu-clear-search-status)

" for vim-tags
" tagジャンプの時に複数候補がある時に一覧表示する
nnoremap <C-]> g<C-]>

" for deoplete.vim
" 一つ目の候補を選択状態にする
set completeopt+=noinsert
```

## plugins.toml
```toml:plugins.toml
# plugin管理
[[plugins]]
repo = 'Shougo/dein.vim'

# 非同期処理全般
[[plugins]]
repo = 'Shougo/vimproc.vim'

# colorschema
[[plugins]]
repo = 'chriskempson/vim-tomorrow-theme'

# statusline
[[plugins]]
repo = 'itchyny/lightline.vim'

# インデントを可視化
[[plugins]]
repo = 'Yggdroot/indentLine'

# 無駄な空白をハイライト
[[plugins]]
repo = 'bronson/vim-trailing-whitespace'

# j, k高速化
[[plugins]]
repo = 'rhysd/accelerated-jk'

# /検索強化
[[plugins]]
repo = 'osyo-manga/vim-anzu'

# f検索強化
[[plugins]]
repo = 'rhysd/clever-f.vim'
```

## lazy.toml
```toml:lazy.toml
# slimのシンタックスハイライト
[[plugins]]
repo = 'slim-template/vim-slim'
on_ft = ['slim']

# ES6のシンタックスハイライト
[[plugins]]
repo = 'othree/yajs.vim'
on_ft = ['javascript']

# コードの自動補完
[[plugins]]
repo = 'Shougo/deoplete.nvim'
on_i = 1
hook_add = 'let g:deoplete#enable_at_startup = 1'

# vim8でdeopleteを使うのに必要
[[plugins]]
repo = 'roxma/nvim-yarp'
on_ft = ['ruby']

# vim8でdeopleteを使うのに必要
[[plugins]]
repo = 'roxma/vim-hug-neovim-rpc'
on_ft = ['ruby']

# Rubyの自動補完
[[plugins]]
repo = 'Shougo/deoplete-rct'
on_ft = ['ruby']

# Rubyの自動補完
[[plugins]]
repo = 'fishbullet/deoplete-ruby'
on_ft = ['ruby']

# Rubyの自動補完
[[plugins]]
repo = 'osyo-manga/vim-monster'
on_i = 1
hook_add = '''
let g:monster#completion#rcodetools#backend = "async_rct_complete"
let g:deoplete#sources#omni#input_patterns = {
  \ "ruby" : '[^. *\t]\.\w*\|\h\w*::',
  \}
'''

# Rubyのend補完
[[plugins]]
repo = 'tpope/vim-endwise'
on_i = 1
on_ft = ['ruby']

# Rubyのメソッドの定義元にジャンプ
[[plugins]]
repo = 'szw/vim-tags'
```