diff options
| author | zeertzjq <zeertzjq@outlook.com> | 2026-04-20 16:14:11 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-20 08:14:11 +0000 |
| commit | 2e8f285f6c1be6a55a9aae2fab64421f24bd7df0 (patch) | |
| tree | a97d560798e5254381e1430a23de8c101761acb5 /src | |
| parent | 61daad3bbaa30c916ee96dba4747fba3556878e1 (diff) | |
vim-patch:partial:9.2.0368: too many strlen() calls when adding strings to dicts (#39237)
Problem: too many strlen() calls when adding strings to dicts
Solution: Refactor code to use string_T, use dict_add_string_len()
instead of dict_add_string() (John Marriott)
Additionally:
- In textprop.c, in function prop_fill_dict() use a string_T to store
local variable text_align.
- In popupwin.c, use a string_T to store struct member pp_name in struct
poppos_entry_T.
- In mark.c, refactor function add_mark() to pass in the length of
argument mname.
- In insexpand.c:
->Use a string_T to store the elements of static array
ctrl_x_mode_names.
->Refactor function trigger_complete_done_event():
->->change type of argument char_u *word to string_T *word.
->->make one access of array ctrl_x_mode_names instead of two.
->Refactor function ins_compl_mode() to accept a string_T to return the
resulting string.
- In fileio.c:
->Refactor function getftypewfd() to accept a string_T to return the
resulting string.
->In function create_readdirex_item() use a string_T to store local
variable q.
- In cmdexpand.c, store global cmdline_orig as a string_T.
- In autocmd.c, in function f_autocmd_get() use a string_T to store local
variables event_name and group_name. Measure their lengths once when
they are assigned so they are not remeasured on each call to
dict_add_string() in the subsequent for loop.
- In channel.c, in function channel_part_info() drop local variable status
and use s instead. Make s a string_T.
closes: vim/vim#19999
https://github.com/vim/vim/commit/c13232699db413e735f30b5649c78a7f38a9a069
Co-authored-by: John Marriott <basilisk@internode.on.net>
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/api/private/helpers.h | 3 | ||||
| -rw-r--r-- | src/nvim/cmdexpand.c | 11 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 18 | ||||
| -rw-r--r-- | src/nvim/insexpand.c | 92 | ||||
| -rw-r--r-- | src/nvim/mark.c | 29 | ||||
| -rw-r--r-- | src/nvim/match.c | 6 | ||||
| -rw-r--r-- | src/nvim/memline.c | 8 | ||||
| -rw-r--r-- | src/nvim/menu.c | 11 | ||||
| -rw-r--r-- | src/nvim/optionstr.c | 2 | ||||
| -rw-r--r-- | src/nvim/quickfix.c | 13 | ||||
| -rw-r--r-- | src/nvim/sign.c | 6 |
11 files changed, 110 insertions, 89 deletions
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 21a8f796b9..0436b05ce5 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -99,7 +99,8 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder; #define cbuf_as_string(d, s) ((String) { .data = d, .size = s }) -#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 }) +#define STATIC_CSTR_STRING_INIT(s) { .data = s, .size = sizeof("" s) - 1 } +#define STATIC_CSTR_AS_STRING(s) ((String)STATIC_CSTR_STRING_INIT(s)) /// Create a new String instance, putting data in allocated memory /// diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 0c2c14bdb7..cfcc9c033e 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -96,7 +96,7 @@ static int compl_match_arraysize; static int compl_startcol; static int compl_selected; /// cmdline before expansion -static char *cmdline_orig = NULL; +static String cmdline_orig = STRING_INIT; #define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : matches[m]) @@ -341,8 +341,8 @@ int nextwild(expand_T *xp, int type, int options, bool escape) // Save cmdline before inserting selected item if (!wild_navigate && ccline->cmdbuff != NULL) { - xfree(cmdline_orig); - cmdline_orig = xstrnsave(ccline->cmdbuff, (size_t)ccline->cmdlen); + xfree(cmdline_orig.data); + cmdline_orig = cstrn_to_string(ccline->cmdbuff, (size_t)ccline->cmdlen); } if (p != NULL && !got_int && !(options & WILD_NOSELECT)) { @@ -1030,7 +1030,7 @@ void ExpandCleanup(expand_T *xp) void clear_cmdline_orig(void) { - XFREE_CLEAR(cmdline_orig); + API_CLEAR_STRING(cmdline_orig); } /// Display one line of completion matches. Multiple matches are displayed in @@ -4040,7 +4040,8 @@ void f_cmdcomplete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } dict_T *retdict = rettv->vval.v_dict; - int ret = tv_dict_add_str(retdict, S_LEN("cmdline_orig"), cmdline_orig); + int ret = tv_dict_add_str_len(retdict, S_LEN("cmdline_orig"), + cmdline_orig.data, (int)cmdline_orig.size); if (ret == OK) { ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible()); } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c21655b7ab..ea017b5954 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5140,28 +5140,32 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_dict_add_list(dict, S_LEN("regcontents"), list); char buf[NUMBUFLEN + 2]; - buf[0] = NUL; - buf[1] = NUL; + size_t buflen; colnr_T reglen = 0; switch (get_reg_type(regname, ®len)) { case kMTLineWise: buf[0] = 'V'; + buf[1] = NUL; + buflen = 1; break; case kMTCharWise: buf[0] = 'v'; + buf[1] = NUL; + buflen = 1; break; case kMTBlockWise: - vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1); + buflen = vim_snprintf_safelen(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1); break; case kMTUnknown: abort(); } - tv_dict_add_str(dict, S_LEN("regtype"), buf); + tv_dict_add_str_len(dict, S_LEN("regtype"), buf, (int)buflen); buf[0] = (char)get_register_name(get_unname_register()); buf[1] = NUL; + buflen = buf[0] == NUL ? 0 : 1; if (regname == '"') { - tv_dict_add_str(dict, S_LEN("points_to"), buf); + tv_dict_add_str_len(dict, S_LEN("points_to"), buf, (int)buflen); } else { tv_dict_add_bool(dict, S_LEN("isunnamed"), regname == buf[0] ? kBoolVarTrue : kBoolVarFalse); @@ -5170,10 +5174,10 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void return_register(int regname, typval_T *rettv) { - char buf[2] = { (char)regname, 0 }; + char buf[2] = { (char)regname, NUL }; rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(buf); + rettv->vval.v_string = xmemdupz(buf, buf[0] == NUL ? 0 : 1); } /// "reg_executing()" function diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 11794fd747..2be06a359b 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -137,27 +137,27 @@ static char *ctrl_x_msgs[] = { N_(" Register completion (^N^P)"), }; -static char *ctrl_x_mode_names[] = { - "keyword", - "ctrl_x", - "scroll", - "whole_line", - "files", - "tags", - "path_patterns", - "path_defines", - "unknown", // CTRL_X_FINISHED - "dictionary", - "thesaurus", - "cmdline", - "function", - "omni", - "spell", - NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" - "eval", - "cmdline", - NULL, // CTRL_X_BUFNAME - "register", +static String ctrl_x_mode_names[] = { + STATIC_CSTR_STRING_INIT("keyword"), + STATIC_CSTR_STRING_INIT("ctrl_x"), + STATIC_CSTR_STRING_INIT("scroll"), + STATIC_CSTR_STRING_INIT("whole_line"), + STATIC_CSTR_STRING_INIT("files"), + STATIC_CSTR_STRING_INIT("tags"), + STATIC_CSTR_STRING_INIT("path_patterns"), + STATIC_CSTR_STRING_INIT("path_defines"), + STATIC_CSTR_STRING_INIT("unknown"), // CTRL_X_FINISHED + STATIC_CSTR_STRING_INIT("dictionary"), + STATIC_CSTR_STRING_INIT("thesaurus"), + STATIC_CSTR_STRING_INIT("cmdline"), + STATIC_CSTR_STRING_INIT("function"), + STATIC_CSTR_STRING_INIT("omni"), + STATIC_CSTR_STRING_INIT("spell"), + STRING_INIT, // CTRL_X_LOCAL_MSG is only used in "ctrl_x_msgs" + STATIC_CSTR_STRING_INIT("eval"), + STATIC_CSTR_STRING_INIT("cmdline"), + STRING_INIT, // CTRL_X_BUFNAME + STATIC_CSTR_STRING_INIT("register"), }; /// Structure used to store one match for insert completion. @@ -638,21 +638,25 @@ static bool is_first_match(const compl_T *const match) return match == compl_first_match; } -static void do_autocmd_completedone(int c, int mode, char *word) +static void do_autocmd_completedone(int c, int mode, String *word) { save_v_event_T save_v_event; dict_T *v_event = get_v_event(&save_v_event); - mode = mode & ~CTRL_X_WANT_IDENT; - char *mode_str = NULL; - if (ctrl_x_mode_names[mode]) { - mode_str = ctrl_x_mode_names[mode]; + if (word == NULL || word->data == NULL) { + tv_dict_add_str_len(v_event, S_LEN("complete_word"), "", 0); + } else { + tv_dict_add_str_len(v_event, S_LEN("complete_word"), word->data, (int)word->size); } - tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : ""); - tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : ""); + + String *mode_str = &ctrl_x_mode_names[mode & ~CTRL_X_WANT_IDENT]; + tv_dict_add_str_len(v_event, S_LEN("complete_type"), + mode_str->data == NULL ? "" : mode_str->data, + (int)mode_str->size); tv_dict_add_str(v_event, S_LEN("reason"), - (c == Ctrl_Y || word != NULL ? "accept" : (c == Ctrl_E ? "cancel" : "discard"))); + (c == Ctrl_Y || (word != NULL && word->data != NULL) + ? "accept" : (c == Ctrl_E ? "cancel" : "discard"))); tv_dict_set_keys_readonly(v_event); ins_apply_autocmds(EVENT_COMPLETEDONE); @@ -1319,13 +1323,13 @@ static dict_T *ins_compl_dict_alloc(compl_T *match) { // { word, abbr, menu, kind, info } dict_T *dict = tv_dict_alloc_lock(VAR_FIXED); - tv_dict_add_str(dict, S_LEN("word"), match->cp_str.data); + tv_dict_add_str_len(dict, S_LEN("word"), match->cp_str.data, (int)match->cp_str.size); tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]); tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]); tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]); tv_dict_add_str(dict, S_LEN("info"), match->cp_text[CPT_INFO]); if (match->cp_user_data.v_type == VAR_UNKNOWN) { - tv_dict_add_str(dict, S_LEN("user_data"), ""); + tv_dict_add_str_len(dict, S_LEN("user_data"), "", 0); } else { tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data); } @@ -2648,14 +2652,14 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) } } - char *word = NULL; + String word = STRING_INIT; // If the popup menu is displayed pressing CTRL-Y means accepting // the selection without inserting anything. When // compl_enter_selects is set the Enter key does the same. if ((c == Ctrl_Y || (compl_enter_selects && (c == CAR || c == K_KENTER || c == NL))) && pum_visible()) { - word = xstrdup(compl_shown_match->cp_str.data); + word = copy_string(compl_shown_match->cp_str, NULL); retval = true; // May need to remove ComplMatchIns highlight. redrawWinline(curwin, curwin->w_cursor.lnum); @@ -2665,10 +2669,10 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) // (eg: only one match with 'completeopt' "menu" without "menuone"), // the user had no opportunity to explicitly accept or dismiss it, // so treat this as an implicit accept (#38160). - if (word == NULL && c != Ctrl_E && compl_used_match && compl_match_array == NULL + if (word.data == NULL && c != Ctrl_E && compl_used_match && compl_match_array == NULL && compl_curr_match != NULL && compl_curr_match->cp_str.data != NULL) { - word = xstrdup(compl_curr_match->cp_str.data); + word = copy_string(compl_curr_match->cp_str, NULL); } // CTRL-E means completion is Ended, go back to the typed text. @@ -2731,8 +2735,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) } // Trigger the CompleteDone event to give scripts a chance to act // upon the end of completion. - do_autocmd_completedone(c, prev_mode, word); - xfree(word); + do_autocmd_completedone(c, prev_mode, &word); + xfree(word.data); return retval; } @@ -3517,12 +3521,13 @@ void f_complete_check(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// Return Insert completion mode name string -static char *ins_compl_mode(void) +static String ins_compl_mode(void) { if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started) { - return ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT]; + String *mode = &ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT]; + return cbuf_as_string(mode->data == NULL ? "" : mode->data, mode->size); } - return ""; + return cbuf_as_string("", 0); } /// Assign the sequence number to all the completion matches which don't have @@ -3577,7 +3582,7 @@ static void ins_compl_update_sequence_numbers(void) /// Fill the dict of complete_info static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match) { - tv_dict_add_str(di, S_LEN("word"), match->cp_str.data); + tv_dict_add_str_len(di, S_LEN("word"), match->cp_str.data, (int)match->cp_str.size); tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]); tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]); tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]); @@ -3587,7 +3592,7 @@ static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match) } if (match->cp_user_data.v_type == VAR_UNKNOWN) { // Add an empty string for backwards compatibility - tv_dict_add_str(di, S_LEN("user_data"), ""); + tv_dict_add_str_len(di, S_LEN("user_data"), "", 0); } else { tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data); } @@ -3635,7 +3640,8 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) int ret = OK; if (what_flag & CI_WHAT_MODE) { - ret = tv_dict_add_str(retdict, S_LEN("mode"), ins_compl_mode()); + String mode = ins_compl_mode(); + ret = tv_dict_add_str_len(retdict, S_LEN("mode"), mode.data, (int)mode.size); } if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) { diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 100921d682..dd49276edc 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1912,8 +1912,9 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) } // Add information about mark 'mname' to list 'l' -static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, const char *fname) - FUNC_ATTR_NONNULL_ARG(1, 2, 3) +static int add_mark(list_T *l, const char *mname, size_t mnamelen, const pos_T *pos, int bufnr, + const char *fname) + FUNC_ATTR_NONNULL_ARG(1, 2, 4) { if (pos->lnum <= 0) { return OK; @@ -1929,7 +1930,7 @@ static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, c tv_list_append_number(lpos, pos->col < MAXCOL ? pos->col + 1 : MAXCOL); tv_list_append_number(lpos, pos->coladd); - if (tv_dict_add_str(d, S_LEN("mark"), mname) == FAIL + if (tv_dict_add_str_len(d, S_LEN("mark"), mname, (int)mnamelen) == FAIL || tv_dict_add_list(d, S_LEN("pos"), lpos) == FAIL || (fname != NULL && tv_dict_add_str(d, S_LEN("file"), fname) == FAIL)) { return FAIL; @@ -1946,23 +1947,24 @@ void get_buf_local_marks(const buf_T *buf, list_T *l) FUNC_ATTR_NONNULL_ALL { char mname[3] = "' "; + size_t mnamelen = STRLEN_LITERAL("' "); // Marks 'a' to 'z' for (int i = 0; i < NMARKS; i++) { mname[1] = (char)('a' + i); - add_mark(l, mname, &buf->b_namedm[i].mark, buf->b_fnum, NULL); + add_mark(l, mname, mnamelen, &buf->b_namedm[i].mark, buf->b_fnum, NULL); } // Mark '' is a window local mark and not a buffer local mark - add_mark(l, "''", &curwin->w_pcmark, curbuf->b_fnum, NULL); + add_mark(l, S_LEN("''"), &curwin->w_pcmark, curbuf->b_fnum, NULL); - add_mark(l, "'\"", &buf->b_last_cursor.mark, buf->b_fnum, NULL); - add_mark(l, "'[", &buf->b_op_start, buf->b_fnum, NULL); - add_mark(l, "']", &buf->b_op_end, buf->b_fnum, NULL); - add_mark(l, "'^", &buf->b_last_insert.mark, buf->b_fnum, NULL); - add_mark(l, "'.", &buf->b_last_change.mark, buf->b_fnum, NULL); - add_mark(l, "'<", &buf->b_visual.vi_start, buf->b_fnum, NULL); - add_mark(l, "'>", &buf->b_visual.vi_end, buf->b_fnum, NULL); + add_mark(l, S_LEN("'\""), &buf->b_last_cursor.mark, buf->b_fnum, NULL); + add_mark(l, S_LEN("'["), &buf->b_op_start, buf->b_fnum, NULL); + add_mark(l, S_LEN("']"), &buf->b_op_end, buf->b_fnum, NULL); + add_mark(l, S_LEN("'^"), &buf->b_last_insert.mark, buf->b_fnum, NULL); + add_mark(l, S_LEN("'."), &buf->b_last_change.mark, buf->b_fnum, NULL); + add_mark(l, S_LEN("'<"), &buf->b_visual.vi_start, buf->b_fnum, NULL); + add_mark(l, S_LEN("'>"), &buf->b_visual.vi_end, buf->b_fnum, NULL); } /// Get a global mark @@ -1982,6 +1984,7 @@ void get_global_marks(list_T *l) FUNC_ATTR_NONNULL_ALL { char mname[3] = "' "; + size_t mnamelen = STRLEN_LITERAL("' "); char *name; // Marks 'A' to 'Z' and '0' to '9' @@ -1994,7 +1997,7 @@ void get_global_marks(list_T *l) if (name != NULL) { mname[1] = i >= NMARKS ? (char)(i - NMARKS + '0') : (char)(i + 'A'); - add_mark(l, mname, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name); + add_mark(l, mname, mnamelen, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name); if (namedfm[i].fmark.fnum != 0) { xfree(name); } diff --git a/src/nvim/match.c b/src/nvim/match.c index 5d95d06661..10d02356fd 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -907,9 +907,9 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (cur->mit_conceal_char) { char buf[MB_MAXCHAR + 1]; - - buf[utf_char2bytes(cur->mit_conceal_char, buf)] = NUL; - tv_dict_add_str(dict, S_LEN("conceal"), buf); + int buflen = utf_char2bytes(cur->mit_conceal_char, buf); + buf[buflen] = NUL; + tv_dict_add_str_len(dict, S_LEN("conceal"), buf, buflen); } tv_list_append_dict(rettv->vval.v_list, dict); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index a0a9c84d0d..b5ac0cdb28 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1496,9 +1496,9 @@ void swapfile_dict(const char *fname, dict_T *d) if ((fd = os_open(fname, O_RDONLY, 0)) >= 0) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { if (ml_check_b0_id(&b0) == FAIL) { - tv_dict_add_str(d, S_LEN("error"), "Not a swap file"); + tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Not a swap file")); } else if (b0_magic_wrong(&b0)) { - tv_dict_add_str(d, S_LEN("error"), "Magic number mismatch"); + tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Magic number mismatch")); } else { // We have swap information. tv_dict_add_str_len(d, S_LEN("version"), b0.b0_version, 10); @@ -1515,11 +1515,11 @@ void swapfile_dict(const char *fname, dict_T *d) tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino)); } } else { - tv_dict_add_str(d, S_LEN("error"), "Cannot read file"); + tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Cannot read file")); } close(fd); } else { - tv_dict_add_str(d, S_LEN("error"), "Cannot open file"); + tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Cannot open file")); } } diff --git a/src/nvim/menu.c b/src/nvim/menu.c index d4fd0a067c..db4d325d77 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -674,8 +674,8 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) if (menu->mnemonic) { char buf[MB_MAXCHAR + 1] = { 0 }; // > max value of utf8_char2bytes - utf_char2bytes(menu->mnemonic, buf); - tv_dict_add_str(dict, S_LEN("shortcut"), buf); + int buflen = utf_char2bytes(menu->mnemonic, buf); + tv_dict_add_str_len(dict, S_LEN("shortcut"), buf, buflen); } if (menu->actext) { @@ -1864,8 +1864,9 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m tv_dict_add_str(dict, S_LEN("modes"), get_menu_mode_str(menu->modes)); char buf[NUMBUFLEN]; - buf[utf_char2bytes(menu->mnemonic, buf)] = NUL; - tv_dict_add_str(dict, S_LEN("shortcut"), buf); + int buflen = utf_char2bytes(menu->mnemonic, buf); + buf[buflen] = NUL; + tv_dict_add_str_len(dict, S_LEN("shortcut"), buf, buflen); if (menu->children == NULL) { // leaf menu int bit; @@ -1877,7 +1878,7 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m if (menu->strings[bit] != NULL) { tv_dict_add_allocated_str(dict, S_LEN("rhs"), *menu->strings[bit] == NUL - ? xstrdup("<Nop>") + ? xmemdupz(S_LEN("<Nop>")) : str2special_save(menu->strings[bit], false, false)); } tv_dict_add_bool(dict, S_LEN("noremenu"), menu->noremap[bit] == REMAP_NONE); diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 91f52bbcd2..274fbb653c 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -2223,7 +2223,7 @@ struct chars_tab { }; #define CHARSTAB_ENTRY(cp, name, def, fallback) \ - { (cp), { name, STRLEN_LITERAL(name) }, def, fallback } + { (cp), STATIC_CSTR_STRING_INIT(name), def, fallback } static fcs_chars_T fcs_chars; static const struct chars_tab fcs_tab[] = { diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1c332d5885..9e90aabc5d 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6104,6 +6104,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list) char buf[2]; buf[0] = qfp->qf_type; buf[1] = NUL; + size_t buflen = (buf[0] == NUL) ? 0 : 1; if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum) == FAIL) || (tv_dict_add_nr(dict, S_LEN("end_lnum"), (varnumber_T)qfp->qf_end_lnum) == FAIL) @@ -6116,7 +6117,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list) || (tv_dict_add_str(dict, S_LEN("pattern"), (qfp->qf_pattern == NULL ? "" : qfp->qf_pattern)) == FAIL) || (tv_dict_add_str(dict, S_LEN("text"), (qfp->qf_text == NULL ? "" : qfp->qf_text)) == FAIL) - || (tv_dict_add_str(dict, S_LEN("type"), buf) == FAIL) + || (tv_dict_add_str_len(dict, S_LEN("type"), buf, (int)buflen) == FAIL) || (qfp->qf_user_data.v_type != VAR_UNKNOWN && tv_dict_add_tv(dict, S_LEN("user_data"), &qfp->qf_user_data) == FAIL) || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid) == FAIL)) { @@ -6372,7 +6373,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r int status = OK; if (flags & QF_GETLIST_TITLE) { - status = tv_dict_add_str(retdict, S_LEN("title"), ""); + status = tv_dict_add_str_len(retdict, S_LEN("title"), "", 0); } if ((status == OK) && (flags & QF_GETLIST_ITEMS)) { list_T *l = tv_list_alloc(kListLenMayKnow); @@ -6385,7 +6386,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi)); } if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) { - status = tv_dict_add_str(retdict, S_LEN("context"), ""); + status = tv_dict_add_str_len(retdict, S_LEN("context"), "", 0); } if ((status == OK) && (flags & QF_GETLIST_ID)) { status = tv_dict_add_nr(retdict, S_LEN("id"), 0); @@ -6406,7 +6407,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r status = qf_getprop_qfbufnr(qi, retdict); } if ((status == OK) && (flags & QF_GETLIST_QFTF)) { - status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), ""); + status = tv_dict_add_str_len(retdict, S_LEN("quickfixtextfunc"), "", 0); } return status; @@ -6460,7 +6461,7 @@ static int qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict) tv_dict_item_free(di); } } else { - status = tv_dict_add_str(retdict, S_LEN("context"), ""); + status = tv_dict_add_str_len(retdict, S_LEN("context"), "", 0); } return status; @@ -6494,7 +6495,7 @@ static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict) status = tv_dict_add_tv(retdict, S_LEN("quickfixtextfunc"), &tv); tv_clear(&tv); } else { - status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), ""); + status = tv_dict_add_str_len(retdict, S_LEN("quickfixtextfunc"), "", 0); } return status; diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 882295a7c1..49f56795a1 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -916,7 +916,11 @@ static dict_T *sign_get_info_dict(sign_T *sp) for (int i = 0; i < 4; i++) { if (hl[i] > 0) { const char *p = get_highlight_name_ext(NULL, hl[i] - 1, false); - tv_dict_add_str(d, arg[i], strlen(arg[i]), p ? p : "NONE"); + if (p == NULL) { + tv_dict_add_str_len(d, arg[i], strlen(arg[i]), S_LEN("NONE")); + } else { + tv_dict_add_str(d, arg[i], strlen(arg[i]), p); + } } } return d; |
