これが無いと個人的に辛いVimの話

この記事は[Vim2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vim2)の6日目の記事です。

#はじめに
皆さん、Vim使ってますか？ 私は、iterm2+neovim+tmuxという環境で毎日使っています。（iterm2からAlacrittyに乗り換えたいが、日本語入力がなぁ、、、、）
ほんの2年前は「Vimで作業なんてできない！ SublimeTextで十分や！」なんて言ってましたが、今じゃ「Vimじゃないと仕事できない！！」なんて言ってる今日このごろです。
ただVSCodeの勢力がものすごくて、部署の殆どの人がVSCodeを使っています。Vimを使ってるのは自分だけという肩身の狭い思いをしながら毎日を過ごしてます。 


それなりに使ってきた中で、「こいつを入れておいてよかった」「意外とこのマッピング便利」など、良かったものを書いていこうかと思います。
たくさんあるので、その中でもいくつかピックアップします。

## プラグイン編
### 0. vim-plug
https://github.com/junegunn/vim-plug
軽量でシンプルなプラグインマネージャ。Vimmerな人の多くはdein.vimを使ってるようですが、こちらを使っています。0と書いてるのはこれがないと何も始まらないからです笑

### 1. fzf.vim
https://github.com/junegunn/fzf.vim

fuzzy検索用コマンド[fzf](https://github.com/junegunn/fzf)をVimから扱えるようにするプラグイン。これが無いと作業が進まないですね。入れておいて損は無いプラグインです。
デフォルトでリポジトリ内のファイルを検索して開いたり、agコマンドによるファイル内検索などが標準で提供されています。

よくやるのは、
1. ag(またはrg)コマンドでファイル内検索
2. 該当箇所を見つけたら、それを含むファイルを選択
3. QuickFixに出力されるので、[qfreplace](https://github.com/thinca/vim-qfreplace)と組み合わせて置換処理
4. 保存すると変更が反映されます
![replace.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57325/fe88a458-1642-30a8-e4f3-0e4098f2c170.gif)

#### おすすめマッピング
```vim
# カーソル下にあるwordをagで検索
nnoremap <silent> <leader>ag  :Ag <C-R><C-W><CR>
nnoremap <silent> <leader>AG  :Ag <C-R><C-A><CR>
# visual modeで選択したwordを検索
xnoremap <silent> <leader>ag  y:Ag <C-R>"<CR>

# ファイルを開く（CrtlP風、よく使います）
# 条件分岐はNERDTree上で使うと、ツリー内でファイルが開かれるのを防ぐために入れてます
autocmd VimEnter * nnoremap <silent><expr><C-P> (expand('%') =~ 'NERD_tree' ? "\<C-W>\<C-W>" : '').":Files<CR>"

# カーソル配下の文字列からファイルを開く（gfとかでうまく開けない場合に便利です。たまに使います）
autocmd VimEnter * nnoremap <silent><expr><leader>F (expand('%') =~ 'NERD_tree' ? "\<C-W>\<C-W>" : '').':Files'.(!empty(expand('<cword>')) ? '--query='.expand('<cword>') : '').'<CR>'
```

Filesコマンドの代わりに、https://github.com/tweekmonster/fzf-filemru のFilesMruを使ってます。
リポジトリごとに最近開いたファイルがまとまって上位に表示されるのでおすすめです。
あとneovimを使ってる場合、fzf.vimのpreview表示で、 ``` --no-unicode``` オプションを付けるとsyntax表示が正常になるのでつけると良いです。

### 2. coc.nvim
https://github.com/neoclide/coc.nvim

YouCompleteMeやdeopleteなどのauto-completion系プラグインの一つです。（LSPで動作します）
少し前まではdeopleteを使ってたのですが、Python依存が強くて動かなくなることが結構ありました。YouCompleteMeも依存モジュールが結構あって、deoplete同様設定周りが大変そうだったので、代替を探してた際に見つけたものです。これのすごいところは、

 - インストールすればすぐ使えるようになる
 - 補完がめちゃ早い
 - 専用の拡張が豊富（補完以外にも様々な拡張があり、これで事足りるんじゃないかというくらい）
    - https://www.npmjs.com/search?q=coc.nvim

設定はWikiに分かりやすく載ってるので読んでみてください。今使ってる拡張として

```vimscript
let g:coc_global_extensions = [
      \  'coc-lists'
      \, 'coc-json'
      \, 'coc-marketplace'
      \, 'coc-html'
      \, 'coc-css'
      \, 'coc-tsserver'
      \, 'coc-solargraph'
      \, 'coc-python'
      \, 'coc-snippets'
      \, 'coc-vetur'
      \ ]
```
があります。 この変数に設定しておくと、vim起動時にその拡張がなければ勝手にインストールしてくれます。


### 3. vim-easyclip
vimのヤンクや削除などのoperatorの操作を拡張させた感じのプラグインです。いくつかのマッピングが変更されています。
これを入れると、例えばddが一行削除とクリップボードにコピーが行われたものが、一行削除だけになりクリップボードにコピーされなくなります。代わりにmmが一行削除とクリップボードにコピーとなります。

#### おすすめマッピングと設定
```vim
# クリップボードにコピーしたものを履歴として残す。vim再起動時に復元
let g:EasyClipShareYanks = 1
```

vimscriptを書いてfzfを使って今までコピーした履歴から復元することも可能
vimを終了して再度開き直しても呼び出せるので、結構便利です。

```vim
# easycilpからコピーした一覧を取得
function! s:yank_list()
  redir => ys
  silent Yanks
  redir END
  return split(ys, '\n')[1:]
endfunction

# 引数からPasteコマンドで貼り付け
function! s:yank_handler(reg)
  if empty(a:reg)
    echo "aborted register paste"
  else
    let token = split(a:reg, ' ')
    execute 'Paste' . token[0]
  endif
endfunction

# fzfを使って一覧を呼び出して貼り付け
command! FZFYank call fzf#run({
\ 'source': <sid>yank_list(),
\ 'sink': function('<sid>yank_handler'),
\ 'options': '-m --prompt="FZFYank> "',
\ 'down':    '40%'
\ })

# マッピングはお好みで
nnoremap <C-Y><C-Y> :<C-U>FZFYank<CR>
inoremap <C-Y><C-Y> <C-O>:<C-U>FZFYank<CR>
```
こんな感じになります
![yank.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57325/2ee6d63c-8eae-e6c2-ae0b-79e2fda0d432.gif)

### 4.git-messenger.vim
https://github.com/rhysd/git-messenger.vim
カーソルの行変更のコミットをPreviewウィンドウやホップアップで確認することができるプラグイン
使う頻度はそこまで高くないですが、変更履歴をサッと確認するのに便利です。
マッピングはREADMEを読んで設定してみてください。

こんな感じになります
![messenger.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57325/cb288814-ab45-4add-bae2-641e19fdbb12.gif)


## マッピング編
プラグインとは関係ないけど、リマップしてよく使ってるものを抜粋

```vim
" escと押し間違えてhelpを開かないようにする
nmap <F1> <nop>
imap <F1> <nop>

" neovimのターミナルでECSキーでノーマルモードにする
if has("nvim")
  autocmd TermOpen * tnoremap <Esc> <C-\><C-N>
endif

" ウィンドウをCtrlとjklhで移動する
nmap <C-j> <C-w>j
nmap <C-k> <C-w>k
nmap <C-l> <C-w>l
nmap <C-h> <C-w>h

" 画面分割
noremap <silent><C-w>s :<C-u>split<CR>
noremap <silent><C-w>v :<C-u>vsplit<CR>

" 行移動
vnoremap <silent>J :m'>+1<CR>gv=gv
vnoremap <silent>K :m-2<CR>gv=gv
nnoremap <silent>J :m+<CR>==
nnoremap <silent>K :m-2<CR>==

" OS側のクリップボードにコピーする（vimのクリップボードと共有したくなかったので、必要なときだけコピーできるようにしてます）
command! Pbcopy0 :let @*=@0
nnoremap YY yy:<C-U>Pbcopy0<CR>:echomsg "Copy to Clipbord!"<CR>
vnoremap YY y:<C-U>Pbcopy0<CR>:echomsg "Copy to Clipbord!"<CR>

" スペースキー2回で保存する
noremap <space><space> :<C-U>w<CR>

" quickfixとlocation list内にあるファイル間の移動し、ターミナル中央に移動
nnoremap ]q :cnext<CR>zz
nnoremap [q :cprev<CR>zz
nnoremap ]l :lnext<CR>zz
nnoremap [l :lprev<CR>zz

```

## 設定編

```vim
" コメントアウト行後の改行時にコメントアウトを入れない
autocmd FileType * setlocal formatoptions-=ro

" この２つを設定すると、コマンドモードで小文字でもタブ補完できるようにする
set ignorecase
set smartcase

" neovimでターミナルの色がcolorschemeと違った感じになるのを防ぐ設定
if has("nvim")
  let g:terminal_color_0  = "#1b2b34" "black
  let g:terminal_color_1  = "#ed5f67" "red
  let g:terminal_color_2  = "#9ac895" "green
  let g:terminal_color_3  = "#fbc963" "yellow
  let g:terminal_color_4  = "#669acd" "blue
  let g:terminal_color_5  = "#c695c6" "magenta
  let g:terminal_color_6  = "#5fb4b4" "cyan
  let g:terminal_color_7  = "#c1c6cf" "white
  let g:terminal_color_background="#1b2b34" "background
  let g:terminal_color_foreground="#c1c6cf" "foreground
endif

" カーソルの位置を復元する
if has("autocmd")
  augroup redhat
    autocmd BufRead *.txt set tw=78
    autocmd BufReadPost *
    \ if line("'\"") > 0 && line ("'\"") <= line("$") |
    \   exe "normal! g'\"" |
    \ endif
    " git commitのカーソル位置は常に最初
    autocmd VimEnter FIleType gitcommit normal! gg0
    autocmd VimEnter COMMIT_EDITMSG  normal! gg0
  augroup END
endif

" vimでファイルを開いたときに、tmuxのwindow名にファイル名を表示
if exists('$TMUX') && !exists('$NORENAME')
  au BufEnter * if empty(&buftype) | call system('tmux rename-window "[vim]"'.expand('%:t:S')) | endif
  au VimLeave * call system('tmux set-window automatic-rename on')
endif
```

tmuxのファイル名の表示はこんな感じになります（左下のstatuslineを見るとわかります）
![openfile.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57325/e3753b2f-3827-a0e9-6e0e-0a3ee23b6137.gif)

# まとめ
ざっと書きましたが、ごく一部の設定になります。vimのカスタマイズって沼ですよね。手を付けてしまうとなかなか抜け出せないです。
自分だけのオリジナルのvimを作って、VSCodeに引けを取らないエディタを目指しましょう！