Vim駅伝2025-09-03の記事です。前回の記事はkawarimidollさんによるNeovim 0.12(開発版)でcopilot-language-serverを設定してみたぞ(脱copilot.lua)でした。私の直近の記事を早速参考にしていただいて、うれしかったです。
さて、本題。
ランタイムが群雄割拠しているTypeScript/JavaScriptのプロジェクトにおいて、適切な言語サーバー選びは重要項目です。 Neovimでの設定方法について毎年のように記事が出ています。
- 2024
- 2023
- 2022
- 2021
適切な言語サーバーをバッファにアタッチする方法として、2022年と2024年の記事では、両方をアタッチしてから不適切な方をデタッチしていました。その背景には、nvim-lspconfigプラグインの仕様が関係していたかと思います。このプラグインによる言語サーバーの自動起動機構にユーザー側でロジックを足すことが難しく、停止ロジックでごまかしていたと思います。
ところが、vim.lsp.enable()
が実装されたNeovim >= 0.11で事情が変わり、nvim-lspconfigプラグインを使わずに本体と自身の設定で自動起動を制御するようになりました。たとえば、vim.lsp.enable("denols")
を設定に仕込んでおくと、vim.lsp.config.denols.filetypes
にマッチするファイルタイプに対して自動的にdenols
がアタッチされます。
この、ユーザーに自動起動するか委ねる変化により、ts_ls
を使うかdenols
を使うかも起動のタイミングで決めやすくなりました。無駄にプロセスを起動することもないですし、バッファ単位で言語サーバーを選べるので、nodeとdenoが混在するモノリポなんてレアケースも怖くありません。
設定はざっくり以下の通りです。
-- 起動条件が単純な言語サーバーは `vim.lsp.enable` で自動起動させる
vim.lsp.enable({ "lua_ls", "pyright" })
-- 起動条件が複雑な言語サーバーはFileTypeイベント時に判定する
--(ts_ls/denols)
vim.api.nvim_create_autocmd("FileType", {
group = vim.api.nvim_create_augroup("LspStartNodeOrDeno", { clear = true }),
callback = function(ctx)
if not vim.tbl_contains(
{ "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" },
ctx.match
) then
return
end
-- node
if vim.fn.findfile("package.json", ".;") ~= "" then
vim.lsp.start(vim.lsp.config.ts_ls)
return
end
-- deno
vim.lsp.start(vim.lsp.config.denols)
end,
})
Neovim >= 0.11向けのLSPの設定方法をまず知りたいという方は、kawarimidollさんの記事をご覧ください。
また、nodeかdenoかの判定にpackage.json
の有無を使っていますが、もう少しこだわるならkyoh86さんの記事をご参考ください。