Merge pull request #25724 from luukvbaal/signmerge

refactor(sign): move legacy signs to extmarks
This commit is contained in:
bfredl
2023-11-18 15:04:14 +01:00
committed by GitHub
33 changed files with 768 additions and 1898 deletions

View File

@@ -22,6 +22,7 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/pos.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/vim.h"
@@ -81,7 +82,7 @@ Dictionary nvim_get_namespaces(void)
return retval;
}
const char *describe_ns(NS ns_id)
const char *describe_ns(NS ns_id, const char *unknown)
{
String name;
handle_T id;
@@ -90,7 +91,7 @@ const char *describe_ns(NS ns_id)
return name.data;
}
})
return "(UNKNOWN PLUGIN)";
return unknown;
}
// Is the Namespace in use?
@@ -314,8 +315,8 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
return extmark_to_array(&extmark, false, details, hl_name);
}
/// Gets |extmarks| in "traversal order" from a |charwise| region defined by
/// buffer positions (inclusive, 0-indexed |api-indexing|).
/// Gets |extmarks| (including |signs|) in "traversal order" from a |charwise|
/// region defined by buffer positions (inclusive, 0-indexed |api-indexing|).
///
/// Region can be given as (row,col) tuples, or valid extmark ids (whose
/// positions define the bounds). 0 and -1 are understood as (0,0) and (-1,-1)
@@ -750,7 +751,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
if (HAS_KEY(opts, set_extmark, sign_text)) {
VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data),
VALIDATE_S(init_sign_text(NULL, &decor.sign_text, opts->sign_text.data),
"sign_text", "", {
goto error;
});
@@ -1150,41 +1151,6 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in
});
}
}
// adapted from sign.c:sign_define_init_text.
// TODO(lewis6991): Consider merging
static int init_sign_text(char **sign_text, char *text)
{
char *s;
char *endp = text + (int)strlen(text);
// Count cells and check for non-printable chars
int cells = 0;
for (s = text; s < endp; s += utfc_ptr2len(s)) {
if (!vim_isprintc(utf_ptr2char(s))) {
break;
}
cells += utf_ptr2cells(s);
}
// Currently must be empty, one or two display cells
if (s != endp || cells > 2) {
return FAIL;
}
if (cells < 1) {
return OK;
}
// Allocate one byte more if we need to pad up
// with a space.
size_t len = (size_t)(endp - text + ((cells == 1) ? 1 : 0));
*sign_text = xstrnsave(text, len);
if (cells == 1) {
STRCPY(*sign_text + len - 1, " ");
}
return OK;
}
VirtText parse_virt_text(Array chunks, Error *err, int *width)
{

View File

@@ -2196,13 +2196,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
}
}
if (statuscol_lnum) {
HlPriId line = { 0 };
HlPriId cul = { 0 };
HlPriId num = { 0 };
int line_id = 0;
int cul_id = 0;
int num_id = 0;
linenr_T lnum = statuscol_lnum;
int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul);
decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul);
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;
statuscol.foldinfo = fold_info(wp, lnum);
@@ -2215,9 +2214,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR);
}
statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0;
if (num.hl_id) {
stc_hl_id = num.hl_id;
statuscol.sign_cul_id = statuscol.use_cul ? cul_id : 0;
if (num_id) {
stc_hl_id = num_id;
} else if (statuscol.use_cul) {
stc_hl_id = HLF_CLN + 1;
} else if (wp->w_p_rnu) {

View File

@@ -919,7 +919,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
@@ -4023,62 +4022,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).
///
@@ -4108,18 +4051,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++;
}
@@ -4128,42 +4071,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);
}

View File

@@ -704,7 +704,6 @@ struct file_buffer {
// normally points to this, but some windows
// may use a different synblock_T.
sign_entry_T *b_signlist; // list of placed signs
struct {
int size; // last calculated number of sign columns
bool valid; // calculated sign columns is valid

View File

@@ -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;

View File

@@ -60,7 +60,9 @@ struct Decoration {
int col; // fixed col value, like win_col
int virt_text_width; // width of virt_text
char *sign_text;
char *sign_name;
int sign_hl_id;
int sign_add_id;
int number_hl_id;
int line_hl_id;
int cursorline_hl_id;
@@ -71,7 +73,7 @@ struct Decoration {
};
#define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, \
kHlModeUnknown, false, false, false, false, kNone, \
DECOR_PRIORITY_BASE, 0, 0, NULL, 0, 0, 0, 0, 0, false }
DECOR_PRIORITY_BASE, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, false }
typedef struct {
int start_row;

View File

@@ -25,7 +25,7 @@ static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
static void decor_provider_error(DecorProvider *provider, const char *name, const char *msg)
{
const char *ns_name = describe_ns(provider->ns_id);
const char *ns_name = describe_ns(provider->ns_id, "(UNKNOWN PLUGIN)");
ELOG("error in provider %s.%s: %s", ns_name, name, msg);
msg_schedule_semsg_multiline("Error in decoration provider %s.%s:\n%s", ns_name, name, msg);
}

View File

@@ -456,85 +456,37 @@ size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum, i
/// Get information needed to display the sign in line "wlv->lnum" in window "wp".
/// If "nrcol" is true, the sign is going to be displayed in the number column.
/// Otherwise the sign is going to be displayed in the sign column.
/// Otherwise the sign is going to be displayed in the sign column. If there is no
/// sign, draw blank cells instead.
static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx,
int sign_cul_attr)
{
// Draw cells with the sign value or blank.
wlv->c_extra = ' ';
SignTextAttrs sattr = wlv->sattrs[sign_idx];
wlv->c_final = NUL;
if (nrcol) {
wlv->n_extra = number_width(wp) + 1;
if (sattr.text && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) {
size_t fill = nrcol ? (size_t)number_width(wp) - SIGN_WIDTH : 0;
size_t sign_len = strlen(sattr.text);
// Spaces + sign: " " + ">>" + ' '
wlv->n_extra = (int)(fill + sign_len + nrcol);
if (nrcol) {
memset(wlv->extra, ' ', (size_t)wlv->n_extra);
}
memcpy(wlv->extra + fill, sattr.text, sign_len);
wlv->p_extra = wlv->extra;
wlv->c_extra = NUL;
wlv->char_attr = (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr)
? sign_cul_attr : sattr.hl_id ? syn_id2attr(sattr.hl_id) : 0;
} else {
if (use_cursor_line_highlight(wp, wlv->lnum)) {
wlv->char_attr = win_hl_attr(wp, HLF_CLS);
} else {
wlv->char_attr = win_hl_attr(wp, HLF_SC);
}
wlv->n_extra = win_signcol_width(wp);
}
if (wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) {
SignTextAttrs *sattr = sign_get_attr(sign_idx, wlv->sattrs, wp->w_scwidth);
if (sattr != NULL) {
wlv->p_extra = sattr->text;
if (wlv->p_extra != NULL) {
wlv->c_extra = NUL;
wlv->c_final = NUL;
if (nrcol) {
int width = number_width(wp) - 2;
size_t n;
for (n = 0; (int)n < width; n++) {
wlv->extra[n] = ' ';
}
wlv->extra[n] = NUL;
snprintf(wlv->extra + n, sizeof(wlv->extra) - n, "%s ", wlv->p_extra);
wlv->p_extra = wlv->extra;
wlv->n_extra = (int)strlen(wlv->p_extra);
} else {
size_t symbol_blen = strlen(wlv->p_extra);
// TODO(oni-link): Is sign text already extended to
// full cell width?
assert((size_t)win_signcol_width(wp) >= mb_string2cells(wlv->p_extra));
// symbol(s) bytes + (filling spaces) (one byte each)
wlv->n_extra = (int)symbol_blen + win_signcol_width(wp) -
(int)mb_string2cells(wlv->p_extra);
assert(sizeof(wlv->extra) > symbol_blen);
memset(wlv->extra, ' ', sizeof(wlv->extra));
memcpy(wlv->extra, wlv->p_extra, symbol_blen);
wlv->p_extra = wlv->extra;
wlv->p_extra[wlv->n_extra] = NUL;
}
}
if (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr > 0) {
wlv->char_attr = sign_cul_attr;
} else {
wlv->char_attr = sattr->hl_id ? syn_id2attr(sattr->hl_id) : 0;
}
wlv->c_extra = ' ';
wlv->n_extra = nrcol ? number_width(wp) + 1 : SIGN_WIDTH;
if (!nrcol) {
wlv->char_attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLS : HLF_SC);
}
}
}
/// Returns width of the signcolumn that should be used for the whole window
///
/// @param wp window we want signcolumn width from
/// @return max width of signcolumn (cell unit)
///
/// @note Returns a constant for now but hopefully we can improve neovim so that
/// the returned value width adapts to the maximum number of marks to draw
/// for the window
/// TODO(teto)
int win_signcol_width(win_T *wp)
{
// 2 is vim default value
return 2;
}
static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len)
{
linenr_T num;
@@ -598,8 +550,7 @@ static int get_line_number_attr(win_T *wp, winlinevars_T *wlv)
/// Display the absolute or relative line number. After the first row fill with
/// blanks when the 'n' flag isn't in 'cpo'.
static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int sign_idx,
int sign_num_attr, int sign_cul_attr)
static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, int sign_cul_attr)
{
bool has_cpo_n = vim_strchr(p_cpo, CPO_NUMCOL) != NULL;
@@ -610,8 +561,8 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int si
&& !((has_cpo_n && !wp->w_p_bri) && wp->w_skipcol > 0 && wlv->lnum == wp->w_topline)) {
// If 'signcolumn' is set to 'number' and a sign is present in "lnum",
// then display the sign instead of the line number.
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) {
get_sign_display_info(true, wp, wlv, sign_idx, sign_cul_attr);
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && wlv->sattrs[0].text) {
get_sign_display_info(true, wp, wlv, 0, sign_cul_attr);
} else {
// Draw the line number (empty space after wrapping).
if (wlv->row == wlv->startrow + wlv->filler_lines
@@ -1317,15 +1268,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
area_highlighting = true;
}
HlPriId line_id = { 0 };
HlPriId sign_cul = { 0 };
HlPriId sign_num = { 0 };
// TODO(bfredl, vigoux): line_attr should not take priority over decoration!
int num_signs = buf_get_signattrs(buf, wlv.lnum, wlv.sattrs, &sign_num, &line_id, &sign_cul);
decor_redraw_signs(buf, wlv.lnum - 1, &num_signs, wlv.sattrs, &sign_num, &line_id, &sign_cul);
int line_attr = 0;
int sign_cul_attr = 0;
int sign_num_attr = 0;
// TODO(bfredl, vigoux): line_attr should not take priority over decoration!
decor_redraw_signs(wp, buf, wlv.lnum - 1, wlv.sattrs, &line_attr, &sign_cul_attr, &sign_num_attr);
statuscol_T statuscol = { 0 };
if (*wp->w_p_stc != NUL) {
// Draw the 'statuscolumn' if option is set.
@@ -1334,18 +1282,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
statuscol.foldinfo = foldinfo;
statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin);
statuscol.use_cul = use_cursor_line_highlight(wp, lnum);
statuscol.sign_cul_id = statuscol.use_cul ? sign_cul.hl_id : 0;
statuscol.num_attr = sign_num.hl_id > 0 ? syn_id2attr(sign_num.hl_id) : 0;
statuscol.sign_cul_id = statuscol.use_cul ? sign_cul_attr : 0;
statuscol.num_attr = sign_num_attr > 0 ? syn_id2attr(sign_num_attr) : 0;
} else {
if (sign_cul.hl_id > 0) {
sign_cul_attr = syn_id2attr(sign_cul.hl_id);
if (sign_cul_attr > 0) {
sign_cul_attr = syn_id2attr(sign_cul_attr);
}
if (sign_num.hl_id > 0) {
sign_num_attr = syn_id2attr(sign_num.hl_id);
if (sign_num_attr > 0) {
sign_num_attr = syn_id2attr(sign_num_attr);
}
}
if (line_id.hl_id > 0) {
wlv.line_attr = syn_id2attr(line_id.hl_id);
if (line_attr > 0) {
wlv.line_attr = syn_id2attr(line_attr);
}
// Highlight the current line in the quickfix window.
@@ -1661,8 +1609,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.draw_state = WL_SIGN;
if (wp->w_scwidth > 0) {
get_sign_display_info(false, wp, &wlv, sign_idx, sign_cul_attr);
sign_idx++;
if (sign_idx < wp->w_scwidth) {
if (++sign_idx < wp->w_scwidth) {
wlv.draw_state = WL_SIGN - 1;
} else {
sign_idx = 0;
@@ -1673,14 +1620,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.draw_state == WL_NR - 1 && wlv.n_extra == 0) {
// Show the line number, if desired.
wlv.draw_state = WL_NR;
handle_lnum_col(wp, &wlv, num_signs, sign_idx, sign_num_attr, sign_cul_attr);
handle_lnum_col(wp, &wlv, sign_num_attr, sign_cul_attr);
}
if (wlv.draw_state == WL_STC - 1 && wlv.n_extra == 0) {
wlv.draw_state = WL_STC;
// Draw the 'statuscolumn' if option is set.
if (statuscol.draw) {
if (sign_num.hl_id == 0) {
if (sign_num_attr == 0) {
statuscol.num_attr = get_line_number_attr(wp, &wlv);
}
if (statuscol.textp == NULL) {

View File

@@ -2558,7 +2558,7 @@ void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endr
// draw the sign column
int count = wp->w_scwidth;
if (count > 0) {
n = win_fill_end(wp, ' ', ' ', n, win_signcol_width(wp) * count, row,
n = win_fill_end(wp, ' ', ' ', n, SIGN_WIDTH * count, row,
endrow, win_hl_attr(wp, HLF_SC));
}
// draw the number column
@@ -2633,7 +2633,7 @@ int number_width(win_T *wp)
// If 'signcolumn' is set to 'number' and there is a sign to display, then
// the minimal width for the number column is 2.
if (n < 2 && (wp->w_buffer->b_signlist != NULL)
if (n < 2 && wp->w_buffer->b_signs_with_text
&& (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
n = 2;
}

View File

@@ -504,7 +504,7 @@ static dict_T *get_buffer_info(buf_T *buf)
}
tv_dict_add_list(dict, S_LEN("windows"), windows);
if (buf->b_signlist != NULL) {
if (buf->b_signs) {
// List of signs placed in this buffer
tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
}

View File

@@ -159,21 +159,22 @@ static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
return true;
}
linenr_T extmark_del_id(buf_T *buf, uint32_t ns_id, uint32_t id)
/// Remove an extmark in "ns_id" by "id"
///
/// @return false on missing id
bool extmark_del_id(buf_T *buf, uint32_t ns_id, uint32_t id)
{
MarkTreeIter it[1] = { 0 };
MTKey key = marktree_lookup_ns(buf->b_marktree, ns_id, id, false, it);
if (!key.id) {
return 0;
MarkTreeIter itr[1] = { 0 };
MTKey key = marktree_lookup_ns(buf->b_marktree, ns_id, id, false, itr);
if (key.id) {
extmark_del(buf, itr, key, false);
}
return extmark_del(buf, it, key, false);
return key.id > 0;
}
/// Remove a (paired) extmark "key" pointed to by "itr"
///
/// @return line number of the deleted mark
linenr_T extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore)
void extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore)
{
assert(key.pos.row >= 0);
@@ -193,7 +194,6 @@ linenr_T extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore)
}
// TODO(bfredl): delete it from current undo header, opportunistically?
return key.pos.row + 1;
}
/// Free extmarks in a ns between lines
@@ -240,8 +240,8 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
///
/// if upper_lnum or upper_col are negative the buffer
/// will be searched to the start, or end
/// dir can be set to control the order of the array
/// amount = amount of marks to find or -1 for all
/// reverse can be set to control the order of the array
/// amount = amount of marks to find or INT64_MAX for all
ExtmarkInfoArray extmark_get(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_row,
colnr_T u_col, int64_t amount, bool reverse, ExtmarkType type_filter,
bool overlap)
@@ -299,7 +299,10 @@ static void push_mark(ExtmarkInfoArray *array, uint32_t ns_id, ExtmarkType type_
if (type_filter != kExtmarkNone) {
Decoration *decor = mark.decor_full;
if (decor && (decor->sign_text || decor->number_hl_id)) {
type_flags |= kExtmarkSign;
type_flags |= (kExtmarkSignHL|kExtmarkSign);
}
if (decor && (decor->line_hl_id || decor->cursorline_hl_id)) {
type_flags |= (kExtmarkSignHL|kExtmarkHighlight);
}
if (decor && decor->virt_text.size) {
type_flags |= kExtmarkVirtText;
@@ -307,8 +310,7 @@ static void push_mark(ExtmarkInfoArray *array, uint32_t ns_id, ExtmarkType type_
if (decor && decor->virt_lines.size) {
type_flags |= kExtmarkVirtLines;
}
if ((decor && (decor->line_hl_id || decor->cursorline_hl_id))
|| mark.hl_id) {
if (mark.hl_id) {
type_flags |= kExtmarkHighlight;
}
@@ -596,6 +598,20 @@ 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, 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);

View File

@@ -84,9 +84,10 @@ typedef enum {
typedef enum {
kExtmarkNone = 0x1,
kExtmarkSign = 0x2,
kExtmarkVirtText = 0x4,
kExtmarkVirtLines = 0x8,
kExtmarkHighlight = 0x10,
kExtmarkSignHL = 0x4,
kExtmarkVirtText = 0x8,
kExtmarkVirtLines = 0x10,
kExtmarkHighlight = 0x20,
} ExtmarkType;
// TODO(bfredl): reduce the number of undo action types

View File

@@ -474,10 +474,6 @@ EXTERN buf_T *curbuf INIT( = NULL); // currently active buffer
#define FOR_ALL_BUF_WININFO(buf, wip) \
for ((wip) = (buf)->b_wininfo; (wip) != NULL; (wip) = (wip)->wi_next) // NOLINT
// Iterate through all the signs placed in a buffer
#define FOR_ALL_SIGNS_IN_BUF(buf, sign) \
for ((sign) = (buf)->b_signlist; (sign) != NULL; (sign) = (sign)->se_next) // NOLINT
// List of files being edited (global argument list). curwin->w_alist points
// to this when the window is using the global argument list.
EXTERN alist_T global_alist; // global argument list

View File

@@ -246,9 +246,3 @@ typedef struct {
} ColorItem;
#define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, .version = -1, \
.is_default = false, .link_global = false }
/// highlight attributes with associated priorities
typedef struct {
int hl_id;
int priority;
} HlPriId;

View File

@@ -69,7 +69,6 @@
#include "nvim/quickfix.h"
#include "nvim/runtime.h"
#include "nvim/shada.h"
#include "nvim/sign.h"
#include "nvim/statusline.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
@@ -217,8 +216,6 @@ void early_init(mparm_T *paramp)
TIME_MSG("inits 1");
set_lang_var(); // set v:lang and v:ctype
init_signs();
}
#ifdef MAKE_LIB

View File

@@ -33,7 +33,6 @@
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/textobject.h"
#include "nvim/vim.h"
@@ -1190,8 +1189,6 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount
if (!found_one) {
buf->b_has_qf_entry &= ~BUF_HAS_LL_ENTRY;
}
sign_mark_adjust(buf, line1, line2, amount, amount_after);
}
if (op != kExtmarkNOOP) {

View File

@@ -760,8 +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) * win_signcol_width(wp));
+ win_fdccol_count(wp) + (win_signcol_count(wp) * SIGN_WIDTH);
}
int curwin_col_off(void)

View File

@@ -6170,7 +6170,7 @@ bool fish_like_shell(void)
/// buffer signs and on user configuration.
int win_signcol_count(win_T *wp)
{
return win_signcol_configured(wp, NULL);
return win_signcol_configured(wp);
}
/// Return true when window "wp" has no sign column.
@@ -6182,14 +6182,10 @@ bool win_no_signcol(win_T *wp)
}
/// Return the number of requested sign columns, based on user / configuration.
int win_signcol_configured(win_T *wp, int *is_fixed)
int win_signcol_configured(win_T *wp)
{
const char *scl = wp->w_p_scl;
if (is_fixed) {
*is_fixed = 1;
}
if (win_no_signcol(wp)) {
return 0;
}
@@ -6203,11 +6199,6 @@ int win_signcol_configured(win_T *wp, int *is_fixed)
return 1;
}
if (is_fixed) {
// auto or auto:<NUM>
*is_fixed = 0;
}
int minimum = 0, maximum = 1;
if (!strncmp(scl, "auto:", 5)) {

View File

@@ -7590,12 +7590,6 @@ return {
number (maximum 9), e.g. "yes:3"
"number" display signs in the 'number' column. If the number
column is not present, then behaves like "auto".
Note regarding "orphaned signs": with signcolumn numbers higher than
1, deleting lines will also remove the associated signs automatically,
in contrast to the default Vim behavior of keeping and grouping them.
This is done in order for the signcolumn appearance not appear weird
during line deletion.
]=],
expand_cb = 'expand_set_signcolumn',
full_name = 'signcolumn',

File diff suppressed because it is too large Load Diff

View File

@@ -5,47 +5,23 @@
#include "nvim/pos.h"
#include "nvim/types.h"
// signs: line annotations
// Sign group
typedef struct signgroup_S {
int sg_next_sign_id; ///< next sign id for this group
uint16_t sg_refcount; ///< number of signs in this group
char sg_name[]; ///< sign group name
} signgroup_T;
// Macros to get the sign group structure from the group name
#define SGN_KEY_OFF offsetof(signgroup_T, sg_name)
#define HI2SG(hi) ((signgroup_T *)((hi)->hi_key - SGN_KEY_OFF))
typedef struct sign_entry sign_entry_T;
struct sign_entry {
int se_id; // unique identifier for each placed sign
int se_typenr; // typenr of sign
int se_priority; // priority for highlighting
bool se_has_text_or_icon; // has text or icon
linenr_T se_lnum; // line number which has this sign
signgroup_T *se_group; // sign group
sign_entry_T *se_next; // next entry in a list of signs
sign_entry_T *se_prev; // previous entry -- for easy reordering
};
/// Sign attributes. Used by the screen refresh routines.
typedef struct {
char *text;
int hl_id;
int priority;
} SignTextAttrs;
#define SIGN_SHOW_MAX 9
/// Struct to hold the sign properties.
typedef struct sign {
char *sn_name; // name of sign
char *sn_icon; // name of pixmap
char *sn_text; // text used instead of pixmap
int sn_line_hl; // highlight ID for line
int sn_text_hl; // highlight ID for text
int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set
int sn_num_hl; // highlight ID for line number
} sign_T;
// Default sign priority for highlighting
#define SIGN_DEF_PRIO 10
// type argument for sign_get_attr()
typedef enum {
SIGN_LINEHL,
SIGN_NUMHL,
SIGN_TEXT,
} SignType;
#define SIGN_WIDTH 2 // Number of display cells for a sign in the signcolumn
#define SIGN_SHOW_MAX 9 // Maximum number of signs shown on a single line
#define SIGN_DEF_PRIO 10 // Default sign highlight priority

View File

@@ -1656,9 +1656,9 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
varnumber_T virtnum = get_vim_var_nr(VV_VIRTNUM);
for (int i = 0; i < width; i++) {
if (!fold) {
SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, stcp->sattrs, wp->w_scwidth);
SignTextAttrs *sattr = virtnum ? NULL : &stcp->sattrs[i];
p = sattr && sattr->text ? sattr->text : " ";
stl_items[curitem].minwid = -(sattr ? stcp->sign_cul_id ? stcp->sign_cul_id
stl_items[curitem].minwid = -(sattr && sattr->text ? stcp->sign_cul_id ? stcp->sign_cul_id
: sattr->hl_id : (stcp->use_cul ? HLF_CLS : HLF_SC) + 1);
}
stl_items[curitem].type = Highlight;