aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/buffer.c8
-rw-r--r--src/nvim/eval/decode.c18
-rw-r--r--src/nvim/eval/encode.c17
-rw-r--r--src/nvim/eval/encode.h18
-rw-r--r--src/nvim/eval/executor.c5
-rw-r--r--src/nvim/eval/funcs.c714
-rw-r--r--src/nvim/eval/funcs.h1
-rw-r--r--src/nvim/eval/gc.h2
-rw-r--r--src/nvim/eval/typval.c62
-rw-r--r--src/nvim/eval/typval.h23
-rw-r--r--src/nvim/eval/typval_defs.h20
-rw-r--r--src/nvim/eval/typval_encode.c.h3
-rw-r--r--src/nvim/eval/userfunc.c45
-rw-r--r--src/nvim/eval/userfunc.h4
-rw-r--r--src/nvim/eval/vars.c131
-rw-r--r--src/nvim/eval/window.c94
-rw-r--r--src/nvim/eval/window.h70
17 files changed, 840 insertions, 395 deletions
diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c
index c60a104381..7b8f71ef3f 100644
--- a/src/nvim/eval/buffer.c
+++ b/src/nvim/eval/buffer.c
@@ -5,6 +5,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/change.h"
@@ -14,7 +15,6 @@
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
-#include "nvim/func_attr.h"
#include "nvim/globals.h"
#include "nvim/macros_defs.h"
#include "nvim/memline.h"
@@ -494,6 +494,7 @@ static dict_T *get_buffer_info(buf_T *buf)
tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
tv_dict_add_nr(dict, S_LEN("hidden"), buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
+ tv_dict_add_nr(dict, S_LEN("command"), buf == cmdwin_buf);
// Get a reference to buffer variables
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
@@ -507,7 +508,7 @@ static dict_T *get_buffer_info(buf_T *buf)
}
tv_dict_add_list(dict, S_LEN("windows"), windows);
- if (buf->b_signs) {
+ if (buf_has_signs(buf)) {
// List of signs placed in this buffer
tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
}
@@ -584,7 +585,8 @@ void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
///
/// @return range (from start to end) of lines in rettv from the specified
/// buffer.
-static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
+static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, bool retlist,
+ typval_T *rettv)
{
rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
rettv->vval.v_string = NULL;
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 03f79fca84..d7df7bb150 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -14,9 +14,9 @@
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
-#include "nvim/func_attr.h"
+#include "nvim/eval_defs.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/macros_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
@@ -142,9 +142,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack
ValuesStackItem key = kv_pop(*stack);
if (last_container.special_val == NULL) {
// These cases should have already been handled.
- assert(!(key.is_special_string
- || key.val.vval.v_string == NULL
- || *key.val.vval.v_string == NUL));
+ assert(!(key.is_special_string || key.val.vval.v_string == NULL));
dictitem_T *const obj_di = tv_dict_item_alloc(key.val.vval.v_string);
tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
@@ -171,11 +169,10 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack
tv_clear(&obj.val);
return FAIL;
}
- // Handle empty key and key represented as special dictionary
+ // Handle special dictionaries
if (last_container.special_val == NULL
&& (obj.is_special_string
|| obj.val.vval.v_string == NULL
- || *obj.val.vval.v_string == NUL
|| tv_dict_find(last_container.container.vval.v_dict, obj.val.vval.v_string, -1))) {
tv_clear(&obj.val);
@@ -405,13 +402,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
semsg(_("E474: Expected string end: %.*s"), (int)buf_len, buf);
goto parse_json_string_fail;
}
- if (len == 0) {
- POP(((typval_T) {
- .v_type = VAR_STRING,
- .vval = { .v_string = NULL },
- }), false);
- goto parse_json_string_ret;
- }
char *str = xmalloc(len + 1);
int fst_in_pair = 0;
char *str_end = str;
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 8505c30fad..d35ac4eb7b 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -20,7 +20,8 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
+#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/macros_defs.h"
#include "nvim/math.h"
@@ -1055,3 +1056,17 @@ char *encode_tv2json(typval_T *tv, size_t *len)
#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
#undef TYPVAL_ENCODE_CONV_RECURSE
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
+
+/// Initialize ListReaderState structure
+ListReaderState encode_init_lrstate(const list_T *const list)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return (ListReaderState) {
+ .list = list,
+ .li = tv_list_first(list),
+ .offset = 0,
+ .li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
+ ? 0
+ : strlen(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
+ };
+}
diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h
index 26a3286f2b..6d1c0b61c5 100644
--- a/src/nvim/eval/encode.h
+++ b/src/nvim/eval/encode.h
@@ -1,12 +1,8 @@
#pragma once
-#include <msgpack.h>
#include <msgpack/pack.h>
-#include <stddef.h>
#include <string.h>
-#include "nvim/eval.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/garray_defs.h"
@@ -36,20 +32,6 @@ typedef struct {
size_t li_length; ///< Length of the string inside the read item.
} ListReaderState;
-/// Initialize ListReaderState structure
-static inline ListReaderState encode_init_lrstate(const list_T *const list)
- FUNC_ATTR_NONNULL_ALL
-{
- return (ListReaderState) {
- .list = list,
- .li = tv_list_first(list),
- .offset = 0,
- .li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
- ? 0
- : strlen(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
- };
-}
-
/// Array mapping values from SpecialVarValue enum to names
extern const char *const encode_bool_var_names[];
extern const char *const encode_special_var_names[];
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index dc23fcdc72..1b8c057d7c 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -5,9 +5,8 @@
#include "nvim/eval/executor.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/message.h"
#include "nvim/strings.h"
@@ -15,7 +14,7 @@
#include "nvim/vim_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/executor.c.generated.h" // IWYU pragma: export
+# include "eval/executor.c.generated.h"
#endif
char *e_list_index_out_of_range_nr
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 13425b21d1..d7237d6443 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -14,7 +14,6 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <time.h>
#include <uv.h>
@@ -27,9 +26,11 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
+#include "nvim/channel_defs.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdexpand_defs.h"
@@ -48,22 +49,26 @@
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
#include "nvim/eval/window.h"
+#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#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/garray_defs.h"
#include "nvim/getchar.h"
-#include "nvim/gettext.h"
+#include "nvim/getchar_defs.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
@@ -75,24 +80,34 @@
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
#include "nvim/math.h"
#include "nvim/mbyte.h"
+#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
+#include "nvim/memory_defs.h"
#include "nvim/menu.h"
+#include "nvim/menu_defs.h"
#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/normal_defs.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/option_defs.h"
#include "nvim/option_vars.h"
#include "nvim/optionstr.h"
#include "nvim/os/dl.h"
#include "nvim/os/fileio.h"
+#include "nvim/os/fileio_defs.h"
#include "nvim/os/fs.h"
+#include "nvim/os/fs_defs.h"
#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
#include "nvim/os/stdpaths_defs.h"
@@ -103,15 +118,19 @@
#include "nvim/pos_defs.h"
#include "nvim/profile.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/sha256.h"
#include "nvim/spell.h"
#include "nvim/spellsuggest.h"
#include "nvim/state.h"
+#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/version.h"
#include "nvim/vim_defs.h"
@@ -305,7 +324,7 @@ int call_internal_method(const char *const fname, const int argcount, typval_T *
}
/// @return true for a non-zero Number and a non-empty String.
-static int non_zero_arg(typval_T *argvars)
+static bool non_zero_arg(typval_T *argvars)
{
return ((argvars[0].v_type == VAR_NUMBER
&& argvars[0].vval.v_number != 0)
@@ -341,33 +360,28 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
MsgpackRpcRequestHandler handler = *fptr.api_handler;
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, false));
}
Error err = ERROR_INIT;
- Arena res_arena = ARENA_EMPTY;
- Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err);
+ Object result = handler.fn(VIML_INTERNAL_CALL, args, &arena, &err);
if (ERROR_SET(&err)) {
semsg_multiline(e_api_error, err.msg);
goto end;
}
- if (!object_to_vim(result, rettv, &err)) {
- assert(ERROR_SET(&err));
- semsg(_("Error converting the call result: %s"), err.msg);
- }
+ object_to_vim_take_luaref(&result, rettv, true, &err);
end:
- api_free_array(args);
- if (handler.arena_return) {
- arena_mem_free(arena_finish(&res_arena));
- } else {
+ if (handler.ret_alloc) {
api_free_object(result);
}
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@@ -428,8 +442,7 @@ static void f_and(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "api_info()" function
static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- Dictionary metadata = api_metadata();
- (void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
+ object_to_vim(api_metadata(), rettv, NULL);
}
/// "atan2()" function
@@ -1022,10 +1035,11 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Dictionary ctx_dict = ctx_to_dict(ctx);
+ Arena arena = ARENA_EMPTY;
+ Dictionary ctx_dict = ctx_to_dict(ctx, &arena);
Error err = ERROR_INIT;
- (void)object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
- api_free_dictionary(ctx_dict);
+ object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
}
@@ -1093,7 +1107,8 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const int save_did_emsg = did_emsg;
did_emsg = false;
- Dictionary dict = vim_to_object(&argvars[0]).data.dictionary;
+ Arena arena = ARENA_EMPTY;
+ Dictionary dict = vim_to_object(&argvars[0], &arena, true).data.dictionary;
Context tmp = CONTEXT_INIT;
Error err = ERROR_INIT;
ctx_from_dict(dict, &tmp, &err);
@@ -1106,7 +1121,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
*ctx = tmp;
}
- api_free_dictionary(dict);
+ arena_mem_free(arena_finish(&arena));
api_clear_error(&err);
did_emsg = save_did_emsg;
}
@@ -1675,7 +1690,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *path = NULL;
- (void)os_can_exe(tv_get_string(&argvars[0]), &path, true);
+ os_can_exe(tv_get_string(&argvars[0]), &path, true);
#ifdef BACKSLASH_IN_FILENAME
if (path != NULL) {
@@ -1711,7 +1726,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
n = false; // Trailing garbage.
}
} else if (*p == '*') { // Internal or user defined function.
- n = function_exists(p + 1, false);
+ n = strnequal(p, "*v:lua.", 7) ? nlua_func_exists(p + 7) : function_exists(p + 1, false);
} else if (*p == ':') {
n = cmd_exists(p + 1);
} else if (*p == '#') {
@@ -1922,44 +1937,47 @@ static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new,
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) {
- int before = (int)tv_get_number_chk(&argvars[2], &error);
- if (error) {
- return; // Type error; errmsg already given.
- }
+ if (!is_new && value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
- if (before == tv_list_len(l1)) {
- item = NULL;
- } else {
- item = tv_list_find(l1, before);
- if (item == NULL) {
- semsg(_(e_list_index_out_of_range_nr), (int64_t)before);
- return;
- }
- }
- } else {
- item = NULL;
+ if (is_new) {
+ l1 = tv_list_copy(NULL, l1, false, get_copyID());
+ if (l1 == NULL) {
+ return;
}
- tv_list_extend(l1, l2, item);
+ }
- if (is_new) {
- *rettv = (typval_T){
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval.v_list = l1,
- };
+ listitem_T *item;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ int before = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return; // Type error; errmsg already given.
+ }
+
+ if (before == tv_list_len(l1)) {
+ item = NULL;
} else {
- tv_copy(&argvars[0], rettv);
+ item = tv_list_find(l1, before);
+ if (item == NULL) {
+ semsg(_(e_list_index_out_of_range_nr), (int64_t)before);
+ return;
+ }
}
+ } else {
+ item = NULL;
+ }
+ 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);
}
}
@@ -1970,54 +1988,61 @@ static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new,
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) {
+ return;
+ }
+ dict_T *const d2 = argvars[1].vval.v_dict;
+ 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;
- }
+ return;
+ }
+
+ if (!is_new && value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
+
+ 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);
}
}
@@ -2068,8 +2093,8 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
flags = tv_get_string_buf(&argvars[1], nbuf);
}
- nvim_feedkeys(cstr_as_string((char *)keys),
- cstr_as_string((char *)flags), true);
+ nvim_feedkeys(cstr_as_string(keys),
+ cstr_as_string(flags), true);
}
/// "filereadable()" function
@@ -2175,7 +2200,7 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
+ if (f <= (float_T)(-VARNUMBER_MAX) + DBL_EPSILON) {
rettv->vval.v_number = -VARNUMBER_MAX;
} else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
rettv->vval.v_number = VARNUMBER_MAX;
@@ -2219,8 +2244,8 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
len = strlen(fname);
if (*mods != NUL) {
size_t usedlen = 0;
- (void)modify_fname((char *)mods, false, &usedlen,
- (char **)&fname, &fbuf, &len);
+ modify_fname((char *)mods, false, &usedlen,
+ (char **)&fname, &fbuf, &len);
}
}
@@ -2444,7 +2469,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos, bool
: (varnumber_T)0));
tv_list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
if (getcurpos) {
- const int save_set_curswant = curwin->w_set_curswant;
+ const bool save_set_curswant = curwin->w_set_curswant;
const colnr_T save_curswant = curwin->w_curswant;
const colnr_T save_virtcol = curwin->w_virtcol;
@@ -2776,6 +2801,167 @@ static void f_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
getpos_both(argvars, rettv, false, false);
}
+/// Convert from block_def to string
+static char *block_def2str(struct block_def *bd)
+{
+ size_t size = (size_t)bd->startspaces + (size_t)bd->endspaces + (size_t)bd->textlen;
+ char *ret = xmalloc(size + 1);
+ char *p = ret;
+ memset(p, ' ', (size_t)bd->startspaces);
+ p += bd->startspaces;
+ memmove(p, bd->textstart, (size_t)bd->textlen);
+ p += bd->textlen;
+ memset(p, ' ', (size_t)bd->endspaces);
+ *(p + bd->endspaces) = NUL;
+ return ret;
+}
+
+/// "getregion()" function
+static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ if (tv_check_for_list_arg(argvars, 0) == FAIL
+ || tv_check_for_list_arg(argvars, 1) == FAIL
+ || tv_check_for_opt_dict_arg(argvars, 2) == FAIL) {
+ return;
+ }
+
+ int fnum1 = -1;
+ int fnum2 = -1;
+ pos_T p1, p2;
+ if (list2fpos(&argvars[0], &p1, &fnum1, NULL, false) != OK
+ || list2fpos(&argvars[1], &p2, &fnum2, NULL, false) != OK
+ || fnum1 != fnum2) {
+ return;
+ }
+
+ bool is_select_exclusive;
+ char *type;
+ char default_type[] = "v";
+ if (argvars[2].v_type == VAR_DICT) {
+ is_select_exclusive = tv_dict_get_bool(argvars[2].vval.v_dict, "exclusive",
+ *p_sel == 'e');
+ type = tv_dict_get_string(argvars[2].vval.v_dict, "type", false);
+ if (type == NULL) {
+ type = default_type;
+ }
+ } else {
+ is_select_exclusive = *p_sel == 'e';
+ type = default_type;
+ }
+
+ MotionType region_type = kMTUnknown;
+ if (type[0] == 'v' && type[1] == NUL) {
+ region_type = kMTCharWise;
+ } else if (type[0] == 'V' && type[1] == NUL) {
+ region_type = kMTLineWise;
+ } else if (type[0] == Ctrl_V && type[1] == NUL) {
+ region_type = kMTBlockWise;
+ } else {
+ return;
+ }
+
+ buf_T *const save_curbuf = curbuf;
+
+ if (fnum1 != 0) {
+ buf_T *findbuf = buflist_findnr(fnum1);
+ // buffer not loaded
+ if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) {
+ return;
+ }
+ curbuf = findbuf;
+ }
+
+ const TriState save_virtual = virtual_op;
+ virtual_op = virtual_active();
+
+ // NOTE: Adjust is needed.
+ p1.col--;
+ p2.col--;
+
+ if (!lt(p1, p2)) {
+ // swap position
+ pos_T p = p1;
+ p1 = p2;
+ p2 = p;
+ }
+
+ oparg_T oa;
+ bool inclusive = true;
+
+ if (region_type == kMTCharWise) {
+ // handle 'selection' == "exclusive"
+ if (is_select_exclusive && !equalpos(p1, p2)) {
+ if (p2.coladd > 0) {
+ p2.coladd--;
+ } else if (p2.col > 0) {
+ p2.col--;
+ mark_mb_adjustpos(curbuf, &p2);
+ } else if (p2.lnum > 1) {
+ p2.lnum--;
+ p2.col = (colnr_T)strlen(ml_get(p2.lnum));
+ if (p2.col > 0) {
+ p2.col--;
+ mark_mb_adjustpos(curbuf, &p2);
+ }
+ }
+ }
+ // if fp2 is on NUL (empty line) inclusive becomes false
+ if (*ml_get_pos(&p2) == NUL && !virtual_op) {
+ inclusive = false;
+ }
+ } else if (region_type == kMTBlockWise) {
+ colnr_T sc1, ec1, sc2, ec2;
+ getvvcol(curwin, &p1, &sc1, NULL, &ec1);
+ getvvcol(curwin, &p2, &sc2, NULL, &ec2);
+ oa.motion_type = kMTBlockWise;
+ oa.inclusive = true;
+ oa.op_type = OP_NOP;
+ oa.start = p1;
+ oa.end = p2;
+ oa.start_vcol = MIN(sc1, sc2);
+ if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) {
+ oa.end_vcol = sc2 - 1;
+ } else {
+ oa.end_vcol = MAX(ec1, ec2);
+ }
+ }
+
+ // Include the trailing byte of a multi-byte char.
+ int l = utfc_ptr2len(ml_get_pos(&p2));
+ if (l > 1) {
+ p2.col += l - 1;
+ }
+
+ for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) {
+ char *akt = NULL;
+
+ if (region_type == kMTLineWise) {
+ akt = xstrdup(ml_get(lnum));
+ } else if (region_type == kMTBlockWise) {
+ struct block_def bd;
+ block_prep(&oa, &bd, lnum, false);
+ akt = block_def2str(&bd);
+ } else if (p1.lnum < lnum && lnum < p2.lnum) {
+ akt = xstrdup(ml_get(lnum));
+ } else {
+ struct block_def bd;
+ charwise_block_prep(p1, p2, &bd, lnum, inclusive);
+ akt = block_def2str(&bd);
+ }
+
+ assert(akt != NULL);
+ tv_list_append_allocated_string(rettv->vval.v_list, akt);
+ }
+
+ if (curbuf != save_curbuf) {
+ curbuf = save_curbuf;
+ }
+
+ virtual_op = save_virtual;
+}
+
/// Common between getreg(), getreginfo() and getregtype(): get the register
/// name from the first argument.
/// Returns zero on error.
@@ -3140,7 +3326,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"path_extra",
"persistent_undo",
"profile",
- "pythonx",
"reltime",
"quickfix",
"rightleft",
@@ -3182,6 +3367,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"xattr",
#endif
"nvim",
+ "rneovim",
};
// XXX: eval_has_provider() may shell out :(
@@ -3231,6 +3417,8 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
n = syntax_present(curwin);
} else if (STRICMP(name, "clipboard_working") == 0) {
n = eval_has_provider("clipboard");
+ } else if (STRICMP(name, "pythonx") == 0) {
+ n = eval_has_provider("python3");
} else if (STRICMP(name, "wsl") == 0) {
n = has_wsl();
#ifdef UNIX
@@ -3253,13 +3441,11 @@ 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.uv.os_uname()['release']:lower()"
- ":match('microsoft') and true or false"),
- (Array)ARRAY_DICT_INIT, &err);
+ Object o = NLUA_EXEC_STATIC("return vim.uv.os_uname()['release']:lower()"
+ ":match('microsoft')",
+ (Array)ARRAY_DICT_INIT, kRetNilBool, NULL, &err);
assert(!ERROR_SET(&err));
- assert(o.type == kObjectTypeBoolean);
- has_wsl = o.data.boolean ? kTrue : kFalse;
- api_free_object(o);
+ has_wsl = LUARET_TRUTHY(o) ? kTrue : kFalse;
}
return has_wsl == kTrue;
}
@@ -3639,7 +3825,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
});
// Ask for choice.
- int mouse_used;
+ bool mouse_used;
int selected = prompt_for_number(&mouse_used);
if (mouse_used) {
selected -= lines_left;
@@ -3899,13 +4085,16 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = 1;
}
-static const char *ignored_env_vars[] = {
+static const char *pty_ignored_env_vars[] = {
#ifndef MSWIN
"COLUMNS",
"LINES",
"TERMCAP",
"COLORFGBG",
+ "COLORTERM",
#endif
+ "VIM",
+ "VIMRUNTIME",
NULL
};
@@ -3944,9 +4133,9 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
// child process. We're removing them here so the user can still decide
// they want to explicitly set them.
for (size_t i = 0;
- i < ARRAY_SIZE(ignored_env_vars) && ignored_env_vars[i];
+ i < ARRAY_SIZE(pty_ignored_env_vars) && pty_ignored_env_vars[i];
i++) {
- dictitem_T *dv = tv_dict_find(env, ignored_env_vars[i], -1);
+ dictitem_T *dv = tv_dict_find(env, pty_ignored_env_vars[i], -1);
if (dv) {
tv_dict_item_remove(env, dv);
}
@@ -3954,10 +4143,6 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
#ifndef MSWIN
// 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
@@ -4056,8 +4241,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool clear_env = false;
bool overlapped = false;
ChannelStdinMode stdin_mode = kChannelStdinPipe;
- CallbackReader on_stdout = CALLBACK_READER_INIT,
- on_stderr = CALLBACK_READER_INIT;
+ CallbackReader on_stdout = CALLBACK_READER_INIT;
+ CallbackReader on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
char *cwd = NULL;
dictitem_T *job_env = NULL;
@@ -4120,7 +4305,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
- uint16_t width = 0, height = 0;
+ uint16_t width = 0;
+ uint16_t height = 0;
char *term_name = NULL;
if (pty) {
@@ -4168,7 +4354,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *error = NULL;
if (data->is_rpc) {
// Ignore return code, but show error later.
- (void)channel_close(data->id, kChannelPartRpc, &error);
+ channel_close(data->id, kChannelPartRpc, &error);
}
process_stop(&data->stream.proc);
rettv->vval.v_number = 1;
@@ -4503,7 +4689,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- nlua_typval_eval(cstr_as_string((char *)str), &argvars[1], rettv);
+ nlua_typval_eval(cstr_as_string(str), &argvars[1], rettv);
}
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
@@ -4714,6 +4900,151 @@ theend:
p_cpo = save_cpo;
}
+/// Return all the matches in string "str" for pattern "rmp".
+/// The matches are returned in the List "mlist".
+/// If "submatches" is true, then submatch information is also returned.
+/// "matchbuf" is true when called for matchbufline().
+static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist, int idx,
+ bool submatches, bool matchbuf)
+{
+ size_t len = strlen(str);
+ int match = 0;
+ colnr_T startidx = 0;
+
+ while (true) {
+ match = vim_regexec_nl(rmp, str, startidx);
+ if (!match) {
+ break;
+ }
+
+ dict_T *d = tv_dict_alloc();
+ tv_list_append_dict(mlist, d);
+
+ if (matchbuf) {
+ tv_dict_add_nr(d, S_LEN("lnum"), idx);
+ } else {
+ tv_dict_add_nr(d, S_LEN("idx"), idx);
+ }
+
+ tv_dict_add_nr(d, S_LEN("byteidx"),
+ (colnr_T)(rmp->startp[0] - str));
+
+ tv_dict_add_str_len(d, S_LEN("text"), rmp->startp[0],
+ (int)(rmp->endp[0] - rmp->startp[0]));
+
+ if (submatches) {
+ list_T *sml = tv_list_alloc(NSUBEXP - 1);
+
+ tv_dict_add_list(d, S_LEN("submatches"), sml);
+
+ // return a list with the submatches
+ for (int i = 1; i < NSUBEXP; i++) {
+ if (rmp->endp[i] == NULL) {
+ tv_list_append_string(sml, "", 0);
+ } else {
+ tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]);
+ }
+ }
+ }
+ startidx = (colnr_T)(rmp->endp[0] - str);
+ if (startidx >= (colnr_T)len || str + startidx <= rmp->startp[0]) {
+ break;
+ }
+ }
+}
+
+/// "matchbufline()" function
+static void f_matchbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+ tv_list_alloc_ret(rettv, kListLenUnknown);
+ list_T *retlist = rettv->vval.v_list;
+
+ if (tv_check_for_buffer_arg(argvars, 0) == FAIL
+ || tv_check_for_string_arg(argvars, 1) == FAIL
+ || tv_check_for_lnum_arg(argvars, 2) == FAIL
+ || tv_check_for_lnum_arg(argvars, 3) == FAIL
+ || tv_check_for_opt_dict_arg(argvars, 4) == FAIL) {
+ return;
+ }
+
+ const int prev_did_emsg = did_emsg;
+ buf_T *buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ if (did_emsg == prev_did_emsg) {
+ semsg(_(e_invalid_buffer_name_str), tv_get_string(&argvars[0]));
+ }
+ return;
+ }
+ if (buf->b_ml.ml_mfp == NULL) {
+ emsg(_(e_buffer_is_not_loaded));
+ return;
+ }
+
+ char patbuf[NUMBUFLEN];
+ const char *pat = tv_get_string_buf(&argvars[1], patbuf);
+
+ const int did_emsg_before = did_emsg;
+ linenr_T slnum = tv_get_lnum_buf(&argvars[2], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ if (slnum < 1) {
+ semsg(_(e_invargval), "lnum");
+ return;
+ }
+
+ linenr_T elnum = tv_get_lnum_buf(&argvars[3], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ if (elnum < 1 || elnum < slnum) {
+ semsg(_(e_invargval), "end_lnum");
+ return;
+ }
+
+ if (elnum > buf->b_ml.ml_line_count) {
+ elnum = buf->b_ml.ml_line_count;
+ }
+
+ bool submatches = false;
+ if (argvars[4].v_type != VAR_UNKNOWN) {
+ dict_T *d = argvars[4].vval.v_dict;
+ if (d != NULL) {
+ dictitem_T *di = tv_dict_find(d, S_LEN("submatches"));
+ if (di != NULL) {
+ if (di->di_tv.v_type != VAR_BOOL) {
+ semsg(_(e_invargval), "submatches");
+ return;
+ }
+ submatches = tv_get_bool(&di->di_tv);
+ }
+ }
+ }
+
+ // Make 'cpoptions' empty, the 'l' flag should not be used here.
+ char *const save_cpo = p_cpo;
+ p_cpo = empty_string_option;
+
+ regmatch_T regmatch;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog == NULL) {
+ goto theend;
+ }
+ regmatch.rm_ic = p_ic;
+
+ while (slnum <= elnum) {
+ const char *str = ml_get_buf(buf, slnum);
+ get_matches_in_str(str, &regmatch, retlist, slnum, submatches, true);
+ slnum++;
+ }
+
+ vim_regfree(regmatch.regprog);
+
+theend:
+ p_cpo = save_cpo;
+}
+
/// "match()" function
static void f_match(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -4738,6 +5069,73 @@ static void f_matchstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
find_some_match(argvars, rettv, kSomeMatchStr);
}
+/// "matchstrlist()" function
+static void f_matchstrlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+ tv_list_alloc_ret(rettv, kListLenUnknown);
+ list_T *retlist = rettv->vval.v_list;
+
+ if (tv_check_for_list_arg(argvars, 0) == FAIL
+ || tv_check_for_string_arg(argvars, 1) == FAIL
+ || tv_check_for_opt_dict_arg(argvars, 2) == FAIL) {
+ return;
+ }
+
+ list_T *l = NULL;
+ if ((l = argvars[0].vval.v_list) == NULL) {
+ return;
+ }
+
+ char patbuf[NUMBUFLEN];
+ const char *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ if (pat == NULL) {
+ return;
+ }
+
+ // Make 'cpoptions' empty, the 'l' flag should not be used here.
+ char *const save_cpo = p_cpo;
+ p_cpo = empty_string_option;
+
+ regmatch_T regmatch;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog == NULL) {
+ goto theend;
+ }
+ regmatch.rm_ic = p_ic;
+
+ bool submatches = false;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ dict_T *d = argvars[2].vval.v_dict;
+ if (d != NULL) {
+ dictitem_T *di = tv_dict_find(d, S_LEN("submatches"));
+ if (di != NULL) {
+ if (di->di_tv.v_type != VAR_BOOL) {
+ semsg(_(e_invargval), "submatches");
+ goto cleanup;
+ }
+ submatches = tv_get_bool(&di->di_tv);
+ }
+ }
+ }
+
+ int idx = 0;
+ TV_LIST_ITER_CONST(l, li, {
+ const typval_T *const li_tv = TV_LIST_ITEM_TV(li);
+ if (li_tv->v_type == VAR_STRING && li_tv->vval.v_string != NULL) {
+ const char *str = li_tv->vval.v_string;
+ get_matches_in_str(str, &regmatch, retlist, idx, submatches, false);
+ }
+ idx++;
+ });
+
+cleanup:
+ vim_regfree(regmatch.regprog);
+
+theend:
+ p_cpo = save_cpo;
+}
+
/// "matchstrpos()" function
static void f_matchstrpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -5216,7 +5614,7 @@ static void f_printf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (!did_emsg) {
char *s = xmalloc((size_t)len + 1);
rettv->vval.v_string = s;
- (void)vim_vsnprintf_typval(s, (size_t)len + 1, fmt, dummy_ap, argvars + 1);
+ vim_vsnprintf_typval(s, (size_t)len + 1, fmt, dummy_ap, argvars + 1);
}
did_emsg |= saved_did_emsg;
}
@@ -5620,6 +6018,12 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl
}
}
+ if (blob) {
+ tv_blob_alloc_ret(rettv);
+ } else {
+ tv_list_alloc_ret(rettv, kListLenUnknown);
+ }
+
// Always open the file in binary mode, library functions have a mind of
// their own about CR-LF conversion.
const char *const fname = tv_get_string(&argvars[0]);
@@ -5634,7 +6038,6 @@ 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, offset, size) == FAIL) {
semsg(_(e_notread), fname);
}
@@ -5642,7 +6045,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl
return;
}
- list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
+ list_T *const l = rettv->vval.v_list;
while (maxline < 0 || tv_list_len(l) < maxline) {
int readlen = (int)fread(buf, 1, (size_t)io_size, fd);
@@ -5807,7 +6210,7 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (list == NULL) {
return;
}
- (void)tv_dict_add_list(dict, S_LEN("regcontents"), list);
+ tv_dict_add_list(dict, S_LEN("regcontents"), list);
char buf[NUMBUFLEN + 2];
buf[0] = NUL;
@@ -5826,15 +6229,15 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
case kMTUnknown:
abort();
}
- (void)tv_dict_add_str(dict, S_LEN("regtype"), buf);
+ tv_dict_add_str(dict, S_LEN("regtype"), buf);
buf[0] = (char)get_register_name(get_unname_register());
buf[1] = NUL;
if (regname == '"') {
- (void)tv_dict_add_str(dict, S_LEN("points_to"), buf);
+ tv_dict_add_str(dict, S_LEN("points_to"), buf);
} else {
- (void)tv_dict_add_bool(dict, S_LEN("isunnamed"),
- regname == buf[0] ? kBoolVarTrue : kBoolVarFalse);
+ tv_dict_add_bool(dict, S_LEN("isunnamed"),
+ regname == buf[0] ? kBoolVarTrue : kBoolVarFalse);
}
}
@@ -6648,16 +7051,17 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, true));
}
bool ok = rpc_send_event((uint64_t)argvars[0].vval.v_number,
tv_get_string(&argvars[1]), args);
- api_free_array(args);
+ arena_mem_free(arena_finish(&arena));
if (!ok) {
semsg(_(e_invarg2), "Channel doesn't exist");
@@ -6687,10 +7091,11 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- Array args = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(args, MAX_FUNC_ARGS);
+ Arena arena = ARENA_EMPTY;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
+ ADD_C(args, vim_to_object(tv, &arena, true));
}
sctx_T save_current_sctx;
@@ -6726,6 +7131,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ArenaMem res_mem = NULL;
Object result = rpc_send_call(chan_id, method, args, &res_mem, &err);
+ arena_mem_free(arena_finish(&arena));
if (l_provider_call_nesting) {
current_sctx = save_current_sctx;
@@ -6755,10 +7161,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
goto end;
}
- if (!object_to_vim(result, rettv, &err)) {
- assert(ERROR_SET(&err));
- semsg(_("Error converting the call result: %s"), err.msg);
- }
+ object_to_vim(result, rettv, &err);
end:
arena_mem_free(res_mem);
@@ -6889,15 +7292,8 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ScreenGrid *grid;
screenchar_adjust(&grid, &row, &col);
- int c;
- if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) {
- c = -1;
- } else {
- char buf[MAX_SCHAR_SIZE + 1];
- schar_get(buf, grid_getchar(grid, row, col, NULL));
- c = utf_ptr2char(buf);
- }
- rettv->vval.v_number = c;
+ rettv->vval.v_number = (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols)
+ ? -1 : schar_get_first_codepoint(grid_getchar(grid, row, col, NULL));
}
/// "screenchars()" function
@@ -7247,7 +7643,7 @@ int 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", CSTR_AS_OPTVAL(save_cpo), 0);
+ set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0);
}
free_string_option(save_cpo);
}
@@ -8090,7 +8486,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (*p == '+' || *p == '-') {
p = skipwhite(p + 1);
}
- (void)string2float(p, &rettv->vval.v_float);
+ string2float(p, &rettv->vval.v_float);
if (isneg) {
rettv->vval.v_float *= -1;
}
@@ -8391,7 +8787,6 @@ static void f_synIDtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int syntax_flags = 0;
- int cchar;
int matchid = 0;
char str[NUMBUFLEN];
@@ -8405,19 +8800,18 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0
&& (size_t)col <= strlen(ml_get(lnum)) && curwin->w_p_cole > 0) {
- (void)syn_get_id(curwin, lnum, col, false, NULL, false);
+ syn_get_id(curwin, lnum, col, false, NULL, false);
syntax_flags = get_syntax_info(&matchid);
// get the conceal character
if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) {
- cchar = syn_get_sub_char();
+ schar_T cchar = schar_from_char(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;
+ ? schar_from_ascii(' ') : curwin->w_p_lcs_chars.conceal;
}
if (cchar != NUL) {
- utf_char2bytes(cchar, str);
+ schar_get(str, cchar);
}
}
}
@@ -8443,7 +8837,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
&& col >= 0
&& (size_t)col <= strlen(ml_get(lnum))) {
tv_list_alloc_ret(rettv, kListLenMayKnow);
- (void)syn_get_id(curwin, lnum, col, false, NULL, true);
+ syn_get_id(curwin, lnum, col, false, NULL, true);
int id;
int i = 0;
@@ -8517,8 +8911,8 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (argvars[1].v_type != VAR_UNKNOWN) {
fname = tv_get_string(&argvars[1]);
}
- (void)get_tags(tv_list_alloc_ret(rettv, kListLenUnknown),
- (char *)tag_pattern, (char *)fname);
+ get_tags(tv_list_alloc_ret(rettv, kListLenUnknown),
+ (char *)tag_pattern, (char *)fname);
}
/// "tempname()" function
@@ -8558,8 +8952,8 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- CallbackReader on_stdout = CALLBACK_READER_INIT,
- on_stderr = CALLBACK_READER_INIT;
+ CallbackReader on_stdout = CALLBACK_READER_INIT;
+ CallbackReader on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
dict_T *job_opts = NULL;
const char *cwd = ".";
@@ -8637,17 +9031,17 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
curbuf->b_p_swf = false;
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
- (void)setfname(curbuf, NameBuff, NULL, true);
+ setfname(curbuf, NameBuff, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
// Save the job id and pid in b:terminal_job_{id,pid}
Error err = ERROR_INIT;
// deprecated: use 'channel' buffer option
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
- INTEGER_OBJ((Integer)chan->id), false, false, &err);
+ INTEGER_OBJ((Integer)chan->id), false, false, NULL, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
- INTEGER_OBJ(pid), false, false, &err);
+ INTEGER_OBJ(pid), false, false, NULL, &err);
api_clear_error(&err);
channel_incref(chan);
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index 0c345dacb4..e3a574b233 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -3,7 +3,6 @@
#include <stdbool.h>
#include <stdint.h>
-#include "nvim/buffer_defs.h" // IWYU pragma: keep
#include "nvim/cmdexpand_defs.h" // IWYU pragma: keep
#include "nvim/eval/typval_defs.h"
#include "nvim/pos_defs.h" // IWYU pragma: keep
diff --git a/src/nvim/eval/gc.h b/src/nvim/eval/gc.h
index 36149ec060..ea91952fff 100644
--- a/src/nvim/eval/gc.h
+++ b/src/nvim/eval/gc.h
@@ -6,5 +6,5 @@ extern dict_T *gc_first_dict;
extern list_T *gc_first_list;
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/gc.h.generated.h" // IWYU pragma: export
+# include "eval/gc.h.generated.h"
#endif
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 069cdced34..9328f53dbd 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -5,7 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <uv.h>
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
@@ -20,10 +20,11 @@
#include "nvim/eval/vars.h"
#include "nvim/garray.h"
#include "nvim/garray_defs.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
-#include "nvim/lib/queue.h"
+#include "nvim/hashtab_defs.h"
+#include "nvim/lib/queue_defs.h"
#include "nvim/lua/executor.h"
#include "nvim/macros_defs.h"
#include "nvim/mbyte.h"
@@ -622,13 +623,14 @@ tv_list_copy_error:
listitem_T *tv_list_check_range_index_one(list_T *const l, int *const n1, const bool quiet)
{
listitem_T *li = tv_list_find_index(l, n1);
- if (li == NULL) {
- if (!quiet) {
- semsg(_(e_list_index_out_of_range_nr), (int64_t)(*n1));
- }
- return NULL;
+ if (li != NULL) {
+ return li;
}
- return li;
+
+ if (!quiet) {
+ semsg(_(e_list_index_out_of_range_nr), (int64_t)(*n1));
+ }
+ return NULL;
}
/// Check that "n2" can be used as the second index in a range of list "l".
@@ -1633,11 +1635,13 @@ static listitem_T *tv_list_find_index(list_T *const l, int *const idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
listitem_T *li = tv_list_find(l, *idx);
- if (li == NULL) {
- if (*idx < 0) {
- *idx = 0;
- li = tv_list_find(l, *idx);
- }
+ if (li != NULL) {
+ return li;
+ }
+
+ if (*idx < 0) {
+ *idx = 0;
+ li = tv_list_find(l, *idx);
}
return li;
}
@@ -1801,10 +1805,10 @@ void callback_copy(Callback *dest, Callback *src)
}
/// Generate a string description of a callback
-char *callback_to_string(Callback *cb)
+char *callback_to_string(Callback *cb, Arena *arena)
{
if (cb->type == kCallbackLua) {
- return nlua_funcref_str(cb->data.luaref);
+ return nlua_funcref_str(cb->data.luaref, arena);
}
const size_t msglen = 100;
@@ -2129,10 +2133,12 @@ void tv_dict_free_dict(dict_T *const d)
void tv_dict_free(dict_T *const d)
FUNC_ATTR_NONNULL_ALL
{
- if (!tv_in_free_unref_items) {
- tv_dict_free_contents(d);
- tv_dict_free_dict(d);
+ if (tv_in_free_unref_items) {
+ return;
}
+
+ tv_dict_free_contents(d);
+ tv_dict_free_dict(d);
}
/// Unreference a dictionary
@@ -2910,7 +2916,7 @@ static int tv_blob_index(const blob_T *blob, int len, varnumber_T idx, typval_T
return OK;
}
-int tv_blob_slice_or_index(const blob_T *blob, int is_range, varnumber_T n1, varnumber_T n2,
+int tv_blob_slice_or_index(const blob_T *blob, bool is_range, varnumber_T n1, varnumber_T n2,
bool exclusive, typval_T *rettv)
{
int len = tv_blob_len(rettv->vval.v_blob);
@@ -4345,6 +4351,22 @@ int tv_check_for_string_or_number_arg(const typval_T *const args, const int idx)
return OK;
}
+/// Give an error and return FAIL unless "args[idx]" is a buffer number.
+/// Buffer number can be a number or a string.
+int tv_check_for_buffer_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ return tv_check_for_string_or_number_arg(args, idx);
+}
+
+/// Give an error and return FAIL unless "args[idx]" is a line number.
+/// Line number can be a number or a string.
+int tv_check_for_lnum_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ return tv_check_for_string_or_number_arg(args, idx);
+}
+
/// Give an error and return FAIL unless "args[idx]" is a string or a list.
int tv_check_for_string_or_list_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 58f74a9796..f9ebd2f778 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -6,14 +6,13 @@
#include <stdint.h>
#include <string.h>
-#include "nvim/eval/typval_defs.h" // IWYU pragma: export
+#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
#include "nvim/func_attr.h"
-#include "nvim/garray_defs.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/hashtab.h"
-#include "nvim/lib/queue.h"
+#include "nvim/lib/queue_defs.h"
#include "nvim/macros_defs.h"
-#include "nvim/mbyte_defs.h"
+#include "nvim/mbyte_defs.h" // IWYU pragma: keep
#include "nvim/message.h"
#include "nvim/types_defs.h"
@@ -85,6 +84,9 @@ static inline void tv_list_set_lock(list_T *const l, const VarLockStatus lock)
l->lv_lock = lock;
}
+static inline void tv_list_set_copyid(list_T *l, int copyid)
+ REAL_FATTR_NONNULL_ALL;
+
/// Set list copyID
///
/// Does not expect NULL list, be careful.
@@ -92,7 +94,6 @@ static inline void tv_list_set_lock(list_T *const l, const VarLockStatus lock)
/// @param[out] l List to modify.
/// @param[in] copyid New copyID.
static inline void tv_list_set_copyid(list_T *const l, const int copyid)
- FUNC_ATTR_NONNULL_ALL
{
l->lv_copyID = copyid;
}
@@ -359,7 +360,7 @@ extern bool tv_in_free_unref_items;
/// @param li Name of the variable with current listitem_T entry.
/// @param code Cycle body.
#define TV_LIST_ITER(l, li, code) \
- TV_LIST_ITER_MOD( , l, li, code) // NOLINT(whitespace/parens)
+ TV_LIST_ITER_MOD( , l, li, code)
/// Iterate over a list
///
@@ -442,22 +443,20 @@ static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret
}
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
- REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
- REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE
- FUNC_ATTR_NO_SANITIZE_ADDRESS;
+ REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET
+ REAL_FATTR_NO_SANITIZE_ADDRESS REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Compute the `DictWatcher` address from a QUEUE node.
///
/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
/// arithmetic).
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
- FUNC_ATTR_NO_SANITIZE_ADDRESS
{
return QUEUE_DATA(q, DictWatcher, node);
}
static inline bool tv_is_func(typval_T tv)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
+ REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
/// Check whether given typval_T contains a function
///
diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h
index c6bd11ccdb..0d6ee28adc 100644
--- a/src/nvim/eval/typval_defs.h
+++ b/src/nvim/eval/typval_defs.h
@@ -2,10 +2,11 @@
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include "nvim/garray_defs.h"
#include "nvim/hashtab_defs.h"
-#include "nvim/lib/queue.h"
+#include "nvim/lib/queue_defs.h"
#include "nvim/pos_defs.h"
#include "nvim/types_defs.h"
@@ -13,8 +14,10 @@
typedef int64_t varnumber_T;
typedef uint64_t uvarnumber_T;
-/// Refcount for dict or list that should not be freed
-enum { DO_NOT_FREE_CNT = (INT_MAX / 2), };
+enum {
+ /// Refcount for dict or list that should not be freed
+ DO_NOT_FREE_CNT = (INT_MAX / 2),
+};
/// Additional values for tv_list_alloc() len argument
enum ListLenSpecials {
@@ -72,7 +75,7 @@ typedef struct {
#define CALLBACK_NONE ((Callback)CALLBACK_INIT)
/// Structure holding dictionary watcher
-typedef struct dict_watcher {
+typedef struct {
Callback callback;
char *key_pattern;
size_t key_pattern_len;
@@ -291,12 +294,9 @@ typedef struct {
uint64_t channel_id; /// Only used when script_id is SID_API_CLIENT.
} LastSet;
-/// Maximum number of function arguments
-enum { MAX_FUNC_ARGS = 20, };
-/// Short variable name length
-enum { VAR_SHORT_LEN = 20, };
-/// Number of fixed variables used for arguments
-enum { FIXVAR_CNT = 12, };
+enum { MAX_FUNC_ARGS = 20, }; ///< Maximum number of function arguments
+enum { VAR_SHORT_LEN = 20, }; ///< Short variable name length
+enum { FIXVAR_CNT = 12, }; ///< Number of fixed variables used for arguments
/// Structure to hold info for a function that is currently being executed.
typedef struct funccall_S funccall_T;
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 2e0b68d486..c0cd0ce557 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -246,11 +246,12 @@
#include <inttypes.h>
#include <stddef.h>
+#include "klib/kvec.h"
+#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/func_attr.h"
-#include "klib/kvec.h"
/// Dummy variable used because some macros need lvalue
///
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 33fab82d21..d16814ed1e 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -10,6 +10,8 @@
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
@@ -22,11 +24,13 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/ex_eval_defs.h"
#include "nvim/ex_getln.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
+#include "nvim/garray_defs.h"
#include "nvim/getchar.h"
-#include "nvim/gettext.h"
+#include "nvim/getchar_defs.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/insexpand.h"
@@ -41,11 +45,13 @@
#include "nvim/path.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
+#include "nvim/regexp_defs.h"
#include "nvim/runtime.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
+#include "nvim/ui_defs.h"
#include "nvim/vim_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -105,8 +111,6 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
bool mustend = false;
char *arg = *argp;
char *p = arg;
- uint8_t c;
- int i;
if (newargs != NULL) {
ga_init(newargs, (int)sizeof(char *), 3);
@@ -143,12 +147,12 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
}
if (newargs != NULL) {
ga_grow(newargs, 1);
- c = (uint8_t)(*p);
+ uint8_t c = (uint8_t)(*p);
*p = NUL;
arg = xstrdup(arg);
// Check for duplicate argument name.
- for (i = 0; i < newargs->ga_len; i++) {
+ for (int i = 0; i < newargs->ga_len; i++) {
if (strcmp(((char **)(newargs->ga_data))[i], arg) == 0) {
semsg(_("E853: Duplicate argument name: %s"), arg);
xfree(arg);
@@ -174,7 +178,7 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
while (p > expr && ascii_iswhite(p[-1])) {
p--;
}
- c = (uint8_t)(*p);
+ uint8_t c = (uint8_t)(*p);
*p = NUL;
expr = xstrdup(expr);
((char **)(default_args->ga_data))[default_args->ga_len] = expr;
@@ -326,7 +330,6 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg)
if (evaluate) {
int flags = 0;
- char *p;
garray_T newlines;
char *name = get_lambda_name();
@@ -339,7 +342,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg)
// Add "return " before the expression.
size_t len = (size_t)(7 + end - start + 1);
- p = xmalloc(len);
+ char *p = xmalloc(len);
((char **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
xstrlcpy(p + 7, start, (size_t)(end - start) + 1);
@@ -919,11 +922,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
bool using_sandbox = false;
- int save_did_emsg;
static int depth = 0;
dictitem_T *v;
int fixvar_idx = 0; // index in fc_fixvar[]
- int ai;
bool islambda = false;
char numbuf[NUMBUFLEN];
char *name;
@@ -931,7 +932,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
int tv_to_free_len = 0;
proftime_T wait_start;
proftime_T call_start;
- int started_profiling = false;
+ bool started_profiling = false;
bool did_save_redo = false;
save_redo_T save_redo;
char* saved_repeat_cmdline = NULL;
@@ -1030,7 +1031,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
bool isdefault = false;
typval_T def_rettv;
- ai = i - fp->uf_args.ga_len;
+ int ai = i - fp->uf_args.ga_len;
if (ai < 0) {
// named argument a:name
name = FUNCARG(fp, i);
@@ -1173,7 +1174,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
const sctx_T save_current_sctx = current_sctx;
current_sctx = fp->uf_script_ctx;
- save_did_emsg = did_emsg;
+ int save_did_emsg = did_emsg;
did_emsg = false;
if (default_arg_err && (fp->uf_flags & FC_ABORT)) {
@@ -1184,7 +1185,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
// A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly.
ex_nesting_level++;
- (void)eval1(&p, rettv, &EVALARG_EVALUATE);
+ eval1(&p, rettv, &EVALARG_EVALUATE);
ex_nesting_level--;
} else {
// call do_cmdline() to execute the lines
@@ -2080,7 +2081,7 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
if (strncmp(p, "<lambda>", 8) == 0) {
p += 8;
- (void)getdigits(&p, false, 0);
+ getdigits(&p, false, 0);
saved = xmemdupz(*name, (size_t)(p - *name));
if (fudi != NULL) {
CLEAR_POINTER(fudi);
@@ -3044,7 +3045,7 @@ static inline bool fc_referenced(const funccall_T *const fc)
/// @return true if items in "fc" do not have "copyID". That means they are not
/// referenced from anywhere that is in use.
-static int can_free_funccal(funccall_T *fc, int copyID)
+static bool can_free_funccal(funccall_T *fc, int copyID)
{
return fc->fc_l_varlist.lv_copyID != copyID
&& fc->fc_l_vars.dv_copyID != copyID
@@ -3057,7 +3058,7 @@ void ex_return(exarg_T *eap)
{
char *arg = eap->arg;
typval_T rettv;
- int returning = false;
+ bool returning = false;
if (current_funccal == NULL) {
emsg(_("E133: :return not inside a function"));
@@ -3404,7 +3405,7 @@ end:
///
/// @return true when the return can be carried out,
/// false when the return gets pending.
-int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
+bool do_return(exarg_T *eap, bool reanimate, bool is_cmd, void *rettv)
{
cstack_T *const cstack = eap->cstack;
@@ -3669,7 +3670,7 @@ bool free_unref_funccal(int copyID, int testing)
if (did_free_funccal) {
// When a funccal was freed some more items might be garbage
// collected, so run again.
- (void)garbage_collect(testing);
+ garbage_collect(testing);
}
return did_free;
}
@@ -3825,7 +3826,7 @@ bool set_ref_in_previous_funccal(int copyID)
fc->fc_copyID = copyID + 1;
if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID + 1, NULL)
|| set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_list(&fc->fc_l_varlist, copyID + 1, NULL)) {
+ || set_ref_in_list_items(&fc->fc_l_varlist, copyID + 1, NULL)) {
return true;
}
}
@@ -3838,7 +3839,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
fc->fc_copyID = copyID;
if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID, NULL)
|| set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID, NULL)
- || set_ref_in_list(&fc->fc_l_varlist, copyID, NULL)
+ || set_ref_in_list_items(&fc->fc_l_varlist, copyID, NULL)
|| set_ref_in_func(NULL, fc->fc_func, copyID)) {
return true;
}
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index 8050caab2b..b3488b15a7 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -4,15 +4,13 @@
#include <stddef.h>
#include "nvim/cmdexpand_defs.h" // IWYU pragma: keep
-#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
+#include "nvim/eval_defs.h" // IWYU pragma: keep
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
#include "nvim/hashtab_defs.h" // IWYU pragma: keep
#include "nvim/pos_defs.h"
#include "nvim/types_defs.h" // IWYU pragma: keep
-struct funccal_entry;
-
// From user function to hashitem and back.
#define UF2HIKEY(fp) ((fp)->uf_name)
#define HIKEY2UF(p) ((ufunc_T *)((p) - offsetof(ufunc_T, uf_name)))
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 2968f75f4d..91ac60d8ea 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -7,10 +7,11 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <uv.h>
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
@@ -18,16 +19,17 @@
#include "nvim/eval/encode.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"
+#include "nvim/eval_defs.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/macros_defs.h"
@@ -44,6 +46,8 @@
#include "nvim/vim_defs.h"
#include "nvim/window.h"
+typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int);
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/vars.c.generated.h"
#endif
@@ -377,7 +381,7 @@ void ex_let(exarg_T *eap)
if (!eap->skip) {
op[0] = '=';
op[1] = NUL;
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
+ ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
}
tv_clear(&rettv);
}
@@ -414,7 +418,7 @@ void ex_let(exarg_T *eap)
clear_evalarg(&evalarg, eap);
if (!eap->skip && eval_res != FAIL) {
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
+ ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
}
if (eval_res != FAIL) {
tv_clear(&rettv);
@@ -553,7 +557,7 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
static const char *skip_var_one(const char *arg)
{
if (*arg == '@' && arg[1] != NUL) {
- return arg + 2;
+ return arg + 1 + utfc_ptr2len(arg + 1);
}
return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
@@ -617,7 +621,7 @@ static void list_tab_vars(int *first)
/// List variables in "arg".
static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
{
- int error = false;
+ bool error = false;
int len;
const char *name;
const char *name_start;
@@ -762,11 +766,12 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
// Find the end of the name.
char *arg_end = NULL;
+ OptIndex opt_idx;
int scope;
- char *const p = (char *)find_option_end((const char **)&arg, &scope);
- if (p == NULL
- || (endchars != NULL
- && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
+
+ char *const p = (char *)find_option_var_end((const char **)&arg, &opt_idx, &scope);
+
+ if (p == NULL || (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
emsg(_(e_letunexp));
return NULL;
}
@@ -774,11 +779,12 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
const char c1 = *p;
*p = NUL;
- uint32_t opt_p_flags;
- bool hidden;
- OptVal curval = get_option_value(arg, &opt_p_flags, scope, &hidden);
+ bool is_tty_opt = is_tty_option(arg);
+ bool hidden = is_option_hidden(opt_idx);
+ OptVal curval = is_tty_opt ? get_tty_option(arg) : get_option_value(opt_idx, scope);
OptVal newval = NIL_OPTVAL;
- if (curval.type == kOptValTypeNil && arg[0] != 't' && arg[1] != '_') {
+
+ if (curval.type == kOptValTypeNil) {
semsg(_(e_unknown_option2), arg);
goto theend;
}
@@ -790,7 +796,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
}
bool error;
- newval = tv_to_optval(tv, arg, opt_p_flags, &error);
+ newval = tv_to_optval(tv, opt_idx, arg, &error);
if (error) {
goto theend;
}
@@ -832,7 +838,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
}
}
- const char *err = set_option_value(arg, newval, scope);
+ const char *err = set_option_value_handle_tty(arg, opt_idx, newval, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -857,16 +863,20 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const,
char *arg_end = NULL;
arg++;
+
+ int regname = utf_ptr2char(arg);
+ int mblen = utf_ptr2len(arg);
+
if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + mblen))) == NULL) {
emsg(_(e_letunexp));
} else {
char *ptofree = NULL;
const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
- char *s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
+ char *s = get_reg_contents(*arg == '@' ? '"' : regname, kGRegExprSrc);
if (s != NULL) {
ptofree = concat_str(s, p);
p = ptofree;
@@ -874,8 +884,9 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const,
}
}
if (p != NULL) {
- write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false);
- arg_end = arg + 1;
+ write_reg_contents(*arg == '@' ? '"' : regname,
+ p, (ssize_t)strlen(p), false);
+ arg_end = arg + mblen;
}
xfree(ptofree);
}
@@ -1300,7 +1311,7 @@ void vars_clear(hashtab_T *ht)
}
/// Like vars_clear(), but only free the value if "free_val" is true.
-void vars_clear_ext(hashtab_T *ht, int free_val)
+void vars_clear_ext(hashtab_T *ht, bool free_val)
{
int todo;
hashitem_T *hi;
@@ -1847,22 +1858,27 @@ static void getwinvar(typval_T *argvars, typval_T *rettv, int off)
///
/// @return Typval converted to OptVal. Must be freed by caller.
/// Returns NIL_OPTVAL for invalid option name.
-static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, bool *error)
+///
+/// TODO(famiu): Refactor this to support multitype options.
+static OptVal tv_to_optval(typval_T *tv, OptIndex opt_idx, const char *option, bool *error)
{
OptVal value = NIL_OPTVAL;
char nbuf[NUMBUFLEN];
bool err = false;
+ const bool is_tty_opt = is_tty_option(option);
+ const bool option_has_bool = !is_tty_opt && option_has_type(opt_idx, kOptValTypeBoolean);
+ const bool option_has_num = !is_tty_opt && option_has_type(opt_idx, kOptValTypeNumber);
+ const bool option_has_str = is_tty_opt || option_has_type(opt_idx, kOptValTypeString);
- if ((flags & P_FUNC) && tv_is_func(*tv)) {
+ if (!is_tty_opt && (get_option(opt_idx)->flags & P_FUNC) && tv_is_func(*tv)) {
// If the option can be set to a function reference or a lambda
// and the passed value is a function reference, then convert it to
// the name (string) of the function reference.
char *strval = encode_tv2string(tv, NULL);
err = strval == NULL;
value = CSTR_AS_OPTVAL(strval);
- } else if (flags & (P_NUM | P_BOOL)) {
- varnumber_T n = (flags & P_NUM) ? tv_get_number_chk(tv, &err)
- : tv_get_bool_chk(tv, &err);
+ } else if (option_has_bool || option_has_num) {
+ varnumber_T n = option_has_num ? tv_get_number_chk(tv, &err) : tv_get_bool_chk(tv, &err);
// This could be either "0" or a string that's not a number.
// So we need to check if it's actually a number.
if (!err && tv->v_type == VAR_STRING && n == 0) {
@@ -1875,14 +1891,14 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
semsg(_("E521: Number required: &%s = '%s'"), option, tv->vval.v_string);
}
}
- value = (flags & P_NUM) ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
- } else if ((flags & P_STRING) || is_tty_option(option)) {
+ value = option_has_num ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
+ } else if (option_has_str) {
// Avoid setting string option to a boolean or a special value.
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
const char *strval = tv_get_string_buf_chk(tv, nbuf);
err = strval == NULL;
value = CSTR_TO_OPTVAL(strval);
- } else if (flags & P_STRING) {
+ } else if (!is_tty_opt) {
err = true;
emsg(_(e_stringreq));
}
@@ -1898,10 +1914,12 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
/// Convert an option value to typval.
///
-/// @param[in] value Option value to convert.
+/// @param[in] value Option value to convert.
+/// @param numbool Whether to convert boolean values to number.
+/// Used for backwards compatibility.
///
/// @return OptVal converted to typval.
-typval_T optval_as_tv(OptVal value)
+typval_T optval_as_tv(OptVal value, bool numbool)
{
typval_T rettv = { .v_type = VAR_SPECIAL, .vval = { .v_special = kSpecialVarNull } };
@@ -1909,19 +1927,16 @@ typval_T optval_as_tv(OptVal value)
case kOptValTypeNil:
break;
case kOptValTypeBoolean:
- switch (value.data.boolean) {
- case kTrue:
- rettv.v_type = VAR_BOOL;
- rettv.vval.v_bool = kBoolVarTrue;
- break;
- case kFalse:
- rettv.v_type = VAR_BOOL;
- rettv.vval.v_bool = kBoolVarFalse;
- break;
- case kNone:
- break; // return v:null for None boolean value
+ if (value.data.boolean != kNone) {
+ if (numbool) {
+ rettv.v_type = VAR_NUMBER;
+ rettv.vval.v_number = value.data.boolean == kTrue;
+ } else {
+ rettv.v_type = VAR_BOOL;
+ rettv.vval.v_bool = value.data.boolean == kTrue;
+ }
}
- break;
+ break; // return v:null for None boolean value.
case kOptValTypeNumber:
rettv.v_type = VAR_NUMBER;
rettv.vval.v_number = value.data.number;
@@ -1938,25 +1953,27 @@ typval_T optval_as_tv(OptVal value)
/// Set option "varname" to the value of "varp" for the current buffer/window.
static void set_option_from_tv(const char *varname, typval_T *varp)
{
- int opt_idx = findoption(varname);
- if (opt_idx < 0) {
+ OptIndex opt_idx = find_option(varname);
+ if (opt_idx == kOptInvalid) {
semsg(_(e_unknown_option2), varname);
return;
}
- uint32_t opt_p_flags = get_option(opt_idx)->flags;
bool error = false;
- OptVal value = tv_to_optval(varp, varname, opt_p_flags, &error);
+ OptVal value = tv_to_optval(varp, opt_idx, varname, &error);
if (!error) {
- set_option_value_give_err(varname, value, OPT_LOCAL);
- }
+ const char *errmsg = set_option_value_handle_tty(varname, opt_idx, value, OPT_LOCAL);
+ if (errmsg) {
+ emsg(errmsg);
+ }
+ }
optval_free(value);
}
/// "setwinvar()" and "settabwinvar()" functions
-static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
+static void setwinvar(typval_T *argvars, int off)
{
if (check_secure()) {
return;
@@ -2065,8 +2082,6 @@ void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "settabvar()" function
void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- rettv->vval.v_number = 0;
-
if (check_secure()) {
return;
}
@@ -2080,6 +2095,7 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
tabpage_T *const save_curtab = curtab;
+ tabpage_T *const save_lu_tp = lastused_tabpage;
goto_tabpage_tp(tp, false, false);
const size_t varname_len = strlen(varname);
@@ -2089,22 +2105,25 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
set_var(tabvarname, varname_len + 2, varp, true);
xfree(tabvarname);
- // Restore current tabpage.
+ // Restore current tabpage and last accessed tabpage.
if (valid_tabpage(save_curtab)) {
goto_tabpage_tp(save_curtab, false, false);
+ if (valid_tabpage(save_lu_tp)) {
+ lastused_tabpage = save_lu_tp;
+ }
}
}
/// "settabwinvar()" function
void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- setwinvar(argvars, rettv, 1);
+ setwinvar(argvars, 1);
}
/// "setwinvar()" function
void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- setwinvar(argvars, rettv, 0);
+ setwinvar(argvars, 0);
}
/// "setbufvar()" function
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
index e0abbad477..b8aa0c9641 100644
--- a/src/nvim/eval/window.c
+++ b/src/nvim/eval/window.c
@@ -9,19 +9,22 @@
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
-#include "nvim/buffer_defs.h"
#include "nvim/cursor.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/window.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/garray_defs.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/macros_defs.h"
+#include "nvim/mark_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/move.h"
+#include "nvim/option_vars.h"
+#include "nvim/os/fs.h"
#include "nvim/pos_defs.h"
#include "nvim/types_defs.h"
#include "nvim/vim_defs.h"
@@ -480,6 +483,68 @@ void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = nr;
}
+/// Switch to a window for executing user code.
+/// Caller must call win_execute_after() later regardless of return value.
+///
+/// @return whether switching the window succeeded.
+bool win_execute_before(win_execute_T *args, win_T *wp, tabpage_T *tp)
+{
+ args->wp = wp;
+ args->curpos = wp->w_cursor;
+ args->cwd_status = FAIL;
+ args->apply_acd = false;
+
+ // Getting and setting directory can be slow on some systems, only do
+ // this when the current or target window/tab have a local directory or
+ // 'acd' is set.
+ if (curwin != wp
+ && (curwin->w_localdir != NULL || wp->w_localdir != NULL
+ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL))
+ || p_acd)) {
+ args->cwd_status = os_dirname(args->cwd, MAXPATHL);
+ }
+
+ // If 'acd' is set, check we are using that directory. If yes, then
+ // apply 'acd' afterwards, otherwise restore the current directory.
+ if (args->cwd_status == OK && p_acd) {
+ do_autochdir();
+ char autocwd[MAXPATHL];
+ if (os_dirname(autocwd, MAXPATHL) == OK) {
+ args->apply_acd = strcmp(args->cwd, autocwd) == 0;
+ }
+ }
+
+ if (switch_win_noblock(&args->switchwin, wp, tp, true) == OK) {
+ check_cursor();
+ return true;
+ }
+ return false;
+}
+
+/// Restore the previous window after executing user code.
+void win_execute_after(win_execute_T *args)
+{
+ restore_win_noblock(&args->switchwin, true);
+
+ if (args->apply_acd) {
+ do_autochdir();
+ } else if (args->cwd_status == OK) {
+ os_chdir(args->cwd);
+ }
+
+ // Update the status line if the cursor moved.
+ if (win_valid(args->wp) && !equalpos(args->curpos, args->wp->w_cursor)) {
+ args->wp->w_redr_status = true;
+ }
+
+ // In case the command moved the cursor or changed the Visual area,
+ // check it is valid.
+ check_cursor();
+ if (VIsual_active) {
+ check_pos(curbuf, &VIsual);
+ }
+}
+
/// "win_execute(win_id, command)" function
void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -494,7 +559,11 @@ void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1));
+ win_execute_T win_execute_args;
+ if (win_execute_before(&win_execute_args, wp, tp)) {
+ execute_common(argvars, rettv, 1);
+ }
+ win_execute_after(&win_execute_args);
}
/// "win_findbuf()" function
@@ -607,13 +676,13 @@ static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags
// Remove the old window and frame from the tree of frames
int dir;
- (void)winframe_remove(wp, &dir, NULL);
+ winframe_remove(wp, &dir, NULL);
win_remove(wp, NULL);
last_status(false); // may need to remove last status line
- (void)win_comp_pos(); // recompute window positions
+ win_comp_pos(); // recompute window positions
// Split a window on the desired side and put the old window there
- (void)win_split_ins(size, flags, wp, dir);
+ win_split_ins(size, flags, wp, dir);
// If splitting horizontally, try to preserve height
if (size == 0 && !(flags & WSP_VERT)) {
@@ -642,7 +711,8 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- int flags = 0, size = 0;
+ int flags = 0;
+ int size = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
dict_T *d;
@@ -685,7 +755,7 @@ void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_string = xstrdup("preview");
} else if (wp->w_floating) {
rettv->vval.v_string = xstrdup("popup");
- } else if (wp == curwin && cmdwin_type != 0) {
+ } else if (wp == cmdwin_win) {
rettv->vval.v_string = xstrdup("command");
} else if (bt_quickfix(wp->w_buffer)) {
rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
@@ -914,16 +984,16 @@ int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool n
return OK;
}
-// Restore current tabpage and window saved by switch_win(), if still valid.
-// When "no_display" is true the display won't be affected, no redraw is
-// triggered.
+/// Restore current tabpage and window saved by switch_win(), if still valid.
+/// When "no_display" is true the display won't be affected, no redraw is
+/// triggered.
void restore_win(switchwin_T *switchwin, bool no_display)
{
restore_win_noblock(switchwin, no_display);
unblock_autocmds();
}
-// As restore_win() but without unblocking autocommands.
+/// As restore_win() but without unblocking autocommands.
void restore_win_noblock(switchwin_T *switchwin, bool no_display)
{
if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
diff --git a/src/nvim/eval/window.h b/src/nvim/eval/window.h
index ed879c895a..37cb138404 100644
--- a/src/nvim/eval/window.h
+++ b/src/nvim/eval/window.h
@@ -1,20 +1,12 @@
#pragma once
#include <stdbool.h>
-#include <string.h>
-#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
-#include "nvim/cursor.h"
-#include "nvim/eval/typval_defs.h"
-#include "nvim/globals.h"
-#include "nvim/mark.h"
-#include "nvim/option_defs.h"
-#include "nvim/option_vars.h"
-#include "nvim/os/fs.h"
+#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
+#include "nvim/os/os_defs.h"
#include "nvim/pos_defs.h"
-#include "nvim/vim_defs.h"
-#include "nvim/window.h"
+#include "nvim/types_defs.h"
/// Structure used by switch_win() to pass values to restore_win()
typedef struct {
@@ -24,53 +16,15 @@ typedef struct {
bool sw_visual_active;
} switchwin_T;
-/// Execute a block of code in the context of window `wp` in tabpage `tp`.
-/// Ensures the status line is redrawn and cursor position is valid if it is moved.
-#define WIN_EXECUTE(wp, tp, block) \
- do { \
- win_T *const wp_ = (wp); \
- const pos_T curpos_ = wp_->w_cursor; \
- char cwd_[MAXPATHL]; \
- char autocwd_[MAXPATHL]; \
- bool apply_acd_ = false; \
- int cwd_status_ = FAIL; \
- /* Getting and setting directory can be slow on some systems, only do */ \
- /* this when the current or target window/tab have a local directory or */ \
- /* 'acd' is set. */ \
- if (curwin != wp \
- && (curwin->w_localdir != NULL || wp->w_localdir != NULL \
- || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
- || p_acd)) { \
- cwd_status_ = os_dirname(cwd_, MAXPATHL); \
- } \
- /* If 'acd' is set, check we are using that directory. If yes, then */ \
- /* apply 'acd' afterwards, otherwise restore the current directory. */ \
- if (cwd_status_ == OK && p_acd) { \
- do_autochdir(); \
- apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \
- } \
- switchwin_T switchwin_; \
- if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
- check_cursor(); \
- block; \
- } \
- restore_win_noblock(&switchwin_, true); \
- if (apply_acd_) { \
- do_autochdir(); \
- } else if (cwd_status_ == OK) { \
- os_chdir(cwd_); \
- } \
- /* Update the status line if the cursor moved. */ \
- if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
- wp_->w_redr_status = true; \
- } \
- /* In case the command moved the cursor or changed the Visual area, */ \
- /* check it is valid. */ \
- check_cursor(); \
- if (VIsual_active) { \
- check_pos(curbuf, &VIsual); \
- } \
- } while (false)
+/// Structure used by win_execute_before() to pass values to win_execute_after()
+typedef struct {
+ win_T *wp;
+ pos_T curpos;
+ char cwd[MAXPATHL];
+ int cwd_status;
+ bool apply_acd;
+ switchwin_T switchwin;
+} win_execute_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/window.h.generated.h"