vimの環境がだいぶ煮詰まってきたので紹介する

vim2 advent calendar 2019 15日目です。

# 導入
vimと一口に言ってもその設定項目は多岐に渡ります。さらにプラグインも入れればプラグインそのものと設定を含めて、百人いれば百通りのvim環境が出来上がるでしょう。
なんだかんだでvimを使い続けて5年ほどになりますが、今まで煮詰めてきた自分のvim環境を百通りのうちの一つとして紹介するのがこの記事の趣旨です。

# neovim
vimと言ってもいくつか種類がありますが、自分が使用しているのはneovimです。
非同期がサポートされたあたりで乗り換えています。現在はvimでも非同期をサポートしており、neovimでしか動かなかったようなプラグインもvimで動くようになっているようです。今回のアドベントカレンダーに合わせて、neovim専用になっていた設定ファイルをvimでも使えるようにしたかったのですが、手元で試してみた限りうまくいかなかったのでいくつかの部分がneovimでしか動かなくなっています。ご了承ください。一応本来の想定は記述しておきます。

# フォルダ構成
## dotfiles
vim含め、様々な設定ファイルをdotfilesで管理しています。
dotfilesのルートは以下の構成になっています。

```
% tree -a -L 1                                                                                                                                                                                                                                                 
.
├── .config
├── .ctags
├── .git
├── .gitignore
├── .tmux
├── .vimrc
├── .zplugrc
├── .zsh
├── .zshrc
├── bin
├── etc
├── nvim -> /Users/takumikawase/dotfiles/.config/nvim
└── tags
```
更に.configの中身は以下のようになっています。

```
% tree -a -L 1                                                                                                                                                                                                                                         
.
├── anyenv
├── coc
├── efm-langserver
├── nvim
└── xbuild
```
いくつかのファイルは省略しています。
vimの設定ファイルはデフォルトでは.vimrcですが、neovimの設定ファイルはデフォルトでは.config/nvim下にあるinit.vimとなっています。
vimとneovimで同じ設定ファイルを使い回すために.vimrcの中身は以下の二行のみです。
set runtimepath+=$XDG_CONFIG_HOME/nvim
source $XDG_CONFIG_HOME/nvim/init.vim
これでvimを起動すると同時にneovimの設定ファイルをそのまま読み込んでくれます。あとはneovimの設定ファイルでvimかneovimかによって処理を分岐させることでvim, neovim量対応の設定が可能です。
自分のdotfilesについては「[CUI環境とdotfilesを紹介する](https://qiita.com/coil_msp123/items/c7a2927498a03bb63493)」を参照してください。

## nvim
nvimのフォルダ構成になります。

```
% tree -a -L 1                                                                                                                                                                                                                                             
.
├── autocmds.vim
├── autoload
├── coc-settings.json
├── coc.toml
├── color.vim
├── colors
├── commands.vim
├── dein.toml
├── dein.vim
├── dein_lang.toml
├── dein_lazy.toml
├── dein_lsp.toml
├── dein_plugin.toml
├── dein_vim.toml
├── func.vim
├── init.vim
├── keymappings.vim
├── linux.vim
├── mac.vim
├── tags
└── types.vim
```
元々は一つの.vimrcを使用していましたが、neovimへの移行に伴い段階的に機能ごとにファイル分けを行いました。
それぞれのファイルの役割は以下の通りです。

### init.vim
起動時に最初に読み込まれるファイルです。このファイルを起点に他のファイルを読み込んでいきます。
更に、setコマンドで各種設定を行なっています。


<details><summary>init.vim</summary><div>


```bash
" settings for mac and unix
if has('mac')
    " settings for mac
    source $HOME/.config/nvim/mac.vim
    " settings for linux
else
    source $HOME/.config/nvim/linux.vim
endif


" load dein.vim
source $XDG_CONFIG_HOME/nvim/dein.vim


" color scheme
source $XDG_CONFIG_HOME/nvim/color.vim


" load other setting files
" key mappings
source $HOME/.config/nvim/keymappings.vim


" settings for each filetypes
source $HOME/.config/nvim/types.vim


" launch commands
" source $HOME/.config/nvim/commands.vim


" autocommands
source $HOME/.config/nvim/autocmds.vim


" functions
" source $HOME/.config/nvim/func.vim


set number
set title
set ambiwidth=double
set tabstop=4
set expandtab
set shiftwidth=4
set smartindent
set list
set listchars=tab:»-,trail:-,extends:»,precedes:«,nbsp:%
set nrformats-=octal
set hidden
set history=200
set virtualedit=block
set whichwrap=b,s,h,l,[,],<,>
set backspace=indent,eol,start
set wildmenu
set fenc=utf-8
set nobackup
set noswapfile
set autoread
set showcmd
set cursorline
set visualbell
set laststatus=2
set wrapscan
set modeline
set autowrite
set display=lastline
set matchpairs& matchpairs+=<:>
set matchtime=1
set showtabline=2
set wildmenu
set wildignore=*.o,*.obj,*.pyc,*.so,*.dll
set mouse=a
set updatetime=100


" search system
set showmatch
set smartcase
set ignorecase
set infercase
set hlsearch
set incsearch


" foldmethod
set foldmethod=marker
set foldlevel=0
set foldcolumn=1


" disable the preview window
set completeopt-=preview


if has('nvim')
    set pumblend=5
endif
```


最後のset pumblendはneovimのfloating windowを使うためのオプションです。
</div></details>


### dein.vim
後述するvimのプラグインマネージャーであるdeinで、各種プラグインを読み込むためのファイルです。
ちなみにインストールするプラグインはtomlファイルで管理していますが、tomlファイルも用途ごとにファイルを分けています。


<details><summary>dein.vim</summary><div>


```bash
" dein Scripts-----------------------------
if &compatible
    set nocompatible               " Be iMproved
endif


" set cache and config dirs
let s:dein_cache_dir = $XDG_CACHE_HOME . '/dein'
let s:dein_config_dir = $XDG_CONFIG_HOME . '/nvim'


" Required:
set runtimepath+=$XDG_CACHE_HOME/dein/repos/github.com/Shougo/dein.vim


let s:dein_dir = s:dein_cache_dir . '/repos/github.com/Shougo/dein.vim'
if !isdirectory(s:dein_dir)
    call system('git clone https://github.com/Shougo/dein.vim ' . shellescape(s:dein_dir))
endif


" Required:
if dein#load_state(s:dein_cache_dir)
    call dein#begin(s:dein_cache_dir)


    let s:toml = s:dein_config_dir . '/dein.toml'
    let s:toml_lazy = s:dein_config_dir . '/dein_lazy.toml'
    let s:toml_coc = s:dein_config_dir . '/coc.toml'
    let s:toml_lang = s:dein_config_dir . '/dein_lang.toml'
    let s:toml_plugin = s:dein_config_dir . '/dein_plugin.toml'
    let s:toml_vim = s:dein_config_dir . '/dein_vim.toml'




    call dein#load_toml(s:toml, {'lazy': 0})
    call dein#load_toml(s:toml_lazy, {'lazy': 1})
    call dein#load_toml(s:toml_coc, {'lazy': 1})
    call dein#load_toml(s:toml_lang, {'lazy': 1})
    call dein#load_toml(s:toml_plugin, {'lazy': 0})
    if !has('nvim')
        call dein#load_toml(s:toml_vim, {'lazy': 0})
    endif


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


    " Let dein manage dein
    " Required:
    " call dein#add('/Users/kawasetakumi/.cache/dein/repos/github.com/Shougo/dein.vim')


    " Add or remove your plugins here:
    " call dein#add('Shougo/neosnippet.vim')
    " call dein#add('Shougo/neosnippet-snippets')


    " You can specify revision/branch/tag.
    " call dein#add('Shougo/vimshell', { 'rev': '3787e5' })


    " Required:
    " call dein#end()
    " call dein#save_state()
endif
    
" Required:
filetype plugin indent on


" if dein#check_install(['vimproc'])
"     call dein#install(['vimproc'])
" endif


" If you want to install not installed plugins on startup.
if dein#check_install()
    call dein#install()
endif


" End dein Scripts-------------------------
```
</div></details>


### autocmds.vim
autocmd類をこちらに定義しています。現在は各種Filetypeをトリガーに動くautocmdが全てを占めています。


<details><summary>autocmds.vim</summary><div>


```bash
"" push quickfix window always to the bottom
autocmd FileType qf wincmd J


" for go lang
augroup go
    autocmd!
    autocmd FileType go :highlight goErr cterm=bold ctermfg=214
    autocmd FileType go :match goErr /\<err\>/
augroup END


" for python
augroup python
    autocmd!
    autocmd FileType python :syn match pythonOperator "\(+\|=\|-\|\^\|\*\)"
    autocmd FileType python :syn match pythonDelimiter "\(,\|\.\|:\)"
    autocmd FileType python :syn keyword self self
    autocmd FileType python :hi link pythonOperator Statement
    autocmd FileType python :hi link pythonDelimiter Special
    autocmd FileType python :hi link self Type
    " autocmd FileType python :highlight self cterm=bold ctermfg=214
    " autocmd FileType python :match self /self/
    " autocmd FileType python :highlight colon cterm=bold ctermfg=214
    " autocmd FileType python :match colon /:/
augroup END


" for c++
augroup cpp
    autocmd!
    autocmd FileType cpp :highlight cppcoloncolon cterm=bold ctermfg=214
    autocmd FileType cpp :match cppcoloncolon /\:\:/
augroup END


augroup typescript
    autocmd!
    autocmd FileType typescript :syn match Operator "\(|\|+\|=\|-\|\^\|\*\)"
    autocmd FileType typescript :syn match Delimiter "\(\.\|:\)"
    autocmd FileType typescript :hi link Operator Statement
    autocmd FileType typescript :hi link Delimiter Special
augroup END


augroup typescriptreact
    autocmd!
    autocmd BufNewFile,BufRead *.tsx set filetype=typescript.tsx
    autocmd FileType typescript.tsx :syn match Operator "\(|\|+\|=\|-\|\^\|\*\)"
    autocmd FileType typescript.tsx :syn match Delimiter "\(\.\|:\)"
    autocmd FileType typescript.tsx  :hi link Operator Statement
    autocmd FileType typescript.tsx :hi link Delimiter Special
augroup END


augroup denite-windows
    autocmd!
    autocmd FileType denite set winblend=5
    autocmd FileType denite-filter set winblend=5
augroup END


" Define mappings
autocmd FileType denite call s:denite_my_settings()
function! s:denite_my_settings() abort
    nnoremap <silent><buffer><expr> <CR>
    \ denite#do_map('do_action')
    nnoremap <silent><buffer><expr> d
    \ denite#do_map('do_action', 'delete')
    nnoremap <silent><buffer><expr> p
    \ denite#do_map('do_action', 'preview')
    nnoremap <silent><buffer><expr> q
    \ denite#do_map('quit')
    nnoremap <silent><buffer><expr> i
    \ denite#do_map('open_filter_buffer')
    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


autocmd FileType defx call s:defx_my_settings()
function! s:defx_my_settings() abort
    " Define mappings
    nnoremap <silent><buffer><expr> <CR>
    \ defx#do_action('drop')
    nnoremap <silent><buffer><expr> c
    \ defx#do_action('copy')
    nnoremap <silent><buffer><expr> m
    \ defx#do_action('move')
    nnoremap <silent><buffer><expr> p
    \ defx#do_action('paste')
    nnoremap <silent><buffer><expr> l
    \ defx#do_action('open')
    nnoremap <silent><buffer><expr> E
    \ defx#do_action('open', 'vsplit')
    nnoremap <silent><buffer><expr> P
    \ defx#do_action('open', 'pedit')
    nnoremap <silent><buffer><expr> o
    \ defx#do_action('open_or_close_tree')
    nnoremap <silent><buffer><expr> K
    \ defx#do_action('new_directory')
    nnoremap <silent><buffer><expr> N
    \ defx#do_action('new_file')
    nnoremap <silent><buffer><expr> M
    \ defx#do_action('new_multiple_files')
    nnoremap <silent><buffer><expr> C
    \ defx#do_action('toggle_columns',
    \                'mark:indent:icon:filename:type:size:time')
    nnoremap <silent><buffer><expr> S
    \ defx#do_action('toggle_sort', 'time')
    nnoremap <silent><buffer><expr> d
    \ defx#do_action('remove')
    nnoremap <silent><buffer><expr> r
    \ defx#do_action('rename')
    nnoremap <silent><buffer><expr> !
    \ defx#do_action('execute_command')
    nnoremap <silent><buffer><expr> x
    \ defx#do_action('execute_system')
    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('repeat')
    nnoremap <silent><buffer><expr> h
    \ defx#do_action('cd', ['..'])
    nnoremap <silent><buffer><expr> ~
    \ defx#do_action('cd')
    nnoremap <silent><buffer><expr> q
    \ defx#do_action('quit')
    nnoremap <silent><buffer><expr> <Space>
    \ defx#do_action('toggle_select') . 'j'
    nnoremap <silent><buffer><expr> *
    \ defx#do_action('toggle_select_all')
    nnoremap <silent><buffer><expr> j
    \ line('.') == line('$') ? 'gg' : 'j'
    nnoremap <silent><buffer><expr> k
    \ line('.') == 1 ? 'G' : 'k'
    nnoremap <silent><buffer><expr> <C-l>
    \ defx#do_action('redraw')
    nnoremap <silent><buffer><expr> <C-g>
    \ defx#do_action('print')
    nnoremap <silent><buffer><expr> cd
    \ defx#do_action('change_vim_cwd')
endfunction
```
</div></details>


### color.vim
カラースキームやハイライトの設定をここでまとめて行っています。


<details><summary>color.vim</summary><div>


```bash
set t_8f=^[[38;2;%lu;%lu;%lum
set t_8b=^[[48;2;%lu;%lu;%lum
colorscheme default
set bg=light


" syntax highlight
if has('syntax')
syntax enable
endif


" hi fold'
hi Folded ctermbg=0 ctermfg=2
hi FoldColumn ctermbg=8 ctermfg=2


" hi popup
hi Pmenu ctermfg=15 ctermbg=0
hi PmenuSel ctermfg=0 ctermbg=15
hi PMenuSbar ctermfg=15 ctermbg=0


" hilight color
hi Search ctermbg=lightyellow
hi Search ctermfg=black
hi CursorColumn ctermbg=lightyellow
hi CursorColumn ctermfg=black
hi SpellBad ctermfg=black
hi SpellRare ctermfg=black
```
</div></details>


### keymappings.vim
ファイル名通りキーマッピングをここでまとめて定義しています。キーマッピングはプラグインで設定されるものが衝突しやすいので:nnoremapなどを使って確認しながら設定することをおすすめします。
<details><summary>keymappings.vim</summary><div>


```bash
" set <Leader> to <Space>
let mapleader = "\<Space>"


" mappings for plugins
nmap [denite] <Nop>
map <Space>u [denite]


" mappings for the quickfix window
nnoremap <Space>n :cn<CR>
nnoremap <Space>p :cp<CR>
nnoremap <Space>q :ccl<CR>
nnoremap <Space>w :botright cwindow<CR>


nnoremap <Space><Space> i<Space><Esc>


" mapping for ctags
nnoremap <C-]> g<C-]>


nnoremap j gj
nnoremap k gk
nnoremap <Down> gj
nnoremap <Up> gk
nnoremap gj j
nnoremap gk k


nnoremap <C-6> :b #


" change the terminal mode to the normal mode.
tnoremap <silent> <ESC> <C-\><C-n>


autocmd FileType go nmap [vim-go] <Nop>
autocmd FileType go nmap <leader>g [vim-go]


autocmd FileType go nmap [vim-go]t <Plug>(go-test)


function! s:build_go_files()
let l:file = expand('%')
if l:file =~# '^\f\+_test\.go$'
call go#test#Test(0, 1)
elseif l:file =~# '^\f\+\.go$'
call go#cmd#Build(0)
endif
endfunction


autocmd FileType go nmap [vim-go]b :<C-u>call <SID>build_go_files()<CR>


autocmd FileType go nmap [vim-go]c <Plug>(go-coverage-toggle)
```
</div></details>

 
### autoload
プラグインの設定は、関数としてautoload以下にまとめて置いておき、プラグインの読み込みの際にdeinの機能で関数を呼び出しています。


# プラグイン
実際に使用しているプラグインについて紹介していきます。
先程から名前が出ている通りプラグインマネージにはdeinを使用しています。最初期はvim-plugを使用していましたが、deinが流行ってくるのにあわせて移行しました。
正直これについてはvim-plugでもdeinでもどちらでも良い気がします。


## tomlファイル
使用したいプラグインと設定をtomlファイルに書き込みdeinでロードすることでプラグインが使用可能になります。
deinの関数で一つずつプラグインを追加することも可能なようですが、deinを使う場合はtomlファイルによるプラグインの管理をおすすめします。
更にtomlファイルを読み込む際、lazyオプションを追加することで遅延ロードが可能になります。vim起動時にたくさんのプラグインを読み込むのは起動が遅くなるので、起動時に必要かに応じてlazyオプションを付与するのが良いと思います。
現在使用しているtomlファイルは以下のとおりです。
% ls -1 | grep toml                                                                                                                                [~/.config/nvim] 
dein_plugin.toml
dein.toml
coc.toml # lazy
dein_lang.toml # lazy
dein_vim.toml
dein_lazy.toml # lazy
\# lazyと横に書いているものは遅延ロードされるtomlファイルです。遅延ロードを行う際は、tomlファイル内のプラグイン一つ一つに対して読み込む条件を設定します。


### dein.toml
vimを起動する際に必ず実行するプラグイン群です。


```bash
[[plugins]]
repo = 'Shougo/dein.vim'
 
[[plugins]]
repo = 'itchyny/lightline.vim'
depends = 'gina.vim'
hook_add = 'call config#init#lightline#hook_add()'
 
[[plugins]]
repo = 'soramugi/auto-ctags.vim'
hook_add = '''
    let g:auto_ctags = 1
'''
 
[[plugins]]
repo = 'tpope/vim-surround'
 
[[plugins]]
repo = 't9md/vim-quickhl'
hook_add = 'call config#init#vim_quickhl#hook_add()'
 
[[plugins]]
repo = 'w0rp/ale'
hook_add = 'call config#init#ale#hook_add()'
 
[[plugins]]
repo = 'maximbaz/lightline-ale'
 
[[plugins]]
repo = 'junegunn/fzf'
build = './install --all'
 
[[plugins]]
repo = 'junegunn/fzf.vim'
 
[[plugins]]
repo = 'airblade/vim-gitgutter'
 
[[plugins]]
repo = 'lambdalisue/gina.vim'
 
[[plugins]]
repo = 'ryanoasis/vim-devicons'
 
[[plugins]]
repo = 'luochen1990/rainbow'
hook_add = '''
    let g:rainbow_active = 1
'''
```
余談ですが、deinではhook_add, hook_sourceなどのフックを使用してプラグインを読むこむ際のどこかのタイミングに処理を挟むことができます。
基本的にはhook_addでプラグインの使用に必要な設定を行っていますが、設定が長い場合は関数として切り出してファイルをautoload/config/initフォルダ以下に置き、その関数をコールするようにしています。
また、場合によっては他のフックを使いますが、そちらも同じようなルールで運用しています。


#### [itchyny/lightline.vim](https://github.com/itchyny/lightline.vim)
vimの下部にステータスラインを追加するプラグインです。他のプラグインと連携して表示する情報を増やすことができます。
gina.vimを使用したブランチの表示、cocを使用した関す情報の表示を行っています。


<details><summary>lightline.vim</summary><div>


```bash
function! config#init#lightline#hook_add() abort
    let g:lightline = {
      \ 'colorscheme': 'wombat',
      \ 'active': {
      \     'left': [['mode', 'paste'],
      \              ['gitbranch', 'readonly', 'filename', 'modified']],
      \     'right': [['lineinfo'], ['percent'], ['fileformat', 'fileencoding', 'filetype'],
      \              ['cocstatus', 'currentfunction']]
      \ },
      \ 'component_function': {
      \     'gitbranch': 'gina#component#repo#branch',
      \     'mode': 'LightlineMode',
      \     'cocstatus': 'coc#status',
      \     'currentfunction': 'CocCurrentFunction'
      \ }
      \ }
endfunction


function! LightlineMode()
    return &ft == 'denite' ? 'Denite' :
      \    &ft == 'vimfiler' ? 'VimFiler' :
      \    winwidth(0) > 60 ? lightline#mode() : ''
endfunction


function! CocCurrentFunction()
    return get(b:, 'coc_current_function', '')
endfunction
```

lightlineの設定例です。このように設定が複数行に渡る場合は関数に切り出してファイルとしてautoload/config/init以下に置いておき、hookからコールするようにしています。
</div></details>


#### [soramugi/auto-ctags.vim](https://github.com/soramugi/auto-ctags.vim)
vimにはctagsと連携して関数定義に移動する機能が備わっています。実はその機能はLSPを導入することでより便利に行うことが可能なのですが、後述のtagbarというプラグインのためにctagsを生成するようにしています。ただ、デフォルトではctagsは手動で実行する必要があるのでそれを自動化するプラグインです。g:auto_ctagsオプションをオンにすることで保存時に自動で生成してくれます。


#### [tpope/vim-surround](https://github.com/tpope/vim-surround)
ある文字列を囲んでいるHTMLタグやクォートなどを消したり変更したり追加するコマンドを追加するプラグインです。コマンドが覚えにくいのでなれないうちは都度調べる必要があるのが面倒ですが、ちょくちょく機能が欲しくなるプラグインです。


#### [t9md/vim-quickhl](https://github.com/t9md/vim-quickhl)
単語のハイライトを自動で行ったり、特定の文字列をハイライトできるプラグインです。いくらでもハイライトがつけられるのでコードリーディングの際などに便利です。


#### [w0rp/ale](https://github.com/w0rp/ale)
言語のlinterを使ってコードをチェックしてくれるプラグインです。デフォルトでも多くのlinterやその他ツールに対応しているので、とりあえずlinter等をインストールすればすぐ使えるのが強みです。最近はLSP機能も入ったようですが、自分は使用していません。


<details><summary>ale.vim</summary><div>


```bash
function! config#init#ale#hook_add() abort
    highlight clear ALEError
    highlight clear ALEWarning
    let g:ale_lint_on_enter = 0
    let g:ale_sign_column_always = 1
    let g:ale_set_loclist = 0
    let g:ale_set_quickfix = 1
    if has('mac')
        let s:header_path = '-I/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include'
        let g:ale_cpp_clang_options = '-std=c++14 -Wall ' . s:header_path
        let g:ale_cpp_gcc_options = '-std=c++14 -Wall ' . s:header_path
    endif
    let g:ale_linters = {
                \ 'c': ['clangd'],
                \ 'cpp' : ['clangd']
                \ }
endfunction
```
設定例です。c, cppのlinterについてはclangdを使用するように明示しています。


</div></details>


#### [airblade/vim-gitgutter](https://github.com/airblade/vim-gitgutter)
gitの差分が発生した場合に、どこにどのような差分が発生しているかを行頭に表示してくれます。


#### [lambdalisue/gina.vim](https://github.com/lambdalisue/gina.vim)
vim中でgitを扱うためにプラグインですが、自分は基本的にtmuxで開いている別ペインでgitを使用しています。
なのでlightlineでブランチを表示するためにプラグインになりかけてます...


#### [luochen1990/rainbow](https://github.com/luochen1990/rainbow)
vimでも括弧の色分けができるようになります。素のvimでも対応する括弧にハイライトをつけたり、%コマンドで対応する括弧に移動ができますが、色による視認性の方が高いです。


### dein_vim.toml
neovimではなくvimでneovim用に作られたプラグインを動かすための前提プラグイン用です。
dein.vimの方で、使用しているクライアントがnvimでない(=vim)のときに読み込みます。


```bash
[[plugins]]
repo = 'roxma/vim-hug-neovim-rpc'


[[plugins]]
repo = 'roxma/nvim-yarp'
```
ただ、これで動くと思っていたのですが、どうもpythonがうまく呼べてないようで、エラーが出てうまくいっていません。（情報欲しいです！）




### dein_lazy.toml
名前の通り遅延ロードしているプラグインです。比較的重そうなプラグインや、特定の状況下で動く必ずしも起動時に必要ではないプラグインは出来るだけ遅延ロードさせるようにしています。


```toml
[[plugins]]
repo = 'Shougo/denite.nvim'
on_cmd = ['Denite']
depends = ['vim-devicons']
hook_add = 'call config#init#denite#hook_add()'
hook_post_source = 'call config#init#denite#hook_post_source()'


[[plugins]]
repo = 'Shougo/neomru.vim'
on_cmd = ['Denite']
on_source = ['denite.nvim']


[[plugins]]
repo = 'Shougo/neoyank.vim'
on_cmd = ['Denite']
on_source = ['denite.nvim']


[[plugins]]
repo = 'cespare/vim-toml'
on_ft = 'toml'


[[plugins]]
repo = 'majutsushi/tagbar'
on_cmd = ['TagbarToggle']
hook_add = 'call config#init#tagbar#hook_add()'
hook_source = 'call config#init#tagbar#hook_source()'


[[plugins]]
repo = 'cohama/lexima.vim'
on_event = 'InsertEnter'


[[plugins]]
repo = 'scrooloose/nerdtree'
on_cmd = ['NERDTreeToggle']
depends = ['vim-devicons', 'vim-nerdtree-syntax-highlight', 'nerdtree-git-plugin']
hook_add = 'call config#init#nerdtree#hook_add()'
hook_source = 'call config#init#nerdtree#hook_source()'


[[plugins]]
repo = 'Xuyuanp/nerdtree-git-plugin'


[[plugins]]
repo = 'tiagofumo/vim-nerdtree-syntax-highlight'


[[plugins]]
repo = 'ryanoasis/vim-devicons'
```


#### [Shougo/denite.nvim](https://github.com/Shougo/denite.nvim)
開いているバッファーやカレントディレクトリ以下のファイル、最近開いたファイルなどに素早くアクセスするためのインターフェースを提供するプラグインです。
ファイラーのように一覧表示されているのも便利ですが、名前のわかっているファイルへの移動についてはこちらのほうが高速です。こちらを導入する際にはripgrepなどの導入も合わせて行うと効果的です。遅延ロードの条件はdenite実行時にしています。


<details><summary>denite.vim</summary><div>


```bash
function! config#init#denite#hook_add() abort
    " defined in keymappings.vim
    " Prefix for denite
    " nmap [denite] <Nop>
    " map <Space>u [denite]


    " key mappings for Denite and sources
    nnoremap <silent> [denite]y :<C-u>Denite neoyank -split=floating<CR>
    nnoremap <silent> [denite]u :<C-u>Denite buffer file/rec -split=floating<CR>
    nnoremap <silent> [denite]f :<C-u>Denite file/rec -split=floating<CR>
    nnoremap <silent> [denite]b :<C-u>Denite buffer -split=floating<CR>
    nnoremap <silent> [denite]m :<C-u>Denite file_mru -split=floating<CR>
    nnoremap <silent> [denite]a :<C-u>Denite -resume -split=floating<CR>


    " settings for grep
    nnoremap <silent> [denite]g :<C-u>Denite grep -buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]w :<C-u>DeniteCursorWord grep -buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]r :<C-u>Denite -resume -buffer-name=search-buffer-denite -split=floating<CR>
    nnoremap <silent> [denite]n :<C-u>Denite -resume -buffer-name=search-buffer-denite -cursor-pos=+1 -immediately -split=floating<CR>
    nnoremap <silent> [denite]p :<C-u>Denite -resume -buffer-name=search-buffer-denite -cursor-pos=-1 -immediately -split=floating<CR>
endfunction


function! config#init#denite#hook_post_source() abort
    " Change the prompt
    call denite#custom#option('default', 'prompt', '>')


    " Add action keybinds
    call denite#custom#map('insert', '<C-v>', '<denite:do_action:vsplit>')
    call denite#custom#map('insert', '<C-s>', '<denite:do_action:split>')
    call denite#custom#map('normal', '<C-v>', '<denite:do_action:vsplit>')
    call denite#custom#map('normal', '<C-s>', '<denite:do_action:split>')


    call denite#custom#map('insert', '<C-n>', '<denite:move_to_next_line>')
    call denite#custom#map('insert', '<C-p>', '<denite:move_to_previous_line>')
    call denite#custom#map('normal', '<C-n>', '<denite:move_to_next_line>')
    call denite#custom#map('normal', '<C-p>', '<denite:move_to_previous_line>')


    " Variables
    "grepでagを使用するように設定
    call denite#custom#var('grep', 'command', ['rg'])
    "カレントディレクトリ内の検索もagを使用する
    call denite#custom#var('file/rec', 'command', ['rg', '--files', '--glob', '!.git'])
    " call denite#custom#var('file/rec', 'command', ['ag', '--follow', '--nocolor', '--nogroup', '-g', ''])
    "その他のgrepの設定
    call denite#custom#var('grep', 'default_opts',['-i', '--vimgrep', '--no-heading'])
    call denite#custom#var('grep', 'recursive_opts', [])
    call denite#custom#var('grep', 'pattern_opt', ['--regexp'])
    call denite#custom#var('grep', 'separator', ['--'])
    call denite#custom#var('grep', 'final_opts', [])
endfunction
```
 
</div></details>


#### [Shougo/neomru.vim](https://github.com/Shougo/neomru.vim)
deniteのソースに"最近開いたバッファ"を追加します。deniteのインターフェースで検索を行う際に最近開いたバッファも検索対象として結果に出てくるようになります。


#### [Shougo/neoyank.vim](https://github.com/Shougo/neoyank.vim)
上記同様に、yankしたものについてもdeniteのソースに追加できます。


#### [cespare/vim-toml](https://github.com/cespare/vim-toml)
vimでtomlファイルを編集する際に、シンタックスを追加してくれるプラグインです。deinなどでtomlファイルを編集する場合は入れておくと便利かもしれません。


#### [majutsushi/tagbar](https://github.com/majutsushi/tagbar)
前述したctagsの中身を画面に表示するプラグインです。ctagsによる生成がうまく行っていれば、ファイル内の変数やクラス、関数などの一覧が表示されます。


<details><summary>tagbar.vim</summary><div>


```bash
function! config#init#tagbar#hook_add() abort
    let g:tagbar_width=40
    nmap <Space>z :TagbarToggle<CR>
endfunction


function! config#init#tagbar#hook_source() abort
    let g:tagbar_type_go = {
    \ 'ctagstype' : 'go',
    \ 'kinds'     : [
        \ 'p:package',
        \ 'i:imports:1',
        \ 'c:constants',
        \ 'v:variables',
        \ 't:types',
        \ 'n:interfaces',
        \ 'w:fields',
        \ 'e:embedded',
        \ 'm:methods',
        \ 'r:constructor',
        \ 'f:functions'
    \ ],
    \ 'sro' : '.',
    \ 'kind2scope' : {
        \ 't' : 'ctype',
        \ 'n' : 'ntype'
    \ },
    \ 'scope2kind' : {
        \ 'ctype' : 't',
        \ 'ntype' : 'n'
    \ },
    \ 'ctagsbin'  : 'gotags',
    \ 'ctagsargs' : '-sort -silent'
    \ }
    let g:tagbar_type_typescript = {                                                  
      \ 'ctagsbin' : 'ctags',                                                        
      \ 'kinds': [                                                                     
        \ 'e:enums:0:1',                                                               
        \ 'f:function:0:1',                                                            
        \ 't:typealias:0:1',                                                           
        \ 'M:Module:0:1',                                                              
        \ 'I:import:0:1',                                                              
        \ 'i:interface:0:1',                                                           
        \ 'C:class:0:1',                                                               
        \ 'm:method:0:1',                                                              
        \ 'p:property:0:1',                                                            
        \ 'v:variable:0:1',                                                            
        \ 'c:const:0:1',                                                              
      \ ],                                                                            
      \ 'sort' : 0                                                                    
    \ }                   
endfunction
```
 
goとtypescriptについてはデフォルトでは物足りないので設定を追加しています。
</div></details>


#### [cohama/lexima.vim](https://github.com/cohama/lexima.vim)
括弧やクォートを入力した際に対応する閉じ括弧を自動で付け足してくれるプラグインです。基本的には便利ですが、括弧を消したときや閉じ括弧を入力したときにうまく括弧の数が揃わない場合があるので注意が必要です。また、pythonの複数行コメントを入力したい場合など、クォートの数がイレギュラーな場合はうまく補完ができません。


#### [scrooloose/nerdtree](https://github.com/scrooloose/nerdtree)
vimのファイラーです。少し前までdefxを使用していましたが、ファイルのアイコンを表示した際にファイル名の表記が崩れるのでこちらに移行しました。
こちらでもファイル名の表記は多少崩れますが、defxに比べれば少ないので許容範囲内としています。vimにも実はファイラーは付属していますが、defxやnerdtreeのほうが操作が直感的でわかりやすいです。


<details><summary>nerdtree.vim</summary><div>


```bash
function! config#init#nerdtree#hook_add() abort
    nnoremap <silent> <Space>v :<C-u>NERDTreeToggle<CR>
endfunction


function! config#init#nerdtree#hook_source() abort
    let g:NERDTreeWinSize = 40
    let g:WebDevIconsUnicodeGlyphDoubleWidth = 0
    let g:WebDevIconsNerdTreeBeforeGlyphPadding = ''
    let g:WebDevIconsNerdTreeAfterGlyphPadding = '  '
    let g:WebDevIconsUnicodeDecorateFolderNodes = 0
endfunction
```
 
</div></details>


#### [Xuyuanp/nerdtree-git-plugin](https://github.com/Xuyuanp/nerdtree-git-plugin)
nerdtree上で、gitのステータスを表示してくれるプラグインです。


#### [tiagofumo/vim-nerdtree-syntax-highlight](https://github.com/tiagofumo/vim-nerdtree-syntax-highlight)
nerdtree上で、シンタックスハイライトを追加してくれるプラグインです。純粋に視認性が上がるのでおすすめです。
 
#### [ryanoasis/vim-devicons](https://ryanoasis/vim-devicons)
vim内でdeviconを表示するためのプラグインです。deniteやnerdtreeでファイル名の頭にアイコンがつくようになってsyntax-highlightと同じく視認性が上がります。


### dein_lang.toml
言語依存のプラグインをon_ftを使用して特定のファイルタイプのときに実行するようにしています。vimのデフォルトだと言語のサポート(syntax highlight)が不十分な場合に補ったり特定の言語のサポートツールをvimで使えるようにします。


```toml
[[plugins]]
repo = 'rust-lang/rust.vim'
on_ft = 'rust'
hook_source = 'call config#init#rust#hook_source()'


[[plugins]]
repo = 'octol/vim-cpp-enhanced-highlight'
on_ft = ['c', 'cpp']


[[plugins]]
repo = 'fatih/vim-go'
on_ft = 'go'
hook_source = 'call config#init#vim_go#hook_source()'


[[plugins]]
repo = 'neovimhaskell/haskell-vim'
on_ft = 'haskell'
```


#### [rust-lang/rust.vim](https://github.com/rust-lang/rust.vim)
vimでrustを書く際に、シンタックスハイライトを効かせたり、その他フォーマッターなどのサポートが導入できます。


#### [octol/vim-cpp-enhanced-hightlight](https://github.com/octol/vim-cpp-enhanced-highlight)
より新しいバージョンのc, c++についてもシンタックスハイライトが効くようになるプラグインです。


#### [fatih/vim-go](https://github.com/fatih/vim-go)
vimでgoを書くならば必須のプラグイン。goは周辺のツールが充実しており、それらをvimでうまく使えるようにしてくれます。


<details><summary>vim_go.vim</summary><div>


```bash
function! config#init#vim_go#hook_source() abort
    let g:go_highlight_array_whitespace_error = 1
    let g:go_highlight_chan_whitespace_error = 1
    let g:go_highlight_extra_types = 1
    let g:go_highlight_space_tab_error = 1
    let g:go_highlight_trailing_whitespace_error = 1
    let g:go_highlight_operators = 1
    let g:go_highlight_functions = 1
    let g:go_highlight_function_parameters = 1
    let g:go_highlight_function_calls = 1
    let g:go_highlight_types = 1
    let g:go_highlight_fields = 1
    let g:go_highlight_build_constraints = 1
    let g:go_highlight_generate_tags = 1
    let g:go_highlight_variable_declarations = 1
    let g:go_highlight_variable_assignments = 1
    let g:go_fmt_command = "goimports"
    let g:go_auto_type_info = 1
    let g:go_auto_sameids = 1
    let g:go_list_type = "quickfix"
endfunction
```
 
</div></details>


#### [neovimhaskell/haskell-vim](https://github.com/neovimhaskell/haskell-vim)
同じくvimでhaskellを書きやすいようにシンタックスハイライトやインデントのルールなどを追加してくれるプラグインです。


### coc.toml
lspクライアントであるcoc.nvimのためのtomlファイルです。もともとlsp関連プラグイン用のファイルとしてdein_lspがありましたが、coc.nvimを導入したことでlsp関連は全て間に合うのでこのようなファイル名になりました。


```
[[plugins]]
repo = 'neoclide/coc.nvim'
rev = 'release'
on_i = 1
merged = '0'
hook_source = 'call config#init#coc#hook_source()'
```


<details><summary>coc.vim</summary><div>


```bash
function! config#init#coc#hook_source() abort
    " if hidden is not set, TextEdit might fail.
    set hidden


    " Some servers have issues with backup files, see #649
    set nobackup
    set nowritebackup


    " Better display for messages
    " set cmdheight=2


    " You will have bad experience for diagnostic messages when it's default 4000.
    set updatetime=300


    " don't give |ins-completion-menu| messages.
    set shortmess+=c


    " always show signcolumns
    set signcolumn=yes


    " Use tab for trigger completion with characters ahead and navigate.
    " Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
    inoremap <silent><expr> <TAB>
          \ pumvisible() ? "\<C-n>" :
          \ <SID>check_back_space() ? "\<TAB>" :
          \ coc#refresh()
    inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"


    function! s:check_back_space() abort
      let col = col('.') - 1
      return !col || getline('.')[col - 1]  =~# '\s'
    endfunction


    " Use <c-space> to trigger completion.
    inoremap <silent><expr> <c-space> coc#refresh()


    " Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
    " Coc only does snippet and additional edit on confirm.
    inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
    " Or use `complete_info` if your vim support it, like:
    " inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"


    " Use `[g` and `]g` to navigate diagnostics
    nmap <silent> [g <Plug>(coc-diagnostic-prev)
    nmap <silent> ]g <Plug>(coc-diagnostic-next)


    " Remap keys for gotos
    nmap <silent> gd <Plug>(coc-definition)
    nmap <silent> gy <Plug>(coc-type-definition)
    nmap <silent> gi <Plug>(coc-implementation)
    nmap <silent> gr <Plug>(coc-references)


    " Use K to show documentation in preview window
    nnoremap <silent> K :call <SID>show_documentation()<CR>


    function! s:show_documentation()
      if (index(['vim','help'], &filetype) >= 0)
        execute 'h '.expand('<cword>')
      else
        call CocAction('doHover')
      endif
    endfunction


    " Highlight symbol under cursor on CursorHold
    " autocmd CursorHold * silent call CocActionAsync('highlight')


    " Remap for rename current word
    nmap <leader>rn <Plug>(coc-rename)


    " Remap for format selected region
    xmap <leader>f  <Plug>(coc-format-selected)
    nmap <leader>f  <Plug>(coc-format-selected)


    augroup mygroup
      autocmd!
      " Setup formatexpr specified filetype(s).
      autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
      " Update signature help on jump placeholder
      autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
    augroup end


    " Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
    xmap <leader>a  <Plug>(coc-codeaction-selected)
    nmap <leader>a  <Plug>(coc-codeaction-selected)


    " Remap for do codeAction of current line
    nmap <leader>ac  <Plug>(coc-codeaction)
    " Fix autofix problem of current line
    nmap <leader>qf  <Plug>(coc-fix-current)


    " Create mappings for function text object, requires document symbols feature of languageserver.


    xmap if <Plug>(coc-funcobj-i)
    xmap af <Plug>(coc-funcobj-a)
    omap if <Plug>(coc-funcobj-i)
    omap af <Plug>(coc-funcobj-a)


    " Use <tab> for select selections ranges, needs server support, like: coc-tsserver, coc-python
    nmap <silent> <TAB> <Plug>(coc-range-select)
    xmap <silent> <TAB> <Plug>(coc-range-select)
    xmap <silent> <S-TAB> <Plug>(coc-range-select-backword)


    " Use `:Format` to format current buffer
    command! -nargs=0 Format :call CocAction('format')


    " Use `:Fold` to fold current buffer
    command! -nargs=? Fold :call     CocAction('fold', <f-args>)


    " use `:OR` for organize import of current buffer
    command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')


    " Add status line support, for integration with other plugin, checkout `:h coc-status`
    " set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}


    " Using CocList
    " Show all diagnostics
    nnoremap <silent> <space>a  :<C-u>CocList diagnostics<cr>
    " Manage extensions
    nnoremap <silent> <space>e  :<C-u>CocList extensions<cr>
    " Show commands
    nnoremap <silent> <space>c  :<C-u>CocList commands<cr>
    " Find symbol of current document
    nnoremap <silent> <space>o  :<C-u>CocList outline<cr>
    " Search workspace symbols
    nnoremap <silent> <space>s  :<C-u>CocList -I symbols<cr>
    " Do default action for next item.
    nnoremap <silent> <space>j  :<C-u>CocNext<CR>
    " Do default action for previous item.
    nnoremap <silent> <space>k  :<C-u>CocPrev<CR>
    " Resume latest coc list
    nnoremap <silent> <space>r  :<C-u>CocListResume<CR>
endfunction
```


ほとんど公式からもってきたものそのままになっています。
 
</div></details>
coc.nvimについて詳しくはこちらに書いています。
[coc.nvimを使ってvimをもっと強くする](https://qiita.com/coil_msp123/items/29de76b035dd28af77a9)

# 終わり
以上が自分のvimの設定になっています。今まで多種多様な設定及びプラグインを導入しては削除を繰り返してきましたが、最近は以上のような構成で落ち着いています。
vimプラグインは開発が活発で様々なプラグインが存在しますが、プラグインの導入はだんだんとコストがかかるようになります。
vimの起動時間、キーマッピングの衝突、機能の使い方を覚えるetc...
たまにはインストールしているプラグインの一覧を見て、あまり使っていないようであれば消してしまってもいいと思います。また必要になったらインストールすればいいだけですし
それを繰り返していくことでだんだんと自分の理想の環境ができてくると思います。