Skip to content

Commit 4fa1175

Browse files
committed
patch 8.2.2563: cannot use multibyte characters for folding in 'fillchars'
Problem: Cannot use multibyte characters for folding in 'fillchars'. Solution: Port pull request 11568 to Vim. (Yegappan Lakshmanan, closes #7924)
1 parent 37096af commit 4fa1175

8 files changed

Lines changed: 219 additions & 53 deletions

File tree

src/drawline.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,12 +1031,11 @@ win_line(
10311031
// Draw the 'foldcolumn'. Allocate a buffer, "extra" may
10321032
// already be in use.
10331033
vim_free(p_extra_free);
1034-
p_extra_free = alloc(12 + 1);
1035-
1034+
p_extra_free = alloc(MAX_MCO * fdc + 1);
10361035
if (p_extra_free != NULL)
10371036
{
1038-
fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
1039-
n_extra = fdc;
1037+
n_extra = fill_foldcolumn(p_extra_free, wp,
1038+
FALSE, lnum);
10401039
p_extra_free[n_extra] = NUL;
10411040
p_extra = p_extra_free;
10421041
c_extra = NUL;

src/drawscreen.c

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,9 @@ fold_line(
10441044
linenr_T lnum,
10451045
int row)
10461046
{
1047-
char_u buf[FOLD_TEXT_LEN];
1047+
// Max value of 'foldcolumn' is 12 and maximum number of bytes in a
1048+
// multi-byte character is MAX_MCO.
1049+
char_u buf[MAX_MCO * 12 + 1];
10481050
pos_T *top, *bot;
10491051
linenr_T lnume = lnum + fold_count - 1;
10501052
int len;
@@ -1077,29 +1079,6 @@ fold_line(
10771079
}
10781080
#endif
10791081

1080-
// 2. Add the 'foldcolumn'
1081-
// Reduce the width when there is not enough space.
1082-
fdc = compute_foldcolumn(wp, col);
1083-
if (fdc > 0)
1084-
{
1085-
fill_foldcolumn(buf, wp, TRUE, lnum);
1086-
#ifdef FEAT_RIGHTLEFT
1087-
if (wp->w_p_rl)
1088-
{
1089-
int i;
1090-
1091-
copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
1092-
HL_ATTR(HLF_FC));
1093-
// reverse the fold column
1094-
for (i = 0; i < fdc; ++i)
1095-
ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
1096-
}
1097-
else
1098-
#endif
1099-
copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
1100-
col += fdc;
1101-
}
1102-
11031082
#ifdef FEAT_RIGHTLEFT
11041083
# define RL_MEMSET(p, v, l) \
11051084
do { \
@@ -1118,6 +1097,53 @@ fold_line(
11181097
} while (0)
11191098
#endif
11201099

1100+
// 2. Add the 'foldcolumn'
1101+
// Reduce the width when there is not enough space.
1102+
fdc = compute_foldcolumn(wp, col);
1103+
if (fdc > 0)
1104+
{
1105+
char_u *p;
1106+
int i;
1107+
int idx;
1108+
1109+
fill_foldcolumn(buf, wp, TRUE, lnum);
1110+
p = buf;
1111+
for (i = 0; i < fdc; i++)
1112+
{
1113+
int ch;
1114+
1115+
if (has_mbyte)
1116+
ch = mb_ptr2char_adv(&p);
1117+
else
1118+
ch = *p++;
1119+
#ifdef FEAT_RIGHTLEFT
1120+
if (wp->w_p_rl)
1121+
idx = off + wp->w_width - i - 1 - col;
1122+
else
1123+
#endif
1124+
idx = off + col + i;
1125+
if (enc_utf8)
1126+
{
1127+
if (ch >= 0x80)
1128+
{
1129+
ScreenLinesUC[idx] = ch;
1130+
ScreenLinesC[0][idx] = 0;
1131+
ScreenLines[idx] = 0x80;
1132+
}
1133+
else
1134+
{
1135+
ScreenLines[idx] = ch;
1136+
ScreenLinesUC[idx] = 0;
1137+
}
1138+
}
1139+
else
1140+
ScreenLines[idx] = ch;
1141+
}
1142+
1143+
RL_MEMSET(col, HL_ATTR(HLF_FC), fdc);
1144+
col += fdc;
1145+
}
1146+
11211147
// Set all attributes of the 'number' or 'relativenumber' column and the
11221148
// text
11231149
RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);

src/macros.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,10 @@
388388

389389
// Inlined version of ga_grow(). Especially useful if "n" is a constant.
390390
#define GA_GROW(gap, n) (((gap)->ga_maxlen - (gap)->ga_len < n) ? ga_grow_inner((gap), (n)) : OK)
391+
392+
#ifndef MIN
393+
# define MIN(a, b) ((a) < (b) ? (a) : (b))
394+
#endif
395+
#ifndef MAX
396+
# define MAX(a, b) ((a) > (b) ? (a) : (b))
397+
#endif

src/proto/screen.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ void conceal_check_cursor_line(void);
44
int get_wcr_attr(win_T *wp);
55
void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
66
int compute_foldcolumn(win_T *wp, int col);
7-
void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
7+
size_t fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
88
int screen_get_current_line_off(void);
99
void reset_screen_attr(void);
1010
void screen_line(int row, int coloff, int endcol, int clear_width, int flags);

src/screen.c

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,11 @@ compute_foldcolumn(win_T *wp, int col)
239239
/*
240240
* Fill the foldcolumn at "p" for window "wp".
241241
* Only to be called when 'foldcolumn' > 0.
242+
* Returns the number of bytes stored in 'p'. When non-multibyte characters are
243+
* used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
244+
* this will be greater than 'fdc'.
242245
*/
243-
void
246+
size_t
244247
fill_foldcolumn(
245248
char_u *p,
246249
win_T *wp,
@@ -252,39 +255,54 @@ fill_foldcolumn(
252255
int first_level;
253256
int empty;
254257
int fdc = compute_foldcolumn(wp, 0);
258+
size_t byte_counter = 0;
259+
int symbol = 0;
260+
int len = 0;
255261

256262
// Init to all spaces.
257-
vim_memset(p, ' ', (size_t)fdc);
263+
vim_memset(p, ' ', MAX_MCO * fdc + 1);
258264

259265
level = win_foldinfo.fi_level;
260-
if (level > 0)
261-
{
262-
// If there is only one column put more info in it.
263-
empty = (fdc == 1) ? 0 : 1;
266+
empty = (fdc == 1) ? 0 : 1;
267+
268+
// If the column is too narrow, we start at the lowest level that
269+
// fits and use numbers to indicated the depth.
270+
first_level = level - fdc - closed + 1 + empty;
271+
if (first_level < 1)
272+
first_level = 1;
264273

265-
// If the column is too narrow, we start at the lowest level that
266-
// fits and use numbers to indicated the depth.
267-
first_level = level - fdc - closed + 1 + empty;
268-
if (first_level < 1)
269-
first_level = 1;
274+
for (i = 0; i < MIN(fdc, level); i++)
275+
{
276+
if (win_foldinfo.fi_lnum == lnum
277+
&& first_level + i >= win_foldinfo.fi_low_level)
278+
symbol = fill_foldopen;
279+
else if (first_level == 1)
280+
symbol = fill_foldsep;
281+
else if (first_level + i <= 9)
282+
symbol = '0' + first_level + i;
283+
else
284+
symbol = '>';
270285

271-
for (i = 0; i + empty < fdc; ++i)
286+
len = utf_char2bytes(symbol, &p[byte_counter]);
287+
byte_counter += len;
288+
if (first_level + i >= level)
272289
{
273-
if (win_foldinfo.fi_lnum == lnum
274-
&& first_level + i >= win_foldinfo.fi_low_level)
275-
p[i] = fill_foldopen;
276-
else if (first_level == 1)
277-
p[i] = fill_foldsep;
278-
else if (first_level + i <= 9)
279-
p[i] = '0' + first_level + i;
280-
else
281-
p[i] = '>';
282-
if (first_level + i == level)
283-
break;
290+
i++;
291+
break;
284292
}
285293
}
294+
286295
if (closed)
287-
p[i >= fdc ? i - 1 : i] = fill_foldclosed;
296+
{
297+
if (symbol != 0)
298+
// rollback length
299+
byte_counter -= len;
300+
symbol = fill_foldclosed;
301+
len = utf_char2bytes(symbol, &p[byte_counter]);
302+
byte_counter += len;
303+
}
304+
305+
return MAX(byte_counter + (fdc - i), (size_t)fdc);
288306
}
289307
#endif // FEAT_FOLDING
290308

src/testdir/test_fold.vim

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,4 +894,116 @@ func Test_fold_relative_move()
894894
set fdm& sw& wrap& tw&
895895
endfunc
896896

897+
" Test for using multibyte characters as 'foldopen', 'foldclose' and
898+
" 'foldsetp' items in 'fillchars'
899+
func s:mbyte_fillchar_tests(fo, fc, fs)
900+
setlocal foldcolumn=3
901+
902+
normal zE
903+
1,2fold
904+
call assert_equal([a:fc .. ' +-- 2 ', ' three '],
905+
\ ScreenLines([1, 2], 10))
906+
1,2foldopen
907+
call assert_equal([a:fo .. ' one ', a:fs .. ' two '],
908+
\ ScreenLines([1, 2], 7))
909+
1,2foldclose
910+
redraw!
911+
call assert_equal([a:fc .. ' +-- 2 ', ' three '],
912+
\ ScreenLines([1, 2], 10))
913+
914+
" Two level fold
915+
normal zE
916+
2,3fold
917+
1,4fold
918+
call assert_equal([a:fc .. ' +-- 4 ', ' five '],
919+
\ ScreenLines([1, 2], 10))
920+
1,4foldopen
921+
call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
922+
\ ScreenLines([1, 2], 10))
923+
1,4foldopen
924+
call assert_equal([a:fo .. ' one ', a:fs .. a:fo .. ' two ',
925+
\ a:fs .. a:fs .. ' three '], ScreenLines([1, 3], 10))
926+
2,3foldclose
927+
call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
928+
\ ScreenLines([1, 2], 10))
929+
1,4foldclose
930+
call assert_equal([a:fc .. ' +-- 4 ', ' five '],
931+
\ ScreenLines([1, 2], 10))
932+
933+
" Three level fold
934+
normal zE
935+
3,4fold
936+
2,5fold
937+
1,6fold
938+
call assert_equal([a:fc .. ' +-- 6 '], ScreenLines(1, 10))
939+
" open all the folds
940+
normal zR
941+
call assert_equal([
942+
\ a:fo .. ' one ',
943+
\ a:fs .. a:fo .. ' two ',
944+
\ '2' .. a:fo .. ' three ',
945+
\ '23 four ',
946+
\ a:fs .. a:fs .. ' five ',
947+
\ a:fs .. ' six ',
948+
\ ], ScreenLines([1, 6], 10))
949+
" close the innermost fold
950+
3,4foldclose
951+
call assert_equal([
952+
\ a:fo .. ' one ',
953+
\ a:fs .. a:fo .. ' two ',
954+
\ a:fs .. a:fs .. a:fc .. '+---- ',
955+
\ a:fs .. a:fs .. ' five ',
956+
\ a:fs .. ' six ',
957+
\ ], ScreenLines([1, 5], 10))
958+
" close the next fold
959+
2,5foldclose
960+
call assert_equal([
961+
\ a:fo .. ' one ',
962+
\ a:fs .. a:fc .. ' +--- 4',
963+
\ a:fs .. ' six ',
964+
\ ], ScreenLines([1, 3], 10))
965+
966+
" set the fold column size to 2
967+
setlocal fdc=2
968+
normal zR
969+
call assert_equal([
970+
\ a:fo .. ' one ',
971+
\ a:fo .. ' two ',
972+
\ a:fo .. ' three',
973+
\ '3 four ',
974+
\ '2 five ',
975+
\ a:fs .. ' six ',
976+
\ ], ScreenLines([1, 6], 7))
977+
978+
" set the fold column size to 1
979+
setlocal fdc=1
980+
normal zR
981+
call assert_equal([
982+
\ a:fo .. 'one ',
983+
\ a:fo .. 'two ',
984+
\ a:fo .. 'three ',
985+
\ '3four ',
986+
\ '2five ',
987+
\ a:fs .. 'six ',
988+
\ ], ScreenLines([1, 6], 7))
989+
990+
setlocal foldcolumn&
991+
endfunc
992+
993+
func Test_foldcolumn_multibyte_char()
994+
new
995+
call setline(1, ['one', 'two', 'three', 'four', 'five', 'six'])
996+
setlocal foldenable foldmethod=manual
997+
998+
" First test with the default setting
999+
call s:mbyte_fillchar_tests('-', '+', '|')
1000+
1001+
" Use multi-byte characters
1002+
set fillchars+=foldopen:▾,foldsep:│,foldclose:▸
1003+
call s:mbyte_fillchar_tests('', '', '')
1004+
1005+
bw!
1006+
set foldenable& fdc& fdm& fillchars&
1007+
endfunc
1008+
8971009
" vim: shiftwidth=2 sts=2 expandtab

src/testdir/test_profile.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ func Test_vim9_nested_call()
636636
call assert_match('FUNCTION <SNR>\d\+_Two().*'
637637
\ .. '#Called 3 times.*'
638638
\ .. '# 3 \s*[0-9.]\+ total += nr', prof_lines)
639+
call delete('Xprofile_nested.vim')
640+
call delete('Xprofile_nested.log')
639641
endfunc
640642

641643

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2563,
753755
/**/
754756
2562,
755757
/**/

0 commit comments

Comments
 (0)