diff options
author | bfredl <bjorn.linse@gmail.com> | 2023-03-08 15:18:02 +0100 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2023-11-22 09:28:54 +0100 |
commit | 0b38fe4dbb77c15ae6f5779174855acab25fc86c (patch) | |
tree | f37567ea2fe07b6e640386bec469bf8e5d9166d1 /src/nvim/sign.c | |
parent | 8c6b0a5f21d5f0cf3781ef2b6fdbb306d5604a02 (diff) | |
download | rneovim-0b38fe4dbb77c15ae6f5779174855acab25fc86c.tar.gz rneovim-0b38fe4dbb77c15ae6f5779174855acab25fc86c.tar.bz2 rneovim-0b38fe4dbb77c15ae6f5779174855acab25fc86c.zip |
refactor(decorations): break up Decoration struct into smaller pieces
Remove the monolithic Decoration struct. Before this change, each extmark
could either represent just a hl_id + priority value as a inline
decoration, or it would take a pointer to this monolitic 112 byte struct
which has to be allocated.
This change separates the decorations into two pieces: DecorSignHighlight
for signs, highlights and simple set-flag decorations (like spell,
ui-watched), and DecorVirtText for virtual text and lines.
The main separation here is whether they are expected to allocate more
memory. Currently this is not really true as sign text has to be an
allocated string, but the plan is to get rid of this eventually (it can
just be an array of two schar_T:s). Further refactors are expected to
improve the representation of each decoration kind individually. The
goal of this particular PR is to get things started by cutting the
Gordian knot which was the monolithic struct Decoration.
Now, each extmark can either contain chained indicies/pointers to
these kinds of objects, or it can fit a subset of DecorSignHighlight
inline.
The point of this change is not only to make decorations smaller in
memory. In fact, the main motivation is to later allow them to grow
_larger_, but on a dynamic, on demand fashion. As a simple example, it
would be possible to augment highlights to take a list of multiple
`hl_group`:s, which then would trivially map to a chain of multiple
DecorSignHighlight entries.
One small feature improvement included with this refactor itself, is
that the restriction that extmarks cannot be removed inside a decoration
provider has been lifted. These are instead safely lifetime extended
on a "to free" list until the current iteration of screen drawing is done.
NB: flags is a mess. but DecorLevel is useless, this slightly less so
Diffstat (limited to 'src/nvim/sign.c')
-rw-r--r-- | src/nvim/sign.c | 113 |
1 files changed, 70 insertions, 43 deletions
diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 0136937ad2..9a48b1b1a5 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -71,9 +71,9 @@ static int64_t group_get_ns(const char *group) return ns ? ns : -1; } -static const char *sign_get_name(MTKey mark) +static const char *sign_get_name(DecorSignHighlight *sh) { - char *name = mark.decor_full->sign_name; + char *name = sh->sign_name; return !name ? "" : map_has(cstr_t, &sign_map, name) ? name : "[Deleted]"; } @@ -92,15 +92,24 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr } uint32_t ns = group ? (uint32_t)nvim_create_namespace(cstr_as_string(group)) : 0; - Decoration decor = DECORATION_INIT; - decor.sign_text = sp->sn_text ? xstrdup(sp->sn_text) : NULL; - decor.sign_name = xstrdup(sp->sn_name); - decor.sign_hl_id = sp->sn_text_hl; - decor.line_hl_id = sp->sn_line_hl; - decor.number_hl_id = sp->sn_num_hl; - decor.cursorline_hl_id = sp->sn_cul_hl; - decor.priority = (DecorPriority)prio; - extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, &decor, true, false, true, true, NULL); + DecorSignHighlight sign = DECOR_SIGN_HIGHLIGHT_INIT; + + sign.flags |= kSHIsSign; + sign.text.ptr = sp->sn_text ? xstrdup(sp->sn_text) : NULL; + sign.sign_name = xstrdup(sp->sn_name); + sign.hl_id = sp->sn_text_hl; + sign.line_hl_id = sp->sn_line_hl; + sign.number_hl_id = sp->sn_num_hl; + sign.cursorline_hl_id = sp->sn_cul_hl; + sign.priority = (DecorPriority)prio; + + bool has_hl = (sp->sn_line_hl || sp->sn_num_hl || sp->sn_cul_hl); + uint16_t decor_flags = (sp->sn_text ? MT_FLAG_DECOR_SIGNTEXT : 0) + | (has_hl ? MT_FLAG_DECOR_SIGNHL : 0); + + DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } }; + extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true, + false, true, true, NULL); } /// For an existing, placed sign with "id", modify the sign, group or priority. @@ -148,9 +157,18 @@ int sign_cmp(const void *p1, const void *p2) const MTKey *s2 = (MTKey *)p2; int n = s1->pos.row - s2->pos.row; - return n ? n : (n = s2->decor_full->priority - s1->decor_full->priority) - ? n : (n = (int)(s2->id - s1->id)) - ? n : (s2->decor_full->sign_add_id - s1->decor_full->sign_add_id); + if (n) { + return n; + } + + DecorSignHighlight *sh1 = decor_find_sign(mt_decor(*s1)); + DecorSignHighlight *sh2 = decor_find_sign(mt_decor(*s2)); + assert(sh1 && sh2); + + n = sh2->priority - sh1->priority; + + return n ? n : (n = (int)(s2->id - s1->id)) + ? n : (sh2->sign_add_id - sh1->sign_add_id); } /// Delete the specified signs @@ -177,8 +195,7 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) MTPair pair; while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) { - if ((ns == UINT32_MAX || ns == pair.start.ns) - && pair.start.decor_full && decor_has_sign(pair.start.decor_full)) { + if ((ns == UINT32_MAX || ns == pair.start.ns) && mt_decor_sign(pair.start)) { kv_push(signs, pair.start); } } @@ -191,7 +208,7 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) if (row && mark.pos.row > row) { break; } - if (!mt_end(mark) && mark.decor_full && decor_has_sign(mark.decor_full) + if (!mt_end(mark) && mt_decor_sign(mark) && (id == 0 || (int)mark.id == id) && (ns == UINT32_MAX || ns == mark.ns)) { if (atlnum > 0) { @@ -248,7 +265,7 @@ static void sign_list_placed(buf_T *rbuf, char *group) while (itr->x) { MTKey mark = marktree_itr_current(itr); - if (!mt_end(mark) && mark.decor_full && decor_has_sign(mark.decor_full) + if (!mt_end(mark) && mt_decor_sign(mark) && (ns == UINT32_MAX || ns == mark.ns)) { kv_push(signs, mark); } @@ -262,14 +279,16 @@ static void sign_list_placed(buf_T *rbuf, char *group) namebuf[0] = '\0'; groupbuf[0] = '\0'; MTKey mark = kv_A(signs, i); - if (mark.decor_full->sign_name != NULL) { - vim_snprintf(namebuf, MSG_BUF_LEN, _(" name=%s"), sign_get_name(mark)); + + DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); + if (sh->sign_name != NULL) { + vim_snprintf(namebuf, MSG_BUF_LEN, _(" name=%s"), sign_get_name(sh)); } if (mark.ns != 0) { vim_snprintf(groupbuf, MSG_BUF_LEN, _(" group=%s"), describe_ns((int)mark.ns, "")); } vim_snprintf(lbuf, MSG_BUF_LEN, _(" line=%" PRIdLINENR " id=%u%s%s priority=%d"), - mark.pos.row + 1, mark.id, groupbuf, namebuf, mark.decor_full->priority); + mark.pos.row + 1, mark.id, groupbuf, namebuf, sh->priority); msg_puts(lbuf); msg_putchar('\n'); } @@ -841,21 +860,12 @@ void ex_sign(exarg_T *eap) } } -/// Append dictionary of information for a defined sign "sp", or placed -/// sign "mark" to "retlist". Either "sp", or "mark" is NULL. -static void sign_list_append_info(sign_T *sp, MTKey *mark, list_T *retlist) +/// Get dictionary of information for a defined sign "sp" +static dict_T *sign_get_info_dict(sign_T *sp) { dict_T *d = tv_dict_alloc(); - tv_list_append_dict(retlist, d); - tv_dict_add_str(d, S_LEN("name"), sp ? sp->sn_name : sign_get_name(*mark)); - if (mark != NULL) { - tv_dict_add_nr(d, S_LEN("id"), (int)mark->id); - tv_dict_add_str(d, S_LEN("group"), describe_ns((int)mark->ns, "")); - tv_dict_add_nr(d, S_LEN("lnum"), mark->pos.row + 1); - tv_dict_add_nr(d, S_LEN("priority"), mark->decor_full->priority); - return; - } + tv_dict_add_str(d, S_LEN("name"), sp->sn_name); if (sp->sn_icon != NULL) { tv_dict_add_str(d, S_LEN("icon"), sp->sn_icon); @@ -871,6 +881,22 @@ static void sign_list_append_info(sign_T *sp, MTKey *mark, list_T *retlist) tv_dict_add_str(d, arg[i], strlen(arg[i]), p ? p : "NONE"); } } + return d; +} + +/// Get dictionary of information for placed sign "mark" +static dict_T *sign_get_placed_info_dict(MTKey mark) +{ + dict_T *d = tv_dict_alloc(); + + DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); + + tv_dict_add_str(d, S_LEN("name"), sign_get_name(sh)); + tv_dict_add_nr(d, S_LEN("id"), (int)mark.id); + tv_dict_add_str(d, S_LEN("group"), describe_ns((int)mark.ns, "")); + tv_dict_add_nr(d, S_LEN("lnum"), mark.pos.row + 1); + tv_dict_add_nr(d, S_LEN("priority"), sh->priority); + return d; } /// Returns information about signs placed in a buffer as list of dicts. @@ -883,8 +909,8 @@ list_T *get_buffer_signs(buf_T *buf) while (itr->x) { MTKey mark = marktree_itr_current(itr); - if (!mt_end(mark) && mark.decor_full && decor_has_sign(mark.decor_full)) { - sign_list_append_info(NULL, &mark, l); + if (!mt_end(mark) && mt_decor_sign(mark)) { + tv_list_append_dict(l, sign_get_placed_info_dict(mark)); } marktree_itr_next(buf->b_marktree, itr); } @@ -918,13 +944,15 @@ static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const if (lnum && mark.pos.row >= lnum) { break; } - if (!mt_end(mark) && mark.decor_full && decor_has_sign(mark.decor_full) + if (!mt_end(mark) && (ns == UINT32_MAX || ns == mark.ns) && ((lnum == 0 && sign_id == 0) || (sign_id == 0 && lnum == mark.pos.row + 1) || (lnum == 0 && sign_id == (int)mark.id) || (lnum == mark.pos.row + 1 && sign_id == (int)mark.id))) { - kv_push(signs, mark); + if (mt_decor_sign(mark)) { + kv_push(signs, mark); + } } marktree_itr_next(buf->b_marktree, itr); } @@ -932,7 +960,7 @@ static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const if (kv_size(signs)) { qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_cmp); for (size_t i = 0; i < kv_size(signs); i++) { - sign_list_append_info(NULL, &kv_A(signs, i), l); + tv_list_append_dict(l, sign_get_placed_info_dict(kv_A(signs, i))); } kv_destroy(signs); } @@ -1222,18 +1250,17 @@ void f_sign_define(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "sign_getdefined()" function void f_sign_getdefined(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - sign_T *sp; - tv_list_alloc_ret(rettv, 0); if (argvars[0].v_type == VAR_UNKNOWN) { + sign_T *sp; map_foreach_value(&sign_map, sp, { - sign_list_append_info(sp, NULL, rettv->vval.v_list); + tv_list_append_dict(rettv->vval.v_list, sign_get_info_dict(sp)); }); } else { - sp = pmap_get(cstr_t)(&sign_map, tv_get_string(&argvars[0])); + sign_T *sp = pmap_get(cstr_t)(&sign_map, tv_get_string(&argvars[0])); if (sp != NULL) { - sign_list_append_info(sp, NULL, rettv->vval.v_list); + tv_list_append_dict(rettv->vval.v_list, sign_get_info_dict(sp)); } } } |