summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-07-29 21:10:07 +0200
committerChristian Brabandt <cb@256bit.org>2024-07-29 21:10:07 +0200
commit9d997addc7bd0fd132a809cf497ed816e61fcd25 (patch)
tree0ef7b82926d68d877b145c29396e7b063e56cf65
parentbaaf6deb957e11227c6ffa5e22b48d9082ae7e77 (diff)
patch 9.1.0642: Check that mapping rhs starts with lhs fails if not simplifiedv9.1.0642
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>
-rw-r--r--src/getchar.c24
-rw-r--r--src/map.c46
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_mapping.vim43
-rw-r--r--src/version.c2
5 files changed, 99 insertions, 19 deletions
diff --git a/src/getchar.c b/src/getchar.c
index 4af176978c..54222ec308 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -3156,6 +3156,7 @@ handle_mapping(
int save_m_noremap;
int save_m_silent;
char_u *save_m_keys;
+ char_u *save_alt_m_keys;
#else
# define save_m_noremap mp->m_noremap
# define save_m_silent mp->m_silent
@@ -3204,6 +3205,7 @@ handle_mapping(
save_m_noremap = mp->m_noremap;
save_m_silent = mp->m_silent;
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
@@ -3221,6 +3223,8 @@ handle_mapping(
may_garbage_collect = FALSE;
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);
// The mapping may do anything, but we expect it to take care of
@@ -3278,15 +3282,20 @@ handle_mapping(
noremap = save_m_noremap;
else if (
#ifdef FEAT_EVAL
- STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys,
- (size_t)keylen)
-#else
- STRNCMP(map_str, mp->m_keys, (size_t)keylen)
+ save_m_expr ?
+ (save_m_keys != NULL
+ && 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) :
#endif
- != 0)
- noremap = REMAP_YES;
- else
+ 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);
#ifdef FEAT_EVAL
@@ -3296,6 +3305,7 @@ handle_mapping(
}
#ifdef FEAT_EVAL
vim_free(save_m_keys);
+ vim_free(save_alt_m_keys);
#endif
*keylenp = keylen;
if (i == FAIL)
diff --git a/src/map.c b/src/map.c
index c416c0a327..91ab6e3f16 100644
--- a/src/map.c
+++ b/src/map.c
@@ -85,6 +85,8 @@ map_free(mapblock_T **mpp)
mp = *mpp;
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_orig_str);
*mpp = mp->m_next;
@@ -213,7 +215,7 @@ theend:
--map_locked;
}
- static int
+ static mapblock_T *
map_add(
mapblock_T **map_table,
mapblock_T **abbr_table,
@@ -236,7 +238,7 @@ map_add(
mapblock_T *mp = ALLOC_CLEAR_ONE(mapblock_T);
if (mp == NULL)
- return FAIL;
+ return NULL;
// If CTRL-C has been mapped, don't always use it for Interrupting.
if (*keys == Ctrl_C)
@@ -256,7 +258,7 @@ map_add(
vim_free(mp->m_str);
vim_free(mp->m_orig_str);
vim_free(mp);
- return FAIL;
+ return NULL;
}
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
@@ -292,7 +294,7 @@ map_add(
mp->m_next = map_table[n];
map_table[n] = mp;
}
- return OK;
+ return mp;
}
/*
@@ -444,6 +446,7 @@ do_map(
{
char_u *keys;
mapblock_T *mp, **mpp;
+ mapblock_T *mp_result[2] = {NULL, NULL};
char_u *rhs;
char_u *p;
int n;
@@ -844,6 +847,8 @@ do_map(
retval = 4; // no mem
goto theend;
}
+ if (mp->m_alt != NULL)
+ mp->m_alt = mp->m_alt->m_alt = NULL;
vim_free(mp->m_str);
mp->m_str = newstr;
vim_free(mp->m_orig_str);
@@ -858,6 +863,7 @@ do_map(
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
+ mp_result[keyround - 1] = mp;
did_it = TRUE;
}
}
@@ -921,18 +927,25 @@ do_map(
continue; // have added the new entry already
// Get here when adding a new entry to the maphash[] list or abbrlist.
- if (map_add(map_table, abbr_table, keys, rhs, orig_rhs,
- noremap, nowait, silent, mode, abbrev,
+ mp_result[keyround - 1] = map_add(map_table, abbr_table, keys,
+ rhs, orig_rhs, noremap, nowait, silent, mode, abbrev,
#ifdef FEAT_EVAL
expr, /* sid */ 0, /* scriptversion */ 0, /* lnum */ 0,
#endif
- keyround1_simplified) == FAIL)
+ keyround1_simplified);
+ if (mp_result[keyround - 1] == NULL)
{
retval = 4; // no mem
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:
vim_free(keys_buf);
vim_free(alt_keys_buf);
@@ -2710,6 +2723,7 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
int nowait;
char_u *arg;
int dict_only;
+ mapblock_T *mp_result[2] = {NULL, NULL};
// If first arg is a dict, then that's the only arg permitted.
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);
vim_free(arg);
- (void)map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs, noremap,
- nowait, silent, mode, is_abbr, expr, sid, scriptversion, lnum, 0);
+ mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs,
+ noremap, nowait, silent, mode, is_abbr, expr, sid,
+ scriptversion, lnum, 0);
if (lhsrawalt != NULL)
- (void)map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs, noremap,
- nowait, silent, mode, is_abbr, expr, sid, scriptversion,
- lnum, 1);
+ mp_result[1] = map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs,
+ noremap, nowait, silent, mode, is_abbr, expr, sid,
+ 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);
}
#endif
diff --git a/src/structs.h b/src/structs.h
index 32c35b7bf5..fe4704a367 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1309,6 +1309,9 @@ 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_u *m_keys; // mapped from, lhs
char_u *m_str; // mapped to, rhs
char_u *m_orig_str; // rhs as entered by the user
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index 1175310465..654a6734e2 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -1767,6 +1767,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()
diff --git a/src/version.c b/src/version.c
index 8afbd01487..153685953a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 642,
+/**/
641,
/**/
640,