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>
diff --git a/src/map.c b/src/map.c
index 91ab6e3..209d9d2 100644
--- a/src/map.c
+++ b/src/map.c
@@ -408,9 +408,11 @@
  * 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 @@
     int		expr = FALSE;
 #endif
     int		did_simplify = FALSE;
+    int		unmap_lhs_only = FALSE;
     int		noremap;
     char_u      *orig_rhs;
 
@@ -477,6 +480,12 @@
     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 @@
 	int	did_local = FALSE;
 	int	keyround1_simplified = keyround == 1 && did_simplify;
 	int	round;
+	int	num_rounds;
 
 	if (keyround == 2)
 	{
@@ -742,8 +752,8 @@
 	// 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 @@
 	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,