mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 9.1.0642: Check that mapping rhs starts with lhs fails if not simplified
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: #15376 closes: #15384 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
baaf6deb95
commit
9d997addc7
@ -3156,6 +3156,7 @@ handle_mapping(
|
|||||||
int save_m_noremap;
|
int save_m_noremap;
|
||||||
int save_m_silent;
|
int save_m_silent;
|
||||||
char_u *save_m_keys;
|
char_u *save_m_keys;
|
||||||
|
char_u *save_alt_m_keys;
|
||||||
#else
|
#else
|
||||||
# define save_m_noremap mp->m_noremap
|
# define save_m_noremap mp->m_noremap
|
||||||
# define save_m_silent mp->m_silent
|
# define save_m_silent mp->m_silent
|
||||||
@ -3204,6 +3205,7 @@ handle_mapping(
|
|||||||
save_m_noremap = mp->m_noremap;
|
save_m_noremap = mp->m_noremap;
|
||||||
save_m_silent = mp->m_silent;
|
save_m_silent = mp->m_silent;
|
||||||
save_m_keys = NULL; // only saved when needed
|
save_m_keys = NULL; // only saved when needed
|
||||||
|
save_alt_m_keys = NULL; // only saved when needed
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle ":map <expr>": evaluate the {rhs} as an expression. Also
|
* Handle ":map <expr>": evaluate the {rhs} as an expression. Also
|
||||||
@ -3221,6 +3223,8 @@ handle_mapping(
|
|||||||
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_alt_m_keys = mp->m_alt != NULL
|
||||||
|
? vim_strsave(mp->m_alt->m_keys) : NULL;
|
||||||
map_str = eval_map_expr(mp, NUL);
|
map_str = eval_map_expr(mp, NUL);
|
||||||
|
|
||||||
// The mapping may do anything, but we expect it to take care of
|
// The mapping may do anything, but we expect it to take care of
|
||||||
@ -3278,15 +3282,20 @@ handle_mapping(
|
|||||||
noremap = save_m_noremap;
|
noremap = save_m_noremap;
|
||||||
else if (
|
else if (
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys,
|
save_m_expr ?
|
||||||
(size_t)keylen)
|
(save_m_keys != NULL
|
||||||
#else
|
&& STRNCMP(map_str, save_m_keys, (size_t)keylen) == 0)
|
||||||
STRNCMP(map_str, mp->m_keys, (size_t)keylen)
|
|| (save_alt_m_keys != NULL
|
||||||
|
&& STRNCMP(map_str, save_alt_m_keys,
|
||||||
|
STRLEN(save_alt_m_keys)) == 0) :
|
||||||
#endif
|
#endif
|
||||||
!= 0)
|
STRNCMP(map_str, mp->m_keys, (size_t)keylen) == 0
|
||||||
noremap = REMAP_YES;
|
|| (mp->m_alt != NULL
|
||||||
else
|
&& STRNCMP(map_str, mp->m_alt->m_keys,
|
||||||
|
STRLEN(mp->m_alt->m_keys)) == 0))
|
||||||
noremap = REMAP_SKIP;
|
noremap = REMAP_SKIP;
|
||||||
|
else
|
||||||
|
noremap = REMAP_YES;
|
||||||
i = ins_typebuf(map_str, noremap,
|
i = ins_typebuf(map_str, noremap,
|
||||||
0, TRUE, cmd_silent || save_m_silent);
|
0, TRUE, cmd_silent || save_m_silent);
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
@ -3296,6 +3305,7 @@ handle_mapping(
|
|||||||
}
|
}
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
vim_free(save_m_keys);
|
vim_free(save_m_keys);
|
||||||
|
vim_free(save_alt_m_keys);
|
||||||
#endif
|
#endif
|
||||||
*keylenp = keylen;
|
*keylenp = keylen;
|
||||||
if (i == FAIL)
|
if (i == FAIL)
|
||||||
|
46
src/map.c
46
src/map.c
@ -85,6 +85,8 @@ map_free(mapblock_T **mpp)
|
|||||||
|
|
||||||
mp = *mpp;
|
mp = *mpp;
|
||||||
vim_free(mp->m_keys);
|
vim_free(mp->m_keys);
|
||||||
|
if (mp->m_alt != NULL)
|
||||||
|
mp->m_alt->m_alt = NULL;
|
||||||
vim_free(mp->m_str);
|
vim_free(mp->m_str);
|
||||||
vim_free(mp->m_orig_str);
|
vim_free(mp->m_orig_str);
|
||||||
*mpp = mp->m_next;
|
*mpp = mp->m_next;
|
||||||
@ -213,7 +215,7 @@ theend:
|
|||||||
--map_locked;
|
--map_locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static mapblock_T *
|
||||||
map_add(
|
map_add(
|
||||||
mapblock_T **map_table,
|
mapblock_T **map_table,
|
||||||
mapblock_T **abbr_table,
|
mapblock_T **abbr_table,
|
||||||
@ -236,7 +238,7 @@ map_add(
|
|||||||
mapblock_T *mp = ALLOC_CLEAR_ONE(mapblock_T);
|
mapblock_T *mp = ALLOC_CLEAR_ONE(mapblock_T);
|
||||||
|
|
||||||
if (mp == NULL)
|
if (mp == NULL)
|
||||||
return FAIL;
|
return NULL;
|
||||||
|
|
||||||
// If CTRL-C has been mapped, don't always use it for Interrupting.
|
// If CTRL-C has been mapped, don't always use it for Interrupting.
|
||||||
if (*keys == Ctrl_C)
|
if (*keys == Ctrl_C)
|
||||||
@ -256,7 +258,7 @@ map_add(
|
|||||||
vim_free(mp->m_str);
|
vim_free(mp->m_str);
|
||||||
vim_free(mp->m_orig_str);
|
vim_free(mp->m_orig_str);
|
||||||
vim_free(mp);
|
vim_free(mp);
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
mp->m_keylen = (int)STRLEN(mp->m_keys);
|
mp->m_keylen = (int)STRLEN(mp->m_keys);
|
||||||
mp->m_noremap = noremap;
|
mp->m_noremap = noremap;
|
||||||
@ -292,7 +294,7 @@ map_add(
|
|||||||
mp->m_next = map_table[n];
|
mp->m_next = map_table[n];
|
||||||
map_table[n] = mp;
|
map_table[n] = mp;
|
||||||
}
|
}
|
||||||
return OK;
|
return mp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -444,6 +446,7 @@ do_map(
|
|||||||
{
|
{
|
||||||
char_u *keys;
|
char_u *keys;
|
||||||
mapblock_T *mp, **mpp;
|
mapblock_T *mp, **mpp;
|
||||||
|
mapblock_T *mp_result[2] = {NULL, NULL};
|
||||||
char_u *rhs;
|
char_u *rhs;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
int n;
|
int n;
|
||||||
@ -844,6 +847,8 @@ do_map(
|
|||||||
retval = 4; // no mem
|
retval = 4; // no mem
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
if (mp->m_alt != NULL)
|
||||||
|
mp->m_alt = mp->m_alt->m_alt = NULL;
|
||||||
vim_free(mp->m_str);
|
vim_free(mp->m_str);
|
||||||
mp->m_str = newstr;
|
mp->m_str = newstr;
|
||||||
vim_free(mp->m_orig_str);
|
vim_free(mp->m_orig_str);
|
||||||
@ -858,6 +863,7 @@ do_map(
|
|||||||
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;
|
||||||
#endif
|
#endif
|
||||||
|
mp_result[keyround - 1] = mp;
|
||||||
did_it = TRUE;
|
did_it = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -921,18 +927,25 @@ do_map(
|
|||||||
continue; // have added the new entry already
|
continue; // have added the new entry already
|
||||||
|
|
||||||
// Get here when adding a new entry to the maphash[] list or abbrlist.
|
// Get here when adding a new entry to the maphash[] list or abbrlist.
|
||||||
if (map_add(map_table, abbr_table, keys, rhs, orig_rhs,
|
mp_result[keyround - 1] = map_add(map_table, abbr_table, keys,
|
||||||
noremap, nowait, silent, mode, abbrev,
|
rhs, orig_rhs, noremap, nowait, silent, mode, abbrev,
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
expr, /* sid */ 0, /* scriptversion */ 0, /* lnum */ 0,
|
expr, /* sid */ 0, /* scriptversion */ 0, /* lnum */ 0,
|
||||||
#endif
|
#endif
|
||||||
keyround1_simplified) == FAIL)
|
keyround1_simplified);
|
||||||
|
if (mp_result[keyround - 1] == NULL)
|
||||||
{
|
{
|
||||||
retval = 4; // no mem
|
retval = 4; // no mem
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
theend:
|
||||||
vim_free(keys_buf);
|
vim_free(keys_buf);
|
||||||
vim_free(alt_keys_buf);
|
vim_free(alt_keys_buf);
|
||||||
@ -2710,6 +2723,7 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
int nowait;
|
int nowait;
|
||||||
char_u *arg;
|
char_u *arg;
|
||||||
int dict_only;
|
int dict_only;
|
||||||
|
mapblock_T *mp_result[2] = {NULL, NULL};
|
||||||
|
|
||||||
// If first arg is a dict, then that's the only arg permitted.
|
// If first arg is a dict, then that's the only arg permitted.
|
||||||
dict_only = argvars[0].v_type == VAR_DICT;
|
dict_only = argvars[0].v_type == VAR_DICT;
|
||||||
@ -2806,12 +2820,20 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
do_map(MAPTYPE_UNMAP, arg, mode, is_abbr);
|
do_map(MAPTYPE_UNMAP, arg, mode, is_abbr);
|
||||||
vim_free(arg);
|
vim_free(arg);
|
||||||
|
|
||||||
(void)map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs, noremap,
|
mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs,
|
||||||
nowait, silent, mode, is_abbr, expr, sid, scriptversion, lnum, 0);
|
noremap, nowait, silent, mode, is_abbr, expr, sid,
|
||||||
|
scriptversion, lnum, 0);
|
||||||
if (lhsrawalt != NULL)
|
if (lhsrawalt != NULL)
|
||||||
(void)map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs, noremap,
|
mp_result[1] = map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs,
|
||||||
nowait, silent, mode, is_abbr, expr, sid, scriptversion,
|
noremap, nowait, silent, mode, is_abbr, expr, sid,
|
||||||
lnum, 1);
|
scriptversion, lnum, 1);
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
vim_free(arg_buf);
|
vim_free(arg_buf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1309,6 +1309,9 @@ typedef struct mapblock mapblock_T;
|
|||||||
struct mapblock
|
struct mapblock
|
||||||
{
|
{
|
||||||
mapblock_T *m_next; // next mapblock in list
|
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_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
|
||||||
|
@ -1767,6 +1767,49 @@ func Test_unmap_simplifiable()
|
|||||||
unmap <C-I>
|
unmap <C-I>
|
||||||
endfunc
|
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()
|
func Test_expr_map_escape_special()
|
||||||
nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
|
nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
|
||||||
func Func()
|
func Func()
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
642,
|
||||||
/**/
|
/**/
|
||||||
641,
|
641,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user