mirror of
https://github.com/neovim/neovim.git
synced 2025-10-17 15:21:47 +00:00
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:
@@ -11,7 +11,7 @@
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/move.h"
|
||||
#include "nvim/pos.h"
|
||||
#include "nvim/sign_defs.h"
|
||||
#include "nvim/sign.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "decoration.c.generated.h"
|
||||
@@ -92,6 +92,8 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||
}
|
||||
}
|
||||
|
||||
static int sign_add_id = 0;
|
||||
|
||||
void decor_add(buf_T *buf, int row, int row2, Decoration *decor, bool hl_id)
|
||||
{
|
||||
if (decor) {
|
||||
@@ -102,12 +104,12 @@ void decor_add(buf_T *buf, int row, int row2, Decoration *decor, bool hl_id)
|
||||
buf->b_virt_line_blocks++;
|
||||
}
|
||||
if (decor_has_sign(decor)) {
|
||||
decor->sign_add_id = sign_add_id++;
|
||||
buf->b_signs++;
|
||||
}
|
||||
if (decor->sign_text) {
|
||||
buf->b_signs_with_text++;
|
||||
// TODO(lewis6991): smarter invalidation
|
||||
buf_signcols_add_check(buf, NULL);
|
||||
buf_signcols_add_check(buf, row + 1);
|
||||
}
|
||||
}
|
||||
if (decor || hl_id) {
|
||||
@@ -152,6 +154,7 @@ void decor_clear(Decoration *decor)
|
||||
}
|
||||
kv_destroy(decor->virt_lines);
|
||||
xfree(decor->sign_text);
|
||||
xfree(decor->sign_name);
|
||||
}
|
||||
|
||||
void decor_free(Decoration *decor)
|
||||
@@ -429,107 +432,73 @@ next_mark:
|
||||
return attr;
|
||||
}
|
||||
|
||||
void decor_redraw_signs(buf_T *buf, int row, int *num_signs, SignTextAttrs sattrs[],
|
||||
HlPriId *num_id, HlPriId *line_id, HlPriId *cul_id)
|
||||
/// Return the sign attributes on the currently refreshed row.
|
||||
///
|
||||
/// @param[out] sattrs Output array for sign text and texthl id
|
||||
/// @param[out] line_attr Highest priority linehl id
|
||||
/// @param[out] cul_attr Highest priority culhl id
|
||||
/// @param[out] num_attr Highest priority numhl id
|
||||
void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], int *line_id,
|
||||
int *cul_id, int *num_id)
|
||||
{
|
||||
if (!buf->b_signs) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, row, 0, itr);
|
||||
|
||||
// TODO(bfredl): integrate with main decor loop.
|
||||
if (!marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
|
||||
MarkTreeIter itr[1];
|
||||
if (!buf->b_signs || !marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MTPair pair;
|
||||
int num_text = 0;
|
||||
kvec_t(MTKey) signs = KV_INITIAL_VALUE;
|
||||
// TODO(bfredl): integrate with main decor loop.
|
||||
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
||||
if (mt_invalid(pair.start) || marktree_decor_level(pair.start) < kDecorLevelVisible) {
|
||||
continue;
|
||||
if (!mt_invalid(pair.start) && pair.start.decor_full && decor_has_sign(pair.start.decor_full)) {
|
||||
pair.start.pos.row = row;
|
||||
num_text += (pair.start.decor_full->sign_text != NULL);
|
||||
kv_push(signs, pair.start);
|
||||
}
|
||||
|
||||
Decoration *decor = pair.start.decor_full;
|
||||
|
||||
if (!decor || !decor_has_sign(decor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
decor_to_sign(decor, num_signs, sattrs, num_id, line_id, cul_id);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (itr->x) {
|
||||
MTKey mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0 || mark.pos.row > row) {
|
||||
if (mark.pos.row != row) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mt_end(mark) || mt_invalid(mark) || marktree_decor_level(mark) < kDecorLevelVisible) {
|
||||
goto next_mark;
|
||||
if (!mt_end(mark) && !mt_invalid(mark) && mark.decor_full && decor_has_sign(mark.decor_full)) {
|
||||
num_text += (mark.decor_full->sign_text != NULL);
|
||||
kv_push(signs, mark);
|
||||
}
|
||||
|
||||
Decoration *decor = mark.decor_full;
|
||||
|
||||
if (!decor || !decor_has_sign(decor)) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
decor_to_sign(decor, num_signs, sattrs, num_id, line_id, cul_id);
|
||||
|
||||
next_mark:
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
}
|
||||
|
||||
static void decor_to_sign(Decoration *decor, int *num_signs, SignTextAttrs sattrs[],
|
||||
HlPriId *num_id, HlPriId *line_id, HlPriId *cul_id)
|
||||
{
|
||||
if (decor->sign_text) {
|
||||
int j;
|
||||
for (j = (*num_signs); j > 0; j--) {
|
||||
if (sattrs[j - 1].priority >= decor->priority) {
|
||||
break;
|
||||
if (kv_size(signs)) {
|
||||
int width = (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u') ? 1 : wp->w_scwidth;
|
||||
int idx = MIN(width, num_text) - 1;
|
||||
qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_cmp);
|
||||
|
||||
for (size_t i = 0; i < kv_size(signs); i++) {
|
||||
Decoration *decor = kv_A(signs, i).decor_full;
|
||||
if (idx >= 0 && decor->sign_text) {
|
||||
sattrs[idx].text = decor->sign_text;
|
||||
sattrs[idx--].hl_id = decor->sign_hl_id;
|
||||
}
|
||||
if (j < SIGN_SHOW_MAX) {
|
||||
sattrs[j] = sattrs[j - 1];
|
||||
if (*num_id == 0) {
|
||||
*num_id = decor->number_hl_id;
|
||||
}
|
||||
if (*line_id == 0) {
|
||||
*line_id = decor->line_hl_id;
|
||||
}
|
||||
if (*cul_id == 0) {
|
||||
*cul_id = decor->cursorline_hl_id;
|
||||
}
|
||||
}
|
||||
if (j < SIGN_SHOW_MAX) {
|
||||
sattrs[j] = (SignTextAttrs) {
|
||||
.text = decor->sign_text,
|
||||
.hl_id = decor->sign_hl_id,
|
||||
.priority = decor->priority
|
||||
};
|
||||
(*num_signs)++;
|
||||
}
|
||||
}
|
||||
|
||||
struct { HlPriId *dest; int hl; } cattrs[] = {
|
||||
{ line_id, decor->line_hl_id },
|
||||
{ num_id, decor->number_hl_id },
|
||||
{ cul_id, decor->cursorline_hl_id },
|
||||
{ NULL, -1 },
|
||||
};
|
||||
for (int i = 0; cattrs[i].dest; i++) {
|
||||
if (cattrs[i].hl != 0 && decor->priority >= cattrs[i].dest->priority) {
|
||||
*cattrs[i].dest = (HlPriId) {
|
||||
.hl_id = cattrs[i].hl,
|
||||
.priority = decor->priority
|
||||
};
|
||||
}
|
||||
kv_destroy(signs);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the maximum required amount of sign columns needed between row and
|
||||
// end_row.
|
||||
int decor_signcols(buf_T *buf, DecorState *state, int row, int end_row, int max)
|
||||
int decor_signcols(buf_T *buf, int row, int end_row, int max)
|
||||
{
|
||||
int count = 0; // count for the number of signs on a given row
|
||||
int count_remove = 0; // how much to decrement count by when iterating marks for a new row
|
||||
int signcols = 0; // highest value of count
|
||||
int currow = -1; // current row
|
||||
|
||||
if (max <= 1 && buf->b_signs_with_text >= (size_t)max) {
|
||||
return max;
|
||||
}
|
||||
@@ -538,66 +507,41 @@ int decor_signcols(buf_T *buf, DecorState *state, int row, int end_row, int max)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, 0, -1, itr);
|
||||
while (true) {
|
||||
MTKey mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0 || mark.pos.row > end_row) {
|
||||
break;
|
||||
int signcols = 0; // highest value of count
|
||||
for (int currow = row; currow <= end_row; currow++) {
|
||||
MarkTreeIter itr[1];
|
||||
if (!marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mark.pos.row < row && mt_end(mark))
|
||||
|| marktree_decor_level(mark) < kDecorLevelVisible
|
||||
|| !mark.decor_full) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
Decoration decor = get_decor(mark);
|
||||
|
||||
if (!decor.sign_text) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
if (mark.pos.row > currow) {
|
||||
count -= count_remove;
|
||||
count_remove = 0;
|
||||
currow = mark.pos.row;
|
||||
}
|
||||
|
||||
if (!mt_paired(mark)) {
|
||||
if (mark.pos.row >= row) {
|
||||
int count = 0;
|
||||
MTPair pair;
|
||||
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
||||
if (!mt_invalid(pair.start) && pair.start.decor_full && pair.start.decor_full->sign_text) {
|
||||
count++;
|
||||
if (count > signcols) {
|
||||
signcols = count;
|
||||
if (signcols >= max) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
count_remove++;
|
||||
}
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
MTPos altpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
|
||||
if (mt_end(mark)) {
|
||||
if (mark.pos.row >= row && altpos.row <= end_row) {
|
||||
count_remove++;
|
||||
while (itr->x) {
|
||||
MTKey mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row != currow) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (altpos.row >= row) {
|
||||
if (!mt_invalid(mark) && !mt_end(mark) && mark.decor_full && mark.decor_full->sign_text) {
|
||||
count++;
|
||||
if (count > signcols) {
|
||||
signcols = count;
|
||||
if (signcols >= max) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
}
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
|
||||
next_mark:
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
if (count > signcols) {
|
||||
if (row != end_row) {
|
||||
buf->b_signcols.sentinel = currow + 1;
|
||||
}
|
||||
if (count >= max) {
|
||||
return max;
|
||||
}
|
||||
signcols = count;
|
||||
}
|
||||
}
|
||||
|
||||
return signcols;
|
||||
|
Reference in New Issue
Block a user