Neovimのmini.nvimとは 0.12の標準機能と重なるモジュールを見分ける
mini.nvimは、コメント・補完・括弧の付け外し・ファイラーなどを1つにまとめたNeovimのプラグイン集で、手元に入れた版ではlua/mini/の下に46個のモジュールがありました。Neovim 0.12でコメントのgc、autocomplete、vim.snippet、vim.packが本体に入り、その一部と役目が重なっています。
そこでNeovim 0.12.6で、重なりそうなモジュールを標準機能と同じ操作で動かして比べました。結論を先に書くと、コメントとプラグイン管理は標準で足ります。一方でmini.aiの関数呼び出しと引数のテキストオブジェクト、mini.surround、mini.filesは標準に代わりがありません。
検証環境:NVIM v0.12.6(macOS)、比較用にVim 9.1.1752。mini.nvimは2026-11-07のmainブランチ(コミットf9550dd、CHANGELOG上は0.19.0-dev。最新のstableはv0.18.0)、MiniMaxは同日のコミット9f3ac33です。一時ディレクトリにgit cloneし、nvim -n -uで数行の設定を読ませて起動しました。編集結果はnvim_feedkeys()でキーを送った結果、補完・スニペット・mini.filesはtmuxで操作した画面です。oil.nvimは入れていません。
目次(9項目)
mini.nvimとは何か
モジュールは互いに依存せず、どれもrequire('mini.xxx').setup()を呼ぶまで何もしません。runtimepathに足しただけ、requireしただけ、setup()の後の3つで、キーマップをmaparg()で読み比べました。
before: MiniAi= nil sa= (none) gc= Toggle comment gcc= Toggle comment line M-j= (none)
after require only: MiniComment= false gc= Toggle comment
after setup: gc= Comment gcc= Comment line sa= Add surrounding M-j= Move line down o_a= Around textobject
1行目のgcに付いているToggle commentはNeovim本体のマッピングです。require('mini.comment')だけでは何も変わらず、グローバルのMiniCommentも作られません。setup()を呼んだところで初めてgcがmini.commentのCommentに置き換わり、mini.surroundのsaやmini.moveのAlt-jが生えます。入れたのに効かないときはsetup()の呼び忘れを疑ってください。
入れ方 モジュールごとか丸ごとか
READMEが推奨として最初に挙げているのはvim.packです。丸ごと入れるなら1行で済みます。
-- init.lua(mainブランチ)
vim.pack.add({ 'https://github.com/nvim-mini/mini.nvim' })
-- stableブランチにする場合
vim.pack.add({ { src = 'https://github.com/nvim-mini/mini.nvim', version = 'stable' } })
require('mini.surround').setup()
各モジュールは単独のリポジトリとしても配られています。https://github.com/nvim-mini/mini.surroundをvim.pack.add()に渡して試したところ、入ったのはmini.surroundのディレクトリだけで、require('mini.ai')は失敗しました。ロックファイルnvim-pack-lock.jsonには次の1件が書かれます。
{
"plugins": {
"mini.surround": {
"rev": "5357f00aca51a3b43e7775901b1ad9699f8c2678",
"src": "https://github.com/nvim-mini/mini.surround"
}
}
}
lazy.nvimならREADMEの書き方は{ 'nvim-mini/mini.nvim', version = false }(stableはversion = '*')で、setup()はやはり自分で呼びます。vim.packそのものの使い方はNeovim 0.12の標準プラグイン管理 vim.packにまとめてあります。
Neovim 0.12の標準機能と重なるモジュール
mini.comment と標準のgc
Neovim 0.10から入った標準のgcは、MiniMaxの設定ファイルのコメントによるとmini.commentを元にしています。Luaのバッファで比べると、ほとんど区別が付きません。
| 操作 | 標準のgc | mini.comment |
|---|---|---|
| gcc→j→. | 2行ともコメント化 | 同じ |
| 3gcc | 3行コメント化 | 同じ |
| dgc | コメントの塊を削除 | 同じ |
| 空行を含む範囲 | 空行にも--が入る | 同じ(ignore_blank_lineで除外できる) |
commentstring=--%s | --a = 1 | -- a = 1 |
違いは最後の2行です。mini.commentはpad_comment_partsが既定で有効なので、commentstringに空白が無くても記号の後に空白を入れます。ほかにhooksとcustom_commentstringがありますが、こうした調整が要らないなら標準のgcで足ります。
mini.completion と標準のautocomplete
LSP無しでfoobar foobaz footballと書いたバッファにfooと打つと、vim.o.autocomplete = trueだけでもrequire('mini.completion').setup()だけでも、同じ3つの候補が出ました。LSPが無いときのmini.completionは100ミリ秒待ってCtrl-nを実行するだけです。
差が出るのはLSPを使うときです。mini.completionはLSPの候補を先に取り、無ければCtrl-nへ落ちる2段構えで、候補の説明と関数の引数も浮動ウィンドウに出します。標準側はvim.lsp.completion.enable()にautotrigger = trueを渡します。設定はVim/Neovimの標準自動補完(autocomplete)で扱っています。
mini.snippets と vim.snippet
vim.snippetにあるのはvim.snippet.expand()とジャンプの仕組みだけです。vim.snippet.expand('function ${1:name}($2)\n\t$0\nend')を呼ぶと3行の関数が展開されますが、fnと打ってから展開する手段は本体にありません。素の状態でfnのあとCtrl-jを押すと、ただ改行が入りました。
mini.snippetsは同じ本文をprefix = 'fn'で登録しておくと、fn→Ctrl-jで展開します。nameの位置でfooと打つと仮の文字が置き換わり、Ctrl-lで括弧の中、次のCtrl-lで本文の行へ移りました。戻るのはCtrl-h、やめるのはCtrl-cです。JSONのスニペット集を読む仕組みもmini側にしかありません。詳しい境目はNeovimでスニペットを使う vim.snippetとLuaSnipの境目を見てください。
mini.deps と vim.pack
ここは比べるまでもありません。mini.depsのヘルプの冒頭に、vim.packがmini.depsを設計の参考にして入ったこと、開発は凍結したこと、0.12以降ではvim.packを使うよう勧めることが書いてあります。mini.depsにあったMiniDeps.nowとMiniDeps.laterの代わりは、mini.miscのMiniMisc.safelyです。
local misc = require('mini.misc')
misc.safely('now', function() table.insert(order, 'now') end)
misc.safely('later', function() table.insert(order, 'later') end)
table.insert(order, 'end-of-init')
misc.safely('now', function() error('boom') end)
-- 出力: now -> end-of-init -> later
-- error('boom') は (mini.misc) Error during safe execution: ... の警告になり、起動は続く
'later'の関数は設定ファイルを読み終えてから実行され、error('boom')は警告になって残りの設定は止まりませんでした。
mini.ai と標準のテキストオブジェクトの差
カーソルを行頭に置いたlocal x = foo(bar, "baz qux") + baz(1)で、同じキーを標準とmini.aiの両方で打ちました。
| キー | カーソル | 標準 | mini.ai |
|---|---|---|---|
| di" | 行頭 | foo(bar, "") | 同じ |
| di) | 行頭 | foo() | 同じ |
| din) | barの上 | 変化なし | baz(1)の1を削除 |
| dif | 行頭 | 変化なし | foo() |
| daf | 行頭 | 変化なし | foo(...)ごと削除 |
| dia | barの上 | 変化なし | foo(, "baz qux") |
| diq | 行頭 | 変化なし | foo(bar, "") |
意外だったのは2行目です。括弧の外からでも、標準のdi)は同じ行の先の括弧を見つけて中身を消しました(Vim 9.1.1752でも同じ)。これはmini.aiだけの利点ではありません。mini.aiにしかないのは、関数呼び出しのf、引数1つぶんのa、引用符の種類を問わないq、そして「次の」括弧を指すin/anです。
そのinとanには注意が要ります。Neovim 0.12はビジュアルモードと演算子待ちのan/inに、構文木やLSPで選択範囲を広げ縮めする機能を割り当てました。標準のままdin)を打つとvim.lsp: method "textDocument/selectionRange" is not supportedと出て何も起きなかったのはこのためです。mini.aiはsetup()でこれを上書きします。
before x an Select parent (outer) node
before x in Select child (inner) node
after x an Around next textobject
after x in Inside next textobject
:h MiniAi-default-an-inは上書きを意図したものとしたうえで、setup()の前に標準のマッピングを別のキーへ写す方法と、around_next = 'aN'のように名前を変える方法を載せています。同じように「前の」を指すal/ilも、Neovimに行と全体のテキストオブジェクトが入る al と ilで扱った0.13の新機能と名前が重なります。
mini.surround・mini.move・mini.filesで標準に無いこと
この3つは0.12.6の本体に相当する機能がありません。mini.surroundはsaで付け、sdで外し、srで付け替えます。hello worldの先頭でsaiw)なら(hello) world、saiw(なら( hello ) worldです。setup()のあとmaparg('s', 'n')は<Nop>を返し、素のsは使えなくなります(代わりはcl)。f(a)でsr)]はf[a]、x = foo(bar)のfooの上でsdfは関数名ごと外してx = barになりました。
ただしmini.surroundの検索は既定でsearch_method = 'cover'、つまりカーソルを囲んでいるものしか探しません。x = "hi"の行頭でsd"を打つとNo surrounding '"' found within 20 linesと出て失敗し、引用符の中からなら外れました。先を探すmini.aiとは既定が違います。vim-surroundのys/cs/dsとの対応はVimのsurroundで括弧や引用符を付け替える(ys / cs / ds)にあります。
mini.moveはAlt-j/Alt-kで行や選択範囲を上下に動かします。a b c dの4行でVj→Alt-jならc a b dの順になりました。標準では:mを自分でマップします(Vimで行を上下に移動する :mコマンドとddpの違い)。キーはnvim_feedkeys()で送ったので、端末のAltキーが届くかは確かめていません。
mini.filesはディレクトリを列で並べるファイラーです。:lua MiniFiles.open()で開き、lで子のディレクトリが右の列に開き、hで戻ります。ファイルの操作は列のバッファを書き換えて=を押すと確定します。srcの列でoからnew.luaと書いて=を押すと、次の確認が出ました。
CONFIRM FILE SYSTEM ACTIONS
.../proj/src
CREATE │ new.lua (file)
[Y]es, (N)o, (C)ancel:
ここで気を付けたいのが改名です。util.luaの行をccで丸ごと書き直して=を押すと、確認画面はDELETE │ util.lua (permanently)とCREATE │ helpers.lua (file)の2行になりました。行の先頭には見えない識別子が隠れていて、ccはそれごと消すからです。名前の部分だけをciwなどで書き換えたときはRENAMEと出ました。既定のpermanent_delete = trueでは削除がゴミ箱を通りません。
oil.nvimは:wで確定しますが、mini.filesで:wを打つとE382: Cannot write, 'buftype' option is setになりました(buftypeはnofile)。確定のキーは=だけです。oil.nvim側の操作はNeovimのoil.nvimの使い方にあります。標準のnetrwは%やRで1つずつ操作する方式です。
公式の雛形MiniMaxは何を有効にしているか
MiniMaxはmini.nvimの作者による設定の生成スクリプトで、NVIM_APPNAME=nvim-minimax nvim -l ./MiniMax/setup.luaを流すとNeovimの版に合った雛形を写します。0.12用の雛形はプラグインをvim.pack.add()で入れ、mini.depsは使わず、読み込みの順番をMiniMisc.safelyで書いています。
plugin/30_mini.luaでrequireしているモジュールを数えると37個でした。使っていないのはanimate base16 colors cursorword deps doc fuzzy hues testの9個です。標準と重なるmini.commentも有効のままで、「標準のコメント機能はmini.commentが元だが、調整の余地が多いので有効にしておく」という趣旨のコメントが付いています。mini.snippetsはfriendly-snippetsを読む形でした。
標準で足りるもの、miniを入れる価値があるもの
| モジュール | 比べた標準機能 | 判定 | 決め手 |
|---|---|---|---|
| mini.deps | vim.pack | 標準で足りる | 開発凍結。作者もvim.packを勧める |
| mini.comment | gc | 標準で足りる | 差は空白の補い・空行の扱い・hooksだけ |
| mini.completion | autocomplete | LSP次第 | LSP無しなら同じ。説明と引数の表示はmini |
| mini.snippets | vim.snippet | miniに差あり | 接頭辞から展開・スニペット集の読み込み |
| mini.ai | i( i" | miniに差あり | f a qと次の括弧。an/inは上書き |
| mini.surround | なし | miniにしかない | 付け・外し・付け替え |
| mini.move | :m | miniにしかない | 選択範囲ごと動かせる |
| mini.files | netrw | miniにしかない | 列表示と=での一括確定 |
0.12で本体に入った機能全体の一覧はNeovim 0.12の新機能 外せるプラグインと外せないものにあります。
mini.filesで改名を試したとき、最初は手に馴染んだccで行を打ち直しました。確認画面にRENAMEではなくDELETEが出ていて、しかも(permanently)と付いていたので慌ててcで取り消しました。一時ディレクトリの空ファイルでしたが、本物のプロジェクトでyを反射的に押していたらゴミ箱にも残りません。
まとめ
Neovim 0.12で使うなら、mini.depsとmini.commentは入れなくて困りません。最初に入れる3つを選ぶなら、標準に代わりのないmini.ai、mini.surround、mini.filesです。mini.aiは0.12のan/inを上書きすること、mini.filesの改名は名前の部分だけを書き換えることの2つを覚えておけば足ります。補完とスニペットは、LSPとスニペット集を使うかどうかで決めてください。