diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 9e4457f793..21e8cb625c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -881,7 +881,7 @@ static int insert_handle_key(InsertState *s) goto check_pum; case K_LUA: - map_execute_lua(); + map_execute_lua(false); check_pum: // nvim_select_popupmenu_item() can be called from the handling of diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a8ac6ab439..7cbe05dbc7 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1137,7 +1137,7 @@ static int command_line_execute(VimState *state, int key) } else if (s->c == K_COMMAND) { do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); } else { - map_execute_lua(); + map_execute_lua(false); } // nvim_select_popupmenu_item() can be called from the handling of diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 69a371ccf9..c8a39d93a0 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2958,7 +2958,12 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat) return line_ga.ga_data; } -bool map_execute_lua(void) +/// Handle a Lua mapping: get its LuaRef from typeahead and execute it. +/// +/// @param may_repeat save the LuaRef for redoing with "." later +/// +/// @return false if getting the LuaRef was aborted, true otherwise +bool map_execute_lua(bool may_repeat) { garray_T line_ga; int c1 = -1; @@ -2990,6 +2995,10 @@ bool map_execute_lua(void) } LuaRef ref = (LuaRef)atoi(line_ga.ga_data); + if (may_repeat) { + repeat_luaref = ref; + } + Error err = ERROR_INIT; Array args = ARRAY_DICT_INIT; nlua_call_ref(ref, NULL, args, false, &err); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c3a7fc7a0e..57ec041911 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3232,7 +3232,7 @@ static void nv_colon(cmdarg_T *cap) } if (is_lua) { - cmd_result = map_execute_lua(); + cmd_result = map_execute_lua(true); } else { // get a command line and execute it cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 9aacfcad30..e3cbe96817 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5774,6 +5774,11 @@ typedef struct { int rv_arg; ///< extra argument } redo_VIsual_T; +static bool is_ex_cmdchar(cmdarg_T *cap) +{ + return cap->cmdchar == ':' || cap->cmdchar == K_COMMAND; +} + /// Handle an operator after Visual mode or when the movement is finished. /// "gui_yank" is true when yanking text for the clipboard. void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) @@ -5828,7 +5833,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if ((redo_yank || oap->op_type != OP_YANK) && ((!VIsual_active || oap->motion_force) // Also redo Operator-pending Visual mode mappings. - || ((cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) + || ((is_ex_cmdchar(cap) || cap->cmdchar == K_LUA) && oap->op_type != OP_COLON)) && cap->cmdchar != 'D' && oap->op_type != OP_FOLD @@ -5848,7 +5853,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) AppendToRedobuffLit(cap->searchbuf, -1); } AppendToRedobuff(NL_STR); - } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) { + } else if (is_ex_cmdchar(cap)) { // do_cmdline() has stored the first typed line in // "repeat_cmdline". When several lines are typed repeating // won't be possible. @@ -5859,6 +5864,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) AppendToRedobuff(NL_STR); XFREE_CLEAR(repeat_cmdline); } + } else if (cap->cmdchar == K_LUA) { + AppendNumberToRedobuff(repeat_luaref); + AppendToRedobuff(NL_STR); } } @@ -6014,7 +6022,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) prep_redo(oap->regname, cap->count0, get_op_char(oap->op_type), get_extra_op_char(oap->op_type), oap->motion_force, cap->cmdchar, cap->nchar); - } else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND) { + } else if (!is_ex_cmdchar(cap) && cap->cmdchar != K_LUA) { int opchar = get_op_char(oap->op_type); int extra_opchar = get_extra_op_char(oap->op_type); int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL; diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 75ea1853a0..4c5c6bafce 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -4,6 +4,7 @@ #include #include +#include "lauxlib.h" #include "nvim/ascii.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -126,4 +127,7 @@ static inline int op_reg_index(const int regname) #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ops.h.generated.h" #endif + +EXTERN LuaRef repeat_luaref INIT(= LUA_NOREF); ///< LuaRef for "." + #endif // NVIM_OPS_H diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index c774dbe384..93737da40d 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -596,7 +596,7 @@ static int terminal_execute(VimState *state, int key) break; case K_LUA: - map_execute_lua(); + map_execute_lua(false); break; case Ctrl_N: diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index f2817ff627..e239717d3a 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -813,19 +813,18 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can make lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]]) feed('asdf\n') eq(1, exec_lua[[return GlobalCount]]) - end) it (':map command shows lua mapping correctly', function() exec_lua [[ - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] assert.truthy( string.match( @@ -837,7 +836,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it ('mapcheck() returns lua mapping correctly', function() exec_lua [[ - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] assert.truthy(string.match(funcs.mapcheck('asdf', 'n'), "^")) @@ -871,7 +870,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can make lua expr mappings replacing keycodes', function() exec_lua [[ - vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) + vim.api.nvim_set_keymap('n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) ]] feed('aa') @@ -881,7 +880,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can make lua expr mappings without replacing keycodes', function() exec_lua [[ - vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return '' end, expr = true }) + vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return '' end, expr = true }) ]] feed('iaa') @@ -891,7 +890,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('lua expr mapping returning nil is equivalent to returning an empty string', function() exec_lua [[ - vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return nil end, expr = true }) + vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return nil end, expr = true }) ]] feed('iaa') @@ -902,17 +901,29 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('does not reset pum in lua mapping', function() eq(0, exec_lua [[ VisibleCount = 0 - vim.api.nvim_set_keymap ('i', '', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end}) + vim.api.nvim_set_keymap('i', '', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end}) return VisibleCount ]]) feed('i') eq(2, exec_lua[[return VisibleCount]]) end) + it('redo of lua mappings in op-pending mode work', function() + eq(0, exec_lua [[ + OpCount = 0 + vim.api.nvim_set_keymap('o', '', '', {callback = function() OpCount = OpCount + 1 end}) + return OpCount + ]]) + feed('d') + eq(1, exec_lua[[return OpCount]]) + feed('.') + eq(2, exec_lua[[return OpCount]]) + end) + it('can overwrite lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]]) @@ -921,7 +932,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() eq(1, exec_lua[[return GlobalCount]]) exec_lua [[ - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) ]] feed('asdf\n') @@ -932,7 +943,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can unmap lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]]) @@ -1078,7 +1089,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can make lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]]) @@ -1089,7 +1100,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can make lua expr mappings replacing keycodes', function() exec_lua [[ - vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) + vim.api.nvim_buf_set_keymap(0, 'n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) ]] feed('aa') @@ -1099,7 +1110,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can make lua expr mappings without replacing keycodes', function() exec_lua [[ - vim.api.nvim_buf_set_keymap (0, 'i', 'aa', '', {callback = function() return '' end, expr = true }) + vim.api.nvim_buf_set_keymap(0, 'i', 'aa', '', {callback = function() return '' end, expr = true }) ]] feed('iaa') @@ -1111,7 +1122,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can overwrite lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]]) @@ -1120,7 +1131,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() eq(1, exec_lua[[return GlobalCount]]) exec_lua [[ - vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) ]] feed('asdf\n') @@ -1131,7 +1142,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can unmap lua mappings', function() eq(0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) return GlobalCount ]])