From 543e0256c19f397921a332e06b423215fd9aecb5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 Nov 2023 15:51:05 +0800 Subject: build: don't define FUNC_ATTR_* as empty in headers (#26317) FUNC_ATTR_* should only be used in .c files with generated headers. Defining FUNC_ATTR_* as empty in headers causes misuses of them to be silently ignored. Instead don't define them by default, and only define them as empty after a .c file has included its generated header. --- src/nvim/eval.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index f4479d06a6..a43ca3d78a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -36,7 +36,6 @@ #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/ex_session.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" -- cgit From c8e37a589a4bffbdf374a5893ef269d2fe233ce6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 Nov 2023 19:52:23 +0800 Subject: refactor(IWYU): move typedefs out of globals.h (#26322) --- src/nvim/eval.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a43ca3d78a..de36bf016f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14,6 +14,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/channel.h" -- cgit From a6f26c86cb74222fe2449f8a035f29b0ee45c98e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 Nov 2023 22:48:15 +0800 Subject: refactor(IWYU): fix includes for cmdhist.h (#26324) --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index de36bf016f..6786316b8e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4548,7 +4548,7 @@ bool garbage_collect(bool testing) // history items (ShaDa additional elements) if (p_hi) { - for (HistoryType i = 0; i < HIST_COUNT; i++) { + for (int i = 0; i < HIST_COUNT; i++) { const void *iter = NULL; do { histentry_T hist; -- cgit From f6e5366d0077e9f171651f37282cb5c47629d1b6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 2 Dec 2023 07:55:44 +0800 Subject: refactor: free more reachable memory with EXITFREE (#26349) Discovered using __sanitizer_print_memory_profile(). --- src/nvim/eval.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6786316b8e..ae34f5715f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -500,6 +500,10 @@ static void evalvars_clear(void) p->vv_list = NULL; } } + + partial_unref(vvlua_partial); + vimvars[VV_LUA].vv_partial = vvlua_partial = NULL; + hash_clear(&vimvarht); hash_init(&vimvarht); // garbage_collect() will access it hash_clear(&compat_hashtab); -- cgit From 401ce9f3fdebed05a929de1b94e55c74d45e2ffb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 6 Dec 2023 15:48:16 +0800 Subject: vim-patch:8.1.1583: set_ref_in_list() only sets ref in items (#26418) Problem: Set_ref_in_list() only sets ref in items. Solution: Rename to set_ref_in_list_items() to avoid confusion. https://github.com/vim/vim/commit/7be3ab25891fec711d8a2d9d242711a9155852b6 Omit set_ref_in_list() and set_ref_in_dict(): only used in popup window, if_pyth and if_lua. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ae34f5715f..3ce6e98539 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4711,7 +4711,7 @@ bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack) /// @param ht_stack Used to add hashtabs to be marked. Can be NULL. /// /// @returns true if setting references failed somehow. -bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack) +bool set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack) FUNC_ATTR_WARN_UNUSED_RESULT { bool abort = false; @@ -4788,7 +4788,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack // Didn't see this list yet. ll->lv_copyID = copyID; if (list_stack == NULL) { - abort = set_ref_in_list(ll, copyID, ht_stack); + abort = set_ref_in_list_items(ll, copyID, ht_stack); } else { list_stack_T *const newitem = xmalloc(sizeof(list_stack_T)); newitem->list = ll; -- cgit From f22e9e10f9ad77d2cce7f52837c5724877505a08 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 6 Dec 2023 16:49:40 +0800 Subject: vim-patch:8.2.3695: confusing error for missing key (#26420) Problem: Confusing error for missing key. Solution: Use the actualy key for the error. (closes vim/vim#9241) https://github.com/vim/vim/commit/5c1ec439f0a69e9aa7ece9bbb7d916f48f58be1e Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3ce6e98539..ac1461056c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3735,7 +3735,11 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv dictitem_T *const item = tv_dict_find(rettv->vval.v_dict, key, keylen); if (item == NULL && verbose) { - semsg(_(e_dictkey), key); + if (keylen > 0) { + semsg(_(e_dictkey_len), keylen, key); + } else { + semsg(_(e_dictkey), key); + } } if (item == NULL || tv_is_luafunc(&item->di_tv)) { return FAIL; -- cgit From 9ae7d36ff5ebaf75597b442e10890bd77df01fbe Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 7 Dec 2023 00:40:48 +0600 Subject: refactor(options): split `get_option_value()` into smaller functions Problem: Currently, `get_option_value()` returns 3 separate things: The actual value of the option, whether the option is hidden, and the option flags. This makes the function difficult to refactor, modify or otherwise reason about. Solution: Split `get_option_value()` into 3 functions, each with a single purpose. This also affects `get_option_value_for()`. --- src/nvim/eval.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ac1461056c..16c1231682 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3784,37 +3784,32 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua } int ret = OK; - bool hidden; char c = *option_end; *option_end = NUL; - OptVal value = get_option_value(*arg, NULL, scope, &hidden); - if (rettv != NULL) { - switch (value.type) { - case kOptValTypeNil: + bool is_tty_opt = is_tty_option(*arg); + int opt_idx = is_tty_opt ? -1 : findoption(*arg); + + if (opt_idx < 0 && !is_tty_opt) { + // Only give error if result is going to be used. + if (rettv != NULL) { semsg(_("E113: Unknown option: %s"), *arg); - ret = FAIL; - break; - case kOptValTypeBoolean: - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = value.data.boolean; - break; - case kOptValTypeNumber: - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = value.data.number; - break; - case kOptValTypeString: - rettv->v_type = VAR_STRING; - rettv->vval.v_string = value.data.string.data; - break; } - } else { - // Value isn't being used, free it. - optval_free(value); - if (value.type == kOptValTypeNil || (working && hidden)) { - ret = FAIL; + ret = FAIL; + } else if (rettv != NULL) { + OptVal value = is_tty_opt ? get_tty_option(*arg) : get_option_value(opt_idx, scope); + assert(value.type != kOptValTypeNil); + + *rettv = optval_as_tv(value); + + // Convert boolean option value to number for backwards compatibility. + if (rettv->v_type == VAR_BOOL) { + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = rettv->vval.v_bool == kBoolVarTrue ? 1 : 0; } + } else if (working && !is_tty_opt && is_option_hidden(opt_idx)) { + ret = FAIL; } *option_end = c; // put back for error messages -- cgit From 2ebd328a798778825be61015acd975d8a929dfec Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 9 Dec 2023 11:36:11 +0800 Subject: refactor: format casting of negative number better (#26482) --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 16c1231682..2bbc8b58e7 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5029,7 +5029,7 @@ size_t string2float(const char *const text, float_T *const ret_value) return 3; } if (STRNICMP(text, "-inf", 3) == 0) { - *ret_value = (float_T) - INFINITY; + *ret_value = (float_T)(-INFINITY); return 4; } if (STRNICMP(text, "nan", 3) == 0) { -- cgit From 6346987601a28b00564295ee8be0a8b00d9ff911 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 7 Dec 2023 23:46:57 +0600 Subject: refactor(options): reduce `findoption()` usage Problem: Many places in the code use `findoption()` to access an option using its name, even if the option index is available. This is very slow because it requires looping through the options array over and over. Solution: Use option index instead of name wherever possible. Also introduce an `OptIndex` enum which contains the index for every option as enum constants, this eliminates the need to pass static option names as strings. --- src/nvim/eval.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2bbc8b58e7..1c30075991 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -681,7 +681,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to, set_vim_var_string(VV_CC_TO, enc_to, -1); set_vim_var_string(VV_FNAME_IN, fname_from, -1); set_vim_var_string(VV_FNAME_OUT, fname_to, -1); - sctx_T *ctx = get_option_sctx("charconvert"); + sctx_T *ctx = get_option_sctx(kOptCharconvert); if (ctx != NULL) { current_sctx = *ctx; } @@ -710,7 +710,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char set_vim_var_string(VV_FNAME_NEW, newfile, -1); set_vim_var_string(VV_FNAME_OUT, outfile, -1); - sctx_T *ctx = get_option_sctx("diffexpr"); + sctx_T *ctx = get_option_sctx(kOptDiffexpr); if (ctx != NULL) { current_sctx = *ctx; } @@ -732,7 +732,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch set_vim_var_string(VV_FNAME_DIFF, difffile, -1); set_vim_var_string(VV_FNAME_OUT, outfile, -1); - sctx_T *ctx = get_option_sctx("patchexpr"); + sctx_T *ctx = get_option_sctx(kOptPatchexpr); if (ctx != NULL) { current_sctx = *ctx; } @@ -1134,7 +1134,7 @@ list_T *eval_spell_expr(char *badword, char *expr) if (p_verbose == 0) { emsg_off++; } - sctx_T *ctx = get_option_sctx("spellsuggest"); + sctx_T *ctx = get_option_sctx(kOptSpellsuggest); if (ctx != NULL) { current_sctx = *ctx; } @@ -1278,7 +1278,7 @@ void *call_func_retlist(const char *func, int argc, typval_T *argv) int eval_foldexpr(win_T *wp, int *cp) { const sctx_T saved_sctx = current_sctx; - const bool use_sandbox = was_set_insecurely(wp, "foldexpr", OPT_LOCAL); + const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL); char *arg = wp->w_p_fde; current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx; @@ -1326,7 +1326,7 @@ int eval_foldexpr(win_T *wp, int *cp) /// Evaluate 'foldtext', returning an Array or a String (NULL_STRING on failure). Object eval_foldtext(win_T *wp) { - const bool use_sandbox = was_set_insecurely(wp, "foldtext", OPT_LOCAL); + const bool use_sandbox = was_set_insecurely(wp, kOptFoldtext, OPT_LOCAL); char *arg = wp->w_p_fdt; funccal_entry_T funccal_entry; @@ -8715,7 +8715,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char // 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", CSTR_AS_OPTVAL(save_cpo), 0); + set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0); } free_string_option(save_cpo); } -- cgit From bf3bc1cec9f00b9644815001a8732ecedf3ce07f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 7 Dec 2023 23:59:30 +0600 Subject: refactor(options): convert `opt_idx` variables to `OptIndex` --- src/nvim/eval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1c30075991..1fdaa95076 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3788,9 +3788,9 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua *option_end = NUL; bool is_tty_opt = is_tty_option(*arg); - int opt_idx = is_tty_opt ? -1 : findoption(*arg); + OptIndex opt_idx = is_tty_opt ? kOptInvalid : findoption(*arg); - if (opt_idx < 0 && !is_tty_opt) { + if (opt_idx == kOptInvalid && !is_tty_opt) { // Only give error if result is going to be used. if (rettv != NULL) { semsg(_("E113: Unknown option: %s"), *arg); -- cgit From 3c2c022e5e299ecac4663c3813e2db5e2b099ffa Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 7 Dec 2023 01:34:29 +0600 Subject: refactor(options): remove option type macros Problem: We have `P_(BOOL|NUM|STRING)` macros to represent an option's type, which is redundant because `OptValType` can already do that. The current implementation of option type flags is also too limited to allow adding multitype options in the future. Solution: Remove `P_(BOOL|NUM|STRING)` and replace it with a new `type_flags` attribute in `vimoption_T`. Also do some groundwork for adding multitype options in the future. Side-effects: Attempting to set an invalid keycode option (e.g. `set t_foo=123`) no longer gives an error. --- src/nvim/eval.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1fdaa95076..11c6034cc8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3767,10 +3767,12 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua FUNC_ATTR_NONNULL_ARG(1) { const bool working = (**arg == '+'); // has("+option") + OptIndex opt_idx; int scope; // Isolate the option name and find its value. - char *option_end = (char *)find_option_end(arg, &scope); + char *const option_end = (char *)find_option_var_end(arg, &opt_idx, &scope); + if (option_end == NULL) { if (rettv != NULL) { semsg(_("E112: Option name missing: %s"), *arg); @@ -3783,12 +3785,11 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua return OK; } - int ret = OK; char c = *option_end; *option_end = NUL; + int ret = OK; bool is_tty_opt = is_tty_option(*arg); - OptIndex opt_idx = is_tty_opt ? kOptInvalid : findoption(*arg); if (opt_idx == kOptInvalid && !is_tty_opt) { // Only give error if result is going to be used. @@ -3801,13 +3802,7 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua OptVal value = is_tty_opt ? get_tty_option(*arg) : get_option_value(opt_idx, scope); assert(value.type != kOptValTypeNil); - *rettv = optval_as_tv(value); - - // Convert boolean option value to number for backwards compatibility. - if (rettv->v_type == VAR_BOOL) { - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = rettv->vval.v_bool == kBoolVarTrue ? 1 : 0; - } + *rettv = optval_as_tv(value, true); } else if (working && !is_tty_opt && is_option_hidden(opt_idx)) { ret = FAIL; } @@ -8138,13 +8133,14 @@ void ex_execute(exarg_T *eap) eap->nextcmd = check_nextcmd(arg); } -/// Skip over the name of an option: "&option", "&g:option" or "&l:option". +/// Skip over the name of an option variable: "&option", "&g:option" or "&l:option". /// -/// @param arg points to the "&" or '+' when called, to "option" when returning. +/// @param[in,out] arg Points to the "&" or '+' when called, to "option" when returning. +/// @param[out] opt_idxp Set to option index in options[] table. +/// @param[out] scope Set to option scope. /// -/// @return NULL when no option name found. Otherwise pointer to the char -/// after the option name. -const char *find_option_end(const char **const arg, int *const scope) +/// @return NULL when no option name found. Otherwise pointer to the char after the option name. +const char *find_option_var_end(const char **const arg, OptIndex *const opt_idxp, int *const scope) { const char *p = *arg; @@ -8159,19 +8155,9 @@ const char *find_option_end(const char **const arg, int *const scope) *scope = 0; } - if (!ASCII_ISALPHA(*p)) { - return NULL; - } - *arg = p; - - if (p[0] == 't' && p[1] == '_' && p[2] != NUL && p[3] != NUL) { - p += 4; // t_xx/termcap option - } else { - while (ASCII_ISALPHA(*p)) { - p++; - } - } - return p; + const char *end = find_option_end(p, opt_idxp); + *arg = end == NULL ? *arg : p; + return end; } static var_flavour_T var_flavour(char *varname) -- cgit From 69bc519b53ebf78fd95c8256468e7d538ebcb948 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 12 Dec 2023 15:40:21 +0100 Subject: refactor: move non-symbols to defs.h headers --- src/nvim/eval.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 11c6034cc8..d8134c2360 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -32,6 +32,7 @@ #include "nvim/eval/vars.h" #include "nvim/event/multiqueue.h" #include "nvim/event/process.h" +#include "nvim/event/time.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" -- cgit From 6cb78e2d1c4c6c63c628c965076a07ce5f7adbb6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 16 Dec 2023 22:14:28 +0100 Subject: docs: add style rule regarding initialization Specifically, specify that each initialization should be done on a separate line. --- src/nvim/eval.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d8134c2360..7d869881e8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2863,7 +2863,8 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) } else { bool error = false; varnumber_T n1, n2; - float_T f1 = 0, f2 = 0; + float_T f1 = 0; + float_T f2 = 0; if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; @@ -2954,7 +2955,8 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan } varnumber_T n1, n2; - float_T f1 = 0, f2 = 0; + float_T f1 = 0; + float_T f2 = 0; bool error = false; const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); if (evaluate) { -- cgit From 7f6b775b45de5011ff1c44e63e57551566d80704 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 16 Dec 2023 22:14:28 +0100 Subject: refactor: use `bool` to represent boolean values --- src/nvim/eval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7d869881e8..21bb325e37 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -564,7 +564,7 @@ static char *redir_varname = NULL; /// @param append append to an existing variable /// /// @return OK if successfully completed the setup. FAIL otherwise. -int var_redir_start(char *name, int append) +int var_redir_start(char *name, bool append) { // Catch a bad name early. if (!eval_isnamec1(*name)) { @@ -765,7 +765,7 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) /// @param skip only parse, don't execute /// /// @return true or false. -int eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) +bool eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) { typval_T tv; bool retval = false; -- cgit From 8533adb4844b771b84dac2141fa2fa60e0487b47 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 21 Dec 2023 16:50:05 +0800 Subject: refactor(IWYU): move decor provider types to decoration_defs.h (#26692) --- src/nvim/eval.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 21bb325e37..d12a49e7d4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -16,7 +16,6 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" -#include "nvim/buffer_defs.h" #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" -- cgit From af93a74a0f4afa9a3a4f55ffdf28141eaf776d22 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 18 Dec 2023 10:55:23 +0100 Subject: refactor: run IWYU on entire repo Reference: https://github.com/neovim/neovim/issues/6371. --- src/nvim/eval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d12a49e7d4..68347fd582 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7,11 +7,10 @@ #include #include #include -#include +#include #include "auto/config.h" #include "nvim/api/private/converter.h" -#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" @@ -29,6 +28,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" +#include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/event/process.h" #include "nvim/event/time.h" -- cgit From 6700127b30d55e6ddf70495e7b886464172d7ac6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 22 Dec 2023 10:33:34 +0800 Subject: vim-patch:9.0.2183: Maximum callback depth is not configurable (#26703) Problem: Maximum callback depth is not configurable. Solution: Revert patch 9.0.2103. Set 'maxfuncdepth' in test. fixes: vim/vim#13732 closes: vim/vim#13736 https://github.com/vim/vim/commit/fe583b1e5987fbfdb5f2141c133dbff9665ed301 --- src/nvim/eval.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 68347fd582..3818944fc9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -89,8 +89,6 @@ #define DICT_MAXNEST 100 // maximum nesting of lists and dicts -#define MAX_CALLBACK_DEPTH 20 - static const char *e_missbrac = N_("E111: Missing ']'"); static const char *e_list_end = N_("E697: Missing end of List ']': %s"); static const char e_cannot_slice_dictionary[] @@ -6061,7 +6059,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co typval_T *const rettv) FUNC_ATTR_NONNULL_ALL { - if (callback_depth > MAX_CALLBACK_DEPTH) { + if (callback_depth > p_mfd) { emsg(_(e_command_too_recursive)); return false; } -- cgit From 242261d4e77806cdb4559c2be58613113a393a4e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 23 Dec 2023 08:28:17 +0800 Subject: refactor(IWYU): move evalarg_T to eval_defs.h (#26716) --- src/nvim/eval.c | 89 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 88 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3818944fc9..43aeda06ef 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -36,7 +36,6 @@ #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" -#include "nvim/ex_session.h" #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" @@ -8160,7 +8159,7 @@ const char *find_option_var_end(const char **const arg, OptIndex *const opt_idxp return end; } -static var_flavour_T var_flavour(char *varname) +var_flavour_T var_flavour(char *varname) FUNC_ATTR_PURE { char *p = varname; @@ -8176,48 +8175,6 @@ static var_flavour_T var_flavour(char *varname) return VAR_FLAVOUR_DEFAULT; } -/// Iterate over global variables -/// -/// @warning No modifications to global variable dictionary must be performed -/// while iteration is in progress. -/// -/// @param[in] iter Iterator. Pass NULL to start iteration. -/// @param[out] name Variable name. -/// @param[out] rettv Variable value. -/// -/// @return Pointer that needs to be passed to next `var_shada_iter` invocation -/// or NULL to indicate that iteration is over. -const void *var_shada_iter(const void *const iter, const char **const name, typval_T *rettv, - var_flavour_T flavour) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3) -{ - const hashitem_T *hi; - const hashitem_T *hifirst = globvarht.ht_array; - const size_t hinum = (size_t)globvarht.ht_mask + 1; - *name = NULL; - if (iter == NULL) { - hi = globvarht.ht_array; - while ((size_t)(hi - hifirst) < hinum - && (HASHITEM_EMPTY(hi) - || !(var_flavour(hi->hi_key) & flavour))) { - hi++; - } - if ((size_t)(hi - hifirst) == hinum) { - return NULL; - } - } else { - hi = (const hashitem_T *)iter; - } - *name = TV_DICT_HI2DI(hi)->di_key; - tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv); - while ((size_t)(++hi - hifirst) < hinum) { - if (!HASHITEM_EMPTY(hi) && (var_flavour(hi->hi_key) & flavour)) { - return hi; - } - } - return NULL; -} - void var_set_global(const char *const name, typval_T vartv) { funccal_entry_T funccall_entry; @@ -8227,50 +8184,6 @@ void var_set_global(const char *const name, typval_T vartv) restore_funccal(); } -int store_session_globals(FILE *fd) -{ - TV_DICT_ITER(&globvardict, this_var, { - if ((this_var->di_tv.v_type == VAR_NUMBER - || this_var->di_tv.v_type == VAR_STRING) - && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) { - // Escape special characters with a backslash. Turn a LF and - // CR into \n and \r. - char *const p = vim_strsave_escaped(tv_get_string(&this_var->di_tv), "\\\"\n\r"); - for (char *t = p; *t != NUL; t++) { - if (*t == '\n') { - *t = 'n'; - } else if (*t == '\r') { - *t = 'r'; - } - } - if ((fprintf(fd, "let %s = %c%s%c", - this_var->di_key, - ((this_var->di_tv.v_type == VAR_STRING) ? '"' : ' '), - p, - ((this_var->di_tv.v_type == VAR_STRING) ? '"' : ' ')) < 0) - || put_eol(fd) == FAIL) { - xfree(p); - return FAIL; - } - xfree(p); - } else if (this_var->di_tv.v_type == VAR_FLOAT - && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) { - float_T f = this_var->di_tv.vval.v_float; - int sign = ' '; - - if (f < 0) { - f = -f; - sign = '-'; - } - if ((fprintf(fd, "let %s = %c%f", this_var->di_key, sign, f) < 0) - || put_eol(fd) == FAIL) { - return FAIL; - } - } - }); - return OK; -} - /// Display script name where an item was last set. /// Should only be invoked when 'verbose' is non-zero. void last_set_msg(sctx_T script_ctx) -- cgit From 2ff2785c396e66c285fecf5b151d8f8863f9d4e6 Mon Sep 17 00:00:00 2001 From: Pablo Arias Date: Mon, 25 Dec 2023 01:30:56 +0100 Subject: feat(health): checkhealth buffer can show in a split window (#26714) :checkhealth now respects :vertical and :horizontal. For example: :vertical checkhealth foo bar will open the healthcheck buffer in a vertical split. --- src/nvim/eval.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 43aeda06ef..a1ac1de1df 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8814,7 +8814,14 @@ void eval_fmt_source_name_line(char *buf, size_t bufsize) void ex_checkhealth(exarg_T *eap) { Error err = ERROR_INIT; - MAXSIZE_TEMP_ARRAY(args, 1); + MAXSIZE_TEMP_ARRAY(args, 2); + if (cmdmod.cmod_split & WSP_VERT) { + ADD_C(args, CSTR_AS_OBJ("vertical")); + } else if (cmdmod.cmod_split & WSP_HOR) { + ADD_C(args, CSTR_AS_OBJ("horizontal")); + } else { + ADD_C(args, CSTR_AS_OBJ("tab")); + } ADD_C(args, CSTR_AS_OBJ(eap->arg)); NLUA_EXEC_STATIC("return vim.health._check(...)", args, &err); if (!ERROR_SET(&err)) { -- cgit From 2877672d70e76f71ae1190090b8aea7044d458be Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Dec 2023 10:21:13 +0800 Subject: feat(health): make :checkhealth support more split modifiers (#26731) --- src/nvim/eval.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a1ac1de1df..540c10e494 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8810,39 +8810,6 @@ void eval_fmt_source_name_line(char *buf, size_t bufsize) } } -/// ":checkhealth [plugins]" -void ex_checkhealth(exarg_T *eap) -{ - Error err = ERROR_INIT; - MAXSIZE_TEMP_ARRAY(args, 2); - if (cmdmod.cmod_split & WSP_VERT) { - ADD_C(args, CSTR_AS_OBJ("vertical")); - } else if (cmdmod.cmod_split & WSP_HOR) { - ADD_C(args, CSTR_AS_OBJ("horizontal")); - } else { - ADD_C(args, CSTR_AS_OBJ("tab")); - } - ADD_C(args, CSTR_AS_OBJ(eap->arg)); - NLUA_EXEC_STATIC("return vim.health._check(...)", args, &err); - if (!ERROR_SET(&err)) { - return; - } - - const char *vimruntime_env = os_getenv("VIMRUNTIME"); - if (vimruntime_env == NULL) { - emsg(_("E5009: $VIMRUNTIME is empty or unset")); - } else { - bool rtp_ok = NULL != strstr(p_rtp, vimruntime_env); - if (rtp_ok) { - semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env); - } else { - emsg(_("E5009: Invalid 'runtimepath'")); - } - } - semsg_multiline(err.msg); - api_clear_error(&err); -} - void invoke_prompt_callback(void) { typval_T rettv; -- cgit From c89292fcb7f2ebf06efb7c1d00c28f34c6f68fec Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 28 Dec 2023 13:42:24 +0100 Subject: refactor: follow style guide --- src/nvim/eval.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 540c10e494..5069f00df0 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -529,7 +529,7 @@ void eval_clear(void) free_autoload_scriptnames(); // unreferenced lists and dicts - (void)garbage_collect(false); + garbage_collect(false); // functions not garbage collected free_all_functions(); @@ -761,7 +761,7 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) /// @param skip only parse, don't execute /// /// @return true or false. -bool eval_to_bool(char *arg, bool *error, exarg_T *eap, int skip) +bool eval_to_bool(char *arg, bool *error, exarg_T *eap, bool skip) { typval_T tv; bool retval = false; @@ -1726,7 +1726,7 @@ void clear_lval(lval_T *lp) /// @param endp points to just after the parsed name. /// @param op NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=", /// "%" for "%=", "." for ".=" or "=" for "=". -void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool is_const, +void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, bool copy, const bool is_const, const char *op) { int cc; @@ -1795,8 +1795,8 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool return; } - (void)tv_list_assign_range(lp->ll_list, rettv->vval.v_list, - lp->ll_n1, lp->ll_n2, lp->ll_empty2, op, lp->ll_name); + tv_list_assign_range(lp->ll_list, rettv->vval.v_list, + lp->ll_n1, lp->ll_n2, lp->ll_empty2, op, lp->ll_name); } else { typval_T oldtv = TV_INITIAL_VALUE; dict_T *dict = lp->ll_dict; @@ -8585,9 +8585,9 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char int i = (int)(regmatch.startp[0] - tail); memmove((char *)ga.ga_data + ga.ga_len, tail, (size_t)i); // add the substituted text - (void)vim_regsub(®match, sub, expr, - (char *)ga.ga_data + ga.ga_len + i, sublen, - REGSUB_COPY | REGSUB_MAGIC); + vim_regsub(®match, sub, expr, + (char *)ga.ga_data + ga.ga_len + i, sublen, + REGSUB_COPY | REGSUB_MAGIC); ga.ga_len += i + sublen - 1; tail = regmatch.endp[0]; if (*tail == NUL) { @@ -8727,7 +8727,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments, boo funcexe.fe_firstline = curwin->w_cursor.lnum; funcexe.fe_lastline = curwin->w_cursor.lnum; funcexe.fe_evaluate = true; - (void)call_func(func, name_len, &rettv, 2, argvars, &funcexe); + call_func(func, name_len, &rettv, 2, argvars, &funcexe); tv_list_unref(arguments); // Restore caller scope information -- cgit From beca827212b106114c371f8bb61aa1a50810062f Mon Sep 17 00:00:00 2001 From: Ghjuvan Lacambre Date: Tue, 9 Jan 2024 15:27:56 +0100 Subject: feat(terminal): trigger TermRequest autocommand events (#22159) This commit implements a new TermRequest autocommand event and has Neovim emit this event when children of terminal buffers emit an OSC or DCS sequence libvterm does not handle. The TermRequest autocommand event has additional data in the v:termrequest variable. Co-authored-by: Gregory Anders --- src/nvim/eval.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5069f00df0..451e258356 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -185,6 +185,7 @@ static struct vimvar { VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT + VV_RO), VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX), VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO), + VV(VV_TERMREQUEST, "termrequest", VAR_STRING, VV_RO), VV(VV_FNAME, "fname", VAR_STRING, VV_RO), VV(VV_LANG, "lang", VAR_STRING, VV_RO), VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO), -- cgit From 1813661a6197c76ea6621284570aca1d56597099 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 4 Jan 2024 15:38:16 +0100 Subject: refactor(IWYU): fix headers Remove `export` pramgas from defs headers as it causes IWYU to believe that the definitions from the defs headers comes from main header, which is not what we really want. --- src/nvim/eval.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 451e258356..5826316828 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11,10 +11,12 @@ #include "auto/config.h" #include "nvim/api/private/converter.h" +#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" @@ -37,20 +39,22 @@ #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" -#include "nvim/gettext.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/grid_defs.h" #include "nvim/hashtab.h" #include "nvim/highlight_group.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" -#include "nvim/lib/queue.h" +#include "nvim/lib/queue_defs.h" #include "nvim/lua/executor.h" #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/map_defs.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -63,8 +67,10 @@ #include "nvim/optionstr.h" #include "nvim/os/fileio.h" #include "nvim/os/fs.h" +#include "nvim/os/fs_defs.h" #include "nvim/os/lang.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/os/stdpaths_defs.h" #include "nvim/path.h" @@ -72,13 +78,16 @@ #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/regexp_defs.h" #include "nvim/runtime.h" +#include "nvim/runtime_defs.h" #include "nvim/search.h" #include "nvim/strings.h" #include "nvim/tag.h" #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/ui_compositor.h" +#include "nvim/ui_defs.h" #include "nvim/usercmd.h" #include "nvim/version.h" #include "nvim/vim_defs.h" -- cgit From a34451982fe661fcfb6082607a8cf4c22ff51577 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 16 Jan 2024 09:32:57 +0800 Subject: vim-patch:8.1.1968: crash when using nested map() (#27029) Problem: Crash when using nested map(). Solution: Clear the pointer in prepare_vimvar(). (Ozaki Kiichi, closes vim/vim#4890, closes vim/vim#4891) https://github.com/vim/vim/commit/27da7de7c547dbf983ed7dd901ea59be4e7c9ab2 Cherry-pick Test_filter_map_nested() from patch 8.1.1964. Co-authored-by: Bram Moolenaar --- src/nvim/eval.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5826316828..ad2ff89f7e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1095,17 +1095,19 @@ bool is_compatht(const hashtab_T *ht) } /// Prepare v: variable "idx" to be used. -/// Save the current typeval in "save_tv". +/// Save the current typeval in "save_tv" and clear it. /// When not used yet add the variable to the v: hashtable. void prepare_vimvar(int idx, typval_T *save_tv) { *save_tv = vimvars[idx].vv_tv; + vimvars[idx].vv_str = NULL; // don't free it now if (vimvars[idx].vv_type == VAR_UNKNOWN) { hash_add(&vimvarht, vimvars[idx].vv_di.di_key); } } /// Restore v: variable "idx" to typeval "save_tv". +/// Note that the v: variable must have been cleared already. /// When no longer defined, remove the variable from the v: hashtable. void restore_vimvar(int idx, typval_T *save_tv) { -- cgit From 46a7c1b3193d1f4ba09cd66ce03a1e2340d324a7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 16 Jan 2024 11:30:35 +0800 Subject: vim-patch:partial:9.1.0027: Vim is missing a foreach() func (#27037) Problem: Vim is missing a foreach() func Solution: Implement foreach({expr1}, {expr2}) function, which applies {expr2} for each item in {expr1} without changing it (Ernie Rael) closes: vim/vim#12166 https://github.com/vim/vim/commit/e79e2077607e8f829ba823308c91104a795736ba Partial port as this doesn't handle non-materialized range() lists. vim-patch:c92b8bed1fa6 runtime(help): delete duplicate help tag E741 (vim/vim#13861) https://github.com/vim/vim/commit/c92b8bed1fa632569c8358feb3b72dd6a0844ef7 Co-authored-by: Ernie Rael --- src/nvim/eval.c | 79 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 25 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ad2ff89f7e..faa652f80a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -308,11 +308,12 @@ static partial_T *vvlua_partial; /// v: hashtab #define vimvarht vimvardict.dv_hashtab -/// Enum used by filter(), map() and mapnew() +/// Enum used by filter(), map(), mapnew() and foreach() typedef enum { FILTERMAP_FILTER, FILTERMAP_MAP, FILTERMAP_MAPNEW, + FILTERMAP_FOREACH, } filtermap_T; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -5098,7 +5099,8 @@ void assert_error(garray_T *gap) tv_list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, (ptrdiff_t)gap->ga_len); } -/// Implementation of map() and filter() for a Dict. +/// Implementation of map(), filter(), foreach() for a Dict. Apply "expr" to +/// every item in Dict "d" and return the result in "rettv". static void filter_map_dict(dict_T *d, filtermap_T filtermap, const char *func_name, const char *arg_errmsg, typval_T *expr, typval_T *rettv) { @@ -5166,7 +5168,7 @@ static void filter_map_dict(dict_T *d, filtermap_T filtermap, const char *func_n d->dv_lock = prev_lock; } -/// Implementation of map() and filter() for a Blob. +/// Implementation of map(), filter(), foreach() for a Blob. static void filter_map_blob(blob_T *blob_arg, filtermap_T filtermap, typval_T *expr, const char *arg_errmsg, typval_T *rettv) { @@ -5209,20 +5211,22 @@ static void filter_map_blob(blob_T *blob_arg, filtermap_T filtermap, typval_T *e || did_emsg) { break; } - if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL) { - tv_clear(&newtv); - emsg(_(e_invalblob)); - break; - } - if (filtermap != FILTERMAP_FILTER) { - if (newtv.vval.v_number != val) { - tv_blob_set(b_ret, i, (uint8_t)newtv.vval.v_number); + if (filtermap != FILTERMAP_FOREACH) { + if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL) { + tv_clear(&newtv); + emsg(_(e_invalblob)); + break; + } + if (filtermap != FILTERMAP_FILTER) { + if (newtv.vval.v_number != val) { + tv_blob_set(b_ret, i, (uint8_t)newtv.vval.v_number); + } + } else if (rem) { + char *const p = (char *)blob_arg->bv_ga.ga_data; + memmove(p + i, p + i + 1, (size_t)(b->bv_ga.ga_len - i - 1)); + b->bv_ga.ga_len--; + i--; } - } else if (rem) { - char *const p = (char *)blob_arg->bv_ga.ga_data; - memmove(p + i, p + i + 1, (size_t)(b->bv_ga.ga_len - i - 1)); - b->bv_ga.ga_len--; - i--; } idx++; } @@ -5230,7 +5234,7 @@ static void filter_map_blob(blob_T *blob_arg, filtermap_T filtermap, typval_T *e b->bv_lock = prev_lock; } -/// Implementation of map() and filter() for a String. +/// Implementation of map(), filter(), foreach() for a String. static void filter_map_string(const char *str, filtermap_T filtermap, typval_T *expr, typval_T *rettv) { @@ -5259,7 +5263,8 @@ static void filter_map_string(const char *str, filtermap_T filtermap, typval_T * tv_clear(&newtv); tv_clear(&tv); break; - } else if (filtermap != FILTERMAP_FILTER) { + } + if (filtermap == FILTERMAP_MAP || filtermap == FILTERMAP_MAPNEW) { if (newtv.v_type != VAR_STRING) { tv_clear(&newtv); tv_clear(&tv); @@ -5268,7 +5273,7 @@ static void filter_map_string(const char *str, filtermap_T filtermap, typval_T * } else { ga_concat(&ga, newtv.vval.v_string); } - } else if (!rem) { + } else if (filtermap == FILTERMAP_FOREACH || !rem) { ga_concat(&ga, tv.vval.v_string); } @@ -5281,7 +5286,8 @@ static void filter_map_string(const char *str, filtermap_T filtermap, typval_T * rettv->vval.v_string = ga.ga_data; } -/// Implementation of map() and filter() for a List. +/// Implementation of map(), filter(), foreach() for a List. Apply "expr" to +/// every item in List "l" and return the result in "rettv". static void filter_map_list(list_T *l, filtermap_T filtermap, const char *func_name, const char *arg_errmsg, typval_T *expr, typval_T *rettv) { @@ -5345,21 +5351,25 @@ static void filter_map_list(list_T *l, filtermap_T filtermap, const char *func_n tv_list_set_lock(l, prev_lock); } -/// Implementation of map() and filter(). +/// Implementation of map(), filter() and foreach(). static void filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap) { const char *const func_name = (filtermap == FILTERMAP_MAP ? "map()" : (filtermap == FILTERMAP_MAPNEW ? "mapnew()" - : "filter()")); + : (filtermap == FILTERMAP_FILTER + ? "filter()" + : "foreach()"))); const char *const arg_errmsg = (filtermap == FILTERMAP_MAP ? N_("map() argument") : (filtermap == FILTERMAP_MAPNEW ? N_("mapnew() argument") - : N_("filter() argument"))); + : (filtermap == FILTERMAP_FILTER + ? N_("filter() argument") + : N_("foreach() argument")))); - // map() and filter() return the first argument, also on failure. + // map(), filter(), foreach() return the first argument, also on failure. if (filtermap != FILTERMAP_MAPNEW && argvars[0].v_type != VAR_STRING) { tv_copy(&argvars[0], rettv); } @@ -5407,7 +5417,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap } } -/// Handle one item for map() and filter(). +/// Handle one item for map(), filter(), foreach(). /// Sets v:val to "tv". Caller must set v:key. /// /// @param tv original value @@ -5422,6 +5432,17 @@ static int filter_map_one(typval_T *tv, typval_T *expr, const filtermap_T filter int retval = FAIL; tv_copy(tv, &vimvars[VV_VAL].vv_tv); + + newtv->v_type = VAR_UNKNOWN; + if (filtermap == FILTERMAP_FOREACH && expr->v_type == VAR_STRING) { + // foreach() is not limited to an expression + do_cmdline_cmd(expr->vval.v_string); + if (!did_emsg) { + retval = OK; + } + goto theend; + } + argv[0] = vimvars[VV_KEY].vv_tv; argv[1] = vimvars[VV_VAL].vv_tv; if (eval_expr_typval(expr, false, argv, 2, newtv) == FAIL) { @@ -5438,6 +5459,8 @@ static int filter_map_one(typval_T *tv, typval_T *expr, const filtermap_T filter if (error) { goto theend; } + } else if (filtermap == FILTERMAP_FOREACH) { + tv_clear(newtv); } retval = OK; theend: @@ -5463,6 +5486,12 @@ void f_mapnew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) filter_map(argvars, rettv, FILTERMAP_MAPNEW); } +/// "foreach()" function +void f_foreach(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + filter_map(argvars, rettv, FILTERMAP_FOREACH); +} + /// "function()" function /// "funcref()" function void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) -- cgit From 1f40b4e22232f22551a9ae89a9f8d59b5ba0c0b6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 3 Feb 2024 09:42:04 +0800 Subject: vim-patch:9.0.1105: code is indented too much (#27314) Problem: Code is indented too much. Solution: Use an early return. (Yegappan Lakshmanan, closes vim/vim#11756) https://github.com/vim/vim/commit/87c1cbbe984e60582f2536e4d3c2ce88cd474bb7 Omit free_eval_tofree_later(): Vim9 script only. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval.c | 90 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 38 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index faa652f80a..5053cc38de 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -758,11 +758,14 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) { *evalarg = (evalarg_T){ .eval_flags = skip ? 0 : EVAL_EVALUATE }; - if (eap != NULL) { - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg->eval_getline = eap->getline; - evalarg->eval_cookie = eap->cookie; - } + + if (eap == NULL) { + return; + } + + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + evalarg->eval_getline = eap->getline; + evalarg->eval_cookie = eap->cookie; } } @@ -2326,20 +2329,22 @@ static int eval_func(char **const arg, evalarg_T *const evalarg, char *const nam /// After using "evalarg" filled from "eap": free the memory. void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) { - if (evalarg != NULL) { - if (evalarg->eval_tofree != NULL) { - if (eap != NULL) { - // We may need to keep the original command line, e.g. for - // ":let" it has the variable names. But we may also need the - // new one, "nextcmd" points into it. Keep both. - xfree(eap->cmdline_tofree); - eap->cmdline_tofree = *eap->cmdlinep; - *eap->cmdlinep = evalarg->eval_tofree; - } else { - xfree(evalarg->eval_tofree); - } - evalarg->eval_tofree = NULL; + if (evalarg == NULL) { + return; + } + + if (evalarg->eval_tofree != NULL) { + if (eap != NULL) { + // We may need to keep the original command line, e.g. for + // ":let" it has the variable names. But we may also need the + // new one, "nextcmd" points into it. Keep both. + xfree(eap->cmdline_tofree); + eap->cmdline_tofree = *eap->cmdlinep; + *eap->cmdlinep = evalarg->eval_tofree; + } else { + xfree(evalarg->eval_tofree); } + evalarg->eval_tofree = NULL; } } @@ -3626,12 +3631,14 @@ static int check_can_index(typval_T *rettv, bool evaluate, bool verbose) /// slice() function void f_slice(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (check_can_index(argvars, true, false) == OK) { - tv_copy(argvars, rettv); - eval_index_inner(rettv, true, argvars + 1, - argvars[2].v_type == VAR_UNKNOWN ? NULL : argvars + 2, - true, NULL, 0, false); + if (check_can_index(argvars, true, false) != OK) { + return; } + + tv_copy(argvars, rettv); + eval_index_inner(rettv, true, argvars + 1, + argvars[2].v_type == VAR_UNKNOWN ? NULL : argvars + 2, + true, NULL, 0, false); } /// Apply index or range to "rettv". @@ -4248,7 +4255,11 @@ static void partial_free(partial_T *pt) /// becomes zero. void partial_unref(partial_T *pt) { - if (pt != NULL && --pt->pt_refcount <= 0) { + if (pt == NULL) { + return; + } + + if (--pt->pt_refcount <= 0) { partial_free(pt); } } @@ -8241,21 +8252,24 @@ void last_set_msg(sctx_T script_ctx) /// Should only be invoked when 'verbose' is non-zero. void option_last_set_msg(LastSet last_set) { - if (last_set.script_ctx.sc_sid != 0) { - bool should_free; - char *p = get_scriptname(last_set, &should_free); - verbose_enter(); - msg_puts(_("\n\tLast set from ")); - msg_puts(p); - if (last_set.script_ctx.sc_lnum > 0) { - msg_puts(_(line_msg)); - msg_outnum(last_set.script_ctx.sc_lnum); - } - if (should_free) { - xfree(p); - } - verbose_leave(); + if (last_set.script_ctx.sc_sid == 0) { + return; + } + + bool should_free; + char *p = get_scriptname(last_set, &should_free); + + verbose_enter(); + msg_puts(_("\n\tLast set from ")); + msg_puts(p); + if (last_set.script_ctx.sc_lnum > 0) { + msg_puts(_(line_msg)); + msg_outnum(last_set.script_ctx.sc_lnum); + } + if (should_free) { + xfree(p); } + verbose_leave(); } // reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal, -- cgit From 9ab9cde2ca7b917a894068698ef2fec3a851fdd5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 3 Feb 2024 10:22:11 +0800 Subject: vim-patch:partial:9.0.1196: code is indented more than necessary (#27315) Problem: Code is indented more than necessary. Solution: Use an early return where it makes sense. (Yegappan Lakshmanan, closes vim/vim#11813) https://github.com/vim/vim/commit/e8575988969579f9e1439181ae338b2ff74054a8 Skip list_alloc_with_items(). Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval.c | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5053cc38de..3647bde952 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5397,35 +5397,37 @@ static void filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap // On type errors, the preceding call has already displayed an error // message. Avoid a misleading error message for an empty string that // was not passed as argument. - if (expr->v_type != VAR_UNKNOWN) { - typval_T save_val; - prepare_vimvar(VV_VAL, &save_val); - - // We reset "did_emsg" to be able to detect whether an error - // occurred during evaluation of the expression. - int save_did_emsg = did_emsg; - did_emsg = false; - - typval_T save_key; - prepare_vimvar(VV_KEY, &save_key); - if (argvars[0].v_type == VAR_DICT) { - filter_map_dict(argvars[0].vval.v_dict, filtermap, func_name, - arg_errmsg, expr, rettv); - } else if (argvars[0].v_type == VAR_BLOB) { - filter_map_blob(argvars[0].vval.v_blob, filtermap, expr, arg_errmsg, rettv); - } else if (argvars[0].v_type == VAR_STRING) { - filter_map_string(tv_get_string(&argvars[0]), filtermap, expr, rettv); - } else { - assert(argvars[0].v_type == VAR_LIST); - filter_map_list(argvars[0].vval.v_list, filtermap, func_name, - arg_errmsg, expr, rettv); - } + if (expr->v_type == VAR_UNKNOWN) { + return; + } + + typval_T save_val; + prepare_vimvar(VV_VAL, &save_val); - restore_vimvar(VV_KEY, &save_key); - restore_vimvar(VV_VAL, &save_val); + // We reset "did_emsg" to be able to detect whether an error + // occurred during evaluation of the expression. + int save_did_emsg = did_emsg; + did_emsg = false; - did_emsg |= save_did_emsg; + typval_T save_key; + prepare_vimvar(VV_KEY, &save_key); + if (argvars[0].v_type == VAR_DICT) { + filter_map_dict(argvars[0].vval.v_dict, filtermap, func_name, + arg_errmsg, expr, rettv); + } else if (argvars[0].v_type == VAR_BLOB) { + filter_map_blob(argvars[0].vval.v_blob, filtermap, expr, arg_errmsg, rettv); + } else if (argvars[0].v_type == VAR_STRING) { + filter_map_string(tv_get_string(&argvars[0]), filtermap, expr, rettv); + } else { + assert(argvars[0].v_type == VAR_LIST); + filter_map_list(argvars[0].vval.v_list, filtermap, func_name, + arg_errmsg, expr, rettv); } + + restore_vimvar(VV_KEY, &save_key); + restore_vimvar(VV_VAL, &save_val); + + did_emsg |= save_did_emsg; } /// Handle one item for map(), filter(), foreach(). -- cgit From 0353dd3029f9ce31c3894530385443a90f6677ee Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 11 Feb 2024 15:46:14 +0100 Subject: refactor(lua): use Arena when converting from lua stack to API args and for return value of nlua_exec/nlua_call_ref, as this uses the same family of functions. NB: the handling of luaref:s is a bit of a mess. add api_luarefs_free_XX functions as a stop-gap as refactoring luarefs is a can of worms for another PR:s. as a minor feature/bug-fix, nvim_buf_call and nvim_win_call now preserves arbitrary return values. --- src/nvim/eval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3647bde952..a4da582dca 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6143,8 +6143,8 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co break; case kCallbackLua: - rv = nlua_call_ref(callback->data.luaref, NULL, args, false, NULL); - return (rv.type == kObjectTypeBoolean && rv.data.boolean == true); + rv = nlua_call_ref(callback->data.luaref, NULL, args, kRetNilBool, NULL, NULL); + return LUARET_TRUTHY(rv); case kCallbackNone: return false; -- cgit From d60412b18e4e21f301baa2ac3f3fb7be89655e4b Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 12 Feb 2024 20:40:27 +0100 Subject: refactor(eval): use arena when converting typvals to Object Note: this contains two _temporary_ changes which can be reverted once the Arena vs no-Arena distinction in API wrappers has been removed. Both nlua_push_Object and object_to_vim_take_luaref() has been changed to take the object argument as a pointer. This is not going to be necessary once these are only used with arena (or not at all) allocated Objects. The object_to_vim() variant which leaves luaref untouched might need to stay for a little longer. --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a4da582dca..4734e46362 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1355,7 +1355,7 @@ Object eval_foldtext(win_T *wp) retval = STRING_OBJ(NULL_STRING); } else { if (tv.v_type == VAR_LIST) { - retval = vim_to_object(&tv); + retval = vim_to_object(&tv, NULL, false); } else { retval = STRING_OBJ(cstr_to_string(tv_get_string(&tv))); } -- cgit From b8c34efe3399b0786a0e00012cfa3a05a4aa4654 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 18 Feb 2024 19:11:44 +0800 Subject: fix(eval): skip over v:lua properly (#27517) Problem: Error when parsing v:lua in a ternary expression. Solution: Set rettv->v_type for v:lua even if not evaluating. --- src/nvim/eval.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4734e46362..3d224bfa0f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3238,6 +3238,13 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan } else { // skip the name check_vars(s, (size_t)len); + // If evaluate is false rettv->v_type was not set, but it's needed + // in handle_subscript() to parse v:lua, so set it here. + if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) { + rettv->v_type = VAR_PARTIAL; + rettv->vval.v_partial = vvlua_partial; + rettv->vval.v_partial->pt_refcount++; + } ret = OK; } } @@ -3442,7 +3449,7 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const int len; char *name = *arg; char *lua_funcname = NULL; - if (strncmp(name, "v:lua.", 6) == 0) { + if (strnequal(name, "v:lua.", 6)) { lua_funcname = name + 6; *arg = (char *)skip_luafunc_name(lua_funcname); *arg = skipwhite(*arg); // to detect trailing whitespace later @@ -7614,6 +7621,10 @@ int handle_subscript(const char **const arg, typval_T *rettv, evalarg_T *const e const char *lua_funcname = NULL; if (tv_is_luafunc(rettv)) { + if (!evaluate) { + tv_clear(rettv); + } + if (**arg != '.') { tv_clear(rettv); ret = FAIL; -- cgit