mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
vim-patch:9.1.0642: Check that mapping rhs starts with lhs fails if not simplified (#29909)
Problem: Check that mapping rhs starts with lhs doesn't work if lhs is
not simplified.
Solution: Keep track of the mapblock containing the alternative lhs and
also compare with it (zeertzjq).
fixes: vim/vim#15376
closes: vim/vim#15384
9d997addc7
Cherry-pick removal of save_m_str from patch 8.2.4059.
This commit is contained in:
@@ -2341,8 +2341,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|
||||
const int save_m_noremap = mp->m_noremap;
|
||||
const bool save_m_silent = mp->m_silent;
|
||||
char *save_m_keys = NULL; // only saved when needed
|
||||
char *save_m_str = NULL; // only saved when needed
|
||||
const LuaRef save_m_luaref = mp->m_luaref;
|
||||
char *save_alt_m_keys = NULL; // only saved when needed
|
||||
|
||||
// Handle ":map <expr>": evaluate the {rhs} as an
|
||||
// expression. Also save and restore the command line
|
||||
@@ -2356,9 +2355,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|
||||
may_garbage_collect = false;
|
||||
|
||||
save_m_keys = xstrdup(mp->m_keys);
|
||||
if (save_m_luaref == LUA_NOREF) {
|
||||
save_m_str = xstrdup(mp->m_str);
|
||||
}
|
||||
save_alt_m_keys = mp->m_alt != NULL ? xstrdup(mp->m_alt->m_keys) : NULL;
|
||||
map_str = eval_map_expr(mp, NUL);
|
||||
|
||||
if ((map_str == NULL || *map_str == NUL)) {
|
||||
@@ -2409,11 +2406,18 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|
||||
|
||||
if (save_m_noremap != REMAP_YES) {
|
||||
noremap = save_m_noremap;
|
||||
} else if (strncmp(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys,
|
||||
(size_t)keylen) != 0) {
|
||||
noremap = REMAP_YES;
|
||||
} else {
|
||||
} else if (save_m_expr
|
||||
? strncmp(map_str, save_m_keys, (size_t)keylen) == 0
|
||||
|| (save_alt_m_keys != NULL
|
||||
&& strncmp(map_str, save_alt_m_keys,
|
||||
strlen(save_alt_m_keys)) == 0)
|
||||
: strncmp(map_str, mp->m_keys, (size_t)keylen) == 0
|
||||
|| (mp->m_alt != NULL
|
||||
&& strncmp(map_str, mp->m_alt->m_keys,
|
||||
strlen(mp->m_alt->m_keys)) == 0)) {
|
||||
noremap = REMAP_SKIP;
|
||||
} else {
|
||||
noremap = REMAP_YES;
|
||||
}
|
||||
i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent);
|
||||
if (save_m_expr) {
|
||||
@@ -2421,7 +2425,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|
||||
}
|
||||
}
|
||||
xfree(save_m_keys);
|
||||
xfree(save_m_str);
|
||||
xfree(save_alt_m_keys);
|
||||
*keylenp = keylen;
|
||||
if (i == FAIL) {
|
||||
return map_result_fail;
|
||||
|
@@ -151,7 +151,9 @@ static void mapblock_free(mapblock_T **mpp)
|
||||
{
|
||||
mapblock_T *mp = *mpp;
|
||||
xfree(mp->m_keys);
|
||||
if (!mp->m_simplified) {
|
||||
if (mp->m_alt != NULL) {
|
||||
mp->m_alt->m_alt = NULL;
|
||||
} else {
|
||||
NLUA_CLEAR_REF(mp->m_luaref);
|
||||
xfree(mp->m_str);
|
||||
xfree(mp->m_orig_str);
|
||||
@@ -493,13 +495,13 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa
|
||||
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 args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait",
|
||||
/// "replace_keycodes" and "desc" fields are used.
|
||||
/// @param sid 0 to use current_sctx
|
||||
static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char *keys,
|
||||
MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid,
|
||||
linenr_T lnum, bool simplified)
|
||||
static mapblock_T *map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
|
||||
const char *keys, MapArguments *args, int noremap, int mode,
|
||||
bool is_abbr, scid_T sid, linenr_T lnum, bool simplified)
|
||||
FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
mapblock_T *mp = xcalloc(1, sizeof(mapblock_T));
|
||||
|
||||
@@ -516,11 +518,6 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
|
||||
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;
|
||||
@@ -551,6 +548,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table,
|
||||
mp->m_next = map_table[n];
|
||||
map_table[n] = mp;
|
||||
}
|
||||
return mp;
|
||||
}
|
||||
|
||||
/// Sets or removes a mapping or abbreviation in buffer `buf`.
|
||||
@@ -571,6 +569,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
|
||||
// mappings/abbreviations, not the globals.
|
||||
mapblock_T **map_table = args->buffer ? buf->b_maphash : maphash;
|
||||
mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr;
|
||||
mapblock_T *mp_result[2] = { NULL, NULL };
|
||||
|
||||
// For ":noremap" don't remap, otherwise do remap.
|
||||
int noremap = args->script ? REMAP_SCRIPT
|
||||
@@ -805,19 +804,16 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
|
||||
mp->m_mode &= ~mode; // remove mode bits
|
||||
if (mp->m_mode == 0 && !did_it) { // reuse entry
|
||||
XFREE_CLEAR(mp->m_desc);
|
||||
if (!mp->m_simplified) {
|
||||
if (mp->m_alt != NULL) {
|
||||
mp->m_alt = mp->m_alt->m_alt = NULL;
|
||||
} else {
|
||||
NLUA_CLEAR_REF(mp->m_luaref);
|
||||
XFREE_CLEAR(mp->m_str);
|
||||
XFREE_CLEAR(mp->m_orig_str);
|
||||
xfree(mp->m_str);
|
||||
xfree(mp->m_orig_str);
|
||||
}
|
||||
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_noremap = noremap;
|
||||
mp->m_nowait = args->nowait;
|
||||
mp->m_silent = args->silent;
|
||||
@@ -831,6 +827,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
|
||||
if (args->desc != NULL) {
|
||||
mp->m_desc = xstrdup(args->desc);
|
||||
}
|
||||
mp_result[keyround - 1] = mp;
|
||||
did_it = true;
|
||||
}
|
||||
}
|
||||
@@ -889,13 +886,24 @@ 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.
|
||||
map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev,
|
||||
0, // sid
|
||||
0, // lnum
|
||||
keyround1_simplified);
|
||||
mp_result[keyround - 1] = map_add(buf, map_table, abbr_table, lhs,
|
||||
args, noremap, mode, is_abbrev,
|
||||
0, // sid
|
||||
0, // lnum
|
||||
keyround1_simplified);
|
||||
}
|
||||
|
||||
if (mp_result[0] != NULL && mp_result[1] != NULL) {
|
||||
mp_result[0]->m_alt = mp_result[1];
|
||||
mp_result[1]->m_alt = mp_result[0];
|
||||
}
|
||||
|
||||
theend:
|
||||
if (mp_result[0] != NULL || mp_result[1] != NULL) {
|
||||
args->rhs = NULL;
|
||||
args->orig_rhs = NULL;
|
||||
args->rhs_lua = LUA_NOREF;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -2348,12 +2356,19 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
xfree(unmap_args.rhs);
|
||||
xfree(unmap_args.orig_rhs);
|
||||
|
||||
mapblock_T *mp_result[2] = { NULL, NULL };
|
||||
|
||||
mp_result[0] = map_add(curbuf, map_table, abbr_table, lhsraw, &args,
|
||||
noremap, mode, is_abbr, sid, lnum, false);
|
||||
if (lhsrawalt != NULL) {
|
||||
map_add(curbuf, map_table, abbr_table, lhsrawalt, &args, noremap, mode, is_abbr,
|
||||
sid, lnum, true);
|
||||
mp_result[1] = map_add(curbuf, map_table, abbr_table, lhsrawalt, &args,
|
||||
noremap, mode, is_abbr, sid, lnum, true);
|
||||
}
|
||||
|
||||
if (mp_result[0] != NULL && mp_result[1] != NULL) {
|
||||
mp_result[0]->m_alt = mp_result[1];
|
||||
mp_result[1]->m_alt = mp_result[0];
|
||||
}
|
||||
map_add(curbuf, map_table, abbr_table, lhsraw, &args, noremap, mode, is_abbr,
|
||||
sid, lnum, false);
|
||||
}
|
||||
|
||||
/// "maplist()" function
|
||||
|
@@ -10,6 +10,9 @@ enum { MAXMAPLEN = 50, }; ///< Maximum length of key sequence to be mapped.
|
||||
typedef struct mapblock mapblock_T;
|
||||
struct mapblock {
|
||||
mapblock_T *m_next; ///< next mapblock in list
|
||||
mapblock_T *m_alt; ///< pointer to mapblock of the same mapping
|
||||
///< with an alternative form of m_keys, or NULL
|
||||
///< if there is no such mapblock
|
||||
char *m_keys; ///< mapped from, lhs
|
||||
char *m_str; ///< mapped to, rhs
|
||||
char *m_orig_str; ///< rhs as entered by the user
|
||||
|
@@ -1672,6 +1672,49 @@ func Test_unmap_simplifiable()
|
||||
unmap <C-I>
|
||||
endfunc
|
||||
|
||||
" Test that the first byte of rhs is not remapped if rhs starts with lhs.
|
||||
func Test_map_rhs_starts_with_lhs()
|
||||
new
|
||||
func MapExpr()
|
||||
return "\<C-R>\<C-P>"
|
||||
endfunc
|
||||
|
||||
for expr in [v:false, v:true]
|
||||
if expr
|
||||
imap <buffer><expr> <C-R> MapExpr()
|
||||
else
|
||||
imap <buffer> <C-R> <C-R><C-P>
|
||||
endif
|
||||
|
||||
for restore in [v:false, v:true]
|
||||
if restore
|
||||
let saved = maparg('<C-R>', 'i', v:false, v:true)
|
||||
iunmap <buffer> <C-R>
|
||||
call mapset(saved)
|
||||
endif
|
||||
|
||||
let @a = 'foo'
|
||||
call feedkeys("S\<C-R>a", 'tx')
|
||||
call assert_equal('foo', getline('.'))
|
||||
|
||||
let @a = 'bar'
|
||||
call feedkeys("S\<*C-R>a", 'tx')
|
||||
call assert_equal('bar', getline('.'))
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" When two mappings are used for <C-I> and <Tab>, remapping should work.
|
||||
imap <buffer> <C-I> <Tab>bar
|
||||
imap <buffer> <Tab> foo
|
||||
call feedkeys("S\<Tab>", 'xt')
|
||||
call assert_equal('foo', getline('.'))
|
||||
call feedkeys("S\<*C-I>", 'xt')
|
||||
call assert_equal('foobar', getline('.'))
|
||||
|
||||
delfunc MapExpr
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_expr_map_escape_special()
|
||||
nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
|
||||
func Func()
|
||||
|
Reference in New Issue
Block a user