Neovimの補完をddc.vim + Built-in LSP へ移行した

March 20, 2022

lsp

これまで補完には、deoplete.nvimvim-lsp を利用していたのだが、deoplete.nvim は開発終了となっており、ddc.vim への移行が推奨されている。

また、Neovim 0.5.0以降では、組み込みのLSPクライアントが利用できるようになっているため、合わせて移行することとした。

ddc.vim について

Shougo氏が開発しているvimの補完プラグインで、deoplete.nvim の後継にあたる。ddcは「dark deno-powered completion」の略とのこと。

特徴としては、

  • Vim8/Neovimの両対応
  • Python非依存、Deno(denops.vim)依存
  • 非同期処理による高速化
  • 最低限の補完機能のみが提供されておりプラグインを利用して自由に拡張できる

等がある。詳しくはShougo氏のzennの記事に経緯や deoplete.nvim との差異についてもまとめてくださっている。

ddc.vim の導入

インストール

利用には、NeoVim 0.6.0 か Vim 8.2.0662 以上が必要となる。 また、Deno依存であるため、Deno 並びに denops.vim の導入が必要となる。

自身の環境ではプラグイン管理に dein.vim のtoml管理を利用しており、Insertモード時に遅延して起動できるようにしている。

# dein/plugins.toml
[[plugins]]
repo = 'vim-denops/denops.vim'
# dein/lazy.toml
[[plugins]]
repo = 'Shougo/ddc.vim'
on_event = 'InsertEnter'
depends = ['denops.vim']

基本的な補完の導入

ddcではsource/filterが本体から分離されており、本体だけでは動作しないためプラグインで個別に導入する必要がある。 基本的な補完を満たすために以下のプラグインが提供されている。

  • ddc-around
    • 現在の行の周辺の単語を候補として抽出してくれる
  • ddc-matcher_head
    • 入力中の文字列に基づいて候補から絞り込みを行う
  • ddc-sorter_rank
    • 候補の一覧をマッチした順や既に入力されている順でソートする
# dein/lazy.toml
[[plugins]]
repo = 'Shougo/ddc.vim'
on_event = 'InsertEnter'
depends = ['denops.vim']
hook_source = '''
  call ddc#custom#patch_global('sources', ['around'])
  call ddc#custom#patch_global('sourceOptions', {
        \ '_': {
        \   'matchers': ['matcher_head'],
        \   'sorters': ['sorter_rank']},
        \ 'around': {
        \   'mark': 'around' },
        \ })
  call ddc#enable()
'''

[[plugins]]
repo = 'Shougo/ddc-around'
on_source = 'ddc.vim'

[[plugins]]
repo = 'Shougo/ddc-matcher_head'
on_source = 'ddc.vim'

[[plugins]]
repo = 'Shougo/ddc-sorter_rank'
on_source = 'ddc.vim'

Built-in LSP の補完をddcで利用する

ddcのsourceに設定する

ddc-nvim-lsp を利用する。READMEに従い、以下のようにsourcesにnvim-lsp を追加し設定を記述する。 markには、aroundからの補完なのかnvim-lspからの補完なのかが分かるような文字列をいれることで、補完時に表示される。

# dein/lazy.toml
[[plugins]]
repo = 'Shougo/ddc.vim'
on_event = 'InsertEnter'
depends = ['denops.vim']
hook_source = '''
  call ddc#custom#patch_global('sources', ['nvim-lsp', 'around'])
  call ddc#custom#patch_global('sourceOptions', {
        \ '_': {
        \   'matchers': ['matcher_head'],
        \   'sorters': ['sorter_rank']},
        \ 'around': {
        \   'mark': 'around' },
        \ 'nvim-lsp': {
        \   'mark': 'lsp',
        \   'forceCompletionPattern': '\.\w*|:\w*|->\w*' },
        \ })
  call ddc#enable()
'''

[[plugins]]
repo = 'Shougo/ddc-nvim-lsp'
on_source = 'ddc.vim'

Built-in LSPの設定

:help lsp でLSP client/framework のリファレンスが確認できるので、QUICKSTARTに従って設定を行うと良い。

LSPの導入には各言語用のサーバーの設定が必要になるが、一般的な言語毎の設定を宣言的に記述できる nvim-lspconfig と、言語用サーバーのインストールを簡単にする nvim-lsp-installer を利用する。

# dein/lazy.toml
[[plugins]]
repo = 'neovim/nvim-lspconfig'
on_event = 'BufEnter'
hook_source= '''
lua << EOF
local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(function(server)
  local opts = {}
  server:setup(opts)
end)
EOF
'''

[[plugins]]
repo = 'williamboman/nvim-lsp-installer'
on_source = 'nvim-lspconfig'

バッファをLSPの候補に登録するトリガーとして server:setupの直後に vim.cmd [[ do User LspAttachBuffers ]] を指定している記事がいくつかあるが、現在ではsetup内で実行されるようになっており必要が無くなっているようだった。

williamboman/nvim-lsp-installer#220

nvim-lsp-installer では、:LspInstall <言語サーバー名> で必要な言語サーバーがインストールできる。 もしくは、:LspInstallInfo で言語サーバーのインストール状況が確認できるTUIが起動するため、必要なサーバーを選択しi を入力することでもインストールできる。

lsp info

必要な言語サーバーをインストールすると、LSPを利用した補完が利用できる。

感想

本体はシンプルに必要な機能はプラグインで追加という思想はとても好みで、ここまで記載した最小限の構成でもかなり便利に使えている。

Python から Deno 依存になったことについて、Neovim が Lua を採用している中である意味サードパーティの依存が必要になることに抵抗がないといえば嘘になる。
しかし、deoplete.nvim を利用していた際に Python の環境をそれなりに意識する必要があったのに比べると、ddc.vim を利用する上では Deno の環境をそれほど意識する必要がないように現状感じている。

手元の環境の依存が増えるのは望まないところではあるが、自分が Lua と TypeScript のどちらでプラグインを作りたいかと言われたら間違いなく TypeScript を選ぶだろうし、その意味で denops.vim で開発されるプラグインが増えていくのも楽しみだとも思っている。

他のddc関連のプラグインなども色々試しつつ、環境をさらに充実させていきたい。


© 2020-2024 ntsk.