diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-10-12 08:07:05 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-12 08:07:05 +0800 |
commit | 0e42c81c7fd429529d89458349c7cdde254d5406 (patch) | |
tree | 4504e1e7382f27d80aaf5914d61c3bdf729ee456 | |
parent | c49030b75ad8b8a9f8e7f023b0ee5f9c8c40afdd (diff) | |
download | rneovim-0e42c81c7fd429529d89458349c7cdde254d5406.tar.gz rneovim-0e42c81c7fd429529d89458349c7cdde254d5406.tar.bz2 rneovim-0e42c81c7fd429529d89458349c7cdde254d5406.zip |
fix(lua): avoid recursive vim.on_key() callback (#30753)
-rw-r--r-- | runtime/doc/lua.txt | 2 | ||||
-rw-r--r-- | runtime/doc/news.txt | 3 | ||||
-rw-r--r-- | runtime/lua/vim/_editor.lua | 2 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 9 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 39 |
5 files changed, 55 insertions, 0 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 3e8d8bb62c..4acf8dc0af 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1678,6 +1678,8 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()* Note: ~ • {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()| Parameters: ~ diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 1b311330b0..6af136bb5a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -262,6 +262,9 @@ These existing features changed their behavior. more emoji characters than before, including those encoded with multiple 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* diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 2e829578a7..17a87dd9fd 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -658,6 +658,8 @@ local on_key_cbs = {} --- @type table<integer,function> --- and cannot be toggled dynamically. --- ---@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()| --- ---@param fn fun(key: string, typed: string)? diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d4940f3add..9392765f40 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -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) { + static bool recursive = false; + + if (recursive) { + return; + } + recursive = true; + char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, 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)); #endif + + recursive = false; } // Sets the editor "script context" during Lua execution. Used by :verbose. diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3c65ec664e..793cf7cfd7 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3223,6 +3223,45 @@ describe('lua stdlib', function() feed('<C-C>') eq('/', exec_lua([[return _G.ctrl_c_cmdtype]])) 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) describe('vim.wait', function() |