🛠️

ddc-source-nvim-lspを大幅に強化した

2023/08/04に公開

この記事は Vim 駅伝の 8/4 の記事です。

はじめに

Vim/Neovim の自動補完フレームワーク ddc.vim のソースである ddc-source-nvim-lsp の機能を大幅に強化しました。

この記事では、何が出来るようになったのかと設定方法について説明しようと思います。

https://github.com/Shougo/ddc-source-nvim-lsp

また ddc-source-nvim-lsp のコラボレーターになりましたので、今後のメンテナンスは私が責任を持ちます。

新機能

統括としては、「LSP の補完機能に9割以上対応した」と言えるでしょう。
細かな拘りポイントは幾つかありますが、分かりやすい新機能(改善点)を紹介します。

Auto-import

TypeScript などの言語では、まだ import していないシンボルも補完候補に含んでくれます。
また、それを確定したときに import 文を自動で追加してくれます

Integration with snippet plugins

LSP では VSCode 形式のスニペットを候補として返すことが認められています。
これを処理できるスニペットプラグインと連携することで、正しく展開できるようになりました。

スニペットプラグインなしでも最低限の展開はできます。

Extreme additionalTextEdits completion

rust-analyzer は結構やばい候補を返します。
これも上手く展開できるようになりました。

Indent fixing completion

vscode-html-language-server などは、インデント補正を含む候補を返すことがあります。
これも正しく扱えるようになりました。

設定例

それぞれの設定値の意味は doc に書いてあるので省略します。
簡単に言うと enableResolveItem: v:trueenableAdditionalTextEdit: v:true を設定することで Auto-import などが有効化されます。
snippetEngine には vsnip 以外にも luasnip などが使えます。

また、keywordPattern には \k+ を使うことを推奨します。
これは単語の切れ目を認識するためのものですが、例えば TypeScript だと $# も含んでほしい、という需要があるでしょう。
LS からこれは通知されないので、'iskeyword' を参照するのが一番無難です。

call ddc#custom#patch_global(#{
      \ sourceOptions: #{
      \   nvim-lsp: #{
      \     dup: 'keep',
      \     keywordPattern: '\k+',
      \     sorters: ['sorter_lsp-kind']
      \   },
      \ },
      \ sourceParams: #{
      \   nvim-lsp: #{
      \     snippetEngine: denops#callback#register({
      \           body -> vsnip#anonymous(body) }),
      \     enableResolveItem: v:true,
      \     enableAdditionalTextEdit: v:true,
      \     confirmBehavior: 'replace',
      \   },
      \ },
      \})

また、こちらも使うことを推奨します。

https://github.com/uga-rosa/ddc-nvim-lsp-setup

require("ddc_nvim_lsp_setup").setup()

require("lspconfig").denols.setup()

これを使うと、client_capabilitiesforceCompletionPattern を自動で適切に設定します。

client_capabilities は、Language Server にクライアント(エディタ)側が対応している機能を通知するものです。
ddc-nvim-lsp-setup を使わないのであれば require("ddc_nvim_lsp").make_client_capabilities() を直接利用してください。

forceCompletionPattern には、LS から通知される triggerCharacters を正規表現に変換して使うと良い感じになります。
例えば TypeScript で .keywordPattern に含まれていなくとも、Foo.|| はカーソル位置)と入力したときに補完が出るようになります。

おわりに

まだ改良は続いていますが、重要なバグ修正は一通り終わりました。
ddc.vim 自体の仕様上どうしても対応できないもの(sortText など)もありますが、実用上問題ないレベルに到達したと思っています。

各 LS の実装にはばらつきがあるので、全ての LS で完全に動作するとは断言できないのが正直なところです。
ユニバーサルなんて幻想...
バグを踏んだ際は issue を立てて下さると助かります。

謝辞

hrsh7th さんには多くの助言を頂きました。流石 LSP と補完のプロ!
本当に助かりました。ありがとうございます!

Shougo さんには ddc.vim 本体のバグ修正と、ddc.vim の仕様について助言を頂きました。
ありがとうございます!

GitHubで編集を提案

Discussion