diff options
Diffstat (limited to 'src/nvim/sign.c')
-rw-r--r-- | src/nvim/sign.c | 142 |
1 files changed, 86 insertions, 56 deletions
diff --git a/src/nvim/sign.c b/src/nvim/sign.c index d05c708d2c..4e6672c5dd 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -18,22 +18,27 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/extmark.h" #include "nvim/fold.h" -#include "nvim/func_attr.h" -#include "nvim/gettext.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" +#include "nvim/grid.h" +#include "nvim/grid_defs.h" #include "nvim/highlight.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/macros_defs.h" #include "nvim/map_defs.h" #include "nvim/marktree.h" +#include "nvim/marktree_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -46,8 +51,12 @@ #include "nvim/vim_defs.h" #include "nvim/window.h" -static PMap(cstr_t) sign_map INIT( = MAP_INIT); -static kvec_t(Integer) sign_ns INIT( = MAP_INIT); +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "sign.c.generated.h" +#endif + +static PMap(cstr_t) sign_map = MAP_INIT; +static kvec_t(Integer) sign_ns = KV_INITIAL_VALUE; static char *cmds[] = { "define", @@ -75,7 +84,7 @@ static int64_t group_get_ns(const char *group) return UINT32_MAX; // All namespaces } // Specific or non-existing namespace - int ns = map_get(String, int)(&namespace_ids, cstr_as_string((char *)group)); + int ns = map_get(String, int)(&namespace_ids, cstr_as_string(group)); return ns ? ns : -1; } @@ -103,7 +112,7 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr DecorSignHighlight sign = DECOR_SIGN_HIGHLIGHT_INIT; sign.flags |= kSHIsSign; - sign.text.ptr = sp->sn_text ? xstrdup(sp->sn_text) : NULL; + memcpy(sign.text, sp->sn_text, SIGN_WIDTH * sizeof(schar_T)); sign.sign_name = xstrdup(sp->sn_name); sign.hl_id = sp->sn_text_hl; sign.line_hl_id = sp->sn_line_hl; @@ -112,12 +121,12 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr 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) + uint16_t decor_flags = (sp->sn_text[0] ? 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); + false, true, true, false, NULL); } /// For an existing, placed sign with "id", modify the sign, group or priority. @@ -159,24 +168,22 @@ static int buf_findsign(buf_T *buf, int id, char *group) } /// qsort() function to sort signs by line number, priority, id and recency. -int sign_cmp(const void *p1, const void *p2) +static int sign_row_cmp(const void *p1, const void *p2) { const MTKey *s1 = (MTKey *)p1; const MTKey *s2 = (MTKey *)p2; - int n = s1->pos.row - s2->pos.row; - if (n) { - return n; + if (s1->pos.row != s2->pos.row) { + return s1->pos.row > s2->pos.row ? 1 : -1; } DecorSignHighlight *sh1 = decor_find_sign(mt_decor(*s1)); DecorSignHighlight *sh2 = decor_find_sign(mt_decor(*s2)); assert(sh1 && sh2); + SignItem si1 = { sh1, s1->id }; + SignItem si2 = { sh2, s2->id }; - n = sh2->priority - sh1->priority; - - return n ? n : (n = (int)(s2->id - s1->id)) - ? n : (sh2->sign_add_id - sh1->sign_add_id); + return sign_item_cmp(&si1, &si2); } /// Delete the specified sign(s) @@ -232,7 +239,7 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) // Sort to remove the highest priority sign at a specific line number. if (kv_size(signs)) { - qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_cmp); + qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp); extmark_del_id(buf, kv_A(signs, 0).ns, kv_A(signs, 0).id); kv_destroy(signs); } else if (atlnum > 0) { @@ -241,13 +248,18 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) // When deleting the last sign need to redraw the windows to remove the // sign column. Not when curwin is NULL (this means we're exiting). - if (!buf->b_signs_with_text && curwin != NULL) { + if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) { changed_line_abv_curs(); } return OK; } +bool buf_has_signs(const buf_T *buf) +{ + return (buf_meta_total(buf, kMTMetaSignHL) + buf_meta_total(buf, kMTMetaSignText)); +} + /// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers. static void sign_list_placed(buf_T *rbuf, char *group) { @@ -261,7 +273,7 @@ static void sign_list_placed(buf_T *rbuf, char *group) msg_putchar('\n'); while (buf != NULL && !got_int) { - if (buf->b_signs) { + if (buf_has_signs(buf)) { vim_snprintf(lbuf, MSG_BUF_LEN, _("Signs for %s:"), buf->b_fname); msg_puts_attr(lbuf, HL_ATTR(HLF_D)); msg_putchar('\n'); @@ -282,7 +294,7 @@ static void sign_list_placed(buf_T *rbuf, char *group) } if (kv_size(signs)) { - qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_cmp); + qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp); for (size_t i = 0; i < kv_size(signs); i++) { namebuf[0] = '\0'; @@ -332,9 +344,24 @@ static int sign_cmd_idx(char *begin_cmd, char *end_cmd) return idx; } +/// buf must be SIGN_WIDTH * MAX_SCHAR_SIZE (no extra +1 needed) +size_t describe_sign_text(char *buf, schar_T *sign_text) +{ + size_t p = 0; + for (int i = 0; i < SIGN_WIDTH; i++) { + schar_get(buf + p, sign_text[i]); + size_t len = strlen(buf + p); + if (len == 0) { + break; + } + p += len; + } + return p; +} + /// Initialize the "text" for a new sign and store in "sign_text". /// "sp" is NULL for signs added through nvim_buf_set_extmark(). -int init_sign_text(sign_T *sp, char **sign_text, char *text) +int init_sign_text(sign_T *sp, schar_T *sign_text, char *text) { char *s; char *endp = text + (int)strlen(text); @@ -349,34 +376,29 @@ int init_sign_text(sign_T *sp, char **sign_text, char *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))) { + int c; + sign_text[cells] = utfc_ptr2schar(s, &c); + if (!vim_isprintc(c)) { break; } - cells += utf_ptr2cells(s); + int width = utf_char2cells(c); + if (width == 2) { + sign_text[cells + 1] = 0; + } + cells += width; } // Currently must be empty, one or two display cells - if (s != endp || cells > 2) { + if (s != endp || cells > SIGN_WIDTH) { if (sp != NULL) { semsg(_("E239: Invalid sign text: %s"), text); } return FAIL; } - if (cells < 1) { - if (sp != NULL) { - sp->sn_text = NULL; - } - return OK; - } - if (sp != NULL) { - xfree(sp->sn_text); - } - // Allocate one byte more if we need to pad up with a space. - size_t len = (size_t)(endp - text + (cells == 1)); - *sign_text = xstrnsave(text, len); - - if (cells == 1) { - STRCPY(*sign_text + len - 1, " "); + if (cells < 1) { + sign_text[0] = 0; + } else if (cells == 1) { + sign_text[1] = schar_from_ascii(' '); } return OK; @@ -396,7 +418,7 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, } else { // Signs may already exist, a redraw is needed in windows with a non-empty sign list. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer->b_signs) { + if (buf_has_signs(wp->w_buffer)) { redraw_buf_later(wp->w_buffer, UPD_NOT_VALID); } } @@ -410,7 +432,7 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, backslash_halve((*sp)->sn_icon); } - if (text != NULL && (init_sign_text(*sp, &(*sp)->sn_text, text) == FAIL)) { + if (text != NULL && (init_sign_text(*sp, (*sp)->sn_text, text) == FAIL)) { return FAIL; } @@ -435,7 +457,6 @@ static int sign_undefine_by_name(const char *name) } xfree(sp->sn_name); - xfree(sp->sn_text); xfree(sp->sn_icon); xfree(sp); return OK; @@ -450,9 +471,11 @@ static void sign_list_defined(sign_T *sp) msg_outtrans(sp->sn_icon, 0); msg_puts(_(" (not supported)")); } - if (sp->sn_text != NULL) { + if (sp->sn_text[0]) { msg_puts(" text="); - msg_outtrans(sp->sn_text, 0); + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; + describe_sign_text(buf, sp->sn_text); + msg_outtrans(buf, 0); } static char *arg[] = { " linehl=", " texthl=", " culhl=", " numhl=" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; @@ -522,7 +545,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum) { - if (!buf->b_signs) { // No signs in the buffer + if (!buf_has_signs(buf)) { // No signs in the buffer return FAIL; } @@ -542,7 +565,7 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum) // When all the signs in a buffer are removed, force recomputing the // number column width (if enabled) in all the windows displaying the // buffer if 'signcolumn' is set to 'number' in that window. - if (!buf->b_signs_with_text) { + if (!buf_meta_total(buf, kMTMetaSignText)) { may_force_numberwidth_recompute(buf, true); } @@ -706,7 +729,7 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, c return; } - (void)sign_jump(id, group, buf); + sign_jump(id, group, buf); } /// Parse the command line arguments for the ":sign place", ":sign unplace" and @@ -718,7 +741,7 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char ** { char *arg1 = arg; char *filename = NULL; - int lnum_arg = false; + bool lnum_arg = false; // first arg could be placed sign id if (ascii_isdigit(*arg)) { @@ -787,7 +810,7 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char ** } if (filename != NULL && *buf == NULL) { - semsg(_("E158: Invalid buffer name: %s"), filename); + semsg(_(e_invalid_buffer_name_str), filename); return FAIL; } @@ -879,8 +902,10 @@ static dict_T *sign_get_info_dict(sign_T *sp) if (sp->sn_icon != NULL) { tv_dict_add_str(d, S_LEN("icon"), sp->sn_icon); } - if (sp->sn_text != NULL) { - tv_dict_add_str(d, S_LEN("text"), sp->sn_text); + if (sp->sn_text[0]) { + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; + describe_sign_text(buf, sp->sn_text); + tv_dict_add_str(d, S_LEN("text"), buf); } static char *arg[] = { "linehl", "texthl", "culhl", "numhl" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; @@ -910,7 +935,7 @@ static dict_T *sign_get_placed_info_dict(MTKey mark) /// Returns information about signs placed in a buffer as list of dicts. list_T *get_buffer_signs(buf_T *buf) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { list_T *const l = tv_list_alloc(kListLenMayKnow); MarkTreeIter itr[1]; @@ -940,7 +965,7 @@ static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const tv_dict_add_list(d, S_LEN("signs"), l); int64_t ns = group_get_ns(group); - if (!buf->b_signs || ns < 0) { + if (!buf_has_signs(buf) || ns < 0) { return; } @@ -967,7 +992,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); + qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp); for (size_t i = 0; i < kv_size(signs); i++) { tv_list_append_dict(l, sign_get_placed_info_dict(kv_A(signs, i))); } @@ -984,7 +1009,7 @@ static void sign_get_placed(buf_T *buf, linenr_T lnum, int id, const char *group sign_get_placed_in_buf(buf, lnum, id, group, retlist); } else { FOR_ALL_BUFFERS(cbuf) { - if (cbuf->b_signs) { + if (buf_has_signs(cbuf)) { sign_get_placed_in_buf(cbuf, 0, id, group, retlist); } } @@ -994,9 +1019,14 @@ static void sign_get_placed(buf_T *buf, linenr_T lnum, int id, const char *group void free_signs(void) { cstr_t name; + kvec_t(cstr_t) names = KV_INITIAL_VALUE; map_foreach_key(&sign_map, name, { - sign_undefine_by_name(name); + kv_push(names, name); }); + for (size_t i = 0; i < kv_size(names); i++) { + sign_undefine_by_name(kv_A(names, i)); + } + kv_destroy(names); } static enum { |