To: vim_dev@googlegroups.com Subject: Patch 8.2.2563 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2563 Problem: Cannot use multibyte characters for folding in 'fillchars'. Solution: Port pull request 11568 to Vim. (Yegappan Lakshmanan, closes #7924) Files: src/drawline.c, src/drawscreen.c, src/macros.h, src/proto/screen.pro, src/screen.c, src/testdir/test_fold.vim, src/testdir/test_profile.vim *** ../vim-8.2.2562/src/drawline.c 2021-02-15 20:37:58.453374547 +0100 --- src/drawline.c 2021-03-03 13:24:21.164315994 +0100 *************** *** 1031,1042 **** // Draw the 'foldcolumn'. Allocate a buffer, "extra" may // already be in use. vim_free(p_extra_free); ! p_extra_free = alloc(12 + 1); ! if (p_extra_free != NULL) { ! fill_foldcolumn(p_extra_free, wp, FALSE, lnum); ! n_extra = fdc; p_extra_free[n_extra] = NUL; p_extra = p_extra_free; c_extra = NUL; --- 1031,1041 ---- // Draw the 'foldcolumn'. Allocate a buffer, "extra" may // already be in use. vim_free(p_extra_free); ! p_extra_free = alloc(MAX_MCO * fdc + 1); if (p_extra_free != NULL) { ! n_extra = fill_foldcolumn(p_extra_free, wp, ! FALSE, lnum); p_extra_free[n_extra] = NUL; p_extra = p_extra_free; c_extra = NUL; *** ../vim-8.2.2562/src/drawscreen.c 2021-02-15 20:37:58.453374547 +0100 --- src/drawscreen.c 2021-03-03 13:17:00.949391520 +0100 *************** *** 1044,1050 **** linenr_T lnum, int row) { ! char_u buf[FOLD_TEXT_LEN]; pos_T *top, *bot; linenr_T lnume = lnum + fold_count - 1; int len; --- 1044,1052 ---- linenr_T lnum, int row) { ! // 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,1105 **** } #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 { \ --- 1079,1084 ---- *************** *** 1118,1123 **** --- 1097,1149 ---- } 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); *** ../vim-8.2.2562/src/macros.h 2021-01-04 10:47:21.698153964 +0100 --- src/macros.h 2021-03-03 13:17:00.949391520 +0100 *************** *** 388,390 **** --- 388,397 ---- // 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 *** ../vim-8.2.2562/src/proto/screen.pro 2021-02-15 20:37:58.457374538 +0100 --- src/proto/screen.pro 2021-03-03 13:17:00.949391520 +0100 *************** *** 4,10 **** 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); 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); --- 4,10 ---- 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); ! 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); *** ../vim-8.2.2562/src/screen.c 2021-02-17 13:14:03.688013283 +0100 --- src/screen.c 2021-03-03 13:25:26.444048031 +0100 *************** *** 239,246 **** /* * Fill the foldcolumn at "p" for window "wp". * Only to be called when 'foldcolumn' > 0. */ ! void fill_foldcolumn( char_u *p, win_T *wp, --- 239,249 ---- /* * 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'. */ ! size_t fill_foldcolumn( char_u *p, win_T *wp, *************** *** 252,290 **** int first_level; int empty; int fdc = compute_foldcolumn(wp, 0); // Init to all spaces. ! vim_memset(p, ' ', (size_t)fdc); level = win_foldinfo.fi_level; ! if (level > 0) ! { ! // If there is only one column put more info in it. ! 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; ! for (i = 0; i + empty < fdc; ++i) { ! 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; } } if (closed) ! p[i >= fdc ? i - 1 : i] = fill_foldclosed; } #endif // FEAT_FOLDING --- 255,308 ---- 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, ' ', MAX_MCO * fdc + 1); level = win_foldinfo.fi_level; ! 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; ! 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 = '>'; ! len = utf_char2bytes(symbol, &p[byte_counter]); ! byte_counter += len; ! if (first_level + i >= level) { ! i++; ! break; } } + if (closed) ! { ! 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 *** ../vim-8.2.2562/src/testdir/test_fold.vim 2021-01-24 11:59:58.075425245 +0100 --- src/testdir/test_fold.vim 2021-03-03 13:17:00.949391520 +0100 *************** *** 894,897 **** --- 894,1009 ---- 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 *** ../vim-8.2.2562/src/testdir/test_profile.vim 2021-02-19 19:13:13.087904339 +0100 --- src/testdir/test_profile.vim 2021-03-03 13:17:00.949391520 +0100 *************** *** 636,641 **** --- 636,643 ---- call assert_match('FUNCTION \d\+_Two().*' \ .. '#Called 3 times.*' \ .. '# 3 \s*[0-9.]\+ total += nr', prof_lines) + call delete('Xprofile_nested.vim') + call delete('Xprofile_nested.log') endfunc *** ../vim-8.2.2562/src/version.c 2021-03-02 19:04:08.029594922 +0100 --- src/version.c 2021-03-03 13:18:52.469121733 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2563, /**/ -- BEDEVERE: Stand by for attack!! [CUT TO enormous army forming up. Trebuchets, rows of PIKEMEN, siege towers, pennants flying, shouts of "Stand by for attack!" Traditional army build-up shots. The shouts echo across the ranks of the army. We see various groups reacting, and stirring themselves in readiness.] ARTHUR: Who are they? BEDEVERE: Oh, just some friends! "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///