世界を動かす技術を、日本語で。

Neovim パック

概要

Neovimの パッケージ管理プラグイン管理 の仕組みについて解説。 Vimパッケージディレクトリ構造や 自動・手動ロード の違いを整理。 パッケージ作成手順や 依存関係の管理方法 を紹介。 新しい 内蔵プラグインマネージャ(vim.pack) の使い方も説明。 各手順や推奨配置を 箇条書き でまとめて理解しやすく構成。

NeovimでのVimパッケージ拡張

  • Vimパッケージ は複数プラグインをまとめて管理するディレクトリ構成
  • アーカイブ展開Gitリポジトリ として管理・更新が容易
  • 依存関係を持つ複数プラグイン のまとめ管理が可能
  • 自動ロード(start)手動ロード(opt) の2種類の配置
    • start: pack/*/start/* 配下で自動ロード
    • opt: pack/*/opt/* 配下で :packadd で手動ロード
  • runtime-search-path ではstartディレクトリが自動的に検索対象
    • ただし 'runtimepath' には明示的に含まれず ":set rtp" で確認不可
    • nvim_list_runtime_paths()nvim_get_runtime_file()で確認

パッケージの追加・自動ロード手順

  • 例: ~/.local/share/nvim/site/pack/foo/start/foobar/ にプラグイン展開
  • ディレクトリ名(foo)は任意
  • Nvim起動時にpackpath内のstartディレクトリを自動スキャン・ロード
  • foobarプラグインがfiletypeを設定した場合、該当syntaxファイルも自動検索
  • opt配下のプラグインは自動ロードされない(手動で:packaddが必要)
  • プラグインの自動ロード無効時は:packloadallで明示的ロードが可能
  • afterディレクトリが存在する場合、'runtimepath'の末尾に追加され後からロード

単体プラグインの自動ロード

  • パッケージ構造がなくても、pack/foo/start/foobar/を作成し展開で同様に動作

オプションプラグインの手動ロード

  • :packaddコマンドでopt配下のプラグインを手動ロード
    • 例: :packadd foodebug
    • 設定ファイル内で:packadd! foodebugと書くと--noplugin時はロードしない
  • opt配下のみのパッケージも作成可能、必要時のみロード

配置の推奨

  • colorschemeはstart/optどちらでも可、推奨はopt配下
  • filetypeプラグインはstart配下推奨
  • afterディレクトリは通常不要だが利用自体は可能

Vimパッケージの作成

  • 複数プラグインをまとめて配布したい場合にパッケージ作成
  • 構成例:
    • start/foobar/plugin/foo.vim(常時ロードされるコマンド定義)
    • start/foobar/autoload/foo.vim(コマンド利用時に自動ロード)
    • start/foobar/doc/foo.txt, tags(ヘルプファイル)
    • opt/fooextra/plugin/extra.vim(オプションプラグイン)
    • opt/fooextra/autoload/extra.vim, doc/extra.txt, tags
  • 配布方法はアーカイブまたはリポジトリ(GitHub推奨)
  • 利用者はgit clonepackディレクトリに配置
  • オプションプラグインのロード例: :packadd! fooextra
  • ヘルプタグ生成には:helptagsコマンドを利用

プラグイン間の依存関係管理

  • 共通機能はautoloadディレクトリに配置
  • 例:
    • pack/foo/start/one/plugin/one.vim(foolib#getit()呼び出し)
    • pack/foo/start/lib/autoload/foolib.vim(共通関数定義)
  • startパッケージ内でautoloadファイルも自動検索対象

内蔵プラグインマネージャ vim.pack

  • vim.pack はNeovim組み込みのプラグイン管理機能(開発中)
  • $XDG_DATA_HOME/nvim/site/pack/core/opt専用ディレクトリで管理
  • Git必須 (バージョン2.36以上)、プラグインはGitリポジトリで管理
  • プラグイン名=サブディレクトリ名(指定可能)
  • セマンティックバージョニング(v1.2.3など)タグを利用

基本的な使い方

  • init.luavim.pack.add()を記述
    • 例:
      • 'https://github.com/user/plugin1'(デフォルトブランチでインストール)
      • { src = 'https://github.com/user/plugin3', version = vim.version.range('1.0') }(バージョン指定)
      • { src = 'https://github.com/user/generic-name', name = 'plugin2' }(任意の名前指定)
  • Neovim再起動で未インストールプラグインが自動インストール
  • vim.pack.update()で全プラグインを最新化
    • アップデート内容を確認後、:writeで確定、:quitで破棄
  • バージョン変更やフリーズ(更新停止)はinit.luaでversion指定を編集
  • vim.pack.del()でプラグイン削除

イベントフック

  • PackChangedPre(状態変更前)、PackChanged(変更後)のイベント
  • kind(install/update/delete)、spec(仕様)、path(パス)などの情報付与

仕様フィールド

  • src:Git URI
  • name:プラグイン名(デフォルトはリポジトリ名)
  • version:ブランチ・タグ・コミットハッシュまたはvim.version.range出力
  • data:任意データ

補足

  • インストールは並列処理、全完了後に次の処理へ
  • ディスク上の状態が指定バージョンと異なる場合は明示的にアップデートが必要

参考:

  • 詳細は:help packagesや公式ドキュメント参照
  • vim.packは今後仕様変更の可能性あり、利用時は注意

Hackerたちの意見

3年ごとに新しい(Neo)Vimパッケージマネージャに移行しなきゃいけない気がする。これまでの流れは、pathogen -> Vundle -> vim-plug -> lazy.nvimって感じかな。これが最後のVIMパッケージマネージャであってほしいな。

Plugはまだまだ使えると思う。でも、これが言語に組み込まれてるから、たくさんのユーザーにとってはエンドゲームにふさわしいものになるんじゃないかなって期待してる。試してみたけど、特に問題なく使えたよ。lazyが提供するような派手なことはやってないけどね。

lazy.nvimはかなり成功してるみたいだね。でも、他にもいろんなプラグインがサポートされてるし、抽象的には統一感があったらいいなと思う。でも、lazy.nvimのように速くて信頼できるものが手に入るかどうか、ちょっと信じるのが難しいな。まあ、可能性はあるけどね!

新しいパッケージマネージャは今のところかなり遅いよ。lazy vimでnvimを読み込むのに200msかかるのに対して、Packだと1秒かかる感じ。

幸運なことに、これは組み込みの公式なやつだから、最も広くサポートされる可能性が高いね。(でも、機能が豊富とは限らないかも)

俺はほんとにただgitとvimを使ってるだけだよ。

nixvimを使い始めたんだけど、vim-plugあたりで諦めた気がする。複数のマシンやOSで安定して動く設定を維持するのが悪夢だったからね。

2017年にpathogenをやめて、~/.vim/pack/*/start/にgitサブモジュールを使うようにしたけど、今でもそのままだよ。

みんながlazy.vimに移行してる中、私はvim-plugを使い続けてる。週末にlazy.vimに移行しようかなって考えてたけど、このニュースを聞いて、プラグインマネージャーが出るまで待った方が良さそうだな。

自分の(プライベートな)dotfilesのgit履歴を見てみたら、2011年にpathogen、2013年にvundle、2017年にvim-plugを使い始めて、それ以来動かしてない。Plugはまだまだ役に立ってるし、2021年にneovimに移行した後も問題なし。落ち着いたら新しい組み込みパッケージマネージャーに移るかも。

Nixでは、NixOSやMacOS、Linuxのnix管理のhome-managerでも、覚えてる限り同じだよ: neovim = { enable = true; vimAlias = true; vimdiffAlias = true; defaultEditor = true; plugins = [ pkgs.vimPlugins.fugitive pkgs.vimPlugins.fzf-vim pkgs.vimPlugins.vim-gh-line pkgs.vimPlugins.vim-gutentags pkgs.vimPlugins.nvim-lspconfig pkgs.pkgs-unstable.vimPlugins.vim-go pkgs.pkgs-unstable.vimPlugins.zig-vim ]; extraConfig = builtins.readFile ./vimrc; extraLuaConfig = builtins.readFile (pkgs.replaceVars ./dev.lua { inherit (pkgs) ripgrep; }).outPath; }

これがその元の問題だよ: https://github.com/neovim/neovim/issues/20893 どうやら、これはNeovimプロジェクトの長年の目標だったみたいだけど、理由はあまり説明されてないんだよね。既存のプラグインが素晴らしい仕事をしてたところに、無駄が増えたように感じるけど、どうやらそう思わない人もいるみたい。

まだまだ原始的だね。でも、遅延読み込みが実装されたら、lazyを使ってみたいな。lazy.nvimは最高だと思うけど、最近は作者が便利なオープンソースプラグイン(snack.nvimやmini.nvimみたいな)を次々と再実装してる気がして、ちょっとユーザーを引き留めようとしてるのかなって思う。それって、キルゾーンやコピーキャット戦略じゃない?よくわからないな。

それに、メンテされてないパッケージ(snacksみたいな)を捨てるのもね。// mini.nvimは全然別の作者だから、lazyとはあまり関係ないけど。

最小限である必要はないんだ。これが真の解決策になってほしいな、ニッチな要件は除いてね。今はまだgitサブモジュールを使ったvim packを使ってるけど、どのサードパーティのnvimパッケージマネージャーが一番サポートされてるか、人気があるか、今推奨されてるかを調べるのが面倒でさ。

Gitからコードをインポートできるものを見るたびに、特にブランチを指定できる場合(このパックはコミットハッシュもサポートしてるし)、特定の時点でブランチを「チェックアウト」できるってことをドキュメントに書いてほしいなって思う。だって、多くのブランチ(vimプラグインも含めて)はバージョニングすらしてないから。例えば、特定の日時でリポジトリをチェックアウトするには、こうするんだよ: > git checkout 'master@{2025-05-26 18:30:00}' みんながまた左パッドの災害(あるいはほぼ起こりかけたxzの黙示録)を避けられるように、ちょっとでも助けになれたらいいな。

SHAでやればいいじゃん?

気になるな。サプライチェーン攻撃のリスクってどんな感じ?VIMプラグインの権限ってどのくらいあるの?

プルリクの時点でのマスターを示すと思ってたけど、そうじゃなくてその時点に最も近いコミットを示すのはすごく混乱するね(再現性がないし、自分以外には)。再現性を持たせるためには、もっと複雑な git log --before=time が必要だと思う。

それはありそうなアイデアだけど、時計を使う場合、最初の質問は「誰の時計?」ってことになるね。リポジトリで定義された時計?自分の時計?Gitリモートの時計?私の知る限り、これはハッシュに使えるけど、友達はソフトウェア開発で時計を使わせない(最後の手段じゃない限り)。

これめっちゃ楽しみ!nvimプラグインコミュニティが、複雑なプラグインマネージャーに頼らず、デフォルトでプラグインをレイジーロードする方向に進む手助けになればいいな。nvimのドキュメントにも関連するちょっとしたメモがあるよ[1]。nvim-neorocksプラグインのベストプラクティスも結構好きなんだ[2]。実際、最近その一部がマージされたみたいだし[3]、ハハハ。

neovimのsetup()を使うモデルは、従来のVimよりもレイジーロードがちょっと難しいね。Vimの変数設定による構成モデルだと、レイジーロードはずっと簡単なんだけど。init.vimで変数を設定するだけで、その関数が実行されたときにプラグインが自動でロードされるから。Luaだともっとオーケストレーションが必要で、同じプラグインを参照するautocmdがたくさんあると、全部がsetup()を呼び出すことを明示的に覚えておかないといけない。

Vimプラグインマネージャーはあんまり必要ないと思う、特にdotfilesにgitを使ってるなら。プラグインのインストールは、そのファイルを(例えばリポジトリをクローンして)よく知られた場所に置くだけで済むから。そうすればいいんだよ。設定をgitで管理してるなら、プラグインもサブモジュールで管理できる。これによって正確なバージョンを固定できるし、そのバージョンを追跡することもできる。

自分は頻繁にプラグインを有効化したり無効化したりしてるけど、シェルやファイルシステムよりもcom configの方が簡単だと思う。でももっと重要なのは、ファイルタイプに基づいてプラグインを簡単にアクティブにできることかな。大体、ほとんどのプラグインマネージャーはgitの小さなラッパーに過ぎないと思うけどね。

設定をgitで管理してるなら、プラグインもサブモジュールで管理できる。これによって正確なバージョンを固定できるし、そのバージョンを追跡することもできる。これを1年くらいやってたけど、サブモジュールが全てのツール特有のパッケージマネージャー(vim、tmux、zshなど)を置き換えられるっていうモチベーションがあった。でも正直、Gitのサブモジュールの管理は、昔のvim-plugの設定に比べると面倒に感じた。サブモジュールはいいアイデアだけど、Gitでの実装があんまり使いやすくないからね。結局、戻っちゃった。もし誰かがvimの組み込みパックを使って、vim-plugよりも使いやすい設定をしてるなら、ぜひ聞きたいな。

最近これに移行したけど、特に問題はないよ。Lazy.nvimが持ってるような機能(例えば、いろんな方法でトリガーできるプラグインの遅延読み込み)はないけど、これは全然気にしてない。

長いことvim使ってるけど、プラグイン付きのneovimは自分には合わないな。いつも何かが壊れるし。LSPやtree sitterみたいなコアプラグインを統合し始めたら、neovimはもっと良くなると思う。

同じく。でも、次の5〜10年で落ち着くんじゃないかな。

LSPやtree sitterみたいなコアプラグインを統合し始めたら、neovimはもっと良くなると思う それ、まさに彼らがやってることだよ。tree-sitterとLSPは組み込まれていて、主要なLSP/tree-sitterプラグインはそれぞれデフォルトのLSP設定とtree-sitterクエリをバンドルしてる。さらに、nvim-treesitterプラグインにあまり依存しないように、tree-sitterクエリのバンドルをネイティブにNeovimに組み込む計画もあるみたい。最近、LSP設定が簡素化されて、新しいLSPを設定するのは基本的にこれだけ: vim.lsp.config("expert", { cmd = { "expert" }, root_markers = { "mix.exs", ".git" }, filetypes = { "elixir", "eelixir", "heex" }, }) vim.lsp.enable("expert") それから「LspAttach」autocmdでLSP特有のキーマップを定義できるよ。

自分も同じで、C/C++の開発にはずっとvimを使ってた。vim-plugやgutentags(ctagsマネージャー)、ALEはうまく機能してたから、他の方法を学ぶ気になれなかった。でも、ウェブ開発に移ると、いろんな構文やツールを使いこなさなきゃいけなくて…結局、neovimのディストリビューションを使うことにした。いろいろ試したけど、Lunarvim(今は非アクティブ)と今のAstronvimは今のところ自分に合ってる。

名前からして、AstroNVimのコミュニティパックみたいに「パック」を追加することだと思ってた。