optディレクトリのみを使うNeovim用プラグインマネージャーを作った

2021/12/29に公開

https://github.com/notomo/optpack.nvim

Neovim用のプラグインマネージャーを作った。ひとまず自分が使う機能しかない。

なぜ作った?

  • minpacを愛用していて拡張するスクリプトが大きくなったのが最初の動機
    • 更に拡張したくなって自分用の設定から切り出す必要があった
  • startディレクトリの挙動が自分に合わない
    • startディレクトリ内のプラグインは存在すれば読み込まれる
    • ディレクトリがあっても設定のコメントアウトで無効にしたい
  • 単なる興味

ほぼ再発明プラグインだが、実装して知ったことを以下に書く。

optディレクトリを扱う上での注意点

意外とpackagesの機能を分かってなかった。
その中でもoptディレクトリについての注意点を3つ挙げる。

packpath配下に同名のプラグインがある場合のpackaddで両方がruntimepathに追加される

結果としてruntimepath上で先にある方が優先される。
以下のluaディレクトリを使う例だとrequire("myplugin")mypackage1の方のinit.luaを読む。

local packpath = "./mypackpath"
vim.cmd("set packpath^=" .. packpath)

local create_plugin = function(package_name)
  local plugin = packpath .. ("/pack/%s/opt/myplugin.nvim/lua/myplugin/"):format(package_name)
  vim.fn.mkdir(plugin, "p")
  io.open(plugin .. "init.lua", "w"):close()
end
create_plugin("mypackage1")
create_plugin("mypackage2")

vim.cmd("packadd myplugin.nvim")

print(vim.inspect(vim.api.nvim_get_runtime_file("lua/myplugin/init.lua", true)))
-- { "./mypackpath/pack/mypackage1/opt/myplugin.nvim/lua/myplugin/init.lua", "./mypackpath/pack/mypackage2/opt/myplugin.nvim/lua/myplugin/init.lua" }

:colorschemeはoptディレクトリに入っているカラースキームも読み込める

特に困らないが例外的な挙動に感じたので一応挙げた。
ヘルプにも書かれている。 :help packages

初期化時以外に:packaddしてもafter/pluginディレクトリは読み込まれない

runtimepathには追加されるので、初期化時の:packaddなら問題ない。 :help load-plugins
つまり、以下のように初期化時の処理の最後に呼ばれる+{command}だと読み込まれない。

$ nvim --headless -u NORC +"luafile ./test.lua"
$ nvim --headless -u test.vim
test
test.vim
luafile ./test.lua
test.lua
local packpath = "./mypackpath"
vim.cmd("set packpath^=" .. packpath)

local create_plugin = function(package_name)
  local plugin = packpath .. ("/pack/%s/opt/myplugin.nvim/after/plugin/"):format(package_name)
  vim.fn.mkdir(plugin, "p")
  local f = io.open(plugin .. "myplugin.lua", "w")
  f:write([[print("test")]])
  f:close()
end
create_plugin("mypackage1")

vim.cmd("packadd myplugin.nvim")

読まれないと動作に支障があるプラグインなら明示的に読み込むしかなさそう。
(例: :runtime after/plugin/myplugin.vim)

テストでGitサーバーを使う

プラグインの更新時の挙動のテストを書く際にモックではないGitサーバーを使った。
プラグインマネージャーは常に壊れてほしくないのと、
Gitサーバーをモックにして意味のあるテストを書く自信がなかった。

Gitサーバーはpython -m http.server --cgigit-http-backendで実現し、
テスト内で起動・終了するようにした。
https://git-scm.com/book/en/v2/Git-on-the-Server-Smart-HTTP に書かれているが、
テストなので全リポジトリが公開されるように環境変数にGIT_HTTP_EXPORT_ALLを設定する。(1敗)
optpack.nvimが扱うGitサーバーのurlはオプションで変更可能にしておいて、テストではhttp://127.0.0.1:8000/cgi-bin/git-http-backendを使えばいい。

ローカルで動くのでテストを増やしても全体で1秒ぐらいで済み、体験が悪くならなかった。

感想

  • 実装が難しそうな機能を省いても結構大変だった
  • それぞれのプラグインに対して一連のgitコマンドを実行するので、
    Promiseがないと厳しかった

Discussion