mirror of
https://github.com/neovim/neovim.git
synced 2025-09-30 06:58:35 +00:00
vim-patch:8.1.1631: displaying signs is inefficient
+ support for neovim's dynamic width signcolumn Problem: Displaying signs is inefficient. Solution: Avoid making multiple calls to get information about a placed sign. (Yegappan Lakshmanan, closes #4586)
This commit is contained in:
163
src/nvim/sign.c
163
src/nvim/sign.c
@@ -413,54 +413,101 @@ linenr_T buf_change_sign_type(
|
||||
return (linenr_T)0;
|
||||
}
|
||||
|
||||
/// Gets a sign from a given line.
|
||||
///
|
||||
/// Return the type number of the sign at line number 'lnum' in buffer 'buf'
|
||||
/// which has the attribute specified by 'type'. Returns 0 if a sign is not
|
||||
/// found at the line number or it doesn't have the specified attribute.
|
||||
/// @param buf Buffer in which to search
|
||||
/// @param lnum Line in which to search
|
||||
/// Return the sign attrs which has the attribute specified by 'type'. Returns
|
||||
/// NULL if a sign is not found with the specified attribute.
|
||||
/// @param type Type of sign to look for
|
||||
/// @param sattrs Sign attrs to search through
|
||||
/// @param idx if there multiple signs, this index will pick the n-th
|
||||
// out of the most `max_signs` sorted ascending by Id.
|
||||
/// out of the most `max_signs` sorted ascending by Id.
|
||||
/// @param max_signs the number of signs, with priority for the ones
|
||||
// with the highest Ids.
|
||||
/// @return Identifier of the matching sign, or 0
|
||||
int buf_getsigntype(buf_T *buf, linenr_T lnum, SignType type,
|
||||
int idx, int max_signs)
|
||||
/// with the highest Ids.
|
||||
/// @return Attrs of the matching sign, or NULL
|
||||
sign_attrs_T * sign_get_attr(SignType type, sign_attrs_T sattrs[],
|
||||
int idx, int max_signs)
|
||||
{
|
||||
signlist_T *sign; // a sign in a b_signlist
|
||||
signlist_T *matches[9];
|
||||
sign_attrs_T *matches[SIGN_SHOW_MAX];
|
||||
int nr_matches = 0;
|
||||
|
||||
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
||||
if (sign->lnum == lnum
|
||||
&& (type == SIGN_ANY
|
||||
|| (type == SIGN_TEXT
|
||||
&& sign_get_text(sign->typenr) != NULL)
|
||||
|| (type == SIGN_LINEHL
|
||||
&& sign_get_attr(sign->typenr, SIGN_LINEHL) != 0)
|
||||
|| (type == SIGN_NUMHL
|
||||
&& sign_get_attr(sign->typenr, SIGN_NUMHL) != 0))) {
|
||||
matches[nr_matches] = sign;
|
||||
for (int i = 0; i < SIGN_SHOW_MAX; i++) {
|
||||
if ( (type == SIGN_TEXT && sattrs[i].text != NULL)
|
||||
|| (type == SIGN_LINEHL && sattrs[i].linehl != 0)
|
||||
|| (type == SIGN_NUMHL && sattrs[i].numhl != 0)) {
|
||||
matches[nr_matches] = &sattrs[i];
|
||||
nr_matches++;
|
||||
// signlist is sorted with most important (priority, id), thus we
|
||||
// attr list is sorted with most important (priority, id), thus we
|
||||
// may stop as soon as we have max_signs matches
|
||||
if (nr_matches == ARRAY_SIZE(matches) || nr_matches >= max_signs) {
|
||||
if (nr_matches >= max_signs) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_matches > 0) {
|
||||
if (idx >= nr_matches) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return matches[nr_matches - idx -1]->typenr;
|
||||
if (nr_matches > idx) {
|
||||
return matches[nr_matches - idx - 1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Lookup a sign by typenr. Returns NULL if sign is not found.
|
||||
static sign_T * find_sign_by_typenr(int typenr)
|
||||
{
|
||||
sign_T *sp;
|
||||
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
|
||||
if (sp->sn_typenr == typenr) {
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Return the attributes of all the signs placed on line 'lnum' in buffer
|
||||
/// 'buf'. Used when refreshing the screen. Returns the number of signs.
|
||||
/// @param buf Buffer in which to search
|
||||
/// @param lnum Line in which to search
|
||||
/// @param sattrs Output array for attrs
|
||||
/// @return Number of signs of which attrs were found
|
||||
int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
|
||||
{
|
||||
signlist_T *sign;
|
||||
sign_T *sp;
|
||||
|
||||
int nr_matches = 0;
|
||||
|
||||
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
||||
if (sign->lnum > lnum) {
|
||||
// Signs are sorted by line number in the buffer. No need to check
|
||||
// for signs after the specified line number 'lnum'.
|
||||
break;
|
||||
}
|
||||
|
||||
if (sign->lnum == lnum) {
|
||||
sign_attrs_T sattr;
|
||||
memset(&sattr, 0, sizeof(sattr));
|
||||
sattr.typenr = sign->typenr;
|
||||
sp = find_sign_by_typenr(sign->typenr);
|
||||
if (sp != NULL) {
|
||||
sattr.text = sp->sn_text;
|
||||
if (sattr.text != NULL && sp->sn_text_hl != 0) {
|
||||
sattr.texthl = syn_id2attr(sp->sn_text_hl);
|
||||
}
|
||||
if (sp->sn_line_hl != 0) {
|
||||
sattr.linehl = syn_id2attr(sp->sn_line_hl);
|
||||
}
|
||||
if (sp->sn_num_hl != 0) {
|
||||
sattr.numhl = syn_id2attr(sp->sn_num_hl);
|
||||
}
|
||||
}
|
||||
|
||||
sattrs[nr_matches] = sattr;
|
||||
nr_matches++;
|
||||
if (nr_matches == SIGN_SHOW_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nr_matches;
|
||||
}
|
||||
|
||||
/// Delete sign 'id' in group 'group' from buffer 'buf'.
|
||||
@@ -557,6 +604,12 @@ static signlist_T * buf_getsign_at_line(
|
||||
signlist_T *sign; // a sign in the signlist
|
||||
|
||||
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
||||
if (sign->lnum > lnum) {
|
||||
// Signs are sorted by line number in the buffer. No need to check
|
||||
// for signs after the specified line number 'lnum'.
|
||||
break;
|
||||
}
|
||||
|
||||
if (sign->lnum == lnum && sign_in_group(sign, groupname)) {
|
||||
return sign;
|
||||
}
|
||||
@@ -1613,50 +1666,6 @@ static void sign_undefine(sign_T *sp, sign_T *sp_prev)
|
||||
xfree(sp);
|
||||
}
|
||||
|
||||
/// Gets highlighting attribute for sign "typenr" corresponding to "type".
|
||||
int sign_get_attr(int typenr, SignType type)
|
||||
{
|
||||
sign_T *sp;
|
||||
int sign_hl = 0;
|
||||
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
|
||||
if (sp->sn_typenr == typenr) {
|
||||
switch (type) {
|
||||
case SIGN_TEXT:
|
||||
sign_hl = sp->sn_text_hl;
|
||||
break;
|
||||
case SIGN_LINEHL:
|
||||
sign_hl = sp->sn_line_hl;
|
||||
break;
|
||||
case SIGN_NUMHL:
|
||||
sign_hl = sp->sn_num_hl;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (sign_hl > 0) {
|
||||
return syn_id2attr(sign_hl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Get text mark for sign "typenr".
|
||||
/// Returns NULL if there isn't one.
|
||||
char_u * sign_get_text(int typenr)
|
||||
{
|
||||
sign_T *sp;
|
||||
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
|
||||
if (sp->sn_typenr == typenr) {
|
||||
return sp->sn_text;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Undefine/free all signs.
|
||||
void free_signs(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user