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.c2108
1 files changed, 1333 insertions, 775 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1ba31bfe68..5569d74413 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -47,6 +47,7 @@
#include "nvim/os/input.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
@@ -79,22 +80,23 @@ KHASH_MAP_INIT_STR(functions, VimLFuncDef)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/funcs.c.generated.h"
-#ifdef _MSC_VER
+# ifdef _MSC_VER
// This prevents MSVC from replacing the functions with intrinsics,
// and causing errors when trying to get their addresses in funcs.generated.h
-#pragma function(ceil)
-#pragma function(floor)
-#endif
+# pragma function(ceil)
+# pragma function(floor)
+# endif
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
-#include "funcs.generated.h"
+# include "funcs.generated.h"
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
#endif
static char *e_listarg = N_("E686: Argument of %s must be a List");
+static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number");
/// Dummy va_list for passing to vim_snprintf
@@ -113,12 +115,14 @@ char_u *get_function_name(expand_T *xp, int idx)
static int intidx = -1;
char_u *name;
- if (idx == 0)
+ if (idx == 0) {
intidx = -1;
+ }
if (intidx < 0) {
name = get_user_func_name(xp, idx);
if (name != NULL) {
- if (*name != '<' && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
+ if (*name != NUL && *name != '<'
+ && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
return cat_prefix_varname('g', name);
}
return name;
@@ -152,12 +156,14 @@ char_u *get_expr_name(expand_T *xp, int idx)
static int intidx = -1;
char_u *name;
- if (idx == 0)
+ if (idx == 0) {
intidx = -1;
+ }
if (intidx < 0) {
name = get_function_name(xp, idx);
- if (name != NULL)
+ if (name != NULL) {
return name;
+ }
}
return get_user_var_name(xp, ++intidx);
}
@@ -174,6 +180,52 @@ const VimLFuncDef *find_internal_func(const char *const name)
return find_internal_func_gperf(name, len);
}
+int call_internal_func(const char_u *const fname, const int argcount, typval_T *const argvars,
+ typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (argcount < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+ argvars[argcount].v_type = VAR_UNKNOWN;
+ fdef->func(argvars, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
+/// Invoke a method for base->method().
+int call_internal_method(const char_u *const fname, const int argcount, typval_T *const argvars,
+ typval_T *const rettv, typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (fdef->base_arg == BASE_NONE) {
+ return ERROR_NOTMETHOD;
+ } else if (argcount + 1 < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount + 1 > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+
+ typval_T argv[MAX_FUNC_ARGS + 1];
+ const ptrdiff_t base_index
+ = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
+ memcpy(argv, argvars, base_index * sizeof(typval_T));
+ argv[base_index] = *basetv;
+ memcpy(argv + base_index + 1, argvars + base_index,
+ (argcount - base_index) * sizeof(typval_T));
+ argv[argcount + 1].v_type = VAR_UNKNOWN;
+
+ fdef->func(argv, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
/*
* Return TRUE for a non-zero Number and a non-empty String.
*/
@@ -196,7 +248,7 @@ static int non_zero_arg(typval_T *argvars)
static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
float_T f;
- float_T (*function)(float_T) = (float_T (*)(float_T))fptr;
+ float_T (*function)(float_T) = (float_T (*)(float_T)) fptr;
rettv->v_type = VAR_FLOAT;
if (tv_get_float_chk(argvars, &f)) {
@@ -273,8 +325,20 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_tv(l, &argvars[1]);
tv_copy(&argvars[0], rettv);
}
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+ if (b != NULL
+ && !var_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
+ bool error = false;
+ const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ ga_append(&b->bv_ga, (int)n);
+ tv_copy(&argvars[0], rettv);
+ }
+ }
} else {
- EMSG(_(e_listreq));
+ EMSG(_(e_listblobreq));
}
}
@@ -382,8 +446,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = NULL;
int idx = tv_get_number_chk(&argvars[0], NULL);
if (arglist != NULL && idx >= 0 && idx < argcount) {
- rettv->vval.v_string = (char_u *)xstrdup(
- (const char *)alist_name(&arglist[idx]));
+ rettv->vval.v_string = (char_u *)xstrdup((const char *)alist_name(&arglist[idx]));
} else if (idx == -1) {
get_arglist_as_rettv(arglist, argcount, rettv);
}
@@ -425,13 +488,13 @@ static void f_assert_notequal(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "assert_report(msg)
static void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- garray_T ga;
+ garray_T ga;
- prepare_assert_error(&ga);
- ga_concat(&ga, (const char_u *)tv_get_string(&argvars[0]));
- assert_error(&ga);
- ga_clear(&ga);
- rettv->vval.v_number = 1;
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (const char_u *)tv_get_string(&argvars[0]));
+ assert_error(&ga);
+ ga_clear(&ga);
+ rettv->vval.v_number = 1;
}
/// "assert_exception(string[, msg])" function
@@ -515,11 +578,11 @@ static void f_browsedir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static buf_T *find_buffer(typval_T *avar)
{
- buf_T *buf = NULL;
+ buf_T *buf = NULL;
- if (avar->v_type == VAR_NUMBER)
+ if (avar->v_type == VAR_NUMBER) {
buf = buflist_findnr((int)avar->vval.v_number);
- else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
+ } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
buf = buflist_findname_exp(avar->vval.v_string);
if (buf == NULL) {
/* No full path name match, try a match with a URL or a "nofile"
@@ -560,7 +623,7 @@ static void f_bufexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
+ buf_T *buf;
buf = find_buffer(&argvars[0]);
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
@@ -586,7 +649,7 @@ static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
*/
static void f_bufloaded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
+ buf_T *buf;
buf = find_buffer(&argvars[0]);
rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
@@ -688,19 +751,23 @@ static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
buf_T *tv_get_buf(typval_T *tv, int curtab_only)
{
- char_u *name = tv->vval.v_string;
+ char_u *name = tv->vval.v_string;
int save_magic;
- char_u *save_cpo;
- buf_T *buf;
+ char_u *save_cpo;
+ buf_T *buf;
- if (tv->v_type == VAR_NUMBER)
+ if (tv->v_type == VAR_NUMBER) {
return buflist_findnr((int)tv->vval.v_number);
- if (tv->v_type != VAR_STRING)
+ }
+ if (tv->v_type != VAR_STRING) {
return NULL;
- if (name == NULL || *name == NUL)
+ }
+ if (name == NULL || *name == NUL) {
return curbuf;
- if (name[0] == '$' && name[1] == NUL)
+ }
+ if (name[0] == '$' && name[1] == NUL) {
return lastbuf;
+ }
// Ignore 'magic' and 'cpoptions' here to make scripts portable
save_magic = p_magic;
@@ -736,7 +803,7 @@ buf_T *tv_get_buf_from_arg(typval_T *const tv) FUNC_ATTR_NONNULL_ALL
/// Get the buffer from "arg" and give an error and return NULL if it is not
/// valid.
-buf_T * get_buf_arg(typval_T *arg)
+buf_T *get_buf_arg(typval_T *arg)
{
buf_T *buf;
@@ -814,9 +881,9 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
bool owned = false;
- char_u *func;
- partial_T *partial = NULL;
- dict_T *selfdict = NULL;
+ char_u *func;
+ partial_T *partial = NULL;
+ dict_T *selfdict = NULL;
if (argvars[0].v_type == VAR_FUNC) {
func = argvars[0].vval.v_string;
} else if (argvars[0].v_type == VAR_PARTIAL) {
@@ -866,7 +933,7 @@ static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[0].v_type != VAR_NUMBER || (argvars[1].v_type != VAR_STRING
- && argvars[1].v_type != VAR_UNKNOWN)) {
+ && argvars[1].v_type != VAR_UNKNOWN)) {
EMSG(_(e_invarg));
return;
}
@@ -911,7 +978,17 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ptrdiff_t input_len = 0;
- char *input = save_tv_as_string(&argvars[1], &input_len, false);
+ char *input = NULL;
+ if (argvars[1].v_type == VAR_BLOB) {
+ const blob_T *const b = argvars[1].vval.v_blob;
+ input_len = tv_blob_len(b);
+ if (input_len > 0) {
+ input = xmemdup(b->bv_ga.ga_data, input_len);
+ }
+ } else {
+ input = save_tv_as_string(&argvars[1], &input_len, false);
+ }
+
if (!input) {
// Either the error has been handled by save_tv_as_string(),
// or there is no input to send.
@@ -936,8 +1013,7 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- rettv->vval.v_number = utf_ptr2char(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = utf_ptr2char((const char_u *)tv_get_string(&argvars[0]));
}
// "charidx()" function
@@ -1000,11 +1076,12 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
curwin->w_cursor.lnum = lnum;
rettv->vval.v_number = get_c_indent();
curwin->w_cursor = pos;
- } else
+ } else {
rettv->vval.v_number = -1;
+ }
}
-static win_T * get_optional_window(typval_T *argvars, int idx)
+static win_T *get_optional_window(typval_T *argvars, int idx)
{
win_T *win = curwin;
@@ -1036,7 +1113,7 @@ static void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
colnr_T col = 0;
- pos_T *fp;
+ pos_T *fp;
int fnum = curbuf->b_fnum;
fp = var2fpos(&argvars[0], FALSE, &fnum);
@@ -1053,14 +1130,17 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// col(".") when the cursor is on the NUL at the end of the line
// because of "coladd" can be seen as an extra column.
if (virtual_active() && fp == &curwin->w_cursor) {
- char_u *p = get_cursor_pos_ptr();
+ char_u *p = get_cursor_pos_ptr();
- if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
- curwin->w_virtcol - curwin->w_cursor.coladd)) {
+ if (curwin->w_cursor.coladd
+ >= (colnr_T)win_chartabsize(curwin, p,
+ (curwin->w_virtcol
+ - curwin->w_cursor.coladd))) {
int l;
- if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
+ if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) {
col += l;
+ }
}
}
}
@@ -1078,10 +1158,11 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- /* Check for undo allowed here, because if something was already inserted
- * the line was already saved for undo and this check isn't done. */
- if (!undo_allowed())
+ // Check for undo allowed here, because if something was already inserted
+ // the line was already saved for undo and this check isn't done.
+ if (!undo_allowed(curbuf)) {
return;
+ }
if (argvars[1].v_type != VAR_LIST) {
EMSG(_(e_invarg));
@@ -1165,11 +1246,16 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
error = true;
} else {
switch (TOUPPER_ASC(*typestr)) {
- case 'E': type = VIM_ERROR; break;
- case 'Q': type = VIM_QUESTION; break;
- case 'I': type = VIM_INFO; break;
- case 'W': type = VIM_WARNING; break;
- case 'G': type = VIM_GENERIC; break;
+ case 'E':
+ type = VIM_ERROR; break;
+ case 'Q':
+ type = VIM_QUESTION; break;
+ case 'I':
+ type = VIM_INFO; break;
+ case 'W':
+ type = VIM_WARNING; break;
+ case 'G':
+ type = VIM_GENERIC; break;
}
}
}
@@ -1181,8 +1267,8 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!error) {
- rettv->vval.v_number = do_dialog(
- type, NULL, (char_u *)message, (char_u *)buttons, def, NULL, false);
+ rettv->vval.v_number = do_dialog(type, NULL, (char_u *)message, (char_u *)buttons, def, NULL,
+ false);
}
}
@@ -1232,8 +1318,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
} else if (argvars[0].v_type == VAR_LIST) {
- listitem_T *li;
- list_T *l;
+ listitem_T *li;
+ list_T *l;
long idx;
if ((l = argvars[0].vval.v_list) != NULL) {
@@ -1248,8 +1334,9 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- if (error)
+ if (error) {
li = NULL;
+ }
}
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
@@ -1260,8 +1347,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (argvars[0].v_type == VAR_DICT) {
int todo;
- dict_T *d;
- hashitem_T *hi;
+ dict_T *d;
+ hashitem_T *hi;
if ((d = argvars[0].vval.v_dict) != NULL) {
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -1715,7 +1802,7 @@ static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
+ rettv->vval.v_number = MAX(0, diff_check(curwin, tv_get_lnum(argvars)));
}
/*
@@ -1780,53 +1867,45 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool n = true;
switch (argvars[0].v_type) {
- case VAR_STRING:
- case VAR_FUNC: {
- n = argvars[0].vval.v_string == NULL
- || *argvars[0].vval.v_string == NUL;
- break;
- }
- case VAR_PARTIAL: {
+ case VAR_STRING:
+ case VAR_FUNC:
+ n = argvars[0].vval.v_string == NULL
+ || *argvars[0].vval.v_string == NUL;
+ break;
+ case VAR_PARTIAL:
+ n = false;
+ break;
+ case VAR_NUMBER:
+ n = argvars[0].vval.v_number == 0;
+ break;
+ case VAR_FLOAT:
+ n = argvars[0].vval.v_float == 0.0;
+ break;
+ case VAR_LIST:
+ n = (tv_list_len(argvars[0].vval.v_list) == 0);
+ break;
+ case VAR_DICT:
+ n = (tv_dict_len(argvars[0].vval.v_dict) == 0);
+ break;
+ case VAR_BOOL:
+ switch (argvars[0].vval.v_bool) {
+ case kBoolVarTrue:
n = false;
break;
- }
- case VAR_NUMBER: {
- n = argvars[0].vval.v_number == 0;
- break;
- }
- case VAR_FLOAT: {
- n = argvars[0].vval.v_float == 0.0;
- break;
- }
- case VAR_LIST: {
- n = (tv_list_len(argvars[0].vval.v_list) == 0);
- break;
- }
- case VAR_DICT: {
- n = (tv_dict_len(argvars[0].vval.v_dict) == 0);
- break;
- }
- case VAR_BOOL: {
- switch (argvars[0].vval.v_bool) {
- case kBoolVarTrue: {
- n = false;
- break;
- }
- case kBoolVarFalse: {
- n = true;
- break;
- }
- }
- break;
- }
- case VAR_SPECIAL: {
- n = argvars[0].vval.v_special == kSpecialVarNull;
- break;
- }
- case VAR_UNKNOWN: {
- internal_error("f_empty(UNKNOWN)");
+ case kBoolVarFalse:
+ n = true;
break;
}
+ break;
+ case VAR_SPECIAL:
+ n = argvars[0].vval.v_special == kSpecialVarNull;
+ break;
+ case VAR_BLOB:
+ n = (tv_blob_len(argvars[0].vval.v_blob) == 0);
+ break;
+ case VAR_UNKNOWN:
+ internal_error("f_empty(UNKNOWN)");
+ break;
}
rettv->vval.v_number = n;
@@ -1886,9 +1965,8 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char buf[NUMBUFLEN];
- rettv->vval.v_string = vim_strsave_escaped(
- (const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_string = vim_strsave_escaped((const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
rettv->v_type = VAR_STRING;
}
@@ -1921,7 +1999,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (expr_start != NULL && !aborting()) {
EMSG2(_(e_invexpr2), expr_start);
}
- need_clr_eos = FALSE;
+ need_clr_eos = false;
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
} else if (*s != NUL) {
@@ -1969,8 +2047,7 @@ static char_u *get_list_line(int c, void *cookie, int indent, bool do_concat)
return (char_u *)(s == NULL ? NULL : xstrdup(s));
}
-static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr,
- int arg_off)
+static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int arg_off)
{
const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_silent;
@@ -2076,7 +2153,7 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Update the status line if the cursor moved.
if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) {
- wp->w_redr_status = true;
+ wp->w_redr_status = true;
}
}
}
@@ -2144,7 +2221,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
size_t len;
- char_u *errormsg;
+ char_u *errormsg;
int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
expand_T xpc;
bool error = false;
@@ -2443,8 +2520,9 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
if (*fname != NUL && !error) {
do {
- if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
+ if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) {
xfree(fresult);
+ }
fresult = find_file_in_path_option(first ? (char_u *)fname : NULL,
first ? strlen(fname) : 0,
0, first, path,
@@ -2460,8 +2538,9 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
}
- if (rettv->v_type == VAR_STRING)
+ if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = fresult;
+ }
}
@@ -2528,8 +2607,7 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_string = (char_u *)vim_strsave_fnameescape(
- tv_get_string(&argvars[0]), false);
+ rettv->vval.v_string = (char_u *)vim_strsave_fnameescape(tv_get_string(&argvars[0]), false);
rettv->v_type = VAR_STRING;
}
@@ -2617,14 +2695,14 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T foldstart;
- linenr_T foldend;
- char_u *dashes;
- linenr_T lnum;
- char_u *s;
- char_u *r;
- int len;
- char *txt;
+ linenr_T foldstart;
+ linenr_T foldend;
+ char_u *dashes;
+ linenr_T lnum;
+ char_u *s;
+ char_u *r;
+ int len;
+ char *txt;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -2647,8 +2725,9 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
s = skipwhite(s + 2);
if (*skipwhite(s) == NUL && lnum + 1 < foldend) {
s = skipwhite(ml_get(lnum + 1));
- if (*s == '*')
+ if (*s == '*') {
s = skipwhite(s + 1);
+ }
}
}
unsigned long count = (unsigned long)(foldend - foldstart + 1);
@@ -2671,7 +2750,7 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *text;
+ char_u *text;
char_u buf[FOLD_TEXT_LEN];
static bool entered = false;
@@ -2733,14 +2812,30 @@ static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- listitem_T *li;
- list_T *l;
- dictitem_T *di;
- dict_T *d;
- typval_T *tv = NULL;
+ listitem_T *li;
+ list_T *l;
+ dictitem_T *di;
+ dict_T *d;
+ typval_T *tv = NULL;
bool what_is_dict = false;
- if (argvars[0].v_type == VAR_LIST) {
+ if (argvars[0].v_type == VAR_BLOB) {
+ bool error = false;
+ int idx = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ rettv->v_type = VAR_NUMBER;
+ if (idx < 0) {
+ idx = tv_blob_len(argvars[0].vval.v_blob) + idx;
+ }
+ if (idx < 0 || idx >= tv_blob_len(argvars[0].vval.v_blob)) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = tv_blob_get(argvars[0].vval.v_blob, idx);
+ tv = rettv;
+ }
+ }
+ } else if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL) {
bool error = false;
@@ -2801,7 +2896,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
} else {
- EMSG2(_(e_listdictarg), "get()");
+ EMSG2(_(e_listdictblobarg), "get()");
}
if (tv == NULL) {
@@ -2880,11 +2975,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* buffer.
* If 'retlist' is TRUE, then the lines are returned as a Vim List.
*/
-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, int retlist, typval_T *rettv)
{
rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
rettv->vval.v_string = NULL;
@@ -3027,10 +3118,9 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "getchar()" function
- */
-static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+// "getchar()" and "getcharstr()" functions
+static void getchar_common(typval_T *argvars, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
{
varnumber_T n;
bool error = false;
@@ -3097,6 +3187,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
i += utf_char2bytes(n, temp + i);
}
+ assert(i < 10);
temp[i++] = NUL;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = vim_strsave(temp);
@@ -3105,21 +3196,21 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = mouse_row;
int col = mouse_col;
int grid = mouse_grid;
- win_T *win;
linenr_T lnum;
- win_T *wp;
+ win_T *wp;
int winnr = 1;
if (row >= 0 && col >= 0) {
- /* Find the window at the mouse coordinates and compute the
- * text position. */
- win = mouse_find_win(&grid, &row, &col);
+ // Find the window at the mouse coordinates and compute the
+ // text position.
+ win_T *const win = mouse_find_win(&grid, &row, &col);
if (win == NULL) {
return;
}
(void)mouse_comp_pos(win, &row, &col, &lnum);
- for (wp = firstwin; wp != win; wp = wp->w_next)
+ for (wp = firstwin; wp != win; wp = wp->w_next) {
++winnr;
+ }
set_vim_var_nr(VV_MOUSE_WIN, winnr);
set_vim_var_nr(VV_MOUSE_WINID, wp->handle);
set_vim_var_nr(VV_MOUSE_LNUM, lnum);
@@ -3129,6 +3220,32 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "getchar()" function
+static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getchar_common(argvars, rettv);
+}
+
+// "getcharstr()" function
+static void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getchar_common(argvars, rettv);
+
+ if (rettv->v_type == VAR_NUMBER) {
+ char_u temp[7]; // mbyte-char: 6, NUL: 1
+ const varnumber_T n = rettv->vval.v_number;
+ int i = 0;
+
+ if (n != 0) {
+ i += utf_char2bytes(n, temp);
+ }
+ assert(i < 7);
+ temp[i++] = NUL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(temp);
+ }
+}
+
/*
* "getcharmod()" function
*/
@@ -3192,11 +3309,11 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "getcompletion()" function
static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *pat;
- expand_T xpc;
- bool filtered = false;
- int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
- | WILD_NO_BEEP;
+ char_u *pat;
+ expand_T xpc;
+ bool filtered = false;
+ int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
+ | WILD_NO_BEEP;
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "type must be a string");
@@ -3290,7 +3407,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char_u *from = NULL; // The original string to copy
tabpage_T *tp = curtab; // The tabpage to look at.
- win_T *win = curwin; // The window to look at.
+ win_T *win = curwin; // The window to look at.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -3353,29 +3470,29 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
cwd = xmalloc(MAXPATHL);
switch (scope) {
- case kCdScopeWindow:
- assert(win);
- from = win->w_localdir;
- if (from) {
- break;
- }
- FALLTHROUGH;
- case kCdScopeTab:
- assert(tp);
- from = tp->tp_localdir;
- if (from) {
- break;
- }
- FALLTHROUGH;
- case kCdScopeGlobal:
- if (globaldir) { // `globaldir` is not always set.
- from = globaldir;
- } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD.
- from = (char_u *)""; // Return empty string on failure.
- }
+ case kCdScopeWindow:
+ assert(win);
+ from = win->w_localdir;
+ if (from) {
+ break;
+ }
+ FALLTHROUGH;
+ case kCdScopeTab:
+ assert(tp);
+ from = tp->tp_localdir;
+ if (from) {
break;
- case kCdScopeInvalid: // We should never get here
- abort();
+ }
+ FALLTHROUGH;
+ case kCdScopeGlobal:
+ if (globaldir) { // `globaldir` is not always set.
+ from = globaldir;
+ } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD.
+ from = (char_u *)""; // Return empty string on failure.
+ }
+ break;
+ case kCdScopeInvalid: // We should never get here
+ abort();
}
if (from) {
@@ -3468,8 +3585,8 @@ static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *type = NULL;
- char *t;
+ char_u *type = NULL;
+ char *t;
const char *fname = tv_get_string(&argvars[0]);
@@ -3596,7 +3713,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (cur->match.regprog == NULL) {
// match added with matchaddpos()
for (i = 0; i < MAXPOSMATCH; i++) {
- llpos_T *llpos;
+ llpos_T *llpos;
char buf[30]; // use 30 to avoid compiler warning
llpos = &cur->pos.pos[i];
@@ -3633,6 +3750,59 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "getmousepos()" function
+void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ dict_T *d;
+ win_T *wp;
+ int row = mouse_row;
+ int col = mouse_col;
+ int grid = mouse_grid;
+ varnumber_T winid = 0;
+ varnumber_T winrow = 0;
+ varnumber_T wincol = 0;
+ linenr_T line = 0;
+ varnumber_T column = 0;
+
+ tv_dict_alloc_ret(rettv);
+ d = rettv->vval.v_dict;
+
+ tv_dict_add_nr(d, S_LEN("screenrow"), (varnumber_T)mouse_row + 1);
+ tv_dict_add_nr(d, S_LEN("screencol"), (varnumber_T)mouse_col + 1);
+
+ wp = mouse_find_win(&grid, &row, &col);
+ if (wp != NULL) {
+ int height = wp->w_height + wp->w_status_height;
+ // The height is adjusted by 1 when there is a bottom border. This is not
+ // necessary for a top border since `row` starts at -1 in that case.
+ if (row < height + wp->w_border_adj[2]) {
+ winid = wp->handle;
+ winrow = row + 1 + wp->w_border_adj[0]; // Adjust by 1 for top border
+ wincol = col + 1 + wp->w_border_adj[3]; // Adjust by 1 for left border
+ if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) {
+ char_u *p;
+ int count;
+
+ mouse_comp_pos(wp, &row, &col, &line);
+
+ // limit to text length plus one
+ p = ml_get_buf(wp->w_buffer, line, false);
+ count = (int)STRLEN(p);
+ if (col > count) {
+ col = count;
+ }
+
+ column = col + 1;
+ }
+ }
+ }
+ tv_dict_add_nr(d, S_LEN("winid"), winid);
+ tv_dict_add_nr(d, S_LEN("winrow"), winrow);
+ tv_dict_add_nr(d, S_LEN("wincol"), wincol);
+ tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)line);
+ tv_dict_add_nr(d, S_LEN("column"), column);
+}
+
/*
* "getpid()" function
*/
@@ -3657,12 +3827,10 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
tv_list_append_number(l, ((fp != NULL)
? (varnumber_T)fp->lnum
: (varnumber_T)0));
- tv_list_append_number(
- l, ((fp != NULL)
+ tv_list_append_number(l, ((fp != NULL)
? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
- : (varnumber_T)0));
- tv_list_append_number(
- l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
+ : (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 colnr_T save_curswant = curwin->w_curswant;
@@ -3867,18 +4035,18 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "gettagstack()" function
static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp = curwin; // default is current window
+ win_T *wp = curwin; // default is current window
- tv_dict_alloc_ret(rettv);
+ tv_dict_alloc_ret(rettv);
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- return;
- }
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
}
+ }
- get_tagstack(wp, rettv->vval.v_dict);
+ get_tagstack(wp, rettv->vval.v_dict);
}
/// "getwininfo()" function
@@ -3996,12 +4164,11 @@ static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
//
// Move the window wp into a new split of targetwin in a given direction
//
-static void win_move_into_split(win_T *wp, win_T *targetwin,
- int size, int flags)
+static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
{
- int dir;
- int height = wp->w_height;
- win_T *oldwin = curwin;
+ int dir;
+ int height = wp->w_height;
+ win_T *oldwin = curwin;
if (wp == targetwin) {
return;
@@ -4037,9 +4204,9 @@ static void win_move_into_split(win_T *wp, win_T *targetwin,
// "win_splitmove()" function
static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp;
- win_T *targetwin;
- int flags = 0, size = 0;
+ win_T *wp;
+ win_T *targetwin;
+ int flags = 0, size = 0;
wp = find_win_by_nr_or_id(&argvars[0]);
targetwin = find_win_by_nr_or_id(&argvars[1]);
@@ -4053,8 +4220,8 @@ static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
EMSG(_(e_invarg));
@@ -4133,11 +4300,12 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (!error) {
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
- if (p_wic)
+ if (p_wic) {
options += WILD_ICASE;
+ }
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = ExpandOne(
- &xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL);
+ rettv->vval.v_string = ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
+ WILD_ALL);
} else {
ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
WILD_ALL_KEEP);
@@ -4148,8 +4316,9 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ExpandCleanup(&xpc);
}
- } else
+ } else {
rettv->vval.v_string = NULL;
+ }
}
/// "globpath()" function
@@ -4327,6 +4496,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"user_commands",
"vartabs",
"vertsplit",
+ "vimscript-1",
"virtualedit",
"visual",
"visualextra",
@@ -4408,8 +4578,9 @@ static void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_dictreq));
return;
}
- if (argvars[0].vval.v_dict == NULL)
+ if (argvars[0].vval.v_dict == NULL) {
return;
+ }
rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict,
tv_get_string(&argvars[1]),
@@ -4440,7 +4611,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
};
tabpage_T *tp = curtab; // The tabpage to look at.
- win_T *win = curwin; // The window to look at.
+ win_T *win = curwin; // The window to look at.
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4499,20 +4670,20 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
switch (scope) {
- case kCdScopeWindow:
- assert(win);
- rettv->vval.v_number = win->w_localdir ? 1 : 0;
- break;
- case kCdScopeTab:
- assert(tp);
- rettv->vval.v_number = tp->tp_localdir ? 1 : 0;
- break;
- case kCdScopeGlobal:
- // The global scope never has a local directory
- break;
- case kCdScopeInvalid:
- // We should never get here
- abort();
+ case kCdScopeWindow:
+ assert(win);
+ rettv->vval.v_number = win->w_localdir ? 1 : 0;
+ break;
+ case kCdScopeTab:
+ assert(tp);
+ rettv->vval.v_number = tp->tp_localdir ? 1 : 0;
+ break;
+ case kCdScopeGlobal:
+ // The global scope never has a local directory
+ break;
+ case kCdScopeInvalid:
+ // We should never get here
+ abort();
}
}
@@ -4635,8 +4806,7 @@ static void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = syn_name2id(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = syn_name2id((const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -4644,8 +4814,7 @@ static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = highlight_exists(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = highlight_exists((const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -4672,11 +4841,9 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const str = tv_get_string(&argvars[0]);
char buf1[NUMBUFLEN];
- char_u *const from = enc_canonize(enc_skip(
- (char_u *)tv_get_string_buf(&argvars[1], buf1)));
+ char_u *const from = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[1], buf1)));
char buf2[NUMBUFLEN];
- char_u *const to = enc_canonize(enc_skip(
- (char_u *)tv_get_string_buf(&argvars[2], buf2)));
+ char_u *const to = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
convert_setup(&vimconv, from, to);
@@ -4714,8 +4881,38 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool ic = false;
rettv->vval.v_number = -1;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG(_(e_listreq));
+ if (argvars[0].v_type == VAR_BLOB) {
+ bool error = false;
+ int start = 0;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ start = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ }
+ blob_T *const b = argvars[0].vval.v_blob;
+ if (b == NULL) {
+ return;
+ }
+ if (start < 0) {
+ start = tv_blob_len(b) + start;
+ if (start < 0) {
+ start = 0;
+ }
+ }
+ for (idx = start; idx < tv_blob_len(b); idx++) {
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = tv_blob_get(b, idx);
+ if (tv_equal(&tv, &argvars[1], ic, false)) {
+ rettv->vval.v_number = idx;
+ return;
+ }
+ }
+ return;
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG(_(e_listblobreq));
return;
}
list_T *const l = argvars[0].vval.v_list;
@@ -4844,8 +5041,46 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *l;
bool error = false;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "insert()");
+ if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+
+ if (b == NULL
+ || var_check_lock(b->bv_lock, N_("insert() argument"),
+ TV_TRANSLATE)) {
+ return;
+ }
+
+ long before = 0;
+ const int len = tv_blob_len(b);
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ before = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return; // type error; errmsg already given
+ }
+ if (before < 0 || before > len) {
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
+ const int val = tv_get_number_chk(&argvars[1], &error);
+ if (error) {
+ return;
+ }
+ if (val < 0 || val > 255) {
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
+ return;
+ }
+
+ ga_grow(&b->bv_ga, 1);
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ memmove(p + before + 1, p + before, (size_t)len - before);
+ *(p + before) = val;
+ b->bv_ga.ga_len++;
+
+ tv_copy(&argvars[0], rettv);
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listblobarg), "insert()");
} else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
N_("insert() argument"), TV_TRANSLATE)) {
long before = 0;
@@ -4873,8 +5108,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "interrupt()" function
-static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED,
- typval_T *rettv FUNC_ATTR_UNUSED,
+static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, typval_T *rettv FUNC_ATTR_UNUSED,
FunPtr fptr FUNC_ATTR_UNUSED)
{
got_int = true;
@@ -4902,7 +5136,7 @@ static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
lval_T lv;
- dictitem_T *di;
+ dictitem_T *di;
rettv->vval.v_number = -1;
const char_u *const end = get_lval((char_u *)tv_get_string(&argvars[0]),
@@ -4954,7 +5188,7 @@ static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_isnan(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
- && xisnan(argvars[0].vval.v_float);
+ && xisnan(argvars[0].vval.v_float);
}
/// "id()" function
@@ -5062,9 +5296,7 @@ static const char *required_env_vars[] = {
NULL
};
-static dict_T *create_environment(const dictitem_T *job_env,
- const bool clear_env,
- const bool pty,
+static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, const bool pty,
const char * const pty_term_name)
{
dict_T * env = tv_dict_alloc();
@@ -5181,6 +5413,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool pty = false;
bool clear_env = false;
bool overlapped = false;
+ ChannelStdinMode stdin_mode = kChannelStdinPipe;
CallbackReader on_stdout = CALLBACK_READER_INIT,
on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
@@ -5195,6 +5428,17 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
overlapped = tv_dict_get_number(job_opts, "overlapped") != 0;
+ char *s = tv_dict_get_string(job_opts, "stdin", false);
+ if (s) {
+ if (!strncmp(s, "null", NUMBUFLEN)) {
+ stdin_mode = kChannelStdinNull;
+ } else if (!strncmp(s, "pipe", NUMBUFLEN)) {
+ // Nothing to do, default value
+ } else {
+ EMSG3(_(e_invargNval), "stdin", s);
+ }
+ }
+
if (pty && rpc) {
EMSG2(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set");
shell_free_argv(argv);
@@ -5251,8 +5495,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
env = create_environment(job_env, clear_env, pty, term_name);
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty,
- rpc, overlapped, detach, cwd, width, height,
- env, &rettv->vval.v_number);
+ rpc, overlapped, detach, stdin_mode, cwd,
+ width, height, env, &rettv->vval.v_number);
if (chan) {
channel_create_event(chan, NULL);
}
@@ -5301,7 +5545,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
if (argvars[0].v_type != VAR_LIST || (argvars[1].v_type != VAR_NUMBER
- && argvars[1].v_type != VAR_UNKNOWN)) {
+ && argvars[1].v_type != VAR_UNKNOWN)) {
EMSG(_(e_invarg));
return;
}
@@ -5316,14 +5560,19 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(args, arg, {
Channel *chan = NULL;
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
- || !(chan = find_job(TV_LIST_ITEM_TV(arg)->vval.v_number, false))) {
+ || !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number))
+ || chan->streamtype != kChannelStreamProc) {
+ jobs[i] = NULL; // Invalid job.
+ } else if (process_is_stopped(&chan->stream.proc)) {
+ // Job is stopped but not fully destroyed.
+ // Ensure all callbacks on its event queue are executed. #15402
+ process_wait(&chan->stream.proc, -1, NULL);
jobs[i] = NULL; // Invalid job.
} else {
jobs[i] = chan;
channel_incref(chan);
if (chan->stream.proc.status < 0) {
- // Process any pending events on the job's queue before temporarily
- // replacing it.
+ // Flush any events in the job's queue before temporarily replacing it.
multiqueue_process_events(chan->events);
multiqueue_replace_parent(chan->events, waiting_jobs);
}
@@ -5482,29 +5731,27 @@ static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
switch (argvars[0].v_type) {
- case VAR_STRING:
- case VAR_NUMBER: {
- rettv->vval.v_number = (varnumber_T)strlen(
- tv_get_string(&argvars[0]));
- break;
- }
- case VAR_LIST: {
- rettv->vval.v_number = tv_list_len(argvars[0].vval.v_list);
- break;
- }
- case VAR_DICT: {
- rettv->vval.v_number = tv_dict_len(argvars[0].vval.v_dict);
- break;
- }
- case VAR_UNKNOWN:
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_FLOAT:
- case VAR_PARTIAL:
- case VAR_FUNC: {
- EMSG(_("E701: Invalid type for len()"));
- break;
- }
+ case VAR_STRING:
+ case VAR_NUMBER:
+ rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
+ break;
+ case VAR_BLOB:
+ rettv->vval.v_number = tv_blob_len(argvars[0].vval.v_blob);
+ break;
+ case VAR_LIST:
+ rettv->vval.v_number = tv_list_len(argvars[0].vval.v_list);
+ break;
+ case VAR_DICT:
+ rettv->vval.v_number = tv_dict_len(argvars[0].vval.v_dict);
+ break;
+ case VAR_UNKNOWN:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ EMSG(_("E701: Invalid type for len()"));
+ break;
}
}
@@ -5549,7 +5796,7 @@ static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
}
if (out_type == VAR_NUMBER) {
- rettv->vval.v_number = (varnumber_T)int_out;
+ rettv->vval.v_number = (varnumber_T)int_out;
}
}
@@ -5679,7 +5926,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
int mode;
int abbr = FALSE;
int get_dict = FALSE;
- mapblock_T *mp;
+ mapblock_T *mp;
int buffer_local;
// Return empty string for failure.
@@ -5721,11 +5968,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
if (*rhs == NUL) {
rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
} else {
- rettv->vval.v_string = (char_u *)str2special_save(
- (char *)rhs, false, false);
+ rettv->vval.v_string = (char_u *)str2special_save((char *)rhs, false, false);
}
}
-
} else {
tv_dict_alloc_ret(rettv);
if (rhs != NULL) {
@@ -5775,19 +6020,19 @@ static void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
- char_u *str = NULL;
- long len = 0;
- char_u *expr = NULL;
+ char_u *str = NULL;
+ long len = 0;
+ char_u *expr = NULL;
regmatch_T regmatch;
- char_u *save_cpo;
+ char_u *save_cpo;
long start = 0;
long nth = 1;
colnr_T startcol = 0;
bool match = false;
- list_T *l = NULL;
- listitem_T *li = NULL;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
long idx = 0;
- char_u *tofree = NULL;
+ char_u *tofree = NULL;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo;
@@ -5795,30 +6040,26 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
rettv->vval.v_number = -1;
switch (type) {
- // matchlist(): return empty list when there are no matches.
- case kSomeMatchList: {
- tv_list_alloc_ret(rettv, kListLenMayKnow);
- break;
- }
- // matchstrpos(): return ["", -1, -1, -1]
- case kSomeMatchStrPos: {
- tv_list_alloc_ret(rettv, 4);
- tv_list_append_string(rettv->vval.v_list, "", 0);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
- break;
- }
- case kSomeMatchStr: {
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- break;
- }
- case kSomeMatch:
- case kSomeMatchEnd: {
- // Do nothing: zero is default.
- break;
- }
+ // matchlist(): return empty list when there are no matches.
+ case kSomeMatchList:
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ break;
+ // matchstrpos(): return ["", -1, -1, -1]
+ case kSomeMatchStrPos:
+ tv_list_alloc_ret(rettv, 4);
+ tv_list_append_string(rettv->vval.v_list, "", 0);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ break;
+ case kSomeMatchStr:
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ break;
+ case kSomeMatch:
+ case kSomeMatchEnd:
+ // Do nothing: zero is default.
+ break;
}
if (argvars[0].v_type == VAR_LIST) {
@@ -5851,10 +6092,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
}
li = tv_list_find(l, idx);
} else {
- if (start < 0)
+ if (start < 0) {
start = 0;
- if (start > len)
+ }
+ if (start > len) {
goto theend;
+ }
// When "count" argument is there ignore matches before "start",
// otherwise skip part of the string. Differs when pattern is "^"
// or "\<".
@@ -5894,10 +6137,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
- if (match && --nth <= 0)
+ if (match && --nth <= 0) {
break;
- if (l == NULL && !match)
+ }
+ if (l == NULL && !match) {
break;
+ }
// Advance to just after the match.
if (l != NULL) {
@@ -5907,74 +6152,70 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
startcol = (colnr_T)(regmatch.startp[0]
+ (*mb_ptr2len)(regmatch.startp[0]) - str);
if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) {
- match = false;
- break;
+ match = false;
+ break;
}
}
}
if (match) {
switch (type) {
- case kSomeMatchStrPos: {
- list_T *const ret_l = rettv->vval.v_list;
- listitem_T *li1 = tv_list_first(ret_l);
- listitem_T *li2 = TV_LIST_ITEM_NEXT(ret_l, li1);
- listitem_T *li3 = TV_LIST_ITEM_NEXT(ret_l, li2);
- listitem_T *li4 = TV_LIST_ITEM_NEXT(ret_l, li3);
- xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
-
- const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
- TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz(
- (const char *)regmatch.startp[0], rd);
- TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(
- regmatch.startp[0] - expr);
- TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(
- regmatch.endp[0] - expr);
- if (l != NULL) {
- TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx;
- }
- break;
- }
- case kSomeMatchList: {
- // Return list with matched string and submatches.
- for (int i = 0; i < NSUBEXP; i++) {
- if (regmatch.endp[i] == NULL) {
- tv_list_append_string(rettv->vval.v_list, NULL, 0);
- } else {
- tv_list_append_string(rettv->vval.v_list,
- (const char *)regmatch.startp[i],
- (regmatch.endp[i] - regmatch.startp[i]));
- }
- }
- break;
+ case kSomeMatchStrPos: {
+ list_T *const ret_l = rettv->vval.v_list;
+ listitem_T *li1 = tv_list_first(ret_l);
+ listitem_T *li2 = TV_LIST_ITEM_NEXT(ret_l, li1);
+ listitem_T *li3 = TV_LIST_ITEM_NEXT(ret_l, li2);
+ listitem_T *li4 = TV_LIST_ITEM_NEXT(ret_l, li3);
+ xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
+
+ const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
+ TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz((const char *)regmatch.startp[0], rd);
+ TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(
+ regmatch.startp[0] - expr);
+ TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(
+ regmatch.endp[0] - expr);
+ if (l != NULL) {
+ TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx;
}
- case kSomeMatchStr: {
- // Return matched string.
- if (l != NULL) {
- tv_copy(TV_LIST_ITEM_TV(li), rettv);
+ break;
+ }
+ case kSomeMatchList:
+ // Return list with matched string and submatches.
+ for (int i = 0; i < NSUBEXP; i++) {
+ if (regmatch.endp[i] == NULL) {
+ tv_list_append_string(rettv->vval.v_list, NULL, 0);
} else {
- rettv->vval.v_string = (char_u *)xmemdupz(
- (const char *)regmatch.startp[0],
- (size_t)(regmatch.endp[0] - regmatch.startp[0]));
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)regmatch.startp[i],
+ (regmatch.endp[i] - regmatch.startp[i]));
}
- break;
}
- case kSomeMatch:
- case kSomeMatchEnd: {
- if (l != NULL) {
- rettv->vval.v_number = idx;
+ break;
+ case kSomeMatchStr:
+ // Return matched string.
+ if (l != NULL) {
+ tv_copy(TV_LIST_ITEM_TV(li), rettv);
+ } else {
+ rettv->vval.v_string = (char_u *)xmemdupz((const char *)regmatch.startp[0],
+ (size_t)(regmatch.endp[0] -
+ regmatch.startp[0]));
+ }
+ break;
+ case kSomeMatch:
+ case kSomeMatchEnd:
+ if (l != NULL) {
+ rettv->vval.v_number = idx;
+ } else {
+ if (type == kSomeMatch) {
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.startp[0] - str);
} else {
- if (type == kSomeMatch) {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.startp[0] - str);
- } else {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.endp[0] - str);
- }
- rettv->vval.v_number += (varnumber_T)(str - expr);
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.endp[0] - str);
}
- break;
+ rettv->vval.v_number += (varnumber_T)(str - expr);
}
+ break;
}
}
vim_regfree(regmatch.regprog);
@@ -6123,7 +6364,7 @@ static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *win = get_optional_window(argvars, 1);
+ win_T *win = get_optional_window(argvars, 1);
if (win == NULL) {
rettv->vval.v_number = -1;
} else {
@@ -6171,8 +6412,7 @@ static void f_matchstrpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// vval.v_number, type is not touched. Returns zero for
/// empty lists/dictionaries.
/// @param[in] domax Determines whether maximal or minimal value is desired.
-static void max_min(const typval_T *const tv, typval_T *const rettv,
- const bool domax)
+static void max_min(const typval_T *const tv, typval_T *const rettv, const bool domax)
FUNC_ATTR_NONNULL_ALL
{
bool error = false;
@@ -6298,9 +6538,16 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listarg), "msgpackdump()");
return;
}
- list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
list_T *const list = argvars[0].vval.v_list;
- msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write);
+ msgpack_packer *packer;
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && strequal(tv_get_string(&argvars[1]), "B")) {
+ tv_blob_alloc_ret(rettv);
+ packer = msgpack_packer_new(rettv->vval.v_blob, &encode_blob_write);
+ } else {
+ packer = msgpack_packer_new(tv_list_alloc_ret(rettv, kListLenMayKnow),
+ &encode_list_write);
+ }
const char *const msg = _("msgpackdump() argument, index %i");
// Assume that translation will not take more then 4 times more space
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
@@ -6308,23 +6555,47 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER(list, li, {
vim_snprintf(msgbuf, sizeof(msgbuf), (char *)msg, idx);
idx++;
- if (encode_vim_to_msgpack(lpacker, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
+ if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
break;
}
});
- msgpack_packer_free(lpacker);
+ msgpack_packer_free(packer);
}
-/// "msgpackparse" function
-static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static int msgpackparse_convert_item(const msgpack_object data, const msgpack_unpack_return result,
+ list_T *const ret_list, const bool fail_if_incomplete)
FUNC_ATTR_NONNULL_ALL
{
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "msgpackparse()");
- return;
+ switch (result) {
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ EMSG2(_(e_invarg2), "Failed to parse msgpack string");
+ return FAIL;
+ case MSGPACK_UNPACK_NOMEM_ERROR:
+ EMSG(_(e_outofmem));
+ return FAIL;
+ case MSGPACK_UNPACK_CONTINUE:
+ if (fail_if_incomplete) {
+ EMSG2(_(e_invarg2), "Incomplete msgpack string");
+ return FAIL;
+ }
+ return NOTDONE;
+ case MSGPACK_UNPACK_SUCCESS: {
+ typval_T tv = { .v_type = VAR_UNKNOWN };
+ if (msgpack_to_vim(data, &tv) == FAIL) {
+ EMSG2(_(e_invarg2), "Failed to convert msgpack string");
+ return FAIL;
+ }
+ tv_list_append_owned_tv(ret_list, tv);
+ return OK;
}
- list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
- const list_T *const list = argvars[0].vval.v_list;
+ default:
+ abort();
+ }
+}
+
+static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret_list)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
if (tv_list_len(list) == 0) {
return;
}
@@ -6343,43 +6614,28 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
do {
if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) {
EMSG(_(e_outofmem));
- goto f_msgpackparse_exit;
+ goto end;
}
size_t read_bytes;
- const int rlret = encode_read_from_list(
- &lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE, &read_bytes);
+ const int rlret = encode_read_from_list(&lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE,
+ &read_bytes);
if (rlret == FAIL) {
EMSG2(_(e_invarg2), "List item is not a string");
- goto f_msgpackparse_exit;
+ goto end;
}
msgpack_unpacker_buffer_consumed(unpacker, read_bytes);
if (read_bytes == 0) {
break;
}
while (unpacker->off < unpacker->used) {
- const msgpack_unpack_return result = msgpack_unpacker_next(unpacker,
- &unpacked);
- if (result == MSGPACK_UNPACK_PARSE_ERROR) {
- EMSG2(_(e_invarg2), "Failed to parse msgpack string");
- goto f_msgpackparse_exit;
- }
- if (result == MSGPACK_UNPACK_NOMEM_ERROR) {
- EMSG(_(e_outofmem));
- goto f_msgpackparse_exit;
- }
- if (result == MSGPACK_UNPACK_SUCCESS) {
- typval_T tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(unpacked.data, &tv) == FAIL) {
- EMSG2(_(e_invarg2), "Failed to convert msgpack string");
- goto f_msgpackparse_exit;
- }
- tv_list_append_owned_tv(ret_list, tv);
- }
- if (result == MSGPACK_UNPACK_CONTINUE) {
- if (rlret == OK) {
- EMSG2(_(e_invarg2), "Incomplete msgpack string");
- }
+ const msgpack_unpack_return result
+ = msgpack_unpacker_next(unpacker, &unpacked);
+ const int conv_result = msgpackparse_convert_item(unpacked.data, result,
+ ret_list, rlret == OK);
+ if (conv_result == NOTDONE) {
break;
+ } else if (conv_result == FAIL) {
+ goto end;
}
}
if (rlret == OK) {
@@ -6387,10 +6643,46 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} while (true);
-f_msgpackparse_exit:
- msgpack_unpacked_destroy(&unpacked);
+end:
msgpack_unpacker_free(unpacker);
- return;
+ msgpack_unpacked_destroy(&unpacked);
+}
+
+static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret_list)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ const int len = tv_blob_len(blob);
+ if (len == 0) {
+ return;
+ }
+ msgpack_unpacked unpacked;
+ msgpack_unpacked_init(&unpacked);
+ for (size_t offset = 0; offset < (size_t)len;) {
+ const msgpack_unpack_return result
+ = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, len, &offset);
+ if (msgpackparse_convert_item(unpacked.data, result, ret_list, true)
+ != OK) {
+ break;
+ }
+ }
+
+ msgpack_unpacked_destroy(&unpacked);
+}
+
+/// "msgpackparse" function
+static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
+ EMSG2(_(e_listblobarg), "msgpackparse()");
+ return;
+ }
+ list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
+ if (argvars[0].v_type == VAR_LIST) {
+ msgpackparse_unpack_list(argvars[0].vval.v_list, ret_list);
+ } else {
+ msgpackparse_unpack_blob(argvars[0].vval.v_blob, ret_list);
+ }
}
/*
@@ -6525,53 +6817,51 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "prompt_setcallback({buffer}, {callback})" function
-static void f_prompt_setcallback(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- Callback prompt_callback = { .type = kCallbackNone };
+ buf_T *buf;
+ Callback prompt_callback = { .type = kCallbackNone };
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
- if (!callback_from_typval(&prompt_callback, &argvars[1])) {
- return;
- }
+ if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
+ if (!callback_from_typval(&prompt_callback, &argvars[1])) {
+ return;
}
+ }
- callback_free(&buf->b_prompt_callback);
- buf->b_prompt_callback = prompt_callback;
+ callback_free(&buf->b_prompt_callback);
+ buf->b_prompt_callback = prompt_callback;
}
// "prompt_setinterrupt({buffer}, {callback})" function
-static void f_prompt_setinterrupt(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- Callback interrupt_callback = { .type = kCallbackNone };
+ buf_T *buf;
+ Callback interrupt_callback = { .type = kCallbackNone };
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
- if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
- return;
- }
+ if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
+ if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
+ return;
}
+ }
- callback_free(&buf->b_prompt_interrupt);
- buf->b_prompt_interrupt= interrupt_callback;
+ callback_free(&buf->b_prompt_interrupt);
+ buf->b_prompt_interrupt= interrupt_callback;
}
/// "prompt_getprompt({buffer})" function
@@ -6595,23 +6885,22 @@ void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "prompt_setprompt({buffer}, {text})" function
-static void f_prompt_setprompt(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- const char_u *text;
+ buf_T *buf;
+ const char_u *text;
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- text = (const char_u *)tv_get_string(&argvars[1]);
- xfree(buf->b_prompt_text);
- buf->b_prompt_text = vim_strsave(text);
+ text = (const char_u *)tv_get_string(&argvars[1]);
+ xfree(buf->b_prompt_text);
+ buf->b_prompt_text = vim_strsave(text);
}
// "pum_getpos()" function
@@ -6626,8 +6915,9 @@ static void f_pum_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (pum_visible())
+ if (pum_visible()) {
rettv->vval.v_number = 1;
+ }
}
/*
@@ -6801,11 +7091,12 @@ static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
bool binary = false;
- FILE *fd;
+ bool blob = false;
+ FILE *fd;
char_u buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1
int io_size = sizeof(buf);
int readlen; // size of last fread()
- char_u *prev = NULL; // previously read bytes, if any
+ char_u *prev = NULL; // previously read bytes, if any
long prevlen = 0; // length of data in prev
long prevsize = 0; // size of prev buffer
long maxline = MAXLNUM;
@@ -6813,22 +7104,41 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (strcmp(tv_get_string(&argvars[1]), "b") == 0) {
binary = true;
+ } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) {
+ blob = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
maxline = tv_get_number(&argvars[2]);
}
}
- list_T *const l = 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]);
+
+ if (os_isdir((const char_u *)fname)) {
+ EMSG2(_(e_isadir2), fname);
+ return;
+ }
if (*fname == NUL || (fd = os_fopen(fname, READBIN)) == NULL) {
EMSG2(_(e_notopen), *fname == NUL ? _("<empty>") : fname);
return;
}
+ if (blob) {
+ tv_blob_alloc_ret(rettv);
+ if (!read_blob(fd, rettv->vval.v_blob)) {
+ EMSG2(_(e_notread), fname);
+ // An empty blob is returned on error.
+ tv_blob_free(rettv->vval.v_blob);
+ rettv->vval.v_blob = NULL;
+ }
+ fclose(fd);
+ return;
+ }
+
+ list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
+
while (maxline < 0 || tv_list_len(l) < maxline) {
readlen = (int)fread(buf, 1, io_size, fd);
@@ -6843,7 +7153,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
p++) {
if (*p == '\n' || readlen <= 0) {
- char_u *s = NULL;
+ char_u *s = NULL;
size_t len = p - start;
// Finished a line. Remove CRs before NL.
@@ -6893,16 +7203,17 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (*p == NUL) {
*p = '\n';
- // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
- // when finding the BF and check the previous two bytes.
+ // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
+ // when finding the BF and check the previous two bytes.
} else if (*p == 0xbf && !binary) {
// Find the two bytes before the 0xbf. If p is at buf, or buf + 1,
// these may be in the "prev" string.
char_u back1 = p >= buf + 1 ? p[-1]
- : prevlen >= 1 ? prev[prevlen - 1] : NUL;
+ : prevlen >= 1 ? prev[prevlen - 1] : NUL;
char_u back2 = p >= buf + 2 ? p[-2]
- : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
- : prevlen >= 2 ? prev[prevlen - 2] : NUL;
+ : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
+ : prevlen >=
+ 2 ? prev[prevlen - 2] : NUL;
if (back2 == 0xef && back1 == 0xbb) {
char_u *dest = p - 2;
@@ -6920,8 +7231,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// adjust_prevlen must be 1 or 2.
dest = buf;
}
- if (readlen > p - buf + 1)
+ if (readlen > p - buf + 1) {
memmove(dest, p + 1, readlen - (p - buf) - 1);
+ }
readlen -= 3 - adjust_prevlen;
prevlen -= adjust_prevlen;
p = dest - 1;
@@ -6940,9 +7252,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* fragment of a line, so the first allocation is made
* small, to avoid repeatedly 'allocing' large and
* 'reallocing' small. */
- if (prevsize == 0)
+ if (prevsize == 0) {
prevsize = (long)(p - start);
- else {
+ } else {
long grow50pc = (prevsize * 3) / 2;
long growmin = (long)((p - start) * 2 + prevlen);
prevsize = grow50pc > growmin ? grow50pc : growmin;
@@ -6959,6 +7271,61 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
fclose(fd);
}
+/// "getreginfo()" function
+static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *strregname;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ strregname = tv_get_string_chk(&argvars[0]);
+ if (strregname == NULL) {
+ return;
+ }
+ } else {
+ strregname = (const char *)get_vim_var_str(VV_REG);
+ }
+
+ int regname = (strregname == NULL ? '"' : *strregname);
+ if (regname == 0 || regname == '@') {
+ regname = '"';
+ }
+
+ tv_dict_alloc_ret(rettv);
+ dict_T *const dict = rettv->vval.v_dict;
+
+ list_T *const list = get_reg_contents(regname, kGRegExprSrc | kGRegList);
+ if (list == NULL) {
+ return;
+ }
+ tv_dict_add_list(dict, S_LEN("regcontents"), list);
+
+ char buf[NUMBUFLEN + 2];
+ buf[0] = NUL;
+ buf[1] = NUL;
+ colnr_T reglen = 0;
+ switch (get_reg_type(regname, &reglen)) {
+ case kMTLineWise:
+ buf[0] = 'V';
+ break;
+ case kMTCharWise:
+ buf[0] = 'v';
+ break;
+ case kMTBlockWise:
+ vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
+ break;
+ case kMTUnknown:
+ abort();
+ }
+ tv_dict_add_str(dict, S_LEN("regtype"), buf);
+
+ buf[0] = get_register_name(get_unname_register());
+ buf[1] = NUL;
+ if (regname == '"') {
+ tv_dict_add_str(dict, S_LEN("points_to"), buf);
+ } else {
+ tv_dict_add_bool(dict, S_LEN("isunnamed"), regname == buf[0] ? kBoolVarTrue : kBoolVarFalse);
+ }
+}
+
// "reg_executing()" function
static void f_reg_executing(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -7042,7 +7409,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// results, if varnumber_T or proftime_T change, the union cast will need
// to be revised.
STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u),
- "type punning will produce incorrect results on this platform");
+ "type punning will produce incorrect results on this platform");
tv_list_alloc_ret(rettv, 2);
tv_list_append_number(rettv->vval.v_list, u.split.high);
@@ -7067,13 +7434,13 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l;
- listitem_T *item, *item2;
- listitem_T *li;
+ list_T *l;
+ listitem_T *item, *item2;
+ listitem_T *li;
long idx;
long end;
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
const char *const arg_errmsg = N_("remove() argument");
if (argvars[0].v_type == VAR_DICT) {
@@ -7097,8 +7464,64 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+
+ if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
+
+ bool error = false;
+ idx = (long)tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ const int len = tv_blob_len(b);
+
+ if (idx < 0) {
+ // count from the end
+ idx = len + idx;
+ }
+ if (idx < 0 || idx >= len) {
+ EMSGN(_(e_blobidx), idx);
+ return;
+ }
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ // Remove one item, return its value.
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ rettv->vval.v_number = (varnumber_T)(*(p + idx));
+ memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
+ b->bv_ga.ga_len--;
+ } else {
+ // Remove range of items, return blob with values.
+ end = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (end < 0) {
+ // count from the end
+ end = len + end;
+ }
+ if (end >= len || idx > end) {
+ EMSGN(_(e_blobidx), end);
+ return;
+ }
+ blob_T *const blob = tv_blob_alloc();
+ blob->bv_ga.ga_len = end - idx + 1;
+ ga_grow(&blob->bv_ga, end - idx + 1);
+
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ memmove((char_u *)blob->bv_ga.ga_data, p + idx,
+ (size_t)(end - idx + 1));
+ tv_blob_set_ret(rettv, blob);
+
+ if (len - end - 1 > 0) {
+ memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
+ }
+ b->bv_ga.ga_len -= end - idx + 1;
+ }
+ }
} else if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listdictarg), "remove()");
+ EMSG2(_(e_listdictblobarg), "remove()");
} else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
arg_errmsg, TV_TRANSLATE)) {
bool error = false;
@@ -7151,9 +7574,8 @@ static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
} else {
char buf[NUMBUFLEN];
- rettv->vval.v_number = vim_rename(
- (const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_number = vim_rename((const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
}
}
@@ -7372,13 +7794,25 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "reverse()");
- } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("reverse() argument"), TV_TRANSLATE)) {
- tv_list_reverse(l);
- tv_list_set_ret(rettv, l);
+ if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+ const int len = tv_blob_len(b);
+
+ for (int i = 0; i < len / 2; i++) {
+ const char_u tmp = tv_blob_get(b, i);
+ tv_blob_set(b, i, tv_blob_get(b, len - i - 1));
+ tv_blob_set(b, len - i - 1, tmp);
+ }
+ tv_blob_set_ret(rettv, b);
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listblobarg), "reverse()");
+ } else {
+ list_T *const l = argvars[0].vval.v_list;
+ if (!var_check_lock(tv_list_locked(l), N_("reverse() argument"),
+ TV_TRANSLATE)) {
+ tv_list_reverse(l);
+ tv_list_set_ret(rettv, l);
+ }
}
}
@@ -7409,30 +7843,40 @@ static int get_search_arg(typval_T *varp, int *flagsp)
}
while (*flags != NUL) {
switch (*flags) {
- case 'b': dir = BACKWARD; break;
- case 'w': p_ws = true; break;
- case 'W': p_ws = false; break;
- default: {
- mask = 0;
- if (flagsp != NULL) {
- switch (*flags) {
- case 'c': mask = SP_START; break;
- case 'e': mask = SP_END; break;
- case 'm': mask = SP_RETCOUNT; break;
- case 'n': mask = SP_NOMOVE; break;
- case 'p': mask = SP_SUBPAT; break;
- case 'r': mask = SP_REPEAT; break;
- case 's': mask = SP_SETPCMARK; break;
- case 'z': mask = SP_COLUMN; break;
- }
- }
- if (mask == 0) {
- emsgf(_(e_invarg2), flags);
- dir = 0;
- } else {
- *flagsp |= mask;
+ case 'b':
+ dir = BACKWARD; break;
+ case 'w':
+ p_ws = true; break;
+ case 'W':
+ p_ws = false; break;
+ default:
+ mask = 0;
+ if (flagsp != NULL) {
+ switch (*flags) {
+ case 'c':
+ mask = SP_START; break;
+ case 'e':
+ mask = SP_END; break;
+ case 'm':
+ mask = SP_RETCOUNT; break;
+ case 'n':
+ mask = SP_NOMOVE; break;
+ case 'p':
+ mask = SP_SUBPAT; break;
+ case 'r':
+ mask = SP_REPEAT; break;
+ case 's':
+ mask = SP_SETPCMARK; break;
+ case 'z':
+ mask = SP_COLUMN; break;
}
}
+ if (mask == 0) {
+ emsgf(_(e_invarg2), flags);
+ dir = 0;
+ } else {
+ *flagsp |= mask;
+ }
}
if (dir == 0) {
break;
@@ -7511,12 +7955,14 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1,
options, RE_SEARCH, &sia);
if (subpatnum != FAIL) {
- if (flags & SP_SUBPAT)
+ if (flags & SP_SUBPAT) {
retval = subpatnum;
- else
+ } else {
retval = pos.lnum;
- if (flags & SP_SETPCMARK)
+ }
+ if (flags & SP_SETPCMARK) {
setpcmark();
+ }
curwin->w_cursor = pos;
if (match_pos != NULL) {
// Store the match cursor position
@@ -7654,10 +8100,10 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
msg_ext_set_kind("rpc_error");
if (name) {
- emsgf_multiline("Error invoking '%s' on channel %"PRIu64" (%s):\n%s",
+ emsgf_multiline("Error invoking '%s' on channel %" PRIu64 " (%s):\n%s",
method, chan_id, name, err.msg);
} else {
- emsgf_multiline("Error invoking '%s' on channel %"PRIu64":\n%s",
+ emsgf_multiline("Error invoking '%s' on channel %" PRIu64 ":\n%s",
method, chan_id, err.msg);
}
@@ -7732,8 +8178,9 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT,
CALLBACK_READER_INIT, CALLBACK_NONE,
- false, true, false, false, NULL, 0, 0,
- NULL, &rettv->vval.v_number);
+ false, true, false, false,
+ kChannelStdinPipe, NULL, 0, 0, NULL,
+ &rettv->vval.v_number);
if (chan) {
channel_create_event(chan, NULL);
}
@@ -7769,9 +8216,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "screenattr()" function
- */
+// "screenattr()" function
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@@ -7789,9 +8234,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
-/*
- * "screenchar()" function
- */
+// "screenchar()" function
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@@ -7809,11 +8252,34 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
-/*
- * "screencol()" function
- *
- * First column is 1 to be consistent with virtcol().
- */
+// "screenchars()" function
+static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ int row = tv_get_number_chk(&argvars[0], NULL) - 1;
+ int col = tv_get_number_chk(&argvars[1], NULL) - 1;
+ if (row < 0 || row >= default_grid.Rows
+ || col < 0 || col >= default_grid.Columns) {
+ tv_list_alloc_ret(rettv, 0);
+ return;
+ }
+ ScreenGrid *grid = &default_grid;
+ screenchar_adjust_grid(&grid, &row, &col);
+ int pcc[MAX_MCO];
+ int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + col], pcc);
+ int composing_len = 0;
+ while (pcc[composing_len] != 0) {
+ composing_len++;
+ }
+ tv_list_alloc_ret(rettv, composing_len + 1);
+ tv_list_append_number(rettv->vval.v_list, c);
+ for (int i = 0; i < composing_len; i++) {
+ tv_list_append_number(rettv->vval.v_list, pcc[i]);
+ }
+}
+
+// "screencol()" function
+//
+// First column is 1 to be consistent with virtcol().
static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_col() + 1;
@@ -7845,17 +8311,29 @@ static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
}
-/*
- * "screenrow()" function
- */
+// "screenrow()" function
static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_row() + 1;
}
-/*
- * "search()" function
- */
+// "screenstring()" function
+static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->vval.v_string = NULL;
+ rettv->v_type = VAR_STRING;
+ int row = tv_get_number_chk(&argvars[0], NULL) - 1;
+ int col = tv_get_number_chk(&argvars[1], NULL) - 1;
+ if (row < 0 || row >= default_grid.Rows
+ || col < 0 || col >= default_grid.Columns) {
+ return;
+ }
+ ScreenGrid *grid = &default_grid;
+ screenchar_adjust_grid(&grid, &row, &col);
+ rettv->vval.v_string = vim_strsave(grid->chars[grid->line_offset[row] + col]);
+}
+
+// "search()" function
static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int flags = 0;
@@ -7958,9 +8436,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
}
- retval = do_searchpair(
- spat, mpat, epat, dir, skip,
- flags, match_pos, lnum_stop, time_limit);
+ retval = do_searchpair(spat, mpat, epat, dir, skip,
+ flags, match_pos, lnum_stop, time_limit);
theend:
p_ws = save_p_ws;
@@ -8001,22 +8478,19 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* Used by searchpair(), see its documentation for the details.
* Returns 0 or -1 for no match,
*/
-long
-do_searchpair(
- const char *spat, // start pattern
- const char *mpat, // middle pattern
- const char *epat, // end pattern
- int dir, // BACKWARD or FORWARD
- const typval_T *skip, // skip expression
- int flags, // SP_SETPCMARK and other SP_ values
- pos_T *match_pos,
- linenr_T lnum_stop, // stop at this line if not zero
- long time_limit // stop after this many msec
-)
+long do_searchpair(const char *spat, // start pattern
+ const char *mpat, // middle pattern
+ const char *epat, // end pattern
+ int dir, // BACKWARD or FORWARD
+ const typval_T *skip, // skip expression
+ int flags, // SP_SETPCMARK and other SP_ values
+ pos_T *match_pos, linenr_T lnum_stop, // stop at this line if not zero
+ long time_limit // stop after this many msec
+ )
FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
- char_u *save_cpo;
- char_u *pat, *pat2 = NULL, *pat3 = NULL;
+ char_u *save_cpo;
+ char_u *pat, *pat2 = NULL, *pat3 = NULL;
long retval = 0;
pos_T pos;
pos_T firstpos;
@@ -8078,8 +8552,9 @@ do_searchpair(
break;
}
- if (firstpos.lnum == 0)
+ if (firstpos.lnum == 0) {
firstpos = pos;
+ }
if (equalpos(pos, foundpos)) {
// Found the same position again. Can happen with a pattern that
// has "\zs" at the end and searching backwards. Advance one
@@ -8108,8 +8583,9 @@ do_searchpair(
retval = -1;
break;
}
- if (r)
+ if (r) {
continue;
+ }
}
if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) {
@@ -8136,8 +8612,9 @@ do_searchpair(
setpcmark();
}
curwin->w_cursor = pos;
- if (!(flags & SP_REPEAT))
+ if (!(flags & SP_REPEAT)) {
break;
+ }
nest = 1; // search for next unmatched
}
}
@@ -8269,16 +8746,16 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "setbufline()" function
static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
- buf_T *buf;
+ linenr_T lnum;
+ buf_T *buf;
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
- }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ rettv->vval.v_number = 1; // FAIL
+ } else {
+ lnum = tv_get_lnum_buf(&argvars[1], buf);
+ set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
+ }
}
/*
@@ -8329,8 +8806,8 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
if (argvars[0].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
@@ -8510,7 +8987,7 @@ skip_args:
*/
static void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *win;
+ win_T *win;
rettv->vval.v_number = -1;
@@ -8632,7 +9109,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
pos_T pos;
int fnum;
- colnr_T curswant = -1;
+ colnr_T curswant = -1;
rettv->vval.v_number = -1;
const char *const name = tv_get_string_chk(argvars);
@@ -8650,7 +9127,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
check_cursor();
rettv->vval.v_number = 0;
- } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
+ } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
// set mark
if (setmark_pos((uint8_t)name[1], &pos, fnum) == OK) {
rettv->vval.v_number = 0;
@@ -8670,6 +9147,36 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
set_qf_ll_list(NULL, argvars, rettv);
}
+/// Translate a register type string to the yank type and block length
+static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *const block_len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *stropt = *pp;
+ switch (*stropt) {
+ case 'v':
+ case 'c': // character-wise selection
+ *yank_type = kMTCharWise;
+ break;
+ case 'V':
+ case 'l': // line-wise selection
+ *yank_type = kMTLineWise;
+ break;
+ case 'b':
+ case Ctrl_V: // block-wise selection
+ *yank_type = kMTBlockWise;
+ if (ascii_isdigit(stropt[1])) {
+ stropt++;
+ *block_len = getdigits_long(&stropt, false, 0) - 1;
+ stropt--;
+ }
+ break;
+ default:
+ return FAIL;
+ }
+ *pp = stropt;
+ return OK;
+}
+
/*
* "setreg()" function
*/
@@ -8694,45 +9201,75 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
regname = '"';
}
+ const typval_T *regcontents = NULL;
+ int pointreg = 0;
+ if (argvars[1].v_type == VAR_DICT) {
+ dict_T *const d = argvars[1].vval.v_dict;
+
+ if (tv_dict_len(d) == 0) {
+ // Empty dict, clear the register (like setreg(0, []))
+ char_u *lstval[2] = { NULL, NULL };
+ write_reg_contents_lst(regname, lstval, false, kMTUnknown, -1);
+ return;
+ }
+
+ dictitem_T *const di = tv_dict_find(d, "regcontents", -1);
+ if (di != NULL) {
+ regcontents = &di->di_tv;
+ }
+
+ const char *stropt = tv_dict_get_string(d, "regtype", false);
+ if (stropt != NULL) {
+ const int ret = get_yank_type((char_u **)&stropt, &yank_type, &block_len);
+
+ if (ret == FAIL || *(++stropt) != NUL) {
+ EMSG2(_(e_invargval), "value");
+ return;
+ }
+ }
+
+ if (regname == '"') {
+ stropt = tv_dict_get_string(d, "points_to", false);
+ if (stropt != NULL) {
+ pointreg = *stropt;
+ regname = pointreg;
+ }
+ } else if (tv_dict_get_number(d, "isunnamed")) {
+ pointreg = regname;
+ }
+ } else {
+ regcontents = &argvars[1];
+ }
+
bool set_unnamed = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
+ if (yank_type != kMTUnknown) {
+ EMSG2(_(e_toomanyarg), "setreg");
+ return;
+ }
+
const char *stropt = tv_get_string_chk(&argvars[2]);
if (stropt == NULL) {
return; // Type error.
}
for (; *stropt != NUL; stropt++) {
switch (*stropt) {
- case 'a': case 'A': { // append
- append = true;
- break;
- }
- case 'v': case 'c': { // character-wise selection
- yank_type = kMTCharWise;
- break;
- }
- case 'V': case 'l': { // line-wise selection
- yank_type = kMTLineWise;
- break;
- }
- case 'b': case Ctrl_V: { // block-wise selection
- yank_type = kMTBlockWise;
- if (ascii_isdigit(stropt[1])) {
- stropt++;
- block_len = getdigits_long((char_u **)&stropt, true, 0) - 1;
- stropt--;
- }
- break;
- }
- case 'u': case '"': { // unnamed register
- set_unnamed = true;
- break;
- }
+ case 'a':
+ case 'A': // append
+ append = true;
+ break;
+ case 'u':
+ case '"': // unnamed register
+ set_unnamed = true;
+ break;
+ default:
+ get_yank_type((char_u **)&stropt, &yank_type, &block_len);
}
}
}
- if (argvars[1].v_type == VAR_LIST) {
- list_T *ll = argvars[1].vval.v_list;
+ if (regcontents != NULL && regcontents->v_type == VAR_LIST) {
+ list_T *const ll = regcontents->vval.v_list;
// If the list is NULL handle like an empty list.
const int len = tv_list_len(ll);
@@ -8768,19 +9305,23 @@ free_lstval:
xfree(*--curallocval);
}
xfree(lstval);
- } else {
- const char *strval = tv_get_string_chk(&argvars[1]);
+ } else if (regcontents != NULL) {
+ const char *const strval = tv_get_string_chk(regcontents);
if (strval == NULL) {
return;
}
write_reg_contents_ex(regname, (const char_u *)strval, STRLEN(strval),
append, yank_type, block_len);
}
+ if (pointreg != 0) {
+ get_yank_register(pointreg, YREG_YANK);
+ }
rettv->vval.v_number = 0;
if (set_unnamed) {
// Discard the result. We already handle the error case.
- if (op_reg_set_previous(regname)) { }
+ if (op_reg_set_previous(regname)) {
+ }
}
}
@@ -8828,54 +9369,54 @@ static void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "settagstack()" function
static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- static char *e_invact2 = N_("E962: Invalid action: '%s'");
- win_T *wp;
- dict_T *d;
- int action = 'r';
+ static char *e_invact2 = N_("E962: Invalid action: '%s'");
+ win_T *wp;
+ dict_T *d;
+ int action = 'r';
- rettv->vval.v_number = -1;
+ rettv->vval.v_number = -1;
- // first argument: window number or id
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- return;
- }
+ // first argument: window number or id
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
+ }
- // second argument: dict with items to set in the tag stack
- if (argvars[1].v_type != VAR_DICT) {
- EMSG(_(e_dictreq));
- return;
- }
- d = argvars[1].vval.v_dict;
- if (d == NULL) {
+ // second argument: dict with items to set in the tag stack
+ if (argvars[1].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ d = argvars[1].vval.v_dict;
+ if (d == NULL) {
+ return;
+ }
+
+ // third argument: action - 'a' for append and 'r' for replace.
+ // default is to replace the stack.
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ action = 'r';
+ } else if (argvars[2].v_type == VAR_STRING) {
+ const char *actstr;
+ actstr = tv_get_string_chk(&argvars[2]);
+ if (actstr == NULL) {
return;
}
-
- // third argument: action - 'a' for append and 'r' for replace.
- // default is to replace the stack.
- if (argvars[2].v_type == VAR_UNKNOWN) {
- action = 'r';
- } else if (argvars[2].v_type == VAR_STRING) {
- const char *actstr;
- actstr = tv_get_string_chk(&argvars[2]);
- if (actstr == NULL) {
- return;
- }
- if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
- && actstr[1] == NUL) {
- action = *actstr;
- } else {
- EMSG2(_(e_invact2), actstr);
- return;
- }
+ if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
+ && actstr[1] == NUL) {
+ action = *actstr;
} else {
- EMSG(_(e_stringreq));
- return;
+ EMSG2(_(e_invact2), actstr);
+ return;
}
+ } else {
+ EMSG(_(e_stringreq));
+ return;
+ }
- if (set_tagstack(wp, d, action) == OK) {
- rettv->vval.v_number = 0;
- }
+ if (set_tagstack(wp, d, action) == OK) {
+ rettv->vval.v_number = 0;
+ }
}
/*
@@ -8890,7 +9431,7 @@ static void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *p = tv_get_string(&argvars[0]);
- const char *hash = sha256_bytes((const uint8_t *)p, strlen(p) , NULL, 0);
+ const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0);
// make a copy of the hash (sha256_bytes returns a static buffer)
rettv->vval.v_string = (char_u *)xstrdup(hash);
@@ -8904,8 +9445,9 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const bool do_special = non_zero_arg(&argvars[1]);
- rettv->vval.v_string = vim_strsave_shellescape(
- (const char_u *)tv_get_string(&argvars[0]), do_special, do_special);
+ rettv->vval.v_string = vim_strsave_shellescape((const char_u *)tv_get_string(
+ &argvars[0]), do_special,
+ do_special);
rettv->v_type = VAR_STRING;
}
@@ -8955,8 +9497,9 @@ static void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = sign_define_from_dict(
- name, argvars[1].v_type == VAR_DICT ? argvars[1].vval.v_dict : NULL);
+ rettv->vval.v_number = sign_define_from_dict(name,
+ argvars[1].v_type ==
+ VAR_DICT ? argvars[1].vval.v_dict : NULL);
}
/// "sign_getdefined()" function
@@ -9088,8 +9631,8 @@ static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = sign_place_from_dict(
- &argvars[0], &argvars[1], &argvars[2], &argvars[3], dict);
+ rettv->vval.v_number = sign_place_from_dict(&argvars[0], &argvars[1], &argvars[2], &argvars[3],
+ dict);
}
/// "sign_placelist()" function. Place multiple signs.
@@ -9108,8 +9651,7 @@ static void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, {
sign_id = -1;
if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
- sign_id = sign_place_from_dict(
- NULL, NULL, NULL, NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
+ sign_id = sign_place_from_dict(NULL, NULL, NULL, NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
} else {
EMSG(_(e_dictreq));
}
@@ -9378,7 +9920,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
int res;
typval_T rettv;
typval_T argv[3];
- int dummy;
const char *func_name;
partial_T *partial = sortinfo->item_compare_partial;
@@ -9402,10 +9943,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- res = call_func((const char_u *)func_name,
- -1,
- &rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
- partial, sortinfo->item_compare_selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = sortinfo->item_compare_selfdict;
+ res = call_func((const char_u *)func_name, -1, &rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
tv_clear(&argv[1]);
@@ -9445,7 +9987,7 @@ static int item_compare2_not_keeping_zero(const void *s1, const void *s2)
*/
static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
{
- ListSortItem *ptrs;
+ ListSortItem *ptrs;
long len;
long i;
@@ -9632,7 +10174,7 @@ static void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "reltimefloat()" function
-static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
+static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
proftime_T tm;
@@ -9707,10 +10249,12 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_string(rettv->vval.v_list, word, len);
tv_list_append_string(rettv->vval.v_list,
(attr == HLF_SPB ? "bad"
- : attr == HLF_SPR ? "rare"
- : attr == HLF_SPL ? "local"
- : attr == HLF_SPC ? "caps"
- : NULL), -1);
+ : attr == HLF_SPR ? "rare"
+ : attr == HLF_SPL ? "local"
+ : attr ==
+ HLF_SPC ? "caps"
+ :
+ NULL), -1);
}
/*
@@ -9767,7 +10311,7 @@ f_spellsuggest_return:
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *save_cpo;
+ char_u *save_cpo;
int match;
colnr_T col = 0;
bool keepempty = false;
@@ -9904,7 +10448,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int base = 10;
varnumber_T n;
- int what;
+ int what = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
base = tv_get_number(&argvars[1]);
@@ -9912,6 +10456,9 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_invarg));
return;
}
+ if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) {
+ what |= STR2NR_QUOTE;
+ }
}
char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
@@ -9920,23 +10467,18 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p = skipwhite(p + 1);
}
switch (base) {
- case 2: {
- what = STR2NR_BIN | STR2NR_FORCE;
- break;
- }
- case 8: {
- what = STR2NR_OCT | STR2NR_FORCE;
- break;
- }
- case 16: {
- what = STR2NR_HEX | STR2NR_FORCE;
- break;
- }
- default: {
- what = 0;
- }
+ case 2:
+ what |= STR2NR_BIN | STR2NR_FORCE;
+ break;
+ case 8:
+ what |= STR2NR_OCT | STR2NR_OOCT | STR2NR_FORCE;
+ break;
+ case 16:
+ what |= STR2NR_HEX | STR2NR_FORCE;
+ break;
}
- vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false);
+ // Text after the number is silently ignored.
if (isneg) {
rettv->vval.v_number = -n;
} else {
@@ -9967,7 +10509,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
} else {
vimconv_T conv;
- char_u *enc;
+ char_u *enc;
conv.vc_type = CONV_NONE;
enc = enc_locale();
@@ -10312,7 +10854,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]));
+ rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]), true);
}
/*
@@ -10443,53 +10985,46 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *p = NULL;
switch (TOLOWER_ASC(what[0])) {
- case 'b': {
- if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
- p = highlight_color(id, what, modec);
- } else { // bold
- p = highlight_has_attr(id, HL_BOLD, modec);
- }
- break;
- }
- case 'f': { // fg[#] or font
+ case 'b':
+ if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
p = highlight_color(id, what, modec);
- break;
- }
- case 'i': {
- if (TOLOWER_ASC(what[1]) == 'n') { // inverse
- p = highlight_has_attr(id, HL_INVERSE, modec);
- } else { // italic
- p = highlight_has_attr(id, HL_ITALIC, modec);
- }
- break;
+ } else { // bold
+ p = highlight_has_attr(id, HL_BOLD, modec);
}
- case 'n': { // name
- p = get_highlight_name_ext(NULL, id - 1, false);
- break;
- }
- case 'r': { // reverse
+ break;
+ case 'f': // fg[#] or font
+ p = highlight_color(id, what, modec);
+ break;
+ case 'i':
+ if (TOLOWER_ASC(what[1]) == 'n') { // inverse
p = highlight_has_attr(id, HL_INVERSE, modec);
- break;
+ } else { // italic
+ p = highlight_has_attr(id, HL_ITALIC, modec);
}
- case 's': {
- if (TOLOWER_ASC(what[1]) == 'p') { // sp[#]
- p = highlight_color(id, what, modec);
- } else if (TOLOWER_ASC(what[1]) == 't'
- && TOLOWER_ASC(what[2]) == 'r') { // strikethrough
- p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
- } else { // standout
- p = highlight_has_attr(id, HL_STANDOUT, modec);
- }
- break;
+ break;
+ case 'n': // name
+ p = get_highlight_name_ext(NULL, id - 1, false);
+ break;
+ case 'r': // reverse
+ p = highlight_has_attr(id, HL_INVERSE, modec);
+ break;
+ case 's':
+ if (TOLOWER_ASC(what[1]) == 'p') { // sp[#]
+ p = highlight_color(id, what, modec);
+ } else if (TOLOWER_ASC(what[1]) == 't'
+ && TOLOWER_ASC(what[2]) == 'r') { // strikethrough
+ p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
+ } else { // standout
+ p = highlight_has_attr(id, HL_STANDOUT, modec);
}
- case 'u': {
- if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
- p = highlight_has_attr(id, HL_UNDERLINE, modec);
- } else { // undercurl
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
- }
- break;
+ break;
+ case 'u':
+ if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
+ } else { // undercurl
+ p = highlight_has_attr(id, HL_UNDERCURL, modec);
}
+ break;
}
rettv->v_type = VAR_STRING;
@@ -10599,7 +11134,7 @@ static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp = NULL;
+ win_T *wp = NULL;
if (argvars[0].v_type == VAR_UNKNOWN) {
wp = firstwin;
@@ -10652,9 +11187,9 @@ static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static int get_winnr(tabpage_T *tp, typval_T *argvar)
{
- win_T *twin;
+ win_T *twin;
int nr = 1;
- win_T *wp;
+ win_T *wp;
twin = (tp == curtab) ? curwin : tp->tp_curwin;
if (argvar->v_type != VAR_UNKNOWN) {
@@ -10700,7 +11235,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
}
}
- if (nr > 0)
+ if (nr > 0) {
for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
wp != twin; wp = wp->w_next) {
if (wp == NULL) {
@@ -10710,6 +11245,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
}
++nr;
}
+ }
return nr;
}
@@ -10849,10 +11385,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const bool rpc = false;
const bool overlapped = false;
const bool detach = false;
+ ChannelStdinMode stdin_mode = kChannelStdinPipe;
uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin));
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
- pty, rpc, overlapped, detach, cwd,
- term_width, curwin->w_height_inner,
+ pty, rpc, overlapped, detach, stdin_mode,
+ cwd, term_width, curwin->w_height_inner,
env, &rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
return;
@@ -10891,8 +11428,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "test_garbagecollect_now()" function
-static void f_test_garbagecollect_now(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
// This is dangerous, any Lists and Dicts used internally may be freed
// while still in use.
@@ -10900,9 +11436,7 @@ static void f_test_garbagecollect_now(typval_T *argvars,
}
// "test_write_list_log()" function
-static void f_test_write_list_log(typval_T *const argvars,
- typval_T *const rettv,
- FunPtr fptr)
+static void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, FunPtr fptr)
{
const char *const fname = tv_get_string_chk(&argvars[0]);
if (fname == NULL) {
@@ -10977,24 +11511,24 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
rettv->vval.v_number =
- timer_start(tv_get_number(&argvars[0]), repeat, &callback);
+ timer_start(tv_get_number(&argvars[0]), repeat, &callback);
}
// "timer_stop(timerid)" function
static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (argvars[0].v_type != VAR_NUMBER) {
- EMSG(_(e_number_exp));
- return;
- }
+ if (argvars[0].v_type != VAR_NUMBER) {
+ EMSG(_(e_number_exp));
+ return;
+ }
- timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
- if (timer == NULL) {
- return;
- }
+ timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
+ if (timer == NULL) {
+ return;
+ }
- timer_stop(timer);
+ timer_stop(timer);
}
static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr)
@@ -11195,19 +11729,28 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int n = -1;
switch (argvars[0].v_type) {
- case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
- case VAR_STRING: n = VAR_TYPE_STRING; break;
- case VAR_PARTIAL:
- case VAR_FUNC: n = VAR_TYPE_FUNC; break;
- case VAR_LIST: n = VAR_TYPE_LIST; break;
- case VAR_DICT: n = VAR_TYPE_DICT; break;
- case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
- case VAR_BOOL: n = VAR_TYPE_BOOL; break;
- case VAR_SPECIAL:n = VAR_TYPE_SPECIAL; break;
- case VAR_UNKNOWN: {
- internal_error("f_type(UNKNOWN)");
- break;
- }
+ case VAR_NUMBER:
+ n = VAR_TYPE_NUMBER; break;
+ case VAR_STRING:
+ n = VAR_TYPE_STRING; break;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ n = VAR_TYPE_FUNC; break;
+ case VAR_LIST:
+ n = VAR_TYPE_LIST; break;
+ case VAR_DICT:
+ n = VAR_TYPE_DICT; break;
+ case VAR_FLOAT:
+ n = VAR_TYPE_FLOAT; break;
+ case VAR_BOOL:
+ n = VAR_TYPE_BOOL; break;
+ case VAR_SPECIAL:
+ n = VAR_TYPE_SPECIAL; break;
+ case VAR_BLOB:
+ n = VAR_TYPE_BLOB; break;
+ case VAR_UNKNOWN:
+ internal_error("f_type(UNKNOWN)");
+ break;
}
rettv->vval.v_number = n;
}
@@ -11267,7 +11810,7 @@ static void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
colnr_T vcol = 0;
- pos_T *fp;
+ pos_T *fp;
int fnum = curbuf->b_fnum;
fp = var2fpos(&argvars[0], FALSE, &fnum);
@@ -11352,6 +11895,9 @@ static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = vim_strsave((char_u *)"popup");
} else if (wp == curwin && cmdwin_type != 0) {
rettv->vval.v_string = vim_strsave((char_u *)"command");
+ } else if (bt_quickfix(wp->w_buffer)) {
+ rettv->vval.v_string = vim_strsave((char_u *)(wp->w_llist_ref != NULL ?
+ "loclist" : "quickfix"));
}
}
@@ -11515,10 +12061,12 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
win_new_width(curwin, curwin->w_width);
changed_window_setting();
- if (curwin->w_topline <= 0)
+ if (curwin->w_topline <= 0) {
curwin->w_topline = 1;
- if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ }
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
curwin->w_topline = curbuf->b_ml.ml_line_count;
+ }
check_topfill(curwin, true);
}
}
@@ -11528,7 +12076,7 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- dict_T *dict;
+ dict_T *dict;
tv_dict_alloc_ret(rettv);
dict = rettv->vval.v_dict;
@@ -11579,16 +12127,17 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "writefile()");
+ if (argvars[0].v_type == VAR_LIST) {
+ TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, {
+ if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) {
+ return;
+ }
+ });
+ } else if (argvars[0].v_type != VAR_BLOB) {
+ EMSG2(_(e_invarg2),
+ _("writefile() first argument must be a List or a Blob"));
return;
}
- const list_T *const list = argvars[0].vval.v_list;
- TV_LIST_ITER_CONST(list, li, {
- if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) {
- return;
- }
- });
bool binary = false;
bool append = false;
@@ -11600,15 +12149,18 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
for (const char *p = flags; *p; p++) {
switch (*p) {
- case 'b': { binary = true; break; }
- case 'a': { append = true; break; }
- case 's': { do_fsync = true; break; }
- case 'S': { do_fsync = false; break; }
- default: {
- // Using %s, p and not %c, *p to preserve multibyte characters
- emsgf(_("E5060: Unknown flag: %s"), p);
- return;
- }
+ case 'b':
+ binary = true; break;
+ case 'a':
+ append = true; break;
+ case 's':
+ do_fsync = true; break;
+ case 'S':
+ do_fsync = false; break;
+ default:
+ // Using %s, p and not %c, *p to preserve multibyte characters
+ emsgf(_("E5060: Unknown flag: %s"), p);
+ return;
}
}
}
@@ -11628,7 +12180,13 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsgf(_("E482: Can't open file %s for writing: %s"),
fname, os_strerror(error));
} else {
- if (write_list(&fp, list, binary)) {
+ bool write_ok;
+ if (argvars[0].v_type == VAR_BLOB) {
+ write_ok = write_blob(&fp, argvars[0].vval.v_blob);
+ } else {
+ write_ok = write_list(&fp, argvars[0].vval.v_list, binary);
+ }
+ if (write_ok) {
rettv->vval.v_number = 0;
}
if ((error = file_close(&fp, do_fsync)) != 0) {