diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-02-12 13:02:27 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-12 13:02:27 +0800 |
commit | 929e1b7f1c35679424989f5ebfc78f095bb434d9 (patch) | |
tree | 9926fa873746da91cb2564c4d2606ff11829817e /src/nvim/change.c | |
parent | 950a0ac61c70362f168338b815675ac60b1d72dc (diff) | |
download | rneovim-929e1b7f1c35679424989f5ebfc78f095bb434d9.tar.gz rneovim-929e1b7f1c35679424989f5ebfc78f095bb434d9.tar.bz2 rneovim-929e1b7f1c35679424989f5ebfc78f095bb434d9.zip |
perf(extmarks): avoid unnecessary invalidations for virt_text (#27435)
Invalidation of most w_valid flags isn't needed when adding or removing
virtual text below cursor.
Diffstat (limited to 'src/nvim/change.c')
-rw-r--r-- | src/nvim/change.c | 124 |
1 files changed, 70 insertions, 54 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c index e01921a826..2db3d007d7 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -163,6 +163,71 @@ void changed_internal(buf_T *buf) need_maketitle = true; // set window title later } +/// Invalidate a window's w_valid flags and w_lines[] entries after changing lines. +static void changed_lines_invalidate_win(win_T *wp, linenr_T lnum, colnr_T col, linenr_T lnume, + linenr_T xtra) +{ + // If the changed line is in a range of previously folded lines, + // compare with the first line in that range. + if (wp->w_cursor.lnum <= lnum) { + int i = find_wl_entry(wp, lnum); + if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) { + changed_line_abv_curs_win(wp); + } + } + + if (wp->w_cursor.lnum > lnum) { + changed_line_abv_curs_win(wp); + } else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) { + changed_cline_bef_curs(wp); + } + if (wp->w_botline >= lnum) { + // Assume that botline doesn't change (inserted lines make + // other lines scroll down below botline). + approximate_botline_win(wp); + } + + // Check if any w_lines[] entries have become invalid. + // For entries below the change: Correct the lnums for inserted/deleted lines. + // Makes it possible to stop displaying after the change. + for (int i = 0; i < wp->w_lines_valid; i++) { + if (wp->w_lines[i].wl_valid) { + if (wp->w_lines[i].wl_lnum >= lnum) { + // Do not change wl_lnum at index zero, it is used to compare with w_topline. + // Invalidate it instead. + // If lines haven been inserted/deleted and the buffer has virt_lines, + // invalidate the line after the changed lines as some virt_lines may + // now be drawn above a different line. + if (i == 0 || wp->w_lines[i].wl_lnum < lnume + || (xtra != 0 && wp->w_lines[i].wl_lnum == lnume + && buf_meta_total(wp->w_buffer, kMTMetaLines) > 0)) { + // line included in change + wp->w_lines[i].wl_valid = false; + } else if (xtra != 0) { + // line below change + wp->w_lines[i].wl_lnum += xtra; + wp->w_lines[i].wl_lastlnum += xtra; + } + } else if (wp->w_lines[i].wl_lastlnum >= lnum) { + // change somewhere inside this range of folded lines, + // may need to be redrawn + wp->w_lines[i].wl_valid = false; + } + } + } +} + +/// Line changed_lines_invalidate_win(), but for all windows displaying a buffer. +void changed_lines_invalidate_buf(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, + linenr_T xtra) +{ + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer == buf) { + changed_lines_invalidate_win(wp, lnum, col, lnume, xtra); + } + } +} + /// Common code for when a change was made. /// See changed_lines() for the arguments. /// Careful: may trigger autocommands that reload the buffer. @@ -296,55 +361,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum wp->w_cline_folded = folded; } - // If the changed line is in a range of previously folded lines, - // compare with the first line in that range. - if (wp->w_cursor.lnum <= lnum) { - int i = find_wl_entry(wp, lnum); - if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) { - changed_line_abv_curs_win(wp); - } - } - - if (wp->w_cursor.lnum > lnum) { - changed_line_abv_curs_win(wp); - } else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) { - changed_cline_bef_curs(wp); - } - if (wp->w_botline >= lnum) { - // Assume that botline doesn't change (inserted lines make - // other lines scroll down below botline). - approximate_botline_win(wp); - } - - // Check if any w_lines[] entries have become invalid. - // For entries below the change: Correct the lnums for - // inserted/deleted lines. Makes it possible to stop displaying - // after the change. - for (int i = 0; i < wp->w_lines_valid; i++) { - if (wp->w_lines[i].wl_valid) { - if (wp->w_lines[i].wl_lnum >= lnum) { - // Do not change wl_lnum at index zero, it is used to - // compare with w_topline. Invalidate it instead. - // If the buffer has virt_lines, invalidate the line - // after the changed lines as the virt_lines for a - // changed line may become invalid. - if (i == 0 || wp->w_lines[i].wl_lnum < lnume - || (wp->w_lines[i].wl_lnum == lnume - && buf_meta_total(wp->w_buffer, kMTMetaLines) > 0)) { - // line included in change - wp->w_lines[i].wl_valid = false; - } else if (xtra != 0) { - // line below change - wp->w_lines[i].wl_lnum += xtra; - wp->w_lines[i].wl_lastlnum += xtra; - } - } else if (wp->w_lines[i].wl_lastlnum >= lnum) { - // change somewhere inside this range of folded lines, - // may need to be redrawn - wp->w_lines[i].wl_valid = false; - } - } - } + changed_lines_invalidate_win(wp, lnum, col, lnume, xtra); // Take care of side effects for setting w_topline when folds have // changed. Esp. when the buffer was changed in another window. @@ -488,13 +505,13 @@ void deleted_lines_mark(linenr_T lnum, int count) } /// Marks the area to be redrawn after a change. -/// Consider also calling changed_line_display_buf(). +/// Consider also calling changed_lines_invalidate_buf(). /// /// @param buf the buffer where lines were changed /// @param lnum first line with change /// @param lnume line below last changed line /// @param xtra number of extra lines (negative when deleting) -void buf_redraw_changed_lines_later(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra) +void changed_lines_redraw_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra) { if (buf->b_mod_set) { // find the maximum area that must be redisplayed @@ -542,7 +559,7 @@ void buf_redraw_changed_lines_later(buf_T *buf, linenr_T lnum, linenr_T lnume, l void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra, bool do_buf_event) { - buf_redraw_changed_lines_later(buf, lnum, lnume, xtra); + changed_lines_redraw_buf(buf, lnum, lnume, xtra); if (xtra == 0 && curwin->w_p_diff && curwin->w_buffer == buf && !diff_internal()) { // When the number of lines doesn't change then mark_adjust() isn't @@ -555,8 +572,7 @@ void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linen redraw_later(wp, UPD_VALID); wlnum = diff_lnum_win(lnum, wp); if (wlnum > 0) { - buf_redraw_changed_lines_later(wp->w_buffer, wlnum, - lnume - lnum + wlnum, 0); + changed_lines_redraw_buf(wp->w_buffer, wlnum, lnume - lnum + wlnum, 0); } } } |