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

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

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

採用理由

最初に導入したfernの設定が謎すぎて作者のlambdalisue先生のdotfiles見てたらこれが使われていたので真似した。速いらしい。vim-plugなどと互換な記法ができるのも嬉しい。

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

設定など

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

" 中略

let g:dein_dir = expand('~/.cache/dein')
let s:jetpackfile = stdpath('data') .. '/site/pack/jetpack/opt/vim-jetpack/plugin/jetpack.vim'

if $USER != 'root' && !$VIM_PURE
  if $VIM_USE_DEIN && isdirectory(g:dein_dir)
    let g:dein = 1
  elseif filereadable(s:jetpackfile)
    let g:jetpack = 1
  endif
endif

" 中略

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

" 中略

lambdalisue先生のスニペットをパクっている。

packadd vim-jetpack

function! s:load_config(p) abort
  for path in glob(a:p, 1, 1, 1)
    execute printf('source %s', fnameescape(path))
  endfor
endfunction

function! s:load_lua(p) abort
  for path in glob(a:p, 1, 1, 1)
    execute printf('luafile %s', fnameescape(path))
  endfor
endfunction

call jetpack#begin()

" Common
Jetpack 'tani/vim-jetpack', {'opt': 1} "bootstrap
Jetpack 'editorconfig/editorconfig-vim'

" めちゃ長いの中略!

if has('nvim')
  Jetpack 'neoclide/coc.nvim', { 'branch': 'release' }
  Jetpack 'nvim-lua/plenary.nvim'
  Jetpack 'nvim-telescope/telescope.nvim', { 'tag': '0.1.0' }
  if get(g:, 'rich')
    Jetpack 'nvim-tree/nvim-web-devicons'
  endif
endif

if get(g:, 'rich')
  Jetpack 'endaaman/lightline-hybrid.vim'
  Jetpack 'itchyny/lightline.vim'
endif

call jetpack#end()

for name in jetpack#names()
  if !jetpack#tap(name)
    call jetpack#sync()
    break
  endif
endfor

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

call s:load_config(expand('<sfile>:p:h') .. '/plugin.d/*.vim')
if has('nvim')
  call s:load_lua(expand('<sfile>:p:h') .. '/plugin.d/*.lua')
endif

colorscheme iceberg

g:richというのはdeviconとか使える環境だけ有効になるやつ。シリアルコンソールで作業することもあり、そのたびに文字化けするのはうざいので。

ファイラー NERDTree → fern.vim

見た目◯

fern.png

採用理由

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

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

設定など

導入部分

Jetpack 'lambdalisue/fern.vim'
Jetpack 'lambdalisue/fern-git-status.vim'
Jetpack 'lambdalisue/nerdfont.vim'                " アイコン一般
Jetpack 'lambdalisue/fern-renderer-nerdfont.vim'  " fernでアイコンを表示する
Jetpack '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すぎてほしい候補がうまく上に来ないので変更した。

感想

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