🔧
Neovim Luaで実行されたファイルを1つにまとめるプラグイン
渡したLuaの関数で実行されたファイルを1つのチャンクにまとめるプラグインを作った。
動機
Lua製プラグインやNeovim本体のバグらしき挙動に遭遇した際に、バグを再現する最小のコードを作る。
バグの原因に全く見当がつかない場合、
バグを再現する最小でないコードからコードを徐々に減らして原因を見つけるようにしている。
この作業が大変で、補助する仕組みが欲しかった。
具体的な動作
以下のようにデバッグしたい関数を渡すとLuaのチャンクの文字列を得られる。
local debug_target = function()
if false then
error("unreachable")
end
return require("tracebundler.testdata.number")
end
local bundled = require("tracebundler").execute(debug_target)
生成されるチャンク
local _tracebundler_require = {}
local _tracebundler_loaded = {}
local global_require = require
local require = function(name)
if not name then
return global_require(name)
end
local loaded = _tracebundler_loaded[name]
if loaded then
return loaded
end
local f = _tracebundler_require[name:gsub("/", "%.")]
if not f then
return global_require(name)
end
local result = f(name)
_tracebundler_loaded[name] = result or package.loaded[name] or true
return _tracebundler_loaded[name]
end
_tracebundler_require["tracebundler.testdata.number"] = function(...)
return 8888 -- TRACED
end
local _tracebundler_entrypoint = function()
if false then -- TRACED
error("unreachable")
end
return require("tracebundler.testdata.number") -- TRACED
end
return _tracebundler_entrypoint()
チャンク内の関数を呼ぶようにrequire
が置き換えられるため、
require
でつながっている呼び出しがチャンク内で完結する。
(逆にExコマンド経由で呼び出されている場合はチャンク内で完結しない)
また、実行された行がわかるようにTRACED
というコメントを付けているので、
不要な処理を削るヒントになる。
感想
-
require
の置き換えをシンプルにできたのがLuaっぽい - ファイル内の実行されてない行の削減を自動でやるのはしんどそう
- チャンクをファイルに保存すると https://github.com/jbyuki/one-small-step-for-vimkind が動いたのでインタラクティブなデバッグと併用すると便利そう
Discussion