masonのMajorアップデートに伴ってLSPの設定を見直す
はじめに
mason
のv.2がリリースされ、いくつかの破壊的変更が導入されました。ろくすっぽ調べずにアップデートした結果当然のように動かなかったため、設定の見直しを行います。また、Neovim本体の0.11のリリースによりLSP関連の機能が大幅に強化され、ほとんどがネイティブのAPIで設定できるようになったため、そちらの修正も行います。
結論(PR)
今回の対象プラグイン
今回対象となるプラグインについてまとめておきます。
mason
各種言語サーバーの管理を行うプラグインです
nvim-lspconfig
言語サーバーの推奨設定を提供し、Neovimとの連携を容易にするプラグインです
mason-lspconfig
masonでインストールした言語サーバーとnvim-lspconfigの橋渡しをするプラグインです
Masonのv2アップデート対応
バージョン2系のアップデートに伴いOrganizationが変更になっているため、まずはこちらを変更します。masonのアップデートに伴いmason-lspconfig
もアップデートされていたため同じように対応します。
return {
{
- "williamboman/mason-lspconfig.nvim",
+ "mason-org/mason-lspconfig.nvim",
dependencies = {
- { "williamboman/mason.nvim", config = mason },
+ { "mason-org/mason.nvim", config = mason },
},
config = mason_lspconfig,
},
mason-lspconfig
のアップデートにより、mason
経由でインストールされたサーバーをNeovim 0.11で追加された本体側のAPIを使って自動で有効化できるようになりました。具体的にはmason-lspconfig
のsetup()
が実行されたタイミングでmason
によってインストール済みの言語サーバーがvim.lsp.enable()
に渡されるようになっているようです。この機能はデフォルトでOnになっているはずですが、自分の環境では型情報上必須の項目であると怒られてしまったので明示的に追加します。
require("mason-lspconfig").setup({
+ automatic_enable = true,
ensure_installed = { ... }
})
nvim-lspconfigとの連携部分を修正
変更前の設定方法
ここからはMasonのアップデートと合わせて、Neovim 0.11で追加された変更にも追従する形でLSP周りの設定を見直していきます。自分はサーバーごとの設定をtable形式で定義しておき、mason-lspconfig
が提供していたsetup_handlers()
関数を使って、nvim-lspconfig
を通して設定するような書き方をしていました。
server_config.lualocal config = {}
local default_config = {
-- 共通で設定したい項目をここに
}
config["lua_ls"] = vim.tbl_deep_extend("force", default_config, {
-- ...サーバーごとの設定をここに
})
return setmetatable(config, {
__index = function()
return default_config
end
})
lspconfig/init.luarequire("mason-lspconfig").setup_handlers({
function(server_name)
local conf = require("plugins.configs.lspconfig.server_config")[server_name]
require("lspconfig")[server_name].setup(conf)
end
})
もう少し詳細に解説すると、mason-lspconfig
を使ってインストールされたサーバーのループを回し、nvim-lspconfig
で提供されている初期設定に追加の設定項目を渡してあげて、nvim-lspconfig
の機能を使ってNeovimに連携させるような動作になっていました。
新しい設定方法
具体的な設定に入っていきます。まず初めに、setup_handler
が廃止になったため修正します。先ほども述べたのように、言語サーバーの有効化そのものはmason-lspconfig
によって行われているため、言語サーバーの設定のみを考えれば良いことになります。言語サーバーの設定も同様にNeovim 0.11で追加された本体側のAPIで行えるようになっています。vim.lsp.config()
を呼んであげることで、各種言語サーバーの設定を行うことができます。この際第一引数には言語サーバー名を渡すのですが、*
を渡すことで、共通の設定を定義することもできます。この辺りの挙動は:h vim.lsp.config()
から確認できます。
ということで、共通の設定を行います。Neovim 0.11でLSP関連のキーマップも追加になりましたが、使い慣れたものを引き続き使いため個別に設定します。
vim.lsp.config("*", {
on_attach = function(_, bufnr)
-- NOTE: To use fuzzy finder instead of quickfix list
-- other keymaps like GoToImplementation, GoToReferences are set in telescope.nvim config
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { buffer = bufnr, desc = "LSP: [G]oto [D]efinition" })
vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { buffer = bufnr, desc = "LSP: [G]oto [D]eclaration" })
end,
capabilities = require("cmp_nvim_lsp").default_capabilities(),
})
続いて、言語サーバーごとの追加の設定を移行します。:h lsp-config
を確認すると、以下のような挙動になっていることがわかります。
When an LSP client starts, it resolves its configuration by merging from the
following (in increasing priority):
1. Configuration defined for the `'*'` name.
2. Configuration from the result of merging all tables returned by
`lsp/<name>.lua` files in 'runtimepath' for a server of name `name`.
3. Configurations defined anywhere else.
Note: The merge semantics of configurations follow the behaviour of
|vim.tbl_deep_extend()|.
従来までの書き方と同じように各言語サーバーの追加設定をtable形式で定義しておいて、個別にvim.lsp.config()
を呼ぶようにしても良かったのですが、どうやら'runtimepath'
に所定の形式に則ったファイルを作成すれば自動的に読み込んでくれるようです。LSP関連の設定が散らばってしまうデメリットはありますが、ファイルを作成さえすれば明示的にvim.lsp.config()
を呼ぶ必要がなくなりそうです。
暗黙的な知識が必要になりますが、個人の設定ファイルということで良しとしましょう。ということでファイルを作成します。一方で自分はかなりlazy loadの設定を頑張ってしまったので、読み込みのタイミングによってはnvim-lspconfig
で提供されている設定の方が優先されてしまうことも考えられました。しかし以下の記事にあるように、'runtimepath'
の後ろの方に~/.config/nvim/after
が存在していることを利用して、nvim-lspconfig
で提供されている設定よりも自分で作成した追加の設定の優先度を高めることができました。
最終的なフォルダ構成は以下のようになっています。詳細な変更内容については、冒頭にも記載していますがリンク先のPRを参考にしてください。
.config/nvim
├── after/lsp // `nvim-lspconfig`で提供されていない項目を追加で設定したい場合はここにファイルを作成する
│ ├── lua_ls.lua
│ ├── ...
│ └── ts_ls.lua
└── lua/plugins/configs
├── mason.lua
├── mason-lspconfig.lua
└── nvim-lspconfig.lua // 共通の設定はここで設定する
おわりに
masonのメジャーアップデートに合わせて、Neovim 0.11で追加されたLSP関連のAPIに追従するよう変更したことで、ほぼほぼNeovim本体のAPIのみでLSPの設定ができるようになりました。また、従来の設定ではmason-lspconfig
の設定の中でnvim-lspconfig
を呼び出す必要があるなど密結合になっていましたが、今回のアップデートによってそれぞれのプラグインの役割が明確になり、設定ファイルの見通しも良くなったように感じます。