mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #16594 from shadmansaleh/feat/api/lua_keymaps
feat(api): add support for lua function & description in keymap
This commit is contained in:
commit
b218d02c44
@ -1580,8 +1580,11 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
|
|||||||
{rhs} Right-hand-side |{rhs}| of the mapping.
|
{rhs} Right-hand-side |{rhs}| of the mapping.
|
||||||
{opts} Optional parameters map. Accepts all
|
{opts} Optional parameters map. Accepts all
|
||||||
|:map-arguments| as keys excluding |<buffer>| but
|
|:map-arguments| as keys excluding |<buffer>| but
|
||||||
including |noremap|. Values are Booleans. Unknown
|
including |noremap| and "desc". |desc| can be used
|
||||||
key is an error.
|
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.
|
||||||
|
|
||||||
nvim_set_option({name}, {value}) *nvim_set_option()*
|
nvim_set_option({name}, {value}) *nvim_set_option()*
|
||||||
Sets the global value of an option.
|
Sets the global value of an option.
|
||||||
|
@ -835,7 +835,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
|
|||||||
/// @param[out] err Error details, if any
|
/// @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.
|
/// 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)
|
FUNC_API_SINCE(3)
|
||||||
{
|
{
|
||||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
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 (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.
|
/// Sets a buffer-local |mapping| for the given mode.
|
||||||
|
@ -29,6 +29,8 @@ return {
|
|||||||
"script";
|
"script";
|
||||||
"expr";
|
"expr";
|
||||||
"unique";
|
"unique";
|
||||||
|
"callback";
|
||||||
|
"desc";
|
||||||
};
|
};
|
||||||
get_commands = {
|
get_commands = {
|
||||||
"builtin";
|
"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,
|
void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs,
|
||||||
Dict(keymap) *opts, Error *err)
|
Dict(keymap) *opts, Error *err)
|
||||||
{
|
{
|
||||||
|
LuaRef lua_funcref = LUA_NOREF;
|
||||||
bool global = (buffer == -1);
|
bool global = (buffer == -1);
|
||||||
if (global) {
|
if (global) {
|
||||||
buffer = 0;
|
buffer = 0;
|
||||||
@ -604,6 +605,9 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts != NULL && opts->callback.type == kObjectTypeLuaRef) {
|
||||||
|
lua_funcref = api_new_luaref(opts->callback.data.luaref);
|
||||||
|
}
|
||||||
MapArguments parsed_args = MAP_ARGUMENTS_INIT;
|
MapArguments parsed_args = MAP_ARGUMENTS_INIT;
|
||||||
if (opts) {
|
if (opts) {
|
||||||
#define KEY_TO_BOOL(name) \
|
#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;
|
parsed_args.buffer = !global;
|
||||||
|
|
||||||
set_maparg_lhs_rhs((char_u *)lhs.data, lhs.size,
|
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);
|
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) {
|
if (parsed_args.lhs_len > MAXMAPLEN) {
|
||||||
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
|
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
|
||||||
goto fail_and_free;
|
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;
|
bool is_noremap = parsed_args.noremap;
|
||||||
assert(!(is_unmap && is_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>
|
if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop>
|
||||||
parsed_args.rhs_is_noop = true;
|
parsed_args.rhs_is_noop = true;
|
||||||
} else {
|
} 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);
|
api_set_error(err, kErrorTypeValidation, "Parsing of nonempty RHS failed: %s", rhs.data);
|
||||||
goto fail_and_free;
|
goto fail_and_free;
|
||||||
}
|
}
|
||||||
} else if (is_unmap && parsed_args.rhs_len) {
|
} else if (is_unmap && (parsed_args.rhs_len || parsed_args.rhs_lua != LUA_NOREF)) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
if (parsed_args.rhs_len) {
|
||||||
"Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
|
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;
|
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;
|
goto fail_and_free;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
|
parsed_args.rhs_lua = LUA_NOREF; // don't clear ref on success
|
||||||
fail_and_free:
|
fail_and_free:
|
||||||
|
NLUA_CLEAR_REF(parsed_args.rhs_lua);
|
||||||
xfree(parsed_args.rhs);
|
xfree(parsed_args.rhs);
|
||||||
xfree(parsed_args.orig_rhs);
|
xfree(parsed_args.orig_rhs);
|
||||||
|
XFREE_CLEAR(parsed_args.desc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1052,8 +1068,9 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
|
|||||||
///
|
///
|
||||||
/// @param mode The abbreviation for the mode
|
/// @param mode The abbreviation for the mode
|
||||||
/// @param buf The buffer to get the mapping array. NULL for global
|
/// @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
|
/// @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;
|
Array mappings = ARRAY_DICT_INIT;
|
||||||
dict_T *const dict = tv_dict_alloc();
|
dict_T *const dict = tv_dict_alloc();
|
||||||
@ -1073,8 +1090,19 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
|||||||
// Check for correct mode
|
// Check for correct mode
|
||||||
if (int_mode & current_maphash->m_mode) {
|
if (int_mode & current_maphash->m_mode) {
|
||||||
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
|
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);
|
tv_dict_clear(dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1538,10 +1538,10 @@ Dictionary nvim_get_mode(void)
|
|||||||
/// @param mode Mode short-name ("n", "i", "v", ...)
|
/// @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.
|
/// 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)
|
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.
|
/// 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 lhs Left-hand-side |{lhs}| of the mapping.
|
||||||
/// @param rhs Right-hand-side |{rhs}| of the mapping.
|
/// @param rhs Right-hand-side |{rhs}| of the mapping.
|
||||||
/// @param opts Optional parameters map. Accepts all |:map-arguments|
|
/// @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.
|
/// Values are Booleans. Unknown key is an error.
|
||||||
/// @param[out] err Error details, if any.
|
/// @param[out] err Error details, if any.
|
||||||
void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err)
|
void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err)
|
||||||
|
@ -352,6 +352,7 @@ struct mapblock {
|
|||||||
char_u *m_keys; // mapped from, lhs
|
char_u *m_keys; // mapped from, lhs
|
||||||
char_u *m_str; // mapped to, rhs
|
char_u *m_str; // mapped to, rhs
|
||||||
char_u *m_orig_str; // rhs as entered by the user
|
char_u *m_orig_str; // rhs as entered by the user
|
||||||
|
LuaRef m_luaref; // lua function reference as rhs
|
||||||
int m_keylen; // strlen(m_keys)
|
int m_keylen; // strlen(m_keys)
|
||||||
int m_mode; // valid mode
|
int m_mode; // valid mode
|
||||||
int m_noremap; // if non-zero no re-mapping for m_str
|
int m_noremap; // if non-zero no re-mapping for m_str
|
||||||
@ -359,6 +360,7 @@ struct mapblock {
|
|||||||
char m_nowait; // <nowait> used
|
char m_nowait; // <nowait> used
|
||||||
char m_expr; // <expr> used, m_str is an expression
|
char m_expr; // <expr> used, m_str is an expression
|
||||||
sctx_T m_script_ctx; // SCTX where map was defined
|
sctx_T m_script_ctx; // SCTX where map was defined
|
||||||
|
char *m_desc; // description of keymap
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Used for highlighting in the status line.
|
/// Used for highlighting in the status line.
|
||||||
|
@ -1076,6 +1076,10 @@ static int insert_handle_key(InsertState *s)
|
|||||||
|
|
||||||
case K_COMMAND: // some command
|
case K_COMMAND: // some command
|
||||||
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
|
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
|
||||||
|
goto check_pum;
|
||||||
|
|
||||||
|
case K_LUA:
|
||||||
|
map_execute_lua();
|
||||||
|
|
||||||
check_pum:
|
check_pum:
|
||||||
// TODO(bfredl): Not entirely sure this indirection is necessary
|
// TODO(bfredl): Not entirely sure this indirection is necessary
|
||||||
|
@ -7299,12 +7299,19 @@ void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buf
|
|||||||
noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
|
noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compatible) {
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
|
tv_dict_add_nr(dict, S_LEN("callback"), mp->m_luaref);
|
||||||
} else {
|
} else {
|
||||||
tv_dict_add_allocated_str(dict, S_LEN("rhs"),
|
if (compatible) {
|
||||||
str2special_save((const char *)mp->m_str, false,
|
tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
|
||||||
true));
|
} else {
|
||||||
|
tv_dict_add_allocated_str(dict, S_LEN("rhs"),
|
||||||
|
str2special_save((const char *)mp->m_str, false,
|
||||||
|
true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mp->m_desc != NULL) {
|
||||||
|
tv_dict_add_allocated_str(dict, S_LEN("desc"), xstrdup(mp->m_desc));
|
||||||
}
|
}
|
||||||
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
|
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
|
||||||
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
|
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
|
||||||
|
@ -5980,6 +5980,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
|
|||||||
{
|
{
|
||||||
char_u *keys_buf = NULL;
|
char_u *keys_buf = NULL;
|
||||||
char_u *rhs;
|
char_u *rhs;
|
||||||
|
LuaRef rhs_lua;
|
||||||
int mode;
|
int mode;
|
||||||
int abbr = FALSE;
|
int abbr = FALSE;
|
||||||
int get_dict = FALSE;
|
int get_dict = FALSE;
|
||||||
@ -6016,7 +6017,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
|
|||||||
|
|
||||||
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
|
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
|
||||||
CPO_TO_CPO_FLAGS);
|
CPO_TO_CPO_FLAGS);
|
||||||
rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local);
|
rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
|
||||||
xfree(keys_buf);
|
xfree(keys_buf);
|
||||||
|
|
||||||
if (!get_dict) {
|
if (!get_dict) {
|
||||||
@ -6027,10 +6028,15 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
|
|||||||
} else {
|
} else {
|
||||||
rettv->vval.v_string = (char_u *)str2special_save((char *)rhs, false, false);
|
rettv->vval.v_string = (char_u *)str2special_save((char *)rhs, false, false);
|
||||||
}
|
}
|
||||||
|
} else if (rhs_lua != LUA_NOREF) {
|
||||||
|
size_t msglen = 100;
|
||||||
|
char *msg = (char *)xmalloc(msglen);
|
||||||
|
snprintf(msg, msglen, "<Lua function %d>", mp->m_luaref);
|
||||||
|
rettv->vval.v_string = (char_u *)msg;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tv_dict_alloc_ret(rettv);
|
tv_dict_alloc_ret(rettv);
|
||||||
if (rhs != NULL) {
|
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
|
||||||
// Return a dictionary.
|
// Return a dictionary.
|
||||||
mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
|
mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
|
||||||
}
|
}
|
||||||
|
@ -1024,11 +1024,13 @@ static int command_line_execute(VimState *state, int key)
|
|||||||
CommandLineState *s = (CommandLineState *)state;
|
CommandLineState *s = (CommandLineState *)state;
|
||||||
s->c = key;
|
s->c = key;
|
||||||
|
|
||||||
if (s->c == K_EVENT || s->c == K_COMMAND) {
|
if (s->c == K_EVENT || s->c == K_COMMAND || s->c == K_LUA) {
|
||||||
if (s->c == K_EVENT) {
|
if (s->c == K_EVENT) {
|
||||||
state_handle_k_event();
|
state_handle_k_event();
|
||||||
} else {
|
} else if (s->c == K_COMMAND) {
|
||||||
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
|
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
|
||||||
|
} else {
|
||||||
|
map_execute_lua();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmdline_was_last_drawn) {
|
if (!cmdline_was_last_drawn) {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "nvim/api/private/helpers.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
#include "nvim/assert.h"
|
#include "nvim/assert.h"
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
@ -1902,7 +1903,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
|
|||||||
|
|
||||||
// complete match
|
// complete match
|
||||||
if (keylen >= 0 && keylen <= typebuf.tb_len) {
|
if (keylen >= 0 && keylen <= typebuf.tb_len) {
|
||||||
char_u *map_str;
|
char_u *map_str = NULL;
|
||||||
int save_m_expr;
|
int save_m_expr;
|
||||||
int save_m_noremap;
|
int save_m_noremap;
|
||||||
int save_m_silent;
|
int save_m_silent;
|
||||||
@ -1947,6 +1948,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
|
|||||||
save_m_silent = mp->m_silent;
|
save_m_silent = mp->m_silent;
|
||||||
char_u *save_m_keys = NULL; // only saved when needed
|
char_u *save_m_keys = NULL; // only saved when needed
|
||||||
char_u *save_m_str = NULL; // only saved when needed
|
char_u *save_m_str = NULL; // only saved when needed
|
||||||
|
LuaRef save_m_luaref = mp->m_luaref;
|
||||||
|
|
||||||
// Handle ":map <expr>": evaluate the {rhs} as an
|
// Handle ":map <expr>": evaluate the {rhs} as an
|
||||||
// expression. Also save and restore the command line
|
// expression. Also save and restore the command line
|
||||||
@ -1959,8 +1961,10 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
|
|||||||
may_garbage_collect = false;
|
may_garbage_collect = false;
|
||||||
|
|
||||||
save_m_keys = vim_strsave(mp->m_keys);
|
save_m_keys = vim_strsave(mp->m_keys);
|
||||||
save_m_str = vim_strsave(mp->m_str);
|
if (save_m_luaref == LUA_NOREF) {
|
||||||
map_str = eval_map_expr(save_m_str, NUL);
|
save_m_str = vim_strsave(mp->m_str);
|
||||||
|
}
|
||||||
|
map_str = eval_map_expr(mp, NUL);
|
||||||
vgetc_busy = save_vgetc_busy;
|
vgetc_busy = save_vgetc_busy;
|
||||||
may_garbage_collect = save_may_garbage_collect;
|
may_garbage_collect = save_may_garbage_collect;
|
||||||
} else {
|
} else {
|
||||||
@ -2618,11 +2622,13 @@ int fix_input_buffer(char_u *buf, int len)
|
|||||||
/// @param[in] orig_lhs Original mapping LHS, with characters to replace.
|
/// @param[in] orig_lhs Original mapping LHS, with characters to replace.
|
||||||
/// @param[in] orig_lhs_len `strlen` of orig_lhs.
|
/// @param[in] orig_lhs_len `strlen` of orig_lhs.
|
||||||
/// @param[in] orig_rhs Original mapping RHS, with characters to replace.
|
/// @param[in] orig_rhs Original mapping RHS, with characters to replace.
|
||||||
|
/// @param[in] rhs_lua Lua reference for Lua maps.
|
||||||
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
|
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
|
||||||
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
|
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
|
||||||
/// @param[out] mapargs MapArguments struct holding the replaced strings.
|
/// @param[out] mapargs MapArguments struct holding the replaced strings.
|
||||||
void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const char_u *orig_rhs,
|
void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len,
|
||||||
const size_t orig_rhs_len, int cpo_flags, MapArguments *mapargs)
|
const char_u *orig_rhs, const size_t orig_rhs_len,
|
||||||
|
LuaRef rhs_lua, int cpo_flags, MapArguments *mapargs)
|
||||||
{
|
{
|
||||||
char_u *lhs_buf = NULL;
|
char_u *lhs_buf = NULL;
|
||||||
char_u *rhs_buf = NULL;
|
char_u *rhs_buf = NULL;
|
||||||
@ -2638,22 +2644,34 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const
|
|||||||
true, true, true, cpo_flags);
|
true, true, true, cpo_flags);
|
||||||
mapargs->lhs_len = STRLEN(replaced);
|
mapargs->lhs_len = STRLEN(replaced);
|
||||||
STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
|
STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
|
||||||
|
mapargs->rhs_lua = rhs_lua;
|
||||||
|
|
||||||
mapargs->orig_rhs_len = orig_rhs_len;
|
if (rhs_lua == LUA_NOREF) {
|
||||||
mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u));
|
mapargs->orig_rhs_len = orig_rhs_len;
|
||||||
STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
|
mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u));
|
||||||
|
STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
|
||||||
|
|
||||||
if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
|
if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
|
||||||
mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
|
mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
|
||||||
mapargs->rhs_len = 0;
|
mapargs->rhs_len = 0;
|
||||||
mapargs->rhs_is_noop = true;
|
mapargs->rhs_is_noop = true;
|
||||||
|
} else {
|
||||||
|
replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf,
|
||||||
|
false, true, true, cpo_flags);
|
||||||
|
mapargs->rhs_len = STRLEN(replaced);
|
||||||
|
mapargs->rhs_is_noop = false;
|
||||||
|
mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
|
||||||
|
STRLCPY(mapargs->rhs, replaced, mapargs->rhs_len + 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf,
|
char tmp_buf[64];
|
||||||
false, true, true, cpo_flags);
|
// stores <lua>ref_no<cr> in map_str
|
||||||
mapargs->rhs_len = STRLEN(replaced);
|
mapargs->orig_rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "<LUA>%d<CR>", rhs_lua);
|
||||||
mapargs->rhs_is_noop = false;
|
mapargs->orig_rhs = vim_strsave((char_u *)tmp_buf);
|
||||||
mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
|
mapargs->rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "%c%c%c%d\r", K_SPECIAL,
|
||||||
STRLCPY(mapargs->rhs, replaced, mapargs->rhs_len + 1);
|
(char_u)KEY2TERMCAP0(K_LUA), KEY2TERMCAP1(K_LUA),
|
||||||
|
rhs_lua);
|
||||||
|
mapargs->rhs = vim_strsave((char_u *)tmp_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
xfree(lhs_buf);
|
xfree(lhs_buf);
|
||||||
@ -2765,7 +2783,7 @@ int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs)
|
|||||||
|
|
||||||
size_t orig_rhs_len = STRLEN(rhs_start);
|
size_t orig_rhs_len = STRLEN(rhs_start);
|
||||||
set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len,
|
set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len,
|
||||||
rhs_start, orig_rhs_len,
|
rhs_start, orig_rhs_len, LUA_NOREF,
|
||||||
CPO_TO_CPO_FLAGS, &parsed_args);
|
CPO_TO_CPO_FLAGS, &parsed_args);
|
||||||
|
|
||||||
xfree(lhs_to_replace);
|
xfree(lhs_to_replace);
|
||||||
@ -2827,7 +2845,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
|
|||||||
validate_maphash();
|
validate_maphash();
|
||||||
|
|
||||||
bool has_lhs = (args->lhs[0] != NUL);
|
bool has_lhs = (args->lhs[0] != NUL);
|
||||||
bool has_rhs = (args->rhs[0] != NUL) || args->rhs_is_noop;
|
bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
|
||||||
|
|
||||||
// check for :unmap without argument
|
// check for :unmap without argument
|
||||||
if (maptype == 1 && !has_lhs) {
|
if (maptype == 1 && !has_lhs) {
|
||||||
@ -3017,10 +3035,14 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
|
|||||||
} else { // new rhs for existing entry
|
} else { // new rhs for existing entry
|
||||||
mp->m_mode &= ~mode; // remove mode bits
|
mp->m_mode &= ~mode; // remove mode bits
|
||||||
if (mp->m_mode == 0 && !did_it) { // reuse entry
|
if (mp->m_mode == 0 && !did_it) { // reuse entry
|
||||||
xfree(mp->m_str);
|
XFREE_CLEAR(mp->m_str);
|
||||||
|
XFREE_CLEAR(mp->m_orig_str);
|
||||||
|
XFREE_CLEAR(mp->m_desc);
|
||||||
|
NLUA_CLEAR_REF(mp->m_luaref);
|
||||||
|
|
||||||
mp->m_str = vim_strsave(rhs);
|
mp->m_str = vim_strsave(rhs);
|
||||||
xfree(mp->m_orig_str);
|
|
||||||
mp->m_orig_str = vim_strsave(orig_rhs);
|
mp->m_orig_str = vim_strsave(orig_rhs);
|
||||||
|
mp->m_luaref = args->rhs_lua;
|
||||||
mp->m_noremap = noremap;
|
mp->m_noremap = noremap;
|
||||||
mp->m_nowait = args->nowait;
|
mp->m_nowait = args->nowait;
|
||||||
mp->m_silent = args->silent;
|
mp->m_silent = args->silent;
|
||||||
@ -3028,6 +3050,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
|
|||||||
mp->m_expr = args->expr;
|
mp->m_expr = args->expr;
|
||||||
mp->m_script_ctx = current_sctx;
|
mp->m_script_ctx = current_sctx;
|
||||||
mp->m_script_ctx.sc_lnum += sourcing_lnum;
|
mp->m_script_ctx.sc_lnum += sourcing_lnum;
|
||||||
|
if (args->desc != NULL) {
|
||||||
|
mp->m_desc = xstrdup(args->desc);
|
||||||
|
}
|
||||||
did_it = true;
|
did_it = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3096,6 +3121,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
|
|||||||
mp->m_keys = vim_strsave(lhs);
|
mp->m_keys = vim_strsave(lhs);
|
||||||
mp->m_str = vim_strsave(rhs);
|
mp->m_str = vim_strsave(rhs);
|
||||||
mp->m_orig_str = vim_strsave(orig_rhs);
|
mp->m_orig_str = vim_strsave(orig_rhs);
|
||||||
|
mp->m_luaref = args->rhs_lua;
|
||||||
mp->m_keylen = (int)STRLEN(mp->m_keys);
|
mp->m_keylen = (int)STRLEN(mp->m_keys);
|
||||||
mp->m_noremap = noremap;
|
mp->m_noremap = noremap;
|
||||||
mp->m_nowait = args->nowait;
|
mp->m_nowait = args->nowait;
|
||||||
@ -3104,6 +3130,10 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
|
|||||||
mp->m_expr = args->expr;
|
mp->m_expr = args->expr;
|
||||||
mp->m_script_ctx = current_sctx;
|
mp->m_script_ctx = current_sctx;
|
||||||
mp->m_script_ctx.sc_lnum += sourcing_lnum;
|
mp->m_script_ctx.sc_lnum += sourcing_lnum;
|
||||||
|
mp->m_desc = NULL;
|
||||||
|
if (args->desc != NULL) {
|
||||||
|
mp->m_desc = xstrdup(args->desc);
|
||||||
|
}
|
||||||
|
|
||||||
// add the new entry in front of the abbrlist or maphash[] list
|
// add the new entry in front of the abbrlist or maphash[] list
|
||||||
if (is_abbrev) {
|
if (is_abbrev) {
|
||||||
@ -3200,8 +3230,10 @@ static void mapblock_free(mapblock_T **mpp)
|
|||||||
|
|
||||||
mp = *mpp;
|
mp = *mpp;
|
||||||
xfree(mp->m_keys);
|
xfree(mp->m_keys);
|
||||||
xfree(mp->m_str);
|
NLUA_CLEAR_REF(mp->m_luaref);
|
||||||
xfree(mp->m_orig_str);
|
XFREE_CLEAR(mp->m_str);
|
||||||
|
XFREE_CLEAR(mp->m_orig_str);
|
||||||
|
XFREE_CLEAR(mp->m_desc);
|
||||||
*mpp = mp->m_next;
|
*mpp = mp->m_next;
|
||||||
xfree(mp);
|
xfree(mp);
|
||||||
}
|
}
|
||||||
@ -3392,7 +3424,8 @@ static void showmap(mapblock_T *mp, bool local)
|
|||||||
{
|
{
|
||||||
size_t len = 1;
|
size_t len = 1;
|
||||||
|
|
||||||
if (message_filtered(mp->m_keys) && message_filtered(mp->m_str)) {
|
if (message_filtered(mp->m_keys)
|
||||||
|
&& mp->m_str != NULL && message_filtered(mp->m_str)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3437,7 +3470,11 @@ static void showmap(mapblock_T *mp, bool local)
|
|||||||
|
|
||||||
/* Use FALSE below if we only want things like <Up> to show up as such on
|
/* Use FALSE below if we only want things like <Up> to show up as such on
|
||||||
* the rhs, and not M-x etc, TRUE gets both -- webb */
|
* the rhs, and not M-x etc, TRUE gets both -- webb */
|
||||||
if (*mp->m_str == NUL) {
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
|
char msg[100];
|
||||||
|
snprintf(msg, sizeof(msg), "<Lua function %d>", mp->m_luaref);
|
||||||
|
msg_puts_attr(msg, HL_ATTR(HLF_8));
|
||||||
|
} else if (mp->m_str == NULL) {
|
||||||
msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
|
msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
|
||||||
} else {
|
} else {
|
||||||
// Remove escaping of CSI, because "m_str" is in a format to be used
|
// Remove escaping of CSI, because "m_str" is in a format to be used
|
||||||
@ -3447,6 +3484,11 @@ static void showmap(mapblock_T *mp, bool local)
|
|||||||
msg_outtrans_special(s, false, 0);
|
msg_outtrans_special(s, false, 0);
|
||||||
xfree(s);
|
xfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mp->m_desc != NULL) {
|
||||||
|
msg_puts("\n "); // Shift line to same level as rhs.
|
||||||
|
msg_puts(mp->m_desc);
|
||||||
|
}
|
||||||
if (p_verbose > 0) {
|
if (p_verbose > 0) {
|
||||||
last_set_msg(mp->m_script_ctx);
|
last_set_msg(mp->m_script_ctx);
|
||||||
}
|
}
|
||||||
@ -3533,7 +3575,7 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
|
|||||||
}
|
}
|
||||||
for (; mp; mp = mp->m_next) {
|
for (; mp; mp = mp->m_next) {
|
||||||
if ((mp->m_mode & mode)
|
if ((mp->m_mode & mode)
|
||||||
&& strstr((char *)mp->m_str, rhs) != NULL) {
|
&& mp->m_str != NULL && strstr((char *)mp->m_str, rhs) != NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3879,7 +3921,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
|
|||||||
(void)ins_typebuf(tb, 1, 0, true, mp->m_silent);
|
(void)ins_typebuf(tb, 1, 0, true, mp->m_silent);
|
||||||
}
|
}
|
||||||
if (mp->m_expr) {
|
if (mp->m_expr) {
|
||||||
s = eval_map_expr(mp->m_str, c);
|
s = eval_map_expr(mp, c);
|
||||||
} else {
|
} else {
|
||||||
s = mp->m_str;
|
s = mp->m_str;
|
||||||
}
|
}
|
||||||
@ -3909,11 +3951,11 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
|
|||||||
/// special characters.
|
/// special characters.
|
||||||
///
|
///
|
||||||
/// @param c NUL or typed character for abbreviation
|
/// @param c NUL or typed character for abbreviation
|
||||||
static char_u *eval_map_expr(char_u *str, int c)
|
static char_u *eval_map_expr(mapblock_T *mp, int c)
|
||||||
{
|
{
|
||||||
char_u *res;
|
char_u *res;
|
||||||
char_u *p;
|
char_u *p = NULL;
|
||||||
char_u *expr;
|
char_u *expr = NULL;
|
||||||
char_u *save_cmd;
|
char_u *save_cmd;
|
||||||
pos_T save_cursor;
|
pos_T save_cursor;
|
||||||
int save_msg_col;
|
int save_msg_col;
|
||||||
@ -3921,8 +3963,10 @@ static char_u *eval_map_expr(char_u *str, int c)
|
|||||||
|
|
||||||
/* Remove escaping of CSI, because "str" is in a format to be used as
|
/* Remove escaping of CSI, because "str" is in a format to be used as
|
||||||
* typeahead. */
|
* typeahead. */
|
||||||
expr = vim_strsave(str);
|
if (mp->m_luaref == LUA_NOREF) {
|
||||||
vim_unescape_csi(expr);
|
expr = vim_strsave(mp->m_str);
|
||||||
|
vim_unescape_csi(expr);
|
||||||
|
}
|
||||||
|
|
||||||
save_cmd = save_cmdline_alloc();
|
save_cmd = save_cmdline_alloc();
|
||||||
|
|
||||||
@ -3934,7 +3978,22 @@ static char_u *eval_map_expr(char_u *str, int c)
|
|||||||
save_cursor = curwin->w_cursor;
|
save_cursor = curwin->w_cursor;
|
||||||
save_msg_col = msg_col;
|
save_msg_col = msg_col;
|
||||||
save_msg_row = msg_row;
|
save_msg_row = msg_row;
|
||||||
p = eval_to_string(expr, NULL, false);
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
|
Error err = ERROR_INIT;
|
||||||
|
Array args = ARRAY_DICT_INIT;
|
||||||
|
Object ret = nlua_call_ref(mp->m_luaref, NULL, args, true, &err);
|
||||||
|
if (ret.type == kObjectTypeString) {
|
||||||
|
p = (char_u *)xstrndup(ret.data.string.data, ret.data.string.size);
|
||||||
|
}
|
||||||
|
api_free_object(ret);
|
||||||
|
if (err.type != kErrorTypeNone) {
|
||||||
|
semsg_multiline("E5108: %s", err.msg);
|
||||||
|
api_clear_error(&err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p = eval_to_string(expr, NULL, false);
|
||||||
|
xfree(expr);
|
||||||
|
}
|
||||||
textlock--;
|
textlock--;
|
||||||
ex_normal_lock--;
|
ex_normal_lock--;
|
||||||
curwin->w_cursor = save_cursor;
|
curwin->w_cursor = save_cursor;
|
||||||
@ -3942,7 +4001,6 @@ static char_u *eval_map_expr(char_u *str, int c)
|
|||||||
msg_row = save_msg_row;
|
msg_row = save_msg_row;
|
||||||
|
|
||||||
restore_cmdline_alloc(save_cmd);
|
restore_cmdline_alloc(save_cmd);
|
||||||
xfree(expr);
|
|
||||||
|
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -4049,8 +4107,11 @@ int makemap(FILE *fd, buf_T *buf)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip mappings that contain a <SNR> (script-local thing),
|
// skip lua mappings and mappings that contain a <SNR> (script-local thing),
|
||||||
// they probably don't work when loaded again
|
// they probably don't work when loaded again
|
||||||
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (p = mp->m_str; *p != NUL; p++) {
|
for (p = mp->m_str; *p != NUL; p++) {
|
||||||
if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
|
if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
|
||||||
&& p[2] == (int)KE_SNR) {
|
&& p[2] == (int)KE_SNR) {
|
||||||
@ -4331,10 +4392,11 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
|
|||||||
/// @param mp_ptr return: pointer to mapblock or NULL
|
/// @param mp_ptr return: pointer to mapblock or NULL
|
||||||
/// @param local_ptr return: buffer-local mapping or NULL
|
/// @param local_ptr return: buffer-local mapping or NULL
|
||||||
char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr,
|
char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr,
|
||||||
int *local_ptr)
|
int *local_ptr, int *rhs_lua)
|
||||||
{
|
{
|
||||||
int len, minlen;
|
int len, minlen;
|
||||||
mapblock_T *mp;
|
mapblock_T *mp;
|
||||||
|
*rhs_lua = LUA_NOREF;
|
||||||
|
|
||||||
validate_maphash();
|
validate_maphash();
|
||||||
|
|
||||||
@ -4375,7 +4437,8 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb
|
|||||||
if (local_ptr != NULL) {
|
if (local_ptr != NULL) {
|
||||||
*local_ptr = local;
|
*local_ptr = local;
|
||||||
}
|
}
|
||||||
return mp->m_str;
|
*rhs_lua = mp->m_luaref;
|
||||||
|
return mp->m_luaref == LUA_NOREF ? mp->m_str : NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4560,3 +4623,47 @@ char_u *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
|
|||||||
|
|
||||||
return (char_u *)line_ga.ga_data;
|
return (char_u *)line_ga.ga_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool map_execute_lua(void)
|
||||||
|
{
|
||||||
|
garray_T line_ga;
|
||||||
|
int c1 = -1;
|
||||||
|
bool aborted = false;
|
||||||
|
|
||||||
|
ga_init(&line_ga, 1, 32);
|
||||||
|
|
||||||
|
no_mapping++;
|
||||||
|
|
||||||
|
got_int = false;
|
||||||
|
while (c1 != NUL && !aborted) {
|
||||||
|
ga_grow(&line_ga, 32);
|
||||||
|
// Get one character at a time.
|
||||||
|
c1 = vgetorpeek(true);
|
||||||
|
if (got_int) {
|
||||||
|
aborted = true;
|
||||||
|
} else if (c1 == '\r' || c1 == '\n') {
|
||||||
|
c1 = NUL; // end the line
|
||||||
|
} else {
|
||||||
|
ga_append(&line_ga, (char)c1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
no_mapping--;
|
||||||
|
|
||||||
|
if (aborted) {
|
||||||
|
ga_clear(&line_ga);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaRef ref = (LuaRef)atoi(line_ga.ga_data);
|
||||||
|
Error err = ERROR_INIT;
|
||||||
|
Array args = ARRAY_DICT_INIT;
|
||||||
|
nlua_call_ref(ref, NULL, args, false, &err);
|
||||||
|
if (err.type != kErrorTypeNone) {
|
||||||
|
semsg_multiline("E5108: %s", err.msg);
|
||||||
|
api_clear_error(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ga_clear(&line_ga);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -50,14 +50,16 @@ struct map_arguments {
|
|||||||
|
|
||||||
char_u *rhs; /// The {rhs} of the mapping.
|
char_u *rhs; /// The {rhs} of the mapping.
|
||||||
size_t rhs_len;
|
size_t rhs_len;
|
||||||
|
LuaRef rhs_lua; /// lua function as rhs
|
||||||
bool rhs_is_noop; /// True when the {orig_rhs} is <nop>.
|
bool rhs_is_noop; /// True when the {orig_rhs} is <nop>.
|
||||||
|
|
||||||
char_u *orig_rhs; /// The original text of the {rhs}.
|
char_u *orig_rhs; /// The original text of the {rhs}.
|
||||||
size_t orig_rhs_len;
|
size_t orig_rhs_len;
|
||||||
|
char *desc; /// map escription
|
||||||
};
|
};
|
||||||
typedef struct map_arguments MapArguments;
|
typedef struct map_arguments MapArguments;
|
||||||
#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
|
#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
|
||||||
{ 0 }, 0, NULL, 0, false, NULL, 0 }
|
{ 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
|
||||||
|
|
||||||
#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
|
#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
|
||||||
#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
|
#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
|
||||||
|
@ -245,6 +245,7 @@ enum key_extra {
|
|||||||
KE_MOUSEMOVE = 100, // mouse moved with no button down
|
KE_MOUSEMOVE = 100, // mouse moved with no button down
|
||||||
// , KE_CANCEL = 101 // return from vgetc
|
// , KE_CANCEL = 101 // return from vgetc
|
||||||
KE_EVENT = 102, // event
|
KE_EVENT = 102, // event
|
||||||
|
KE_LUA = 103, // lua special key
|
||||||
KE_COMMAND = 104, // <Cmd> special key
|
KE_COMMAND = 104, // <Cmd> special key
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -443,6 +444,7 @@ enum key_extra {
|
|||||||
|
|
||||||
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
||||||
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
|
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
|
||||||
|
#define K_LUA TERMCAP2KEY(KS_EXTRA, KE_LUA)
|
||||||
|
|
||||||
// Bits for modifier mask
|
// Bits for modifier mask
|
||||||
// 0x01 cannot be used, because the modifier must be 0x02 or higher
|
// 0x01 cannot be used, because the modifier must be 0x02 or higher
|
||||||
|
@ -334,6 +334,7 @@ static const struct nv_cmd {
|
|||||||
{ K_SELECT, nv_select, 0, 0 },
|
{ K_SELECT, nv_select, 0, 0 },
|
||||||
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
|
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
|
||||||
{ K_COMMAND, nv_colon, 0, 0 },
|
{ K_COMMAND, nv_colon, 0, 0 },
|
||||||
|
{ K_LUA, nv_colon, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Number of commands in nv_cmds[].
|
// Number of commands in nv_cmds[].
|
||||||
@ -4043,21 +4044,22 @@ static void nv_regreplay(cmdarg_T *cap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a ":" command and <Cmd>.
|
/// Handle a ":" command and <Cmd> or Lua keymaps.
|
||||||
static void nv_colon(cmdarg_T *cap)
|
static void nv_colon(cmdarg_T *cap)
|
||||||
{
|
{
|
||||||
int old_p_im;
|
int old_p_im;
|
||||||
bool cmd_result;
|
bool cmd_result;
|
||||||
bool is_cmdkey = cap->cmdchar == K_COMMAND;
|
bool is_cmdkey = cap->cmdchar == K_COMMAND;
|
||||||
|
bool is_lua = cap->cmdchar == K_LUA;
|
||||||
|
|
||||||
if (VIsual_active && !is_cmdkey) {
|
if (VIsual_active && !is_cmdkey && !is_lua) {
|
||||||
nv_operator(cap);
|
nv_operator(cap);
|
||||||
} else {
|
} else {
|
||||||
if (cap->oap->op_type != OP_NOP) {
|
if (cap->oap->op_type != OP_NOP) {
|
||||||
// Using ":" as a movement is charwise exclusive.
|
// Using ":" as a movement is charwise exclusive.
|
||||||
cap->oap->motion_type = kMTCharWise;
|
cap->oap->motion_type = kMTCharWise;
|
||||||
cap->oap->inclusive = false;
|
cap->oap->inclusive = false;
|
||||||
} else if (cap->count0 && !is_cmdkey) {
|
} else if (cap->count0 && !is_cmdkey && !is_lua) {
|
||||||
// translate "count:" into ":.,.+(count - 1)"
|
// translate "count:" into ":.,.+(count - 1)"
|
||||||
stuffcharReadbuff('.');
|
stuffcharReadbuff('.');
|
||||||
if (cap->count0 > 1) {
|
if (cap->count0 > 1) {
|
||||||
@ -4073,9 +4075,13 @@ static void nv_colon(cmdarg_T *cap)
|
|||||||
|
|
||||||
old_p_im = p_im;
|
old_p_im = p_im;
|
||||||
|
|
||||||
|
if (is_lua) {
|
||||||
|
cmd_result = map_execute_lua();
|
||||||
|
} else {
|
||||||
// get a command line and execute it
|
// get a command line and execute it
|
||||||
cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
|
cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
|
||||||
cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
|
cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
|
||||||
|
}
|
||||||
|
|
||||||
// If 'insertmode' changed, enter or exit Insert mode
|
// If 'insertmode' changed, enter or exit Insert mode
|
||||||
if (p_im != old_p_im) {
|
if (p_im != old_p_im) {
|
||||||
|
@ -528,6 +528,10 @@ static int terminal_execute(VimState *state, int key)
|
|||||||
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
|
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case K_LUA:
|
||||||
|
map_execute_lua();
|
||||||
|
break;
|
||||||
|
|
||||||
case Ctrl_N:
|
case Ctrl_N:
|
||||||
if (s->got_bsl) {
|
if (s->got_bsl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5,6 +5,7 @@ local clear = helpers.clear
|
|||||||
local command = helpers.command
|
local command = helpers.command
|
||||||
local curbufmeths = helpers.curbufmeths
|
local curbufmeths = helpers.curbufmeths
|
||||||
local eq, neq = helpers.eq, helpers.neq
|
local eq, neq = helpers.eq, helpers.neq
|
||||||
|
local exec_lua = helpers.exec_lua
|
||||||
local feed = helpers.feed
|
local feed = helpers.feed
|
||||||
local funcs = helpers.funcs
|
local funcs = helpers.funcs
|
||||||
local meths = helpers.meths
|
local meths = helpers.meths
|
||||||
@ -316,6 +317,55 @@ describe('nvim_get_keymap', function()
|
|||||||
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
|
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
|
||||||
eq({space_table}, meths.get_keymap('n'))
|
eq({space_table}, meths.get_keymap('n'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can handle lua keymaps', function()
|
||||||
|
eq(0, exec_lua [[
|
||||||
|
GlobalCount = 0
|
||||||
|
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
eq(2, exec_lua[[
|
||||||
|
vim.api.nvim_get_keymap('n')[1].callback()
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
local mapargs = meths.get_keymap('n')
|
||||||
|
assert.Truthy(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
|
||||||
|
mapargs[1].callback = nil
|
||||||
|
eq({
|
||||||
|
lhs='asdf',
|
||||||
|
script=0,
|
||||||
|
silent=0,
|
||||||
|
expr=0,
|
||||||
|
sid=0,
|
||||||
|
buffer=0,
|
||||||
|
nowait=0,
|
||||||
|
mode='n',
|
||||||
|
noremap=0,
|
||||||
|
lnum=0,
|
||||||
|
}, mapargs[1])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it ('can handle map descriptions', function()
|
||||||
|
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
|
||||||
|
eq({
|
||||||
|
lhs='lhs',
|
||||||
|
rhs='rhs',
|
||||||
|
script=0,
|
||||||
|
silent=0,
|
||||||
|
expr=0,
|
||||||
|
sid=0,
|
||||||
|
buffer=0,
|
||||||
|
nowait=0,
|
||||||
|
mode='n',
|
||||||
|
noremap=0,
|
||||||
|
lnum=0,
|
||||||
|
desc='map description'
|
||||||
|
}, meths.get_keymap('n')[1])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_set_keymap, nvim_del_keymap', function()
|
describe('nvim_set_keymap, nvim_del_keymap', function()
|
||||||
@ -353,6 +403,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
|
|||||||
to_return.sid = not opts.sid and 0 or opts.sid
|
to_return.sid = not opts.sid and 0 or opts.sid
|
||||||
to_return.buffer = not opts.buffer and 0 or opts.buffer
|
to_return.buffer = not opts.buffer and 0 or opts.buffer
|
||||||
to_return.lnum = not opts.lnum and 0 or opts.lnum
|
to_return.lnum = not opts.lnum and 0 or opts.lnum
|
||||||
|
to_return.desc = opts.desc
|
||||||
|
|
||||||
return to_return
|
return to_return
|
||||||
end
|
end
|
||||||
@ -717,6 +768,105 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
it (':map command shows lua keymap correctly', function()
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
|
||||||
|
]]
|
||||||
|
assert.truthy(string.match(exec_lua[[return vim.api.nvim_exec(':nmap asdf', true)]],
|
||||||
|
"^\nn asdf <Lua function %d+>"))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it ('mapcheck() returns lua keymap correctly', function()
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
|
||||||
|
]]
|
||||||
|
assert.truthy(string.match(funcs.mapcheck('asdf', 'n'),
|
||||||
|
"^<Lua function %d+>"))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it ('maparg() returns lua keymap correctly', function()
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
|
||||||
|
]]
|
||||||
|
assert.truthy(string.match(funcs.maparg('asdf', 'n'),
|
||||||
|
"^<Lua function %d+>"))
|
||||||
|
local mapargs = funcs.maparg('asdf', 'n', false, true)
|
||||||
|
assert.Truthy(type(mapargs.callback) == 'number', 'callback is not luaref number')
|
||||||
|
mapargs.callback = nil
|
||||||
|
eq(generate_mapargs('n', 'asdf', nil, {}), mapargs)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can make lua expr mappings', function()
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('aa')
|
||||||
|
|
||||||
|
eq(99, exec_lua[[return SomeValue]])
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(0, exec_lua[[return GlobalCount]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_del_keymap('n', 'asdf' )
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can set descriptions on keymaps', function()
|
||||||
|
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
|
||||||
|
eq(generate_mapargs('n', 'lhs', 'rhs', {desc="map description"}), get_mapargs('n', 'lhs'))
|
||||||
|
eq("\nn lhs rhs\n map description",
|
||||||
|
helpers.exec_capture("nmap lhs"))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
|
describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
|
||||||
@ -814,4 +964,67 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
|
|||||||
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
|
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
|
||||||
helpers.assert_alive()
|
helpers.assert_alive()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can make lua expr mappings', function()
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('aa')
|
||||||
|
|
||||||
|
eq(99, exec_lua[[return SomeValue ]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(0, exec_lua[[return GlobalCount]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
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 })
|
||||||
|
return GlobalCount
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
vim.api.nvim_buf_del_keymap(0, 'n', 'asdf' )
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('asdf\n')
|
||||||
|
|
||||||
|
eq(1, exec_lua[[return GlobalCount]])
|
||||||
|
eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user