aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-11-02 10:11:06 +0800
committerGitHub <noreply@github.com>2024-11-02 10:11:06 +0800
commit3688a333544251c887d78e6501eec55f0fb685f8 (patch)
tree746b606179500e2ecb5c4e93cac5b70e2e2e831f
parentb25ae5d328fd58bae5052d1ae19bd1d17a991ea8 (diff)
downloadrneovim-3688a333544251c887d78e6501eec55f0fb685f8.tar.gz
rneovim-3688a333544251c887d78e6501eec55f0fb685f8.tar.bz2
rneovim-3688a333544251c887d78e6501eec55f0fb685f8.zip
fix(lua): show stacktrace for error in vim.on_key() callback (#31021)
-rw-r--r--runtime/lua/vim/_editor.lua25
-rw-r--r--src/nvim/lua/executor.c6
-rw-r--r--test/functional/lua/vim_spec.lua27
3 files changed, 39 insertions, 19 deletions
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 3167721a70..cbab2a0165 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -701,11 +701,13 @@ end
--- Executes the on_key callbacks.
---@private
function vim._on_key(buf, typed_buf)
- local failed_ns_ids = {}
- local failed_messages = {}
+ local failed = {} ---@type [integer, string][]
local discard = false
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 type(rv) == 'string' and #rv == 0 then
discard = true
@@ -718,19 +720,16 @@ function vim._on_key(buf, typed_buf)
end
if not ok then
vim.on_key(nil, k)
- table.insert(failed_ns_ids, k)
- table.insert(failed_messages, rv)
+ table.insert(failed, { k, rv })
end
end
- if failed_ns_ids[1] then
- error(
- string.format(
- "Error executing 'on_key' with ns_ids '%s'\n Messages: %s",
- table.concat(failed_ns_ids, ', '),
- table.concat(failed_messages, '\n')
- )
- )
+ if #failed > 0 then
+ local errmsg = ''
+ for _, v in ipairs(failed) do
+ errmsg = errmsg .. string.format('\nWith ns_id %d: %s', v[1], v[2])
+ end
+ error(errmsg)
end
return discard
end
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 27ebfacc5f..e4da274204 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -2099,9 +2099,9 @@ bool nlua_execute_on_key(int c, char *typed_buf)
int save_got_int = got_int;
got_int = false; // avoid interrupts when the key typed is Ctrl-C
bool discard = false;
- if (nlua_pcall(lstate, 2, 1)) {
- nlua_error(lstate,
- _("Error executing vim.on_key Lua callback: %.*s"));
+ // Do not use nlua_pcall here to avoid duplicate stack trace information
+ if (lua_pcall(lstate, 2, 1, 0)) {
+ nlua_error(lstate, _("Error executing vim.on_key() callbacks: %.*s"));
} else {
if (lua_isboolean(lstate, -1)) {
discard = lua_toboolean(lstate, -1);
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 55ca489a9a..9fd7184cb0 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -3312,10 +3312,17 @@ describe('lua stdlib', function()
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
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]])
exec_lua [[
+ local function ErrF2()
+ error("Dumb Error")
+ end
+ local function ErrF1()
+ ErrF2()
+ end
+
keys = {}
return vim.on_key(function(buf)
@@ -3326,7 +3333,7 @@ describe('lua stdlib', function()
table.insert(keys, buf)
if buf == 'l' then
- error("Dumb Error")
+ ErrF1()
end
end)
]]
@@ -3336,6 +3343,19 @@ describe('lua stdlib', function()
-- Only the first letter gets added. After that we remove the callback
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)
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
exec_lua [[
n_call = 0
+
vim.on_key(function(buf, typed_buf)
if typed_buf == 'x' then
n_call = n_call + 1
@@ -3460,7 +3481,7 @@ describe('lua stdlib', function()
api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
local function cleanup_msg(msg)
- return (remove_trace(msg):gsub('^Error.*\n *Messages: ', ''))
+ return msg:gsub('^Error .*\nWith ns%_id %d+: ', '')
end
feed('x')