今からNeovimを始める人のLSP最短設定 (0.11, 2025-10-04現在)
巷にはNeovimのLSPの設定をまとめた記事が多くあり、この記事もその1つです。
しかし、既存の記事は情報が古かったり、既にLSPを設定したユーザー向けの移行ガイドであることが多いです。
この記事は、2025年10月に今からNeovimを始める方向けのガイドです。
いずれこの記事も昔のものとなりますが、現時点で最短でLSPの設定を行うための手順を解説します。
既に古いバージョンのNeovimを使っている人向けの移行記事はこちら:
- neovim 0.11からはLSPをほぼネイティブAPIだけで扱える
- Neovim0.11用のLSP設定
- 📜2025-04-27 nvim-lspconfig v2でNeovim 0.11のLSPに最適な設定を構成する - Minerva
- 忙しい人向け nvim-lspconfigのnvim v0.11対応
- Neovim v0.11のネイティブ補完APIをlazy.nvim+Mason 2.0で使う - わたすけのへや
事前知識
- LSP (Language Server Protocol) とは、コードエディタに言語機能(補完、言語ジャンプなど)を提供するための仕様(プロトコル)
- Official page for Language Server Protocol
- Neovim の LSP を設定するための基本知識
- 言語サーバー(Language Server)のことをLSPと呼んでいる場面を時々見かけるが、あくまでLSPはプロトコルのことなので言語サーバーと混同しないように注意
- Neovimでは、VSCodeなどのIDEと異なりLSP関連の設定は全てOpt-in
- つまり自分で設定する必要がある
- Neovim 0.11からLSP関連の標準APIが充実した
- Lsp - Neovim docs
- 0.10以前の設定とはだいぶ変わっているので注意
- LSP関連でよく聞く用語
-
lazy.nvim
: folke/lazy.nvim: 💤 A modern plugin manager for Neovim- プラグインマネージャー
-
lazy.nvim
以外のプラグインマネージャーを使っても構いないが、ここではlazy.nvim
のフォーマットで書く - また、プラグインマネージャーは既に導入されていることを仮定する
-
nvim-lspconfig
: neovim/nvim-lspconfig: Quickstart configs for Nvim LSP- 言語サーバーのプリセット集を提供するプラグイン
- 前述の通り設定は全てOpt-inなので自分で設定する必要があるが、nvim-lspconfigがプリセットを用意してくれているおかげでこれを読み込んで有効化するだけで大体動く
- もちろんこれを上書きしてカスタムすることもできる
-
mason.nvim
: mason-org/mason.nvim: Portable package manager for Neovim that runs everywhere Neovim runs. Easily install and manage LSP servers, DAP servers, linters, and formatters.- 言語サーバーをNeovim上でインストール・管理できるパッケージマネージャーのプラグイン
- 言語サーバー以外にもDebug Adapter, Linter, Formatterなども管理できる
-
mason-lspconfig
: mason-org/mason-lspconfig.nvim: Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.-
mason.nvim
でインストールした言語サーバーを自動で有効化してくれるプラグイン
-
-
LSP関連設定
いよいよ設定を始めます。
ここではNeovimの設定を書くのに必要なLuaの言語サーバー(lua-language-server
)の設定をすることにしましょう。事前に lua-language-server
を手元にインストールしておいてください。
また、ここではできるだけ依存を減らしてシンプルな説明を試みるため、Neovimの標準APIとnvim-lspconfig
(とプラグインマネージャー)のみを使った方法を解説します。
mason.nvim
やmason-lspconfig
を使う方法は他の記事を参照ください。
ディレクトリ構造
Neovim標準のディレクトリ構造に従いましょう。~/.config/nvim/init.lua
から始まります。
$ tree ~/.config/nvim/
.
├── after # init.luaの読み込みが終わった後に自動で読み込まれる
│ └── lsp # 言語サーバーの上書き設定が自動で読み込まれる
│ └── lua_ls.lua
├── init.lua # エントリーポイント
└── lua # init.luaから読み込まれる
├── config
│ ├── lazy.lua
│ └── lsp.lua
└── plugins
└── nvim-lspconfig.nvim
各ファイルの説明
以下では、各ファイルの中身を説明します。
init.lua では、lazy.nvim
とLSP関連の設定ファイルを読み込みます。
require("config.lazy")
require("config.lsp")
lua/config/lazy.lua では、 lazy.nvim
の設定を行い、プラグイン設定の置き場所を決めます。
既に別の場所に設定している場合は都度読み替えてください。
-- lazy.nvimの設定
-- Ref: https://lazy.folke.io/installation
-- ...
-- Setup lazy.nvim
require("lazy").setup({
spec = {
-- lua/plugins/ 以下のluaファイルをlazy.nvimのPlugin Specとして自動で読み込む
{ import = "plugins" },
},
})
一旦LSP関連の設定は飛ばし、先に nvim-lspconfig
の設定を書きます。
先ほど設定した lua/plugins
の下にPlugin Specを書くだけで lazy.nvim
が自動でインストール、設定をしてくれます。
---@type LazyPluginSpec
return {
"neovim/nvim-lspconfig",
-- Bufferが読み込まれたときやファイルが作成されたときに遅延ロードする
event = { "BufReadPre", "BufNewFile" },
}
nvim-lspconfig
の設定をしたので、一旦飛ばしたLSP関連の設定をします。
vim.lsp.enable({
-- nvim-lspconfig で"lua_ls"という名前で設定したプリセットが読まれる
-- https://github.com/neovim/nvim-lspconfig/blob/master/lsp/lua_ls.lua
"lua_ls",
-- 他の言語サーバーの設定
-- "gopls",
})
-- 言語サーバーがアタッチされた時に呼ばれる
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("my.lsp", {}),
callback = function(args)
local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
local buf = args.buf
-- デフォルトで設定されている言語サーバー用キーバインドに設定を追加する
-- See https://neovim.io/doc/user/lsp.html#lsp-defaults
-- 言語サーバーのクライアントがLSPで定められた機能を実装していたら設定を追加するという流れ
if client:supports_method("textDocument/definition") then
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { buffer = buf, desc = "Go to definition" })
end
if client:supports_method("textDocument/hover") then
vim.keymap.set("n", "<leader>k",
function() vim.lsp.buf.hover({ border = "single" }) end,
{ buffer = buf, desc = "Show hover documentation" })
end
-- Enable auto-completion. Note: Use CTRL-Y to select an item. |complete_CTRL-Y|
if client:supports_method("textDocument/completion") then
-- Optional: trigger autocompletion on EVERY keypress except brackets. May be slow!
local chars = {}
for i = 32, 126 do
local c = string.char(i)
if c ~= "(" and c ~= ")" and c ~= "[" and c ~= "]" and c ~= "{" and c ~= "}" then
table.insert(chars, c)
end
end
client.server_capabilities.completionProvider.triggerCharacters = chars
vim.lsp.completion.enable(true, client.id, args.buf, { autotrigger = true })
end
-- Auto-format ("lint") on save.
-- Usually not needed if server supports "textDocument/willSaveWaitUntil".
if not client:supports_method("textDocument/willSaveWaitUntil")
and client:supports_method("textDocument/formatting") then
vim.api.nvim_create_autocmd("BufWritePre", {
group = vim.api.nvim_create_augroup("my.lsp", { clear = false }),
buffer = args.buf,
callback = function()
vim.lsp.buf.format({ bufnr = args.buf, id = client.id, timeout_ms = 1000 })
end,
})
end
if client:supports_method("textDocument/inlineCompletion") then
vim.lsp.inline_completion.enable(true, { bufnr = buf })
vim.keymap.set("i", "<Tab>", function()
if not vim.lsp.inline_completion.get() then
return "<Tab>"
end
-- close the completion popup if it's open
if vim.fn.pumvisible() == 1 then
return "<C-e>"
end
end, {
expr = true,
buffer = buf,
desc = "Accept the current inline completion",
})
end
end,
})
ここまででLua言語サーバーの設定は完了しました。
この状態でNeovimを起動してLuaファイルのシンボルにカーソルを当て、 <leader>k
(<leader>
はデフォルトではスペースキー)を押すと言語サーバーから提供された情報が見れるのではないでしょうか。
これも nvim-lspconfig
がLua言語サーバー用のプリセットを提供してくれているおかげです。
しかし、Lua言語サーバーはVim/Neovimに特化したものではないため、グローバルで使用している vim.lsp.enable
の vim
キーワードの情報がなく警告を出してくるはずです。
最後に、この警告を消す設定をしましょう。
after/ ディレクトリは特別なディレクトリで、通常の読み込みプロセスが終わった後に読み込まれます。
after/lsp/ ディレクトリの下で言語サーバーの設定を返すことでNeovimが自動でこの設定を呼んでくれます。
nvim-lspconfig
は本来ここに書くべき各言語サーバー用の設定を予め書いてくれているものなのです。
グローバルの vim
キーワードは Neovim に同梱されたLuaファイルで定義されています。
このLuaファイルを格納しているディレクトリには、 vim.env.VIMRUNTIME .. "/lua"
でアクセスできます。
例えばHomebrewでNeovimをインストールしていればこれは /opt/homebrew/share/nvim/runtime/lua
などを指すはずです。
after/lsp/lua_ls.lua を作成し、 settings.Lua.workspace.library
の配列に vim.env.VIMRUNTIME .. "/lua"
を追加することで、vim
キーワードの定義を読み込むことができ、警告を消すことができます。
---@type vim.lsp.Config
return {
settings = {
Lua = {
workspace = {
library = {
vim.env.VIMRUNTIME .. "/lua",
},
},
},
},
}
これで無事警告を消すことができました。
終わりに
良いNeovimライフを!
Discussion
globals
の設定で警告を消すのも良いですが、Neovimに同梱されている型定義を読み込ませるとより正確な情報が得られてハッピーかもしれません100%定義されているわけではないので、一部警告は出てしまいますが……
確かに、"/opt/homebrew/share/nvim/runtime/lua" (これは
vim.env.VIMRUNTIME
でbrewの依存を剥がせそうです) でグローバルのvim
が型定義されているのでそっちを使うのが良さそうですね。実は自分の手元ではそれも併せて設定しているんですが、ここでは最小限のカスタムを行うために
settings.Lua.diagnostics.globals
だけを書いていました。修正しておきます、ご指摘ありがとうございます!