summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-03-03 13:26:02 +0100
committerBram Moolenaar <Bram@vim.org>2021-03-03 13:26:02 +0100
commit4fa1175765d55613302fc27d0f65e2c699452b6e (patch)
treec1322ae51aab567c43386d082fd91d52ff1c786b
parent37096afd3f3133a831ab49a9677f090c3c935c9d (diff)
patch 8.2.2563: cannot use multibyte characters for folding in 'fillchars'v8.2.2563
Problem: Cannot use multibyte characters for folding in 'fillchars'. Solution: Port pull request 11568 to Vim. (Yegappan Lakshmanan, closes #7924)
-rw-r--r--src/drawline.c7
-rw-r--r--src/drawscreen.c74
-rw-r--r--src/macros.h7
-rw-r--r--src/proto/screen.pro2
-rw-r--r--src/screen.c66
-rw-r--r--src/testdir/test_fold.vim112
-rw-r--r--src/testdir/test_profile.vim2
-rw-r--r--src/version.c2
8 files changed, 219 insertions, 53 deletions
diff --git a/src/drawline.c b/src/drawline.c
index 2f865127f7..03a229eaec 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -1031,12 +1031,11 @@ win_line(
// Draw the 'foldcolumn'. Allocate a buffer, "extra" may
// already be in use.
vim_free(p_extra_free);
- p_extra_free = alloc(12 + 1);
-
+ p_extra_free = alloc(MAX_MCO * fdc + 1);
if (p_extra_free != NULL)
{
- fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
- n_extra = fdc;
+ n_extra = fill_foldcolumn(p_extra_free, wp,
+ FALSE, lnum);
p_extra_free[n_extra] = NUL;
p_extra = p_extra_free;
c_extra = NUL;
diff --git a/src/drawscreen.c b/src/drawscreen.c
index 3fe1c0c797..c2752bdd8a 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -1044,7 +1044,9 @@ fold_line(
linenr_T lnum,
int row)
{
- char_u buf[FOLD_TEXT_LEN];
+ // Max value of 'foldcolumn' is 12 and maximum number of bytes in a
+ // multi-byte character is MAX_MCO.
+ char_u buf[MAX_MCO * 12 + 1];
pos_T *top, *bot;
linenr_T lnume = lnum + fold_count - 1;
int len;
@@ -1077,29 +1079,6 @@ fold_line(
}
#endif
- // 2. Add the 'foldcolumn'
- // Reduce the width when there is not enough space.
- fdc = compute_foldcolumn(wp, col);
- if (fdc > 0)
- {
- fill_foldcolumn(buf, wp, TRUE, lnum);
-#ifdef FEAT_RIGHTLEFT
- if (wp->w_p_rl)
- {
- int i;
-
- copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
- HL_ATTR(HLF_FC));
- // reverse the fold column
- for (i = 0; i < fdc; ++i)
- ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
- }
- else
-#endif
- copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
- col += fdc;
- }
-
#ifdef FEAT_RIGHTLEFT
# define RL_MEMSET(p, v, l) \
do { \
@@ -1118,6 +1097,53 @@ fold_line(
} while (0)
#endif
+ // 2. Add the 'foldcolumn'
+ // Reduce the width when there is not enough space.
+ fdc = compute_foldcolumn(wp, col);
+ if (fdc > 0)
+ {
+ char_u *p;
+ int i;
+ int idx;
+
+ fill_foldcolumn(buf, wp, TRUE, lnum);
+ p = buf;
+ for (i = 0; i < fdc; i++)
+ {
+ int ch;
+
+ if (has_mbyte)
+ ch = mb_ptr2char_adv(&p);
+ else
+ ch = *p++;
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ idx = off + wp->w_width - i - 1 - col;
+ else
+#endif
+ idx = off + col + i;
+ if (enc_utf8)
+ {
+ if (ch >= 0x80)
+ {
+ ScreenLinesUC[idx] = ch;
+ ScreenLinesC[0][idx] = 0;
+ ScreenLines[idx] = 0x80;
+ }
+ else
+ {
+ ScreenLines[idx] = ch;
+ ScreenLinesUC[idx] = 0;
+ }
+ }
+ else
+ ScreenLines[idx] = ch;
+ }
+
+ RL_MEMSET(col, HL_ATTR(HLF_FC), fdc);
+ col += fdc;
+ }
+
// Set all attributes of the 'number' or 'relativenumber' column and the
// text
RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
diff --git a/src/macros.h b/src/macros.h
index 3db2456f3c..5a57a89284 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -388,3 +388,10 @@
// Inlined version of ga_grow(). Especially useful if "n" is a constant.
#define GA_GROW(gap, n) (((gap)->ga_maxlen - (gap)->ga_len < n) ? ga_grow_inner((gap), (n)) : OK)
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
index 1ab40df0c9..fc45fa15fe 100644
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -4,7 +4,7 @@ void conceal_check_cursor_line(void);
int get_wcr_attr(win_T *wp);
void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
int compute_foldcolumn(win_T *wp, int col);
-void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
+size_t fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
int screen_get_current_line_off(void);
void reset_screen_attr(void);
void screen_line(int row, int coloff, int endcol, int clear_width, int flags);
diff --git a/src/screen.c b/src/screen.c
index a012c70037..ce4ab11461 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -239,8 +239,11 @@ compute_foldcolumn(win_T *wp, int col)
/*
* Fill the foldcolumn at "p" for window "wp".
* Only to be called when 'foldcolumn' > 0.
+ * Returns the number of bytes stored in 'p'. When non-multibyte characters are
+ * used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
+ * this will be greater than 'fdc'.
*/
- void
+ size_t
fill_foldcolumn(
char_u *p,
win_T *wp,
@@ -252,39 +255,54 @@ fill_foldcolumn(
int first_level;
int empty;
int fdc = compute_foldcolumn(wp, 0);
+ size_t byte_counter = 0;
+ int symbol = 0;
+ int len = 0;
// Init to all spaces.
- vim_memset(p, ' ', (size_t)fdc);
+ vim_memset(p, ' ', MAX_MCO * fdc + 1);
level = win_foldinfo.fi_level;
- if (level > 0)
- {
- // If there is only one column put more info in it.
- empty = (fdc == 1) ? 0 : 1;
+ 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.
+ first_level = level - fdc - closed + 1 + empty;
+ if (first_level < 1)
+ first_level = 1;
- // If the column is too narrow, we start at the lowest level that
- // fits and use numbers to indicated the depth.
- first_level = level - fdc - closed + 1 + empty;
- if (first_level < 1)
- first_level = 1;
+ for (i = 0; i < MIN(fdc, level); i++)
+ {
+ if (win_foldinfo.fi_lnum == lnum
+ && first_level + i >= win_foldinfo.fi_low_level)
+ symbol = fill_foldopen;
+ else if (first_level == 1)
+ symbol = fill_foldsep;
+ else if (first_level + i <= 9)
+ symbol = '0' + first_level + i;
+ else
+ symbol = '>';
- for (i = 0; i + empty < fdc; ++i)
+ len = utf_char2bytes(symbol, &p[byte_counter]);
+ byte_counter += len;
+ if (first_level + i >= level)
{
- if (win_foldinfo.fi_lnum == lnum
- && first_level + i >= win_foldinfo.fi_low_level)
- p[i] = fill_foldopen;
- else if (first_level == 1)
- p[i] = fill_foldsep;
- else if (first_level + i <= 9)
- p[i] = '0' + first_level + i;
- else
- p[i] = '>';
- if (first_level + i == level)
- break;
+ i++;
+ break;
}
}
+
if (closed)
- p[i >= fdc ? i - 1 : i] = fill_foldclosed;
+ {
+ if (symbol != 0)
+ // rollback length
+ byte_counter -= len;
+ symbol = fill_foldclosed;
+ len = utf_char2bytes(symbol, &p[byte_counter]);
+ byte_counter += len;
+ }
+
+ return MAX(byte_counter + (fdc - i), (size_t)fdc);
}
#endif // FEAT_FOLDING
diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim
index 8206193c4a..920dcc406d 100644
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -894,4 +894,116 @@ func Test_fold_relative_move()
set fdm& sw& wrap& tw&
endfunc
+" Test for using multibyte characters as 'foldopen', 'foldclose' and
+" 'foldsetp' items in 'fillchars'
+func s:mbyte_fillchar_tests(fo, fc, fs)
+ setlocal foldcolumn=3
+
+ normal zE
+ 1,2fold
+ call assert_equal([a:fc .. ' +-- 2 ', ' three '],
+ \ ScreenLines([1, 2], 10))
+ 1,2foldopen
+ call assert_equal([a:fo .. ' one ', a:fs .. ' two '],
+ \ ScreenLines([1, 2], 7))
+ 1,2foldclose
+ redraw!
+ call assert_equal([a:fc .. ' +-- 2 ', ' three '],
+ \ ScreenLines([1, 2], 10))
+
+ " Two level fold
+ normal zE
+ 2,3fold
+ 1,4fold
+ call assert_equal([a:fc .. ' +-- 4 ', ' five '],
+ \ ScreenLines([1, 2], 10))
+ 1,4foldopen
+ call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
+ \ ScreenLines([1, 2], 10))
+ 1,4foldopen
+ call assert_equal([a:fo .. ' one ', a:fs .. a:fo .. ' two ',
+ \ a:fs .. a:fs .. ' three '], ScreenLines([1, 3], 10))
+ 2,3foldclose
+ call assert_equal([a:fo .. ' one ', a:fs .. a:fc .. ' +--- 2'],
+ \ ScreenLines([1, 2], 10))
+ 1,4foldclose
+ call assert_equal([a:fc .. ' +-- 4 ', ' five '],
+ \ ScreenLines([1, 2], 10))
+
+ " Three level fold
+ normal zE
+ 3,4fold
+ 2,5fold
+ 1,6fold
+ call assert_equal([a:fc .. ' +-- 6 '], ScreenLines(1, 10))
+ " open all the folds
+ normal zR
+ call assert_equal([
+ \ a:fo .. ' one ',
+ \ a:fs .. a:fo .. ' two ',
+ \ '2' .. a:fo .. ' three ',
+ \ '23 four ',
+ \ a:fs .. a:fs .. ' five ',
+ \ a:fs .. ' six ',
+ \ ], ScreenLines([1, 6], 10))
+ " close the innermost fold
+ 3,4foldclose
+ call assert_equal([
+ \ a:fo .. ' one ',
+ \ a:fs .. a:fo .. ' two ',
+ \ a:fs .. a:fs .. a:fc .. '+---- ',
+ \ a:fs .. a:fs .. ' five ',
+ \ a:fs .. ' six ',
+ \ ], ScreenLines([1, 5], 10))
+ " close the next fold
+ 2,5foldclose
+ call assert_equal([
+ \ a:fo .. ' one ',
+ \ a:fs .. a:fc .. ' +--- 4',
+ \ a:fs .. ' six ',
+ \ ], ScreenLines([1, 3], 10))
+
+ " set the fold column size to 2
+ setlocal fdc=2
+ normal zR
+ call assert_equal([
+ \ a:fo .. ' one ',
+ \ a:fo .. ' two ',
+ \ a:fo .. ' three',
+ \ '3 four ',
+ \ '2 five ',
+ \ a:fs .. ' six ',
+ \ ], ScreenLines([1, 6], 7))
+
+ " set the fold column size to 1
+ setlocal fdc=1
+ normal zR
+ call assert_equal([
+ \ a:fo .. 'one ',
+ \ a:fo .. 'two ',
+ \ a:fo .. 'three ',
+ \ '3four ',
+ \ '2five ',
+ \ a:fs .. 'six ',
+ \ ], ScreenLines([1, 6], 7))
+
+ setlocal foldcolumn&
+endfunc
+
+func Test_foldcolumn_multibyte_char()
+ new
+ call setline(1, ['one', 'two', 'three', 'four', 'five', 'six'])
+ setlocal foldenable foldmethod=manual
+
+ " First test with the default setting
+ call s:mbyte_fillchar_tests('-', '+', '|')
+
+ " Use multi-byte characters
+ set fillchars+=foldopen:▾,foldsep:│,foldclose:▸
+ call s:mbyte_fillchar_tests('▾', '▸', '│')
+
+ bw!
+ set foldenable& fdc& fdm& fillchars&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim
index 835a60279e..785cee3270 100644
--- a/src/testdir/test_profile.vim
+++ b/src/testdir/test_profile.vim
@@ -636,6 +636,8 @@ func Test_vim9_nested_call()
call assert_match('FUNCTION <SNR>\d\+_Two().*'
\ .. '#Called 3 times.*'
\ .. '# 3 \s*[0-9.]\+ total += nr', prof_lines)
+ call delete('Xprofile_nested.vim')
+ call delete('Xprofile_nested.log')
endfunc
diff --git a/src/version.c b/src/version.c
index c4859dedad..83854d1ebb 100644
--- 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 */
/**/
+ 2563,
+/**/
2562,
/**/
2561,