aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim9
-rw-r--r--src/nvim/api/ui.c64
-rw-r--r--src/nvim/api/vim.c22
-rw-r--r--src/nvim/highlight.c30
-rw-r--r--src/nvim/highlight.h2
-rw-r--r--src/nvim/highlight_group.c20
-rw-r--r--src/nvim/mapping.c53
-rw-r--r--src/nvim/testdir/test_gui.vim43
-rw-r--r--src/nvim/testdir/test_maparg.vim33
-rw-r--r--test/functional/vimscript/map_functions_spec.lua42
10 files changed, 216 insertions, 102 deletions
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 802ebd42b5..bfece6aa72 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -964,14 +964,7 @@ func s:DeleteCommands()
nunmap K
else
" call mapset(s:k_map_saved)
- let mode = s:k_map_saved.mode !=# ' ' ? s:k_map_saved.mode : ''
- call nvim_set_keymap(mode, 'K', s:k_map_saved.rhs, {
- \ 'expr': s:k_map_saved.expr ? v:true : v:false,
- \ 'noremap': s:k_map_saved.noremap ? v:true : v:false,
- \ 'nowait': s:k_map_saved.nowait ? v:true : v:false,
- \ 'script': s:k_map_saved.script ? v:true : v:false,
- \ 'silent': s:k_map_saved.silent ? v:true : v:false,
- \ })
+ call mapset('n', 0, s:k_map_saved)
endif
unlet s:k_map_saved
endif
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 654eb19bec..1534e547b0 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -749,10 +749,12 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt
UIData *data = ui->data;
Array args = data->call_buf;
ADD_C(args, INTEGER_OBJ(id));
- MAXSIZE_TEMP_DICT(rgb, 16);
- MAXSIZE_TEMP_DICT(cterm, 16);
- ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&rgb, rgb_attrs, true)));
- ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&cterm, cterm_attrs, false)));
+ MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE);
+ MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE);
+ hlattrs2dict(&rgb, rgb_attrs, true);
+ hlattrs2dict(&cterm, rgb_attrs, false);
+ ADD_C(args, DICTIONARY_OBJ(rgb));
+ ADD_C(args, DICTIONARY_OBJ(cterm));
if (ui->ui_ext[kUIHlState]) {
ADD_C(args, ARRAY_OBJ(info));
@@ -772,8 +774,9 @@ static void remote_ui_highlight_set(UI *ui, int id)
return;
}
data->hl_id = id;
- MAXSIZE_TEMP_DICT(dict, 16);
- ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb)));
+ MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE);
+ hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb);
+ ADD_C(args, DICTIONARY_OBJ(dict));
push_call(ui, "highlight_set", args);
}
@@ -953,65 +956,63 @@ static void remote_ui_flush(UI *ui)
}
}
-static Array translate_contents(UI *ui, Array contents)
+static Array translate_contents(UI *ui, Array contents, Arena *arena)
{
- Array new_contents = ARRAY_DICT_INIT;
+ Array new_contents = arena_array(arena, contents.size);
for (size_t i = 0; i < contents.size; i++) {
Array item = contents.items[i].data.array;
- Array new_item = ARRAY_DICT_INIT;
+ Array new_item = arena_array(arena, 2);
int attr = (int)item.items[0].data.integer;
if (attr) {
- Dictionary rgb_attrs = hlattrs2dict(NULL, syn_attr2entry(attr), ui->rgb);
+ Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
+ hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb);
ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
- ADD(new_item, copy_object(item.items[1], NULL));
+ ADD(new_item, item.items[1]);
ADD(new_contents, ARRAY_OBJ(new_item));
}
return new_contents;
}
-static Array translate_firstarg(UI *ui, Array args)
+static Array translate_firstarg(UI *ui, Array args, Arena *arena)
{
- Array new_args = ARRAY_DICT_INIT;
+ Array new_args = arena_array(arena, args.size);
Array contents = args.items[0].data.array;
- ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents)));
+ ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena)));
for (size_t i = 1; i < args.size; i++) {
- ADD(new_args, copy_object(args.items[i], NULL));
+ ADD(new_args, args.items[i]);
}
return new_args;
}
static void remote_ui_event(UI *ui, char *name, Array args)
{
+ Arena arena = ARENA_EMPTY;
UIData *data = ui->data;
if (!ui->ui_ext[kUILinegrid]) {
// the representation of highlights in cmdline changed, translate back
// never consumes args
if (strequal(name, "cmdline_show")) {
- Array new_args = translate_firstarg(ui, args);
+ Array new_args = translate_firstarg(ui, args, &arena);
push_call(ui, name, new_args);
- api_free_array(new_args);
- return;
+ goto free_ret;
} else if (strequal(name, "cmdline_block_show")) {
Array new_args = data->call_buf;
Array block = args.items[0].data.array;
- Array new_block = ARRAY_DICT_INIT;
+ Array new_block = arena_array(&arena, block.size);
for (size_t i = 0; i < block.size; i++) {
- ADD(new_block,
- ARRAY_OBJ(translate_contents(ui, block.items[i].data.array)));
+ ADD_C(new_block, ARRAY_OBJ(translate_contents(ui, block.items[i].data.array, &arena)));
}
ADD_C(new_args, ARRAY_OBJ(new_block));
push_call(ui, name, new_args);
- api_free_array(new_block);
- return;
+ goto free_ret;
} else if (strequal(name, "cmdline_block_append")) {
- Array new_args = translate_firstarg(ui, args);
+ Array new_args = translate_firstarg(ui, args, &arena);
push_call(ui, name, new_args);
- api_free_array(new_args);
- return;
+ goto free_ret;
}
}
@@ -1023,19 +1024,18 @@ static void remote_ui_event(UI *ui, char *name, Array args)
if (data->wildmenu_active) {
Array new_args = data->call_buf;
Array items = args.items[0].data.array;
- Array new_items = ARRAY_DICT_INIT;
+ Array new_items = arena_array(&arena, items.size);
for (size_t i = 0; i < items.size; i++) {
- ADD(new_items, copy_object(items.items[i].data.array.items[0], NULL));
+ ADD_C(new_items, items.items[i].data.array.items[0]);
}
ADD_C(new_args, ARRAY_OBJ(new_items));
push_call(ui, "wildmenu_show", new_args);
- api_free_array(new_items);
if (args.items[1].data.integer != -1) {
Array new_args2 = data->call_buf;
ADD_C(new_args2, args.items[1]);
push_call(ui, "wildmenu_select", new_args2);
}
- return;
+ goto free_ret;
}
} else if (strequal(name, "popupmenu_select")) {
if (data->wildmenu_active) {
@@ -1049,6 +1049,10 @@ static void remote_ui_event(UI *ui, char *name, Array args)
}
push_call(ui, name, args);
+ return;
+
+free_ret:
+ arena_mem_free(arena_finish(&arena));
}
static void remote_ui_inspect(UI *ui, Dictionary *info)
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 9e1f2dd631..83d6ba8dc7 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -79,7 +79,7 @@
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_id
-Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
+Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary result = ARRAY_DICT_INIT;
@@ -89,8 +89,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data);
return result;
}
- result = nvim_get_hl_by_id(id, rgb, err);
- return result;
+ return nvim_get_hl_by_id(id, rgb, arena, err);
}
/// Gets a highlight definition by id. |hlID()|
@@ -99,7 +98,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_name
-Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
+Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary dic = ARRAY_DICT_INIT;
@@ -108,7 +107,7 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
return dic;
}
int attrcode = syn_id2attr((int)hl_id);
- return hl_get_attr_by_id(attrcode, rgb, err);
+ return hl_get_attr_by_id(attrcode, rgb, arena, err);
}
/// Gets a highlight group by name
@@ -120,10 +119,10 @@ Integer nvim_get_hl_id_by_name(String name)
return syn_check_group(name.data, name.size);
}
-Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
+Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err)
{
if (ns_id == 0) {
- return get_global_hl_defs();
+ return get_global_hl_defs(arena);
}
abort();
}
@@ -1934,7 +1933,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di
}
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time
-Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
+Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, Error *err)
{
Array ret = ARRAY_DICT_INIT;
@@ -1958,13 +1957,14 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
|| col < 0 || col >= g->cols) {
return ret;
}
+ ret = arena_array(arena, 3);
size_t off = g->line_offset[(size_t)row] + (size_t)col;
- ADD(ret, STRING_OBJ(cstr_to_string((char *)g->chars[off])));
+ ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off])));
int attr = g->attrs[off];
- ADD(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, err)));
+ ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
// will not work first time
if (!highlight_use_hlstate()) {
- ADD(ret, ARRAY_OBJ(hl_inspect(attr)));
+ ADD_C(ret, ARRAY_OBJ(hl_inspect(attr)));
}
return ret;
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index a78b933108..e42cb66422 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -788,7 +788,7 @@ HlAttrs syn_attr2entry(int attr)
}
/// Gets highlight description for id `attr_id` as a map.
-Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
+Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *err)
{
Dictionary dic = ARRAY_DICT_INIT;
@@ -801,25 +801,21 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
"Invalid attribute id: %" PRId64, attr_id);
return dic;
}
-
- return hlattrs2dict(NULL, syn_attr2entry((int)attr_id), rgb);
+ Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE);
+ hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb);
+ return retval;
}
/// Converts an HlAttrs into Dictionary
///
-/// @param[out] hl optional pre-allocated dictionary for return value
-/// if present, must be allocated with at least 16 elements!
+/// @param[in/out] hl Dictionary with pre-allocated space for HLATTRS_DICT_SIZE elements
/// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
-Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb)
+void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb)
{
+ assert(dict->capacity >= HLATTRS_DICT_SIZE); // at most 16 items
+ Dictionary hl = *dict;
int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr;
- Dictionary hl = ARRAY_DICT_INIT;
- if (hl_alloc) {
- hl = *hl_alloc;
- } else {
- kv_ensure_space(hl, 16);
- }
if (mask & HL_BOLD) {
PUT_C(hl, "bold", BOOLEAN_OBJ(true));
@@ -899,14 +895,7 @@ Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb)
PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend));
}
- if (hl_alloc) {
- *hl_alloc = hl;
- return hl;
- } else {
- Dictionary allocated = copy_dictionary(hl, NULL);
- kv_destroy(hl);
- return allocated;
- }
+ *dict = hl;
}
HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err)
@@ -1086,6 +1075,7 @@ int object_to_color(Object val, char *key, bool rgb, Error *err)
Array hl_inspect(int attr)
{
+ // TODO(bfredl): use arena allocation
Array ret = ARRAY_DICT_INIT;
if (hlstate_active) {
hl_inspect_impl(&ret, attr);
diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h
index 50299bb91c..e85e3859e2 100644
--- a/src/nvim/highlight.h
+++ b/src/nvim/highlight.h
@@ -19,6 +19,8 @@ static inline int win_hl_attr(win_T *wp, int hlf)
return ((wp->w_ns_hl_attr && ns_hl_fast < 0) ? wp->w_ns_hl_attr : hl_attr_active)[hlf];
}
+#define HLATTRS_DICT_SIZE 16
+
#define HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp) \
do { \
bool dark_ = (*p_bg == 'd'); \
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index ed1f0185b7..5c07784db3 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -632,7 +632,9 @@ int load_colors(char_u *name)
retval = source_runtime((char *)buf, DIP_START + DIP_OPT);
}
xfree(buf);
- apply_autocmds(EVENT_COLORSCHEME, (char *)name, curbuf->b_fname, false, curbuf);
+ if (retval == OK) {
+ apply_autocmds(EVENT_COLORSCHEME, (char *)name, curbuf->b_fname, false, curbuf);
+ }
recursive = false;
@@ -1466,19 +1468,21 @@ static void highlight_list_one(const int id)
}
}
-Dictionary get_global_hl_defs(void)
+Dictionary get_global_hl_defs(Arena *arena)
{
- Dictionary rv = ARRAY_DICT_INIT;
- for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
+ Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len);
+ for (int i = 1; i <= highlight_ga.ga_len; i++) {
Dictionary attrs = ARRAY_DICT_INIT;
HlGroup *h = &hl_table[i - 1];
if (h->sg_attr > 0) {
- attrs = hlattrs2dict(NULL, syn_attr2entry(h->sg_attr), true);
+ attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
+ hlattrs2dict(&attrs, syn_attr2entry(h->sg_attr), true);
} else if (h->sg_link > 0) {
- const char *link = (const char *)hl_table[h->sg_link - 1].sg_name;
- PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
+ attrs = arena_dict(arena, 1);
+ char *link = (char *)hl_table[h->sg_link - 1].sg_name;
+ PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link)));
}
- PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs));
+ PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs));
}
return rv;
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index a3705d5c6f..923eea145c 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -276,21 +276,29 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs
mapargs->alt_lhs_len = 0;
}
+ set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, cpo_flags, mapargs);
+
+ return true;
+}
+
+/// @see set_maparg_lhs_rhs
+static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len,
+ const LuaRef rhs_lua, const int cpo_flags, MapArguments *const mapargs)
+{
mapargs->rhs_lua = rhs_lua;
if (rhs_lua == LUA_NOREF) {
mapargs->orig_rhs_len = orig_rhs_len;
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
- mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
+ mapargs->rhs = xcalloc(1, sizeof(char_u)); // single NUL-char
mapargs->rhs_len = 0;
mapargs->rhs_is_noop = true;
} else {
char *rhs_buf = NULL;
- replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL,
- cpo_flags);
+ char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL,
+ cpo_flags);
mapargs->rhs_len = STRLEN(replaced);
// NB: replace_termcodes may produce an empty string even if orig_rhs is non-empty
// (e.g. a single ^V, see :h map-empty-rhs)
@@ -307,7 +315,6 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs
(char_u)KS_EXTRA, KE_LUA, rhs_lua);
mapargs->rhs = vim_strsave((char_u *)tmp_buf);
}
- return true;
}
/// Parse a string of |:map-arguments| into a @ref MapArguments struct.
@@ -2000,8 +2007,7 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
FUNC_ATTR_NONNULL_ARG(1)
{
Dictionary dict = ARRAY_DICT_INIT;
- char *const lhs = str2special_save((const char *)mp->m_keys,
- compatible, !compatible);
+ char *const lhs = str2special_save((const char *)mp->m_keys, compatible, !compatible);
char *const mapmode = map_mode_to_chars(mp->m_mode);
varnumber_T noremap_value;
@@ -2114,13 +2120,15 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
}
} else {
// Return a dictionary.
- tv_dict_alloc_ret(rettv);
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
Dictionary dict = mapblock_fill_dict(mp,
did_simplify ? (char *)keys_simplified : NULL,
buffer_local, true);
(void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
api_free_dictionary(dict);
+ } else {
+ // Return an empty dictionary.
+ tv_dict_alloc_ret(rettv);
}
}
@@ -2149,29 +2157,36 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *lhs = tv_dict_get_string(d, "lhs", false);
char *lhsraw = tv_dict_get_string(d, "lhsraw", false);
char *lhsrawalt = tv_dict_get_string(d, "lhsrawalt", false);
- char *rhs = tv_dict_get_string(d, "rhs", false);
- if (lhs == NULL || lhsraw == NULL || rhs == NULL) {
+ char *orig_rhs = tv_dict_get_string(d, "rhs", false);
+ LuaRef rhs_lua = LUA_NOREF;
+ dictitem_T *callback_di = tv_dict_find(d, S_LEN("callback"));
+ if (callback_di != NULL) {
+ Object callback_obj = vim_to_object(&callback_di->di_tv);
+ if (callback_obj.type == kObjectTypeLuaRef && callback_obj.data.luaref != LUA_NOREF) {
+ rhs_lua = callback_obj.data.luaref;
+ orig_rhs = "";
+ callback_obj.data.luaref = LUA_NOREF;
+ }
+ api_free_object(callback_obj);
+ }
+ if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) {
emsg(_("E460: entries missing in mapset() dict argument"));
+ api_free_luaref(rhs_lua);
return;
}
- char *orig_rhs = rhs;
- char *arg_buf = NULL;
- rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
- int noremap = tv_dict_get_number(d, "noremap") ? REMAP_NONE : 0;
+ int noremap = tv_dict_get_number(d, "noremap") != 0 ? REMAP_NONE : 0;
if (tv_dict_get_number(d, "script") != 0) {
noremap = REMAP_SCRIPT;
}
- MapArguments args = { // TODO(zeertzjq): support restoring "callback"?
- .rhs = (char_u *)rhs,
- .rhs_lua = LUA_NOREF,
- .orig_rhs = vim_strsave((char_u *)orig_rhs),
+ MapArguments args = {
.expr = tv_dict_get_number(d, "expr") != 0,
.silent = tv_dict_get_number(d, "silent") != 0,
.nowait = tv_dict_get_number(d, "nowait") != 0,
.replace_keycodes = tv_dict_get_number(d, "replace_keycodes") != 0,
.desc = tv_dict_get_string(d, "desc", false),
};
+ set_maparg_rhs(orig_rhs, strlen(orig_rhs), rhs_lua, CPO_TO_CPO_FLAGS, &args);
scid_T sid = (scid_T)tv_dict_get_number(d, "sid");
linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum");
bool buffer = tv_dict_get_number(d, "buffer") != 0;
@@ -2182,7 +2197,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// Delete any existing mapping for this lhs and mode.
MapArguments unmap_args = MAP_ARGUMENTS_INIT;
- set_maparg_lhs_rhs(lhs, strlen(lhs), rhs, strlen(rhs), LUA_NOREF, 0, &unmap_args);
+ set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, 0, &unmap_args);
unmap_args.buffer = buffer;
buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, false, curbuf);
xfree(unmap_args.rhs);
diff --git a/src/nvim/testdir/test_gui.vim b/src/nvim/testdir/test_gui.vim
new file mode 100644
index 0000000000..c3f1f3163a
--- /dev/null
+++ b/src/nvim/testdir/test_gui.vim
@@ -0,0 +1,43 @@
+
+func Test_colorscheme()
+ " call assert_equal('16777216', &t_Co)
+
+ let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default'
+ let g:color_count = 0
+ augroup TestColors
+ au!
+ au ColorScheme * let g:color_count += 1
+ \ | let g:after_colors = g:color_count
+ \ | let g:color_after = expand('<amatch>')
+ au ColorSchemePre * let g:color_count += 1
+ \ | let g:before_colors = g:color_count
+ \ | let g:color_pre = expand('<amatch>')
+ augroup END
+
+ colorscheme torte
+ redraw!
+ call assert_equal('dark', &background)
+ call assert_equal(1, g:before_colors)
+ call assert_equal(2, g:after_colors)
+ call assert_equal('torte', g:color_pre)
+ call assert_equal('torte', g:color_after)
+ call assert_equal("\ntorte", execute('colorscheme'))
+
+ let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g')
+ " FIXME: temporarily check less while the colorscheme changes
+ " call assert_match("\nSearch xxx term=reverse cterm=reverse ctermfg=196 ctermbg=16 gui=reverse guifg=#ff0000 guibg=#000000", a)
+ " call assert_match("\nSearch xxx term=reverse ", a)
+
+ call assert_fails('colorscheme does_not_exist', 'E185:')
+ call assert_equal('does_not_exist', g:color_pre)
+ call assert_equal('torte', g:color_after)
+
+ exec 'colorscheme' colorscheme_saved
+ augroup TestColors
+ au!
+ augroup END
+ unlet g:color_count g:after_colors g:before_colors
+ redraw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 17c5f433ac..f903f5b934 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -158,11 +158,11 @@ func Test_range_map()
call assert_equal("abcd", getline(1))
endfunc
-func One_mapset_test(keys)
- exe 'nnoremap ' .. a:keys .. ' original<CR>'
+func One_mapset_test(keys, rhs)
+ exe 'nnoremap ' .. a:keys .. ' ' .. a:rhs
let orig = maparg(a:keys, 'n', 0, 1)
call assert_equal(a:keys, orig.lhs)
- call assert_equal('original<CR>', orig.rhs)
+ call assert_equal(a:rhs, orig.rhs)
call assert_equal('n', orig.mode)
exe 'nunmap ' .. a:keys
@@ -172,15 +172,16 @@ func One_mapset_test(keys)
call mapset('n', 0, orig)
let d = maparg(a:keys, 'n', 0, 1)
call assert_equal(a:keys, d.lhs)
- call assert_equal('original<CR>', d.rhs)
+ call assert_equal(a:rhs, d.rhs)
call assert_equal('n', d.mode)
exe 'nunmap ' .. a:keys
endfunc
func Test_mapset()
- call One_mapset_test('K')
- call One_mapset_test('<F3>')
+ call One_mapset_test('K', 'original<CR>')
+ call One_mapset_test('<F3>', 'original<CR>')
+ call One_mapset_test('<F3>', '<lt>Nop>')
" Check <> key conversion
new
@@ -203,6 +204,26 @@ func Test_mapset()
iunmap K
+ " Test that <Nop> is restored properly
+ inoremap K <Nop>
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('', getline(1))
+
+ let orig = maparg('K', 'i', 0, 1)
+ call assert_equal('K', orig.lhs)
+ call assert_equal('<Nop>', orig.rhs)
+ call assert_equal('i', orig.mode)
+
+ inoremap K foo
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('foo', getline(1))
+
+ call mapset('i', 0, orig)
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('', getline(1))
+
+ iunmap K
+
" Test literal <CR> using a backslash
let cpo_save = &cpo
set cpo-=B
diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index aa64006de0..96b86d053e 100644
--- a/test/functional/vimscript/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
@@ -3,6 +3,8 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
local expect = helpers.expect
local feed = helpers.feed
local funcs = helpers.funcs
@@ -10,6 +12,7 @@ local meths = helpers.meths
local nvim = helpers.nvim
local source = helpers.source
local command = helpers.command
+local pcall_err = helpers.pcall_err
describe('maparg()', function()
before_each(clear)
@@ -194,4 +197,43 @@ describe('mapset()', function()
feed('foo')
expect('<<lt><')
end)
+
+ it('can restore Lua callback from the dict returned by maparg()', function()
+ eq(0, exec_lua([[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]]))
+ feed('asdf')
+ eq(1, exec_lua([[return GlobalCount]]))
+
+ exec_lua([[
+ _G.saved_asdf_map = vim.fn.maparg('asdf', 'n', false, true)
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end })
+ ]])
+ feed('asdf')
+ eq(11, exec_lua([[return GlobalCount]]))
+
+ exec_lua([[vim.fn.mapset('n', false, _G.saved_asdf_map)]])
+ feed('asdf')
+ eq(12, exec_lua([[return GlobalCount]]))
+
+ exec([[
+ let g:saved_asdf_map = maparg('asdf', 'n', v:false, v:true)
+ lua vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end })
+ ]])
+ feed('asdf')
+ eq(22, exec_lua([[return GlobalCount]]))
+
+ command([[call mapset('n', v:false, g:saved_asdf_map)]])
+ feed('asdf')
+ eq(23, exec_lua([[return GlobalCount]]))
+ end)
+
+ it('does not leak memory if lhs is missing', function()
+ eq('Error executing lua: Vim:E460: entries missing in mapset() dict argument',
+ pcall_err(exec_lua, [[vim.fn.mapset('n', false, {rhs = 'foo'})]]))
+ eq('Error executing lua: Vim:E460: entries missing in mapset() dict argument',
+ pcall_err(exec_lua, [[vim.fn.mapset('n', false, {callback = function() end})]]))
+ end)
end)