mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +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. | ||||
| ---@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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 zeertzjq
					zeertzjq