From 7224c889e0d5d70b99ae377036baa6377c33a568 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:25:24 +0100 Subject: build: enable MSVC level 3 warnings (#21934) MSVC has 4 different warning levels: 1 (severe), 2 (significant), 3 (production quality) and 4 (informational). Enabling level 3 warnings mostly revealed conversion problems, similar to GCC/clang -Wconversion flag. --- src/nvim/eval/funcs.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 48f3cd4293..884a50a433 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -492,7 +492,7 @@ buf_T *get_buf_arg(typval_T *arg) /// "byte2line(byte)" function static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - long boff = tv_get_number(&argvars[0]) - 1; + long boff = (long)tv_get_number(&argvars[0]) - 1; if (boff < 0) { rettv->vval.v_number = -1; } else { @@ -978,11 +978,11 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) listitem_T *li = tv_list_first(l); if (argvars[2].v_type != VAR_UNKNOWN) { if (argvars[3].v_type != VAR_UNKNOWN) { - long idx = tv_get_number_chk(&argvars[3], &error); + int64_t idx = tv_get_number_chk(&argvars[3], &error); if (!error) { li = tv_list_find(l, (int)idx); if (li == NULL) { - semsg(_(e_listidx), (int64_t)idx); + semsg(_(e_listidx), idx); } } } @@ -3589,7 +3589,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_listblobarg), "insert()"); } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), N_("insert() argument"), TV_TRANSLATE)) { - long before = 0; + int64_t before = 0; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); } @@ -3602,7 +3602,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (before != tv_list_len(l)) { item = tv_list_find(l, (int)before); if (item == NULL) { - semsg(_(e_listidx), (int64_t)before); + semsg(_(e_listidx), before); l = NULL; } } @@ -4371,11 +4371,11 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, const SomeMatchType type) { char *str = NULL; - long len = 0; + int64_t len = 0; char *expr = NULL; regmatch_T regmatch; - long start = 0; - long nth = 1; + int64_t start = 0; + int64_t nth = 1; colnr_T startcol = 0; bool match = false; list_T *l = NULL; @@ -5387,7 +5387,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl char *prev = NULL; // previously read bytes, if any ptrdiff_t prevlen = 0; // length of data in prev ptrdiff_t prevsize = 0; // size of prev buffer - long maxline = MAXLNUM; + int64_t maxline = MAXLNUM; if (argvars[1].v_type != VAR_UNKNOWN) { if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { @@ -6161,8 +6161,8 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) { bool save_p_ws = p_ws; int retval = 0; // default: FAIL - long lnum_stop = 0; - long time_limit = 0; + linenr_T lnum_stop = 0; + int64_t time_limit = 0; int options = SEARCH_KEEP; bool use_skip = false; @@ -6184,7 +6184,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) // Optional arguments: line number to stop searching, timeout and skip. if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { - lnum_stop = tv_get_number_chk(&argvars[2], NULL); + lnum_stop = (linenr_T)tv_get_number_chk(&argvars[2], NULL); if (lnum_stop < 0) { goto theend; } @@ -6214,7 +6214,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) pos_T pos = save_cursor = curwin->w_cursor; pos_T firstpos = { 0 }; searchit_arg_T sia = { - .sa_stop_lnum = (linenr_T)lnum_stop, + .sa_stop_lnum = lnum_stop, .sa_tm = &tm, }; @@ -6652,8 +6652,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) bool save_p_ws = p_ws; int flags = 0; int retval = 0; // default: FAIL - long lnum_stop = 0; - long time_limit = 0; + linenr_T lnum_stop = 0; + int64_t time_limit = 0; // Get the three pattern arguments: start, middle, end. Will result in an // error if not a valid argument. @@ -6695,7 +6695,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) skip = &argvars[4]; if (argvars[5].v_type != VAR_UNKNOWN) { - lnum_stop = tv_get_number_chk(&argvars[5], NULL); + lnum_stop = (linenr_T)tv_get_number_chk(&argvars[5], NULL); if (lnum_stop < 0) { semsg(_(e_invarg2), tv_get_string(&argvars[5])); goto theend; @@ -6711,7 +6711,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) } retval = (int)do_searchpair(spat, mpat, epat, dir, skip, - flags, match_pos, (linenr_T)lnum_stop, time_limit); + flags, match_pos, lnum_stop, time_limit); theend: p_ws = save_p_ws; @@ -6758,7 +6758,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, EvalFuncData fpt /// @returns 0 or -1 for no match, long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, const typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, - long time_limit) + int64_t time_limit) FUNC_ATTR_NONNULL_ARG(1, 2, 3) { long retval = 0; @@ -8695,7 +8695,8 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!callback_from_typval(&callback, &argvars[1])) { return; } - rettv->vval.v_number = (varnumber_T)timer_start(tv_get_number(&argvars[0]), repeat, &callback); + rettv->vval.v_number = (varnumber_T)timer_start((const long)tv_get_number(&argvars[0]), repeat, + &callback); } /// "timer_stop(timerid)" function -- cgit From 4be6c6cf0ddf5e31d4103cb5df06651ba6f4897b Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:05:57 +0100 Subject: refactor: replace char_u with char (#21901) refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 884a50a433..6f983d3208 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8769,7 +8769,7 @@ static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tolen = utfc_ptr2len(p); if (idx-- == 0) { cplen = tolen; - cpstr = (char *)p; + cpstr = p; break; } } -- cgit From 904d0995837a2569ae640f5253da3dd4569fec6f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 24 Feb 2023 15:03:28 +0800 Subject: vim-patch:8.2.2449: Vim9: flatten() always changes the list type Problem: Vim9: flatten() always changes the list type. Solution: Disallow using flatten() and add flattennew(). https://github.com/vim/vim/commit/3b690069730805a147d45d92eaca4dc838272d1d Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6f983d3208..3a58b90f96 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1870,8 +1870,8 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_string = cmdstr; } -/// "flatten(list[, {maxdepth}])" function -static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +/// "flatten()" and "flattennew()" functions +static void flatten_common(typval_T *argvars, typval_T *rettv, bool make_copy) { bool error = false; @@ -1895,13 +1895,38 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } list_T *list = argvars[0].vval.v_list; - if (list != NULL - && !value_check_lock(tv_list_locked(list), - N_("flatten() argument"), - TV_TRANSLATE) - && tv_list_flatten(list, maxdepth) == OK) { - tv_copy(&argvars[0], rettv); + rettv->v_type = VAR_LIST; + rettv->vval.v_list = list; + if (list == NULL) { + return; } + + if (make_copy) { + list = tv_list_copy(NULL, list, true, get_copyID()); + rettv->vval.v_list = list; + if (list == NULL) { + return; + } + } else { + if (value_check_lock(tv_list_locked(list), N_("flatten() argument"), TV_TRANSLATE)) { + return; + } + tv_list_ref(list); + } + + tv_list_flatten(list, maxdepth); +} + +/// "flatten(list[, {maxdepth}])" function +static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + flatten_common(argvars, rettv, false); +} + +/// "flattennew(list[, {maxdepth}])" function +static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + flatten_common(argvars, rettv, true); } /// "extend(list, list [, idx])" function -- cgit From d9263688bf0282918f5a9801dae8b85e4c85bd7e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 24 Feb 2023 15:24:38 +0800 Subject: vim-patch:8.2.4627: flatten() does not use maxdepth correctly Problem: flatten() does not use maxdepth correctly. Solution: Use a recursive implementation. (closes vim/vim#10020) https://github.com/vim/vim/commit/acf7d73a7f5cdd63b34de777a4ce5eb3e2ba0ab3 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3a58b90f96..6ac94706c7 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1914,7 +1914,7 @@ static void flatten_common(typval_T *argvars, typval_T *rettv, bool make_copy) tv_list_ref(list); } - tv_list_flatten(list, maxdepth); + tv_list_flatten(list, NULL, tv_list_len(list), maxdepth); } /// "flatten(list[, {maxdepth}])" function -- cgit From ec2557236710f3e062164e7ff4b137b2a0d8dfa4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 24 Feb 2023 15:31:43 +0800 Subject: vim-patch:8.2.4629: flattennew() makes a deep copy unnecessarily Problem: flattennew() makes a deep copy unnecessarily. Solution: Use a shallow copy. (issue vim/vim#10012) https://github.com/vim/vim/commit/c6c1ec4da53db9d292fa3dd081c20123f8261178 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6ac94706c7..f1852f1b6d 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1902,7 +1902,7 @@ static void flatten_common(typval_T *argvars, typval_T *rettv, bool make_copy) } if (make_copy) { - list = tv_list_copy(NULL, list, true, get_copyID()); + list = tv_list_copy(NULL, list, false, get_copyID()); rettv->vval.v_list = list; if (list == NULL) { return; -- cgit From 0972d7a12468d6914a70e453af85c307b167c55b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Feb 2023 23:13:12 +0800 Subject: vim-patch:9.0.0196: finding value in list may require a for loop Problem: Finding value in list may require a for loop. Solution: Add indexof(). (Yegappan Lakshmanan, closes vim/vim#10903) https://github.com/vim/vim/commit/b218655d5a485f5b193fb18d7240837d42b89812 Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f1852f1b6d..980a9fffa3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3488,6 +3488,115 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +/// Evaluate "expr" with the v:key and v:val arguments and return the result. +/// The expression is expected to return a boolean value. The caller should set +/// the VV_KEY and VV_VAL vim variables before calling this function. +static varnumber_T indexof_eval_expr(typval_T *expr) +{ + typval_T argv[3]; + argv[0] = *get_vim_var_tv(VV_KEY); + argv[1] = *get_vim_var_tv(VV_VAL); + typval_T newtv; + newtv.v_type = VAR_UNKNOWN; + + if (eval_expr_typval(expr, argv, 2, &newtv) == FAIL) { + return false; + } + + bool error = false; + varnumber_T found = tv_get_bool_chk(&newtv, &error); + + return error ? false : found; +} + +/// "indexof()" function +static void f_indexof(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = -1; + + if (tv_check_for_list_or_blob_arg(argvars, 0) == FAIL + || tv_check_for_string_or_func_arg(argvars, 1) == FAIL + || tv_check_for_opt_dict_arg(argvars, 2) == FAIL) { + return; + } + + if ((argvars[1].v_type == VAR_STRING && argvars[1].vval.v_string == NULL) + || (argvars[1].v_type == VAR_FUNC && argvars[1].vval.v_partial == NULL)) { + return; + } + + varnumber_T startidx = 0; + varnumber_T idx = 0; + if (argvars[2].v_type == VAR_DICT) { + startidx = tv_dict_get_number_def(argvars[2].vval.v_dict, "startidx", 0); + } + + typval_T save_val; + typval_T save_key; + prepare_vimvar(VV_VAL, &save_val); + prepare_vimvar(VV_KEY, &save_key); + + // We reset "did_emsg" to be able to detect whether an error occurred + // during evaluation of the expression. + const int save_did_emsg = did_emsg; + did_emsg = false; + + if (argvars[0].v_type == VAR_BLOB) { + blob_T *const b = argvars[0].vval.v_blob; + if (b == NULL) { + goto theend; + } + if (startidx < 0) { + startidx = tv_blob_len(b) + startidx; + if (startidx < 0) { + startidx = 0; + } + } + + for (idx = startidx; idx < tv_blob_len(b); idx++) { + set_vim_var_nr(VV_KEY, idx); + set_vim_var_nr(VV_VAL, tv_blob_get(b, (int)idx)); + + if (indexof_eval_expr(&argvars[1])) { + rettv->vval.v_number = idx; + break; + } + } + } else { + list_T *const l = argvars[0].vval.v_list; + if (l == NULL) { + goto theend; + } + + listitem_T *item; + if (startidx == 0) { + item = tv_list_first(l); + } else { + // Start at specified item. Use the cached index that list_find() + // sets, so that a negative number also works. + item = tv_list_find(l, (int)startidx); + if (item != NULL) { + idx = l->lv_idx; + } + } + + for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { + set_vim_var_nr(VV_KEY, idx); + tv_copy(TV_LIST_ITEM_TV(item), get_vim_var_tv(VV_VAL)); + + if (indexof_eval_expr(&argvars[1])) { + rettv->vval.v_number = idx; + break; + } + } + } + +theend: + restore_vimvar(VV_KEY, &save_key); + restore_vimvar(VV_VAL, &save_val); + did_emsg |= save_did_emsg; +} + static bool inputsecret_flag = false; /// "input()" function -- cgit From 13da3d469ae10201de00ae89277c53c40342f4df Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Feb 2023 23:50:35 +0800 Subject: vim-patch:partial:9.0.0202: code and help for indexof() is not ideal Problem: Code and help for indexof() is not ideal. Solution: Refactor the code, improve the help. (Yegappan Lakshmanan, closes vim/vim#10908) https://github.com/vim/vim/commit/3fbf6cd355de2212e9227f57d545592aae3f688f Skip CHECK_LIST_MATERIALIZE and set_vim_var_type(). Use tv_list_uidx() instead of lv_idx. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 115 +++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 48 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 980a9fffa3..8070dacc48 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3509,6 +3509,71 @@ static varnumber_T indexof_eval_expr(typval_T *expr) return error ? false : found; } +/// Evaluate "expr" for each byte in the Blob "b" starting with the byte at +/// "startidx" and return the index of the byte where "expr" is TRUE. Returns +/// -1 if "expr" doesn't evaluate to TRUE for any of the bytes. +static varnumber_T indexof_blob(blob_T *b, varnumber_T startidx, typval_T *expr) +{ + if (b == NULL) { + return -1; + } + + if (startidx < 0) { + // negative index: index from the last byte + startidx = tv_blob_len(b) + startidx; + if (startidx < 0) { + startidx = 0; + } + } + + for (varnumber_T idx = startidx; idx < tv_blob_len(b); idx++) { + set_vim_var_nr(VV_KEY, idx); + set_vim_var_nr(VV_VAL, tv_blob_get(b, (int)idx)); + + if (indexof_eval_expr(expr)) { + return idx; + } + } + + return -1; +} + +/// Evaluate "expr" for each item in the List "l" starting with the item at +/// "startidx" and return the index of the item where "expr" is TRUE. Returns +/// -1 if "expr" doesn't evaluate to TRUE for any of the items. +static varnumber_T indexof_list(list_T *l, varnumber_T startidx, typval_T *expr) +{ + if (l == NULL) { + return -1; + } + + listitem_T *item; + varnumber_T idx = 0; + if (startidx == 0) { + item = tv_list_first(l); + } else { + // Start at specified item. + idx = tv_list_uidx(l, (int)startidx); + if (idx == -1) { + item = NULL; + } else { + item = tv_list_find(l, (int)idx); + assert(item != NULL); + } + } + + for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { + set_vim_var_nr(VV_KEY, idx); + tv_copy(TV_LIST_ITEM_TV(item), get_vim_var_tv(VV_VAL)); + + if (indexof_eval_expr(expr)) { + return idx; + } + } + + return -1; +} + /// "indexof()" function static void f_indexof(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -3526,7 +3591,6 @@ static void f_indexof(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } varnumber_T startidx = 0; - varnumber_T idx = 0; if (argvars[2].v_type == VAR_DICT) { startidx = tv_dict_get_number_def(argvars[2].vval.v_dict, "startidx", 0); } @@ -3542,56 +3606,11 @@ static void f_indexof(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) did_emsg = false; if (argvars[0].v_type == VAR_BLOB) { - blob_T *const b = argvars[0].vval.v_blob; - if (b == NULL) { - goto theend; - } - if (startidx < 0) { - startidx = tv_blob_len(b) + startidx; - if (startidx < 0) { - startidx = 0; - } - } - - for (idx = startidx; idx < tv_blob_len(b); idx++) { - set_vim_var_nr(VV_KEY, idx); - set_vim_var_nr(VV_VAL, tv_blob_get(b, (int)idx)); - - if (indexof_eval_expr(&argvars[1])) { - rettv->vval.v_number = idx; - break; - } - } + rettv->vval.v_number = indexof_blob(argvars[0].vval.v_blob, startidx, &argvars[1]); } else { - list_T *const l = argvars[0].vval.v_list; - if (l == NULL) { - goto theend; - } - - listitem_T *item; - if (startidx == 0) { - item = tv_list_first(l); - } else { - // Start at specified item. Use the cached index that list_find() - // sets, so that a negative number also works. - item = tv_list_find(l, (int)startidx); - if (item != NULL) { - idx = l->lv_idx; - } - } - - for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { - set_vim_var_nr(VV_KEY, idx); - tv_copy(TV_LIST_ITEM_TV(item), get_vim_var_tv(VV_VAL)); - - if (indexof_eval_expr(&argvars[1])) { - rettv->vval.v_number = idx; - break; - } - } + rettv->vval.v_number = indexof_list(argvars[0].vval.v_list, startidx, &argvars[1]); } -theend: restore_vimvar(VV_KEY, &save_key); restore_vimvar(VV_VAL, &save_val); did_emsg |= save_did_emsg; -- cgit From 1f8cef53deb4b91a7249affca77bfb89ce0949b4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Feb 2023 00:00:01 +0800 Subject: vim-patch:9.0.0204: indexof() may leak memory Problem: indexof() may leak memory. Solution: Free allocated values. (Yegappan Lakshmanan, closes vim/vim#10916) https://github.com/vim/vim/commit/63acae13f57c5ad4c8ec3146d0c458550b9e984e Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8070dacc48..13d8f52768 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3505,6 +3505,7 @@ static varnumber_T indexof_eval_expr(typval_T *expr) bool error = false; varnumber_T found = tv_get_bool_chk(&newtv, &error); + tv_clear(&newtv); return error ? false : found; } @@ -3566,7 +3567,10 @@ static varnumber_T indexof_list(list_T *l, varnumber_T startidx, typval_T *expr) set_vim_var_nr(VV_KEY, idx); tv_copy(TV_LIST_ITEM_TV(item), get_vim_var_tv(VV_VAL)); - if (indexof_eval_expr(expr)) { + bool found = indexof_eval_expr(expr); + tv_clear(get_vim_var_tv(VV_VAL)); + + if (found) { return idx; } } -- cgit From 2c9fbe34b20266ef5ab54f6ed14fb38eef60430d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Feb 2023 10:10:42 +0800 Subject: vim-patch:8.2.2336: Vim9: not possible to extend dictionary with different type (#22425) Problem: Vim9: it is not possible to extend a dictionary with different item types. Solution: Add extendnew(). (closes vim/vim#7666) https://github.com/vim/vim/commit/b0e6b513648db7035046613431a4aa9d71ef4653 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 70 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 14 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 13d8f52768..1baf96e281 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1929,18 +1929,22 @@ static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) flatten_common(argvars, rettv, true); } -/// "extend(list, list [, idx])" function -/// "extend(dict, dict [, action])" function -static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +/// "extend()" or "extendnew()" function. "is_new" is true for extendnew(). +static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new) { - const char *const arg_errmsg = N_("extend() argument"); - if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) { bool error = false; - list_T *const l1 = argvars[0].vval.v_list; + list_T *l1 = argvars[0].vval.v_list; list_T *const l2 = argvars[1].vval.v_list; - if (!value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { + if (is_new || !value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { + if (is_new) { + l1 = tv_list_copy(NULL, l1, false, get_copyID()); + if (l1 == NULL) { + return; + } + } + listitem_T *item; if (argvars[2].v_type != VAR_UNKNOWN) { long before = (long)tv_get_number_chk(&argvars[2], &error); @@ -1962,11 +1966,18 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } tv_list_extend(l1, l2, item); - tv_copy(&argvars[0], rettv); + if (is_new) { + *rettv = (typval_T){ + .v_type = VAR_LIST, + .v_lock = VAR_UNLOCKED, + .vval.v_list = l1, + }; + } else { + tv_copy(&argvars[0], rettv); + } } - } else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == - VAR_DICT) { - dict_T *const d1 = argvars[0].vval.v_dict; + } else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) { + dict_T *d1 = argvars[0].vval.v_dict; dict_T *const d2 = argvars[1].vval.v_dict; if (d1 == NULL) { const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); @@ -1975,7 +1986,14 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else if (d2 == NULL) { // Do nothing tv_copy(&argvars[0], rettv); - } else if (!value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { + } else if (is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { + if (is_new) { + d1 = tv_dict_copy(NULL, d1, false, get_copyID()); + if (d1 == NULL) { + return; + } + } + const char *action = "force"; // Check the third argument. if (argvars[2].v_type != VAR_UNKNOWN) { @@ -1999,13 +2017,37 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_dict_extend(d1, d2, action); - tv_copy(&argvars[0], rettv); + if (is_new) { + *rettv = (typval_T){ + .v_type = VAR_DICT, + .v_lock = VAR_UNLOCKED, + .vval.v_dict = d1, + }; + } else { + tv_copy(&argvars[0], rettv); + } } } else { - semsg(_(e_listdictarg), "extend()"); + semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()"); } } +/// "extend(list, list [, idx])" function +/// "extend(dict, dict [, action])" function +static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + char *errmsg = N_("extend() argument"); + extend(argvars, rettv, errmsg, false); +} + +/// "extendnew(list, list [, idx])" function +/// "extendnew(dict, dict [, action])" function +static void f_extendnew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + char *errmsg = N_("extendnew() argument"); + extend(argvars, rettv, errmsg, true); +} + /// "feedkeys()" function static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { -- cgit From ce597235a26839826de88ecd8b949ec54c310fbd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Feb 2023 16:31:05 +0100 Subject: feat(ui): restore has('gui_running') Problem: has('gui_running') is still common in the wild and our answer has changed over time, causing frustration. https://github.com/vimpostor/vim-tpipeline/commit/95a6ccbe9f33bc42dd4cee45731d8bc3fbcd92d1 Solution: Use stdin_tty/stdout_tty to decide if a UI is (not) a GUI. --- src/nvim/eval/funcs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1baf96e281..d97f7b6d35 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3228,7 +3228,9 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (!n) { - if (STRNICMP(name, "patch", 5) == 0) { + if (STRNICMP(name, "gui_running", 11) == 0) { + n = ui_gui_attached(); + } else if (STRNICMP(name, "patch", 5) == 0) { if (name[5] == '-' && strlen(name) >= 11 && ascii_isdigit(name[6]) -- cgit From 88b70e7d4650795210222a598cbb233bf7fc98f8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Feb 2023 15:50:35 +0800 Subject: vim-patch:8.2.2782: Vim9: blob operations not fully tested Problem: Vim9: blob operations not fully tested. Solution: Make more blob tests run in Vim9 script. Fix filter(). Make insert() give an error for a null blob, like add(). https://github.com/vim/vim/commit/39211cba723a2cb58a97c7e08826713164b86efc vim-patch:8.2.3284: no error for insert() or remove() changing a locked blob Problem: No error for insert() or remove() changing a locked blob. Solution: Check a blob is not locked before changing it. (Sean Dewar, closes vim/vim#8696) https://github.com/vim/vim/commit/80d7395dcfe96158428da6bb3d28a6eee1244e28 Co-authored-by: Bram Moolenaar Co-authored-by: Sean Dewar --- src/nvim/eval/funcs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1baf96e281..20e590a30c 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3743,7 +3743,6 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "insert()" function static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - list_T *l; bool error = false; if (argvars[0].v_type == VAR_BLOB) { @@ -3786,8 +3785,12 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_copy(&argvars[0], rettv); } else if (argvars[0].v_type != VAR_LIST) { semsg(_(e_listblobarg), "insert()"); - } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), - N_("insert() argument"), TV_TRANSLATE)) { + } else { + list_T *l = argvars[0].vval.v_list; + if (value_check_lock(tv_list_locked(l), N_("insert() argument"), TV_TRANSLATE)) { + return; + } + int64_t before = 0; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); -- cgit From bfa0bc7df0ca527fcec49dbd2055f1bac438663e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Feb 2023 19:04:32 +0800 Subject: vim-patch:9.0.0795: readblob() always reads the whole file Problem: readblob() always reads the whole file. Solution: Add arguments to read part of the file. (Ken Takata, closes vim/vim#11402) https://github.com/vim/vim/commit/11df3aeee548b959ccd4b9a4d3c44651eab6b3ce Remove trailing whitespace in test as done in patch 9.0.1257. Move the help for rand() before range(). Co-authored-by: K.Takata --- src/nvim/eval/funcs.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d3bac14754..5da6233e38 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5592,15 +5592,24 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl ptrdiff_t prevlen = 0; // length of data in prev ptrdiff_t prevsize = 0; // size of prev buffer int64_t maxline = MAXLNUM; + off_T offset = 0; + off_T size = -1; if (argvars[1].v_type != VAR_UNKNOWN) { - if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { - binary = true; - } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) { - blob = true; - } - if (argvars[2].v_type != VAR_UNKNOWN) { - maxline = tv_get_number(&argvars[2]); + if (always_blob) { + offset = (off_T)tv_get_number(&argvars[1]); + if (argvars[2].v_type != VAR_UNKNOWN) { + size = (off_T)tv_get_number(&argvars[2]); + } + } else { + if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { + binary = true; + } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) { + blob = true; + } + if (argvars[2].v_type != VAR_UNKNOWN) { + maxline = tv_get_number(&argvars[2]); + } } } @@ -5619,11 +5628,8 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl if (blob) { tv_blob_alloc_ret(rettv); - if (!read_blob(fd, rettv->vval.v_blob)) { + if (read_blob(fd, rettv, offset, size) == FAIL) { semsg(_(e_notread), fname); - // An empty blob is returned on error. - tv_blob_free(rettv->vval.v_blob); - rettv->vval.v_blob = NULL; } fclose(fd); return; -- cgit From 278aeee3aed753d1084597378e653395bd472c42 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Feb 2023 21:07:56 +0800 Subject: vim-patch:9.0.0430: cannot use repeat() with a blob Problem: Cannot use repeat() with a blob. Solution: Implement blob repeat. (closes vim/vim#11090) https://github.com/vim/vim/commit/375141e1f80dced9be738568a3418f65813f4a2f Co-authored-by: Bakudankun --- src/nvim/eval/funcs.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5da6233e38..4208c5ca46 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5976,6 +5976,37 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) while (n-- > 0) { tv_list_extend(rettv->vval.v_list, argvars[0].vval.v_list, NULL); } + } else if (argvars[0].v_type == VAR_BLOB) { + tv_blob_alloc_ret(rettv); + if (argvars[0].vval.v_blob == NULL || n <= 0) { + return; + } + + const int slen = argvars[0].vval.v_blob->bv_ga.ga_len; + const int len = (int)(slen * n); + if (len <= 0) { + return; + } + + ga_grow(&rettv->vval.v_blob->bv_ga, len); + + rettv->vval.v_blob->bv_ga.ga_len = len; + + int i; + for (i = 0; i < slen; i++) { + if (tv_blob_get(argvars[0].vval.v_blob, i) != 0) { + break; + } + } + + if (i == slen) { + // No need to copy since all bytes are already zero + return; + } + + for (i = 0; i < n; i++) { + tv_blob_set_range(rettv->vval.v_blob, i * slen, (i + 1) * slen - 1, argvars); + } } else { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; -- cgit From 419819b6245e120aba8897e3ddea711b2cd0246c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 5 Mar 2023 09:18:42 +0800 Subject: vim-patch:9.0.1380: CTRL-X on 2**64 subtracts two (#22530) Problem: CTRL-X on 2**64 subtracts two. (James McCoy) Solution: Correct computation for large number. (closes vim/vim#12103) https://github.com/vim/vim/commit/5fb78c3fa5c996c08a65431d698bd2c251eef5c7 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4208c5ca46..3a7da21606 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8033,7 +8033,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) break; } varnumber_T n; - vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false); + vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false, NULL); // Text after the number is silently ignored. if (isneg) { rettv->vval.v_number = -n; -- cgit From 063e93864a7e99ac1c4781bbe4ea63c0adb075a8 Mon Sep 17 00:00:00 2001 From: Lucas Merritt Date: Fri, 24 Mar 2023 22:11:14 -0600 Subject: refactor(PVS/V1048): remove duplicated assignments (#21873) --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3a7da21606..df8004dc73 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7581,7 +7581,7 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // third argument: action - 'a' for append and 'r' for replace. // default is to replace the stack. if (argvars[2].v_type == VAR_UNKNOWN) { - action = 'r'; + // action = 'r'; } else if (argvars[2].v_type == VAR_STRING) { const char *actstr; actstr = tv_get_string_chk(&argvars[2]); -- cgit From d5f6176e6dc4b4e12fc5061ca6e87f4af533e46a Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Sat, 1 Apr 2023 02:49:51 +0200 Subject: refactor: add const and remove unnecessary casts (#22841) --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index df8004dc73..25d383d8ea 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4670,7 +4670,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, } } - regmatch.regprog = vim_regcomp((char *)pat, RE_MAGIC + RE_STRING); + regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { regmatch.rm_ic = p_ic; @@ -7895,7 +7895,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } regmatch_T regmatch = { - .regprog = vim_regcomp((char *)pat, RE_MAGIC + RE_STRING), + .regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING), .startp = { NULL }, .endp = { NULL }, .rm_ic = false, @@ -7906,7 +7906,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (*str == NUL) { match = false; // Empty item at the end. } else { - match = vim_regexec_nl(®match, (char *)str, col); + match = vim_regexec_nl(®match, str, col); } const char *end; if (match) { -- cgit From d510bfbc8e447b1a60d5ec7faaa8f440eb4ef56f Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 2 Apr 2023 10:11:42 +0200 Subject: refactor: remove char_u (#22829) Closes https://github.com/neovim/neovim/issues/459 --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 25d383d8ea..4286e16eb1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6197,7 +6197,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } # else char *v = os_realpath(fname, NULL); - rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v); + rettv->vval.v_string = v == NULL ? xstrdup(fname) : v; # endif #endif -- cgit From 371823d407d7d7519735131bcad4670c62a731a7 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:13:53 +0200 Subject: refactor: make error message definitions const message.c functions now take const char * as a format. Error message definitions can be made const. --- src/nvim/eval/funcs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4286e16eb1..4225e164e4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -145,10 +145,10 @@ PRAGMA_DIAG_POP PRAGMA_DIAG_POP #endif -static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); -static char *e_invalwindow = N_("E957: Invalid window number"); -static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); -static char e_using_number_as_bool_nr[] +static const char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); +static const char *e_invalwindow = N_("E957: Invalid window number"); +static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); +static const char e_using_number_as_bool_nr[] = N_("E1023: Using a Number as a Bool: %d"); /// Dummy va_list for passing to vim_snprintf @@ -7557,7 +7557,7 @@ free_lstval: /// "settagstack()" function static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - static char *e_invact2 = N_("E962: Invalid action: '%s'"); + static const char *e_invact2 = N_("E962: Invalid action: '%s'"); char action = 'r'; rettv->vval.v_number = -1; -- cgit From 7190dba017e3aac0409c73ff1c954d18858cb3c9 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:39:50 +0200 Subject: refactor: remove use of reserved c++ keywords libnvim couldn't be easily used in C++ due to the use of reserved keywords. Additionally, add explicit casts to *alloc function calls used in inline functions, as C++ doesn't allow implicit casts from void pointers. --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4225e164e4..03df0661c5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3996,7 +3996,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en if (!clear_env) { typval_T temp_env = TV_INITIAL_VALUE; - f_environ(NULL, &temp_env, (EvalFuncData){ .nullptr = NULL }); + f_environ(NULL, &temp_env, (EvalFuncData){ .null = NULL }); tv_dict_extend(env, temp_env.vval.v_dict, "force"); tv_dict_free(temp_env.vval.v_dict); -- cgit From 9408f2dcf7cade2631688300e9b58eed6bc5219a Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:40:57 +0200 Subject: refactor: remove redundant const char * casts --- src/nvim/eval/funcs.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 03df0661c5..b7425b1ef3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -319,7 +319,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err); if (ERROR_SET(&err)) { - semsg_multiline((const char *)e_api_error, err.msg); + semsg_multiline(e_api_error, err.msg); goto end; } @@ -1546,7 +1546,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *s = tv_get_string_chk(&argvars[0]); if (s != NULL) { - s = (const char *)skipwhite(s); + s = skipwhite(s); } const char *const expr_start = s; @@ -1779,7 +1779,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (rettv->v_type == VAR_LIST) { tv_list_alloc_ret(rettv, (result != NULL)); if (result != NULL) { - tv_list_append_string(rettv->vval.v_list, (const char *)result, -1); + tv_list_append_string(rettv->vval.v_list, result, -1); } XFREE_CLEAR(result); } else { @@ -1805,8 +1805,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ExpandOne(&xpc, (char *)s, NULL, options, WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { - tv_list_append_string(rettv->vval.v_list, - (const char *)xpc.xp_files[i], -1); + tv_list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); } ExpandCleanup(&xpc); } @@ -2134,7 +2133,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) first = false; if (fresult != NULL && rettv->v_type == VAR_LIST) { - tv_list_append_string(rettv->vval.v_list, (const char *)fresult, -1); + tv_list_append_string(rettv->vval.v_list, fresult, -1); } } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); } @@ -3008,8 +3007,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { - tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i], - -1); + tv_list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); } ExpandCleanup(&xpc); } @@ -4050,7 +4048,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en #ifdef MSWIN TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { // Always use upper-case keys for Windows so we detect duplicate keys - char *const key = strcase_save((const char *)var->di_key, true); + char *const key = strcase_save(var->di_key, true); size_t len = strlen(key); dictitem_T *dv = tv_dict_find(env, key, len); if (dv) { @@ -4735,8 +4733,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (regmatch.endp[i] == NULL) { tv_list_append_string(rettv->vval.v_list, NULL, 0); } else { - tv_list_append_string(rettv->vval.v_list, - (const char *)regmatch.startp[i], + tv_list_append_string(rettv->vval.v_list, regmatch.startp[i], (regmatch.endp[i] - regmatch.startp[i])); } } @@ -4746,7 +4743,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (l != NULL) { tv_copy(TV_LIST_ITEM_TV(li), rettv); } else { - rettv->vval.v_string = xmemdupz((const char *)regmatch.startp[0], + rettv->vval.v_string = xmemdupz(regmatch.startp[0], (size_t)(regmatch.endp[0] - regmatch.startp[0])); } @@ -7910,14 +7907,14 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } const char *end; if (match) { - end = (const char *)regmatch.startp[0]; + end = regmatch.startp[0]; } else { end = str + strlen(str); } if (keepempty || end > str || (tv_list_len(rettv->vval.v_list) > 0 && *str != NUL && match - && end < (const char *)regmatch.endp[0])) { + && end < regmatch.endp[0])) { tv_list_append_string(rettv->vval.v_list, str, end - str); } if (!match) { @@ -7930,7 +7927,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // Don't get stuck at the same match. col = utfc_ptr2len(regmatch.endp[0]); } - str = (const char *)regmatch.endp[0]; + str = regmatch.endp[0]; } vim_regfree(regmatch.regprog); -- cgit From 04933b1ea968f958d2541dd65fd33ebb503caac3 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:08:16 +0200 Subject: refactor: remove redundant casts --- src/nvim/eval/funcs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b7425b1ef3..eaa66f6483 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -9093,14 +9093,14 @@ static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (dir == 0 || dir == 1) { // Trim leading characters while (*head != NUL) { - c1 = utf_ptr2char((char *)head); + c1 = utf_ptr2char(head); if (mask == NULL) { if (c1 > ' ' && c1 != 0xa0) { break; } } else { for (p = mask; *p != NUL; MB_PTR_ADV(p)) { - if (c1 == utf_ptr2char((char *)p)) { + if (c1 == utf_ptr2char(p)) { break; } } @@ -9118,14 +9118,14 @@ static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) for (; tail > head; tail = prev) { prev = tail; MB_PTR_BACK(head, prev); - c1 = utf_ptr2char((char *)prev); + c1 = utf_ptr2char(prev); if (mask == NULL) { if (c1 > ' ' && c1 != 0xa0) { break; } } else { for (p = mask; *p != NUL; MB_PTR_ADV(p)) { - if (c1 == utf_ptr2char((char *)p)) { + if (c1 == utf_ptr2char(p)) { break; } } -- cgit From 2d78e656b715119ca11d131a1a932f22f1b4ad36 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:43:00 +0200 Subject: refactor: remove redundant casts --- src/nvim/eval/funcs.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index eaa66f6483..7f224f371c 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -956,7 +956,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const size_t len = strlen(expr); while (*p != NUL) { - if (mb_strnicmp((char *)p, (char *)expr, len) == 0) { + if (mb_strnicmp(p, expr, len) == 0) { n++; p += len; } else { @@ -965,7 +965,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } else { char *next; - while ((next = strstr((char *)p, (char *)expr)) != NULL) { + while ((next = strstr(p, expr)) != NULL) { n++; p = next + strlen(expr); } @@ -1064,17 +1064,17 @@ static void f_ctxpush(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) TV_LIST_ITER(argvars[0].vval.v_list, li, { typval_T *tv_li = TV_LIST_ITEM_TV(li); if (tv_li->v_type == VAR_STRING) { - if (strequal((char *)tv_li->vval.v_string, "regs")) { + if (strequal(tv_li->vval.v_string, "regs")) { types |= kCtxRegs; - } else if (strequal((char *)tv_li->vval.v_string, "jumps")) { + } else if (strequal(tv_li->vval.v_string, "jumps")) { types |= kCtxJumps; - } else if (strequal((char *)tv_li->vval.v_string, "bufs")) { + } else if (strequal(tv_li->vval.v_string, "bufs")) { types |= kCtxBufs; - } else if (strequal((char *)tv_li->vval.v_string, "gvars")) { + } else if (strequal(tv_li->vval.v_string, "gvars")) { types |= kCtxGVars; - } else if (strequal((char *)tv_li->vval.v_string, "sfuncs")) { + } else if (strequal(tv_li->vval.v_string, "sfuncs")) { types |= kCtxSFuncs; - } else if (strequal((char *)tv_li->vval.v_string, "funcs")) { + } else if (strequal(tv_li->vval.v_string, "funcs")) { types |= kCtxFuncs; } } @@ -4953,7 +4953,7 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN]; int idx = 0; TV_LIST_ITER(list, li, { - vim_snprintf(msgbuf, sizeof(msgbuf), (char *)msg, idx); + vim_snprintf(msgbuf, sizeof(msgbuf), msg, idx); idx++; if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) { break; @@ -6282,7 +6282,7 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) argv[0] = *rettv; argv[1] = *TV_LIST_ITEM_TV(li); rettv->v_type = VAR_UNKNOWN; - const int r = call_func((char *)func_name, -1, rettv, 2, argv, &funcexe); + const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); tv_clear(&argv[0]); if (r == FAIL || called_emsg != called_emsg_start) { break; @@ -6315,7 +6315,7 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) argv[0] = *rettv; argv[1].v_type = VAR_NUMBER; argv[1].vval.v_number = tv_blob_get(b, i); - if (call_func((char *)func_name, -1, rettv, 2, argv, &funcexe) == FAIL) { + if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) { return; } } @@ -8584,7 +8584,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)(p == NULL ? p : xstrdup(p)); + rettv->vval.v_string = p == NULL ? NULL : xstrdup(p); } /// "synIDtrans(id)" function -- cgit From 8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:11:59 +0800 Subject: vim-patch:8.2.{0695,0725,0734,0753,0818,0819,0822} (#23075) vim-patch:8.2.0695: Vim9: cannot define a function inside a function Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def. https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c vim-patch:8.2.0725: Vim9: cannot call a function declared later in Vim9 script Problem: Vim9: cannot call a function declared later in Vim9 script. Solution: Make two passes through the script file. https://github.com/vim/vim/commit/09689a02840be40fa7bb10b1921fb5bc5b2908f1 vim-patch:8.2.0734: Vim9: leaking memory when using :finish Problem: Vim9: leaking memory when using :finish. Solution: Do not check for next line in third pass. https://github.com/vim/vim/commit/04816717dfea6e2469ff4c9d40f68b59aaf03724 vim-patch:8.2.0753: Vim9: expressions are evaluated in the discovery phase Problem: Vim9: expressions are evaluated in the discovery phase. Solution: Bail out if an expression is not a constant. Require a type for declared constants. https://github.com/vim/vim/commit/32e351179eacfc84f64cd5029e221582d400bb38 vim-patch:8.2.0818: Vim9: using a discovery phase doesn't work well Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier. https://github.com/vim/vim/commit/822ba24743af9ee1b5e7f656a7a61a38f3638bca vim-patch:8.2.0819: compiler warning for unused variable Problem: Compiler warning for unused variable. Solution: Remove the variable. https://github.com/vim/vim/commit/f40e51a880a95f94dbbbecc9476559506c2cc345 vim-patch:8.2.0822: Vim9: code left over from discovery phase Problem: Vim9: code left over from discovery phase. Solution: Remove the dead code. https://github.com/vim/vim/commit/2eec37926db6d31beb36f162ac00357a30c093c8 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7f224f371c..52e38b73ba 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1550,7 +1550,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } const char *const expr_start = s; - if (s == NULL || eval1((char **)&s, rettv, true) == FAIL) { + if (s == NULL || eval1((char **)&s, rettv, EVAL_EVALUATE) == FAIL) { if (expr_start != NULL && !aborting()) { semsg(_(e_invexpr2), expr_start); } -- cgit From bd83b587b18bb6f2ac555a992fa5b7d907de7e79 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:22:01 +0800 Subject: vim-patch:8.2.1047: Vim9: script cannot use line continuation like :def function Problem: Vim9: script cannot use line continuation like in a :def function. Solution: Pass the getline function pointer to the eval() functions. Use it for addition and multiplication operators. https://github.com/vim/vim/commit/5409f5d8c95007216ae1190565a7a8ee9ebd7100 Omit source_nextline() and eval_next_non_blank(): Vim9 script only. N/A patches for version.c: vim-patch:8.2.1048: build failure without the eval feature Problem: Build failure without the eval feature. Solution: Add dummy typedef. https://github.com/vim/vim/commit/9d40c63c7dc8c3eb3886c58dcd334bc7f37eceba vim-patch:8.2.1052: build failure with older compilers Problem: Build failure with older compilers. Solution: Move declaration to start of block. https://github.com/vim/vim/commit/7acde51832f383f9a6d2e740cd0420b433ea841a Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 52e38b73ba..887a4857f6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1550,7 +1550,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } const char *const expr_start = s; - if (s == NULL || eval1((char **)&s, rettv, EVAL_EVALUATE) == FAIL) { + if (s == NULL || eval1((char **)&s, rettv, &EVALARG_EVALUATE) == FAIL) { if (expr_start != NULL && !aborting()) { semsg(_(e_invexpr2), expr_start); } -- cgit From 90efe85a99c7986acccc8af370cfb179ae18aeff Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 19:28:39 +0800 Subject: vim-patch:8.2.1111: inconsistent naming of get_list_tv() and eval_dict() (#23086) Problem: Inconsistent naming of get_list_tv() and eval_dict(). Solution: Rename get_list_tv() to eval_list(). Similarly for eval_number(), eval_string(), eval_lit_string() and a few others. https://github.com/vim/vim/commit/9a78e6df17033223ebdf499f2b02b2538601c52d Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 887a4857f6..23d0242ce4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1722,7 +1722,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(exp); } } else if (*p == '&' || *p == '+') { // Option. - n = (get_option_tv(&p, NULL, true) == OK); + n = (eval_option(&p, NULL, true) == OK); if (*skipwhite(p) != NUL) { n = false; // Trailing garbage. } -- cgit From d13222649a2145272f14675d9bbf64bb72c43f64 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 08:58:37 +0800 Subject: vim-patch:8.2.1945: crash when passing NULL function to reduce() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Crash when passing NULL function to reduce(). Solution: Check for NULL pointer and give an error. (Dominique Pellé, closes vim/vim#7243) https://github.com/vim/vim/commit/0d90e728fe089ff1bb34d6a17f5591a96b57f734 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 23d0242ce4..f94725e1cc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -150,6 +150,8 @@ static const char *e_invalwindow = N_("E957: Invalid window number"); static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); static const char e_using_number_as_bool_nr[] = N_("E1023: Using a Number as a Bool: %d"); +static const char e_missing_function_argument[] + = N_("E1132: Missing function argument"); /// Dummy va_list for passing to vim_snprintf /// @@ -6244,8 +6246,9 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else { func_name = tv_get_string(&argvars[1]); } - if (*func_name == NUL) { - return; // type error or empty name + if (func_name == NULL || *func_name == NUL) { + emsg(_(e_missing_function_argument)); + return; } funcexe_T funcexe = FUNCEXE_INIT; -- cgit From 08121ef69f47f8ad8f8903a732920412e24d30c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 08:55:42 +0800 Subject: vim-patch:8.2.2848: crash whn calling partial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Crash whn calling partial. Solution: Check for NULL pointer. (Dominique Pellé, closes vim/vim#8202) https://github.com/vim/vim/commit/fe8ebdbe5c4e116311c0c0d5937b89ded5c92d01 Co-authored-by: Dominique Pelle --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f94725e1cc..99e511a7a4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -565,8 +565,8 @@ static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) func = (char *)tv_get_string(&argvars[0]); } - if (*func == NUL) { - return; // type error or empty name + if (func == NULL || *func == NUL) { + return; // type error, empty name or null function } dict_T *selfdict = NULL; @@ -1136,7 +1136,7 @@ static void f_ctxsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// Set the cursor position. -/// If 'charcol' is true, then use the column number as a character offset. +/// If "charcol" is true, then use the column number as a character offset. /// Otherwise use the column number as a byte offset. static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) { -- cgit From 0167649ce4071e60d985b65f3f9408ffb21cb58c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:07:48 +0800 Subject: vim-patch:9.0.0379: cleaning up after writefile() is a hassle Problem: Cleaning up after writefile() is a hassle. Solution: Add the 'D' flag to defer deleting the written file. Very useful in tests. https://github.com/vim/vim/commit/806a273f3c84ecd475913d901890bb1929be9a0a Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 99e511a7a4..66fd663e5e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -9296,6 +9296,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) bool binary = false; bool append = false; + bool defer = false; bool do_fsync = !!p_fs; bool mkdir_p = false; if (argvars[2].v_type != VAR_UNKNOWN) { @@ -9309,6 +9310,8 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) binary = true; break; case 'a': append = true; break; + case 'D': + defer = true; break; case 's': do_fsync = true; break; case 'S': @@ -9328,6 +9331,12 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (fname == NULL) { return; } + + if (defer && get_current_funccal() == NULL) { + semsg(_(e_str_not_inside_function), "defer"); + return; + } + FileDescriptor fp; int error; if (*fname == NUL) { @@ -9336,9 +9345,17 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ((append ? kFileAppend : kFileTruncate) | (mkdir_p ? kFileMkDir : kFileCreate) | kFileCreate), 0666)) != 0) { - semsg(_("E482: Can't open file %s for writing: %s"), - fname, os_strerror(error)); + semsg(_("E482: Can't open file %s for writing: %s"), fname, os_strerror(error)); } else { + if (defer) { + typval_T tv = { + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrdup(fname), + }; + add_defer("delete", 1, &tv); + } + bool write_ok; if (argvars[0].v_type == VAR_BLOB) { write_ok = write_blob(&fp, argvars[0].vval.v_blob); -- cgit From f39b33ee491a4a8d4b08425e582dd0dd53617edf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:46:17 +0800 Subject: vim-patch:9.0.0411: only created files can be cleaned up with one call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Only created files can be cleaned up with one call. Solution: Add flags to mkdir() to delete with a deferred function. Expand the writefile() name to a full path to handle changing directory. https://github.com/vim/vim/commit/6f14da15ac900589f2f413d77898b9bff3b31ece vim-patch:8.2.3742: dec mouse test fails without gnome terminfo entry Problem: Dec mouse test fails without gnome terminfo entry. Solution: Check if there is a gnome entry. Also fix 'acd' test on MS-Windows. (Dominique Pellé, closes vim/vim#9282) https://github.com/vim/vim/commit/f589fd3e1047cdf90566b68aaf9a13389e54d26a Cherry-pick test_autochdir.vim changes from patch 9.0.0313. Cherry-pick test_autocmd.vim changes from patch 9.0.0323. Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 66fd663e5e..f53b283c79 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4892,6 +4892,9 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) *path_tail_with_sep((char *)dir) = NUL; } + bool defer = false; + bool defer_recurse = false; + char *created = NULL; if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[2].v_type != VAR_UNKNOWN) { prot = (int)tv_get_number_chk(&argvars[2], NULL); @@ -4899,9 +4902,17 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } } - if (strcmp(tv_get_string(&argvars[1]), "p") == 0) { + const char *arg2 = tv_get_string(&argvars[1]); + defer = vim_strchr(arg2, 'D') != NULL; + defer_recurse = vim_strchr(arg2, 'R') != NULL; + if ((defer || defer_recurse) && !can_add_defer()) { + return; + } + + if (vim_strchr(arg2, 'p') != NULL) { char *failed_dir; - int ret = os_mkdir_recurse(dir, prot, &failed_dir); + int ret = os_mkdir_recurse(dir, prot, &failed_dir, + defer || defer_recurse ? &created : NULL); if (ret != 0) { semsg(_(e_mkdir), failed_dir, os_strerror(ret)); xfree(failed_dir); @@ -4909,10 +4920,27 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } rettv->vval.v_number = OK; - return; } } - rettv->vval.v_number = vim_mkdir_emsg(dir, prot); + if (rettv->vval.v_number == FAIL) { + rettv->vval.v_number = vim_mkdir_emsg(dir, prot); + } + + // Handle "D" and "R": deferred deletion of the created directory. + if (rettv->vval.v_number == OK + && created == NULL && (defer || defer_recurse)) { + created = FullName_save(dir, false); + } + if (created != NULL) { + typval_T tv[2]; + tv[0].v_type = VAR_STRING; + tv[0].v_lock = VAR_UNLOCKED; + tv[0].vval.v_string = created; + tv[1].v_type = VAR_STRING; + tv[1].v_lock = VAR_UNLOCKED; + tv[1].vval.v_string = xstrdup(defer_recurse ? "rf" : "d"); + add_defer("delete", 2, tv); + } } /// "mode()" function @@ -9332,8 +9360,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - if (defer && get_current_funccal() == NULL) { - semsg(_(e_str_not_inside_function), "defer"); + if (defer && !can_add_defer()) { return; } @@ -9351,7 +9378,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) typval_T tv = { .v_type = VAR_STRING, .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrdup(fname), + .vval.v_string = FullName_save(fname, false), }; add_defer("delete", 1, &tv); } -- cgit From 7a3f86481e96e5c30db5af74760e475bac8cc403 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 09:08:25 +0800 Subject: vim-patch:9.0.0419: the :defer command does not check the function arguments Problem: The :defer command does not check the function argument count and types. Solution: Check the function arguments when adding a deferred function. https://github.com/vim/vim/commit/169003289fb4b2ad18fd7f5807e0d05efff0be85 Cherry-pick check_internal_func() from Vim, but use EvalFuncDef pointer as first argument. Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f53b283c79..b064379210 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -228,6 +228,31 @@ const EvalFuncDef *find_internal_func(const char *const name) return index >= 0 ? &functions[index] : NULL; } +/// Check the argument count to use for internal function "fdef". +/// @return -1 for failure, 0 if no method base accepted, 1 if method base is +/// first argument, 2 if method base is second argument, etc. +int check_internal_func(const EvalFuncDef *const fdef, const int argcount) + FUNC_ATTR_NONNULL_ALL +{ + int res; + + if (argcount < fdef->min_argc) { + res = FCERR_TOOFEW; + } else if (argcount > fdef->max_argc) { + res = FCERR_TOOMANY; + } else { + return fdef->base_arg; + } + + const char *const name = fdef->name; + if (res == FCERR_TOOMANY) { + semsg(_(e_toomanyarg), name); + } else { + semsg(_(e_toofewarg), name); + } + return -1; +} + int call_internal_func(const char *const fname, const int argcount, typval_T *const argvars, typval_T *const rettv) FUNC_ATTR_NONNULL_ALL -- cgit From 9722b3b9f983a3401423c41f05dd559f6aa410cd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Apr 2023 14:38:53 +0800 Subject: vim-patch:9.0.1400: find_file_in_path() is not reentrant (#23146) Problem: find_file_in_path() is not reentrant. Solution: Instead of global variables pass pointers to the functions. (closes vim/vim#12093) https://github.com/vim/vim/commit/5145c9a829cd43cb9e7962b181bf99226eb3a53f Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b064379210..28901d6e55 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2146,6 +2146,9 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) } if (*fname != NUL && !error) { + char *file_to_find = NULL; + char *search_ctx = NULL; + do { if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) { xfree(fresult); @@ -2156,13 +2159,17 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) find_what, curbuf->b_ffname, (find_what == FINDFILE_DIR ? "" - : curbuf->b_p_sua)); + : curbuf->b_p_sua), + &file_to_find, &search_ctx); first = false; if (fresult != NULL && rettv->v_type == VAR_LIST) { tv_list_append_string(rettv->vval.v_list, fresult, -1); } } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); + + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); } if (rettv->v_type == VAR_STRING) { -- cgit From 85c61d67160133ba53762bc1e5e7bbd7a0c582c0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Apr 2023 10:06:34 +0800 Subject: vim-patch:9.0.1007: there is no way to get a list of swap file names Problem: There is no way to get a list of swap file names. Solution: Add the swapfilelist() function. Use it in the test script to clean up. Remove deleting individual swap files. https://github.com/vim/vim/commit/c216a7a21a25a701b84b79abc1ba6ab0baa3a311 vim-patch:9.0.1005: a failed test may leave a swap file behind Problem: A failed test may leave a swap file behind. Solution: Delete the swap file to avoid another test to fail. Use another file name. https://github.com/vim/vim/commit/d0f8d39d20f8d42f7451f781f7be0bcd20e06741 Cherry-pick test_window_cmd.vim changes from patch 8.2.1593. Remove FUNC_ATTR_UNUSED from eval functions as fptr is always unused. Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 28901d6e55..d9226214c6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -44,6 +44,7 @@ #include "nvim/eval/executor.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" #include "nvim/eval/window.h" @@ -3850,8 +3851,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// "interrupt()" function -static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, typval_T *rettv FUNC_ATTR_UNUSED, - EvalFuncData fptr FUNC_ATTR_UNUSED) +static void f_interrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { got_int = true; } @@ -8523,6 +8523,13 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +/// "swapfilelist()" function +static void f_swapfilelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + tv_list_alloc_ret(rettv, kListLenUnknown); + recover_names(NULL, false, rettv->vval.v_list, 0, NULL); +} + /// "swapinfo(swap_filename)" function static void f_swapinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { -- cgit From 706f871014b46300180156590ff269ee38473989 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 19 Apr 2023 17:04:00 +0100 Subject: build: update uncrustify to 0.76 --- src/nvim/eval/funcs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d9226214c6..d903d498e7 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2265,7 +2265,8 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "foreground()" function static void f_foreground(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{} +{ +} static void f_funcref(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2941,7 +2942,8 @@ static void f_gettagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// Dummy timer callback. Used by f_wait(). static void dummy_timer_due_cb(TimeWatcher *tw, void *data) -{} +{ +} /// Dummy timer close callback. Used by f_wait(). static void dummy_timer_close_cb(TimeWatcher *tw, void *data) -- cgit From 43c49746d9cf82dba0d56b07d39722f9ebeecf90 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 25 Apr 2023 21:32:12 +0800 Subject: vim-patch:9.0.0335: checks for Dictionary argument often give a vague error (#23309) Problem: Checks for Dictionary argument often give a vague error message. Solution: Give a useful error message. (Yegappan Lakshmanan, closes vim/vim#11009) https://github.com/vim/vim/commit/04c4c5746e15884768d2cb41370c3276a196cd4c Cherry-pick removal of E922 from docs from patch 9.0.1403. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d903d498e7..2a5f1cb720 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -597,8 +597,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) dict_T *selfdict = NULL; if (argvars[2].v_type != VAR_UNKNOWN) { - if (argvars[2].v_type != VAR_DICT) { - emsg(_(e_dictreq)); + if (tv_check_for_dict_arg(argvars, 2) == FAIL) { if (owned) { func_unref(func); } @@ -7359,8 +7358,7 @@ static void f_setcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (argvars[0].v_type != VAR_DICT) { - emsg(_(e_dictreq)); + if (tv_check_for_dict_arg(argvars, 0) == FAIL) { return; } @@ -7631,8 +7629,7 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } // second argument: dict with items to set in the tag stack - if (argvars[1].v_type != VAR_DICT) { - emsg(_(e_dictreq)); + if (tv_check_for_dict_arg(argvars, 1) == FAIL) { return; } dict_T *d = argvars[1].vval.v_dict; @@ -8987,11 +8984,10 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (argvars[2].v_type != VAR_UNKNOWN) { - dict_T *dict = argvars[2].vval.v_dict; - if (argvars[2].v_type != VAR_DICT || dict == NULL) { - semsg(_(e_invarg2), tv_get_string(&argvars[2])); + if (tv_check_for_nonnull_dict_arg(argvars, 2) == FAIL) { return; } + dict_T *dict = argvars[2].vval.v_dict; dictitem_T *const di = tv_dict_find(dict, S_LEN("repeat")); if (di != NULL) { repeat = (int)tv_get_number(&di->di_tv); -- cgit From bfa92d3861e425b59f9b1793c08247965a8e53f5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 25 Apr 2023 22:22:26 +0800 Subject: vim-patch:8.2.5019: cannot get the first screen column of a character (#23312) Problem: Cannot get the first screen column of a character. Solution: Let virtcol() optionally return a list. (closes vim/vim#10482, closes vim/vim#7964) https://github.com/vim/vim/commit/0f7a3e1de6f71e8e1423fe594890d6aa7f94e132 Co-authored-by: LemonBoy --- src/nvim/eval/funcs.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2a5f1cb720..72e25411ff 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -9275,10 +9275,11 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(curbuf->b_u_oldhead)); } -/// "virtcol(string)" function +/// "virtcol(string, bool)" function static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - colnr_T vcol = 0; + colnr_T vcol_start = 0; + colnr_T vcol_end = 0; int fnum = curbuf->b_fnum; pos_T *fp = var2fpos(&argvars[0], false, &fnum, false); @@ -9293,11 +9294,18 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) fp->col = (colnr_T)len; } } - getvvcol(curwin, fp, NULL, NULL, &vcol); - vcol++; + getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end); + vcol_start++; + vcol_end++; } - rettv->vval.v_number = vcol; + if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1])) { + tv_list_alloc_ret(rettv, 2); + tv_list_append_number(rettv->vval.v_list, vcol_start); + tv_list_append_number(rettv->vval.v_list, vcol_end); + } else { + rettv->vval.v_number = vcol_end; + } } /// "visualmode()" function -- cgit From 255e547e18e127ab70ffa2e423f7753786cb424e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 25 Apr 2023 22:21:19 +0800 Subject: fix(timer): allow timer_info() to get info about current timer --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 72e25411ff..3cf18e1c68 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8944,7 +8944,7 @@ static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } tv_list_alloc_ret(rettv, 1); timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0])); - if (timer != NULL && !timer->stopped) { + if (timer != NULL && (!timer->stopped || timer->refcount > 1)) { add_timer_info(rettv, timer); } } else { -- cgit From 7e0d66801297677ecbb6b35d0c9139e672920be4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 25 Apr 2023 23:39:15 +0800 Subject: vim-patch:partial:9.0.0359: error message for wrong argument type is not specific (#23315) Problem: Error message for wrong argument type is not specific. Solution: Include more information in the error. (Yegappan Lakshmanan, closes vim/vim#11037) https://github.com/vim/vim/commit/8deb2b30c77035bb682ccf80b781455ac1d6038b Skip reduce() and deepcopy() changes because of missing patches. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3cf18e1c68..afb8d841a4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -793,12 +793,9 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; - if (argvars[0].v_type != VAR_STRING - || argvars[1].v_type != VAR_NUMBER - || (argvars[2].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_NUMBER - && argvars[2].v_type != VAR_BOOL)) { - emsg(_(e_invarg)); + if ((tv_check_for_string_arg(argvars, 0) == FAIL + || tv_check_for_number_arg(argvars, 1) == FAIL + || tv_check_for_opt_bool_arg(argvars, 2) == FAIL)) { return; } @@ -3114,14 +3111,12 @@ static void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "gettext()" function static void f_gettext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (argvars[0].v_type != VAR_STRING - || argvars[0].vval.v_string == NULL - || *argvars[0].vval.v_string == NUL) { - semsg(_(e_invarg2), tv_get_string(&argvars[0])); - } else { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(_(argvars[0].vval.v_string)); + if (tv_check_for_nonempty_string_arg(argvars, 0) == FAIL) { + return; } + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = xstrdup(_(argvars[0].vval.v_string)); } /// "has()" function @@ -7641,7 +7636,9 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // default is to replace the stack. if (argvars[2].v_type == VAR_UNKNOWN) { // action = 'r'; - } else if (argvars[2].v_type == VAR_STRING) { + } else if (tv_check_for_string_arg(argvars, 2) == FAIL) { + return; + } else { const char *actstr; actstr = tv_get_string_chk(&argvars[2]); if (actstr == NULL) { @@ -7654,9 +7651,6 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_invact2), actstr); return; } - } else { - emsg(_(e_stringreq)); - return; } if (set_tagstack(wp, d, action) == OK) { @@ -8937,12 +8931,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "timer_info([timer])" function static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { + tv_list_alloc_ret(rettv, kListLenUnknown); + + if (tv_check_for_opt_number_arg(argvars, 0) == FAIL) { + return; + } + if (argvars[0].v_type != VAR_UNKNOWN) { - if (argvars[0].v_type != VAR_NUMBER) { - emsg(_(e_number_exp)); - return; - } - tv_list_alloc_ret(rettv, 1); timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0])); if (timer != NULL && (!timer->stopped || timer->refcount > 1)) { add_timer_info(rettv, timer); @@ -9008,8 +9003,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "timer_stop(timerid)" function static void f_timer_stop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (argvars[0].v_type != VAR_NUMBER) { - emsg(_(e_number_exp)); + if (tv_check_for_number_arg(argvars, 0) == FAIL) { return; } @@ -9136,8 +9130,7 @@ static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_STRING) { - semsg(_(e_invarg2), tv_get_string(&argvars[1])); + if (tv_check_for_opt_string_arg(argvars, 1) == FAIL) { return; } -- cgit From 907018e547c9b989781667d2cf951e1abf99ab9d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 26 Apr 2023 00:23:11 +0800 Subject: vim-patch:8.2.3139: functions for string manipulation are spread out (#23316) Problem: Functions for string manipulation are spread out. Solution: Move string related functions to a new source file. (Yegappan Lakshmanan, closes vim/vim#8470) https://github.com/vim/vim/commit/a2438132a675be4dde3acbdf03ba1fdb2f09427c Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 621 -------------------------------------------------- 1 file changed, 621 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index afb8d841a4..5c9d39b91f 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -149,8 +149,6 @@ PRAGMA_DIAG_POP static const char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static const char *e_invalwindow = N_("E957: Invalid window number"); static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); -static const char e_using_number_as_bool_nr[] - = N_("E1023: Using a Number as a Bool: %d"); static const char e_missing_function_argument[] = N_("E1132: Missing function argument"); @@ -529,41 +527,6 @@ static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -static void byteidx(typval_T *argvars, typval_T *rettv, int comp) -{ - const char *const str = tv_get_string_chk(&argvars[0]); - varnumber_T idx = tv_get_number_chk(&argvars[1], NULL); - rettv->vval.v_number = -1; - if (str == NULL || idx < 0) { - return; - } - - const char *t = str; - for (; idx > 0; idx--) { - if (*t == NUL) { // EOL reached. - return; - } - if (comp) { - t += utf_ptr2len(t); - } else { - t += utfc_ptr2len(t); - } - } - rettv->vval.v_number = (varnumber_T)(t - str); -} - -/// "byteidx()" function -static void f_byteidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - byteidx(argvars, rettv, false); -} - -/// "byteidxcomp()" function -static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - byteidx(argvars, rettv, true); -} - /// "call(func, arglist [, dict])" function static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -788,50 +751,6 @@ static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) get_col(argvars, rettv, true); } -/// "charidx()" function -static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = -1; - - if ((tv_check_for_string_arg(argvars, 0) == FAIL - || tv_check_for_number_arg(argvars, 1) == FAIL - || tv_check_for_opt_bool_arg(argvars, 2) == FAIL)) { - return; - } - - const char *str = tv_get_string_chk(&argvars[0]); - varnumber_T idx = tv_get_number_chk(&argvars[1], NULL); - if (str == NULL || idx < 0) { - return; - } - int countcc = 0; - if (argvars[2].v_type != VAR_UNKNOWN) { - countcc = (int)tv_get_number(&argvars[2]); - } - if (countcc < 0 || countcc > 1) { - semsg(_(e_using_number_as_bool_nr), countcc); - return; - } - - int (*ptr2len)(const char *); - if (countcc) { - ptr2len = utf_ptr2len; - } else { - ptr2len = utfc_ptr2len; - } - - const char *p; - int len; - for (p = str, len = 0; p <= str + idx; len++) { - if (*p == NUL) { - return; - } - p += ptr2len(p); - } - - rettv->vval.v_number = len > 0 ? len - 1 : 0; -} - /// "chdir(dir)" function static void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -3447,34 +3366,6 @@ static void f_hostname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_string = xstrdup(hostname); } -/// iconv() function -static void f_iconv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - vimconv_T vimconv; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - const char *const str = tv_get_string(&argvars[0]); - char buf1[NUMBUFLEN]; - char *const from = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[1], buf1))); - char buf2[NUMBUFLEN]; - char *const to = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[2], buf2))); - vimconv.vc_type = CONV_NONE; - convert_setup(&vimconv, from, to); - - // If the encodings are equal, no conversion needed. - if (vimconv.vc_type == CONV_NONE) { - rettv->vval.v_string = xstrdup(str); - } else { - rettv->vval.v_string = string_convert(&vimconv, (char *)str, NULL); - } - - convert_setup(&vimconv, NULL, NULL); - xfree(from); - xfree(to); -} - /// "indent()" function static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -8041,60 +7932,6 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->v_type = VAR_FLOAT; } -/// "str2list()" function -static void f_str2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - tv_list_alloc_ret(rettv, kListLenUnknown); - const char *p = tv_get_string(&argvars[0]); - - for (; *p != NUL; p += utf_ptr2len(p)) { - tv_list_append_number(rettv->vval.v_list, utf_ptr2char(p)); - } -} - -/// "str2nr()" function -static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int base = 10; - int what = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) { - base = (int)tv_get_number(&argvars[1]); - if (base != 2 && base != 8 && base != 10 && base != 16) { - emsg(_(e_invarg)); - return; - } - if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2])) { - what |= STR2NR_QUOTE; - } - } - - char *p = skipwhite(tv_get_string(&argvars[0])); - bool isneg = (*p == '-'); - if (*p == '+' || *p == '-') { - p = skipwhite(p + 1); - } - switch (base) { - case 2: - what |= STR2NR_BIN | STR2NR_FORCE; - break; - case 8: - what |= STR2NR_OCT | STR2NR_OOCT | STR2NR_FORCE; - break; - case 16: - what |= STR2NR_HEX | STR2NR_FORCE; - break; - } - varnumber_T n; - vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false, NULL); - // Text after the number is silently ignored. - if (isneg) { - rettv->vval.v_number = -n; - } else { - rettv->vval.v_number = n; - } -} - /// "strftime({format}[, {time}])" function static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -8145,235 +7982,6 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(enc); } -/// "strgetchar()" function -static void f_strgetchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = -1; - - const char *const str = tv_get_string_chk(&argvars[0]); - if (str == NULL) { - return; - } - bool error = false; - varnumber_T charidx = tv_get_number_chk(&argvars[1], &error); - if (error) { - return; - } - - const size_t len = strlen(str); - size_t byteidx = 0; - - while (charidx >= 0 && byteidx < len) { - if (charidx == 0) { - rettv->vval.v_number = utf_ptr2char(str + byteidx); - break; - } - charidx--; - byteidx += (size_t)utf_ptr2len(str + byteidx); - } -} - -/// "stridx()" function -static void f_stridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = -1; - - char buf[NUMBUFLEN]; - const char *const needle = tv_get_string_chk(&argvars[1]); - const char *haystack = tv_get_string_buf_chk(&argvars[0], buf); - const char *const haystack_start = haystack; - if (needle == NULL || haystack == NULL) { - return; // Type error; errmsg already given. - } - - if (argvars[2].v_type != VAR_UNKNOWN) { - bool error = false; - - const ptrdiff_t start_idx = (ptrdiff_t)tv_get_number_chk(&argvars[2], - &error); - if (error || start_idx >= (ptrdiff_t)strlen(haystack)) { - return; - } - if (start_idx >= 0) { - haystack += start_idx; - } - } - - const char *pos = strstr(haystack, needle); - if (pos != NULL) { - rettv->vval.v_number = (varnumber_T)(pos - haystack_start); - } -} - -/// "string()" function -static void f_string(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = encode_tv2string(&argvars[0], NULL); -} - -/// "strlen()" function -static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0])); -} - -static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc) -{ - const char *s = tv_get_string(&argvars[0]); - varnumber_T len = 0; - int (*func_mb_ptr2char_adv)(const char **pp); - - func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; - while (*s != NUL) { - func_mb_ptr2char_adv(&s); - len++; - } - rettv->vval.v_number = len; -} - -/// "strcharlen()" function -static void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - strchar_common(argvars, rettv, true); -} - -/// "strchars()" function -static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int skipcc = false; - - if (argvars[1].v_type != VAR_UNKNOWN) { - skipcc = (int)tv_get_bool(&argvars[1]); - } - if (skipcc < 0 || skipcc > 1) { - semsg(_(e_using_number_as_bool_nr), skipcc); - } else { - strchar_common(argvars, rettv, skipcc); - } -} - -/// "strdisplaywidth()" function -static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const s = tv_get_string(&argvars[0]); - int col = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) { - col = (int)tv_get_number(&argvars[1]); - } - - rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char *)s) - col); -} - -/// "strwidth()" function -static void f_strwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const s = tv_get_string(&argvars[0]); - - rettv->vval.v_number = (varnumber_T)mb_string2cells(s); -} - -/// "strcharpart()" function -static void f_strcharpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const p = tv_get_string(&argvars[0]); - const size_t slen = strlen(p); - - int nbyte = 0; - bool error = false; - varnumber_T nchar = tv_get_number_chk(&argvars[1], &error); - if (!error) { - if (nchar > 0) { - while (nchar > 0 && (size_t)nbyte < slen) { - nbyte += utf_ptr2len(p + nbyte); - nchar--; - } - } else { - nbyte = (int)nchar; - } - } - int len = 0; - if (argvars[2].v_type != VAR_UNKNOWN) { - int charlen = (int)tv_get_number(&argvars[2]); - while (charlen > 0 && nbyte + len < (int)slen) { - int off = nbyte + len; - - if (off < 0) { - len += 1; - } else { - len += utf_ptr2len(p + off); - } - charlen--; - } - } else { - len = (int)slen - nbyte; // default: all bytes that are available. - } - - // Only return the overlap between the specified part and the actual - // string. - if (nbyte < 0) { - len += nbyte; - nbyte = 0; - } else if ((size_t)nbyte > slen) { - nbyte = (int)slen; - } - if (len < 0) { - len = 0; - } else if (nbyte + len > (int)slen) { - len = (int)slen - nbyte; - } - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrndup(p + nbyte, (size_t)len); -} - -/// "strpart()" function -static void f_strpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - bool error = false; - - const char *const p = tv_get_string(&argvars[0]); - const size_t slen = strlen(p); - - varnumber_T n = tv_get_number_chk(&argvars[1], &error); - varnumber_T len; - if (error) { - len = 0; - } else if (argvars[2].v_type != VAR_UNKNOWN) { - len = tv_get_number(&argvars[2]); - } else { - len = (varnumber_T)slen - n; // Default len: all bytes that are available. - } - - // Only return the overlap between the specified part and the actual - // string. - if (n < 0) { - len += n; - n = 0; - } else if (n > (varnumber_T)slen) { - n = (varnumber_T)slen; - } - if (len < 0) { - len = 0; - } else if (n + len > (varnumber_T)slen) { - len = (varnumber_T)slen - n; - } - - if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) { - int off; - - // length in characters - for (off = (int)n; off < (int)slen && len > 0; len--) { - off += utfc_ptr2len(p + off); - } - len = off - n; - } - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = xmemdupz(p + n, (size_t)len); -} - /// "strptime({format}, {timestring})" function static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -8406,56 +8014,6 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(enc); } -/// "strridx()" function -static void f_strridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - char buf[NUMBUFLEN]; - const char *const needle = tv_get_string_chk(&argvars[1]); - const char *const haystack = tv_get_string_buf_chk(&argvars[0], buf); - - rettv->vval.v_number = -1; - if (needle == NULL || haystack == NULL) { - return; // Type error; errmsg already given. - } - - const size_t haystack_len = strlen(haystack); - ptrdiff_t end_idx; - if (argvars[2].v_type != VAR_UNKNOWN) { - // Third argument: upper limit for index. - end_idx = (ptrdiff_t)tv_get_number_chk(&argvars[2], NULL); - if (end_idx < 0) { - return; // Can never find a match. - } - } else { - end_idx = (ptrdiff_t)haystack_len; - } - - const char *lastmatch = NULL; - if (*needle == NUL) { - // Empty string matches past the end. - lastmatch = haystack + end_idx; - } else { - for (const char *rest = haystack; *rest != NUL; rest++) { - rest = strstr(rest, needle); - if (rest == NULL || rest > haystack + end_idx) { - break; - } - lastmatch = rest; - } - } - - if (lastmatch != NULL) { - rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); - } -} - -/// "strtrans()" function -static void f_strtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = transstr(tv_get_string(&argvars[0]), true); -} - /// "submatch()" function static void f_submatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -9020,185 +8578,6 @@ static void f_timer_stopall(typval_T *argvars, typval_T *unused, EvalFuncData fp timer_stop_all(); } -/// "tolower(string)" function -static void f_tolower(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), false); -} - -/// "toupper(string)" function -static void f_toupper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), true); -} - -/// "tr(string, fromstr, tostr)" function -static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - char buf[NUMBUFLEN]; - char buf2[NUMBUFLEN]; - - const char *in_str = tv_get_string(&argvars[0]); - const char *fromstr = tv_get_string_buf_chk(&argvars[1], buf); - const char *tostr = tv_get_string_buf_chk(&argvars[2], buf2); - - // Default return value: empty string. - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - if (fromstr == NULL || tostr == NULL) { - return; // Type error; errmsg already given. - } - garray_T ga; - ga_init(&ga, (int)sizeof(char), 80); - - // fromstr and tostr have to contain the same number of chars. - bool first = true; - while (*in_str != NUL) { - const char *cpstr = in_str; - const int inlen = utfc_ptr2len(in_str); - int cplen = inlen; - int idx = 0; - int fromlen; - for (const char *p = fromstr; *p != NUL; p += fromlen) { - fromlen = utfc_ptr2len(p); - if (fromlen == inlen && strncmp(in_str, p, (size_t)inlen) == 0) { - int tolen; - for (p = tostr; *p != NUL; p += tolen) { - tolen = utfc_ptr2len(p); - if (idx-- == 0) { - cplen = tolen; - cpstr = p; - break; - } - } - if (*p == NUL) { // tostr is shorter than fromstr. - goto error; - } - break; - } - idx++; - } - - if (first && cpstr == in_str) { - // Check that fromstr and tostr have the same number of - // (multi-byte) characters. Done only once when a character - // of in_str doesn't appear in fromstr. - first = false; - int tolen; - for (const char *p = tostr; *p != NUL; p += tolen) { - tolen = utfc_ptr2len(p); - idx--; - } - if (idx != 0) { - goto error; - } - } - - ga_grow(&ga, cplen); - memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); - ga.ga_len += cplen; - - in_str += inlen; - } - - // add a terminating NUL - ga_append(&ga, NUL); - - rettv->vval.v_string = ga.ga_data; - return; -error: - semsg(_(e_invarg2), fromstr); - ga_clear(&ga); -} - -/// "trim({expr})" function -static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - char buf1[NUMBUFLEN]; - char buf2[NUMBUFLEN]; - const char *head = tv_get_string_buf_chk(&argvars[0], buf1); - const char *mask = NULL; - const char *prev; - const char *p; - int dir = 0; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - if (head == NULL) { - return; - } - - if (tv_check_for_opt_string_arg(argvars, 1) == FAIL) { - return; - } - - if (argvars[1].v_type == VAR_STRING) { - mask = tv_get_string_buf_chk(&argvars[1], buf2); - if (argvars[2].v_type != VAR_UNKNOWN) { - bool error = false; - // leading or trailing characters to trim - dir = (int)tv_get_number_chk(&argvars[2], &error); - if (error) { - return; - } - if (dir < 0 || dir > 2) { - semsg(_(e_invarg2), tv_get_string(&argvars[2])); - return; - } - } - } - - int c1; - if (dir == 0 || dir == 1) { - // Trim leading characters - while (*head != NUL) { - c1 = utf_ptr2char(head); - if (mask == NULL) { - if (c1 > ' ' && c1 != 0xa0) { - break; - } - } else { - for (p = mask; *p != NUL; MB_PTR_ADV(p)) { - if (c1 == utf_ptr2char(p)) { - break; - } - } - if (*p == NUL) { - break; - } - } - MB_PTR_ADV(head); - } - } - - const char *tail = head + strlen(head); - if (dir == 0 || dir == 2) { - // Trim trailing characters - for (; tail > head; tail = prev) { - prev = tail; - MB_PTR_BACK(head, prev); - c1 = utf_ptr2char(prev); - if (mask == NULL) { - if (c1 > ' ' && c1 != 0xa0) { - break; - } - } else { - for (p = mask; *p != NUL; MB_PTR_ADV(p)) { - if (c1 == utf_ptr2char(p)) { - break; - } - } - if (*p == NUL) { - break; - } - } - } - } - rettv->vval.v_string = xstrnsave(head, (size_t)(tail - head)); -} - /// "type(expr)" function static void f_type(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { -- cgit From 3b0df1780e2c8526bda5dead18ee7cc45925caba Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:23:44 +0200 Subject: refactor: uncrustify Notable changes: replace all infinite loops to `while(true)` and remove `int` from `unsigned int`. --- src/nvim/eval/funcs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5c9d39b91f..91f78b8ed6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -643,7 +643,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) bool crlf = false; #else Channel *chan = find_channel(id); - bool crlf = (chan != NULL && chan->term) ? true: false; + bool crlf = (chan != NULL && chan->term) ? true : false; #endif if (argvars[1].v_type == VAR_BLOB) { @@ -4593,7 +4593,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (regmatch.regprog != NULL) { regmatch.rm_ic = p_ic; - for (;;) { + while (true) { if (l != NULL) { if (li == NULL) { match = false; @@ -4960,7 +4960,7 @@ static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret } msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); - do { + while (true) { if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) { emsg(_(e_outofmem)); goto end; @@ -4990,7 +4990,7 @@ static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret if (rlret == OK) { break; } - } while (true); + } end: msgpack_unpacker_free(unpacker); @@ -6026,8 +6026,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *const buf = xmallocz(MAXPATHL); char *cpy; - for (;;) { - for (;;) { + while (true) { + while (true) { len = readlink(p, buf, MAXPATHL); if (len <= 0) { break; @@ -6409,7 +6409,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) int subpatnum; // Repeat until {skip} returns false. - for (;;) { + while (true) { subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia); // finding the first match again means there is no match where {skip} @@ -6989,7 +6989,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir pos_T foundpos; clearpos(&foundpos); char *pat = pat3; - for (;;) { + while (true) { searchit_arg_T sia = { .sa_stop_lnum = lnum_stop, .sa_tm = &tm, -- cgit From 9f29176033926b81553985deaba0ea162ca40215 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 28 Apr 2023 00:01:22 +0800 Subject: vim-patch:9.0.1492: using uninitialized memory when argument is missing (#23351) Problem: Using uninitialized memory when argument is missing. Solution: Check there are sufficient arguments before the base. (closes vim/vim#12302) https://github.com/vim/vim/commit/b7f2270bab102d68f83a6300699b7f98efad81f2 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 91f78b8ed6..ebc34564e2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -287,6 +287,9 @@ int call_internal_method(const char *const fname, const int argcount, typval_T * typval_T argv[MAX_FUNC_ARGS + 1]; const ptrdiff_t base_index = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1; + if (argcount < base_index) { + return FCERR_TOOFEW; + } memcpy(argv, argvars, (size_t)base_index * sizeof(typval_T)); argv[base_index] = *basetv; memcpy(argv + base_index + 1, argvars + base_index, -- cgit From ff34c91194f9ab9d02808f2880029c38a4655eb5 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 17 Apr 2023 17:23:47 +0100 Subject: vim-patch:9.0.1330: handling new value of an option has a long "else if" chain Problem: Handling new value of an option has a long "else if" chain. Solution: Use a function pointer. (Yegappan Lakshmanan, closes vim/vim#12015) https://github.com/vim/vim/commit/af93691b53f38784efce0b93fe7644c44a7e382e --- src/nvim/eval/funcs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ebc34564e2..f898063fb0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7711,7 +7711,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } @@ -7768,7 +7768,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } -- cgit From 88cfb49bee3c9102082c7010acb92244e4ad1348 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 May 2023 07:14:39 +0800 Subject: vim-patch:8.2.4890: inconsistent capitalization in error messages Problem: Inconsistent capitalization in error messages. Solution: Make capitalization consistent. (Doug Kearns) https://github.com/vim/vim/commit/cf030578b26460643dca4a40e7f2e3bc19c749aa Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f898063fb0..927c1b3d5c 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -148,6 +148,8 @@ PRAGMA_DIAG_POP static const char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static const char *e_invalwindow = N_("E957: Invalid window number"); +static const char e_invalid_submatch_number_nr[] + = N_("E935: Invalid submatch number: %d"); static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); static const char e_missing_function_argument[] = N_("E1132: Missing function argument"); @@ -928,7 +930,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!error) { li = tv_list_find(l, (int)idx); if (li == NULL) { - semsg(_(e_listidx), idx); + semsg(_(e_list_index_out_of_range_nr), idx); } } } @@ -1902,7 +1904,7 @@ static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is } else { item = tv_list_find(l1, (int)before); if (item == NULL) { - semsg(_(e_listidx), (int64_t)before); + semsg(_(e_list_index_out_of_range_nr), (int64_t)before); return; } } @@ -3729,7 +3731,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (before != tv_list_len(l)) { item = tv_list_find(l, (int)before); if (item == NULL) { - semsg(_(e_listidx), before); + semsg(_(e_list_index_out_of_range_nr), before); l = NULL; } } @@ -8027,7 +8029,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (no < 0 || no >= NSUBEXP) { - semsg(_("E935: invalid submatch number: %d"), no); + semsg(_(e_invalid_submatch_number_nr), no); return; } int retList = 0; -- cgit From a0375b68c1803e7453071a20b28249020abe7260 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Jun 2023 04:31:17 +0800 Subject: vim-patch:9.0.1598: screenchar() and others are wrong with DBCS 'encoding' (#23872) Problem: screenchar(), screenchars() and screenstring() do not work properly when 'encoding' is set to a double-byte encoding. Solution: Fix the way the bytes of the characters are obtained. (issue vim/vim#12469) https://github.com/vim/vim/commit/47eec6716b8621fd43bac8ecc9c19089df26705e --- src/nvim/eval/funcs.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 927c1b3d5c..b4f9e4e219 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -62,7 +62,7 @@ #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/grid_defs.h" +#include "nvim/grid.h" #include "nvim/hashtab.h" #include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" @@ -6745,7 +6745,9 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { c = -1; } else { - c = utf_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col]); + char buf[MB_MAXBYTES + 1]; + grid_getbytes(grid, row, col, buf, NULL); + c = utf_ptr2char(buf); } rettv->vval.v_number = c; } @@ -6763,10 +6765,13 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_list_alloc_ret(rettv, 0); return; } + + char buf[MB_MAXBYTES + 1]; + grid_getbytes(grid, row, col, buf, NULL); int pcc[MAX_MCO]; - int c = utfc_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col], pcc); + int c = utfc_ptr2char(buf, pcc); int composing_len = 0; - while (pcc[composing_len] != 0) { + while (composing_len < MAX_MCO && pcc[composing_len] != 0) { composing_len++; } tv_list_alloc_ret(rettv, composing_len + 1); @@ -6806,7 +6811,9 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr return; } - rettv->vval.v_string = xstrdup((char *)grid->chars[grid->line_offset[row] + (size_t)col]); + char buf[MB_MAXBYTES + 1]; + grid_getbytes(grid, row, col, buf, NULL); + rettv->vval.v_string = xstrdup(buf); } /// "search()" function @@ -7201,7 +7208,7 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// Set the cursor or mark position. -/// If 'charpos' is true, then use the column number as a character offset. +/// If "charpos" is true, then use the column number as a character offset. /// Otherwise use the column number as a byte offset. static void set_position(typval_T *argvars, typval_T *rettv, bool charpos) { -- cgit From 2db719f6c2b677fcbc197b02fe52764a851523b2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 3 Jun 2023 11:06:00 +0100 Subject: feat(lua): rename vim.loop -> vim.uv (#22846) --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b4f9e4e219..04fd81c713 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3238,7 +3238,7 @@ static bool has_wsl(void) static TriState has_wsl = kNone; if (has_wsl == kNone) { Error err = ERROR_INIT; - Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim.loop.os_uname()['release']:lower()" + Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim.uv.os_uname()['release']:lower()" ":match('microsoft') and true or false"), (Array)ARRAY_DICT_INIT, &err); assert(!ERROR_SET(&err)); -- cgit From b3d5138fd0066fda26ef7724a542ae45eb42fc84 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 7 Jun 2023 06:05:16 +0600 Subject: refactor(options): remove `getoption_T` and introduce `OptVal` (#23850) Removes the `getoption_T` struct and also introduces the `OptVal` struct to unify the methods of getting/setting different option value types. This is the first of many PRs to reduce code duplication in the Vim option code as well as to make options easier to maintain. It also increases the flexibility and extensibility of options. Which opens the door for things like Array and Dictionary options. --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 04fd81c713..d465cade3e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7101,7 +7101,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir // If it's still empty it was changed and restored, need to restore in // the complicated way. if (*p_cpo == NUL) { - set_option_value_give_err("cpo", 0L, save_cpo, 0); + set_option_value_give_err("cpo", CSTR_AS_OPTVAL(save_cpo), 0); } free_string_option(save_cpo); } -- cgit From 971049f3189d4769db5e9896cd19b555719b3d09 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 7 Jun 2023 09:26:46 +0800 Subject: revert: "refactor: eliminate `autocmd_fname_full` global" This reverts commit 82cd0be2eaf71c0476e15c66ba3e83c76896d407. --- src/nvim/eval/funcs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d465cade3e..788efe1e84 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6552,6 +6552,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) sctx_T save_current_sctx; char *save_autocmd_fname, *save_autocmd_match; + bool save_autocmd_fname_full; int save_autocmd_bufnr; funccal_entry_T funccal_entry; @@ -6561,6 +6562,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) save_current_sctx = current_sctx; save_autocmd_fname = autocmd_fname; save_autocmd_match = autocmd_match; + save_autocmd_fname_full = autocmd_fname_full; save_autocmd_bufnr = autocmd_bufnr; save_funccal(&funccal_entry); @@ -6569,6 +6571,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ((estack_T *)exestack.ga_data)[exestack.ga_len++] = provider_caller_scope.es_entry; autocmd_fname = provider_caller_scope.autocmd_fname; autocmd_match = provider_caller_scope.autocmd_match; + autocmd_fname_full = provider_caller_scope.autocmd_fname_full; autocmd_bufnr = provider_caller_scope.autocmd_bufnr; set_current_funccal((funccall_T *)(provider_caller_scope.funccalp)); } @@ -6586,6 +6589,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) exestack.ga_len--; autocmd_fname = save_autocmd_fname; autocmd_match = save_autocmd_match; + autocmd_fname_full = save_autocmd_fname_full; autocmd_bufnr = save_autocmd_bufnr; restore_funccal(); } -- cgit From 2f17ef1fc4b96cf1106fd95ba090d34a2e4b977b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 04:09:14 -0700 Subject: fix(messages): use "Vimscript" instead of "VimL" #24111 followup to #24109 fix #16150 --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 788efe1e84..33f1ed51e5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8304,7 +8304,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// f_system - the VimL system() function +/// f_system - the Vimscript system() function static void f_system(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_system_output_as_rettv(argvars, rettv, false); -- cgit From aa362a2af8ce353d7082834a54bcc124ebd2a026 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 29 Jun 2023 15:48:42 +0800 Subject: refactor: remove some casts to char * (#24200) --- src/nvim/eval/funcs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 33f1ed51e5..99fec3d773 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -873,8 +873,7 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (!error) { - rettv->vval.v_number = do_dialog(type, NULL, (char *)message, (char *)buttons, def, NULL, - false); + rettv->vval.v_number = do_dialog(type, NULL, message, buttons, def, NULL, false); } } -- cgit From a741c7fd0465c949a0016fcbee5f4526b65f8c02 Mon Sep 17 00:00:00 2001 From: Alexandre Teoi Date: Sat, 1 Jul 2023 10:33:51 -0300 Subject: fix(api): nvim_parse_cmd error message in pcall() #23297 Problem: nvim_parse_cmd() in pcall() may show an error message (side-effect): :lua pcall(vim.api.nvim_parse_cmd, vim.fn.getcmdline(), {}) E16: Invalid range Solution: Avoid emsg() in the nvim_parse_cmd() codepath. - refactor(api): add error message output parameter to get_address() - fix: null check emsg() parameter - refactor: remove emsg_off workaround from do_incsearch_highlighting() - refactor: remove emsg_off workaround from cmdpreview_may_show() - refactor: remove remaining calls to emsg() from parse_cmd_address() and get_address() - (refactor): lint set_cmd_dflall_range() - refactor: addr_error() - move output parameter to return value Fix #20339 TODO: These are the functions called by `get_address()`: ``` nvim_parse_cmd() -> parse_cmdline() -> parse_cmd_address() -> get_address() skipwhite() addr_error() qf_get_cur_idx() qf_get_cur_valid_idx() qf_get_size() qf_get_valid_size() mark_get() mark_check() assert() skip_regexp() magic_isset() > do_search() > searchit() ascii_isdigit() getdigits() getdigits_int32() compute_buffer_local_count() hasFolding() ``` From these functions, I found at least two that call emsg directly: - do_search() - seems to be simple to refactor - searchit() - will be more challenging because it may generate multiple error messages, which can't be handled by the current `errormsg` out-parameter. For example, it makes multiple calls to `vim_regexec_multi()` in a loop that possibly generate error messages, and later `searchit()` itself may generate another one: - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L631-L647 - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L939-L954 --------- Co-authored-by: Justin M. Keyes --- src/nvim/eval/funcs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 99fec3d773..f53c5fc0c5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1716,7 +1716,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) emsg_off++; } size_t len; - char *errormsg = NULL; + const char *errormsg = NULL; char *result = eval_vars((char *)s, s, &len, NULL, &errormsg, NULL, false); if (p_verbose == 0) { emsg_off--; @@ -1781,7 +1781,7 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// Expand all the special characters in a command string. static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char *errormsg = NULL; + const char *errormsg = NULL; bool emsgoff = true; if (argvars[1].v_type == VAR_DICT -- cgit From fcf3519c65a2d6736de437f686e788684a6c8564 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 17 Apr 2023 22:18:58 +0200 Subject: refactor: remove long long is 32-bits even on 64-bit windows which makes the type suboptimal for a codebase meant to be cross-platform. --- src/nvim/eval/funcs.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f53c5fc0c5..f348a61075 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -886,7 +886,7 @@ static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "count()" function static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - long n = 0; + varnumber_T n = 0; int ic = 0; bool error = false; @@ -1085,8 +1085,9 @@ static void f_ctxsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// Otherwise use the column number as a byte offset. static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) { - long lnum, col; - long coladd = 0; + linenr_T lnum; + colnr_T col; + colnr_T coladd = 0; bool set_curswant = true; rettv->vval.v_number = -1; @@ -1114,12 +1115,12 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) } else if (lnum == 0) { lnum = curwin->w_cursor.lnum; } - col = (long)tv_get_number_chk(&argvars[1], NULL); + col = (colnr_T)tv_get_number_chk(&argvars[1], NULL); if (charcol) { - col = buf_charidx_to_byteidx(curbuf, (linenr_T)lnum, (int)col) + 1; + col = buf_charidx_to_byteidx(curbuf, lnum, (int)col) + 1; } if (argvars[2].v_type != VAR_UNKNOWN) { - coladd = (long)tv_get_number_chk(&argvars[2], NULL); + coladd = (colnr_T)tv_get_number_chk(&argvars[2], NULL); } } else { emsg(_(e_invarg)); @@ -1129,12 +1130,12 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) return; // type error; errmsg already given } if (lnum > 0) { - curwin->w_cursor.lnum = (linenr_T)lnum; + curwin->w_cursor.lnum = lnum; } if (col > 0) { - curwin->w_cursor.col = (colnr_T)col - 1; + curwin->w_cursor.col = col - 1; } - curwin->w_cursor.coladd = (colnr_T)coladd; + curwin->w_cursor.coladd = coladd; // Make sure the cursor is in a valid position. check_cursor(); -- cgit From aa4e47f704c53ab1d825260d2bf34e2872e3ca89 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Fri, 23 Jun 2023 22:32:07 +0100 Subject: fix(api): disallow some more functions during textlock Problem: nvim_buf_set_text(), nvim_open_term() and termopen() all change buffer text, which is forbidden during textlock. Additionally, nvim_open_term() and termopen() may be used to convert the cmdwin buffer into a terminal buffer, which is weird. Solution: Allow nvim_buf_set_text() and nvim_open_term() in the cmdwin, but disallow nvim_open_term() from converting the cmdwin buffer into a terminal buffer. termopen() is not allowed in the cmdwin (as it always operates on curbuf), so just check text_locked(). Also happens to improve the error in #21055: nvim_buf_set_text() was callable during textlock, but happened to check textlock indirectly via u_save(); however, this caused the error to be overwritten by an unhelpful "Failed to save undo information" message when msg_list == NULL (e.g: an `` mapping invoked outside of do_cmdline()). --- src/nvim/eval/funcs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f348a61075..7c3c5cc274 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8385,7 +8385,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (check_secure()) { return; } - + if (text_locked()) { + text_locked_msg(); + return; + } if (curbuf->b_changed) { emsg(_("Can only call this function in an unmodified buffer")); return; -- cgit From 559c4cfd52e385c1b9bd5fa66a0eeb7e8d9e018a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 8 Jul 2023 08:27:39 +0800 Subject: fix(startup): run embedded Nvim with real path (#24282) fix(startup): run embedded process with real path --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7c3c5cc274..e823e131b1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4120,7 +4120,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) env = create_environment(job_env, clear_env, pty, term_name); - Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty, + Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit, pty, rpc, overlapped, detach, stdin_mode, cwd, width, height, env, &rettv->vval.v_number); if (chan) { @@ -6678,7 +6678,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // The last item of argv must be NULL argv[i] = NULL; - Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT, + Channel *chan = channel_job_start(argv, NULL, CALLBACK_READER_INIT, CALLBACK_READER_INIT, CALLBACK_NONE, false, true, false, false, kChannelStdinPipe, NULL, 0, 0, NULL, @@ -8455,7 +8455,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const bool detach = false; ChannelStdinMode stdin_mode = kChannelStdinPipe; uint16_t term_width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin)); - Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, + Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit, pty, rpc, overlapped, detach, stdin_mode, cwd, term_width, (uint16_t)curwin->w_height_inner, env, &rettv->vval.v_number); -- cgit From b8b77820371978a5f937ccc0db356574ae33371b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 26 Jul 2023 15:18:09 +0800 Subject: vim-patch:partial:8.1.1981: the evalfunc.c file is too big (#24490) Problem: The evalfunc.c file is too big. Solution: Move undo functions to undo.c. Move cmdline functions to ex_getln.c. Move some container functions to list.c. https://github.com/vim/vim/commit/08c308aeb5e7dfa18fa61f261b0bff79517a4883 Undo functions only. Cmdline functions have already been moved. A lot of container functions have been added to eval/funcs.c instead of list.c in previously ported Vim 8.2.x patches, so deal with that later. Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e823e131b1..177f64ebba 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -114,7 +114,6 @@ #include "nvim/syntax.h" #include "nvim/tag.h" #include "nvim/ui.h" -#include "nvim/undo.h" #include "nvim/version.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -8629,43 +8628,6 @@ static void f_type(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = n; } -/// "undofile(name)" function -static void f_undofile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - const char *const fname = tv_get_string(&argvars[0]); - - if (*fname == NUL) { - // If there is no file name there will be no undo file. - rettv->vval.v_string = NULL; - } else { - char *ffname = FullName_save(fname, true); - - if (ffname != NULL) { - rettv->vval.v_string = u_get_undo_file_name(ffname, false); - } - xfree(ffname); - } -} - -/// "undotree()" function -static void f_undotree(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - tv_dict_alloc_ret(rettv); - - dict_T *dict = rettv->vval.v_dict; - - tv_dict_add_nr(dict, S_LEN("synced"), (varnumber_T)curbuf->b_u_synced); - tv_dict_add_nr(dict, S_LEN("seq_last"), (varnumber_T)curbuf->b_u_seq_last); - tv_dict_add_nr(dict, S_LEN("save_last"), - (varnumber_T)curbuf->b_u_save_nr_last); - tv_dict_add_nr(dict, S_LEN("seq_cur"), (varnumber_T)curbuf->b_u_seq_cur); - tv_dict_add_nr(dict, S_LEN("time_cur"), (varnumber_T)curbuf->b_u_time_cur); - tv_dict_add_nr(dict, S_LEN("save_cur"), (varnumber_T)curbuf->b_u_save_nr_cur); - - tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(curbuf->b_u_oldhead)); -} - /// "virtcol(string, bool)" function static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { -- cgit From 8cbb2477cf70ea29105e3df17308e6d6a067c8e6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 09:43:00 +0800 Subject: vim-patch:8.2.1969: Vim9: map() may change the list or dict item type Problem: Vim9: map() may change the list or dict item type. Solution: Add mapnew(). https://github.com/vim/vim/commit/ea696852e7abcdebaf7f17a7f23dc90df1f5e2ed Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 177f64ebba..0506c08b07 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2097,12 +2097,6 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) } } -/// "filter()" function -static void f_filter(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - filter_map(argvars, rettv, false); -} - /// "finddir({fname}[, {path}[, {count}]])" function static void f_finddir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -4488,12 +4482,6 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) nlua_typval_eval(cstr_as_string((char *)str), &argvars[1], rettv); } -/// "map()" function -static void f_map(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - filter_map(argvars, rettv, true); -} - static void find_some_match(typval_T *const argvars, typval_T *const rettv, const SomeMatchType type) { -- cgit From c5576fcc8003280489c0aa0323a966e6de33e31f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 13:41:43 +0800 Subject: vim-patch:8.2.3848: cannot use reduce() for a string Problem: Cannot use reduce() for a string. Solution: Make reduce() work with a string. (Naruhiko Nishino, closes vim/vim#9366) https://github.com/vim/vim/commit/0ccb5842f5fb103763d106c7aa364d758343c35a Omit tv_get_first_char() as it doesn't really save much code. Co-authored-by: rbtnn --- src/nvim/eval/funcs.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0506c08b07..bf11fdf029 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -150,8 +150,12 @@ static const char *e_invalwindow = N_("E957: Invalid window number"); static const char e_invalid_submatch_number_nr[] = N_("E935: Invalid submatch number: %d"); static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); +static const char e_string_list_or_blob_required[] + = N_("E1098: String, List or Blob required"); static const char e_missing_function_argument[] = N_("E1132: Missing function argument"); +static const char e_string_expected_for_argument_nr[] + = N_("E1253: String expected for argument %d"); /// Dummy va_list for passing to vim_snprintf /// @@ -6168,11 +6172,16 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// "reduce(list, { accumulator, element -> value } [, initial])" function +/// "reduce(blob, { accumulator, element -> value } [, initial])" function +/// "reduce(string, { accumulator, element -> value } [, initial])" function static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) { - emsg(_(e_listblobreq)); - return; + const int called_emsg_start = called_emsg; + + if (argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_LIST + && argvars[0].v_type != VAR_BLOB) { + emsg(_(e_string_list_or_blob_required)); } const char *func_name; @@ -6217,7 +6226,6 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (l != NULL) { const VarLockStatus prev_locked = tv_list_locked(l); - const int called_emsg_start = called_emsg; tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { @@ -6232,6 +6240,44 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } tv_list_set_lock(l, prev_locked); } + } else if (argvars[0].v_type == VAR_STRING) { + const char *p = tv_get_string(&argvars[0]); + int len; + + if (argvars[2].v_type == VAR_UNKNOWN) { + if (*p == NUL) { + semsg(_(e_reduceempty), "String"); + return; + } + len = utfc_ptr2len(p); + *rettv = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + p += len; + } else if (argvars[2].v_type != VAR_STRING) { + semsg(_(e_string_expected_for_argument_nr), 3); + return; + } else { + tv_copy(&argvars[2], rettv); + } + + for (; *p != NUL; p += len) { + argv[0] = *rettv; + len = utfc_ptr2len(p); + argv[1] = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); + tv_clear(&argv[0]); + tv_clear(&argv[1]); + if (r == FAIL || called_emsg != called_emsg_start) { + break; + } + } } else { const blob_T *const b = argvars[0].vval.v_blob; int i; -- cgit From b193674b4a1dce1b348489fa13dd42254b9a3ebb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 14:12:24 +0800 Subject: vim-patch:partial:8.2.3849: functions implementing reduce and map are too long Problem: Functions implementing reduce and map are too long. Solution: Use a function for each type of value. Add a few more test cases and add to the help. (Yegappan Lakshmanan, closes vim/vim#9370) https://github.com/vim/vim/commit/389b72196e6aaeafe3f907c73d271f2c6b931140 Partial port as this doesn't include handling for non-materialized List. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 241 +++++++++++++++++++++++++++++--------------------- 1 file changed, 138 insertions(+), 103 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index bf11fdf029..d5d9726397 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6171,17 +6171,150 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +/// reduce() on a List +static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + list_T *const l = argvars[0].vval.v_list; + const int called_emsg_start = called_emsg; + + typval_T initial; + const listitem_T *li = NULL; + if (argvars[2].v_type == VAR_UNKNOWN) { + if (tv_list_len(l) == 0) { + semsg(_(e_reduceempty), "List"); + return; + } + const listitem_T *const first = tv_list_first(l); + initial = *TV_LIST_ITEM_TV(first); + li = TV_LIST_ITEM_NEXT(l, first); + } else { + initial = argvars[2]; + li = tv_list_first(l); + } + + tv_copy(&initial, rettv); + + if (l == NULL) { + return; + } + + const VarLockStatus prev_locked = tv_list_locked(l); + + tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here + for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { + typval_T argv[3]; + argv[0] = *rettv; + argv[1] = *TV_LIST_ITEM_TV(li); + rettv->v_type = VAR_UNKNOWN; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + tv_clear(&argv[0]); + if (r == FAIL || called_emsg != called_emsg_start) { + break; + } + } + tv_list_set_lock(l, prev_locked); +} + +/// reduce() on a String +static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + const char *p = tv_get_string(&argvars[0]); + int len; + const int called_emsg_start = called_emsg; + + if (argvars[2].v_type == VAR_UNKNOWN) { + if (*p == NUL) { + semsg(_(e_reduceempty), "String"); + return; + } + len = utfc_ptr2len(p); + *rettv = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + p += len; + } else if (argvars[2].v_type != VAR_STRING) { + semsg(_(e_string_expected_for_argument_nr), 3); + return; + } else { + tv_copy(&argvars[2], rettv); + } + + for (; *p != NUL; p += len) { + typval_T argv[3]; + argv[0] = *rettv; + len = utfc_ptr2len(p); + argv[1] = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + tv_clear(&argv[0]); + tv_clear(&argv[1]); + if (r == FAIL || called_emsg != called_emsg_start) { + break; + } + } +} + +/// reduce() on a Blob +static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + const blob_T *const b = argvars[0].vval.v_blob; + const int called_emsg_start = called_emsg; + + typval_T initial; + int i; + if (argvars[2].v_type == VAR_UNKNOWN) { + if (tv_blob_len(b) == 0) { + semsg(_(e_reduceempty), "Blob"); + return; + } + initial = (typval_T){ + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval.v_number = tv_blob_get(b, 0), + }; + i = 1; + } else if (argvars[2].v_type != VAR_NUMBER) { + emsg(_(e_number_exp)); + return; + } else { + initial = argvars[2]; + i = 0; + } + + tv_copy(&initial, rettv); + for (; i < tv_blob_len(b); i++) { + typval_T argv[3]; + argv[0] = *rettv; + argv[1] = (typval_T){ + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval.v_number = tv_blob_get(b, i), + }; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + if (r == FAIL || called_emsg != called_emsg_start) { + return; + } + } +} + /// "reduce(list, { accumulator, element -> value } [, initial])" function /// "reduce(blob, { accumulator, element -> value } [, initial])" function /// "reduce(string, { accumulator, element -> value } [, initial])" function static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - const int called_emsg_start = called_emsg; - if (argvars[0].v_type != VAR_STRING && argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) { emsg(_(e_string_list_or_blob_required)); + return; } const char *func_name; @@ -6203,110 +6336,12 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) funcexe.fe_evaluate = true; funcexe.fe_partial = partial; - typval_T initial; - typval_T argv[3]; if (argvars[0].v_type == VAR_LIST) { - list_T *const l = argvars[0].vval.v_list; - const listitem_T *li; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (tv_list_len(l) == 0) { - semsg(_(e_reduceempty), "List"); - return; - } - const listitem_T *const first = tv_list_first(l); - initial = *TV_LIST_ITEM_TV(first); - li = TV_LIST_ITEM_NEXT(l, first); - } else { - initial = argvars[2]; - li = tv_list_first(l); - } - - tv_copy(&initial, rettv); - - if (l != NULL) { - const VarLockStatus prev_locked = tv_list_locked(l); - - tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here - for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - argv[0] = *rettv; - argv[1] = *TV_LIST_ITEM_TV(li); - rettv->v_type = VAR_UNKNOWN; - const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); - tv_clear(&argv[0]); - if (r == FAIL || called_emsg != called_emsg_start) { - break; - } - } - tv_list_set_lock(l, prev_locked); - } + reduce_list(argvars, func_name, &funcexe, rettv); } else if (argvars[0].v_type == VAR_STRING) { - const char *p = tv_get_string(&argvars[0]); - int len; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (*p == NUL) { - semsg(_(e_reduceempty), "String"); - return; - } - len = utfc_ptr2len(p); - *rettv = (typval_T){ - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), - }; - p += len; - } else if (argvars[2].v_type != VAR_STRING) { - semsg(_(e_string_expected_for_argument_nr), 3); - return; - } else { - tv_copy(&argvars[2], rettv); - } - - for (; *p != NUL; p += len) { - argv[0] = *rettv; - len = utfc_ptr2len(p); - argv[1] = (typval_T){ - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), - }; - const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); - tv_clear(&argv[0]); - tv_clear(&argv[1]); - if (r == FAIL || called_emsg != called_emsg_start) { - break; - } - } + reduce_string(argvars, func_name, &funcexe, rettv); } else { - const blob_T *const b = argvars[0].vval.v_blob; - int i; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (tv_blob_len(b) == 0) { - semsg(_(e_reduceempty), "Blob"); - return; - } - initial.v_type = VAR_NUMBER; - initial.vval.v_number = tv_blob_get(b, 0); - i = 1; - } else if (argvars[2].v_type != VAR_NUMBER) { - emsg(_(e_number_exp)); - return; - } else { - initial = argvars[2]; - i = 0; - } - - tv_copy(&initial, rettv); - for (; i < tv_blob_len(b); i++) { - argv[0] = *rettv; - argv[1].v_type = VAR_NUMBER; - argv[1].vval.v_number = tv_blob_get(b, i); - if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) { - return; - } - } + reduce_blob(argvars, func_name, &funcexe, rettv); } } -- cgit From 1918e1ea6d0192712e0a03926e2965a7aac0955e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 16:22:11 +0800 Subject: vim-patch:9.0.0359: error message for wrong argument type is not specific Problem: Error message for wrong argument type is not specific. Solution: Include more information in the error. (Yegappan Lakshmanan, closes vim/vim#11037) https://github.com/vim/vim/commit/8deb2b30c77035bb682ccf80b781455ac1d6038b Cherry-pick test_listdict.vim changes from patch 8.2.4809. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d5d9726397..ec55ab512b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -154,8 +154,6 @@ static const char e_string_list_or_blob_required[] = N_("E1098: String, List or Blob required"); static const char e_missing_function_argument[] = N_("E1132: Missing function argument"); -static const char e_string_expected_for_argument_nr[] - = N_("E1253: String expected for argument %d"); /// Dummy va_list for passing to vim_snprintf /// @@ -1187,18 +1185,16 @@ static void f_debugbreak(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "deepcopy()" function static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - int noref = 0; + if (tv_check_for_opt_bool_arg(argvars, 1) == FAIL) { + return; + } + varnumber_T noref = 0; if (argvars[1].v_type != VAR_UNKNOWN) { - noref = (int)tv_get_bool_chk(&argvars[1], NULL); - } - if (noref < 0 || noref > 1) { - semsg(_(e_using_number_as_bool_nr), noref); - } else { - var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0 - ? get_copyID() - : 0)); + noref = tv_get_bool_chk(&argvars[1], NULL); } + + var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0 ? get_copyID() : 0)); } /// "delete()" function @@ -6236,8 +6232,7 @@ static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *f .vval.v_string = xstrnsave(p, (size_t)len), }; p += len; - } else if (argvars[2].v_type != VAR_STRING) { - semsg(_(e_string_expected_for_argument_nr), 3); + } else if (tv_check_for_string_arg(argvars, 2) == FAIL) { return; } else { tv_copy(&argvars[2], rettv); @@ -6281,8 +6276,7 @@ static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *fun .vval.v_number = tv_blob_get(b, 0), }; i = 1; - } else if (argvars[2].v_type != VAR_NUMBER) { - emsg(_(e_number_exp)); + } else if (tv_check_for_number_arg(argvars, 2) == FAIL) { return; } else { initial = argvars[2]; -- cgit From 1ed12a2e10708f0d4ce39e5adb94d189455f4d98 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 16:17:22 +0800 Subject: vim-patch:9.0.0548: reduce() with a compiled lambda could be faster Problem: reduce() with a compiled lambda could be faster. Solution: Call eval_expr_typval() instead of call_func() directly. https://github.com/vim/vim/commit/f1c60d4bf10794265b828afd9c5f7eddacada10b Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ec55ab512b..044dabb058 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6167,9 +6167,10 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// reduce() on a List -static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *funcexe, - typval_T *rettv) +/// Implementation of reduce() for list "argvars[0]", using the function "expr" +/// starting with the optional initial value argvars[2] and return the result in +/// "rettv". +static void reduce_list(typval_T *argvars, typval_T *expr, typval_T *rettv) { list_T *const l = argvars[0].vval.v_list; const int called_emsg_start = called_emsg; @@ -6203,7 +6204,9 @@ static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *fun argv[0] = *rettv; argv[1] = *TV_LIST_ITEM_TV(li); rettv->v_type = VAR_UNKNOWN; - const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + + const int r = eval_expr_typval(expr, argv, 2, rettv); + tv_clear(&argv[0]); if (r == FAIL || called_emsg != called_emsg_start) { break; @@ -6212,9 +6215,10 @@ static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *fun tv_list_set_lock(l, prev_locked); } -/// reduce() on a String -static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *funcexe, - typval_T *rettv) +/// Implementation of reduce() for String "argvars[0]" using the function "expr" +/// starting with the optional initial value "argvars[2]" and return the result +/// in "rettv". +static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv) { const char *p = tv_get_string(&argvars[0]); int len; @@ -6247,7 +6251,9 @@ static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *f .v_lock = VAR_UNLOCKED, .vval.v_string = xstrnsave(p, (size_t)len), }; - const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + + const int r = eval_expr_typval(expr, argv, 2, rettv); + tv_clear(&argv[0]); tv_clear(&argv[1]); if (r == FAIL || called_emsg != called_emsg_start) { @@ -6256,9 +6262,10 @@ static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *f } } -/// reduce() on a Blob -static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *funcexe, - typval_T *rettv) +/// Implementaion of reduce() for Blob "argvars[0]" using the function "expr" +/// starting with the optional initial value "argvars[2]" and return the result +/// in "rettv". +static void reduce_blob(typval_T *argvars, typval_T *expr, typval_T *rettv) { const blob_T *const b = argvars[0].vval.v_blob; const int called_emsg_start = called_emsg; @@ -6292,7 +6299,9 @@ static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *fun .v_lock = VAR_UNLOCKED, .vval.v_number = tv_blob_get(b, i), }; - const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + + const int r = eval_expr_typval(expr, argv, 2, rettv); + if (r == FAIL || called_emsg != called_emsg_start) { return; } @@ -6312,12 +6321,10 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } const char *func_name; - partial_T *partial = NULL; if (argvars[1].v_type == VAR_FUNC) { func_name = argvars[1].vval.v_string; } else if (argvars[1].v_type == VAR_PARTIAL) { - partial = argvars[1].vval.v_partial; - func_name = partial_name(partial); + func_name = partial_name(argvars[1].vval.v_partial); } else { func_name = tv_get_string(&argvars[1]); } @@ -6326,16 +6333,12 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - funcexe_T funcexe = FUNCEXE_INIT; - funcexe.fe_evaluate = true; - funcexe.fe_partial = partial; - if (argvars[0].v_type == VAR_LIST) { - reduce_list(argvars, func_name, &funcexe, rettv); + reduce_list(argvars, &argvars[1], rettv); } else if (argvars[0].v_type == VAR_STRING) { - reduce_string(argvars, func_name, &funcexe, rettv); + reduce_string(argvars, &argvars[1], rettv); } else { - reduce_blob(argvars, func_name, &funcexe, rettv); + reduce_blob(argvars, &argvars[1], rettv); } } -- cgit From de6b58f65913931c4f18267cdbb9bfef3ceec3a9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 17 Aug 2023 21:56:03 +0800 Subject: vim-patch:8.2.3867: implementation of some list functions too complicated (#24757) Problem: Implementation of some list functions too complicated. Solution: Refactor do_sort_uniq(), f_count() and extend() (Yegappan Lakshmanan, closes vim/vim#9378) https://github.com/vim/vim/commit/d92813a59877c707e4b64bea6d786aad152acb45 Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 338 +++++++++++++++++++++++++++++--------------------- 1 file changed, 195 insertions(+), 143 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 044dabb058..b0e0fffe5c 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -884,6 +884,86 @@ static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) var_item_copy(NULL, &argvars[0], rettv, false, 0); } +/// Count the number of times "needle" occurs in string "haystack". +/// +/// @param ic ignore case +static varnumber_T count_string(const char *haystack, const char *needle, bool ic) +{ + varnumber_T n = 0; + const char *p = haystack; + + if (p == NULL || needle == NULL || *needle == NUL) { + return 0; + } + + if (ic) { + const size_t len = strlen(needle); + + while (*p != NUL) { + if (mb_strnicmp(p, needle, len) == 0) { + n++; + p += len; + } else { + MB_PTR_ADV(p); + } + } + } else { + const char *next; + while ((next = strstr(p, needle)) != NULL) { + n++; + p = next + strlen(needle); + } + } + + return n; +} + +/// Count the number of times item "needle" occurs in List "l" starting at index "idx". +/// +/// @param ic ignore case +static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic) +{ + if (tv_list_len(l) == 0) { + return 0; + } + + listitem_T *li = tv_list_find(l, (int)idx); + if (li == NULL) { + semsg(_(e_list_index_out_of_range_nr), idx); + return 0; + } + + varnumber_T n = 0; + + for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { + if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic, false)) { + n++; + } + } + + return n; +} + +/// Count the number of times item "needle" occurs in Dict "d". +/// +/// @param ic ignore case +static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic) +{ + if (d == NULL) { + return 0; + } + + varnumber_T n = 0; + + TV_DICT_ITER(d, di, { + if (tv_equal(&di->di_tv, needle, ic, false)) { + n++; + } + }); + + return n; +} + /// "count()" function static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -895,74 +975,26 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ic = (int)tv_get_number_chk(&argvars[2], &error); } - if (argvars[0].v_type == VAR_STRING) { - const char *expr = tv_get_string_chk(&argvars[1]); - const char *p = argvars[0].vval.v_string; - - if (!error && expr != NULL && *expr != NUL && p != NULL) { - if (ic) { - const size_t len = strlen(expr); - - while (*p != NUL) { - if (mb_strnicmp(p, expr, len) == 0) { - n++; - p += len; - } else { - MB_PTR_ADV(p); - } - } - } else { - char *next; - while ((next = strstr(p, expr)) != NULL) { - n++; - p = next + strlen(expr); - } - } + if (!error && argvars[0].v_type == VAR_STRING) { + n = count_string(argvars[0].vval.v_string, tv_get_string_chk(&argvars[1]), ic); + } else if (!error && argvars[0].v_type == VAR_LIST) { + int64_t idx = 0; + if (argvars[2].v_type != VAR_UNKNOWN + && argvars[3].v_type != VAR_UNKNOWN) { + idx = (long)tv_get_number_chk(&argvars[3], &error); } - } else if (argvars[0].v_type == VAR_LIST) { - list_T *l = argvars[0].vval.v_list; - - if (l != NULL) { - listitem_T *li = tv_list_first(l); - if (argvars[2].v_type != VAR_UNKNOWN) { - if (argvars[3].v_type != VAR_UNKNOWN) { - int64_t idx = tv_get_number_chk(&argvars[3], &error); - if (!error) { - li = tv_list_find(l, (int)idx); - if (li == NULL) { - semsg(_(e_list_index_out_of_range_nr), idx); - } - } - } - if (error) { - li = NULL; - } - } - - for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - if (tv_equal(TV_LIST_ITEM_TV(li), &argvars[1], ic, false)) { - n++; - } - } + if (!error) { + n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic); } - } else if (argvars[0].v_type == VAR_DICT) { + } else if (!error && argvars[0].v_type == VAR_DICT) { dict_T *d = argvars[0].vval.v_dict; if (d != NULL) { - if (argvars[2].v_type != VAR_UNKNOWN) { - if (argvars[3].v_type != VAR_UNKNOWN) { - emsg(_(e_invarg)); - } - } - - int todo = error ? 0 : (int)d->dv_hashtab.ht_used; - for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) { - if (!HASHITEM_EMPTY(hi)) { - todo--; - if (tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &argvars[1], ic, false)) { - n++; - } - } + if (argvars[2].v_type != VAR_UNKNOWN + && argvars[3].v_type != VAR_UNKNOWN) { + emsg(_(e_invarg)); + } else { + n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic); } } } else { @@ -1875,104 +1907,124 @@ static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) flatten_common(argvars, rettv, true); } -/// "extend()" or "extendnew()" function. "is_new" is true for extendnew(). -static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new) +/// extend() a List. Append List argvars[1] to List argvars[0] before index +/// argvars[3] and return the resulting list in "rettv". +/// +/// @param is_new true for extendnew() +static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv) { - if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) { - bool error = false; + bool error = false; - list_T *l1 = argvars[0].vval.v_list; - list_T *const l2 = argvars[1].vval.v_list; - if (is_new || !value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { - if (is_new) { - l1 = tv_list_copy(NULL, l1, false, get_copyID()); - if (l1 == NULL) { - return; - } + list_T *l1 = argvars[0].vval.v_list; + list_T *const l2 = argvars[1].vval.v_list; + if (is_new || !value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { + if (is_new) { + l1 = tv_list_copy(NULL, l1, false, get_copyID()); + if (l1 == NULL) { + return; } + } - listitem_T *item; - if (argvars[2].v_type != VAR_UNKNOWN) { - long before = (long)tv_get_number_chk(&argvars[2], &error); - if (error) { - return; // Type error; errmsg already given. - } - - if (before == tv_list_len(l1)) { - item = NULL; - } else { - item = tv_list_find(l1, (int)before); - if (item == NULL) { - semsg(_(e_list_index_out_of_range_nr), (int64_t)before); - return; - } - } - } else { - item = NULL; + listitem_T *item; + if (argvars[2].v_type != VAR_UNKNOWN) { + long before = (long)tv_get_number_chk(&argvars[2], &error); + if (error) { + return; // Type error; errmsg already given. } - tv_list_extend(l1, l2, item); - if (is_new) { - *rettv = (typval_T){ - .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval.v_list = l1, - }; + if (before == tv_list_len(l1)) { + item = NULL; } else { - tv_copy(&argvars[0], rettv); + item = tv_list_find(l1, (int)before); + if (item == NULL) { + semsg(_(e_list_index_out_of_range_nr), (int64_t)before); + return; + } } + } else { + item = NULL; } - } else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) { - dict_T *d1 = argvars[0].vval.v_dict; - dict_T *const d2 = argvars[1].vval.v_dict; - if (d1 == NULL) { - const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); - (void)locked; - assert(locked == true); - } else if (d2 == NULL) { - // Do nothing + tv_list_extend(l1, l2, item); + + if (is_new) { + *rettv = (typval_T){ + .v_type = VAR_LIST, + .v_lock = VAR_UNLOCKED, + .vval.v_list = l1, + }; + } else { tv_copy(&argvars[0], rettv); - } else if (is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { - if (is_new) { - d1 = tv_dict_copy(NULL, d1, false, get_copyID()); - if (d1 == NULL) { - return; - } + } + } +} + +/// extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the +/// resulting Dict in "rettv". +/// +/// @param is_new true for extendnew() +static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv) +{ + dict_T *d1 = argvars[0].vval.v_dict; + dict_T *const d2 = argvars[1].vval.v_dict; + if (d1 == NULL) { + const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); + (void)locked; + assert(locked == true); + } else if (d2 == NULL) { + // Do nothing + tv_copy(&argvars[0], rettv); + } else if (is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { + if (is_new) { + d1 = tv_dict_copy(NULL, d1, false, get_copyID()); + if (d1 == NULL) { + return; } + } - const char *action = "force"; - // Check the third argument. - if (argvars[2].v_type != VAR_UNKNOWN) { - const char *const av[] = { "keep", "force", "error" }; + const char *action = "force"; + // Check the third argument. + if (argvars[2].v_type != VAR_UNKNOWN) { + const char *const av[] = { "keep", "force", "error" }; - action = tv_get_string_chk(&argvars[2]); - if (action == NULL) { - return; // Type error; error message already given. - } - size_t i; - for (i = 0; i < ARRAY_SIZE(av); i++) { - if (strcmp(action, av[i]) == 0) { - break; - } - } - if (i == 3) { - semsg(_(e_invarg2), action); - return; + action = tv_get_string_chk(&argvars[2]); + if (action == NULL) { + return; // Type error; error message already given. + } + size_t i; + for (i = 0; i < ARRAY_SIZE(av); i++) { + if (strcmp(action, av[i]) == 0) { + break; } } + if (i == 3) { + semsg(_(e_invarg2), action); + return; + } + } - tv_dict_extend(d1, d2, action); + tv_dict_extend(d1, d2, action); - if (is_new) { - *rettv = (typval_T){ - .v_type = VAR_DICT, - .v_lock = VAR_UNLOCKED, - .vval.v_dict = d1, - }; - } else { - tv_copy(&argvars[0], rettv); - } + if (is_new) { + *rettv = (typval_T){ + .v_type = VAR_DICT, + .v_lock = VAR_UNLOCKED, + .vval.v_dict = d1, + }; + } else { + tv_copy(&argvars[0], rettv); } + } +} + +/// "extend()" or "extendnew()" function. +/// +/// @param is_new true for extendnew() +static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new) +{ + if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) { + extend_list(argvars, arg_errmsg, is_new, rettv); + } else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) { + extend_dict(argvars, arg_errmsg, is_new, rettv); } else { semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()"); } -- cgit From ffb87f4dd992ff23ff66f888dbe1bcc54bd0b012 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 18 Aug 2023 05:07:48 +0800 Subject: vim-patch:9.0.1722: wrong error messages when passing wrong types to count() Problem: wrong error messages when passing wrong types to count() Solution: fix it This fixes two problems: 1. When passing wrong type to {ic} argument of count(), two error messages are given, the second of which is misleading. 2. When passing wrong type to {comp} argument of count(), the error message doesn't mention that {comp} may be a String. closes: vim/vim#12825 https://github.com/vim/vim/commit/4f389e7c0fe7dfeccfa512a72fa36f9028d57159 --- src/nvim/eval/funcs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b0e0fffe5c..a9f87b5008 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -147,6 +147,8 @@ PRAGMA_DIAG_POP static const char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static const char *e_invalwindow = N_("E957: Invalid window number"); +static const char e_argument_of_str_must_be_list_string_or_dictionary[] + = N_("E706: Argument of %s must be a List, String or Dictionary"); static const char e_invalid_submatch_number_nr[] = N_("E935: Invalid submatch number: %d"); static const char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); @@ -997,8 +999,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic); } } - } else { - semsg(_(e_listdictarg), "count()"); + } else if (!error) { + semsg(_(e_argument_of_str_must_be_list_string_or_dictionary), "count()"); } rettv->vval.v_number = n; } -- cgit From bb29ef40084e1cea1f35cbbcbac794f41f46d5f8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 18 Aug 2023 05:09:24 +0800 Subject: vim-patch:9.0.1723: Fix regression in {func} argument of reduce() Problem: Fix regression in {func} argument of reduce() Solution: pass function name as string again Before patch 9.0.0548, passing a string as {func} argument of reduce() is treated as a function name, but after patch 9.0.0548 it is treated as an expression instead, which is useless as reduce() doesn't set any v: variables. This PR restores the behavior of {func} before that patch. Also correct an emsg() call, as e_string_list_or_blob_required doesn't contain format specifiers. closes: vim/vim#12824 https://github.com/vim/vim/commit/ad0c442f1fcc6fe9c433777ee3e5b9e6addc6d69 --- src/nvim/eval/funcs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index a9f87b5008..e8224671dc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2953,7 +2953,7 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const int called_emsg_before = called_emsg; LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, timeout, - eval_expr_typval(&expr, &argv, 0, &exprval) != OK + eval_expr_typval(&expr, false, &argv, 0, &exprval) != OK || tv_get_number_chk(&exprval, &error) || called_emsg > called_emsg_before || error || got_int); @@ -3515,7 +3515,7 @@ static varnumber_T indexof_eval_expr(typval_T *expr) typval_T newtv; newtv.v_type = VAR_UNKNOWN; - if (eval_expr_typval(expr, argv, 2, &newtv) == FAIL) { + if (eval_expr_typval(expr, false, argv, 2, &newtv) == FAIL) { return false; } @@ -5537,7 +5537,7 @@ static varnumber_T readdir_checkitem(void *context, const char *name) argv[0].vval.v_string = (char *)name; typval_T rettv; - if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL) { + if (eval_expr_typval(expr, false, argv, 1, &rettv) == FAIL) { goto theend; } @@ -6259,7 +6259,7 @@ static void reduce_list(typval_T *argvars, typval_T *expr, typval_T *rettv) argv[1] = *TV_LIST_ITEM_TV(li); rettv->v_type = VAR_UNKNOWN; - const int r = eval_expr_typval(expr, argv, 2, rettv); + const int r = eval_expr_typval(expr, true, argv, 2, rettv); tv_clear(&argv[0]); if (r == FAIL || called_emsg != called_emsg_start) { @@ -6306,7 +6306,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv) .vval.v_string = xstrnsave(p, (size_t)len), }; - const int r = eval_expr_typval(expr, argv, 2, rettv); + const int r = eval_expr_typval(expr, true, argv, 2, rettv); tv_clear(&argv[0]); tv_clear(&argv[1]); @@ -6354,7 +6354,7 @@ static void reduce_blob(typval_T *argvars, typval_T *expr, typval_T *rettv) .vval.v_number = tv_blob_get(b, i), }; - const int r = eval_expr_typval(expr, argv, 2, rettv); + const int r = eval_expr_typval(expr, true, argv, 2, rettv); if (r == FAIL || called_emsg != called_emsg_start) { return; -- cgit From f8afa8023ee032dfb2aa9a6489f51484fb276732 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 18 Aug 2023 08:42:45 +0800 Subject: vim-patch:9.0.1728: missing winid argument for virtcol() (#24770) Problem: missing winid argument for virtcol() Solution: Add a {winid} argument to virtcol() Other functions col(), charcol() and virtcol2col() support a {winid} argument, so it makes sense for virtcol() to also support than. Also add test for virtcol2col() with 'showbreak' and {winid}. closes: vim/vim#12633 https://github.com/vim/vim/commit/825cf813fa0fddf085fcbd3194781e875320ff63 --- src/nvim/eval/funcs.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e8224671dc..9926530d58 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8748,13 +8748,31 @@ static void f_type(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = n; } -/// "virtcol(string, bool)" function +/// "virtcol({expr}, [, {list} [, {winid}]])" function static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { colnr_T vcol_start = 0; colnr_T vcol_end = 0; - int fnum = curbuf->b_fnum; + switchwin_T switchwin; + bool winchanged = false; + + if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { + // use the window specified in the third argument + tabpage_T *tp; + win_T *wp = win_id2wp_tp((int)tv_get_number(&argvars[2]), &tp); + if (wp == NULL || tp == NULL) { + goto theend; + } + if (switch_win_noblock(&switchwin, wp, tp, true) != OK) { + goto theend; + } + + check_cursor(); + winchanged = true; + } + + int fnum = curbuf->b_fnum; pos_T *fp = var2fpos(&argvars[0], false, &fnum, false); if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count && fnum == curbuf->b_fnum) { @@ -8772,6 +8790,7 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) vcol_end++; } +theend: if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1])) { tv_list_alloc_ret(rettv, 2); tv_list_append_number(rettv->vval.v_list, vcol_start); @@ -8779,6 +8798,10 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else { rettv->vval.v_number = vcol_end; } + + if (winchanged) { + restore_win_noblock(&switchwin, true); + } } /// "visualmode()" function -- cgit From 4c7df98e4eeed20f8a9c461729935b79743d7752 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 19 Aug 2023 17:44:19 +0800 Subject: vim-patch:9.0.1515: reverse() does not work for a String Problem: reverse() does not work for a String. Solution: Implement reverse() for a String. (Yegappan Lakshmanan, closes vim/vim#12179) https://github.com/vim/vim/commit/03ff1c2dde7f15eca5c9baa6dafbda9b49bedc3b vim-patch:9.0.1738: Duplicate code to reverse a string Problem: Duplicate code to reverse a string Solution: Move reverse_text() to strings.c and remove string_reverse(). closes: vim/vim#12847 https://github.com/vim/vim/commit/4dd266cb66d901cf5324f09405cfea3f004bd29f Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 9926530d58..b97e19131e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6209,6 +6209,13 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_blob_set(b, len - i - 1, tmp); } tv_blob_set_ret(rettv, b); + } else if (argvars[0].v_type == VAR_STRING) { + rettv->v_type = VAR_STRING; + if (argvars[0].vval.v_string != NULL) { + rettv->vval.v_string = reverse_text(argvars[0].vval.v_string); + } else { + rettv->vval.v_string = NULL; + } } else if (argvars[0].v_type != VAR_LIST) { semsg(_(e_listblobarg), "reverse()"); } else { -- cgit From fcd729f22c658826024467801ae4ba0a92a8fabc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 19 Aug 2023 17:57:09 +0800 Subject: vim-patch:9.0.1540: reverse() on string doesn't work in compiled function Problem: reverse() on string doesn't work in compiled function. Solution: Accept string in argument type check. (Yegappan Lakshmanan, closes vim/vim#12377) https://github.com/vim/vim/commit/f9dc278946d52235a0025fd347bd9ff571258470 Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/funcs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b97e19131e..250b5c5556 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6199,6 +6199,10 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "reverse({list})" function static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { + if (tv_check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL) { + return; + } + if (argvars[0].v_type == VAR_BLOB) { blob_T *const b = argvars[0].vval.v_blob; const int len = tv_blob_len(b); @@ -6216,9 +6220,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else { rettv->vval.v_string = NULL; } - } else if (argvars[0].v_type != VAR_LIST) { - semsg(_(e_listblobarg), "reverse()"); - } else { + } else if (argvars[0].v_type == VAR_LIST) { list_T *const l = argvars[0].vval.v_list; if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"), TV_TRANSLATE)) { -- cgit From 64ccfdaafef56b451e3a5eed94367fad93978ec8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 21 Aug 2023 11:22:25 +0800 Subject: vim-patch:8.1.2047: cannot check the current state Problem: Cannot check the current state. Solution: Add the state() function. https://github.com/vim/vim/commit/0e57dd859ecb1e8a3b91509d2f4343e839340eb8 Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 250b5c5556..c47fd4cfcb 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4925,6 +4925,47 @@ static void f_mode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->v_type = VAR_STRING; } +static void may_add_state_char(garray_T *gap, const char *include, uint8_t c) +{ + if (include == NULL || vim_strchr(include, c) != NULL) { + ga_append(gap, c); + } +} + +/// "state()" function +static void f_state(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + garray_T ga; + ga_init(&ga, 1, 20); + const char *include = NULL; + + if (argvars[0].v_type != VAR_UNKNOWN) { + include = tv_get_string(&argvars[0]); + } + + if (!(stuff_empty() && typebuf.tb_len == 0 && !using_script())) { + may_add_state_char(&ga, include, 'm'); + } + if (op_pending()) { + may_add_state_char(&ga, include, 'o'); + } + if (autocmd_busy) { + may_add_state_char(&ga, include, 'x'); + } + if (!ctrl_x_mode_none()) { + may_add_state_char(&ga, include, 'a'); + } + for (int i = 0; i < get_callback_depth() && i < 3; i++) { + may_add_state_char(&ga, include, 'c'); + } + if (msg_scrolled > 0) { + may_add_state_char(&ga, include, 's'); + } + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = ga.ga_data; +} + /// "msgpackdump()" function static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL -- cgit From 7ce2acd59be89e5e6d2ac778ad074a9ae42951cd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 21 Aug 2023 12:16:33 +0800 Subject: vim-patch:8.1.2053: SafeStateAgain not triggered if callback uses feedkeys() Problem: SafeStateAgain not triggered if callback uses feedkeys(). Solution: Check for safe state in the input loop. Make log messages easier to find. Add 'S' flag to state(). https://github.com/vim/vim/commit/d103ee78432f9036d243b18dd5aac1263d3b7dc9 Include misc1.c change from patch 8.1.2062. Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c47fd4cfcb..8c07623369 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4955,6 +4955,9 @@ static void f_state(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!ctrl_x_mode_none()) { may_add_state_char(&ga, include, 'a'); } + if (!get_was_safe_state()) { + may_add_state_char(&ga, include, 'S'); + } for (int i = 0; i < get_callback_depth() && i < 3; i++) { may_add_state_char(&ga, include, 'c'); } -- cgit From 6bf5b2428b146330688922d66438357c0568725d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 21 Aug 2023 12:26:02 +0800 Subject: vim-patch:8.1.2066: no tests for state() Problem: No tests for state(). Solution: Add tests. Clean up some feature checks. Make "a" flag work. https://github.com/vim/vim/commit/c2585490321854ca3df115efcf0b40986901d96c Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8c07623369..3c232a7163 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4952,7 +4952,7 @@ static void f_state(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (autocmd_busy) { may_add_state_char(&ga, include, 'x'); } - if (!ctrl_x_mode_none()) { + if (ins_compl_active()) { may_add_state_char(&ga, include, 'a'); } if (!get_was_safe_state()) { -- cgit From cc35352f65f823259675f84a915ee03d2423913e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 21 Aug 2023 15:23:32 +0800 Subject: vim-patch:8.1.2062: the mouse code is spread out (#24817) Problem: The mouse code is spread out. Solution: Move all the mouse code to mouse.c. (Yegappan Lakshmanan, closes vim/vim#4959) https://github.com/vim/vim/commit/b20b9e14ddd8db111e886ad0494e15b955159426 Also move getmousepos() there. N/A patches for version.c: vim-patch:8.1.2070: mouse code is spread out Problem: Mouse code is spread out. Solution: Move mouse terminal code parsing to mouse.c. (Yegappan Lakshmanan, closes vim/vim#4966) https://github.com/vim/vim/commit/b8ff5c271ee5dcef6f63436b77e228e062ff9a0e Co-authored-by: Bram Moolenaar --- src/nvim/eval/funcs.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3c232a7163..755df761e7 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2750,47 +2750,6 @@ static void f_getmarklist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) get_buf_local_marks(buf, rettv->vval.v_list); } -/// "getmousepos()" function -static void f_getmousepos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int row = mouse_row; - int col = mouse_col; - int grid = mouse_grid; - varnumber_T winid = 0; - varnumber_T winrow = 0; - varnumber_T wincol = 0; - linenr_T lnum = 0; - varnumber_T column = 0; - - tv_dict_alloc_ret(rettv); - dict_T *d = rettv->vval.v_dict; - - tv_dict_add_nr(d, S_LEN("screenrow"), (varnumber_T)mouse_row + 1); - tv_dict_add_nr(d, S_LEN("screencol"), (varnumber_T)mouse_col + 1); - - win_T *wp = mouse_find_win(&grid, &row, &col); - if (wp != NULL) { - int height = wp->w_height + wp->w_hsep_height + wp->w_status_height; - // The height is adjusted by 1 when there is a bottom border. This is not - // necessary for a top border since `row` starts at -1 in that case. - if (row < height + wp->w_border_adj[2]) { - winid = wp->handle; - winrow = row + 1 + wp->w_winrow_off; // Adjust by 1 for top border - wincol = col + 1 + wp->w_wincol_off; // Adjust by 1 for left border - if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) { - (void)mouse_comp_pos(wp, &row, &col, &lnum); - col = vcol2col(wp, lnum, col); - column = col + 1; - } - } - } - tv_dict_add_nr(d, S_LEN("winid"), winid); - tv_dict_add_nr(d, S_LEN("winrow"), winrow); - tv_dict_add_nr(d, S_LEN("wincol"), wincol); - tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)lnum); - tv_dict_add_nr(d, S_LEN("column"), column); -} - /// "getpid()" function static void f_getpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { -- cgit From 0fd8eb8aae101815c699048a4dbc6ac7c5e35a9d Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:55:51 -0500 Subject: fix(terminal): set $COLORTERM unconditionally in :terminal (#24763) $COLORTERM is set in the terminal emulator based on the value of 'termguicolors' ("truecolor" if &tgc is set, 256 otherwise), but ONLY if $COLORTERM is also set in the parent terminal emulator. This is an unnecessary restriction that can cause issues in some cases. For instance, $COLORTERM is stripped by default by OpenSSH, so is not present in an SSH session. The terminal emulator still supports 24 bit color, so the lack of $COLORTERM is not a reliable indicator. When an application runs in Nvim's :terminal it thus has no way to know whether or not true color is supported. Instead, setting it unconditionally based on 'termguicolors' uses the user's own preferences to infer if 24-bit color is supported, rather than depending on the (unreliable) presence of $COLORTERM. If 'termguicolors' is set in a terminal that does not support true color then the colors in Nvim will already look bad. Enabling them for applications in the terminal emulator will not make it any worse. If 'termguicolors' is not set then the value of $COLORTERM from the parent terminal (if any) is forwarded to Nvim's :terminal. Fixes: https://github.com/neovim/neovim/issues/24717 --- src/nvim/eval/funcs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 755df761e7..cf8525e66a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3943,12 +3943,13 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en } } #ifndef MSWIN - // Set COLORTERM to "truecolor" if termguicolors is set and 256 - // otherwise, but only if it was set in the parent terminal at all - dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM")); - if (dv) { - tv_dict_item_remove(env, dv); - tv_dict_add_str(env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256"); + // Set COLORTERM to "truecolor" if termguicolors is set + if (p_tgc) { + dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM")); + if (dv) { + tv_dict_item_remove(env, dv); + } + tv_dict_add_str(env, S_LEN("COLORTERM"), "truecolor"); } #endif } -- cgit From 01fe6b9e6a84338d4752c93a286262d79120f163 Mon Sep 17 00:00:00 2001 From: Alisue Date: Sun, 6 Aug 2023 23:19:29 +0900 Subject: feat(msgpack_rpc): support out-of-order responses on `msgpack-rpc` Added to support MessagePack-RPC fully compliant clients that do not return responses in request order. Although it is currently not an efficient implementation for full compliance and full compliance cannot be guaranteed, the addition of the new client type `msgpack-rpc` creates a situation where "if the client type is `msgpack-rpc`, then backward compatibility is ignored and full compliance with MessagePack- RPC compliance is justified even if backward compatibility is ignored if the client type is `msgpack-rpc`. --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index cf8525e66a..1ed0994222 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6730,7 +6730,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const char *name = NULL; Channel *chan = find_channel(chan_id); if (chan) { - name = rpc_client_name(chan); + name = get_client_info(chan, "name"); } msg_ext_set_kind("rpc_error"); if (name) { -- cgit From a6e74c1f0a2bbf03f5b99c167b549018f4c8fb0d Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:05:27 +0200 Subject: docs: fix typos and other small fixes (#25005) Co-authored-by: nuid64 Co-authored-by: Mike Smith <10135646+mikesmithgh@users.noreply.github.com> Co-authored-by: XTY Co-authored-by: Empa Co-authored-by: kyu08 <49891479+kyu08@users.noreply.github.com> --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1ed0994222..93075cf0e2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6329,7 +6329,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv) } } -/// Implementaion of reduce() for Blob "argvars[0]" using the function "expr" +/// Implementation of reduce() for Blob "argvars[0]" using the function "expr" /// starting with the optional initial value "argvars[2]" and return the result /// in "rettv". static void reduce_blob(typval_T *argvars, typval_T *expr, typval_T *rettv) -- cgit From cf8b2c0e74fd5e723b0c15c2ce84e6900fd322d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 12:05:28 +0800 Subject: build(iwyu): add a few more _defs.h mappings (#25435) --- src/nvim/eval/funcs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 93075cf0e2..61f3793f4d 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -63,12 +63,12 @@ #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/grid.h" -#include "nvim/hashtab.h" #include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/input.h" +#include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" #include "nvim/macros.h" @@ -76,12 +76,10 @@ #include "nvim/mark.h" #include "nvim/math.h" #include "nvim/mbyte.h" -#include "nvim/memfile_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/menu.h" #include "nvim/message.h" -#include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel_defs.h" -- cgit From dc6d0d2daf69e2fdadda81feb97906dbc962a239 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 14:41:34 +0800 Subject: refactor: reorganize option header files (#25437) - Move vimoption_T to option.h - option_defs.h is for option-related types - option_vars.h corresponds to Vim's option.h - option_defs.h and option_vars.h don't include each other --- src/nvim/eval/funcs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 61f3793f4d..710d9c73a5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -87,6 +87,7 @@ #include "nvim/normal.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/dl.h" #include "nvim/os/fileio.h" -- cgit From f6e72c3dfed83b02483976eaedb27819df9a878d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 19:14:24 +0800 Subject: vim-patch:9.0.1962: No support for writing extended attributes Problem: No support for writing extended attributes Solution: Add extended attribute support for linux It's been a long standing issue, that if you write a file with extended attributes and backupcopy is set to no, the file will loose the extended attributes. So this patch adds support for retrieving the extended attributes and copying it to the new file. It currently only works on linux, mainly because I don't know the different APIs for other systems (BSD, MacOSX and Solaris). On linux, this should be supported since Kernel 2.4 or something, so this should be pretty safe to use now. Enable the extended attribute support with normal builds. I also added it explicitly to the :version output as well as make it able to check using `:echo has("xattr")`, to have users easily check that this is available. In contrast to the similar support for SELINUX and SMACK support (which also internally uses extended attributes), I have made this a FEAT_XATTR define, instead of the similar HAVE_XATTR. Add a test and change CI to include relevant packages so that CI can test that extended attributes are correctly written. closes: vim/vim#306 closes: vim/vim#13203 https://github.com/vim/vim/commit/e085dfda5d8dde064b0332464040959479696d1c Co-authored-by: Christian Brabandt --- src/nvim/eval/funcs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 710d9c73a5..5bfce7c272 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3171,6 +3171,9 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "windows", "winaltkeys", "writebackup", +#ifdef HAVE_XATTR + "xattr", +#endif "nvim", }; -- cgit From 09a17f91d0d362c6e58bfdbe3ccdeacffb0b44b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 2 Oct 2023 10:45:33 +0800 Subject: refactor: move cmdline completion types to cmdexpand_defs.h (#25465) --- src/nvim/eval/funcs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5bfce7c272..ee70731c7c 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -33,6 +33,7 @@ #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/context.h" #include "nvim/cursor.h" #include "nvim/diff.h" -- cgit From 29fe883aa9166bdbcae3f935523c75a8aa56fe45 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 4 Oct 2023 06:31:25 -0700 Subject: feat: ignore swapfile for running Nvim processes #25336 Problem: The swapfile "E325: ATTENTION" dialog is displayed when editing a file already open in another (running) Nvim. Usually this behavior is annoying and irrelevant: - "Recover" and the other options ("Open readonly", "Quit", "Abort") are almost never wanted. - swapfiles are less relevant for "multi-Nvim" since 'autoread' is enabled by default. - Even less relevant if user enables 'autowrite'. Solution: Define a default SwapExists handler which does the following: 1. If the swapfile is owned by a running Nvim process, automatically chooses "(E)dit anyway" (caveat: this creates a new, extra swapfile, which is mostly harmless and ignored except by `:recover` or `nvim -r`. 2. Shows a 1-line "ignoring swapfile..." message. 3. Users can disable the default SwapExists handler via `autocmd! nvim_swapfile`. --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ee70731c7c..4dd3f193e6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8236,7 +8236,7 @@ static void f_swapfilelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr static void f_swapinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); - get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict); + swapfile_dict(tv_get_string(argvars), rettv->vval.v_dict); } /// "swapname(expr)" function -- cgit From a58bb215449cee65b965b9094e9e996ddfe78315 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 5 Oct 2023 14:44:13 +0200 Subject: refactor(grid): get rid of unbatched grid_puts and grid_putchar This finalizes the long running refactor from the old TUI-focused grid implementation where text-drawing cursor was not separated from the visible cursor. Still, the pattern of setting cursor position together with updating a line was convenient. Introduce grid_line_cursor_goto() to still allow this but now being explicit about it. Only having batched drawing functions makes code involving drawing a bit longer. But it is better to be explicit, and this highlights cases where multiple small redraws can be grouped together. This was the case for most of the changed places (messages, lastline, and :intro) --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4dd3f193e6..eb2e2fb1e2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6885,7 +6885,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) c = -1; } else { char buf[MB_MAXBYTES + 1]; - grid_getbytes(grid, row, col, buf, NULL); + schar_get(buf, grid_getchar(grid, row, col, NULL)); c = utf_ptr2char(buf); } rettv->vval.v_number = c; @@ -6906,7 +6906,7 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } char buf[MB_MAXBYTES + 1]; - grid_getbytes(grid, row, col, buf, NULL); + schar_get(buf, grid_getchar(grid, row, col, NULL)); int pcc[MAX_MCO]; int c = utfc_ptr2char(buf, pcc); int composing_len = 0; @@ -6951,7 +6951,7 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr } char buf[MB_MAXBYTES + 1]; - grid_getbytes(grid, row, col, buf, NULL); + schar_get(buf, grid_getchar(grid, row, col, NULL)); rettv->vval.v_string = xstrdup(buf); } -- cgit From 8e932480f61d6101bf8bea1abc07ed93826221fd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/eval/funcs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index eb2e2fb1e2..782687e6b6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -526,7 +526,7 @@ buf_T *get_buf_arg(typval_T *arg) /// "byte2line(byte)" function static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - long boff = (long)tv_get_number(&argvars[0]) - 1; + int boff = (int)tv_get_number(&argvars[0]) - 1; if (boff < 0) { rettv->vval.v_number = -1; } else { @@ -8708,8 +8708,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!callback_from_typval(&callback, &argvars[1])) { return; } - rettv->vval.v_number = (varnumber_T)timer_start((const long)tv_get_number(&argvars[0]), repeat, - &callback); + rettv->vval.v_number = (varnumber_T)timer_start(tv_get_number(&argvars[0]), repeat, &callback); } /// "timer_stop(timerid)" function -- cgit From 9ff6f73f838a1f90d09922448c434033ba5e094e Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 9 Oct 2023 00:36:48 +0600 Subject: refactor: allow not having a `default` case for enum Problem: The style guide states that all switch statements that are not conditional on an enum must have a `default` case, but does not give any explicit guideline for switch statements that are conditional on enums. As a result, a `default` case is added in many enum switch statements, even when the switch statement is exhaustive. This is not ideal because it removes the ability to have compiler errors to easily detect unchanged switch statements when a new possible value for an enum is added. Solution: Add explicit guidelines for switch statements that are conditional on an enum, clarifying that a `default` case is not necessary if the switch statement is exhaustive. Also refactor pre-existing code with unnecessary `default` cases. --- src/nvim/eval/funcs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 782687e6b6..b9d124532e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4990,9 +4990,10 @@ static int msgpackparse_convert_item(const msgpack_object data, const msgpack_un tv_list_append_owned_tv(ret_list, tv); return OK; } - default: + case MSGPACK_UNPACK_EXTRA_BYTES: abort(); } + UNREACHABLE; } static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret_list) -- cgit From 0892c1cd94672e0dffe3b97fc4a85ea517b05598 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 16 Oct 2023 16:41:17 +0800 Subject: vim-patch:9.0.2033: gcc overflow-warning for f_resolve (#25666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: gcc overflow-warning for f_resolve Solution: use pointer p instead of pointer q[-1] Suppress the following warning: ``` filepath.c: In function ‘f_resolve’: filepath.c:2162:27: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 2162 | q[-1] = NUL; ``` Closes: vim/vim#13352 closes: vim/vim#13353 https://github.com/vim/vim/commit/215c3261a25f7a99e8711a3b3c6158119c6aea9e Co-authored-by: Ken Takata --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b9d124532e..0979087c79 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6098,13 +6098,13 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } // Ensure that the result will have a trailing path separator - // if the argument has one. */ + // if the argument has one. if (remain == NULL && has_trailing_pathsep) { add_pathsep(buf); } // Separate the first path component in the link value and - // concatenate the remainders. */ + // concatenate the remainders. q = (char *)path_next_component(vim_ispathsep(*buf) ? buf + 1 : buf); if (*q != NUL) { cpy = remain; @@ -6118,7 +6118,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) q = path_tail(p); if (q > p && *q == NUL) { // Ignore trailing path separator. - q[-1] = NUL; + p[q - p - 1] = NUL; q = path_tail(p); } if (q > p && !path_is_absolute(buf)) { -- cgit From af010e23f38a23bb74ea5b61e1b1a05e76410b5f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Fri, 13 Oct 2023 20:16:15 +0600 Subject: refactor(options): rename `empty_option` to `empty_string_option` --- src/nvim/eval/funcs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0979087c79..8e5bf68be1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -482,7 +482,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only) int save_magic = p_magic; p_magic = true; char *save_cpo = p_cpo; - p_cpo = empty_option; + p_cpo = empty_string_option; buf_T *buf = buflist_findnr(buflist_findpat(name, name + strlen(name), true, false, curtab_only)); @@ -1733,7 +1733,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *p_csl_save = p_csl; // avoid using 'completeslash' here - p_csl = empty_option; + p_csl = empty_string_option; #endif rettv->v_type = VAR_STRING; @@ -4516,7 +4516,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = empty_option; + p_cpo = empty_string_option; rettv->vval.v_number = -1; switch (type) { @@ -7108,7 +7108,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = empty_option; + p_cpo = empty_string_option; // Set the time limit, if there is one. proftime_T tm = profile_setlimit(time_limit); @@ -7234,7 +7234,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir xfree(pat2); xfree(pat3); - if (p_cpo == empty_option) { + if (p_cpo == empty_string_option) { p_cpo = save_cpo; } else { // Darn, evaluating the {skip} expression changed the value. @@ -7966,7 +7966,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = empty_option; + p_cpo = empty_string_option; const char *str = tv_get_string(&argvars[0]); const char *pat = NULL; -- cgit From 5f03a1eaabfc8de2b3a9c666fcd604763f41e152 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 20 Oct 2023 15:10:33 +0200 Subject: build(lint): remove unnecessary clint.py rules Uncrustify is the source of truth where possible. Remove any redundant checks from clint.py. --- src/nvim/eval/funcs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8e5bf68be1..4759b4ebe3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2502,7 +2502,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) [kCdScopeTabpage] = 0, // Number of tab to look at. }; - char *cwd = NULL; // Current working directory to print + char *cwd = NULL; // Current working directory to print char *from = NULL; // The original string to copy tabpage_T *tp = curtab; // The tabpage to look at. @@ -3281,7 +3281,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) [kCdScopeTabpage] = 0, // Number of tab to look at. }; - tabpage_T *tp = curtab; // The tabpage to look at. + tabpage_T *tp = curtab; // The tabpage to look at. win_T *win = curwin; // The window to look at. rettv->v_type = VAR_NUMBER; @@ -5258,7 +5258,7 @@ static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncDa } callback_free(&buf->b_prompt_interrupt); - buf->b_prompt_interrupt= interrupt_callback; + buf->b_prompt_interrupt = interrupt_callback; } /// "prompt_getprompt({buffer})" function @@ -5589,9 +5589,9 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 int io_size = sizeof(buf); char *prev = NULL; // previously read bytes, if any - ptrdiff_t prevlen = 0; // length of data in prev + ptrdiff_t prevlen = 0; // length of data in prev ptrdiff_t prevsize = 0; // size of prev buffer - int64_t maxline = MAXLNUM; + int64_t maxline = MAXLNUM; off_T offset = 0; off_T size = -1; @@ -5651,7 +5651,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); p++) { if (readlen <= 0 || *p == '\n') { - char *s = NULL; + char *s = NULL; size_t len = (size_t)(p - start); // Finished a line. Remove CRs before NL. @@ -5754,7 +5754,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl prevsize = p - start; } else { ptrdiff_t grow50pc = (prevsize * 3) / 2; - ptrdiff_t growmin = (p - start) * 2 + prevlen; + ptrdiff_t growmin = (p - start) * 2 + prevlen; prevsize = grow50pc > growmin ? grow50pc : growmin; } prev = xrealloc(prev, (size_t)prevsize); -- cgit From 684e93054b82c6b5b215db7d3ecbad803eb81f0e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 25 Oct 2023 09:59:02 +0800 Subject: fix(terminal): assign channel to terminal earlier (#25771) --- src/nvim/eval/funcs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4759b4ebe3..aae544f28d 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8637,8 +8637,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) INTEGER_OBJ(pid), false, false, &err); api_clear_error(&err); + channel_incref(chan); channel_terminal_open(curbuf, chan); channel_create_event(chan, NULL); + channel_decref(chan); } /// "timer_info([timer])" function -- cgit From f97248db757ee300b7808c3dd67858d489b604fd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 28 Oct 2023 10:06:43 +0800 Subject: vim-patch:9.0.2070: [security] disallow setting env in restricted mode (#25807) Problem: [security] disallow setting env in restricted mode Solution: Setting environment variables in restricted mode could potentially be used to execute shell commands. Disallow this. restricted mode: disable allow setting of environment variables Setting environment variables in restricted mode, may have some unwanted consequences. So, for example by setting $GCONV_PATH in restricted mode and then calling the iconv() function, one may be able to execute some unwanted payload, because the `iconv_open()` function internally uses the `$GCONV_PATH` variable to find its conversion data. So let's disable setting environment variables, even so this is no complete protection, since we are not clearing the existing environment. I tried a few ways but wasn't successful :( One could also argue to disable the iconv() function completely in restricted mode, but who knows what other API functions can be influenced by setting some other unrelated environment variables. So let's leave it as it is currently. closes: vim/vim#13394 See: https://huntr.com/bounties/b0a2eda1-459c-4e36-98e6-0cc7d7faccfe/ https://github.com/vim/vim/commit/6b89dd6a7257a1e2e9c7ea070b407bc4674a5118 Co-authored-by: Christian Brabandt --- src/nvim/eval/funcs.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index aae544f28d..c12fd9fd31 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7436,6 +7436,13 @@ static void f_setenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char valbuf[NUMBUFLEN]; const char *name = tv_get_string_buf(&argvars[0], namebuf); + // seting an environment variable may be dangerous, e.g. you could + // setenv GCONV_PATH=/tmp and then have iconv() unexpectedly call + // a shell command using some shared library: + if (check_secure()) { + return; + } + if (argvars[1].v_type == VAR_SPECIAL && argvars[1].vval.v_special == kSpecialVarNull) { vim_unsetenv_ext(name); -- cgit From acc646ad8fc3ef11fcc63b69f3d8484e4a91accd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/eval/funcs.c | 62 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c12fd9fd31..505a91813a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -983,7 +983,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) int64_t idx = 0; if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) { - idx = (long)tv_get_number_chk(&argvars[3], &error); + idx = (int64_t)tv_get_number_chk(&argvars[3], &error); } if (!error) { n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic); @@ -1860,11 +1860,11 @@ static void flatten_common(typval_T *argvars, typval_T *rettv, bool make_copy) return; } - long maxdepth; + int maxdepth; if (argvars[1].v_type == VAR_UNKNOWN) { maxdepth = 999999; } else { - maxdepth = (long)tv_get_number_chk(&argvars[1], &error); + maxdepth = (int)tv_get_number_chk(&argvars[1], &error); if (error) { return; } @@ -1929,7 +1929,7 @@ static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, listitem_T *item; if (argvars[2].v_type != VAR_UNKNOWN) { - long before = (long)tv_get_number_chk(&argvars[2], &error); + int before = (int)tv_get_number_chk(&argvars[2], &error); if (error) { return; // Type error; errmsg already given. } @@ -1937,7 +1937,7 @@ static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, if (before == tv_list_len(l1)) { item = NULL; } else { - item = tv_list_find(l1, (int)before); + item = tv_list_find(l1, before); if (item == NULL) { semsg(_(e_list_index_out_of_range_nr), (int64_t)before); return; @@ -3394,7 +3394,7 @@ static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "index()" function static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - long idx = 0; + int idx = 0; bool ic = false; rettv->vval.v_number = -1; @@ -3421,7 +3421,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) for (idx = start; idx < tv_blob_len(b); idx++) { typval_T tv; tv.v_type = VAR_NUMBER; - tv.vval.v_number = tv_blob_get(b, (int)idx); + tv.vval.v_number = tv_blob_get(b, idx); if (tv_equal(&tv, &argvars[1], ic, false)) { rettv->vval.v_number = idx; return; @@ -3447,7 +3447,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (error || idx == -1) { item = NULL; } else { - item = tv_list_find(l, (int)idx); + item = tv_list_find(l, idx); assert(item != NULL); } if (argvars[3].v_type != VAR_UNKNOWN) { @@ -3690,11 +3690,11 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - long before = 0; + int before = 0; const int len = tv_blob_len(b); if (argvars[2].v_type != VAR_UNKNOWN) { - before = (long)tv_get_number_chk(&argvars[2], &error); + before = (int)tv_get_number_chk(&argvars[2], &error); if (error) { return; // type error; errmsg already given } @@ -4511,7 +4511,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, colnr_T startcol = 0; bool match = false; list_T *l = NULL; - long idx = 0; + int idx = 0; char *tofree = NULL; // Make 'cpoptions' empty, the 'l' flag should not be used here. @@ -4550,7 +4550,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, li = tv_list_first(l); } else { expr = str = (char *)tv_get_string(&argvars[0]); - len = (long)strlen(str); + len = (int64_t)strlen(str); } char patbuf[NUMBUFLEN]; @@ -4571,7 +4571,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (idx == -1) { goto theend; } - li = tv_list_find(l, (int)idx); + li = tv_list_find(l, idx); } else { if (start < 0) { start = 0; @@ -5414,10 +5414,10 @@ static void f_rand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) goto theend; } - typval_T *const tvx = TV_LIST_ITEM_TV(tv_list_find(l, 0L)); - typval_T *const tvy = TV_LIST_ITEM_TV(tv_list_find(l, 1L)); - typval_T *const tvz = TV_LIST_ITEM_TV(tv_list_find(l, 2L)); - typval_T *const tvw = TV_LIST_ITEM_TV(tv_list_find(l, 3L)); + typval_T *const tvx = TV_LIST_ITEM_TV(tv_list_find(l, 0)); + typval_T *const tvy = TV_LIST_ITEM_TV(tv_list_find(l, 1)); + typval_T *const tvz = TV_LIST_ITEM_TV(tv_list_find(l, 2)); + typval_T *const tvw = TV_LIST_ITEM_TV(tv_list_find(l, 3)); if (tvx->v_type != VAR_NUMBER) { goto theend; } @@ -5861,8 +5861,8 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL } bool error = false; - varnumber_T n1 = tv_list_find_nr(arg->vval.v_list, 0L, &error); - varnumber_T n2 = tv_list_find_nr(arg->vval.v_list, 1L, &error); + varnumber_T n1 = tv_list_find_nr(arg->vval.v_list, 0, &error); + varnumber_T n2 = tv_list_find_nr(arg->vval.v_list, 1, &error); if (error) { return FAIL; } @@ -7050,8 +7050,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) } } - retval = (int)do_searchpair(spat, mpat, epat, dir, skip, - flags, match_pos, lnum_stop, time_limit); + retval = do_searchpair(spat, mpat, epat, dir, skip, + flags, match_pos, lnum_stop, time_limit); theend: p_ws = save_p_ws; @@ -7096,12 +7096,12 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, EvalFuncData fpt /// @param time_limit stop after this many msec /// /// @returns 0 or -1 for no match, -long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, - const typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, - int64_t time_limit) +int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, + const typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, + int64_t time_limit) FUNC_ATTR_NONNULL_ARG(1, 2, 3) { - long retval = 0; + int retval = 0; int nest = 1; bool use_skip = false; int options = SEARCH_KEEP; @@ -7147,7 +7147,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir .sa_tm = &tm, }; - int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, + int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1, options, RE_SEARCH, &sia); if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) { // didn't find it or found the first match again: FAIL @@ -7489,7 +7489,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } /// Translate a register type string to the yank type and block length -static int get_yank_type(char **const pp, MotionType *const yank_type, long *const block_len) +static int get_yank_type(char **const pp, MotionType *const yank_type, int *const block_len) FUNC_ATTR_NONNULL_ALL { char *stropt = *pp; @@ -7507,7 +7507,7 @@ static int get_yank_type(char **const pp, MotionType *const yank_type, long *con *yank_type = kMTBlockWise; if (ascii_isdigit(stropt[1])) { stropt++; - *block_len = getdigits_long(&stropt, false, 0) - 1; + *block_len = getdigits_int(&stropt, false, 0) - 1; stropt--; } break; @@ -7523,7 +7523,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool append = false; - long block_len = -1; + int block_len = -1; MotionType yank_type = kMTUnknown; rettv->vval.v_number = 1; // FAIL is default. @@ -7735,11 +7735,11 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = 0; if (argvars[0].v_type != VAR_UNKNOWN) { - long col = (long)tv_get_number_chk(argvars, NULL); + colnr_T col = (colnr_T)tv_get_number_chk(argvars, NULL); if (col < 0) { return; // type error; errmsg already given } - rettv->vval.v_number = get_sw_value_col(curbuf, (colnr_T)col); + rettv->vval.v_number = get_sw_value_col(curbuf, col); return; } rettv->vval.v_number = get_sw_value(curbuf); -- cgit From 1c71c32b29100b3e2989447da9d94b97b2c9959e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 8 Nov 2023 06:29:58 +0800 Subject: fix(job-control): make jobwait() flush UI after hiding cursor (#25927) --- src/nvim/eval/funcs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 505a91813a..550d296093 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4187,6 +4187,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } ui_busy_start(); + ui_flush(); list_T *args = argvars[0].vval.v_list; Channel **jobs = xcalloc((size_t)tv_list_len(args), sizeof(*jobs)); MultiQueue *waiting_jobs = multiqueue_new_parent(loop_on_put, &main_loop); -- cgit From cd63a9addd6e1114c3524fa041ece560550cfe7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 08:39:21 +0800 Subject: refactor: change some xstrndup() and xstrnsave() to xmemdupz() (#25959) When the given length is exactly the number of bytes to copy, xmemdupz() makes the intention clearer. --- src/nvim/eval/funcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 550d296093..36d368a913 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5669,7 +5669,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl } if (prevlen == 0) { assert(len < INT_MAX); - s = xstrnsave(start, len); + s = xmemdupz(start, len); } else { // Change "prev" buffer to be the right size. This way // the bytes are only copied once, and very long lines are @@ -6305,7 +6305,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv) *rettv = (typval_T){ .v_type = VAR_STRING, .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), + .vval.v_string = xmemdupz(p, (size_t)len), }; p += len; } else if (tv_check_for_string_arg(argvars, 2) == FAIL) { @@ -6321,7 +6321,7 @@ static void reduce_string(typval_T *argvars, typval_T *expr, typval_T *rettv) argv[1] = (typval_T){ .v_type = VAR_STRING, .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), + .vval.v_string = xmemdupz(p, (size_t)len), }; const int r = eval_expr_typval(expr, true, argv, 2, rettv); -- cgit From d5a85d737aa2a5c3a64ef0aa5b01672b7ed49c09 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 15:24:36 +0800 Subject: fix(f_wait): flush UI before blocking (#25962) --- src/nvim/eval/funcs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 36d368a913..2d8ad458f1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2911,6 +2911,9 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) bool error = false; const int called_emsg_before = called_emsg; + // Flush screen updates before blocking. + ui_flush(); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, timeout, eval_expr_typval(&expr, false, &argv, 0, &exprval) != OK || tv_get_number_chk(&exprval, &error) -- cgit From e9b9a86cd5a555943b87f0ba40c4527561c3c124 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Nov 2023 10:21:14 +0800 Subject: fix(context): don't crash on invalid arg to nvim_get_context (#25977) Note: The crash happens in the second test case when using uninitialized memory, and therefore doesn't happen with ASAN. --- src/nvim/eval/funcs.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2d8ad458f1..6efd9733e5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -358,6 +358,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (!object_to_vim(result, rettv, &err)) { + assert(ERROR_SET(&err)); semsg(_("Error converting the call result: %s"), err.msg); } @@ -1024,7 +1025,7 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) Dictionary ctx_dict = ctx_to_dict(ctx); Error err = ERROR_INIT; - object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err); + (void)object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err); api_free_dictionary(ctx_dict); api_clear_error(&err); } @@ -1090,14 +1091,16 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - int save_did_emsg = did_emsg; + const int save_did_emsg = did_emsg; did_emsg = false; Dictionary dict = vim_to_object(&argvars[0]).data.dictionary; Context tmp = CONTEXT_INIT; - ctx_from_dict(dict, &tmp); + Error err = ERROR_INIT; + ctx_from_dict(dict, &tmp, &err); - if (did_emsg) { + if (ERROR_SET(&err)) { + semsg("%s", err.msg); ctx_free(&tmp); } else { ctx_free(ctx); @@ -1105,6 +1108,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } api_free_dictionary(dict); + api_clear_error(&err); did_emsg = save_did_emsg; } @@ -6753,6 +6757,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (!object_to_vim(result, rettv, &err)) { + assert(ERROR_SET(&err)); semsg(_("Error converting the call result: %s"), err.msg); } -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/eval/funcs.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6efd9733e5..c6909245af 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include @@ -4810,7 +4807,7 @@ static void f_min(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "mkdir()" function static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - int prot = 0755; // -V536 + int prot = 0755; rettv->vval.v_number = FAIL; if (check_secure()) { @@ -5732,9 +5729,9 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl // have to shuffle buf to close gap int adjust_prevlen = 0; - if (dest < buf) { // -V782 + if (dest < buf) { // adjust_prevlen must be 1 or 2. - adjust_prevlen = (int)(buf - dest); // -V782 + adjust_prevlen = (int)(buf - dest); dest = buf; } if (readlen > p - buf + 1) { -- cgit From b522cb1ac3fbdf6e68eed5d0b6e1cbeaf3ac2254 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 6 Nov 2023 14:52:27 +0100 Subject: refactor(grid): make screen rendering more multibyte than ever before Problem: buffer text with composing chars are converted from UTF-8 to an array of up to seven UTF-32 values and then converted back to UTF-8 strings. Solution: Convert buffer text directly to UTF-8 based schar_T values. The limit of the text size is now in schar_T bytes, which is currently 31+1 but easily could be raised as it no longer multiplies the size of the entire screen grid when not used, the full size is only required for temporary scratch buffers. Also does some general cleanup to win_line text handling, which was unnecessarily complicated due to multibyte rendering being an "opt-in" feature long ago. Nowadays, a char is just a char, regardless if it consists of one ASCII byte or multiple bytes. --- src/nvim/eval/funcs.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c6909245af..8ef208f291 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5134,7 +5134,7 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - char buf[MB_MAXBYTES]; + char buf[MB_MAXCHAR]; const int len = utf_char2bytes((int)num, buf); rettv->v_type = VAR_STRING; @@ -6891,7 +6891,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { c = -1; } else { - char buf[MB_MAXBYTES + 1]; + char buf[MAX_SCHAR_SIZE + 1]; schar_get(buf, grid_getchar(grid, row, col, NULL)); c = utf_ptr2char(buf); } @@ -6907,24 +6907,22 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ScreenGrid *grid; screenchar_adjust(&grid, &row, &col); + tv_list_alloc_ret(rettv, kListLenMayKnow); if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { - tv_list_alloc_ret(rettv, 0); return; } - char buf[MB_MAXBYTES + 1]; + char buf[MAX_SCHAR_SIZE + 1]; schar_get(buf, grid_getchar(grid, row, col, NULL)); - int pcc[MAX_MCO]; - int c = utfc_ptr2char(buf, pcc); - int composing_len = 0; - while (composing_len < MAX_MCO && pcc[composing_len] != 0) { - composing_len++; - } - tv_list_alloc_ret(rettv, composing_len + 1); - tv_list_append_number(rettv->vval.v_list, c); - for (int i = 0; i < composing_len; i++) { - tv_list_append_number(rettv->vval.v_list, pcc[i]); - } + + // schar values are already processed chars which are always NUL-terminated. + // A single [0] is expected when char is NUL. + size_t i = 0; + do { + int c = utf_ptr2char(buf + i); + tv_list_append_number(rettv->vval.v_list, c); + i += (size_t)utf_ptr2len(buf + i); + } while (buf[i] != NUL); } /// "screencol()" function @@ -6957,7 +6955,7 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr return; } - char buf[MB_MAXBYTES + 1]; + char buf[MAX_SCHAR_SIZE + 1]; schar_get(buf, grid_getchar(grid, row, col, NULL)); rettv->vval.v_string = xstrdup(buf); } @@ -7413,8 +7411,7 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fpt char *const csearch = tv_dict_get_string(d, "char", false); if (csearch != NULL) { - int pcc[MAX_MCO]; - const int c = utfc_ptr2char(csearch, pcc); + int c = utf_ptr2char(csearch); set_last_csearch(c, csearch, utfc_ptr2len(csearch)); } -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/eval/funcs.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8ef208f291..c370224476 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2897,8 +2897,8 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) int timeout = (int)argvars[0].vval.v_number; typval_T expr = argvars[1]; int interval = argvars[2].v_type == VAR_NUMBER - ? (int)argvars[2].vval.v_number - : 200; // Default. + ? (int)argvars[2].vval.v_number + : 200; // Default. TimeWatcher *tw = xmalloc(sizeof(TimeWatcher)); // Start dummy timer. @@ -5712,11 +5712,11 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl // Find the two bytes before the 0xbf. If p is at buf, or buf + 1, // these may be in the "prev" string. char back1 = p >= buf + 1 ? p[-1] - : prevlen >= 1 ? prev[prevlen - 1] : NUL; + : prevlen >= 1 ? prev[prevlen - 1] : NUL; char back2 = p >= buf + 2 ? p[-2] - : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] - : prevlen >= - 2 ? prev[prevlen - 2] : NUL; + : (p == buf + 1 && prevlen >= 1 + ? prev[prevlen - 1] + : prevlen >= 2 ? prev[prevlen - 2] : NUL); if ((uint8_t)back2 == 0xef && (uint8_t)back1 == 0xbb) { char *dest = p - 2; @@ -7914,10 +7914,11 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr tv_list_alloc_ret(rettv, 2); tv_list_append_string(rettv->vval.v_list, word, (ssize_t)len); tv_list_append_string(rettv->vval.v_list, - (attr == HLF_SPB ? "bad" : - attr == HLF_SPR ? "rare" : - attr == HLF_SPL ? "local" : - attr == HLF_SPC ? "caps" : NULL), -1); + (attr == HLF_SPB + ? "bad" : (attr == HLF_SPR + ? "rare" : (attr == HLF_SPL + ? "local" : (attr == HLF_SPC + ? "caps" : NULL)))), -1); } /// "spellsuggest()" function @@ -8410,8 +8411,8 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr cchar = syn_get_sub_char(); if (cchar == NUL && curwin->w_p_cole == 1) { cchar = (curwin->w_p_lcs_chars.conceal == NUL) - ? ' ' - : curwin->w_p_lcs_chars.conceal; + ? ' ' + : curwin->w_p_lcs_chars.conceal; } if (cchar != NUL) { utf_char2bytes(cchar, str); -- cgit From a827003e3052c6d9ee7bdb71518182e9bd76317d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 Nov 2023 11:32:32 +0100 Subject: build: rework IWYU mapping files Create mapping to most of the C spec and some POSIX specific functions. This is more robust than relying files shipped with IWYU. --- src/nvim/eval/funcs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c370224476..2e9dce8b5b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include -- cgit From 09541d514dd18bf86f673d3784d406236fcbdad8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 09:51:26 +0800 Subject: build(IWYU): replace public-to-public mappings with pragmas (#26237) --- src/nvim/eval/funcs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2e9dce8b5b..fca1534dfc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -82,7 +82,6 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/normal.h" #include "nvim/ops.h" -- cgit From 2c16c6a6c42f46e290df5441c37572f296aeb09f Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:43:13 +0100 Subject: docs: small fixes (#26154) --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index fca1534dfc..98deb7b32b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7440,7 +7440,7 @@ static void f_setenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char valbuf[NUMBUFLEN]; const char *name = tv_get_string_buf(&argvars[0], namebuf); - // seting an environment variable may be dangerous, e.g. you could + // setting an environment variable may be dangerous, e.g. you could // setenv GCONV_PATH=/tmp and then have iconv() unexpectedly call // a shell command using some shared library: if (check_secure()) { -- cgit From 38a20dd89f91c45ec8589bf1c50d50732882d38a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 20:58:37 +0800 Subject: build(IWYU): replace most private mappings with pragmas (#26247) --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 98deb7b32b..53fad45d04 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -90,7 +90,7 @@ #include "nvim/optionstr.h" #include "nvim/os/dl.h" #include "nvim/os/fileio.h" -#include "nvim/os/fs_defs.h" +#include "nvim/os/fs.h" #include "nvim/os/os.h" #include "nvim/os/pty_process.h" #include "nvim/os/shell.h" -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/eval/funcs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 53fad45d04..6ed992941a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -58,6 +58,7 @@ #include "nvim/ex_getln.h" #include "nvim/file_search.h" #include "nvim/fileio.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" -- cgit From f4aedbae4cb1f206f5b7c6142697b71dd473059b Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 18:39:38 +0100 Subject: build(IWYU): fix includes for undo_defs.h --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6ed992941a..56958224ca 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -100,7 +100,7 @@ #include "nvim/path.h" #include "nvim/plines.h" #include "nvim/popupmenu.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/profile.h" #include "nvim/regexp.h" #include "nvim/runtime.h" -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/eval/funcs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/eval/funcs.c') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 56958224ca..13425b21d1 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -24,8 +24,8 @@ #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" -#include "nvim/ascii.h" -#include "nvim/assert.h" +#include "nvim/ascii_defs.h" +#include "nvim/assert_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -72,7 +72,7 @@ #include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/math.h" @@ -114,7 +114,7 @@ #include "nvim/tag.h" #include "nvim/ui.h" #include "nvim/version.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" /// Describe data to return from find_some_match() -- cgit