From 3e9b4e917d0783d0414192c3ad231cfcb813e73f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 23 Mar 2022 11:30:02 +0800 Subject: vim-patch:8.2.4591: cursor line not updated when a callback moves the cursor Problem: Cursor line not updated when a callback moves the cursor. Solution: Check if the cursor moved. (closes vim/vim#9970) https://github.com/vim/vim/commit/e7a74d53754765f22ef8ce71c915bb669d5f7f3f redraw_after_callback() is N/A. Nvim handles timers on the main loop. --- src/nvim/normal.c | 8 +------- src/nvim/screen.c | 17 ++++++++++++++++- src/nvim/testdir/test_cursorline.vim | 26 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index f402865d2d..e773351d63 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1296,13 +1296,7 @@ static void normal_redraw(NormalState *s) } // Might need to update for 'cursorline'. - // When 'cursorlineopt' is "screenline" need to redraw always. - if (curwin->w_p_cul - && (curwin->w_last_cursorline != curwin->w_cursor.lnum - || (curwin->w_p_culopt_flags & CULOPT_SCRLINE)) - && !char_avail()) { - redraw_later(curwin, VALID); - } + check_redraw_cursorline(); if (VIsual_active) { update_curbuf(INVERTED); // update inverted part diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 0194149b1b..27011c6f1e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -737,6 +737,9 @@ static void win_update(win_T *wp, DecorProviders *providers) #define DID_FOLD 3 // updated a folded line int did_update = DID_NONE; linenr_T syntax_last_parsed = 0; // last parsed text line + // remember the current w_last_cursorline, it changes when drawing the new + // cursor line + linenr_T last_cursorline = wp->w_last_cursorline; linenr_T mod_top = 0; linenr_T mod_bot = 0; int save_got_int; @@ -1368,7 +1371,7 @@ static void win_update(win_T *wp, DecorProviders *providers) || (wp->w_match_head != NULL && buf->b_mod_xlines != 0))))) || (wp->w_p_cul && (lnum == wp->w_cursor.lnum - || lnum == wp->w_last_cursorline))) { + || lnum == last_cursorline))) { if (lnum == mod_top) { top_to_mod = false; } @@ -7615,3 +7618,15 @@ win_T *get_win_by_grid_handle(handle_T handle) return NULL; } +/// Check if the cursor moved and 'cursorline' is set. Mark for a VALID redraw +/// if needed. +void check_redraw_cursorline(void) +{ + // When 'cursorlineopt' is "screenline" need to redraw always. + if (curwin->w_p_cul + && (curwin->w_last_cursorline != curwin->w_cursor.lnum + || (curwin->w_p_culopt_flags & CULOPT_SCRLINE)) + && !char_avail()) { + redraw_later(curwin, VALID); + } +} diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim index 39d8b901ed..bf049ec779 100644 --- a/src/nvim/testdir/test_cursorline.vim +++ b/src/nvim/testdir/test_cursorline.vim @@ -268,4 +268,30 @@ END call delete('Xtextfile') endfunc +func Test_cursorline_callback() + CheckScreendump + CheckFeature timers + + let lines =<< trim END + call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd']) + set cursorline + call cursor(4, 1) + + func Func(timer) + call cursor(2, 1) + endfunc + + call timer_start(300, 'Func') + END + call writefile(lines, 'Xcul_timer') + + let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8}) + call TermWait(buf, 310) + call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {}) + + call StopVimInTerminal(buf) + call delete('Xcul_timer') +endfunc + + " vim: shiftwidth=2 sts=2 expandtab -- cgit From c29a14d1fa58d5472bd14fec99c5b4228ed38b24 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 23 Mar 2022 11:28:32 +0800 Subject: perf(screen): reduce cursorline redrawing when jumping around vim-patch:8.2.4614: redrawing too much when 'cursorline' is set Problem: Redrawing too much when 'cursorline' is set and jumping around. Solution: Rely on win_update() to redraw the current and previous cursor line, do not mark lines as modified. (closes vim/vim#9996) https://github.com/vim/vim/commit/c20e46a4e3efcd408ef132872238144ea34f7ae5 This doesn't match the patch exactly, because I missed some lines when porting patch 8.1.2029, and these lines were removed in this patch. This also makes win_update() always update for 'concealcursor' like how it always updates for 'cursorline', as 'cursorline' and 'concealcursor' redrawing logic has been unified in Nvim. As redrawing for 'cursorline' now always only requires VALID redraw type, it is no longer necessary to call redraw_for_cursorline() in nvim_win_set_cursor(). --- src/nvim/api/window.c | 1 - src/nvim/move.c | 22 ++-------------------- src/nvim/option.c | 5 +---- src/nvim/screen.c | 14 +++++++------- 4 files changed, 10 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index be43708604..fd33a82be3 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -119,7 +119,6 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) update_topline_win(win); redraw_later(win, VALID); - redraw_for_cursorline(win); win->w_redr_status = true; } diff --git a/src/nvim/move.c b/src/nvim/move.c index 27cc2b341c..751e0046bc 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -95,11 +95,6 @@ static void comp_botline(win_T *wp) win_check_anchored_floats(wp); } -void reset_cursorline(void) -{ - curwin->w_last_cursorline = 0; -} - // Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set. void redraw_for_cursorline(win_T *wp) FUNC_ATTR_NONNULL_ALL @@ -107,21 +102,8 @@ void redraw_for_cursorline(win_T *wp) if ((wp->w_p_rnu || win_cursorline_standout(wp)) && (wp->w_valid & VALID_CROW) == 0 && !pum_visible()) { - if (wp->w_p_rnu) { - // win_line() will redraw the number column only. - redraw_later(wp, VALID); - } - if (win_cursorline_standout(wp)) { - if (wp->w_redr_type <= VALID && wp->w_last_cursorline != 0) { - // "w_last_cursorline" may be outdated, worst case we redraw - // too much. This is optimized for moving the cursor around in - // the current window. - redrawWinline(wp, wp->w_last_cursorline); - redrawWinline(wp, wp->w_cursor.lnum); - } else { - redraw_later(wp, SOME_VALID); - } - } + // win_line() will redraw the number column and cursorline only. + redraw_later(wp, VALID); } } diff --git a/src/nvim/option.c b/src/nvim/option.c index ffd009be89..9fd0e0b222 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3962,11 +3962,8 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } else if ((int *)varp == &p_lnr) { // 'langnoremap' -> !'langremap' p_lrm = !p_lnr; - } else if ((int *)varp == &curwin->w_p_cul && !value && old_value) { - // 'cursorline' - reset_cursorline(); - // 'undofile' } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) { + // 'undofile' // Only take action when the option was set. When reset we do not // delete the undo file, the option may be set again without making // any changes in between. diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 27011c6f1e..5a10543559 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -737,9 +737,6 @@ static void win_update(win_T *wp, DecorProviders *providers) #define DID_FOLD 3 // updated a folded line int did_update = DID_NONE; linenr_T syntax_last_parsed = 0; // last parsed text line - // remember the current w_last_cursorline, it changes when drawing the new - // cursor line - linenr_T last_cursorline = wp->w_last_cursorline; linenr_T mod_top = 0; linenr_T mod_bot = 0; int save_got_int; @@ -1326,6 +1323,8 @@ static void win_update(win_T *wp, DecorProviders *providers) DecorProviders line_providers; decor_providers_invoke_win(wp, providers, &line_providers, &provider_err); + bool cursorline_standout = win_cursorline_standout(wp); + for (;;) { /* stop updating when reached the end of the window (check for _past_ * the end of the window is at the end of the loop) */ @@ -1370,8 +1369,8 @@ static void win_update(win_T *wp, DecorProviders *providers) // if lines were inserted or deleted || (wp->w_match_head != NULL && buf->b_mod_xlines != 0))))) - || (wp->w_p_cul && (lnum == wp->w_cursor.lnum - || lnum == last_cursorline))) { + || (cursorline_standout && lnum == wp->w_cursor.lnum) + || lnum == wp->w_last_cursorline) { if (lnum == mod_top) { top_to_mod = false; } @@ -1604,6 +1603,9 @@ static void win_update(win_T *wp, DecorProviders *providers) * End of loop over all window lines. */ + // Now that the window has been redrawn with the old and new cursor line, + // update w_last_cursorline. + wp->w_last_cursorline = cursorline_standout ? wp->w_cursor.lnum : 0; if (idx > wp->w_lines_valid) { wp->w_lines_valid = idx; @@ -2383,8 +2385,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc } area_highlighting = true; } - // Update w_last_cursorline even if Visual mode is active. - wp->w_last_cursorline = wp->w_cursor.lnum; } memset(sattrs, 0, sizeof(sattrs)); -- cgit