summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-10-24 21:43:43 +0200
committerChristian Brabandt <cb@256bit.org>2024-10-24 21:43:43 +0200
commitfdf135a0525746cc0ff85bed2fbbde320ddb6d0d (patch)
tree7994f51c8775606bf4c4c867e6cbe9580be8d464
parent118072862b7c01cceb22f28fd85b1621cf03a2d1 (diff)
patch 9.1.0814: mapset() may remove unrelated mappingv9.1.0814
Problem: mapset() may remove unrelated mapping whose {rhs} matches the restored mapping's {lhs}. Solution: only match by {lhs} when unmapping for mapset() (zeertzjq). closes: #15935 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/map.c22
-rw-r--r--src/testdir/test_map_functions.vim19
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h7
4 files changed, 41 insertions, 9 deletions
diff --git a/src/map.c b/src/map.c
index 91ab6e3f16..209d9d237f 100644
--- a/src/map.c
+++ b/src/map.c
@@ -408,9 +408,11 @@ list_mappings(
* noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
* unabbr {lhs} : remove abbreviation for {lhs}
*
- * maptype: MAPTYPE_MAP for :map
- * MAPTYPE_UNMAP for :unmap
- * MAPTYPE_NOREMAP for noremap
+ * maptype: MAPTYPE_MAP for :map or :abbr
+ * MAPTYPE_UNMAP for :unmap or :unabbr
+ * MAPTYPE_NOREMAP for :noremap or :noreabbr
+ * MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match
+ * with {rhs} if there is no match with {lhs}.
*
* arg is pointer to any arguments. Note: arg cannot be a read-only string,
* it will be modified.
@@ -470,6 +472,7 @@ do_map(
int expr = FALSE;
#endif
int did_simplify = FALSE;
+ int unmap_lhs_only = FALSE;
int noremap;
char_u *orig_rhs;
@@ -477,6 +480,12 @@ do_map(
map_table = maphash;
abbr_table = &first_abbr;
+ if (maptype == MAPTYPE_UNMAP_LHS)
+ {
+ unmap_lhs_only = TRUE;
+ maptype = MAPTYPE_UNMAP;
+ }
+
// For ":noremap" don't remap, otherwise do remap.
if (maptype == MAPTYPE_NOREMAP)
noremap = REMAP_NONE;
@@ -619,6 +628,7 @@ do_map(
int did_local = FALSE;
int keyround1_simplified = keyround == 1 && did_simplify;
int round;
+ int num_rounds;
if (keyround == 2)
{
@@ -742,8 +752,8 @@ do_map(
// an 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 (round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
- && !did_it && !got_int; ++round)
+ num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1;
+ for (round = 0; round < num_rounds && !did_it && !got_int; ++round)
{
// need to loop over all hash lists
for (int hash = 0; hash < 256 && !got_int; ++hash)
@@ -2817,7 +2827,7 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
if (arg == NULL)
return;
}
- do_map(MAPTYPE_UNMAP, arg, mode, is_abbr);
+ do_map(MAPTYPE_UNMAP_LHS, arg, mode, is_abbr);
vim_free(arg);
mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs,
diff --git a/src/testdir/test_map_functions.vim b/src/testdir/test_map_functions.vim
index c656368157..db639337fc 100644
--- a/src/testdir/test_map_functions.vim
+++ b/src/testdir/test_map_functions.vim
@@ -540,6 +540,25 @@ func Test_map_restore_negative_sid()
call delete('Xresult')
endfunc
+" Check that restoring a mapping doesn't remove a mapping whose {rhs} matches
+" the restored mapping's {lhs}.
+func Test_map_restore_with_rhs_match_lhs()
+ nnoremap <F2> <F3>
+ nnoremap <F3> <F4>
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('<F4>', maparg('<F3>', 'n'))
+ let d = maparg('<F3>', 'n', v:false, v:true)
+ nunmap <F3>
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('', maparg('<F3>', 'n'))
+ call mapset(d)
+ call assert_equal('<F3>', maparg('<F2>', 'n'))
+ call assert_equal('<F4>', maparg('<F3>', 'n'))
+
+ nunmap <F2>
+ nunmap <F3>
+endfunc
+
def Test_maplist()
new
def ClearMappingsAbbreviations()
diff --git a/src/version.c b/src/version.c
index 1b3c921925..aa05ea2c35 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 */
/**/
+ 814,
+/**/
813,
/**/
812,
diff --git a/src/vim.h b/src/vim.h
index 387fe4fd97..74e6b95435 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1013,9 +1013,10 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define KEY_COMPLETE 0x103 // end of completion
// Used for the first argument of do_map()
-#define MAPTYPE_MAP 0
-#define MAPTYPE_UNMAP 1
-#define MAPTYPE_NOREMAP 2
+#define MAPTYPE_MAP 0
+#define MAPTYPE_UNMAP 1
+#define MAPTYPE_NOREMAP 2
+#define MAPTYPE_UNMAP_LHS 3
// Values for "noremap" argument of ins_typebuf(). Also used for
// map->m_noremap and menu->noremap[].