mirror of
				https://github.com/vim/vim.git
				synced 2025-10-31 09:57:14 -04:00 
			
		
		
		
	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:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							118072862b
						
					
				
				
					commit
					fdf135a052
				
			
							
								
								
									
										22
									
								
								src/map.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/map.c
									
									
									
									
									
								
							| @@ -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, | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
| @@ -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, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
| @@ -1013,9 +1013,10 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); | |||||||
| #define KEY_COMPLETE	0x103	// end of completion | #define KEY_COMPLETE	0x103	// end of completion | ||||||
|  |  | ||||||
| // Used for the first argument of do_map() | // Used for the first argument of do_map() | ||||||
| #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[]. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user