Merge pull request #19602 from zeertzjq/vim-8.2.0807

vim-patch:8.2.{0807,0809,0812,0815,0832,1773,2804,4831,5106},9.0.0127: first part of mapset()
This commit is contained in:
zeertzjq 2022-08-01 22:19:30 +08:00 committed by GitHub
commit 8d1c55e422
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 441 additions and 169 deletions

View File

@ -295,6 +295,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])
rhs of mapping {name} in mode {mode}
mapcheck({name} [, {mode} [, {abbr}]])
String check for mappings matching {name}
mapset({mode}, {abbr}, {dict})
none restore mapping from |maparg()| result
match({expr}, {pat} [, {start} [, {count}]])
Number position where {pat} matches in {expr}
matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
@ -4716,6 +4718,7 @@ map({expr1}, {expr2}) *map()*
Can also be used as a |method|: >
mylist->map(expr2)
maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is omitted or zero: Return the rhs of mapping
{name} in mode {mode}. The returned String has special
@ -4749,7 +4752,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is there and it is |TRUE| return a dictionary
containing all the information of the mapping with the
following items:
"lhs" The {lhs} of the mapping.
"lhs" The {lhs} of the mapping as it would be typed
"lhsraw" The {lhs} of the mapping as raw bytes
"lhsrawalt" The {lhs} of the mapping as raw bytes, alternate
form, only present when it differs from "lhsraw"
"rhs" The {rhs} of the mapping as typed.
"silent" 1 for a |:map-silent| mapping, else 0.
"noremap" 1 if the {rhs} of the mapping is not remappable.
@ -4768,6 +4774,9 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
"nowait" Do not wait for other, longer mappings.
(|:map-<nowait>|).
The dictionary can be used to restore a mapping with
|mapset()|.
The mappings local to the current buffer are checked first,
then the global mappings.
This function can be used to map a key even when it's already
@ -4813,6 +4822,22 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()*
Can also be used as a |method|: >
GetKey()->mapcheck('n')
mapset({mode}, {abbr}, {dict}) *mapset()*
Restore a mapping from a dictionary returned by |maparg()|.
{mode} and {abbr} should be the same as for the call to
|maparg()|. *E460*
{mode} is used to define the mode in which the mapping is set,
not the "mode" entry in {dict}.
Example for saving and restoring a mapping: >
let save_map = maparg('K', 'n', 0, 1)
nnoremap K somethingelse
...
call mapset('n', 0, save_map)
< Note that if you are going to replace a map in several modes,
e.g. with `:map!`, you need to save the mapping for all of
them, since they can differe.
match({expr}, {pat} [, {start} [, {count}]]) *match()*
When {expr} is a |List| then this returns the index of the
first item where {pat} matches. Each item is used as a

View File

@ -2121,7 +2121,7 @@ void ex_loadkeymap(exarg_T *eap)
vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s",
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from,
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to);
(void)do_map(0, buf, MODE_LANGMAP, false);
(void)do_map(MAPTYPE_MAP, buf, MODE_LANGMAP, false);
}
p_cpo = save_cpo;
@ -2158,7 +2158,7 @@ static void keymap_unload(void)
for (int i = 0; i < curbuf->b_kmap_ga.ga_len; i++) {
vim_snprintf(buf, sizeof(buf), "<buffer> %s", kp[i].from);
(void)do_map(1, (char_u *)buf, MODE_LANGMAP, false);
(void)do_map(MAPTYPE_UNMAP, (char_u *)buf, MODE_LANGMAP, false);
}
keymap_ga_clear(&curbuf->b_kmap_ga);

View File

@ -250,6 +250,7 @@ return {
map={args=2, base=1},
maparg={args={1, 4}, base=1},
mapcheck={args={1, 3}, base=1},
mapset={args=3, base=1},
match={args={2, 4}, base=1},
matchadd={args={2, 5}, base=1},
matchaddpos={args={2, 5}, base=1},

View File

@ -428,6 +428,66 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
return 0;
}
/// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", "replace_keycodes" and
/// and "desc" fields are used.
/// "rhs", "rhs_lua", "orig_rhs" fields are cleared if "simplified" is false.
/// @param sid -1 to use current_sctx
static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char_u *keys,
MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid,
linenr_T lnum, bool simplified)
{
mapblock_T *mp = xcalloc(1, sizeof(mapblock_T));
// If CTRL-C has been mapped, don't always use it for Interrupting.
if (*keys == Ctrl_C) {
if (map_table == buf->b_maphash) {
buf->b_mapped_ctrl_c |= mode;
} else {
mapped_ctrl_c |= mode;
}
}
mp->m_keys = vim_strsave(keys);
mp->m_str = args->rhs;
mp->m_orig_str = args->orig_rhs;
mp->m_luaref = args->rhs_lua;
if (!simplified) {
args->rhs = NULL;
args->orig_rhs = NULL;
args->rhs_lua = LUA_NOREF;
}
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_simplified = simplified;
mp->m_expr = args->expr;
mp->m_replace_keycodes = args->replace_keycodes;
if (sid >= 0) {
mp->m_script_ctx.sc_sid = sid;
mp->m_script_ctx.sc_lnum = lnum;
} else {
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
nlua_set_sctx(&mp->m_script_ctx);
}
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
if (is_abbr) {
mp->m_next = *abbr_table;
*abbr_table = mp;
} else {
const int n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
mp->m_next = map_table[n];
map_table[n] = mp;
}
}
/// Sets or removes a mapping or abbreviation in buffer `buf`.
///
/// @param maptype @see do_map
@ -452,7 +512,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
abbr_table = &first_abbr;
// For ":noremap" don't remap, otherwise do remap.
if (maptype == 2) {
if (maptype == MAPTYPE_NOREMAP) {
noremap = REMAP_NONE;
} else {
noremap = REMAP_YES;
@ -470,10 +530,10 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
const bool has_lhs = (args->lhs[0] != NUL);
const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
const bool do_print = !has_lhs || (maptype != 1 && !has_rhs);
const bool do_print = !has_lhs || (maptype != MAPTYPE_UNMAP && !has_rhs);
// check for :unmap without argument
if (maptype == 1 && !has_lhs) {
if (maptype == MAPTYPE_UNMAP && !has_lhs) {
retval = 1;
goto theend;
}
@ -507,13 +567,11 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
goto theend;
}
if (is_abbrev && maptype != 1) {
//
if (is_abbrev && maptype != MAPTYPE_UNMAP) {
// If an abbreviation ends in a keyword character, the
// rest must be all keyword-char or all non-keyword-char.
// Otherwise we won't be able to find the start of it in a
// vi-compatible way.
//
int same = -1;
const int first = vim_iswordp(lhs);
@ -551,7 +609,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// Check if a new local mapping wasn't already defined globally.
if (args->unique && map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) {
if (args->unique && map_table == buf->b_maphash && has_lhs && has_rhs
&& maptype != MAPTYPE_UNMAP) {
// need to loop over all global hash lists
for (int hash = 0; hash < 256 && !got_int; hash++) {
if (is_abbrev) {
@ -581,7 +640,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// When listing global mappings, also list buffer-local ones here.
if (map_table != buf->b_maphash && !has_rhs && maptype != 1) {
if (map_table != buf->b_maphash && !has_rhs && maptype != MAPTYPE_UNMAP) {
// need to loop over all global hash lists
for (int hash = 0; hash < 256 && !got_int; hash++) {
if (is_abbrev) {
@ -616,7 +675,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
// entry with a matching 'to' part. This was done to allow ":ab foo bar"
// to be unmapped by typing ":unab foo", where "foo" will be replaced by
// "bar" because of the abbreviation.
for (int round = 0; (round == 0 || maptype == 1) && round <= 1
for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
&& !did_it && !got_int; round++) {
int hash_start, hash_end;
if (has_lhs || is_abbrev) {
@ -650,7 +709,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
p = mp->m_keys;
}
if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) {
if (maptype == 1) {
if (maptype == MAPTYPE_UNMAP) {
// Delete entry.
// Only accept a full match. For abbreviations
// we ignore trailing space when matching with
@ -746,7 +805,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
}
if (maptype == 1) {
if (maptype == MAPTYPE_UNMAP) {
// delete entry
if (!did_it) {
if (!keyround1_simplified) {
@ -780,51 +839,10 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// Get here when adding a new entry to the maphash[] list or abbrlist.
mp = xmalloc(sizeof(mapblock_T));
// If CTRL-C has been mapped, don't always use it for Interrupting.
if (*lhs == Ctrl_C) {
if (map_table == buf->b_maphash) {
buf->b_mapped_ctrl_c |= mode;
} else {
mapped_ctrl_c |= mode;
}
}
mp->m_keys = vim_strsave(lhs);
mp->m_str = args->rhs;
mp->m_orig_str = args->orig_rhs;
mp->m_luaref = args->rhs_lua;
if (!keyround1_simplified) {
args->rhs = NULL;
args->orig_rhs = NULL;
args->rhs_lua = LUA_NOREF;
}
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_simplified = keyround1_simplified; // Notice this when porting patch 8.2.0807
mp->m_expr = args->expr;
mp->m_replace_keycodes = args->replace_keycodes;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
nlua_set_sctx(&mp->m_script_ctx);
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
if (is_abbrev) {
mp->m_next = *abbr_table;
*abbr_table = mp;
} else {
n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
mp->m_next = map_table[n];
map_table[n] = mp;
}
map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev,
-1, // sid
0, // lnum
keyround1_simplified);
}
theend:
@ -863,7 +881,9 @@ theend:
/// for :cabbr mode is MODE_CMDLINE
/// ```
///
/// @param maptype 0 for |:map|, 1 for |:unmap|, 2 for |noremap|.
/// @param maptype MAPTYPE_MAP for |:map|
/// MAPTYPE_UNMAP for |:unmap|
/// MAPTYPE_NOREMAP for |noremap|.
/// @param arg C-string containing the arguments of the map/abbrev
/// command, i.e. everything except the initial `:[X][nore]map`.
/// - Cannot be a read-only string; it will be modified.
@ -880,7 +900,7 @@ theend:
int do_map(int maptype, char_u *arg, int mode, bool is_abbrev)
{
MapArguments parsed_args;
int result = str_to_mapargs(arg, maptype == 1, &parsed_args);
int result = str_to_mapargs(arg, maptype == MAPTYPE_UNMAP, &parsed_args);
switch (result) {
case 0:
break;
@ -1977,9 +1997,9 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// @param mp The maphash that contains the mapping information
/// @param buffer_value The "buffer" value
/// @param compatible True for compatible with old maparg() dict
static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buffer_value,
bool compatible)
FUNC_ATTR_NONNULL_ALL
static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp,
const char *lhsrawalt, long buffer_value, bool compatible)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
char *const lhs = str2special_save((const char *)mp->m_keys,
compatible, !compatible);
@ -2011,6 +2031,11 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, l
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_str(dict, S_LEN("lhsraw"), (const char *)mp->m_keys);
if (lhsrawalt != NULL) {
// Also add the value for the simplified entry.
tv_dict_add_str(dict, S_LEN("lhsrawalt"), lhsrawalt);
}
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
tv_dict_add_nr(dict, S_LEN("script"), mp->m_noremap == REMAP_SCRIPT ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
@ -2027,18 +2052,6 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, l
static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
{
char *keys_buf = NULL;
char_u *alt_keys_buf = NULL;
bool did_simplify = false;
char_u *rhs;
LuaRef rhs_lua;
int mode;
bool abbr = false;
bool get_dict = false;
mapblock_T *mp = NULL;
int buffer_local;
int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
// Return empty string for failure.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@ -2048,8 +2061,11 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
return;
}
char buf[NUMBUFLEN];
const char *which;
char buf[NUMBUFLEN];
bool abbr = false;
bool get_dict = false;
if (argvars[1].v_type != VAR_UNKNOWN) {
which = tv_get_string_buf_chk(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
@ -2065,13 +2081,19 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
return;
}
mode = get_map_mode((char **)&which, 0);
char *keys_buf = NULL;
char_u *alt_keys_buf = NULL;
bool did_simplify = false;
const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
const int mode = get_map_mode((char **)&which, 0);
char_u *keys_simplified
= (char_u *)replace_termcodes(keys,
STRLEN(keys), &keys_buf, flags, &did_simplify,
= (char_u *)replace_termcodes(keys, STRLEN(keys), &keys_buf, flags, &did_simplify,
CPO_TO_CPO_FLAGS);
rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
mapblock_T *mp = NULL;
int buffer_local;
LuaRef rhs_lua;
char_u *rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
if (did_simplify) {
// When the lhs is being simplified the not-simplified keys are
// preferred for printing, like in do_map().
@ -2100,7 +2122,8 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
tv_dict_alloc_ret(rettv);
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
// Return a dictionary.
mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
mapblock_fill_dict(rettv->vval.v_dict, mp, did_simplify ? (char *)keys_simplified : NULL,
buffer_local, true);
}
}
@ -2108,6 +2131,74 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(alt_keys_buf);
}
/// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char buf[NUMBUFLEN];
const char *which = tv_get_string_buf_chk(&argvars[0], buf);
if (which == NULL) {
return;
}
const int mode = get_map_mode((char **)&which, 0);
const bool is_abbr = tv_get_number(&argvars[1]) != 0;
if (argvars[2].v_type != VAR_DICT) {
emsg(_(e_dictreq));
return;
}
dict_T *d = argvars[2].vval.v_dict;
// Get the values in the same order as above in get_maparg().
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) {
emsg(_("E460: entries missing in mapset() dict argument"));
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;
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),
.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),
};
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;
// mode from the dict is not used
mapblock_T **map_table = buffer ? curbuf->b_maphash : maphash;
mapblock_T **abbr_table = buffer ? &curbuf->b_first_abbr : &first_abbr;
// 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);
unmap_args.buffer = buffer;
buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, false, curbuf);
xfree(unmap_args.rhs);
xfree(unmap_args.orig_rhs);
if (lhsrawalt != NULL) {
map_add(curbuf, map_table, abbr_table, (char_u *)lhsrawalt, &args, noremap, mode, is_abbr,
sid, lnum, true);
}
map_add(curbuf, map_table, abbr_table, (char_u *)lhsraw, &args, noremap, mode, is_abbr,
sid, lnum, false);
}
/// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@ -2130,11 +2221,11 @@ void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// @param buffer If true, make a buffer-local mapping for curbuf
void add_map(char *lhs, char *rhs, int mode, bool buffer)
{
MapArguments args = { 0 };
MapArguments args = MAP_ARGUMENTS_INIT;
set_maparg_lhs_rhs(lhs, strlen(lhs), rhs, strlen(rhs), LUA_NOREF, 0, &args);
args.buffer = buffer;
buf_do_map(2, &args, mode, false, curbuf);
buf_do_map(MAPTYPE_NOREMAP, &args, mode, false, curbuf);
xfree(args.rhs);
xfree(args.orig_rhs);
}
@ -2314,7 +2405,8 @@ static void do_exmap(exarg_T *eap, int isabbrev)
char *cmdp = eap->cmd;
mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
switch (do_map((*cmdp == 'n') ? MAPTYPE_NOREMAP
: (*cmdp == 'u') ? MAPTYPE_UNMAP : MAPTYPE_MAP,
(char_u *)eap->arg, mode, isabbrev)) {
case 1:
emsg(_(e_invarg));
@ -2474,11 +2566,11 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
}
// buf_do_map() reads noremap/unmap as its own argument.
int maptype_val = 0;
int maptype_val = MAPTYPE_MAP;
if (is_unmap) {
maptype_val = 1;
maptype_val = MAPTYPE_UNMAP;
} else if (is_noremap) {
maptype_val = 2;
maptype_val = MAPTYPE_NOREMAP;
}
switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) {
@ -2536,7 +2628,7 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
}
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
mapblock_fill_dict(dict, current_maphash, NULL, buffer_value, false);
Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT,
.vval.v_dict = dict } });
if (from_lua) {

View File

@ -48,6 +48,11 @@ typedef struct map_arguments MapArguments;
#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, false, \
{ 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
// Used for the first argument of do_map()
#define MAPTYPE_MAP 0
#define MAPTYPE_UNMAP 1
#define MAPTYPE_NOREMAP 2
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mapping.h.generated.h"
#endif

View File

@ -1,12 +1,12 @@
" Tests for maparg().
" Tests for maparg(), mapcheck() and mapset().
" Also test utf8 map with a 0x80 byte.
" Also test mapcheck()
function s:SID()
func s:SID()
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
endfun
endfunc
function Test_maparg()
func Test_maparg()
new
set cpo-=<
set encoding=utf8
@ -17,24 +17,28 @@ function Test_maparg()
vnoremap <script> <buffer> <expr> <silent> bar isbar
call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>',
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0},
\ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v',
\ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0},
\ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
\ 'lhsraw': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
\ 'rhs': 'isbar', 'buffer': 1},
\ 'rhs': 'isbar', 'buffer': 1},
\ 'bar'->maparg('', 0, 1))
let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ',
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo',
\ 'lhsraw': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
\ 'buffer': 1},
\ 'buffer': 1},
\ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>')
tmap baz foo
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't',
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz',
\ 'lhsraw': 'baz', 'mode': 't',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
\ 'buffer': 0},
\ 'buffer': 0},
\ maparg('baz', 't', 0, 1))
map abc x<char-114>x
@ -81,6 +85,12 @@ function Test_maparg()
call assert_equal(['{', 'w', 's'], [d.lhs, d.rhs, d.mode])
sunmap {
map <C-I> foo
unmap <Tab>
" This used to cause a segfault
call maparg('<C-I>', '', 0, 1)
unmap <C-I>
map abc <Nop>
call assert_equal("<Nop>", maparg('abc'))
unmap abc
@ -89,7 +99,8 @@ function Test_maparg()
let d = maparg('esc', 'i', 1, 1)
call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode])
abclear
endfunction
unlet d
endfunc
func Test_mapcheck()
call assert_equal('', mapcheck('a'))
@ -130,7 +141,7 @@ func Test_mapcheck()
unabbr ab
endfunc
function Test_range_map()
func Test_range_map()
new
" Outside of the range, minimum
inoremap <Char-0x1040> a
@ -145,6 +156,147 @@ function Test_range_map()
inoremap <Char-0xf040> d
execute "normal a\uf040\<Esc>"
call assert_equal("abcd", getline(1))
endfunction
endfunc
func One_mapset_test(keys)
exe 'nnoremap ' .. a:keys .. ' original<CR>'
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('n', orig.mode)
exe 'nunmap ' .. a:keys
let d = maparg(a:keys, 'n', 0, 1)
call assert_equal({}, d)
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('n', d.mode)
exe 'nunmap ' .. a:keys
endfunc
func Test_mapset()
call One_mapset_test('K')
call One_mapset_test('<F3>')
" Check <> key conversion
new
inoremap K one<Left>x
call feedkeys("iK\<Esc>", 'xt')
call assert_equal('onxe', getline(1))
let orig = maparg('K', 'i', 0, 1)
call assert_equal('K', orig.lhs)
call assert_equal('one<Left>x', orig.rhs)
call assert_equal('i', orig.mode)
iunmap K
let d = maparg('K', 'i', 0, 1)
call assert_equal({}, d)
call mapset('i', 0, orig)
call feedkeys("SK\<Esc>", 'xt')
call assert_equal('onxe', getline(1))
iunmap K
" Test literal <CR> using a backslash
let cpo_save = &cpo
set cpo-=B
inoremap K one\<CR>two
call feedkeys("SK\<Esc>", 'xt')
call assert_equal('one<CR>two', getline(1))
let orig = maparg('K', 'i', 0, 1)
call assert_equal('K', orig.lhs)
call assert_equal('one\<CR>two', orig.rhs)
call assert_equal('i', orig.mode)
iunmap K
let d = maparg('K', 'i', 0, 1)
call assert_equal({}, d)
call mapset('i', 0, orig)
call feedkeys("SK\<Esc>", 'xt')
call assert_equal('one<CR>two', getline(1))
iunmap K
" Test literal <CR> using CTRL-V
inoremap K one<CR>two
call feedkeys("SK\<Esc>", 'xt')
call assert_equal('one<CR>two', getline(1))
let orig = maparg('K', 'i', 0, 1)
call assert_equal('K', orig.lhs)
call assert_equal("one\x16<CR>two", orig.rhs)
call assert_equal('i', orig.mode)
iunmap K
let d = maparg('K', 'i', 0, 1)
call assert_equal({}, d)
call mapset('i', 0, orig)
call feedkeys("SK\<Esc>", 'xt')
call assert_equal('one<CR>two', getline(1))
iunmap K
let &cpo = cpo_save
bwipe!
call assert_fails('call mapset([], v:false, {})', 'E730:')
endfunc
func Check_ctrlb_map(d, check_alt)
call assert_equal('<C-B>', a:d.lhs)
if a:check_alt
call assert_equal("\x80\xfc\x04B", a:d.lhsraw)
call assert_equal("\x02", a:d.lhsrawalt)
else
call assert_equal("\x02", a:d.lhsraw)
endif
endfunc
func Test_map_local()
nmap a global
nmap <buffer>a local
let prev_map_list = split(execute('nmap a'), "\n")
call assert_match('n\s*a\s*@local', prev_map_list[0])
call assert_match('n\s*a\s*global', prev_map_list[1])
let mapping = maparg('a', 'n', 0, 1)
call assert_equal(1, mapping.buffer)
let mapping.rhs = 'new_local'
call mapset('n', 0, mapping)
" Check that the global mapping is left untouched.
let map_list = split(execute('nmap a'), "\n")
call assert_match('n\s*a\s*@new_local', map_list[0])
call assert_match('n\s*a\s*global', map_list[1])
nunmap a
endfunc
func Test_map_restore()
" Test restoring map with alternate keycode
nmap <C-B> back
let d = maparg('<C-B>', 'n', 0, 1)
call Check_ctrlb_map(d, 1)
let dsimp = maparg("\x02", 'n', 0, 1)
call Check_ctrlb_map(dsimp, 0)
nunmap <C-B>
call mapset('n', 0, d)
let d = maparg('<C-B>', 'n', 0, 1)
call Check_ctrlb_map(d, 1)
let dsimp = maparg("\x02", 'n', 0, 1)
call Check_ctrlb_map(dsimp, 0)
nunmap <C-B>
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -25,6 +25,7 @@ describe('nvim_get_keymap', function()
local foo_bar_string = 'nnoremap foo bar'
local foo_bar_map_table = {
lhs='foo',
lhsraw='foo',
script=0,
silent=0,
rhs='bar',
@ -56,6 +57,7 @@ describe('nvim_get_keymap', function()
command('nnoremap foo_longer bar_longer')
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
foolong_bar_map_table['lhs'] = 'foo_longer'
foolong_bar_map_table['lhsraw'] = 'foo_longer'
foolong_bar_map_table['rhs'] = 'bar_longer'
eq({foolong_bar_map_table, foo_bar_map_table},
@ -87,6 +89,7 @@ describe('nvim_get_keymap', function()
command('nnoremap foo_longer bar_longer')
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
foolong_bar_map_table['lhs'] = 'foo_longer'
foolong_bar_map_table['lhsraw'] = 'foo_longer'
foolong_bar_map_table['rhs'] = 'bar_longer'
local buffer_table = shallowcopy(foo_bar_map_table)
@ -283,6 +286,16 @@ describe('nvim_get_keymap', function()
command('onoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
command('onoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
-- wrapper around get_keymap() that drops "lhsraw" and "lhsrawalt" which are hard to check
local function get_keymap_noraw(...)
local ret = meths.get_keymap(...)
for _, item in ipairs(ret) do
item.lhsraw = nil
item.lhsrawalt = nil
end
return ret
end
for _, cmd in ipairs({
'set cpo-=B',
'set cpo+=B',
@ -290,22 +303,23 @@ describe('nvim_get_keymap', function()
command(cmd)
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'n'),
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'n')},
meths.get_keymap('n'))
get_keymap_noraw('n'))
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'x'),
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'x')},
meths.get_keymap('x'))
get_keymap_noraw('x'))
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 's'),
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 's')},
meths.get_keymap('s'))
get_keymap_noraw('s'))
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 'o'),
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 'o')},
meths.get_keymap('o'))
get_keymap_noraw('o'))
end
end)
it('always uses space for space and bar for bar', function()
local space_table = {
lhs='| |',
lhsraw='| |',
rhs='| |',
mode='n',
script=0,
@ -340,6 +354,7 @@ describe('nvim_get_keymap', function()
mapargs[1].callback = nil
eq({
lhs='asdf',
lhsraw='asdf',
script=0,
silent=0,
expr=0,
@ -356,6 +371,7 @@ describe('nvim_get_keymap', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
eq({
lhs='lhs',
lhsraw='lhs',
rhs='rhs',
script=0,
silent=0,
@ -413,7 +429,11 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
-- Gets a maparg() dict from Nvim, if one exists.
local function get_mapargs(mode, lhs)
return funcs.maparg(lhs, normalize_mapmode(mode), false, true)
local mapargs = funcs.maparg(lhs, normalize_mapmode(mode), false, true)
-- drop "lhsraw" and "lhsrawalt" which are hard to check
mapargs.lhsraw = nil
mapargs.lhsrawalt = nil
return mapargs
end
it('error on empty LHS', function()
@ -817,6 +837,8 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
local mapargs = funcs.maparg('asdf', 'n', false, true)
assert(type(mapargs.callback) == 'number', 'callback is not luaref number')
mapargs.callback = nil
mapargs.lhsraw = nil
mapargs.lhsrawalt = nil
eq(generate_mapargs('n', 'asdf', nil, {sid=sid_lua}), mapargs)
end)

View File

@ -1,59 +0,0 @@
-- Tests for maparg().
-- Also test utf8 map with a 0x80 byte.
local helpers = require('test.functional.helpers')(after_each)
local clear, feed = helpers.clear, helpers.feed
local command, expect = helpers.command, helpers.expect
local poke_eventloop = helpers.poke_eventloop
describe('maparg()', function()
setup(clear)
it('is working', function()
command('set cpo-=<')
-- Test maparg() with a string result
command('map foo<C-V> is<F4>foo')
command('vnoremap <script> <buffer> <expr> <silent> bar isbar')
command([[call append('$', maparg('foo<C-V>'))]])
command([[call append('$', string(maparg('foo<C-V>', '', 0, 1)))]])
command([[call append('$', string(maparg('bar', '', 0, 1)))]])
command('map <buffer> <nowait> foo bar')
command([[call append('$', string(maparg('foo', '', 0, 1)))]])
command('map abc x<char-114>x')
command([[call append('$', maparg('abc'))]])
command('map abc y<S-char-114>y')
command([[call append('$', maparg('abc'))]])
feed('Go<esc>:<cr>')
poke_eventloop()
-- Outside of the range, minimum
command('inoremap <Char-0x1040> a')
command([[execute "normal a\u1040\<Esc>"]])
-- Inside of the range, minimum
command('inoremap <Char-0x103f> b')
command([[execute "normal a\u103f\<Esc>"]])
-- Inside of the range, maximum
command('inoremap <Char-0xf03f> c')
command([[execute "normal a\uf03f\<Esc>"]])
-- Outside of the range, maximum
command('inoremap <Char-0xf040> d')
command([[execute "normal a\uf040\<Esc>"]])
-- Remove empty line
command('1d')
-- Assert buffer contents.
expect([[
is<F4>foo
{'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0}
{'lnum': 0, 'script': 1, 'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'nowait': 0, 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1}
{'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ', 'nowait': 1, 'expr': 0, 'sid': 0, 'rhs': 'bar', 'buffer': 1}
xrx
yRy
abcd]])
end)
end)

View File

@ -3,7 +3,10 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local expect = helpers.expect
local feed = helpers.feed
local funcs = helpers.funcs
local meths = helpers.meths
local nvim = helpers.nvim
local source = helpers.source
local command = helpers.command
@ -13,6 +16,7 @@ describe('maparg()', function()
local foo_bar_map_table = {
lhs='foo',
lhsraw='foo',
script=0,
silent=0,
rhs='bar',
@ -141,6 +145,7 @@ describe('maparg()', function()
local function acmap(lhs, rhs)
return {
lhs = ac(lhs),
lhsraw = ac(lhs),
rhs = ac(rhs),
buffer = 0,
@ -161,3 +166,32 @@ describe('maparg()', function()
eq(acmap('e`', 'f`'), funcs.maparg(ac('e`'), 'n', 0, 1))
end)
end)
describe('mapset()', function()
before_each(clear)
it('can restore mapping description from the dict returned by maparg()', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc = 'map description'})
eq('\nn lhs rhs\n map description',
helpers.exec_capture("nmap lhs"))
local mapargs = funcs.maparg('lhs', 'n', false, true)
meths.del_keymap('n', 'lhs')
eq('\nNo mapping found', helpers.exec_capture("nmap lhs"))
funcs.mapset('n', false, mapargs)
eq('\nn lhs rhs\n map description',
helpers.exec_capture("nmap lhs"))
end)
it('can restore "replace_keycodes" from the dict returned by maparg()', function()
meths.set_keymap('i', 'foo', [['<l' .. 't>']], {expr = true, replace_keycodes = true})
feed('Afoo')
expect('<')
local mapargs = funcs.maparg('foo', 'i', false, true)
meths.set_keymap('i', 'foo', [['<l' .. 't>']], {expr = true})
feed('foo')
expect('<<lt>')
funcs.mapset('i', false, mapargs)
feed('foo')
expect('<<lt><')
end)
end)