# HG changeset patch # User Bram Moolenaar # Date 1614891604 -3600 # Node ID 90d1636a8fcbfc9e721c2137849268523f7aafa7 # Parent 815636fbcd96e4ffe837e81ebc1cdf9920a6d952 patch 8.2.2569: 'fillchars' "stl" and "stlnc" items must be single byte Commit: https://github.com/vim/vim/commit/008bff967f7fcaa6af066f71d65bfbba5ef5c7d3 Author: Bram Moolenaar 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) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- 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 ~ diff --git a/src/buffer.c b/src/buffer.c --- 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; } } diff --git a/src/macros.h b/src/macros.h --- 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) diff --git a/src/screen.c b/src/screen.c --- 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; diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim --- 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() diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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,