mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 12:45:17 -07:00
perf(column): keep track of number of lines that hold up the 'signcolumn'
Problem: The entire marktree needs to be traversed each time a sign is removed from the sentinel line. Solution: Remove sentinel line and instead keep track of the number of lines that hold up the 'signcolumn' in "max_count". Adjust this number for added/removed signs, and set it to 0 when the maximum number of signs on a line changes. Only when "max_count" is decremented to 0 due to sign removal do we need to check the entire buffer. Also replace "invalid_top" and "invalid_bot" with a map of invalid ranges, further reducing the number of lines to be checked. Also improve tree traversal when counting the number of signs. Instead of looping over the to be checked range and counting the overlap for each row, keep track of the overlap in an array and add this to the count.
This commit is contained in:
parent
e42f03264b
commit
4a34da82c1
@ -2189,7 +2189,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
|
||||
int cul_id = 0;
|
||||
int num_id = 0;
|
||||
linenr_T lnum = statuscol_lnum;
|
||||
wp->w_scwidth = win_signcol_count(wp);
|
||||
decor_redraw_signs(wp, wp->w_buffer, lnum - 1, sattrs, &line_id, &cul_id, &num_id);
|
||||
|
||||
statuscol.sattrs = sattrs;
|
||||
|
@ -750,6 +750,8 @@ void buf_clear(void)
|
||||
{
|
||||
linenr_T line_count = curbuf->b_ml.ml_line_count;
|
||||
extmark_free_all(curbuf); // delete any extmarks
|
||||
map_destroy(int, curbuf->b_signcols.invalid);
|
||||
*curbuf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
|
||||
while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) {
|
||||
ml_delete(1, false);
|
||||
}
|
||||
@ -920,6 +922,8 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
|
||||
}
|
||||
uc_clear(&buf->b_ucmds); // clear local user commands
|
||||
extmark_free_all(buf); // delete any extmarks
|
||||
map_destroy(int, buf->b_signcols.invalid);
|
||||
*buf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
|
||||
map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings
|
||||
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
|
||||
XFREE_CLEAR(buf->b_start_fenc);
|
||||
@ -1844,7 +1848,6 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags)
|
||||
buf = xcalloc(1, sizeof(buf_T));
|
||||
// init b: variables
|
||||
buf->b_vars = tv_dict_alloc();
|
||||
buf->b_signcols.sentinel = 0;
|
||||
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
|
||||
buf_init_changedtick(buf);
|
||||
}
|
||||
@ -4026,67 +4029,6 @@ char *buf_spname(buf_T *buf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Invalidate the signcolumn if needed after deleting a sign ranging from line1 to line2.
|
||||
void buf_signcols_del_check(buf_T *buf, linenr_T line1, linenr_T line2)
|
||||
{
|
||||
linenr_T sent = buf->b_signcols.sentinel;
|
||||
if (sent >= line1 && sent <= line2) {
|
||||
// When removed sign overlaps the sentinel line, entire buffer needs to be checked.
|
||||
buf->b_signcols.sentinel = buf->b_signcols.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Invalidate the signcolumn if needed after adding a sign ranging from line1 to line2.
|
||||
void buf_signcols_add_check(buf_T *buf, linenr_T line1, linenr_T line2)
|
||||
{
|
||||
if (!buf->b_signcols.sentinel) {
|
||||
return;
|
||||
}
|
||||
|
||||
linenr_T sent = buf->b_signcols.sentinel;
|
||||
if (sent >= line1 && sent <= line2) {
|
||||
// If added sign overlaps sentinel line, increment without invalidating.
|
||||
if (buf->b_signcols.size == buf->b_signcols.max) {
|
||||
buf->b_signcols.max++;
|
||||
}
|
||||
buf->b_signcols.size++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line1 < buf->b_signcols.invalid_top) {
|
||||
buf->b_signcols.invalid_top = line1;
|
||||
}
|
||||
if (line2 > buf->b_signcols.invalid_bot) {
|
||||
buf->b_signcols.invalid_bot = line2;
|
||||
}
|
||||
}
|
||||
|
||||
int buf_signcols(buf_T *buf, int max)
|
||||
{
|
||||
if (!buf->b_signs_with_text) {
|
||||
buf->b_signcols.size = 0;
|
||||
} else if (max <= 1 && buf->b_signs_with_text >= (size_t)max) {
|
||||
buf->b_signcols.size = max;
|
||||
} else {
|
||||
linenr_T sent = buf->b_signcols.sentinel;
|
||||
if (!sent || max > buf->b_signcols.max) {
|
||||
// Recheck if the window scoped maximum 'signcolumn' is greater than the
|
||||
// previous maximum or if there is no sentinel line yet.
|
||||
buf->b_signcols.invalid_top = sent ? sent : 1;
|
||||
buf->b_signcols.invalid_bot = sent ? sent : buf->b_ml.ml_line_count;
|
||||
}
|
||||
|
||||
if (buf->b_signcols.invalid_bot) {
|
||||
decor_validate_signcols(buf, max);
|
||||
}
|
||||
}
|
||||
|
||||
buf->b_signcols.max = max;
|
||||
buf->b_signcols.invalid_top = MAXLNUM;
|
||||
buf->b_signcols.invalid_bot = 0;
|
||||
return buf->b_signcols.size;
|
||||
}
|
||||
|
||||
/// Get "buf->b_fname", use "[No Name]" if it is NULL.
|
||||
char *buf_get_fname(const buf_T *buf)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
|
@ -703,11 +703,10 @@ struct file_buffer {
|
||||
// may use a different synblock_T.
|
||||
|
||||
struct {
|
||||
int size; // last calculated number of sign columns
|
||||
int max; // maximum value size is valid for.
|
||||
linenr_T sentinel; // a line number which is holding up the signcolumn
|
||||
linenr_T invalid_top; // first invalid line number that needs to be checked
|
||||
linenr_T invalid_bot; // last invalid line number that needs to be checked
|
||||
int max; // maximum number of signs on a single line
|
||||
int max_count; // number of lines with max number of signs
|
||||
bool resized; // whether max changed at start of redraw
|
||||
Map(int, SignRange) invalid[1]; // map of invalid ranges to be checked
|
||||
} b_signcols;
|
||||
|
||||
Terminal *terminal; // Terminal instance associated with the buffer
|
||||
|
@ -203,21 +203,21 @@ void buf_put_decor_virt(buf_T *buf, DecorVirtText *vt)
|
||||
}
|
||||
|
||||
static int sign_add_id = 0;
|
||||
void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row, int row2)
|
||||
void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
|
||||
{
|
||||
if (sh->flags & kSHIsSign) {
|
||||
sh->sign_add_id = sign_add_id++;
|
||||
buf->b_signs++;
|
||||
if (sh->text.ptr) {
|
||||
buf->b_signs_with_text++;
|
||||
buf_signcols_add_check(buf, row + 1, row2 + 1);
|
||||
buf_signcols_invalidate_range(buf, row1, row2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool free)
|
||||
void buf_decor_remove(buf_T *buf, int row1, int row2, DecorInline decor, bool free)
|
||||
{
|
||||
decor_redraw(buf, row, row2, decor);
|
||||
decor_redraw(buf, row1, row2, decor);
|
||||
if (decor.ext) {
|
||||
DecorVirtText *vt = decor.data.ext.vt;
|
||||
while (vt) {
|
||||
@ -227,7 +227,7 @@ void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool fre
|
||||
uint32_t idx = decor.data.ext.sh_idx;
|
||||
while (idx != DECOR_ID_INVALID) {
|
||||
DecorSignHighlight *sh = &kv_A(decor_items, idx);
|
||||
buf_remove_decor_sh(buf, row, row2, sh);
|
||||
buf_remove_decor_sh(buf, row1, row2, sh);
|
||||
idx = sh->next;
|
||||
}
|
||||
if (free) {
|
||||
@ -249,7 +249,7 @@ void buf_remove_decor_virt(buf_T *buf, DecorVirtText *vt)
|
||||
}
|
||||
}
|
||||
|
||||
void buf_remove_decor_sh(buf_T *buf, int row, int row2, DecorSignHighlight *sh)
|
||||
void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
|
||||
{
|
||||
if (sh->flags & kSHIsSign) {
|
||||
assert(buf->b_signs > 0);
|
||||
@ -257,8 +257,8 @@ void buf_remove_decor_sh(buf_T *buf, int row, int row2, DecorSignHighlight *sh)
|
||||
if (sh->text.ptr) {
|
||||
assert(buf->b_signs_with_text > 0);
|
||||
buf->b_signs_with_text--;
|
||||
if (row2 >= row) {
|
||||
buf_signcols_del_check(buf, row + 1, row2 + 1);
|
||||
if (row2 >= row1) {
|
||||
buf_signcols_invalidate_range(buf, row1, row2, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -792,50 +792,128 @@ DecorSignHighlight *decor_find_sign(DecorInline decor)
|
||||
}
|
||||
}
|
||||
|
||||
// Increase the signcolumn size and update the sentinel line if necessary for
|
||||
// the invalidated range.
|
||||
void decor_validate_signcols(buf_T *buf, int max)
|
||||
/// If "count" is greater than current max, set it and reset "max_count".
|
||||
static void buf_signcols_validate_row(buf_T *buf, int count, int add)
|
||||
{
|
||||
int signcols = 0; // highest value of count
|
||||
int currow = buf->b_signcols.invalid_top - 1;
|
||||
// TODO(bfredl): only need to use marktree_itr_get_overlap once.
|
||||
// then we can process both start and end events and update state for each row
|
||||
for (; currow < buf->b_signcols.invalid_bot; currow++) {
|
||||
MarkTreeIter itr[1];
|
||||
if (!marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr)) {
|
||||
continue;
|
||||
}
|
||||
int del = add < 0 ? -add : 0;
|
||||
if (count > buf->b_signcols.max) {
|
||||
buf->b_signcols.max = count;
|
||||
buf->b_signcols.max_count = 0;
|
||||
buf->b_signcols.resized = true;
|
||||
}
|
||||
/// Add sign of "add" to "max_count"
|
||||
if (count == buf->b_signcols.max - del) {
|
||||
buf->b_signcols.max_count += (add > 0) - (add < 0);
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
MTPair pair;
|
||||
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
||||
if (!mt_invalid(pair.start) && (pair.start.flags & MT_FLAG_DECOR_SIGNTEXT)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
/// Validate a range by counting the number of overlapping signs and adjusting
|
||||
/// "b_signcols" accordingly.
|
||||
static void buf_signcols_validate_range(buf_T *buf, int row1, int row2, int add)
|
||||
{
|
||||
int count = 0; // Number of signs on the current line
|
||||
int currow = row1;
|
||||
MTPair pair = { 0 };
|
||||
MarkTreeIter itr[1];
|
||||
|
||||
while (itr->x) {
|
||||
MTKey mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row != currow) {
|
||||
break;
|
||||
}
|
||||
if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
|
||||
count++;
|
||||
}
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
// Allocate an array of integers holding the overlapping signs in the range.
|
||||
assert(row2 >= row1);
|
||||
int *overlap = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1));
|
||||
|
||||
if (count > signcols) {
|
||||
if (count >= buf->b_signcols.size) {
|
||||
buf->b_signcols.size = count;
|
||||
buf->b_signcols.sentinel = currow + 1;
|
||||
}
|
||||
if (count >= max) {
|
||||
return;
|
||||
}
|
||||
signcols = count;
|
||||
// First find the number of overlapping signs at "row1".
|
||||
marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr);
|
||||
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
||||
if (!mt_invalid(pair.start) && pair.start.flags & MT_FLAG_DECOR_SIGNTEXT) {
|
||||
overlap[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue traversing the marktree until beyond "row2". Increment "count" for
|
||||
// the start of a mark, increment the overlap array until the end of a paired mark.
|
||||
while (itr->x) {
|
||||
MTKey mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row > row2) {
|
||||
break;
|
||||
}
|
||||
// Finish the count at the previous row.
|
||||
if (mark.pos.row != currow) {
|
||||
buf_signcols_validate_row(buf, count + overlap[currow - row1], add);
|
||||
currow = mark.pos.row;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// Increment count and overlap array for the range of a paired sign mark.
|
||||
if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
|
||||
count++;
|
||||
if (mt_paired(mark)) {
|
||||
MTPos end = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
for (int i = mark.pos.row; i < MIN(row2, end.row); i++) {
|
||||
overlap[row2 - i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
buf_signcols_validate_row(buf, count + overlap[currow - row1], add);
|
||||
xfree(overlap);
|
||||
}
|
||||
|
||||
int buf_signcols_validate(win_T *wp, buf_T *buf, bool stc_check)
|
||||
{
|
||||
int start;
|
||||
SignRange range;
|
||||
map_foreach(buf->b_signcols.invalid, start, range, {
|
||||
// Leave rest of the ranges invalid if max is already greater than
|
||||
// configured maximum or resize is detected for 'statuscolumn' rebuild.
|
||||
if ((!stc_check || buf->b_signcols.resized)
|
||||
&& (range.add > 0 && buf->b_signcols.max >= wp->w_maxscwidth)) {
|
||||
return wp->w_maxscwidth;
|
||||
}
|
||||
buf_signcols_validate_range(buf, start, range.end, range.add);
|
||||
});
|
||||
|
||||
// Check if we need to scan the entire buffer.
|
||||
if (buf->b_signcols.max_count == 0) {
|
||||
buf->b_signcols.max = 0;
|
||||
buf->b_signcols.resized = true;
|
||||
buf_signcols_validate_range(buf, 0, buf->b_ml.ml_line_count, 0);
|
||||
}
|
||||
|
||||
map_clear(int, buf->b_signcols.invalid);
|
||||
return buf->b_signcols.max;
|
||||
}
|
||||
|
||||
static void buf_signcols_invalidate_range(buf_T *buf, int row1, int row2, int add)
|
||||
{
|
||||
if (!buf->b_signs_with_text) {
|
||||
buf->b_signcols.max = buf->b_signcols.max_count = 0;
|
||||
buf->b_signcols.resized = true;
|
||||
map_clear(int, buf->b_signcols.invalid);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove an invalid range if sum of added/removed signs is now 0.
|
||||
SignRange *srp = map_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
|
||||
if (srp && srp->end == row2 && srp->add + add == 0) {
|
||||
map_del(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge with overlapping invalid range.
|
||||
int start;
|
||||
SignRange range;
|
||||
map_foreach(buf->b_signcols.invalid, start, range, {
|
||||
if (row1 <= range.end && start <= row2) {
|
||||
row1 = MIN(row1, start);
|
||||
row2 = MAX(row2, range.end);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
srp = map_put_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL, NULL);
|
||||
srp->end = row2;
|
||||
srp->add += add;
|
||||
}
|
||||
|
||||
void decor_redraw_end(DecorState *state)
|
||||
|
@ -603,15 +603,6 @@ int update_screen(void)
|
||||
buf->b_mod_tick_decor = display_tick;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset 'statuscolumn' if there is no dedicated signcolumn but it is invalid.
|
||||
if (*wp->w_p_stc != NUL && wp->w_minscwidth <= SCL_NO
|
||||
&& (wp->w_buffer->b_signcols.invalid_bot || !wp->w_buffer->b_signcols.sentinel)) {
|
||||
wp->w_nrwidth_line_count = 0;
|
||||
wp->w_valid &= ~VALID_WCOL;
|
||||
wp->w_redr_type = UPD_NOT_VALID;
|
||||
wp->w_buffer->b_signcols.invalid_bot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Go from top to bottom through the windows, redrawing the ones that need it.
|
||||
@ -658,10 +649,11 @@ int update_screen(void)
|
||||
|
||||
win_check_ns_hl(NULL);
|
||||
|
||||
// Reset b_mod_set flags. Going through all windows is probably faster
|
||||
// than going through all buffers (there could be many buffers).
|
||||
// Reset b_mod_set and b_signcols.resized flags. Going through all windows is
|
||||
// probably faster than going through all buffers (there could be many buffers).
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
wp->w_buffer->b_mod_set = false;
|
||||
wp->w_buffer->b_signcols.resized = false;
|
||||
}
|
||||
|
||||
updating_screen = 0;
|
||||
@ -1200,17 +1192,33 @@ void comp_col(void)
|
||||
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
||||
}
|
||||
|
||||
static void redraw_win_signcol(win_T *wp)
|
||||
/// Redraw entire window "wp" if configured 'signcolumn' width changes.
|
||||
static bool win_redraw_signcols(win_T *wp)
|
||||
{
|
||||
// If we can compute a change in the automatic sizing of the sign column
|
||||
// under 'signcolumn=auto:X' and signs currently placed in the buffer, better
|
||||
// figuring it out here so we can redraw the entire screen for it.
|
||||
int scwidth = wp->w_scwidth;
|
||||
wp->w_scwidth = win_signcol_count(wp);
|
||||
if (wp->w_scwidth != scwidth) {
|
||||
changed_line_abv_curs_win(wp);
|
||||
redraw_later(wp, UPD_NOT_VALID);
|
||||
bool rebuild_stc = false;
|
||||
buf_T *buf = wp->w_buffer;
|
||||
int width = buf->b_signcols.max;
|
||||
|
||||
if (wp->w_minscwidth <= SCL_NO) {
|
||||
if (*wp->w_p_stc) {
|
||||
if (map_size(buf->b_signcols.invalid)) {
|
||||
buf_signcols_validate(wp, buf, true);
|
||||
}
|
||||
if (buf->b_signcols.resized) {
|
||||
rebuild_stc = true;
|
||||
wp->w_nrwidth_line_count = 0;
|
||||
}
|
||||
}
|
||||
width = 0;
|
||||
} else if (wp->w_maxscwidth <= 1 && buf->b_signs_with_text >= (size_t)wp->w_maxscwidth) {
|
||||
width = wp->w_maxscwidth;
|
||||
} else if (map_size(buf->b_signcols.invalid)) {
|
||||
width = buf_signcols_validate(wp, buf, false);
|
||||
}
|
||||
|
||||
int scwidth = wp->w_scwidth;
|
||||
wp->w_scwidth = MAX(wp->w_minscwidth, width);
|
||||
return (wp->w_scwidth != scwidth || rebuild_stc);
|
||||
}
|
||||
|
||||
/// Check if horizontal separator of window "wp" at specified window corner is connected to the
|
||||
@ -1490,7 +1498,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
||||
DecorProviders line_providers;
|
||||
decor_providers_invoke_win(wp, providers, &line_providers);
|
||||
|
||||
redraw_win_signcol(wp);
|
||||
if (win_redraw_signcols(wp)) {
|
||||
wp->w_lines_valid = 0;
|
||||
wp->w_redr_type = UPD_NOT_VALID;
|
||||
changed_line_abv_curs_win(wp);
|
||||
}
|
||||
|
||||
init_search_hl(wp, &screen_search_hl);
|
||||
|
||||
|
@ -67,18 +67,18 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|
||||
} else {
|
||||
assert(marktree_itr_valid(itr));
|
||||
if (old_mark.pos.row == row && old_mark.pos.col == col) {
|
||||
// not paired: we can revise in place
|
||||
if (mt_decor_any(old_mark)) {
|
||||
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT;
|
||||
buf_decor_remove(buf, row, row, mt_decor(old_mark), true);
|
||||
}
|
||||
|
||||
// not paired: we can revise in place
|
||||
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK;
|
||||
mt_itr_rawkey(itr).flags |= flags;
|
||||
mt_itr_rawkey(itr).decor_data = decor.data;
|
||||
goto revised;
|
||||
}
|
||||
buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
|
||||
}
|
||||
} else {
|
||||
*ns = MAX(*ns, id);
|
||||
@ -515,20 +515,6 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
|
||||
extmark_splice_delete(buf, start_row, start_col, end_row, end_col, uvp, false, undo);
|
||||
}
|
||||
|
||||
// Move the signcolumn sentinel line
|
||||
if (buf->b_signs_with_text && buf->b_signcols.sentinel) {
|
||||
linenr_T se_lnum = buf->b_signcols.sentinel;
|
||||
if (se_lnum >= start_row) {
|
||||
if (old_row != 0 && se_lnum > old_row + start_row) {
|
||||
buf->b_signcols.sentinel += new_row - old_row;
|
||||
} else if (new_row == 0) {
|
||||
buf->b_signcols.sentinel = 0;
|
||||
} else {
|
||||
buf->b_signcols.sentinel += new_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
marktree_splice(buf->b_marktree, (int32_t)start_row, start_col,
|
||||
old_row, old_col,
|
||||
new_row, new_col);
|
||||
|
@ -111,6 +111,9 @@ void mh_clear(MapHash *h)
|
||||
#define VAL_NAME(x) quasiquote(x, String)
|
||||
#include "nvim/map_value_impl.c.h"
|
||||
#undef VAL_NAME
|
||||
#define VAL_NAME(x) quasiquote(x, SignRange)
|
||||
#include "nvim/map_value_impl.c.h"
|
||||
#undef VAL_NAME
|
||||
#undef KEY_NAME
|
||||
|
||||
#define KEY_NAME(x) x##ptr_t
|
||||
|
@ -48,6 +48,7 @@ static const uint64_t value_init_uint64_t = 0;
|
||||
static const int64_t value_init_int64_t = 0;
|
||||
static const String value_init_String = STRING_INIT;
|
||||
static const ColorItem value_init_ColorItem = COLOR_ITEM_INITIALIZER;
|
||||
static const SignRange value_init_SignRange = SIGNRANGE_INIT;
|
||||
|
||||
// layer 0: type non-specific code
|
||||
|
||||
@ -150,6 +151,7 @@ KEY_DECLS(uint32_t)
|
||||
KEY_DECLS(String)
|
||||
KEY_DECLS(HlEntry)
|
||||
KEY_DECLS(ColorKey)
|
||||
KEY_DECLS(SignRange)
|
||||
|
||||
MAP_DECLS(int, int)
|
||||
MAP_DECLS(int, ptr_t)
|
||||
@ -166,6 +168,7 @@ MAP_DECLS(uint32_t, uint32_t)
|
||||
MAP_DECLS(String, int)
|
||||
MAP_DECLS(int, String)
|
||||
MAP_DECLS(ColorKey, ColorItem)
|
||||
MAP_DECLS(int, SignRange)
|
||||
|
||||
#define set_has(T, set, key) set_has_##T(set, key)
|
||||
#define set_put(T, set, key) set_put_##T(set, key, NULL)
|
||||
|
@ -760,7 +760,7 @@ int win_col_off(win_T *wp)
|
||||
return ((wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc != NUL)
|
||||
? (number_width(wp) + (*wp->w_p_stc == NUL)) : 0)
|
||||
+ ((cmdwin_type == 0 || wp != curwin) ? 0 : 1)
|
||||
+ win_fdccol_count(wp) + (win_signcol_count(wp) * SIGN_WIDTH);
|
||||
+ win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH);
|
||||
}
|
||||
|
||||
int curwin_col_off(void)
|
||||
|
@ -6172,20 +6172,6 @@ bool fish_like_shell(void)
|
||||
return strstr(path_tail(p_sh), "fish") != NULL;
|
||||
}
|
||||
|
||||
/// Return the number of requested sign columns, based on current
|
||||
/// buffer signs and on user configuration.
|
||||
int win_signcol_count(win_T *wp)
|
||||
{
|
||||
if (wp->w_minscwidth <= SCL_NO) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int needed_signcols = buf_signcols(wp->w_buffer, wp->w_maxscwidth);
|
||||
int ret = MAX(wp->w_minscwidth, MIN(wp->w_maxscwidth, needed_signcols));
|
||||
assert(ret <= SIGN_SHOW_MAX);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Get window or buffer local options
|
||||
dict_T *get_winbuf_options(const int bufopt)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
|
@ -2095,6 +2095,8 @@ const char *did_set_signcolumn(optset_T *args)
|
||||
if (check_signcolumn(win) != OK) {
|
||||
return e_invarg;
|
||||
}
|
||||
int scwidth = win->w_minscwidth <= 0 ? 0 : MIN(win->w_maxscwidth, win->w_scwidth);
|
||||
win->w_scwidth = MAX(win->w_minscwidth, scwidth);
|
||||
// When changing the 'signcolumn' to or from 'number', recompute the
|
||||
// width of the number column if 'number' or 'relativenumber' is set.
|
||||
if ((*oldval == 'n' && *(oldval + 1) == 'u') || win->w_minscwidth == SCL_NUM) {
|
||||
|
@ -761,7 +761,7 @@ int comp_textwidth(bool ff)
|
||||
textwidth -= 1;
|
||||
}
|
||||
textwidth -= win_fdccol_count(curwin);
|
||||
textwidth -= win_signcol_count(curwin);
|
||||
textwidth -= curwin->w_scwidth;
|
||||
|
||||
if (curwin->w_p_nu || curwin->w_p_rnu) {
|
||||
textwidth -= 8;
|
||||
|
@ -48,3 +48,10 @@ typedef enum {
|
||||
#define TRISTATE_FROM_INT(val) ((val) == 0 ? kFalse : ((val) >= 1 ? kTrue : kNone))
|
||||
|
||||
typedef int64_t OptInt;
|
||||
|
||||
// Range entry for the "b_signcols.invalid" map in which the keys are the range start.
|
||||
typedef struct {
|
||||
int end; // End of the invalid range.
|
||||
int add; // Number of signs added in the invalid range, negative for deleted signs.
|
||||
} SignRange;
|
||||
#define SIGNRANGE_INIT { 0, 0 }
|
||||
|
@ -4644,7 +4644,6 @@ l5
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add a single sign (with end row)', function()
|
||||
@ -4665,7 +4664,6 @@ l5
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add a single sign and text highlight', function()
|
||||
@ -4707,7 +4705,6 @@ l5
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add multiple signs (multiple extmarks)', function()
|
||||
@ -4867,7 +4864,6 @@ l5
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add lots of signs', function()
|
||||
@ -4977,6 +4973,22 @@ l5
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('correct width when removing multiple signs from sentinel line', function()
|
||||
screen:try_resize(20, 4)
|
||||
insert(example_test3)
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=3})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {invalidate = true, sign_text='S2'})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {invalidate = true, sign_text='S3'})
|
||||
feed('2Gdd')
|
||||
|
||||
screen:expect{grid=[[
|
||||
S1l1 |
|
||||
S1^l3 |
|
||||
S1l4 |
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('decorations: virt_text', function()
|
||||
@ -5073,5 +5085,4 @@ describe('decorations: virt_text', function()
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user