diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index ab6b9c6ad5..c71729871c 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -2035,12 +2035,11 @@ static void win_update(win_T *wp) // When at start of changed lines: May scroll following lines // up or down to minimize redrawing. // Don't do this when the change continues until the end. - // Don't scroll when dollar_vcol >= 0, keep the "$". // Don't scroll when redrawing the top, scrolled already above. if (lnum == mod_top && mod_bot != MAXLNUM - && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) && row >= top_end) { + int old_cline_height = 0; int old_rows = 0; linenr_T l; int i; @@ -2055,6 +2054,9 @@ static void win_update(win_T *wp) && wp->w_lines[i].wl_lnum == mod_bot) { break; } + if (wp->w_lines[i].wl_lnum == wp->w_cursor.lnum) { + old_cline_height = wp->w_lines[i].wl_size; + } old_rows += wp->w_lines[i].wl_size; if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) { @@ -2081,9 +2083,17 @@ static void win_update(win_T *wp) // rows, and may insert/delete lines int j = idx; for (l = lnum; l < mod_bot; l++) { - int n = plines_correct_topline(wp, l, &l, true, NULL); - new_rows += n; - j += n > 0; // don't count concealed lines + if (dollar_vcol >= 0 && wp == curwin + && old_cline_height > 0 && l == wp->w_cursor.lnum) { + // When dollar_vcol >= 0, cursor line isn't fully + // redrawn, and its height remains unchanged. + new_rows += old_cline_height; + j++; + } else { + int n = plines_correct_topline(wp, l, &l, true, NULL); + new_rows += n; + j += n > 0; // don't count concealed lines + } if (new_rows > wp->w_view_height - row - 2) { // it's getting too much, must redraw the rest new_rows = 9999; @@ -2218,15 +2228,17 @@ static void win_update(win_T *wp) wp->w_lines[idx].wl_lnum = lnum; wp->w_lines[idx].wl_valid = true; + bool is_curline = wp == curwin && lnum == wp->w_cursor.lnum; + if (row > wp->w_view_height) { // past end of grid // we may need the size of that too long line later on - if (dollar_vcol == -1) { + if (dollar_vcol == -1 || !is_curline) { wp->w_lines[idx].wl_size = (uint16_t)plines_win(wp, lnum, true); } idx++; break; } - if (dollar_vcol == -1) { + if (dollar_vcol == -1 || !is_curline) { wp->w_lines[idx].wl_size = (uint16_t)(row - srow); } lnum = wp->w_lines[idx++].wl_lastlnum + 1; @@ -2343,7 +2355,7 @@ redr_statuscol: goto redr_statuscol; } } - } else if (dollar_vcol == -1) { + } else if (dollar_vcol == -1 || wp != curwin) { wp->w_botline = lnum; } @@ -2385,7 +2397,7 @@ redr_statuscol: kv_A(win_extmark_arr, n).win_row, kv_A(win_extmark_arr, n).win_col); } - if (dollar_vcol == -1) { + if (dollar_vcol == -1 || wp != curwin) { // There is a trick with w_botline. If we invalidate it on each // change that might modify it, this will cause a lot of expensive // calls to plines_win() in update_topline() each time. Therefore the diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua index c93b2d96d8..034a04d242 100644 --- a/test/functional/legacy/display_spec.lua +++ b/test/functional/legacy/display_spec.lua @@ -209,4 +209,213 @@ describe('display', function() | ]]) end) + + -- oldtest: Test_change_wrapped_line_cpo_dollar() + it('changing wrapped line with cpo+=$', function() + local screen = Screen.new(45, 10) + exec([[ + set cpoptions+=$ laststatus=0 + call setline(1, ['foo', 'bar', + \ repeat('x', 25) .. '!!()!!' .. repeat('y', 25), + \ 'FOO', 'BAR']) + inoremap call setline(1, repeat('z', 30)) + inoremap call setline(1, 'foo') + vsplit + call cursor(3, 1) + ]]) + + local s1 = [[ + foo │foo | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│xxxxxxxxxxxxxxxxxxxxxx| + xxx!!()!!yyyyyyyyyyyyy│xxx!!()!!yyyyyyyyyyyyy| + yyyyyyyyyyyy │yyyyyyyyyyyy | + FOO │FOO | + BAR │BAR | + {1:~ }│{1:~ }|*2 + | + ]] + screen:expect(s1) + feed('ct!') + local s2 = [[ + foo │foo | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│!!()!!yyyyyyyyyyyyyyyy| + xx$!!()!!yyyyyyyyyyyyy│yyyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]] + screen:expect(s2) + feed('') + screen:expect([[ + zzzzzzzzzzzzzzzzzzzzzz│zzzzzzzzzzzzzzzzzzzzzz| + zzzzzzzz │zzzzzzzz | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│!!()!!yyyyyyyyyyyyyyyy| + xx$!!()!!yyyyyyyyyyyyy│yyyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }| + {5:-- INSERT --} | + ]]) + feed('') + screen:expect(s2) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + y^xxxxxxxxxxxxxxxxxxxxx│y!!()!!yyyyyyyyyyyyyyy| + xx$!!()!!yyyyyyyyyyyyy│yyyyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]]) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + yy^xxxxxxxxxxxxxxxxxxxx│yy!!()!!yyyyyyyyyyyyyy| + xx$!!()!!yyyyyyyyyyyyy│yyyyyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + foo │foo | + bar │bar | + y^y!!()!!yyyyyyyyyyyyyy│yy!!()!!yyyyyyyyyyyyyy| + yyyyyyyyyyy │yyyyyyyyyyy | + FOO │FOO | + BAR │BAR | + {1:~ }│{1:~ }|*3 + | + ]]) + + command('silent undo') + screen:expect(s1) + command('source test/old/testdir/samples/matchparen.vim') + feed('ct(') + screen:expect([[ + foo │foo | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│()!!yyyyyyyyyyyyyyyyyy| + xxx!$()!!yyyyyyyyyyyyy│yyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]]) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + y^xxxxxxxxxxxxxxxxxxxxx│y()!!yyyyyyyyyyyyyyyyy| + xxx!$()!!yyyyyyyyyyyyy│yyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]]) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + yy^xxxxxxxxxxxxxxxxxxxx│yy()!!yyyyyyyyyyyyyyyy| + xxx!$()!!yyyyyyyyyyyyy│yyyyyyyyy | + yyyyyyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }|*2 + {5:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + foo │foo | + bar │bar | + y^y()!!yyyyyyyyyyyyyyyy│yy()!!yyyyyyyyyyyyyyyy| + yyyyyyyyy │yyyyyyyyy | + FOO │FOO | + BAR │BAR | + {1:~ }│{1:~ }|*3 + | + ]]) + + command('silent undo') + screen:expect(s1) + feed('f(azzzzk0') + screen:expect([[ + foo │foo | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│xxxxxxxxxxxxxxxxxxxxxx| + xxx!!(zz │xxx!!(zz | + zz)!!yyyyyyyyyyyyyyyyy│zz)!!yyyyyyyyyyyyyyyyy| + yyyyyyyy │yyyyyyyy | + FOO │FOO | + BAR │BAR | + {1:~ }│{1:~ }| + | + ]]) + feed('ct(') + screen:expect([[ + foo │foo | + bar │bar | + ^xxxxxxxxxxxxxxxxxxxxxx│(zz | + xxx!$(zz │zz)!!yyyyyyyyyyyyyyyyy| + zz)!!yyyyyyyyyyyyyyyyy│yyyyyyyy | + yyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }| + {5:-- INSERT --} | + ]]) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + y^xxxxxxxxxxxxxxxxxxxxx│y(zz | + xxx!$(zz │zz)!!yyyyyyyyyyyyyyyyy| + zz)!!yyyyyyyyyyyyyyyyy│yyyyyyyy | + yyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }| + {5:-- INSERT --} | + ]]) + feed('y') + screen:expect([[ + foo │foo | + bar │bar | + yy^xxxxxxxxxxxxxxxxxxxx│yy(zz | + xxx!$(zz │zz)!!yyyyyyyyyyyyyyyyy| + zz)!!yyyyyyyyyyyyyyyyy│yyyyyyyy | + yyyyyyyy │FOO | + FOO │BAR | + BAR │{1:~ }| + {1:~ }│{1:~ }| + {5:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + foo │foo | + bar │bar | + y^y(zz │yy(zz | + zz)!!yyyyyyyyyyyyyyyyy│zz)!!yyyyyyyyyyyyyyyyy| + yyyyyyyy │yyyyyyyy | + FOO │FOO | + BAR │BAR | + {1:~ }│{1:~ }|*2 + | + ]]) + end) end) diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim index e0ad150c49..90f0077ae9 100644 --- a/test/old/testdir/test_display.vim +++ b/test/old/testdir/test_display.vim @@ -573,4 +573,65 @@ func Test_display_cursor_long_line() call StopVimInTerminal(buf) endfunc +func Test_change_wrapped_line_cpo_dollar() + CheckScreendump + + let lines =<< trim END + set cpoptions+=$ laststatus=0 + call setline(1, ['foo', 'bar', + \ repeat('x', 25) .. '!!()!!' .. repeat('y', 25), + \ 'FOO', 'BAR']) + inoremap call setline(1, repeat('z', 30)) + inoremap call setline(1, 'foo') + vsplit + call cursor(3, 1) + END + call writefile(lines, 'Xwrapped_cpo_dollar', 'D') + let buf = RunVimInTerminal('-S Xwrapped_cpo_dollar', #{rows: 10, cols: 45}) + + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_01', {}) + call term_sendkeys(buf, 'ct!') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_02', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_03', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_02', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_04', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_05', {}) + call term_sendkeys(buf, "\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_06', {}) + + call term_sendkeys(buf, ":silent undo | echo\") + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_01', {}) + call term_sendkeys(buf, ":source samples/matchparen.vim\") + call term_sendkeys(buf, 'ct(') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_07', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_08', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_09', {}) + call term_sendkeys(buf, "\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_10', {}) + + call term_sendkeys(buf, ":silent undo | echo\") + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_01', {}) + call term_sendkeys(buf, "f(azz\zz\k0") + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_11', {}) + call term_sendkeys(buf, 'ct(') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_12', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_13', {}) + call term_sendkeys(buf, 'y') + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_14', {}) + call term_sendkeys(buf, "\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_change_wrapped_line_cpo_dollar_15', {}) + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab