diff options
-rw-r--r-- | src/nvim/drawline.c | 19 | ||||
-rw-r--r-- | test/functional/legacy/conceal_spec.lua | 191 | ||||
-rw-r--r-- | test/old/testdir/test_conceal.vim | 84 |
3 files changed, 248 insertions, 46 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 2f541a8a21..dfe3dbca50 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2403,6 +2403,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } else { mb_schar = schar_from_ascii(' '); } + + if (utf_char2cells(mb_c) > 1) { + // When the first char to be concealed is double-width, + // need to advance one more virtual column. + wlv.n_extra++; + } + mb_c = schar_get_first_codepoint(mb_schar); prev_syntax_id = syntax_seqnr; @@ -2739,11 +2746,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.off++; wlv.col++; } else if (wp->w_p_cole > 0 && is_concealing) { + bool concealed_wide = utf_char2cells(mb_c) > 1; + wlv.skip_cells--; wlv.vcol_off_co++; + if (concealed_wide) { + // When a double-width char is concealed, + // need to advance one more virtual column. + wlv.vcol++; + wlv.vcol_off_co++; + } + if (wlv.n_extra > 0) { wlv.vcol_off_co += wlv.n_extra; } + if (is_wrapped) { // Special voodoo required if 'wrap' is on. // @@ -2764,7 +2781,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.n_attr = 0; } - if (utf_char2cells(mb_c) > 1) { + if (concealed_wide) { // Need to fill two screen columns. wlv.boguscols++; wlv.col++; diff --git a/test/functional/legacy/conceal_spec.lua b/test/functional/legacy/conceal_spec.lua index 63ec644a10..e2cc3b23df 100644 --- a/test/functional/legacy/conceal_spec.lua +++ b/test/functional/legacy/conceal_spec.lua @@ -4,6 +4,7 @@ local clear = helpers.clear local command = helpers.command local exec = helpers.exec local feed = helpers.feed +local api = helpers.api local expect_pos = function(row, col) return helpers.eq({ row, col }, helpers.eval('[screenrow(), screencol()]')) @@ -633,13 +634,13 @@ describe('Conceal', function() expect_pos(9, 26) end) - -- oldtest: Test_conceal_virtualedit_after_eol() - it('cursor drawn at correct column with virtualedit', function() - local screen = Screen.new(75, 3) + local function test_conceal_virtualedit_after_eol(wrap) + local screen = Screen.new(60, 3) screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText }) screen:attach() + api.nvim_set_option_value('wrap', wrap, {}) exec([[ call setline(1, 'abcdefgh|hidden|ijklmnpop') syntax match test /|hidden|/ conceal @@ -647,43 +648,53 @@ describe('Conceal', function() normal! $ ]]) screen:expect([[ - abcdefghijklmnpo^p | - {0:~ }| - | + abcdefghijklmnpo^p | + {0:~ }| + | ]]) feed('l') screen:expect([[ - abcdefghijklmnpop^ | - {0:~ }| - | + abcdefghijklmnpop^ | + {0:~ }| + | ]]) feed('l') screen:expect([[ - abcdefghijklmnpop ^ | - {0:~ }| - | + abcdefghijklmnpop ^ | + {0:~ }| + | ]]) feed('l') screen:expect([[ - abcdefghijklmnpop ^ | - {0:~ }| - | + abcdefghijklmnpop ^ | + {0:~ }| + | ]]) feed('rr') screen:expect([[ - abcdefghijklmnpop ^r | - {0:~ }| - | + abcdefghijklmnpop ^r | + {0:~ }| + | ]]) + end + + -- oldtest: Test_conceal_virtualedit_after_eol() + describe('cursor drawn at correct column with virtualedit', function() + it('with wrapping', function() + test_conceal_virtualedit_after_eol(true) + end) + it('without wrapping', function() + test_conceal_virtualedit_after_eol(false) + end) end) - -- oldtest: Test_conceal_virtualedit_after_eol_rightleft() - it('cursor drawn correctly with virtualedit and rightleft', function() - local screen = Screen.new(75, 3) + local function test_conceal_virtualedit_after_eol_rightleft(wrap) + local screen = Screen.new(60, 3) screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText }) screen:attach() + api.nvim_set_option_value('wrap', wrap, {}) exec([[ call setline(1, 'abcdefgh|hidden|ijklmnpop') syntax match test /|hidden|/ conceal @@ -691,33 +702,141 @@ describe('Conceal', function() normal! $ ]]) screen:expect([[ - ^popnmlkjihgfedcba| - {0: ~}| - | + ^popnmlkjihgfedcba| + {0: ~}| + | ]]) feed('h') screen:expect([[ - ^ popnmlkjihgfedcba| - {0: ~}| - | + ^ popnmlkjihgfedcba| + {0: ~}| + | ]]) feed('h') screen:expect([[ - ^ popnmlkjihgfedcba| - {0: ~}| - | + ^ popnmlkjihgfedcba| + {0: ~}| + | ]]) feed('h') screen:expect([[ - ^ popnmlkjihgfedcba| - {0: ~}| - | + ^ popnmlkjihgfedcba| + {0: ~}| + | ]]) feed('rr') screen:expect([[ - ^r popnmlkjihgfedcba| - {0: ~}| - | + ^r popnmlkjihgfedcba| + {0: ~}| + | + ]]) + end + + -- oldtest: Test_conceal_virtualedit_after_eol_rightleft() + describe('cursor drawn correctly with virtualedit and rightleft', function() + it('with wrapping', function() + test_conceal_virtualedit_after_eol_rightleft(true) + end) + it('without wrapping', function() + test_conceal_virtualedit_after_eol_rightleft(false) + end) + end) + + local function test_conceal_double_width(wrap) + local screen = Screen.new(60, 4) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, + [2] = { background = Screen.colors.LightRed }, + }) + screen:attach() + api.nvim_set_option_value('wrap', wrap, {}) + exec([[ + call setline(1, ['aaaaa口=口bbbbb口=口ccccc', 'foobar']) + syntax match test /口=口/ conceal cchar=β + set conceallevel=2 concealcursor=n colorcolumn=30 + normal! $ + ]]) + screen:expect([[ + aaaaa{1:β}bbbbb{1:β}cccc^c {2: } | + foobar {2: } | + {0:~ }| + | + ]]) + feed('gM') + screen:expect([[ + aaaaa{1:β}bb^bbb{1:β}ccccc {2: } | + foobar {2: } | + {0:~ }| + | + ]]) + command('set conceallevel=3') + screen:expect([[ + aaaaabb^bbbccccc {2: } | + foobar {2: } | + {0:~ }| + | + ]]) + feed('$') + screen:expect([[ + aaaaabbbbbcccc^c {2: } | + foobar {2: } | + {0:~ }| + | + ]]) + end + + -- oldtest: Test_conceal_double_width() + describe('cursor drawn correctly when double-width chars are concealed', function() + it('with wrapping', function() + test_conceal_double_width(true) + end) + it('without wrapping', function() + test_conceal_double_width(false) + end) + end) + + -- oldtest: Test_conceal_double_width_wrap() + it('line wraps correctly when double-width chars are concealed', function() + local screen = Screen.new(20, 4) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, + [2] = { background = Screen.colors.LightRed }, + }) + screen:attach() + exec([[ + call setline(1, 'aaaaaaaaaa口=口bbbbbbbbbb口=口cccccccccc') + syntax match test /口=口/ conceal cchar=β + set conceallevel=2 concealcursor=n + normal! $ + ]]) + screen:expect([[ + aaaaaaaaaa{1:β}bbbbb | + bbbbb{1:β}ccccccccc^c | + {0:~ }| + | + ]]) + feed('gM') + screen:expect([[ + aaaaaaaaaa{1:β}bbbbb | + ^bbbbb{1:β}cccccccccc | + {0:~ }| + | + ]]) + command('set conceallevel=3') + screen:expect([[ + aaaaaaaaaabbbbb | + ^bbbbbcccccccccc | + {0:~ }| + | + ]]) + feed('$') + screen:expect([[ + aaaaaaaaaabbbbb | + bbbbbccccccccc^c | + {0:~ }| + | ]]) end) end) diff --git a/test/old/testdir/test_conceal.vim b/test/old/testdir/test_conceal.vim index 94d5d1d470..52b0661f85 100644 --- a/test/old/testdir/test_conceal.vim +++ b/test/old/testdir/test_conceal.vim @@ -439,7 +439,7 @@ func Test_conceal_mouse_click() call Ntest_setmouse(1, 19) call feedkeys("\<LeftMouse>", "tx") call assert_equal([0, 1, 23, 0, 23], getcurpos()) - " click after end of line puts cursor there without 'virtualedit' + " click after end of line puts cursor there with 'virtualedit' call Ntest_setmouse(1, 20) call feedkeys("\<LeftMouse>", "tx") call assert_equal([0, 1, 24, 0, 24], getcurpos()) @@ -462,10 +462,9 @@ endfunc " Test that cursor is drawn at the correct column when it is after end of the " line with 'virtualedit' and concealing. -func Test_conceal_virtualedit_after_eol() - CheckScreendump - - let code =<< trim [CODE] +func Run_test_conceal_virtualedit_after_eol(wrap) + let code =<< trim eval [CODE] + let &wrap = {a:wrap} call setline(1, 'abcdefgh|hidden|ijklmnpop') syntax match test /|hidden|/ conceal set conceallevel=2 concealcursor=n virtualedit=all @@ -487,12 +486,17 @@ func Test_conceal_virtualedit_after_eol() call StopVimInTerminal(buf) endfunc -" Same as Test_conceal_virtualedit_after_eol(), but with 'rightleft' set. -func Test_conceal_virtualedit_after_eol_rightleft() - CheckFeature rightleft +func Test_conceal_virtualedit_after_eol() CheckScreendump - let code =<< trim [CODE] + call Run_test_conceal_virtualedit_after_eol(1) + call Run_test_conceal_virtualedit_after_eol(0) +endfunc + +" Same as Run_test_conceal_virtualedit_after_eol(), but with 'rightleft'. +func Run_test_conceal_virtualedit_after_eol_rightleft(wrap) + let code =<< trim eval [CODE] + let &wrap = {a:wrap} call setline(1, 'abcdefgh|hidden|ijklmnpop') syntax match test /|hidden|/ conceal set conceallevel=2 concealcursor=n virtualedit=all rightleft @@ -514,4 +518,66 @@ func Test_conceal_virtualedit_after_eol_rightleft() call StopVimInTerminal(buf) endfunc +func Test_conceal_virtualedit_after_eol_rightleft() + CheckFeature rightleft + CheckScreendump + + call Run_test_conceal_virtualedit_after_eol_rightleft(1) + call Run_test_conceal_virtualedit_after_eol_rightleft(0) +endfunc + +" Test that cursor position is correct when double-width chars are concealed. +func Run_test_conceal_double_width(wrap) + let code =<< trim eval [CODE] + let &wrap = {a:wrap} + call setline(1, ['aaaaa口=口bbbbb口=口ccccc', 'foobar']) + syntax match test /口=口/ conceal cchar=β + set conceallevel=2 concealcursor=n colorcolumn=30 + normal! $ + [CODE] + call writefile(code, 'XTest_conceal_double_width', 'D') + let buf = RunVimInTerminal('-S XTest_conceal_double_width', {'rows': 4}) + call VerifyScreenDump(buf, 'Test_conceal_double_width_1', {}) + call term_sendkeys(buf, "gM") + call VerifyScreenDump(buf, 'Test_conceal_double_width_2', {}) + call term_sendkeys(buf, ":set conceallevel=3\<CR>") + call VerifyScreenDump(buf, 'Test_conceal_double_width_3', {}) + call term_sendkeys(buf, "$") + call VerifyScreenDump(buf, 'Test_conceal_double_width_4', {}) + + " clean up + call StopVimInTerminal(buf) +endfunc + +func Test_conceal_double_width() + CheckScreendump + + call Run_test_conceal_double_width(1) + call Run_test_conceal_double_width(0) +endfunc + +" Test that line wrapping is correct when double-width chars are concealed. +func Test_conceal_double_width_wrap() + CheckScreendump + + let code =<< trim [CODE] + call setline(1, 'aaaaaaaaaa口=口bbbbbbbbbb口=口cccccccccc') + syntax match test /口=口/ conceal cchar=β + set conceallevel=2 concealcursor=n + normal! $ + [CODE] + call writefile(code, 'XTest_conceal_double_width_wrap', 'D') + let buf = RunVimInTerminal('-S XTest_conceal_double_width_wrap', {'rows': 4, 'cols': 20}) + call VerifyScreenDump(buf, 'Test_conceal_double_width_wrap_1', {}) + call term_sendkeys(buf, "gM") + call VerifyScreenDump(buf, 'Test_conceal_double_width_wrap_2', {}) + call term_sendkeys(buf, ":set conceallevel=3\<CR>") + call VerifyScreenDump(buf, 'Test_conceal_double_width_wrap_3', {}) + call term_sendkeys(buf, "$") + call VerifyScreenDump(buf, 'Test_conceal_double_width_wrap_4', {}) + + " clean up + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab |