aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r--src/nvim/eval/funcs.c714
1 files changed, 554 insertions, 160 deletions
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);