changeset 25978:40b17deb294f v8.2.3522

patch 8.2.3522: cannot use x and u when setting 'listchars' Commit: https://github.com/vim/vim/commit/93ff6720fe4427341bc426b6d46e6324f226c270 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Oct 16 17:51:40 2021 +0100 patch 8.2.3522: cannot use \x and \u when setting 'listchars' Problem: Cannot use \x and \u when setting 'listchars'. Solution: Support hex and unicode in hex form. (closes https://github.com/vim/vim/issues/9006)
author Bram Moolenaar <Bram@vim.org>
date Sat, 16 Oct 2021 19:00:03 +0200
parents 93fc4b568a54
children 05065e623c89
files runtime/doc/options.txt src/charset.c src/screen.c src/testdir/test_listchars.vim src/version.c
diffstat 5 files changed, 47 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4978,6 +4978,13 @@ A jump table for the options with a shor
 	be used when 'encoding' is "utf-8", otherwise only printable
 	characters are allowed.  All characters must be single width.
 
+	Each character can be specified as hex: >
+		set listchars=eol:\\x24
+		set listchars=eol:\\u21b5
+		set listchars=eol:\\U000021b5
+<	Note that a double backslash is used.  The number of hex characters
+	must be exactly 2 for \\x, 4 for \\u and 8 for \\U.
+
 	Examples: >
 	    :set lcs=tab:>-,trail:-
 	    :set lcs=tab:>-,eol:<,nbsp:%
--- a/src/charset.c
+++ b/src/charset.c
@@ -2013,8 +2013,6 @@ hex2nr(int c)
     return c - '0';
 }
 
-#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) \
-        || defined(PROTO) || defined(FEAT_AUTOSHELLDIR)
 /*
  * Convert two hex characters to a byte.
  * Return -1 if one of the characters is not hex.
@@ -2026,7 +2024,6 @@ hexhex2nr(char_u *p)
 	return -1;
     return (hex2nr(p[0]) << 4) + hex2nr(p[1]);
 }
-#endif
 
 /*
  * Return TRUE if "str" starts with a backslash that should be removed.
--- a/src/screen.c
+++ b/src/screen.c
@@ -4777,6 +4777,35 @@ screen_screenrow(void)
 #endif
 
 /*
+ * Calls mb_ptr2char_adv(p) and returns the character.
+ * If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
+ */
+    static int
+get_encoded_char_adv(char_u **p)
+{
+    char_u *s = *p;
+
+    if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
+    {
+	varnumber_T num = 0;
+	int	    bytes;
+	int	    n;
+
+	for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
+	{
+	    *p += 2;
+	    n = hexhex2nr(*p);
+	    if (n < 0)
+		return 0;
+	    num = num * 256 + n;
+	}
+	*p += 2;
+	return num;
+    }
+    return mb_ptr2char_adv(p);
+}
+
+/*
  * Handle setting 'listchars' or 'fillchars'.
  * Assume monocell characters.
  * Returns error message, NULL if it's OK.
@@ -4884,19 +4913,19 @@ set_chars_option(win_T *wp, char_u **var
 		{
 		    c2 = c3 = 0;
 		    s = p + len + 1;
-		    c1 = mb_ptr2char_adv(&s);
+		    c1 = get_encoded_char_adv(&s);
 		    if (mb_char2cells(c1) > 1)
 			return e_invarg;
 		    if (tab[i].cp == &lcs_chars.tab2)
 		    {
 			if (*s == NUL)
 			    return e_invarg;
-			c2 = mb_ptr2char_adv(&s);
+			c2 = get_encoded_char_adv(&s);
 			if (mb_char2cells(c2) > 1)
 			    return e_invarg;
 			if (!(*s == ',' || *s == NUL))
 			{
-			    c3 = mb_ptr2char_adv(&s);
+			    c3 = get_encoded_char_adv(&s);
 			    if (mb_char2cells(c3) > 1)
 				return e_invarg;
 			}
@@ -4938,7 +4967,7 @@ set_chars_option(win_T *wp, char_u **var
 			multispace_len = 0;
 			while (*s != NUL && *s != ',')
 			{
-			    c1 = mb_ptr2char_adv(&s);
+			    c1 = get_encoded_char_adv(&s);
 			    if (mb_char2cells(c1) > 1)
 				return e_invarg;
 			    ++multispace_len;
@@ -4954,7 +4983,7 @@ set_chars_option(win_T *wp, char_u **var
 
 			while (*s != NUL && *s != ',')
 			{
-			    c1 = mb_ptr2char_adv(&s);
+			    c1 = get_encoded_char_adv(&s);
 			    if (p == last_multispace)
 				lcs_chars.multispace[multispace_pos++] = c1;
 			}
--- a/src/testdir/test_listchars.vim
+++ b/src/testdir/test_listchars.vim
@@ -288,6 +288,10 @@ func Test_listchars_unicode()
   call cursor(1, 1)
   call assert_equal(expected, ScreenLines(1, virtcol('$')))
 
+  set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192
+  redraw!
+  call assert_equal(expected, ScreenLines(1, virtcol('$')))
+
   set listchars+=lead:⇨,trail:⇦
   let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
   redraw!
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3522,
+/**/
     3521,
 /**/
     3520,