changeset 24055:90d1636a8fcb v8.2.2569

patch 8.2.2569: 'fillchars' "stl" and "stlnc" items must be single byte Commit: https://github.com/vim/vim/commit/008bff967f7fcaa6af066f71d65bfbba5ef5c7d3 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 4 21:55:58 2021 +0100 patch 8.2.2569: 'fillchars' "stl" and "stlnc" items must be single byte Problem: 'fillchars' "stl" and "stlnc" items must be single byte. Solution: Accept multi-byte characters. (Christian Wellenbrock, Yegappan Lakshmanan, closes #7927)
author Bram Moolenaar <Bram@vim.org>
date Thu, 04 Mar 2021 22:00:04 +0100
parents 815636fbcd96
children 9f9f3747e096
files runtime/doc/options.txt src/buffer.c src/macros.h src/screen.c src/testdir/test_fold.vim src/testdir/test_statusline.vim src/version.c
diffstat 7 files changed, 101 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3262,7 +3262,8 @@ A jump table for the options with a shor
 <	This is similar to the default, except that these characters will also
 	be used when there is highlighting.
 
-	for "stl" and "stlnc" only single-byte values are supported.
+	For "stl" and "stlnc" single-byte and multibyte characters are
+	supported.  But double-width characters are not supported.
 
 	The highlighting used for these items:
 	  item		highlight group ~
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4157,9 +4157,6 @@ build_stl_str_hl(
 
     if (fillchar == 0)
 	fillchar = ' ';
-    // Can't handle a multi-byte fill character yet.
-    else if (mb_char2len(fillchar) > 1)
-	fillchar = '-';
 
     // The cursor in windows other than the current one isn't always
     // up-to-date, esp. because of autocommands and timers.
@@ -4335,7 +4332,7 @@ build_stl_str_hl(
 
 		// Fill up space left over by half a double-wide char.
 		while (++l < stl_items[stl_groupitem[groupdepth]].stl_minwid)
-		    *p++ = fillchar;
+		    MB_CHAR2BYTES(fillchar, p);
 
 		// correct the start of the items for the truncation
 		for (l = stl_groupitem[groupdepth] + 1; l < curitem; l++)
@@ -4354,20 +4351,20 @@ build_stl_str_hl(
 		    // fill by appending characters
 		    n = 0 - n;
 		    while (l++ < n && p + 1 < out + outlen)
-			*p++ = fillchar;
+			MB_CHAR2BYTES(fillchar, p);
 		}
 		else
 		{
 		    // fill by inserting characters
-		    mch_memmove(t + n - l, t, (size_t)(p - t));
-		    l = n - l;
+		    l = (n - l) * MB_CHAR2LEN(fillchar);
+		    mch_memmove(t + l, t, (size_t)(p - t));
 		    if (p + l >= out + outlen)
 			l = (long)((out + outlen) - p - 1);
 		    p += l;
 		    for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++)
 			stl_items[n].stl_start += l;
 		    for ( ; l > 0; l--)
-			*t++ = fillchar;
+			MB_CHAR2BYTES(fillchar, t);
 		}
 	    }
 	    continue;
@@ -4746,23 +4743,24 @@ build_stl_str_hl(
 		    if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t))
 			*p++ = ' ';
 		    else
-			*p++ = fillchar;
+			MB_CHAR2BYTES(fillchar, p);
 		}
 		minwid = 0;
 	    }
 	    else
 		minwid *= -1;
-	    while (*t && p + 1 < out + outlen)
+	    for (; *t && p + 1 < out + outlen; t++)
 	    {
-		*p++ = *t++;
 		// Change a space by fillchar, unless fillchar is '-' and a
 		// digit follows.
-		if (fillable && p[-1] == ' '
-				     && (!VIM_ISDIGIT(*t) || fillchar != '-'))
-		    p[-1] = fillchar;
+		if (fillable && *t == ' '
+				&& (!VIM_ISDIGIT(*(t + 1)) || fillchar != '-'))
+		    MB_CHAR2BYTES(fillchar, p);
+		else
+		    *p++ = *t;
 	    }
 	    for (; l < minwid && p + 1 < out + outlen; l++)
-		*p++ = fillchar;
+		MB_CHAR2BYTES(fillchar, p);
 	}
 	else if (num >= 0)
 	{
@@ -4865,7 +4863,7 @@ build_stl_str_hl(
 		}
 		// Fill up for half a double-wide character.
 		while (++width < maxwidth)
-		    *s++ = fillchar;
+		    MB_CHAR2BYTES(fillchar, s);
 	    }
 	    else
 		s = out + maxwidth - 1;
@@ -4897,7 +4895,7 @@ build_stl_str_hl(
 	    while (++width < maxwidth)
 	    {
 		s = s + STRLEN(s);
-		*s++ = fillchar;
+		MB_CHAR2BYTES(fillchar, s);
 		*s = NUL;
 	    }
 
@@ -4920,12 +4918,13 @@ build_stl_str_hl(
 		break;
 	if (l < itemcnt)
 	{
-	    p = stl_items[l].stl_start + maxwidth - width;
+	    int middlelength = (maxwidth - width) * MB_CHAR2LEN(fillchar);
+	    p = stl_items[l].stl_start + middlelength;
 	    STRMOVE(p, stl_items[l].stl_start);
-	    for (s = stl_items[l].stl_start; s < p; s++)
-		*s = fillchar;
+	    for (s = stl_items[l].stl_start; s < p;)
+		MB_CHAR2BYTES(fillchar, s);
 	    for (l++; l < itemcnt; l++)
-		stl_items[l].stl_start += maxwidth - width;
+		stl_items[l].stl_start += middlelength;
 	    width = maxwidth;
 	}
     }
--- a/src/macros.h
+++ b/src/macros.h
@@ -252,6 +252,7 @@
 #define MB_CHARLEN(p)	    (has_mbyte ? mb_charlen(p) : (int)STRLEN(p))
 #define MB_CHAR2LEN(c)	    (has_mbyte ? mb_char2len(c) : 1)
 #define PTR2CHAR(p)	    (has_mbyte ? mb_ptr2char(p) : (int)*(p))
+#define MB_CHAR2BYTES(c, b) do { if (has_mbyte) (b) += (*mb_char2bytes)((c), (b)); else *(b)++ = (c); } while(0)
 
 #ifdef FEAT_AUTOCHDIR
 # define DO_AUTOCHDIR do { if (p_acd) do_autochdir(); } while (0)
--- a/src/screen.c
+++ b/src/screen.c
@@ -266,7 +266,7 @@ fill_foldcolumn(
     empty = (fdc == 1) ? 0 : 1;
 
     // If the column is too narrow, we start at the lowest level that
-    // fits and use numbers to indicated the depth.
+    // fits and use numbers to indicate the depth.
     first_level = level - fdc - closed + 1 + empty;
     if (first_level < 1)
 	first_level = 1;
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -987,7 +987,66 @@ func s:mbyte_fillchar_tests(fo, fc, fs)
         \ a:fs .. 'six   ',
         \ ], ScreenLines([1, 6], 7))
 
-  setlocal foldcolumn&
+  " Enable number and sign columns and place some signs
+  setlocal fdc=3
+  setlocal number
+  setlocal signcolumn=auto
+  sign define S1 text=->
+  sign place 10 line=3 name=S1
+  call assert_equal([
+        \ a:fo .. '      1 one  ',
+        \ a:fs .. a:fo .. '     2 two  ',
+        \ '2' .. a:fo .. ' ->  3 three',
+        \ '23     4 four ',
+        \ a:fs .. a:fs .. '     5 five ',
+        \ a:fs .. '      6 six  '
+        \ ], ScreenLines([1, 6], 14))
+
+  " Test with 'rightleft'
+  if has('rightleft')
+    setlocal rightleft
+    let lines = ScreenLines([1, 6], winwidth(0))
+    call assert_equal('o 1      ' .. a:fo,
+          \  strcharpart(lines[0], strchars(lines[0]) - 10, 10))
+    call assert_equal('t 2     ' .. a:fo .. a:fs,
+          \  strcharpart(lines[1], strchars(lines[1]) - 10, 10))
+    call assert_equal('t 3  >- ' .. a:fo .. '2',
+          \  strcharpart(lines[2], strchars(lines[2]) - 10, 10))
+    call assert_equal('f 4     32',
+          \  strcharpart(lines[3], strchars(lines[3]) - 10, 10))
+    call assert_equal('f 5     ' .. a:fs .. a:fs,
+          \  strcharpart(lines[4], strchars(lines[4]) - 10, 10))
+    call assert_equal('s 6      ' .. a:fs,
+          \  strcharpart(lines[5], strchars(lines[5]) - 10, 10))
+    setlocal norightleft
+  endif
+
+  sign unplace *
+  sign undefine S1
+  setlocal number& signcolumn&
+
+  " Add a test with more than 9 folds (and then delete some folds)
+  normal zE
+  for i in range(1, 10)
+    normal zfGzo
+  endfor
+  normal zR
+  call assert_equal([
+        \ a:fo .. a:fo .. ' one ',
+        \ '9> two '
+        \ ], ScreenLines([1, 2], 7))
+  normal 1Gzd
+  call assert_equal([
+        \ a:fo .. a:fo .. ' one ',
+        \ '89 two '
+        \ ], ScreenLines([1, 2], 7))
+  normal 1Gzdzdzdzdzdzdzd
+  call assert_equal([
+        \ a:fo .. a:fo .. ' one ',
+        \ a:fs .. a:fs .. ' two '
+        \ ], ScreenLines([1, 2], 7))
+
+  setlocal foldcolumn& number& signcolumn&
 endfunc
 
 func Test_foldcolumn_multibyte_char()
--- a/src/testdir/test_statusline.vim
+++ b/src/testdir/test_statusline.vim
@@ -464,5 +464,20 @@ func Test_statusline_after_split_vsplit(
   set ls& stl&
 endfunc
 
+" Test using a multibyte character for 'stl' and 'stlnc' items in 'fillchars'
+" with a custom 'statusline'
+func Test_statusline_mbyte_fillchar()
+  only
+  set laststatus=2
+  set fillchars=vert:\|,fold:-,stl:━,stlnc:═
+  set statusline=a%=b
+  call assert_match('^a\+━\+b$', s:get_statusline())
+  vnew
+  call assert_match('^a\+━\+b━a\+═\+b$', s:get_statusline())
+  wincmd w
+  call assert_match('^a\+═\+b═a\+━\+b$', s:get_statusline())
+  set statusline& fillchars& laststatus&
+  %bw!
+endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2569,
+/**/
     2568,
 /**/
     2567,