mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	vim-patch:8.2.3522: cannot use \x and \u when setting 'listchars' (#16049)
Problem:    Cannot use \x and \u when setting 'listchars'.
Solution:   Support hex and unicode in hex form. (closes vim/vim#9006)
93ff6720fe
			
			
This commit is contained in:
		@@ -3792,6 +3792,13 @@ A jump table for the options with a short description can be found at |Q_op|.
 | 
				
			|||||||
	The characters ':' and ',' should not be used.  UTF-8 characters can
 | 
						The characters ':' and ',' should not be used.  UTF-8 characters can
 | 
				
			||||||
	be used.  All characters must be single width.
 | 
						be used.  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: >
 | 
						Examples: >
 | 
				
			||||||
	    :set lcs=tab:>-,trail:-
 | 
						    :set lcs=tab:>-,trail:-
 | 
				
			||||||
	    :set lcs=tab:>-,eol:<,nbsp:%
 | 
						    :set lcs=tab:>-,eol:<,nbsp:%
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1642,6 +1642,16 @@ int hex2nr(int c)
 | 
				
			|||||||
  return c - '0';
 | 
					  return c - '0';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Convert two hex characters to a byte.
 | 
				
			||||||
 | 
					/// Return -1 if one of the characters is not hex.
 | 
				
			||||||
 | 
					int hexhex2nr(char_u *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (!ascii_isxdigit(p[0]) || !ascii_isxdigit(p[1])) {
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (hex2nr(p[0]) << 4) + hex2nr(p[1]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Check that "str" starts with a backslash that should be removed.
 | 
					/// Check that "str" starts with a backslash that should be removed.
 | 
				
			||||||
/// For Windows this is only done when the character after the
 | 
					/// For Windows this is only done when the character after the
 | 
				
			||||||
/// backslash is not a normal file name character.
 | 
					/// backslash is not a normal file name character.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3422,6 +3422,37 @@ void check_blending(win_T *wp)
 | 
				
			|||||||
    wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow);
 | 
					    wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Calls mb_cptr2char_adv(p) and returns the character.
 | 
				
			||||||
 | 
					/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
 | 
				
			||||||
 | 
					/// Returns 0 for invalid hex or invalid UTF-8 byte.
 | 
				
			||||||
 | 
					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')) {
 | 
				
			||||||
 | 
					    int64_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 (int)num;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // TODO(bfredl): use schar_T representation and utfc_ptr2len
 | 
				
			||||||
 | 
					  int clen = utf_ptr2len(s);
 | 
				
			||||||
 | 
					  int c = mb_cptr2char_adv((const char_u **)p);
 | 
				
			||||||
 | 
					  if (clen == 1 && c > 127) {  // Invalid UTF-8 byte
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Handle setting 'listchars' or 'fillchars'.
 | 
					/// Handle setting 'listchars' or 'fillchars'.
 | 
				
			||||||
/// Assume monocell characters
 | 
					/// Assume monocell characters
 | 
				
			||||||
@@ -3526,26 +3557,21 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
 | 
				
			|||||||
            && p[len + 1] != NUL) {
 | 
					            && p[len + 1] != NUL) {
 | 
				
			||||||
          c2 = c3 = 0;
 | 
					          c2 = c3 = 0;
 | 
				
			||||||
          s = p + len + 1;
 | 
					          s = p + len + 1;
 | 
				
			||||||
 | 
					          c1 = get_encoded_char_adv(&s);
 | 
				
			||||||
          // TODO(bfredl): use schar_T representation and utfc_ptr2len
 | 
					          if (c1 == 0 || utf_char2cells(c1) > 1) {
 | 
				
			||||||
          int c1len = utf_ptr2len(s);
 | 
					 | 
				
			||||||
          c1 = mb_cptr2char_adv((const char_u **)&s);
 | 
					 | 
				
			||||||
          if (utf_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
 | 
					 | 
				
			||||||
            return e_invarg;
 | 
					            return e_invarg;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
 | 
					          if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
 | 
				
			||||||
            if (*s == NUL) {
 | 
					            if (*s == NUL) {
 | 
				
			||||||
              return e_invarg;
 | 
					              return e_invarg;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            int c2len = utf_ptr2len(s);
 | 
					            c2 = get_encoded_char_adv(&s);
 | 
				
			||||||
            c2 = mb_cptr2char_adv((const char_u **)&s);
 | 
					            if (c2 == 0 || utf_char2cells(c2) > 1) {
 | 
				
			||||||
            if (utf_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
 | 
					 | 
				
			||||||
              return e_invarg;
 | 
					              return e_invarg;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (!(*s == ',' || *s == NUL)) {
 | 
					            if (!(*s == ',' || *s == NUL)) {
 | 
				
			||||||
              int c3len = utf_ptr2len(s);
 | 
					              c3 = get_encoded_char_adv(&s);
 | 
				
			||||||
              c3 = mb_cptr2char_adv((const char_u **)&s);
 | 
					              if (c3 == 0 || utf_char2cells(c3) > 1) {
 | 
				
			||||||
              if (utf_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
 | 
					 | 
				
			||||||
                return e_invarg;
 | 
					                return e_invarg;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -3578,9 +3604,8 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
 | 
				
			|||||||
            last_multispace = p;
 | 
					            last_multispace = p;
 | 
				
			||||||
            multispace_len = 0;
 | 
					            multispace_len = 0;
 | 
				
			||||||
            while (*s != NUL && *s != ',') {
 | 
					            while (*s != NUL && *s != ',') {
 | 
				
			||||||
              int c1len = utf_ptr2len(s);
 | 
					              c1 = get_encoded_char_adv(&s);
 | 
				
			||||||
              c1 = mb_cptr2char_adv((const char_u **)&s);
 | 
					              if (c1 == 0 || utf_char2cells(c1) > 1) {
 | 
				
			||||||
              if (utf_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
 | 
					 | 
				
			||||||
                return e_invarg;
 | 
					                return e_invarg;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              multispace_len++;
 | 
					              multispace_len++;
 | 
				
			||||||
@@ -3593,7 +3618,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
 | 
				
			|||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            int multispace_pos = 0;
 | 
					            int multispace_pos = 0;
 | 
				
			||||||
            while (*s != NUL && *s != ',') {
 | 
					            while (*s != NUL && *s != ',') {
 | 
				
			||||||
              c1 = mb_cptr2char_adv((const char_u **)&s);
 | 
					              c1 = get_encoded_char_adv(&s);
 | 
				
			||||||
              if (p == last_multispace) {
 | 
					              if (p == last_multispace) {
 | 
				
			||||||
                wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
 | 
					                wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -286,6 +286,10 @@ func Test_listchars_unicode()
 | 
				
			|||||||
  call cursor(1, 1)
 | 
					  call cursor(1, 1)
 | 
				
			||||||
  call assert_equal(expected, ScreenLines(1, virtcol('$')))
 | 
					  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:⇦
 | 
					  set listchars+=lead:⇨,trail:⇦
 | 
				
			||||||
  let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
 | 
					  let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
 | 
				
			||||||
  redraw!
 | 
					  redraw!
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user