mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 00:18:33 +00:00
feat(api): add support for lua function & description in keymap
Behavioral changes: 1. Added support for lua function in keymaps in -------------------------------------------- - nvim_set_keymap Can set lua function as keymap rhs like following: ```lua vim.api.nvim_{buf_}set_keymap('n', '<leader>lr', '', {callback = vim.lsp.buf.references}) ``` Note: lua function can only be set from lua . If api function being called from viml or over rpc this option isn't available. - nvim_{buf_}get_keymap When called from lua, lua function is returned is `callback` key . But in other cases callback contains number of the function ref. - :umap, nvim_del_keymap & nvim_buf_del_keymap clears lua keymaps correctly. - :map commands for displaing rhs . For lua keymaps rhs is displayed as <Lua function ref_no> Note: lua keymap cannot be set through viml command / functions. - mapargs() When dict is false it returns string in `<Lua function ref_no>` format (same format as :map commands). When dict is true it returns ref_no number in `callback` key. - mapcheck() returns string in `<Lua function ref_no>` format (same format as :map commands). 2. Added support for keymap description --------------------------------------- - nvim_{buf_}set_keymap: added `desc` option in opts table . ```lua vim.api.nvim_set_keymap('n', '<leader>w', '<cmd>w<cr>', {desc='Save current file'}) ``` - nvim_{buf_}get_keymap: contains `desc` in returned list. - commands like `:nmap <leader>w` will show description in a new line below rhs. - `maparg()` return dict contains `desc`.
This commit is contained in:
@@ -835,7 +835,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
|
||||
/// @param[out] err Error details, if any
|
||||
/// @returns Array of maparg()-like dictionaries describing mappings.
|
||||
/// The "buffer" key holds the associated buffer handle.
|
||||
ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
|
||||
ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, String mode, Error *err)
|
||||
FUNC_API_SINCE(3)
|
||||
{
|
||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||
@@ -844,7 +844,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
|
||||
return (Array)ARRAY_DICT_INIT;
|
||||
}
|
||||
|
||||
return keymap_array(mode, buf);
|
||||
return keymap_array(mode, buf, channel_id == LUA_INTERNAL_CALL);
|
||||
}
|
||||
|
||||
/// Sets a buffer-local |mapping| for the given mode.
|
||||
|
@@ -29,6 +29,8 @@ return {
|
||||
"script";
|
||||
"expr";
|
||||
"unique";
|
||||
"callback";
|
||||
"desc";
|
||||
};
|
||||
get_commands = {
|
||||
"builtin";
|
||||
|
@@ -594,6 +594,7 @@ Array string_to_array(const String input, bool crlf)
|
||||
void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs,
|
||||
Dict(keymap) *opts, Error *err)
|
||||
{
|
||||
LuaRef lua_funcref = LUA_NOREF;
|
||||
bool global = (buffer == -1);
|
||||
if (global) {
|
||||
buffer = 0;
|
||||
@@ -604,6 +605,9 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts != NULL && opts->callback.type == kObjectTypeLuaRef) {
|
||||
lua_funcref = api_new_luaref(opts->callback.data.luaref);
|
||||
}
|
||||
MapArguments parsed_args = MAP_ARGUMENTS_INIT;
|
||||
if (opts) {
|
||||
#define KEY_TO_BOOL(name) \
|
||||
@@ -623,9 +627,13 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
||||
parsed_args.buffer = !global;
|
||||
|
||||
set_maparg_lhs_rhs((char_u *)lhs.data, lhs.size,
|
||||
(char_u *)rhs.data, rhs.size,
|
||||
(char_u *)rhs.data, rhs.size, lua_funcref,
|
||||
CPO_TO_CPO_FLAGS, &parsed_args);
|
||||
|
||||
if (opts != NULL && opts->desc.type == kObjectTypeString) {
|
||||
parsed_args.desc = xstrdup(opts->desc.data.string.data);
|
||||
} else {
|
||||
parsed_args.desc = NULL;
|
||||
}
|
||||
if (parsed_args.lhs_len > MAXMAPLEN) {
|
||||
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
|
||||
goto fail_and_free;
|
||||
@@ -658,7 +666,8 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
||||
bool is_noremap = parsed_args.noremap;
|
||||
assert(!(is_unmap && is_noremap));
|
||||
|
||||
if (!is_unmap && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) {
|
||||
if (!is_unmap && lua_funcref == LUA_NOREF
|
||||
&& (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) {
|
||||
if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop>
|
||||
parsed_args.rhs_is_noop = true;
|
||||
} else {
|
||||
@@ -668,9 +677,13 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
||||
api_set_error(err, kErrorTypeValidation, "Parsing of nonempty RHS failed: %s", rhs.data);
|
||||
goto fail_and_free;
|
||||
}
|
||||
} else if (is_unmap && parsed_args.rhs_len) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
|
||||
} else if (is_unmap && (parsed_args.rhs_len || parsed_args.rhs_lua != LUA_NOREF)) {
|
||||
if (parsed_args.rhs_len) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "Gave nonempty RHS for unmap");
|
||||
}
|
||||
goto fail_and_free;
|
||||
}
|
||||
|
||||
@@ -700,9 +713,12 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
||||
goto fail_and_free;
|
||||
} // switch
|
||||
|
||||
parsed_args.rhs_lua = LUA_NOREF; // don't clear ref on success
|
||||
fail_and_free:
|
||||
NLUA_CLEAR_REF(parsed_args.rhs_lua);
|
||||
xfree(parsed_args.rhs);
|
||||
xfree(parsed_args.orig_rhs);
|
||||
XFREE_CLEAR(parsed_args.desc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1052,8 +1068,9 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
|
||||
///
|
||||
/// @param mode The abbreviation for the mode
|
||||
/// @param buf The buffer to get the mapping array. NULL for global
|
||||
/// @param from_lua Whether it is called from internal lua api.
|
||||
/// @returns Array of maparg()-like dictionaries describing mappings
|
||||
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
||||
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
|
||||
{
|
||||
Array mappings = ARRAY_DICT_INIT;
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
@@ -1073,8 +1090,19 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
||||
// Check for correct mode
|
||||
if (int_mode & current_maphash->m_mode) {
|
||||
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
|
||||
ADD(mappings, vim_to_object((typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } }));
|
||||
|
||||
Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT,
|
||||
.vval.v_dict = dict } });
|
||||
if (from_lua) {
|
||||
Dictionary d = api_dict.data.dictionary;
|
||||
for (size_t j = 0; j < d.size; j++) {
|
||||
if (strequal("callback", d.items[j].key.data)) {
|
||||
d.items[j].value.type = kObjectTypeLuaRef;
|
||||
d.items[j].value.data.luaref = api_new_luaref((LuaRef)d.items[j].value.data.integer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ADD(mappings, api_dict);
|
||||
tv_dict_clear(dict);
|
||||
}
|
||||
}
|
||||
|
@@ -1538,10 +1538,10 @@ Dictionary nvim_get_mode(void)
|
||||
/// @param mode Mode short-name ("n", "i", "v", ...)
|
||||
/// @returns Array of maparg()-like dictionaries describing mappings.
|
||||
/// The "buffer" key is always zero.
|
||||
ArrayOf(Dictionary) nvim_get_keymap(String mode)
|
||||
ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
|
||||
FUNC_API_SINCE(3)
|
||||
{
|
||||
return keymap_array(mode, NULL);
|
||||
return keymap_array(mode, NULL, channel_id == LUA_INTERNAL_CALL);
|
||||
}
|
||||
|
||||
/// Sets a global |mapping| for the given mode.
|
||||
@@ -1566,7 +1566,10 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
|
||||
/// @param lhs Left-hand-side |{lhs}| of the mapping.
|
||||
/// @param rhs Right-hand-side |{rhs}| of the mapping.
|
||||
/// @param opts Optional parameters map. Accepts all |:map-arguments|
|
||||
/// as keys excluding |<buffer>| but including |noremap|.
|
||||
/// as keys excluding |<buffer>| but including |noremap| and "desc".
|
||||
/// |desc| can be used to give a description to keymap.
|
||||
/// When called from Lua, also accepts a "callback" key that takes
|
||||
/// a Lua function to call when the mapping is executed.
|
||||
/// Values are Booleans. Unknown key is an error.
|
||||
/// @param[out] err Error details, if any.
|
||||
void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err)
|
||||
|
Reference in New Issue
Block a user