ひさびさにそれなりの量のコードを書かないといけない用事が入りそうだったので、思い立ってNeoVimプラグインをブラッシュアップした。

種別
プラグインマネージャー dein.vim vim-plug
ファイラー NERDTree fern.vim
FuzzyFinder denite.nvim telescope.nvim

プラグインマネージャー dein.vim → vim-plug

採用理由

言わずと知れたアレ。「枯れている=正義」みたいなところはあり、困ってもググればすぐに解決するという心強さがある。

deinはtomlがしんどくなってきた。アップデートのログが乱れてて気持ち悪いなど、不満もあったのでこれを期に卒業。

最初はvim-jetpackというを試していたが、壊れたバージョンがHEADにpushされてVim自体が使用不要になったので即パージした。またいつか会いましょう。

設定など

移行期間として、deinと共存させている。環境変数で外から切り替えたり、プラグインすべて無視したりできるようにしてる。

以下抜粋。

let g:dein_dir = expand('~/.cache/dein')
if has('nvim')
  let g:vimplug_file = stdpath('data') .. '/site/autoload/plug.vim'
else
  let g:vimplug_file = expand('~/.vim/autoload/plug.vim')
endif

if $USER != 'root' && !$VIM_NO_PLUGS
  if $VIM_USE_DEIN && isdirectory(g:dein_dir)
    let g:dein = 1
  elseif filereadable(g:vimplug_file)
    let g:vimplug = 1
  endif
endif

" 中略

if get(g:, 'dein')
  runtime! dein.vim
elseif get(g:, 'vimplug')
  runtime! vimplug.vim
else
  runtime! vanilla.vim
endif

以下、プラグイン読み込み部分。

call plug#begin()
Plug 'editorconfig/editorconfig-vim'
" 中略:一般的なVimプラグイン
if has('nvim')
  Plug 'nvim-telescope/telescope.nvim', { 'tag': '0.1.0' }
  " 中略:NeoVimプラグイン
endif
call plug#end()

if has('nvim')
  silent! packadd nvim-treesitter
else
  silent! packadd vim-healthcheck
endif

function! s:load_scripts(p, islua) abort
  for path in glob(a:p, 1, 1, 1)
    let cmd = 'luafile' ? islua : 'source'
    execute printf('%s %s', cmd, fnameescape(path))
  endfor
endfunction

let s:dir = expand('<sfile>:p:h')

function! s:load_plugin_d() abort
  call s:load_scripts(s:dir .. '/plugin.d/*.vim', 0)
  if has('nvim')
    call s:load_scripts(s:dir .. '/plugin.d/*.lua', 1)
  endif
endfunction

if !empty(filter(copy(g:plugs), '!isdirectory(v:val.dir)'))
  PlugInstall --sync
endif
call s:load_plugin_d()

欠けているプラグインがあればPlugInstall --syncして、$vimruntime/plugin.d/*.vim$vimruntime/plugin.d/*.lua を一気に実行する。

ファイラー NERDTree → fern.vim

見た目◯

fern.png

採用理由

順番的には最初に導入した。きっかけは些細なことだった。NERDTree上で「ファイルをリネームした際に下のコマンドウィンドウのサイズが大きいまま戻らない」現象が起きた。地味にうざい。そしてそもそも「なんでこんな化石みたいなプラグイン使ってるんだ…?」という感情に魂が支配された結果移行を決意した。

fernは機能も十分で、なにより適切にドッグフーディングされている様子が見えたので、そこを信用しようということで採用となった(よくある破滅のパターンは作者がOSS活動から失踪と、モチベーション低下によるプロジェクトの放棄なので)。

設定など

導入部分

Plug 'lambdalisue/fern.vim'
Plug 'lambdalisue/fern-git-status.vim'
Plug 'lambdalisue/nerdfont.vim'                " アイコン一般
Plug 'lambdalisue/fern-renderer-nerdfont.vim'  " fernでアイコンを表示する
Plug 'lambdalisue/glyph-palette.vim'           " アイコンに色をつける

個別設定

nnoremap <C-g> :<C-u>Fern . -drawer -width=40 -toggle -reveal=%<CR>

let g:fern#disable_default_mappings = 1
if get(g:, 'rich')
  let g:fern#renderer = 'nerdfont'
endif

function! s:init_fern() abort
  setlocal nonumber
  setlocal nocursorcolumn
  nmap <buffer><silent><expr>
    \ <Plug>(fern-my-open-or-expand-collapse)
    \ fern#smart#leaf(
    \   "\<Plug>(fern-action-open)",
    \   "\<Plug>(fern-action-expand)",
    \   "\<Plug>(fern-action-collapse)",
    \ )
  nmap <buffer> o <Plug>(fern-my-open-or-expand-collapse)
  nmap <buffer> <C-m> <Plug>(fern-action-open)<C-w>p:<C-u>quit<CR>
  nmap <buffer> x <Plug>(fern-action-collapse)
  nmap <buffer> C <Plug>(fern-action-enter)
  nmap <buffer> t <Plug>(fern-action-open:tabedit)
  nmap <buffer> T <Plug>(fern-action-open:tabedit)gT
  nmap <buffer> i <Plug>(fern-action-open:split)
  nmap <buffer> s <Plug>(fern-action-open:vsplit)
  nmap <buffer> X <Plug>(fern-action-open:system)
  nmap <buffer> R <Plug>(fern-action-reload)

  nmap <buffer> A <Plug>(fern-action-new-path=)
  nmap <buffer> m <Plug>(fern-action-mark)j
  nmap <buffer> M <Plug>(fern-action-rename:bottom)
  nmap <buffer> D <Plug>(fern-action-trash=)

  nmap <buffer> q :<C-u>quit<CR>
endfunction

augroup fern-custom
  au! *
  au FileType fern call s:init_fern()
augroup END

augroup my-glyph-palette
  autocmd! *
  autocmd FileType fern call glyph_palette#apply()
augroup END

デフォルトは覚えられないのでOFFにして、NERDTreeっぽいバインディングを用意した。「複数選択してリネーム」するクリップがREADMEにあったがやり方が分からず結構困った。アイテム選択は「mark」で、デフォルトは「-」にマッピングされてるようだった。わかりづれえ。

NERDTReeだと「o」を多用していたので、open-expand-collapseなアクションを自前で用意している。このへんはドキュメントがよく整理されてて助かった。

機能的には、trash-cliと連携してくれるのは地味に嬉しい。CRUDまわりの操作性も良し。一括リネームは便利そうではあるが、mmvという最強のツールがあるのであまり出番はないかな。

web-deviconは、作者自前のライブラリたちじゃないとうまく動作しなかった。アイコンに色までつけるには追加で3つも入れないと行けない。どうせ全部入れることになるんだから、正直言うと一纏めにしてほしい。

カーソル位置のアイコンが反転して見栄えが良くないのをどうにかしたいけどよく分からなくてやめた。いつかやる。

fuzzy finder Denite → telescope.nvim

プロンプトは上派

telescope.png

採用理由

Deniteの開発が終了していることを知ったので、これも思い切って移行を決意。

候補は多い。この記事が参考になった。

  • fzf-vim:fzfが嫌いなわけじゃないが、fzf依存なのが嫌。かなり頑張って拡張しないと必要な機能は揃わなそうなのも辛い。
  • fzf-preview:プレビューをしたいわけではない。上の依存だし、node依存だし。
  • ctrlp.vim:いまさら感。候補として悪くはないが、自分が満足して使うためのカスタマイズに時間が掛かりそう。
  • ddu:正直「Shougowareはもういいかな」という気持ち。作者が飽きてUniteやDeniteみたいに終了しそうなのも嫌。

ほかはあまり積極的に選ぶ理由が見いだせなかった。telescope.nvimはLuaでデータソースを整理できるのが明らかに強いな、と。DeniteでPythonを使ってあれこれ書いていたが、それと近いことができるのは嬉しい。

実際導入してみるとかなり大量のデータソースがデフォルトで用意されていて、結果的にほとんどカスタマイズせずに使えてしまった。嬉しい誤算だった。

設定など

local telescope = require('telescope')
local actions = require('telescope.actions')
local action_layout = require('telescope.actions.layout')
local builtin = require('telescope.builtin')
local sorters = require("telescope.sorters")

vim.keymap.set('n', '<Space>f', builtin.git_files, {})
vim.keymap.set('n', '<Space>g', builtin.live_grep, {})
vim.keymap.set('n', '<Space>o', builtin.oldfiles, {})
vim.keymap.set('n', '<Space>b', builtin.buffers, {})
vim.keymap.set('n', '<Space>h', builtin.help_tags, {})
vim.keymap.set('n', '<Space>d', builtin.git_status, {})
vim.keymap.set('n', '<Space><Space>', builtin.resume, {})


local default_maps = {
  n = {
    ['<Tab>'] = actions.move_selection_next,
    ['<S-Tab>'] = actions.move_selection_previous,
  },
  i = {
    ['<Tab>'] = actions.move_selection_next,
    ['<S-Tab>'] = actions.move_selection_previous,
    ['<Esc>'] = actions.close,
    ['<C-j>'] = actions.git_staging_toggle,
  },
}

telescope.setup{
  defaults = {
    file_sorter = sorters.get_generic_fuzzy_sorter,
    sorting_strategy = 'ascending',
    layout_config = {
      prompt_position="top",
    },
    mappings = default_maps,
  },
  pickers = {
    git_status = {
      mappings = default_maps,
    },
  },
}

今後無限に増えていくだろうが、よく使うものだけとりあえず用意した。プロンプトは上がいいので、layout_config.prompt_position="top"で上に配置して、sorting_strategy = 'ascending'で絞り込みを昇順で変更している。またfzy_sorterアホfuzzyすぎてほしい候補がうまく上に来ないので変更した。

感想

見た目が新しくなると気分も良くなるね。