Neovimの設定を見直して起動を30倍速にした
古い設定が非常に遅かったというだけの話なのですが…。
Neovimは、起動時に--startuptime <filename>
オプションをつけると、起動ログをファイルに残すことができます。
❯ nvim --startuptime ./startup.log
最終行のNVIM STARTED
が起動時間です。
Before(たしか9月半ばくらい)
789.996 000.002: --- NVIM STARTED ---
After(11月末)
025.411 000.030: --- NVIM STARTED ---
こんな感じで高速化することができたので、やったことを書いておきます。
基本的にはプラグインまわりの見直しです。
高速化の手順
上記のstartupログおよび以下の記事で紹介されているプロファイルの結果を見て、時間のかかっているものを重点的に潰していきました。
標準プラグインの無効化
startupログを見るとわかるのですが、neovimはユーザーが設定していない標準プラグインも結構読み込んでいます。この読み込みを防止します。
startupログで表示されているファイルを開く(gf
が使えます)と、冒頭に以下のような条件文がある事がわかります。
if exists('g:loaded_man')
finish
endif
let g:loaded_man = 1
よって、このg:loaded_xxx
という変数を設定ファイル内で定義することで、標準プラグインの読み込みをスキップできます。
let g:did_install_default_menus = 1
let g:did_install_syntax_menu = 1
let g:did_indent_on = 1
let g:did_load_filetypes = 1
let g:did_load_ftplugin = 1
let g:loaded_2html_plugin = 1
let g:loaded_gzip = 1
let g:loaded_man = 1
let g:loaded_matchit = 1
let g:loaded_matchparen = 1
let g:loaded_netrwPlugin = 1
let g:loaded_remote_plugins = 1
let g:loaded_shada_plugin = 1
let g:loaded_spellfile_plugin = 1
let g:loaded_tarPlugin = 1
let g:loaded_tutor_mode_plugin = 1
let g:loaded_zipPlugin = 1
let g:skip_loading_mswin = 1
did_install_default_menus
did_install_syntax_menu
skip_loading_mswin
の3つはstartupログからはたどり着けませんが、設定しておくと不要な機能の読み込みをスキップしてくれます(参考にしたページを忘れてしまいました…)。
実際には各ファイルは一度開かれる(つまり、startupログのsourcing ...
自体は消えない)のですが、冒頭の条件分岐によってすぐ閉じられるため、読み込み時間は大幅に短縮されます。
※ commentstringが設定されない事があるっぽい?のでftpluginはスキップしないほうが良いかもしれません…。上記を設定して不具合が生じた場合は適宜調整してください。
使用するプラグインの見直し
単純に、使っていないのに読み込んでいるプラグインが多くあったので削除しました。
高速化のためにプラグインを見直す中で、lua製のプラグインに置き換えたものがいくつかあります。
また、一部のプラグインは以下の記事で紹介したmini.nvimに(カラースキームも含め)一本化することができました。
記事執筆時点で使用しているのは下記の26個です。
プラグイン(辞書順) | 概要 |
---|---|
bufpreview.vim | denopsプラグイン。ブラウザでMarkdownのプレビューを行う。 |
capture.vim | EXコマンドの出力をバッファに書き出すことができる。 |
coc.nvim | LSP。Node.jsに依存している。 |
denops.vim | Denoでプラグインを書くエコシステム。筆者は現状bufpreviewを使うためだけに入れている。 |
filetype.nvim | 標準機能より高速にファイル形式を判別できる。 |
fzf | Go製Fuzzy Finder。fzf-previewを使うために読み込んでいる。 |
gina.vim | Git操作。筆者は直接呼び出すことはなく、fzf-previewを介して使っている。 |
gitsigns.nvim | Git表示。編集箇所の表示、blameの表示、ステージングなどを行える。 |
hop.nvim | easymotionのlua実装。特定の文字を狙ってジャンプすることができる。 |
impatient.nvim | lua製プラグインの読み込み支援。 |
lazygit.nvim | lazygitをfloating windowで操作できる。 |
mini.nvim | 便利機能詰め合わせセット。 |
nvim-colorizer.lua | 色指定文字列をその色でハイライトする。 |
nvim-hlslens | 検索時にヒット数をvirtual textで表示する。 |
nvim-web-devicons | deviconsの表示に使う。statuslineでアイコンを表示するために導入。 |
open-browser.vim | URL文字列をブラウザで開く。 |
plenary.nvim | luaプラグイン用ユーティリティ。gitsigns.nvimなどが依存している。 |
vim-asterisk |
* による検索を強化する。 |
vim-caser | snake_case camelCase などの変換を提供する。 |
vim-expand-region | Visualモードで選択範囲を良い感じに拡縮する。 |
vim-readme-viewer | プラグインのREADMEを開く。Neovim用プラグインにはhelpがないものが散見されるため役立つ。 |
vim-showmarks | Markを可視化する。 |
vim-silicon | siliconを使い、コードを画像化する。 |
vimdoc-ja | 日本語ドキュメント。あくまでNeovimではなくVimのドキュメントである点は注意が必要。 |
which-key.nvim | キーマップを表示する。 |
winresizer | Windowのサイズを簡単に調整できるようにする。 |
一部のプラグインは、Zennの解説記事を参考に導入しました。
プラグインの遅延読み込み
筆者はプラグインマネージャとしてvim-plugを使用しています。
vim-plugの遅延読み込み機能を使うと、プラグインを実際に使用するタイミングまで読み込まないことができるので、起動を高速化できます。
コマンドによる遅延読み込み
vim-plugの標準機能です。
特定のコマンドまたは<Plug>
が実行されたときに読み込みます。
注意点として、プラグインが読み込まれない以上、デフォルトマッピングの設定もされません。自分でマッピングを定義する必要があります。
以下のような形で設定します。
Plug '4513ECHO/vim-readme-viewer', { 'on': 'PlugReadme' }
Plug 'jacquesbh/vim-showmarks', { 'on': 'DoShowMarks' }
Plug 'kat0h/bufpreview.vim', { 'on': 'PreviewMarkdown' }
Plug 'kdheepak/lazygit.nvim', { 'on': 'LazyGit' }
Plug 'lambdalisue/gina.vim', { 'on': 'Gina' }
Plug 'segeljakt/vim-silicon', { 'on': 'Silicon' }
Plug 'simeji/winresizer', { 'on': 'WinResizerStartResize' }
Plug 'terryma/vim-expand-region', { 'on': '<Plug>(expand_region_' }
Plug 'tyru/capture.vim', { 'on': 'Capture' }
Plug 'tyru/open-browser.vim', { 'on': ['OpenBrowser', '<Plug>(openbrowser-'] }
必要なキーマッピングは自分で行います。
nmap gx <Plug>(openbrowser-smart-search)
xmap gx <Plug>(openbrowser-smart-search)
xmap v <Plug>(expand_region_expand)
xmap <C-v> <Plug>(expand_region_shrink)
タイマー機能による遅延読み込み
これを使ったら何でもアリという気もするのですが、Vim起動時には読み込まず、起動から少し経過したところで読み込みを行います。
前述のコマンドによる遅延読み込みとは違い、自動で起動しておきたいものや、デフォルトのマッピングを使いたいものはこちらのほうが適しています。
vim-plugの宣言部では、次のように{ 'on': [] }
オプションを付け、読み込まないようにします。
Plug 'arthurxavierx/vim-caser', { 'on': [] }
Plug 'folke/which-key.nvim', { 'on': [] }
Plug 'haya14busa/vim-asterisk', { 'on': [] }
Plug 'junegunn/fzf', { 'on': [], 'do': { -> fzf#install() } }
Plug 'kevinhwang91/nvim-hlslens', { 'on': [] }
Plug 'kyazdani42/nvim-web-devicons', { 'on': [] }
Plug 'lewis6991/gitsigns.nvim', { 'on': [] }
Plug 'neoclide/coc.nvim', { 'on': [], 'branch': 'release' }
Plug 'norcalli/nvim-colorizer.lua', { 'on': [] }
Plug 'nvim-lua/plenary.nvim', { 'on': [] }
Plug 'phaazon/hop.nvim', { 'on': [] }
Plug 'vim-denops/denops.vim', { 'on': [] }
そして、以下の関数s:LazyLoadPlugs
内でplug#load()
を使って読み込みます。
-
plug#load()
がバッファを読み直すため、Z
マークを使ってカーソル位置を保存しています。 - lua系プラグインで初期設定が必要なものは、この関数の中に記述しています。
function! s:LazyLoadPlugs(timer) abort
" save current position by marking Z because plug#load reloads current buffer
normal! mZ
call plug#load(
\ 'denops.vim',
\ 'coc.nvim',
\ 'fzf',
\ 'gitsigns.nvim',
\ 'nvim-colorizer.lua',
\ 'nvim-hlslens',
\ 'nvim-web-devicons',
\ 'plenary.nvim',
\ 'hop.nvim',
\ 'vim-asterisk',
\ 'vim-caser',
\ 'which-key.nvim',
\ )
normal! g`Z
delmarks Z
lua << EOF
require('which-key').setup()
require('colorizer').setup()
require('hop').setup()
require('hlslens').setup({ calm_down = true })
require('gitsigns').setup({
signs = {
add = { text = '+' },
change = { text = '~' },
delete = { text = '_' },
topdelete = { text = '‾' },
changedelete = { text = '~_' },
},
current_line_blame = true,
})
EOF
endfunction
call timer_start(20, function("s:LazyLoadPlugs"))
上記コードブロックの最後の行、call timer_start(20, function("s:LazyLoadPlugs"))
により、Neovim起動20ms後に読み込みが走ります。
したがって、起動直後から完全機能で使えるわけではないのですが、筆者の操作速度では20msの差は問題になりませんでした。
これにより、ファーストビューはかなりの高速化が期待できます。
遅延読み込みしていないもの
以下のプラグインはstartupログに出力がなかったため、特に遅延読み込みを行っていません。
Plug 'echasnovski/mini.nvim'
Plug 'lewis6991/impatient.nvim'
Plug 'nathom/filetype.nvim'
Plug 'vim-jp/vimdoc-ja'
おわりに
プラグインの読み込み設定を見直し、かなり起動を高速化できました。
タイマー遅延を使えるので、今後プラグインの増減があっても大幅に遅くなることはない想定です。
これまで起動速度を気にしていなかったという人は、一度計測してみると、思わぬボトルネックが見つかるかもしれません。
ご参考になれば幸いです。
おまけ 筆者のVim遍歴(ざっくり)
2020年前半まで
当時の勤め先のメンバーに合わせSublime textを主に使用
sshしたサーバー内で設定ファイルを書き換えるためにvi
を使うことを教わるがうまく操作できないことに不満を感じる
2020年6月ごろ
少しずつVimの勉強を始める
「実践Vim」を買う
dotfilesリポジトリを作り、vimrcを作成
その後少しずつプラグインなどを足していく
lightlineにaleを表示
カラースキームはgruvbox
vim-lspを導入するも使いこなせず
2021年春ごろ
Neovimに乗り換え
coc.nvimを使い始める
カラースキームはsonokai
vim-jp slackに参入
その後
Zennに記事を書いたりDeno Deployで遊んだりしている中でNeovim設定も育つ
2021年秋
vim-jpで起動速度や遅延読み込みの話題が出ていたことで自分が全然速度を気にしていなかったことを自覚
本記事に至る
Discussion