1
0
forked from aniani/vim

patch 9.1.0814: mapset() may remove unrelated mapping

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>
This commit is contained in:
zeertzjq 2024-10-24 21:43:43 +02:00 committed by Christian Brabandt
parent 118072862b
commit fdf135a052
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
4 changed files with 41 additions and 9 deletions

View File

@ -408,9 +408,11 @@ list_mappings(
* noreabbr {lhs} {rhs} : same, but no remapping for {rhs} * noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
* unabbr {lhs} : remove abbreviation for {lhs} * unabbr {lhs} : remove abbreviation for {lhs}
* *
* maptype: MAPTYPE_MAP for :map * maptype: MAPTYPE_MAP for :map or :abbr
* MAPTYPE_UNMAP for :unmap * MAPTYPE_UNMAP for :unmap or :unabbr
* MAPTYPE_NOREMAP for noremap * 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, * arg is pointer to any arguments. Note: arg cannot be a read-only string,
* it will be modified. * it will be modified.
@ -470,6 +472,7 @@ do_map(
int expr = FALSE; int expr = FALSE;
#endif #endif
int did_simplify = FALSE; int did_simplify = FALSE;
int unmap_lhs_only = FALSE;
int noremap; int noremap;
char_u *orig_rhs; char_u *orig_rhs;
@ -477,6 +480,12 @@ do_map(
map_table = maphash; map_table = maphash;
abbr_table = &first_abbr; abbr_table = &first_abbr;
if (maptype == MAPTYPE_UNMAP_LHS)
{
unmap_lhs_only = TRUE;
maptype = MAPTYPE_UNMAP;
}
// For ":noremap" don't remap, otherwise do remap. // For ":noremap" don't remap, otherwise do remap.
if (maptype == MAPTYPE_NOREMAP) if (maptype == MAPTYPE_NOREMAP)
noremap = REMAP_NONE; noremap = REMAP_NONE;
@ -619,6 +628,7 @@ do_map(
int did_local = FALSE; int did_local = FALSE;
int keyround1_simplified = keyround == 1 && did_simplify; int keyround1_simplified = keyround == 1 && did_simplify;
int round; int round;
int num_rounds;
if (keyround == 2) if (keyround == 2)
{ {
@ -742,8 +752,8 @@ do_map(
// an entry with a matching 'to' part. This was done to allow // 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 // ":ab foo bar" to be unmapped by typing ":unab foo", where "foo" will
// be replaced by "bar" because of the abbreviation. // be replaced by "bar" because of the abbreviation.
for (round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1 num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1;
&& !did_it && !got_int; ++round) for (round = 0; round < num_rounds && !did_it && !got_int; ++round)
{ {
// need to loop over all hash lists // need to loop over all hash lists
for (int hash = 0; hash < 256 && !got_int; ++hash) 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) if (arg == NULL)
return; return;
} }
do_map(MAPTYPE_UNMAP, arg, mode, is_abbr); do_map(MAPTYPE_UNMAP_LHS, arg, mode, is_abbr);
vim_free(arg); vim_free(arg);
mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs, mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs,

View File

@ -540,6 +540,25 @@ func Test_map_restore_negative_sid()
call delete('Xresult') call delete('Xresult')
endfunc 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() def Test_maplist()
new new
def ClearMappingsAbbreviations() def ClearMappingsAbbreviations()

View File

@ -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 */
/**/
814,
/**/ /**/
813, 813,
/**/ /**/

View File

@ -1016,6 +1016,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define MAPTYPE_MAP 0 #define MAPTYPE_MAP 0
#define MAPTYPE_UNMAP 1 #define MAPTYPE_UNMAP 1
#define MAPTYPE_NOREMAP 2 #define MAPTYPE_NOREMAP 2
#define MAPTYPE_UNMAP_LHS 3
// Values for "noremap" argument of ins_typebuf(). Also used for // Values for "noremap" argument of ins_typebuf(). Also used for
// map->m_noremap and menu->noremap[]. // map->m_noremap and menu->noremap[].