fix(lua): avoid recursive vim.on_key() callback (#30753)

This commit is contained in:
zeertzjq 2024-10-12 08:07:05 +08:00 committed by GitHub
parent c49030b75a
commit 0e42c81c7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 0 deletions

View File

@ -1678,6 +1678,8 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
Note: ~ Note: ~
• {fn} will be removed on error. • {fn} will be removed on error.
• {fn} won't be invoked recursively, i.e. if {fn} itself consumes input,
it won't be invoked for those keys.
• {fn} will not be cleared by |nvim_buf_clear_namespace()| • {fn} will not be cleared by |nvim_buf_clear_namespace()|
Parameters: ~ Parameters: ~

View File

@ -262,6 +262,9 @@ These existing features changed their behavior.
more emoji characters than before, including those encoded with multiple more emoji characters than before, including those encoded with multiple
emoji codepoints combined with ZWJ (zero width joiner) codepoints. emoji codepoints combined with ZWJ (zero width joiner) codepoints.
• |vim.on_key()| callbacks won't be invoked recursively when a callback itself
consumes input.
============================================================================== ==============================================================================
REMOVED FEATURES *news-removed* REMOVED FEATURES *news-removed*

View File

@ -658,6 +658,8 @@ local on_key_cbs = {} --- @type table<integer,function>
--- and cannot be toggled dynamically. --- and cannot be toggled dynamically.
--- ---
---@note {fn} will be removed on error. ---@note {fn} will be removed on error.
---@note {fn} won't be invoked recursively, i.e. if {fn} itself consumes input,
--- it won't be invoked for those keys.
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()| ---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
--- ---
---@param fn fun(key: string, typed: string)? ---@param fn fun(key: string, typed: string)?

View File

@ -2065,6 +2065,13 @@ char *nlua_register_table_as_callable(const typval_T *const arg)
void nlua_execute_on_key(int c, char *typed_buf) void nlua_execute_on_key(int c, char *typed_buf)
{ {
static bool recursive = false;
if (recursive) {
return;
}
recursive = true;
char buf[MB_MAXBYTES * 3 + 4]; char buf[MB_MAXBYTES * 3 + 4];
size_t buf_len = special_to_buf(c, mod_mask, false, buf); size_t buf_len = special_to_buf(c, mod_mask, false, buf);
vim_unescape_ks(typed_buf); vim_unescape_ks(typed_buf);
@ -2103,6 +2110,8 @@ void nlua_execute_on_key(int c, char *typed_buf)
// [ ] // [ ]
assert(top == lua_gettop(lstate)); assert(top == lua_gettop(lstate));
#endif #endif
recursive = false;
} }
// Sets the editor "script context" during Lua execution. Used by :verbose. // Sets the editor "script context" during Lua execution. Used by :verbose.

View File

@ -3223,6 +3223,45 @@ describe('lua stdlib', function()
feed('<C-C>') feed('<C-C>')
eq('/', exec_lua([[return _G.ctrl_c_cmdtype]])) eq('/', exec_lua([[return _G.ctrl_c_cmdtype]]))
end) end)
it('callback is not invoked recursively #30752', function()
local screen = Screen.new(60, 10)
screen:attach()
exec_lua([[
vim.on_key(function(key, typed)
vim.api.nvim_echo({
{ 'key_cb\n' },
{ ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) },
}, false, {})
end)
]])
feed('^')
screen:expect([[
|
{1:~ }|*5
{3: }|
key_cb |
KEYCB: key '^', typed '^' |
{6:Press ENTER or type command to continue}^ |
]])
feed('<C-C>')
screen:expect([[
|
{1:~ }|*3
{3: }|
key_cb |
KEYCB: key '^', typed '^' |
key_cb |
KEYCB: key '{18:^C}', typed '{18:^C}' |
{6:Press ENTER or type command to continue}^ |
]])
feed('<C-C>')
screen:expect([[
^ |
{1:~ }|*8
|
]])
end)
end) end)
describe('vim.wait', function() describe('vim.wait', function()