diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/screen.c | 51 | ||||
-rw-r--r-- | src/nvim/testdir/test_matchadd_conceal.vim | 45 |
2 files changed, 85 insertions, 11 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ea2b14c326..a75b146024 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -698,8 +698,10 @@ static void win_update(win_T *wp) int didline = FALSE; /* if TRUE, we finished the last line */ int i; long j; - static int recursive = FALSE; /* being called recursively */ - int old_botline = wp->w_botline; + static bool recursive = false; // being called recursively + const linenr_T old_botline = wp->w_botline; + const int old_wrow = wp->w_wrow; + const int old_wcol = wp->w_wcol; // Remember what happened to the previous line. #define DID_NONE 1 // didn't update a line #define DID_LINE 2 // updated a normal line @@ -1639,18 +1641,51 @@ static void win_update(win_T *wp) wp->w_valid |= VALID_BOTLINE; wp->w_viewport_invalid = true; if (wp == curwin && wp->w_botline != old_botline && !recursive) { - recursive = TRUE; + const linenr_T old_topline = wp->w_topline; + const int new_wcol = wp->w_wcol; + recursive = true; curwin->w_valid &= ~VALID_TOPLINE; - update_topline(); /* may invalidate w_botline again */ - if (must_redraw != 0) { - /* Don't update for changes in buffer again. */ + update_topline(); // may invalidate w_botline again + + if (old_wcol != new_wcol + && (wp->w_valid & (VALID_WCOL|VALID_WROW)) + != (VALID_WCOL|VALID_WROW)) { + // A win_line() call applied a fix to screen cursor column to + // accomodate concealment of cursor line, but in this call to + // update_topline() the cursor's row or column got invalidated. + // If they are left invalid, setcursor() will recompute them + // but there won't be any further win_line() call to re-fix the + // column and the cursor will end up misplaced. So we call + // cursor validation now and reapply the fix again (or call + // win_line() to do it for us). + validate_cursor(); + if (wp->w_wcol == old_wcol + && wp->w_wrow == old_wrow + && old_topline == wp->w_topline) { + wp->w_wcol = new_wcol; + } else { + redrawWinline(wp, wp->w_cursor.lnum); + } + } + // New redraw either due to updated topline or due to wcol fix. + if (wp->w_redr_type != 0) { + // Don't update for changes in buffer again. i = curbuf->b_mod_set; curbuf->b_mod_set = false; + j = curbuf->b_mod_xlines; + curbuf->b_mod_xlines = 0; win_update(curwin); - must_redraw = 0; curbuf->b_mod_set = i; + curbuf->b_mod_xlines = j; + } + // Other windows might have w_redr_type raised in update_topline(). + must_redraw = 0; + FOR_ALL_WINDOWS_IN_TAB(wwp, curtab) { + if (wwp->w_redr_type > must_redraw) { + must_redraw = wwp->w_redr_type; + } } - recursive = FALSE; + recursive = false; } } diff --git a/src/nvim/testdir/test_matchadd_conceal.vim b/src/nvim/testdir/test_matchadd_conceal.vim index b918525dbc..cb70b2857f 100644 --- a/src/nvim/testdir/test_matchadd_conceal.vim +++ b/src/nvim/testdir/test_matchadd_conceal.vim @@ -1,9 +1,11 @@ " Test for matchadd() and conceal feature -if !has('conceal') - finish -endif + +source check.vim +CheckFeature conceal source shared.vim +source term_util.vim +source view_util.vim function! Test_simple_matchadd() new @@ -273,3 +275,40 @@ function! Test_matchadd_and_syn_conceal() call assert_notequal(screenattr(1, 11) , screenattr(1, 12)) call assert_equal(screenattr(1, 11) , screenattr(1, 32)) endfunction + +func Test_cursor_column_in_concealed_line_after_window_scroll() + CheckRunVimInTerminal + + " Test for issue #5012 fix. + " For a concealed line with cursor, there should be no window's cursor + " position invalidation during win_update() after scrolling attempt that is + " not successful and no real topline change happens. The invalidation would + " cause a window's cursor position recalc outside of win_line() where it's + " not possible to take conceal into account. + let lines =<< trim END + 3split + let m = matchadd('Conceal', '=') + setl conceallevel=2 concealcursor=nc + normal gg + "==expr== + END + call writefile(lines, 'Xcolesearch') + let buf = RunVimInTerminal('Xcolesearch', {}) + + " Jump to something that is beyond the bottom of the window, + " so there's a scroll down. + call term_sendkeys(buf, ":so %\<CR>") + call term_sendkeys(buf, "/expr\<CR>") + call term_wait(buf) + + " Are the concealed parts of the current line really hidden? + let cursor_row = term_scrape(buf, '.')->map({_, e -> e.chars})->join('') + call assert_equal('"expr', cursor_row) + + " BugFix check: Is the window's cursor column properly updated for hidden + " parts of the current line? + call assert_equal(2, term_getcursor(buf)[1]) + + call StopVimInTerminal(buf) + call delete('Xcolesearch') +endfunc |