mirror of
https://github.com/neovim/neovim.git
synced 2025-09-22 03:08:27 +00:00
refactor(signcol): smarter invalidation (#17533)
Previously b_signcols was invalidated whenever a sign was added/removed or when a buffer line was added/removed. This change introduces a sentinel linenr_T into the buffer state which is a line number used to determine the signcolumn. With this information, we can invalidate the signcolumn less often. Now the signcolumn is only invalidated when a sign or line at the sentinel line number is removed.
This commit is contained in:
@@ -1737,7 +1737,7 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, int fl
|
|||||||
buf = xcalloc(1, sizeof(buf_T));
|
buf = xcalloc(1, sizeof(buf_T));
|
||||||
// init b: variables
|
// init b: variables
|
||||||
buf->b_vars = tv_dict_alloc();
|
buf->b_vars = tv_dict_alloc();
|
||||||
buf->b_signcols_valid = false;
|
buf->b_signcols.valid = false;
|
||||||
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
|
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
|
||||||
buf_init_changedtick(buf);
|
buf_init_changedtick(buf);
|
||||||
}
|
}
|
||||||
@@ -5468,6 +5468,8 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
|||||||
int linesum = 0;
|
int linesum = 0;
|
||||||
linenr_T curline = 0;
|
linenr_T curline = 0;
|
||||||
|
|
||||||
|
buf->b_signcols.sentinel = 0;
|
||||||
|
|
||||||
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
||||||
if (sign->se_lnum > curline) {
|
if (sign->se_lnum > curline) {
|
||||||
// Counted all signs, now add extmark signs
|
// Counted all signs, now add extmark signs
|
||||||
@@ -5475,13 +5477,14 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
|||||||
linesum += decor_signcols(buf, &decor_state, (int)curline-1, (int)curline-1,
|
linesum += decor_signcols(buf, &decor_state, (int)curline-1, (int)curline-1,
|
||||||
maximum-linesum);
|
maximum-linesum);
|
||||||
}
|
}
|
||||||
|
curline = sign->se_lnum;
|
||||||
if (linesum > signcols) {
|
if (linesum > signcols) {
|
||||||
signcols = linesum;
|
signcols = linesum;
|
||||||
|
buf->b_signcols.sentinel = curline;
|
||||||
if (signcols >= maximum) {
|
if (signcols >= maximum) {
|
||||||
return maximum;
|
return maximum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curline = sign->se_lnum;
|
|
||||||
linesum = 0;
|
linesum = 0;
|
||||||
}
|
}
|
||||||
if (sign->se_has_text_or_icon) {
|
if (sign->se_has_text_or_icon) {
|
||||||
@@ -5504,6 +5507,7 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
|||||||
|
|
||||||
if (linesum > signcols) {
|
if (linesum > signcols) {
|
||||||
signcols = linesum;
|
signcols = linesum;
|
||||||
|
buf->b_signcols.sentinel = curline;
|
||||||
if (signcols >= maximum) {
|
if (signcols >= maximum) {
|
||||||
return maximum;
|
return maximum;
|
||||||
}
|
}
|
||||||
@@ -5512,28 +5516,96 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
|||||||
return signcols;
|
return signcols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invalidate the signcolumn if needed after deleting
|
||||||
|
/// signs between line1 and line2 (inclusive).
|
||||||
|
///
|
||||||
|
/// @param buf buffer to check
|
||||||
|
/// @param line1 start of region being deleted
|
||||||
|
/// @param line2 end of region being deleted
|
||||||
|
void buf_signcols_del_check(buf_T *buf, linenr_T line1, linenr_T line2)
|
||||||
|
{
|
||||||
|
if (!buf->b_signcols.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf->b_signcols.sentinel) {
|
||||||
|
buf->b_signcols.valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
linenr_T sent = buf->b_signcols.sentinel;
|
||||||
|
|
||||||
|
if (sent >= line1 && sent <= line2) {
|
||||||
|
// Only invalidate when removing signs at the sentinel line.
|
||||||
|
buf->b_signcols.valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-calculate the signcolumn after adding a sign.
|
||||||
|
///
|
||||||
|
/// @param buf buffer to check
|
||||||
|
/// @param added sign being added
|
||||||
|
void buf_signcols_add_check(buf_T *buf, sign_entry_T *added)
|
||||||
|
{
|
||||||
|
if (!buf->b_signcols.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!added || !buf->b_signcols.sentinel) {
|
||||||
|
buf->b_signcols.valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (added->se_lnum == buf->b_signcols.sentinel) {
|
||||||
|
if (buf->b_signcols.size == buf->b_signcols.max) {
|
||||||
|
buf->b_signcols.max++;
|
||||||
|
}
|
||||||
|
buf->b_signcols.size++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign_entry_T *s;
|
||||||
|
|
||||||
|
// Get first sign for added lnum
|
||||||
|
for (s = added; s->se_prev && s->se_lnum == s->se_prev->se_lnum; s = s->se_prev) {}
|
||||||
|
|
||||||
|
// Count signs for lnum
|
||||||
|
int linesum = 1;
|
||||||
|
for (; s->se_next && s->se_lnum == s->se_next->se_lnum; s = s->se_next) {
|
||||||
|
linesum++;
|
||||||
|
}
|
||||||
|
linesum += decor_signcols(buf, &decor_state, (int)s->se_lnum-1, (int)s->se_lnum-1,
|
||||||
|
SIGN_SHOW_MAX-linesum);
|
||||||
|
|
||||||
|
if (linesum > buf->b_signcols.size) {
|
||||||
|
buf->b_signcols.size = linesum;
|
||||||
|
buf->b_signcols.max = linesum;
|
||||||
|
buf->b_signcols.sentinel = added->se_lnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int buf_signcols(buf_T *buf, int maximum)
|
int buf_signcols(buf_T *buf, int maximum)
|
||||||
{
|
{
|
||||||
// The maximum can be determined from 'signcolumn' which is window scoped so
|
// The maximum can be determined from 'signcolumn' which is window scoped so
|
||||||
// need to invalidate signcols if the maximum is greater than the previous
|
// need to invalidate signcols if the maximum is greater than the previous
|
||||||
// maximum.
|
// maximum.
|
||||||
if (maximum > buf->b_signcols_max) {
|
if (maximum > buf->b_signcols.max) {
|
||||||
buf->b_signcols_valid = false;
|
buf->b_signcols.valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buf->b_signcols_valid) {
|
if (!buf->b_signcols.valid) {
|
||||||
int signcols = buf_signcols_inner(buf, maximum);
|
int signcols = buf_signcols_inner(buf, maximum);
|
||||||
// Check if we need to redraw
|
// Check if we need to redraw
|
||||||
if (signcols != buf->b_signcols) {
|
if (signcols != buf->b_signcols.size) {
|
||||||
buf->b_signcols = signcols;
|
buf->b_signcols.size = signcols;
|
||||||
buf->b_signcols_max = maximum;
|
buf->b_signcols.max = maximum;
|
||||||
redraw_buf_later(buf, NOT_VALID);
|
redraw_buf_later(buf, NOT_VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->b_signcols_valid = true;
|
buf->b_signcols.valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf->b_signcols;
|
return buf->b_signcols.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get "buf->b_fname", use "[No Name]" if it is NULL.
|
// Get "buf->b_fname", use "[No Name]" if it is NULL.
|
||||||
|
@@ -862,9 +862,12 @@ struct file_buffer {
|
|||||||
// may use a different synblock_T.
|
// may use a different synblock_T.
|
||||||
|
|
||||||
sign_entry_T *b_signlist; // list of placed signs
|
sign_entry_T *b_signlist; // list of placed signs
|
||||||
int b_signcols; // last calculated number of sign columns
|
struct {
|
||||||
bool b_signcols_valid; // calculated sign columns is valid
|
int size; // last calculated number of sign columns
|
||||||
int b_signcols_max; // Maximum value b_signcols is valid for.
|
bool valid; // calculated sign columns is valid
|
||||||
|
linenr_T sentinel; // a line number which is holding up the signcolumn
|
||||||
|
int max; // Maximum value size is valid for.
|
||||||
|
} b_signcols;
|
||||||
|
|
||||||
Terminal *terminal; // Terminal instance associated with the buffer
|
Terminal *terminal; // Terminal instance associated with the buffer
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
|
||||||
|
#include "nvim/buffer.h"
|
||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
#include "nvim/highlight.h"
|
#include "nvim/highlight.h"
|
||||||
@@ -67,11 +68,6 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
|
|||||||
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||||
{
|
{
|
||||||
if (row2 >= row1) {
|
if (row2 >= row1) {
|
||||||
if (decor && decor->sign_text) {
|
|
||||||
buf->b_signcols_valid = false;
|
|
||||||
changed_line_abv_curs();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decor || decor->hl_id || decor_has_sign(decor)) {
|
if (!decor || decor->hl_id || decor_has_sign(decor)) {
|
||||||
redraw_buf_range_later(buf, row1+1, row2+1);
|
redraw_buf_range_later(buf, row1+1, row2+1);
|
||||||
}
|
}
|
||||||
@@ -99,6 +95,9 @@ void decor_remove(buf_T *buf, int row, int row2, Decoration *decor)
|
|||||||
assert(buf->b_signs > 0);
|
assert(buf->b_signs > 0);
|
||||||
buf->b_signs--;
|
buf->b_signs--;
|
||||||
}
|
}
|
||||||
|
if (row2 >= row && decor->sign_text) {
|
||||||
|
buf_signcols_del_check(buf, row+1, row2+1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
decor_free(decor);
|
decor_free(decor);
|
||||||
}
|
}
|
||||||
|
@@ -147,6 +147,10 @@ revised:
|
|||||||
if (decor_has_sign(decor)) {
|
if (decor_has_sign(decor)) {
|
||||||
buf->b_signs++;
|
buf->b_signs++;
|
||||||
}
|
}
|
||||||
|
if (decor->sign_text) {
|
||||||
|
// TODO(lewis6991): smarter invalidation
|
||||||
|
buf_signcols_add_check(buf, NULL);
|
||||||
|
}
|
||||||
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
|
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -196,7 +196,8 @@ static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int
|
|||||||
if (next != NULL) {
|
if (next != NULL) {
|
||||||
next->se_prev = newsign;
|
next->se_prev = newsign;
|
||||||
}
|
}
|
||||||
buf->b_signcols_valid = false;
|
|
||||||
|
buf_signcols_add_check(buf, newsign);
|
||||||
|
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
// When adding first sign need to redraw the windows to create the
|
// When adding first sign need to redraw the windows to create the
|
||||||
@@ -541,7 +542,6 @@ linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group)
|
|||||||
sign_entry_T *next; // the next sign in a b_signlist
|
sign_entry_T *next; // the next sign in a b_signlist
|
||||||
linenr_T lnum; // line number whose sign was deleted
|
linenr_T lnum; // line number whose sign was deleted
|
||||||
|
|
||||||
buf->b_signcols_valid = false;
|
|
||||||
lastp = &buf->b_signlist;
|
lastp = &buf->b_signlist;
|
||||||
lnum = 0;
|
lnum = 0;
|
||||||
for (sign = buf->b_signlist; sign != NULL; sign = next) {
|
for (sign = buf->b_signlist; sign != NULL; sign = next) {
|
||||||
@@ -554,6 +554,7 @@ linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group)
|
|||||||
next->se_prev = sign->se_prev;
|
next->se_prev = sign->se_prev;
|
||||||
}
|
}
|
||||||
lnum = sign->se_lnum;
|
lnum = sign->se_lnum;
|
||||||
|
buf_signcols_del_check(buf, lnum, lnum);
|
||||||
if (sign->se_group != NULL) {
|
if (sign->se_group != NULL) {
|
||||||
sign_group_unref(sign->se_group->sg_name);
|
sign_group_unref(sign->se_group->sg_name);
|
||||||
}
|
}
|
||||||
@@ -675,7 +676,7 @@ void buf_delete_signs(buf_T *buf, char_u *group)
|
|||||||
lastp = &sign->se_next;
|
lastp = &sign->se_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf->b_signcols_valid = false;
|
buf_signcols_del_check(buf, 1, MAXLNUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
|
/// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
|
||||||
@@ -737,14 +738,19 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_a
|
|||||||
int is_fixed = 0;
|
int is_fixed = 0;
|
||||||
int signcol = win_signcol_configured(curwin, &is_fixed);
|
int signcol = win_signcol_configured(curwin, &is_fixed);
|
||||||
|
|
||||||
curbuf->b_signcols_valid = false;
|
bool delete = amount == MAXLNUM;
|
||||||
|
|
||||||
|
if (delete) {
|
||||||
|
buf_signcols_del_check(curbuf, line1, line2);
|
||||||
|
}
|
||||||
|
|
||||||
lastp = &curbuf->b_signlist;
|
lastp = &curbuf->b_signlist;
|
||||||
|
|
||||||
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
|
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
|
||||||
next = sign->se_next;
|
next = sign->se_next;
|
||||||
new_lnum = sign->se_lnum;
|
new_lnum = sign->se_lnum;
|
||||||
if (sign->se_lnum >= line1 && sign->se_lnum <= line2) {
|
if (sign->se_lnum >= line1 && sign->se_lnum <= line2) {
|
||||||
if (amount != MAXLNUM) {
|
if (!delete) {
|
||||||
new_lnum += amount;
|
new_lnum += amount;
|
||||||
} else if (!is_fixed || signcol >= 2) {
|
} else if (!is_fixed || signcol >= 2) {
|
||||||
*lastp = next;
|
*lastp = next;
|
||||||
|
Reference in New Issue
Block a user