Neovim 0.12 を最小構成から安全に育てる
よるほろぐ編集部
Neovim は Vim 互換のモーダルエディターで、Lua による設定と組み込み LSP クライアントを備えています。設定例を丸ごとコピーすれば短時間で見栄えは整いますが、壊れたときにどの設定・プラグイン・外部コマンドが原因か分からなくなりがちです。最初は「起動できる小さな設定」を作り、必要になった機能だけを一つずつ載せる方が、結果として長く使える環境になります。
この記事の対象は、2026-07-10 時点で GitHub の Neovim 公式リリースにある安定版 Neovim 0.12.4 です。ここで使う LSP 設定は vim.lsp.config() と vim.lsp.enable() です。0.11 以降の現行 API であり、過去の LSP 設定フレームワークは使いません。未確認の将来版の挙動は前提にしません。
CLI でパスやファイルを扱うことにまだ不安がある場合は、先に ターミナルの基本 を読むと、以下のコマンドを自分の環境に合わせて確認しやすくなります。
まずは既存設定を壊さずに試す
設定を置き換える前に、現在の設定をコピーして退避します。NVIM_APPNAME を指定すると、Neovim は通常の ~/.config/nvim ではなく、その名前の設定・データ用ディレクトリを使います。既存の設定を移動も削除もせず、実験用の nvim-minimal を作れるため、最初の試行にはこちらが安全です。
nvim --version
config_root="${XDG_CONFIG_HOME:-$HOME/.config}"
backup_dir="$config_root/nvim.backup.$(date +%Y%m%d-%H%M%S)"
if [ -e "$config_root/nvim" ]; then
cp -a -- "$config_root/nvim" "$backup_dir"
printf 'backup: %s\n' "$backup_dir"
fi
mkdir -p -- "$config_root/nvim-minimal"
表示された backup: のパスは、復旧に使うので記録しておきます。続けて、何も読み込まない起動も一度確認します。
nvim --clean
--clean は新規インストールに近い状態で起動する公式オプションです。これで起動できない場合は、これから書く Lua 設定ではなく、Neovim 本体の導入・端末環境・ランタイムファイルを先に確認します。
実験用設定を起動するときは、毎回このように実行します。
NVIM_APPNAME=nvim-minimal nvim
通常の設定に戻るには、この環境変数を付けずに nvim を起動するだけです。プラグインのデータも nvim-minimal 側に分かれるので、普段の環境と混ざりません。
最小の init.lua を動かす
最初から検索、補完、テーマ、ステータスラインを同時に追加しません。まずは編集そのものに必要な選択だけを書き、保存、終了、再起動を確かめます。
-- ~/.config/nvim-minimal/init.lua
vim.g.mapleader = " "
vim.opt.number = true
vim.opt.expandtab = true
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
vim.opt.signcolumn = "yes"
vim.opt.undofile = true
NVIM_APPNAME=nvim-minimal nvim "$config_root/nvim-minimal/init.lua"
設定を追加する単位は一つにします。たとえば、まず表示とインデント、次に自分が毎日使うキーマップ、その後に言語ごとの支援、という順番です。各段階で Neovim を再起動し、普段編集するファイルを一つ開いて確認します。動作が分かれたら lua/ 配下へ分割しても構いませんが、分けること自体は機能を増やしません。最初は init.lua のままの方が、読み込み順と失敗箇所を追えます。
設定ファイルを Git で管理するなら、起動を確認した段階だけをコミットします。プラグインを導入する前の状態を戻り先として残せるため、比較と復旧が簡単になります。
組み込み LSP はサーバーと設定を分けて考える
LSP は、定義ジャンプ、診断、リネームなどを言語の意味に沿って提供するためのプロトコルです。Neovim には LSP クライアントが組み込まれていますが、Lua や Python を解析する言語サーバー本体までは含まれません。先に対象サーバーがシェルから見つかることを確認します。以下は Lua Language Server を使う例です。
command -v lua-language-server
何も表示されなければ、OS のパッケージ管理方法または Lua Language Server の配布元の手順で導入してから進みます。Neovim 側だけ設定しても、$PATH にないサーバーは起動できません。
サーバーごとの既定設定を提供する nvim-lspconfig は、旧来の設定フレームワークではなく設定カタログとして使います。公式 README が非推奨とする旧形式ではなく、vim.lsp.config() と vim.lsp.enable() を使います。Neovim 0.12.4 の隔離設定へ、標準の package 機構で置きます。
mkdir -p -- "$config_root/nvim-minimal/pack/editor/start"
git clone --depth=1 https://github.com/neovim/nvim-lspconfig \
"$config_root/nvim-minimal/pack/editor/start/nvim-lspconfig"
init.lua の末尾に、まずは Lua 用の設定だけを追加します。nvim-lspconfig の lua_ls 定義には起動コマンド、対象 filetype、プロジェクトルートの候補が入っているため、ここでは自分の上書き分だけを記述します。
vim.lsp.config("lua_ls", {
settings = {
Lua = {
diagnostics = {
globals = { "vim" },
},
},
},
})
vim.lsp.enable("lua_ls")
この順序には意味があります。vim.lsp.config() は設定を定義または既存定義へマージし、vim.lsp.enable() は filetype と root 条件に合うバッファで自動起動を有効にします。設定名とサーバー実行ファイル名は必ずしも同じではないため、別の言語を追加するときは :help lspconfig-all の当該サーバー定義を確認します。
起動後は init.lua を開き、次を実行します。
:checkhealth vim.lsp
:set filetype?
:messages
vim.lsp の healthcheck で有効な設定とサーバーの状態を確認し、filetype? が lua になっているかを見ます。接続しない場合は、まず command -v lua-language-server、次にプロジェクトルート判定、最後に :LspLog の順に確認します。診断表示がないことを補完プラグインの問題と決めつけず、サーバーが起動・接続しているかを先に切り分けるのが近道です。
補完 UI は必要になってから追加する
LSP を有効にすることと、候補を整形してポップアップ表示することは別です。候補の選択、スニペット展開、バッファ内単語やパスの候補まで必要になったときに、補完エンジンを足します。nvim-cmp は外部の completion source を集める Lua 製プラグインです。
導入する場合は nvim-cmp と cmp-nvim-lsp、使うスニペットエンジンを一組として扱います。公式 README は LSP のスニペット候補を展開する関数が必要であること、cmp.mapping.preset.* のキーマップは予告なく変わり得ることを明記しています。つまり「候補一覧が欲しい」だけなら便利ですが、キー操作とスニペットの選択まで保守対象になります。
nvim-cmp を導入済みの場合だけ、LSP の capabilities を設定してから有効化します。
local capabilities = require("cmp_nvim_lsp").default_capabilities()
vim.lsp.config("lua_ls", {
capabilities = capabilities,
})
vim.lsp.enable("lua_ls")
補完の有無で LSP の正常性を判断しないでください。最初は補完なしで定義ジャンプや診断を確認し、その後に nvim-cmp の README にある構成を最小の source から足すと、問題の境界が明確です。自分で割り当てるキーを決め、README の preset に全てを委ねない方が、更新時の意図しないキー変更も避けられます。
Tree-sitter は機能と更新コストを分ける
Tree-sitter は構文木を使ってハイライト、折りたたみ、インデントなどを支える仕組みです。LSP の必須条件ではありません。LSP が定義ジャンプや診断を担当し、Tree-sitter は主に構文に基づく編集体験を改善します。Python や Lua を少数編集するだけなら、先に LSP を安定させる方が優先度は高いでしょう。
nvim-treesitter を追加するなら、単に setup() を呼ぶだけでは終わりません。公式 README は、プラグインを更新したらインストール済み parser も :TSUpdate で更新する必要があること、parser と query の組み合わせが言語・機能ごとに必要なことを説明しています。また Tree-sitter によるインデントは experimental とされています。ハイライトが必要な言語だけに絞り、インデントは普段のコードで十分に確認できるまで有効化しない方が安全です。
Neovim 本体には :checkhealth vim.treesitter があるため、parser や実行環境に関する問題はそこから確認できます。追加直後に全言語を入れるのではなく、実際に開く一言語でハイライトを確認し、プラグイン更新時には :TSUpdate と再起動を同じ手順にします。これは便利さではなく、更新時に誰が何を直すかという保守負担との交換です。
失敗した設定を二分探索する
起動エラーを見たら、設定を一から書き直す前に、原因が本体・設定・プラグイン・外部サーバーのどこにあるかを分けます。最初に nvim --clean を実行します。これが成功すれば、少なくとも通常設定を読まない Neovim は起動しています。次に NVIM_APPNAME=nvim-minimal nvim で最小設定を起動します。
設定を複数ファイルに分けた後は、init.lua の require を読み込み順に一行ずつ並べます。後半半分を一時的にコメントアウトして起動し、問題が消えれば原因は外した半分、残れば有効な半分にあります。該当する側をさらに半分にして繰り返せば、設定が 16 個でも 4 回程度で候補を狭められます。候補がプラグインなら、そのプラグインだけを外し、外部コマンドなら command -v と healthcheck を確認します。
:checkhealth
:checkhealth vim.lsp vim.treesitter
:messages
:LspLog
checkhealth は設定、性能、クリップボードなどの標準 healthcheck を実行します。問題の再現手順、表示されたエラー、LspLog の該当箇所を残しておくと、後から設定を戻しても比較できます。エラーを隠すために pcall(require, ...) を増やすのは避けます。起動は通っても、本来必要な機能が静かに失われ、次の更新で調査しにくくなるためです。
元に戻す方法
隔離した nvim-minimal だけを試していたなら、何も戻す必要はありません。NVIM_APPNAME を付けない nvim を起動すれば元の環境です。実験用の設定とデータが不要になったことを確認してから、nvim-minimal 側だけを整理します。
通常の nvim 設定を変更して起動できなくなった場合は、まず設定を読まない状態でファイルを確認します。
nvim --clean "$config_root/nvim/init.lua"
退避したバックアップがあるなら、壊れた設定を消さずに別名へ移してから復元します。backup_dir は最初に表示された実際のパスへ置き換えてください。
config_root="${XDG_CONFIG_HOME:-$HOME/.config}"
backup_dir="$config_root/nvim.backup.20260710-120000" # 実際の退避先に置き換える
stamp="$(date +%Y%m%d-%H%M%S)"
mv -- "$config_root/nvim" "$config_root/nvim.broken.$stamp"
mv -- "$backup_dir" "$config_root/nvim"
この手順は問題の設定を残したまま元へ戻します。復旧後は、二分探索で判明した一項目だけを隔離環境に戻して検証します。設定を育てる速さより、いつでも動く状態へ戻れることを優先すると、更新や新しい言語の追加も怖くなりません。