refactor(sign): move legacy signs to extmarks

Problem:  The legacy signlist data structures and associated functions are
          redundant since the introduction of extmark signs.
Solution: Store signs defined through the legacy commands in a hashmap, placed
          signs in the extmark tree. Replace signlist associated functions.

Usage of the legacy sign commands should yield no change in behavior with the
exception of:
  - "orphaned signs" are now always removed when the line it is placed on is
    deleted. This used to depend on the value of 'signcolumn'.
  - It is no longer possible to place multiple signs with the same identifier
    in a single group on multiple lines. This will now move the sign instead.

Moreover, both signs placed through the legacy sign commands and through
|nvim_buf_set_extmark()|:
  - Will show up in both |sign-place| and |nvim_buf_get_extmarks()|.
  - Are displayed by increasing sign identifier, left to right.
    Extmark signs used to be ordered decreasingly as opposed to legacy signs.
This commit is contained in:
Luuk van Baal
2023-11-11 00:52:50 +01:00
parent ba58c6f8a4
commit c4afb9788c
33 changed files with 768 additions and 1899 deletions

View File

@@ -917,7 +917,6 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
buf_init_changedtick(buf);
}
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, "*"); // delete any signs
extmark_free_all(buf); // delete any extmarks
map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
@@ -4021,62 +4020,6 @@ char *buf_spname(buf_T *buf)
return NULL;
}
static int buf_signcols_inner(buf_T *buf, int maximum)
{
sign_entry_T *sign; // a sign in the sign list
int signcols = 0;
int linesum = 0;
linenr_T curline = 0;
buf->b_signcols.sentinel = 0;
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
if (sign->se_lnum > curline) {
// Counted all signs, now add extmark signs
if (curline > 0) {
linesum += decor_signcols(buf, &decor_state, (int)curline - 1, (int)curline - 1,
maximum - linesum);
}
curline = sign->se_lnum;
if (linesum > signcols) {
signcols = linesum;
buf->b_signcols.sentinel = curline;
if (signcols >= maximum) {
return maximum;
}
}
linesum = 0;
}
if (sign->se_has_text_or_icon) {
linesum++;
}
}
if (curline > 0) {
linesum += decor_signcols(buf, &decor_state, (int)curline - 1, (int)curline - 1,
maximum - linesum);
}
if (linesum > signcols) {
signcols = linesum;
if (signcols >= maximum) {
return maximum;
}
}
// Check extmarks between signs
linesum = decor_signcols(buf, &decor_state, 0, (int)buf->b_ml.ml_line_count - 1, maximum);
if (linesum > signcols) {
signcols = linesum;
buf->b_signcols.sentinel = curline;
if (signcols >= maximum) {
return maximum;
}
}
return signcols;
}
/// Invalidate the signcolumn if needed after deleting
/// signs between line1 and line2 (inclusive).
///
@@ -4106,18 +4049,18 @@ void buf_signcols_del_check(buf_T *buf, linenr_T line1, linenr_T line2)
///
/// @param buf buffer to check
/// @param added sign being added
void buf_signcols_add_check(buf_T *buf, sign_entry_T *added)
void buf_signcols_add_check(buf_T *buf, linenr_T lnum)
{
if (!buf->b_signcols.valid) {
return;
}
if (!added || !buf->b_signcols.sentinel) {
if (!buf->b_signcols.sentinel) {
buf->b_signcols.valid = false;
return;
}
if (added->se_lnum == buf->b_signcols.sentinel) {
if (lnum == buf->b_signcols.sentinel) {
if (buf->b_signcols.size == buf->b_signcols.max) {
buf->b_signcols.max++;
}
@@ -4126,42 +4069,32 @@ void buf_signcols_add_check(buf_T *buf, sign_entry_T *added)
return;
}
sign_entry_T *s;
int signcols = decor_signcols(buf, lnum - 1, lnum - 1, SIGN_SHOW_MAX);
// 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;
if (signcols > buf->b_signcols.size) {
buf->b_signcols.size = signcols;
buf->b_signcols.max = signcols;
buf->b_signcols.sentinel = lnum;
redraw_buf_later(buf, UPD_NOT_VALID);
}
}
int buf_signcols(buf_T *buf, int maximum)
int buf_signcols(buf_T *buf, int max)
{
// The maximum can be determined from 'signcolumn' which is window scoped so
// need to invalidate signcols if the maximum is greater than the previous
// maximum.
if (maximum > buf->b_signcols.max) {
// (valid) maximum.
if (buf->b_signcols.max && max > buf->b_signcols.max) {
buf->b_signcols.valid = false;
}
if (!buf->b_signcols.valid) {
int signcols = buf_signcols_inner(buf, maximum);
buf->b_signcols.sentinel = 0;
int signcols = decor_signcols(buf, 0, (int)buf->b_ml.ml_line_count - 1, max);
// Check if we need to redraw
if (signcols != buf->b_signcols.size) {
buf->b_signcols.size = signcols;
buf->b_signcols.max = maximum;
buf->b_signcols.max = max;
redraw_buf_later(buf, UPD_NOT_VALID);
}