mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
fix(lua): show stacktrace for error in vim.on_key() callback (#31021)
This commit is contained in:
@@ -701,11 +701,13 @@ end
|
|||||||
--- Executes the on_key callbacks.
|
--- Executes the on_key callbacks.
|
||||||
---@private
|
---@private
|
||||||
function vim._on_key(buf, typed_buf)
|
function vim._on_key(buf, typed_buf)
|
||||||
local failed_ns_ids = {}
|
local failed = {} ---@type [integer, string][]
|
||||||
local failed_messages = {}
|
|
||||||
local discard = false
|
local discard = false
|
||||||
for k, v in pairs(on_key_cbs) do
|
for k, v in pairs(on_key_cbs) do
|
||||||
local ok, rv = pcall(v[1], buf, typed_buf)
|
local fn = v[1]
|
||||||
|
local ok, rv = xpcall(function()
|
||||||
|
return fn(buf, typed_buf)
|
||||||
|
end, debug.traceback)
|
||||||
if ok and rv ~= nil then
|
if ok and rv ~= nil then
|
||||||
if type(rv) == 'string' and #rv == 0 then
|
if type(rv) == 'string' and #rv == 0 then
|
||||||
discard = true
|
discard = true
|
||||||
@@ -718,19 +720,16 @@ function vim._on_key(buf, typed_buf)
|
|||||||
end
|
end
|
||||||
if not ok then
|
if not ok then
|
||||||
vim.on_key(nil, k)
|
vim.on_key(nil, k)
|
||||||
table.insert(failed_ns_ids, k)
|
table.insert(failed, { k, rv })
|
||||||
table.insert(failed_messages, rv)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if failed_ns_ids[1] then
|
if #failed > 0 then
|
||||||
error(
|
local errmsg = ''
|
||||||
string.format(
|
for _, v in ipairs(failed) do
|
||||||
"Error executing 'on_key' with ns_ids '%s'\n Messages: %s",
|
errmsg = errmsg .. string.format('\nWith ns_id %d: %s', v[1], v[2])
|
||||||
table.concat(failed_ns_ids, ', '),
|
end
|
||||||
table.concat(failed_messages, '\n')
|
error(errmsg)
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
return discard
|
return discard
|
||||||
end
|
end
|
||||||
|
@@ -2099,9 +2099,9 @@ bool nlua_execute_on_key(int c, char *typed_buf)
|
|||||||
int save_got_int = got_int;
|
int save_got_int = got_int;
|
||||||
got_int = false; // avoid interrupts when the key typed is Ctrl-C
|
got_int = false; // avoid interrupts when the key typed is Ctrl-C
|
||||||
bool discard = false;
|
bool discard = false;
|
||||||
if (nlua_pcall(lstate, 2, 1)) {
|
// Do not use nlua_pcall here to avoid duplicate stack trace information
|
||||||
nlua_error(lstate,
|
if (lua_pcall(lstate, 2, 1, 0)) {
|
||||||
_("Error executing vim.on_key Lua callback: %.*s"));
|
nlua_error(lstate, _("Error executing vim.on_key() callbacks: %.*s"));
|
||||||
} else {
|
} else {
|
||||||
if (lua_isboolean(lstate, -1)) {
|
if (lua_isboolean(lstate, -1)) {
|
||||||
discard = lua_toboolean(lstate, -1);
|
discard = lua_toboolean(lstate, -1);
|
||||||
|
@@ -3312,10 +3312,17 @@ describe('lua stdlib', function()
|
|||||||
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
|
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('skips any function that caused an error', function()
|
it('skips any function that caused an error and shows stacktrace', function()
|
||||||
insert([[hello world]])
|
insert([[hello world]])
|
||||||
|
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
|
local function ErrF2()
|
||||||
|
error("Dumb Error")
|
||||||
|
end
|
||||||
|
local function ErrF1()
|
||||||
|
ErrF2()
|
||||||
|
end
|
||||||
|
|
||||||
keys = {}
|
keys = {}
|
||||||
|
|
||||||
return vim.on_key(function(buf)
|
return vim.on_key(function(buf)
|
||||||
@@ -3326,7 +3333,7 @@ describe('lua stdlib', function()
|
|||||||
table.insert(keys, buf)
|
table.insert(keys, buf)
|
||||||
|
|
||||||
if buf == 'l' then
|
if buf == 'l' then
|
||||||
error("Dumb Error")
|
ErrF1()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
]]
|
]]
|
||||||
@@ -3336,6 +3343,19 @@ describe('lua stdlib', function()
|
|||||||
|
|
||||||
-- Only the first letter gets added. After that we remove the callback
|
-- Only the first letter gets added. After that we remove the callback
|
||||||
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
|
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
|
||||||
|
|
||||||
|
local errmsg = api.nvim_get_vvar('errmsg')
|
||||||
|
matches(
|
||||||
|
[[
|
||||||
|
^Error executing vim%.on%_key%(%) callbacks:.*
|
||||||
|
With ns%_id %d+: .*: Dumb Error
|
||||||
|
stack traceback:
|
||||||
|
.*: in function 'error'
|
||||||
|
.*: in function 'ErrF2'
|
||||||
|
.*: in function 'ErrF1'
|
||||||
|
.*]],
|
||||||
|
errmsg
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('argument 1 is keys after mapping, argument 2 is typed keys', function()
|
it('argument 1 is keys after mapping, argument 2 is typed keys', function()
|
||||||
@@ -3449,6 +3469,7 @@ describe('lua stdlib', function()
|
|||||||
-- second key produces an error which removes the callback
|
-- second key produces an error which removes the callback
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
n_call = 0
|
n_call = 0
|
||||||
|
|
||||||
vim.on_key(function(buf, typed_buf)
|
vim.on_key(function(buf, typed_buf)
|
||||||
if typed_buf == 'x' then
|
if typed_buf == 'x' then
|
||||||
n_call = n_call + 1
|
n_call = n_call + 1
|
||||||
@@ -3460,7 +3481,7 @@ describe('lua stdlib', function()
|
|||||||
api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
|
api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
|
||||||
|
|
||||||
local function cleanup_msg(msg)
|
local function cleanup_msg(msg)
|
||||||
return (remove_trace(msg):gsub('^Error.*\n *Messages: ', ''))
|
return msg:gsub('^Error .*\nWith ns%_id %d+: ', '')
|
||||||
end
|
end
|
||||||
|
|
||||||
feed('x')
|
feed('x')
|
||||||
|
Reference in New Issue
Block a user