diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index aaafa21a59..827d0318ab 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -974,7 +974,7 @@ nvim_get_keymap({mode}) *nvim_get_keymap()* {mode} Mode short-name ("n", "i", "v", ...) Return: ~ - Array of maparg()-like dictionaries describing mappings. + Array of |maparg()|-like dictionaries describing mappings. The "buffer" key is always zero. nvim_get_mark({name}, {opts}) *nvim_get_mark()* @@ -1508,9 +1508,12 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()* used to give a description to the mapping. When called from Lua, also accepts a "callback" key that takes a Lua function to call when the mapping - is executed. "replace_keycodes" can be used with - "expr" to replace keycodes, see - |nvim_replace_termcodes()|. + is executed. When "expr" is true, + "replace_keycodes" (boolean) can be used to + replace keycodes in the resulting string (see + |nvim_replace_termcodes()|), and a Lua callback + returning `nil` is equivalent to returning an + empty string. nvim_set_var({name}, {value}) *nvim_set_var()* Sets a global (g:) variable. @@ -2299,7 +2302,7 @@ nvim_buf_get_keymap({buffer}, {mode}) *nvim_buf_get_keymap()* {buffer} Buffer handle, or 0 for current buffer Return: ~ - Array of maparg()-like dictionaries describing mappings. + Array of |maparg()|-like dictionaries describing mappings. The "buffer" key holds the associated buffer handle. *nvim_buf_get_lines()* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 6dfb0b5791..c9505429c6 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2218,9 +2218,7 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* create mapping on multiple modes. {lhs} (string) Left-hand side |{lhs}| of the mapping. {rhs} string|function Right-hand side |{rhs}| of the - mapping. Can also be a Lua function. If a Lua - function and `opts.expr == true`, returning `nil` - is equivalent to an empty string. + mapping. Can also be a Lua function. {opts} (table) A table of |:map-arguments| such as "silent". In addition to the options listed in |nvim_set_keymap()|, this table also accepts the diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 3592855606..0549f63180 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -31,12 +31,10 @@ local keymap = {} --- vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end) --- --- ----@param mode string|table Same mode short names as |nvim_set_keymap()|. +---@param mode string|table Same mode short names as |nvim_set_keymap()|. --- Can also be list of modes to create mapping on multiple modes. ----@param lhs string Left-hand side |{lhs}| of the mapping. +---@param lhs string Left-hand side |{lhs}| of the mapping. ---@param rhs string|function Right-hand side |{rhs}| of the mapping. Can also be a Lua function. ---- If a Lua function and `opts.expr == true`, returning `nil` is ---- equivalent to an empty string. -- ---@param opts table A table of |:map-arguments| such as "silent". In addition to the options --- listed in |nvim_set_keymap()|, this table also accepts the following keys: diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5e54d0ec9a..1b1a161226 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -932,7 +932,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) /// @param mode Mode short-name ("n", "i", "v", ...) /// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any -/// @returns Array of maparg()-like dictionaries describing mappings. +/// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key holds the associated buffer handle. ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, String mode, Error *err) FUNC_API_SINCE(3) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index dc57841b96..e2f58dba62 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1411,7 +1411,7 @@ Dictionary nvim_get_mode(void) /// Gets a list of global (non-buffer-local) |mapping| definitions. /// /// @param mode Mode short-name ("n", "i", "v", ...) -/// @returns Array of maparg()-like dictionaries describing mappings. +/// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key is always zero. ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode) FUNC_API_SINCE(3) @@ -1423,8 +1423,8 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode) /// /// To set a buffer-local mapping, use |nvim_buf_set_keymap()|. /// -/// Unlike |:map|, leading/trailing whitespace is accepted as part of the {lhs} -/// or {rhs}. Empty {rhs} is ||. |keycodes| are replaced as usual. +/// Unlike |:map|, leading/trailing whitespace is accepted as part of the {lhs} or {rhs}. +/// Empty {rhs} is ||. |keycodes| are replaced as usual. /// /// Example: ///
@@ -1441,14 +1441,15 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
 ///               or "!" for |:map!|, or empty string for |:map|.
 /// @param  lhs   Left-hand-side |{lhs}| of the mapping.
 /// @param  rhs   Right-hand-side |{rhs}| of the mapping.
-/// @param  opts  Optional parameters map: keys are |:map-arguments|, values
-///               are booleans (default false). Accepts all |:map-arguments| as
-///               keys excluding || but including |noremap| and "desc".
-///               Unknown key is an error. "desc" can be used to give a
-///               description to the mapping. When called from Lua, also accepts a
-///               "callback" key that takes a Lua function to call when the
-///               mapping is executed. "replace_keycodes" can be used with "expr"
-///               to replace keycodes, see |nvim_replace_termcodes()|.
+/// @param  opts  Optional parameters map: keys are |:map-arguments|, values are booleans (default
+///               false). Accepts all |:map-arguments| as keys excluding || but including
+///               |noremap| and "desc". Unknown key is an error.
+///               "desc" can be used to give a description to the mapping.
+///               When called from Lua, also accepts a "callback" key that takes a Lua function to
+///               call when the mapping is executed.
+///               When "expr" is true, "replace_keycodes" (boolean) can be used to replace keycodes
+///               in the resulting string (see |nvim_replace_termcodes()|), and a Lua callback
+///               returning `nil` is equivalent to returning an empty string.
 /// @param[out]   err   Error details, if any.
 void nvim_set_keymap(uint64_t channel_id, String mode, String lhs, String rhs, Dict(keymap) *opts,
                      Error *err)
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 41ab236676..520a91491a 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -1537,9 +1537,6 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
 {
   char_u *p = NULL;
   char_u *expr = NULL;
-  pos_T save_cursor;
-  int save_msg_col;
-  int save_msg_row;
 
   // Remove escaping of K_SPECIAL, because "str" is in a format to be used as
   // typeahead.
@@ -1553,9 +1550,9 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
   textlock++;
   ex_normal_lock++;
   set_vim_var_char(c);    // set v:char to the typed character
-  save_cursor = curwin->w_cursor;
-  save_msg_col = msg_col;
-  save_msg_row = msg_row;
+  const pos_T save_cursor = curwin->w_cursor;
+  const int save_msg_col = msg_col;
+  const int save_msg_row = msg_row;
   if (mp->m_luaref != LUA_NOREF) {
     Error err = ERROR_INIT;
     Array args = ARRAY_DICT_INIT;
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 712889828e..eb2a467a8b 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -523,6 +523,11 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
       pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {buffer = true}))
   end)
 
+  it('error when "replace_keycodes" is used without "expr"', function()
+    eq('"replace_keycodes" requires "expr"',
+      pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {replace_keycodes = true}))
+  end)
+
   local optnames = {'nowait', 'silent', 'script', 'expr', 'unique'}
   for _, opt in ipairs(optnames) do
     -- note: need '%' to escape hyphens, which have special meaning in lua
@@ -842,14 +847,14 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
     eq(generate_mapargs('n', 'asdf', nil, {sid=sid_lua}), mapargs)
   end)
 
-  it('can make lua expr mappings', function()
+  it('can make lua expr mappings replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return ':lua SomeValue = 99' 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')
 
-    eq(99, exec_lua[[return SomeValue]])
+    eq({'πfoo<'}, meths.buf_get_lines(0, 0, -1, false))
   end)
 
   it('can make lua expr mappings without replacing keycodes', function()
@@ -862,6 +867,16 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
     eq({''}, meths.buf_get_lines(0, 0, -1, false))
   end)
 
+  it('lua expr mapping returning nil is equivalent to returnig an empty string', function()
+    exec_lua [[
+      vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return nil end, expr = true })
+    ]]
+
+    feed('iaa')
+
+    eq({''}, meths.buf_get_lines(0, 0, -1, false))
+  end)
+
   it('does not reset pum in lua mapping', function()
     eq(0, exec_lua [[
       VisibleCount = 0
@@ -1050,14 +1065,14 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
     eq(1, exec_lua[[return GlobalCount]])
   end)
 
-  it('can make lua expr mappings', function()
+  it('can make lua expr mappings replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return ':lua SomeValue = 99' 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')
 
-    eq(99, exec_lua[[return SomeValue ]])
+    eq({'πfoo<'}, meths.buf_get_lines(0, 0, -1, false))
   end)
 
   it('can make lua expr mappings without replacing keycodes', function()
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 57bb2f9765..2b249b7a69 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -2792,12 +2792,12 @@ describe('vim.keymap', function()
 
   it('can make an expr mapping', function()
     exec_lua [[
-      vim.keymap.set('n', 'aa', function() return ':lua SomeValue = 99' end, {expr = true})
+      vim.keymap.set('n', 'aa', function() return 'πfoo' end, {expr = true})
     ]]
 
     feed('aa')
 
-    eq(99, exec_lua[[return SomeValue]])
+    eq({'πfoo<'}, meths.buf_get_lines(0, 0, -1, false))
   end)
 
   it('can overwrite a mapping', function()