From ac402f4d64bec6b6efd809fef52f5b34627bf947 Mon Sep 17 00:00:00 2001
From: zeertzjq <zeertzjq@outlook.com>
Date: Wed, 4 May 2022 18:51:43 +0100
Subject: [PATCH] patch 8.2.4867: listing of mapping with K_SPECIAL is wrong

Problem:    Listing of mapping with K_SPECIAL is wrong.
Solution:   Adjust escaping of special characters. (closes #10351)
---
 src/map.c                    | 12 +-----------
 src/message.c                | 26 ++++++++++++++++++--------
 src/testdir/test_mapping.vim | 20 ++++++++++++++++++++
 3 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/src/map.c b/src/map.c
index 645cd10..98573b5 100644
--- a/src/map.c
+++ b/src/map.c
@@ -186,17 +186,7 @@ showmap(
     if (*mp->m_str == NUL)
 	msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
     else
-    {
-	// Remove escaping of CSI, because "m_str" is in a format to be used
-	// as typeahead.
-	char_u *s = vim_strsave(mp->m_str);
-	if (s != NULL)
-	{
-	    vim_unescape_csi(s);
-	    msg_outtrans_special(s, FALSE, 0);
-	    vim_free(s);
-	}
-    }
+	msg_outtrans_special(mp->m_str, FALSE, 0);
 #ifdef FEAT_EVAL
     if (p_verbose > 0)
 	last_set_msg(mp->m_script_ctx);
diff --git a/src/message.c b/src/message.c
index eae6e61..0898d90 100644
--- a/src/message.c
+++ b/src/message.c
@@ -1716,19 +1716,29 @@ str2special(
 
     if (has_mbyte && !IS_SPECIAL(c))
     {
-	int len = (*mb_ptr2len)(str);
+        char_u  *p;
 
-	/* For multi-byte characters check for an illegal byte. */
-	if (has_mbyte && MB_BYTE2LEN(*str) > len)
+        *sp = str;
+        // Try to un-escape a multi-byte character after modifiers.
+        p = mb_unescape(sp);
+
+        if (p == NULL)
 	{
-	    transchar_nonprint(buf, c);
-	    *sp = str + 1;
-	    return buf;
+           int len = (*mb_ptr2len)(str);
+
+           // Check for an illegal byte.
+           if (MB_BYTE2LEN(*str) > len)
+           {
+               transchar_nonprint(curbuf, buf, c);
+               *sp = str + 1;
+               return buf;
+           }
+           *sp = str + len;
+           p = str;
 	}
 	/* Since 'special' is TRUE the multi-byte character 'c' will be
 	 * processed by get_special_key_name() */
-	c = (*mb_ptr2char)(str);
-	*sp = str + len;
+	c = (*mb_ptr2char)(p);
     }
     else
 	*sp = str + 1;
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index 55e6af0..58c284d 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -461,6 +461,26 @@ func Test_list_mappings()
   call assert_equal(['i  <S-/>       * ShiftSlash'], execute('imap')->trim()->split("\n"))
   iunmap <S-/>
   call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n"))
+
+  nmap foo …
+  call assert_equal(['n  foo           …'],
+        \ execute('nmap foo')->trim()->split("\n"))
+
+  " modified character with K_SPECIAL byte in rhs
+  nmap foo <M-…>
+  call assert_equal(['n  foo           <M-…>'],
+        \ execute('nmap foo')->trim()->split("\n"))
+
+  " character with K_SPECIAL byte in lhs
+  nmap … foo
+  call assert_equal(['n  …             foo'],
+        \ execute('nmap …')->trim()->split("\n"))
+
+  " modified character with K_SPECIAL byte in lhs
+  nmap <M-…> foo
+  call assert_equal(['n  <M-…>         foo'],
+        \ execute('nmap <M-…>')->trim()->split("\n"))
+
 endfunc
 
 func Test_expr_map_restore_cursor()
-- 
1.8.3.1

