neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 0e42c81c7fd429529d89458349c7cdde254d5406
parent c49030b75ad8b8a9f8e7f023b0ee5f9c8c40afdd
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Sat, 12 Oct 2024 08:07:05 +0800

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


Diffstat:
Mruntime/doc/lua.txt | 2++
Mruntime/doc/news.txt | 3+++
Mruntime/lua/vim/_editor.lua | 2++
Msrc/nvim/lua/executor.c | 9+++++++++
Mtest/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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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()