diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt index 6e5cfc8356..4049f22b44 100644 --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -852,7 +852,7 @@ available. job_getchannel({job}) *job_getchannel()* Get the channel handle that {job} is using. To check if the job has no channel: > - if string(job_getchannel()) == 'channel fail' + if string(job_getchannel(job)) == 'channel fail' < Can also be used as a |method|: > GetJob()->job_getchannel() diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 7f02e5ef81..7d50b325e7 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1331,7 +1331,10 @@ A jump table for the options with a short description can be found at |Q_op|. continuation (positive). sbr Display the 'showbreak' value before applying the additional indent. - The default value for min is 20 and shift is 0. + list:{n} Adds an additional indent for lines that match a + numbered or bulleted list (using the + 'formatlistpat' setting). + The default value for min is 20, shift and list is 0. *'browsedir'* *'bsdir'* 'browsedir' 'bsdir' string (default: "last") diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 8b91cdd4b1..a0681d2875 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1354,6 +1354,9 @@ script file to avoid confusion. `:import` can also be used in legacy Vim script. The imported items still become script-local, even when the "s:" prefix is not given. +`:import` can not be used in a function. Imported items are intended to exist +at the script level and only imported once. + The script name after `import` can be: - A relative path, starting "." or "..". This finds a file relative to the location of the script file itself. This is useful to split up a large @@ -1363,6 +1366,7 @@ The script name after `import` can be: - A path not being relative or absolute. This will be found in the "import" subdirectories of 'runtimepath' entries. The name will usually be longer and unique, to avoid loading the wrong file. + Note that "after/import" is not used. Once a vim9 script file has been imported, the result is cached and used the next time the same script is imported. It will not be read again. diff --git a/src/change.c b/src/change.c index 6dcf016296..9b7582499a 100644 --- a/src/change.c +++ b/src/change.c @@ -563,9 +563,12 @@ changed_common( changed_cline_bef_curs_win(wp); if (wp->w_botline >= lnum) { - // Assume that botline doesn't change (inserted lines make - // other lines scroll down below botline). - approximate_botline_win(wp); + if (xtra < 0) + invalidate_botline_win(wp); + else + // Assume that botline doesn't change (inserted lines make + // other lines scroll down below botline). + approximate_botline_win(wp); } // Check if any w_lines[] entries have become invalid. diff --git a/src/clientserver.c b/src/clientserver.c index f6e18490d7..f4562e4855 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -896,8 +896,15 @@ f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) char_u *r = NULL; #ifdef FEAT_CLIENTSERVER - char_u *serverid = tv_get_string_chk(&argvars[0]); + char_u *serverid; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + serverid = tv_get_string_chk(&argvars[0]); if (serverid != NULL && !check_restricted() && !check_secure()) { int timeout = 0; diff --git a/src/cmdhist.c b/src/cmdhist.c index 8bb3cb61c7..1b04e62237 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -597,6 +597,12 @@ f_histget(typval_T *argvars UNUSED, typval_T *rettv) int idx; char_u *str; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + str = tv_get_string_chk(&argvars[0]); // NULL on type error if (str == NULL) rettv->vval.v_string = NULL; diff --git a/src/diff.c b/src/diff.c index 6f25c373c4..4c8afb12bd 100644 --- a/src/diff.c +++ b/src/diff.c @@ -3283,7 +3283,7 @@ f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_DIFF - linenr_T lnum = tv_get_lnum(argvars); + linenr_T lnum; static linenr_T prev_lnum = 0; static varnumber_T changedtick = 0; static int fnum = 0; @@ -3293,6 +3293,14 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) int filler_lines; int col; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + + lnum = tv_get_lnum(argvars); if (lnum < 0) // ignore type error in {lnum} arg lnum = 0; if (lnum != prev_lnum diff --git a/src/dosinst.c b/src/dosinst.c index 2d2b95c10a..608f381f12 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -1580,6 +1580,7 @@ install_registry(void) char display_name[BUFSIZE]; char uninstall_string[BUFSIZE]; char icon_string[BUFSIZE]; + char version_string[BUFSIZE]; int i; int loop_count = is_64bit_os() ? 2 : 1; DWORD flag; @@ -1652,13 +1653,15 @@ install_registry(void) sprintf(icon_string, "%s\\gvim.exe,0", installdir); + sprintf(version_string, VIM_VERSION_SHORT "." VIM_VERSION_PATCHLEVEL_STR); + lRet = register_uninstall( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, display_name, uninstall_string, icon_string, - VIM_VERSION_SHORT, + version_string, "Bram Moolenaar et al."); if (ERROR_SUCCESS != lRet) return FAIL; diff --git a/src/errors.h b/src/errors.h index d4f3179abe..be1341adb1 100644 --- a/src/errors.h +++ b/src/errors.h @@ -381,8 +381,8 @@ EXTERN char e_mismatched_endfunction[] INIT(= N_("E1151: Mismatched endfunction")); EXTERN char e_mismatched_enddef[] INIT(= N_("E1152: Mismatched enddef")); -EXTERN char e_invalid_operation_for_bool[] - INIT(= N_("E1153: Invalid operation for bool")); +EXTERN char e_invalid_operation_for_str[] + INIT(= N_("E1153: Invalid operation for %s")); EXTERN char e_divide_by_zero[] INIT(= N_("E1154: Divide by zero")); EXTERN char e_cannot_define_autocommands_for_all_events[] @@ -496,3 +496,15 @@ EXTERN char e_dict_required_for_argument_nr[] INIT(= N_("E1206: Dictionary required for argument %d")); EXTERN char e_expression_without_effect_str[] INIT(= N_("E1207: Expression without an effect: %s")); +EXTERN char e_complete_used_without_nargs[] + INIT(= N_("E1208: -complete used without -nargs")); +EXTERN char e_invalid_value_for_line_number_str[] + INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); +EXTERN char e_number_required_for_argument_nr[] + INIT(= N_("E1210: Number required for argument %d")); +EXTERN char e_list_required_for_argument_nr[] + INIT(= N_("E1211: List required for argument %d")); +EXTERN char e_bool_required_for_argument_nr[] + INIT(= N_("E1211: Bool required for argument %d")); +EXTERN char e_redefining_imported_item_str[] + INIT(= N_("E1212: Redefining imported item %s")); diff --git a/src/eval.c b/src/eval.c index 4d94d67ee6..77774b738d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1358,7 +1358,8 @@ set_var_lval( || (!var_check_ro(di->di_flags, lp->ll_name, FALSE) && !tv_check_lock(&di->di_tv, lp->ll_name, FALSE))) && tv_op(&tv, rettv, op) == OK) - set_var(lp->ll_name, &tv, FALSE); + set_var_const(lp->ll_name, NULL, &tv, FALSE, + ASSIGN_NO_DECL, 0); clear_tv(&tv); } } @@ -1784,6 +1785,8 @@ next_for_item(void *fi_void, char_u *arg) | ASSIGN_NO_MEMBER_TYPE) : 0); listitem_T *item; + int skip_assign = in_vim9script() && arg[0] == '_' + && !eval_isnamec(arg[1]); if (fi->fi_blob != NULL) { @@ -1795,6 +1798,8 @@ next_for_item(void *fi_void, char_u *arg) tv.v_lock = VAR_FIXED; tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi); ++fi->fi_bi; + if (skip_assign) + return TRUE; return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK; } @@ -1812,7 +1817,10 @@ next_for_item(void *fi_void, char_u *arg) tv.vval.v_string = vim_strnsave(fi->fi_string + fi->fi_byte_idx, len); fi->fi_byte_idx += len; ++fi->fi_bi; - result = ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, + if (skip_assign) + result = TRUE; + else + result = ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK; vim_free(tv.vval.v_string); return result; @@ -1825,7 +1833,10 @@ next_for_item(void *fi_void, char_u *arg) { fi->fi_lw.lw_item = item->li_next; ++fi->fi_bi; - result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, + if (skip_assign) + result = TRUE; + else + result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK); } return result; @@ -2177,6 +2188,11 @@ eval_next_line(evalarg_T *evalarg) vim_free(evalarg->eval_tofree); evalarg->eval_tofree = line; } + + // Advanced to the next line, "arg" no longer points into the previous + // line. + VIM_CLEAR(evalarg->eval_tofree_cmdline); + return skipwhite(line); } @@ -5376,6 +5392,8 @@ var2fpos( } return &pos; } + if (in_vim9script()) + semsg(_(e_invalid_value_for_line_number_str), name); return NULL; } @@ -6189,6 +6207,7 @@ ex_execute(exarg_T *eap) char_u *p; garray_T ga; int len; + long start_lnum = SOURCING_LNUM; ga_init2(&ga, 1, 80); @@ -6242,6 +6261,9 @@ ex_execute(exarg_T *eap) if (ret != FAIL && ga.ga_data != NULL) { + // use the first line of continuation lines for messages + SOURCING_LNUM = start_lnum; + if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr) { // Mark the already saved text as finishing the line, so that what diff --git a/src/evalfunc.c b/src/evalfunc.c index 350f6d8c3d..b3a1a52cbc 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -254,6 +254,15 @@ arg_dict_any(type_T *type, argcontext_T *context) return check_arg_type(&t_dict_any, type, context); } +/* + * Check "type" is a list of 'any'. + */ + static int +arg_list_any(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_list_any, type, context); +} + /* * Check "type" is a list of numbers. */ @@ -287,9 +296,6 @@ arg_string(type_T *type, argcontext_T *context) static int arg_bool(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_ANY - || type->tt_type == VAR_NUMBER || type->tt_type == VAR_BOOL) - return OK; return check_arg_type(&t_bool, type, context); } @@ -322,7 +328,7 @@ arg_string_or_nr(type_T *type, argcontext_T *context) * Check "type" is a string or a list of strings. */ static int -arg_string_or_list(type_T *type, argcontext_T *context) +arg_string_or_list_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING) return OK; @@ -340,7 +346,20 @@ arg_string_or_list(type_T *type, argcontext_T *context) } /* - * Check "type" is a list or a dict. + * Check "type" is a string or a list of 'any' + */ + static int +arg_string_or_list_any(type_T *type, argcontext_T *context) +{ + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST) + return OK; + arg_type_mismatch(&t_string, type, context->arg_idx + 1); + return FAIL; +} + +/* + * Check "type" is a list of 'any' or a dict of 'any'. */ static int arg_list_or_dict(type_T *type, argcontext_T *context) @@ -352,13 +371,23 @@ arg_list_or_dict(type_T *type, argcontext_T *context) return FAIL; } +/* + * Check "type" is a job. + */ + static int +arg_job(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_job, type, context); +} + /* * Check "type" is a channel or a job. */ static int arg_chan_or_job(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_CHANNEL || type->tt_type == VAR_JOB) + if (type->tt_type == VAR_ANY || + type->tt_type == VAR_CHANNEL || type->tt_type == VAR_JOB) return OK; arg_type_mismatch(&t_channel, type, context->arg_idx + 1); return FAIL; @@ -412,6 +441,21 @@ arg_item_of_prev(type_T *type, argcontext_T *context) return check_arg_type(expected, type, context); } +/* + * Check "type" is a string or a number or a list + */ + static int +arg_str_or_nr_or_list(type_T *type, argcontext_T *context) +{ + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_STRING + || type->tt_type == VAR_NUMBER + || type->tt_type == VAR_LIST) + return OK; + arg_type_mismatch(&t_string, type, context->arg_idx + 1); + return FAIL; +} + /* * Check "type" which is the third argument of extend(). */ @@ -431,31 +475,51 @@ arg_extend3(type_T *type, argcontext_T *context) /* * Lists of functions that check the argument types of a builtin function. */ -argcheck_T arg1_string[] = {arg_string}; -argcheck_T arg1_number[] = {arg_number}; -argcheck_T arg1_dict[] = {arg_dict_any}; -argcheck_T arg1_list_nr[] = {arg_list_number}; -argcheck_T arg1_list_string[] = {arg_list_string}; -argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; -argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; -argcheck_T arg1_string_or_list[] = {arg_string_or_list}; -argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; -argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; -argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; -argcheck_T arg2_number[] = {arg_number, arg_number}; -argcheck_T arg2_string[] = {arg_string, arg_string}; -argcheck_T arg2_list_nr[] = {arg_list_number, arg_list_number}; -argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; -argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; -argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; -argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; -argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; -argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; -argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; -argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; -argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; -argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; -argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; +static argcheck_T arg1_string[] = {arg_string}; +static argcheck_T arg1_number[] = {arg_number}; +static argcheck_T arg1_bool[] = {arg_bool}; +static argcheck_T arg1_dict_any[] = {arg_dict_any}; +static argcheck_T arg1_job[] = {arg_job}; +static argcheck_T arg1_list_any[] = {arg_list_any}; +static argcheck_T arg1_list_nr[] = {arg_list_number}; +static argcheck_T arg1_list_string[] = {arg_list_string}; +static argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; +static argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; +static argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any}; +static argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string}; +static argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; +static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict}; +static argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; +static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; +static argcheck_T arg2_number[] = {arg_number, arg_number}; +static argcheck_T arg2_string[] = {arg_string, arg_string}; +static argcheck_T arg2_list_nr[] = {arg_list_number, arg_list_number}; +static argcheck_T arg2_nr_string[] = {arg_number, arg_string}; +static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; +static argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; +static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; +static argcheck_T arg2_string_nr[] = {arg_string, arg_number}; +static argcheck_T arg2_string_bool[] = {arg_string, arg_bool}; +//static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; +static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; +static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; +static argcheck_T arg2_string_or_nr_string[] = {arg_string_or_nr, arg_string}; +static argcheck_T arg2_string_or_nr_nr[] = {arg_string_or_nr, arg_number}; +static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any}; +static argcheck_T arg2_nr_dict_any[] = {arg_number, arg_dict_any}; +//static argcheck_T arg2_string_number[] = {arg_string, arg_number}; +static argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; +static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; +static argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; +static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; +static argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string}; +static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; +static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; +static argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; +static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list}; +static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL}; +static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; +static argcheck_T arg4_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number}; /* * Functions that return the return type of a builtin function. @@ -727,9 +791,9 @@ static funcentry_T global_functions[] = ret_first_arg, f_add}, {"and", 2, 2, FEARG_1, arg2_number, ret_number, f_and}, - {"append", 2, 2, FEARG_2, NULL, + {"append", 2, 2, FEARG_2, arg2_setline, ret_number_bool, f_append}, - {"appendbufline", 3, 3, FEARG_3, NULL, + {"appendbufline", 3, 3, FEARG_3, arg3_setbufline, ret_number_bool, f_appendbufline}, {"argc", 0, 1, 0, arg1_number, ret_number, f_argc}, @@ -741,7 +805,7 @@ static funcentry_T global_functions[] = ret_argv, f_argv}, {"asin", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_asin)}, - {"assert_beeps", 1, 2, FEARG_1, NULL, + {"assert_beeps", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_beeps}, {"assert_equal", 2, 3, FEARG_2, NULL, ret_number_bool, f_assert_equal}, @@ -757,13 +821,13 @@ static funcentry_T global_functions[] = ret_number_bool, f_assert_inrange}, {"assert_match", 2, 3, FEARG_2, arg3_string, ret_number_bool, f_assert_match}, - {"assert_nobeep", 1, 2, FEARG_1, NULL, + {"assert_nobeep", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_nobeep}, {"assert_notequal", 2, 3, FEARG_2, NULL, ret_number_bool, f_assert_notequal}, {"assert_notmatch", 2, 3, FEARG_2, arg3_string, ret_number_bool, f_assert_notmatch}, - {"assert_report", 1, 1, FEARG_1, NULL, + {"assert_report", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_report}, {"assert_true", 1, 2, FEARG_1, NULL, ret_number_bool, f_assert_true}, @@ -779,7 +843,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list, + {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list_any, ret_void, #ifdef FEAT_BEVAL f_balloon_show @@ -825,9 +889,9 @@ static funcentry_T global_functions[] = ret_number, f_bufwinnr}, {"byte2line", 1, 1, FEARG_1, arg1_number, ret_number, f_byte2line}, - {"byteidx", 2, 2, FEARG_1, NULL, + {"byteidx", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_byteidx}, - {"byteidxcomp", 2, 2, FEARG_1, NULL, + {"byteidxcomp", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_byteidxcomp}, {"call", 2, 3, FEARG_1, NULL, ret_any, f_call}, @@ -845,7 +909,7 @@ static funcentry_T global_functions[] = ret_any, JOB_FUNC(f_ch_evalraw)}, {"ch_getbufnr", 2, 2, FEARG_1, NULL, ret_number, JOB_FUNC(f_ch_getbufnr)}, - {"ch_getjob", 1, 1, FEARG_1, NULL, + {"ch_getjob", 1, 1, FEARG_1, arg1_chan_or_job, ret_job, JOB_FUNC(f_ch_getjob)}, {"ch_info", 1, 1, FEARG_1, arg1_chan_or_job, ret_dict_any, JOB_FUNC(f_ch_info)}, @@ -855,27 +919,27 @@ static funcentry_T global_functions[] = ret_void, JOB_FUNC(f_ch_logfile)}, {"ch_open", 1, 2, FEARG_1, arg2_string_dict, ret_channel, JOB_FUNC(f_ch_open)}, - {"ch_read", 1, 2, FEARG_1, NULL, + {"ch_read", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_read)}, - {"ch_readblob", 1, 2, FEARG_1, NULL, + {"ch_readblob", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_blob, JOB_FUNC(f_ch_readblob)}, - {"ch_readraw", 1, 2, FEARG_1, NULL, + {"ch_readraw", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_readraw)}, {"ch_sendexpr", 2, 3, FEARG_1, NULL, ret_void, JOB_FUNC(f_ch_sendexpr)}, {"ch_sendraw", 2, 3, FEARG_1, NULL, ret_void, JOB_FUNC(f_ch_sendraw)}, - {"ch_setoptions", 2, 2, FEARG_1, NULL, + {"ch_setoptions", 2, 2, FEARG_1, arg2_chan_or_job_dict, ret_void, JOB_FUNC(f_ch_setoptions)}, - {"ch_status", 1, 2, FEARG_1, NULL, + {"ch_status", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_status)}, {"changenr", 0, 0, 0, NULL, ret_number, f_changenr}, - {"char2nr", 1, 2, FEARG_1, NULL, + {"char2nr", 1, 2, FEARG_1, arg2_string_bool, ret_number, f_char2nr}, {"charclass", 1, 1, FEARG_1, arg1_string, ret_number, f_charclass}, - {"charcol", 1, 1, FEARG_1, arg1_string_or_list, + {"charcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_charcol}, {"charidx", 2, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_charidx}, @@ -885,7 +949,7 @@ static funcentry_T global_functions[] = ret_number, f_cindent}, {"clearmatches", 0, 1, FEARG_1, arg1_number, ret_void, f_clearmatches}, - {"col", 1, 1, FEARG_1, arg1_string_or_list, + {"col", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_col}, {"complete", 2, 2, FEARG_2, NULL, ret_void, f_complete}, @@ -927,9 +991,9 @@ static funcentry_T global_functions[] = ret_number_bool, f_did_filetype}, {"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_diff_filler}, - {"diff_hlID", 2, 2, FEARG_1, NULL, + {"diff_hlID", 2, 2, FEARG_1, arg2_string_or_nr_nr, ret_number, f_diff_hlID}, - {"echoraw", 1, 1, FEARG_1, NULL, + {"echoraw", 1, 1, FEARG_1, arg1_string, ret_void, f_echoraw}, {"empty", 1, 1, FEARG_1, NULL, ret_number_bool, f_empty}, @@ -1005,7 +1069,7 @@ static funcentry_T global_functions[] = ret_func_any, f_funcref}, {"function", 1, 3, FEARG_1, NULL, ret_f_function, f_function}, - {"garbagecollect", 0, 1, 0, NULL, + {"garbagecollect", 0, 1, 0, arg1_bool, ret_void, f_garbagecollect}, {"get", 2, 3, FEARG_1, NULL, ret_any, f_get}, @@ -1017,15 +1081,15 @@ static funcentry_T global_functions[] = ret_any, f_getbufvar}, {"getchangelist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_any, f_getchangelist}, - {"getchar", 0, 1, 0, NULL, + {"getchar", 0, 1, 0, arg1_bool, ret_any, f_getchar}, {"getcharmod", 0, 0, 0, NULL, ret_number, f_getcharmod}, - {"getcharpos", 1, 1, FEARG_1, NULL, + {"getcharpos", 1, 1, FEARG_1, arg1_string, ret_list_number, f_getcharpos}, {"getcharsearch", 0, 0, 0, NULL, ret_dict_any, f_getcharsearch}, - {"getcharstr", 0, 1, 0, NULL, + {"getcharstr", 0, 1, 0, arg1_bool, ret_string, f_getcharstr}, {"getcmdline", 0, 0, 0, NULL, ret_string, f_getcmdline}, @@ -1061,7 +1125,7 @@ static funcentry_T global_functions[] = ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, NULL, ret_f_getline, f_getline}, - {"getloclist", 1, 2, 0, NULL, + {"getloclist", 1, 2, 0, arg2_nr_dict_any, ret_list_or_dict_1, f_getloclist}, {"getmarklist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_dict_any, f_getmarklist}, @@ -1073,7 +1137,7 @@ static funcentry_T global_functions[] = ret_number, f_getpid}, {"getpos", 1, 1, FEARG_1, arg1_string, ret_list_number, f_getpos}, - {"getqflist", 0, 1, 0, arg1_dict, + {"getqflist", 0, 1, 0, arg1_dict_any, ret_list_or_dict_0, f_getqflist}, {"getreg", 0, 3, FEARG_1, NULL, ret_getreg, f_getreg}, @@ -1109,7 +1173,7 @@ static funcentry_T global_functions[] = ret_any, f_globpath}, {"has", 1, 2, 0, NULL, ret_number_bool, f_has}, - {"has_key", 2, 2, FEARG_1, arg2_dict_string, + {"has_key", 2, 2, FEARG_1, arg2_dict_string_or_nr, ret_number_bool, f_has_key}, {"haslocaldir", 0, 2, FEARG_1, arg2_number, ret_number, f_haslocaldir}, @@ -1123,7 +1187,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_histadd}, {"histdel", 1, 2, FEARG_1, NULL, ret_number_bool, f_histdel}, - {"histget", 1, 2, FEARG_1, NULL, + {"histget", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_histget}, {"histnr", 1, 1, FEARG_1, arg1_string, ret_number, f_histnr}, @@ -1161,21 +1225,21 @@ static funcentry_T global_functions[] = ret_number_bool, f_isdirectory}, {"isinf", 1, 1, FEARG_1, arg1_float_or_nr, ret_number, MATH_FUNC(f_isinf)}, - {"islocked", 1, 1, FEARG_1, NULL, + {"islocked", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_islocked}, {"isnan", 1, 1, FEARG_1, arg1_float_or_nr, ret_number_bool, MATH_FUNC(f_isnan)}, - {"items", 1, 1, FEARG_1, arg1_dict, + {"items", 1, 1, FEARG_1, arg1_dict_any, ret_list_items, f_items}, - {"job_getchannel", 1, 1, FEARG_1, NULL, + {"job_getchannel", 1, 1, FEARG_1, arg1_job, ret_channel, JOB_FUNC(f_job_getchannel)}, - {"job_info", 0, 1, FEARG_1, NULL, + {"job_info", 0, 1, FEARG_1, arg1_job, ret_job_info, JOB_FUNC(f_job_info)}, {"job_setoptions", 2, 2, FEARG_1, NULL, ret_void, JOB_FUNC(f_job_setoptions)}, {"job_start", 1, 2, FEARG_1, NULL, ret_job, JOB_FUNC(f_job_start)}, - {"job_status", 1, 1, FEARG_1, NULL, + {"job_status", 1, 1, FEARG_1, arg1_job, ret_string, JOB_FUNC(f_job_status)}, {"job_stop", 1, 2, FEARG_1, NULL, ret_number_bool, JOB_FUNC(f_job_stop)}, @@ -1189,9 +1253,9 @@ static funcentry_T global_functions[] = ret_any, f_json_decode}, {"json_encode", 1, 1, FEARG_1, NULL, ret_string, f_json_encode}, - {"keys", 1, 1, FEARG_1, arg1_dict, + {"keys", 1, 1, FEARG_1, arg1_dict_any, ret_list_string, f_keys}, - {"last_buffer_nr", 0, 0, 0, arg1_string_or_nr, // obsolete + {"last_buffer_nr", 0, 0, 0, NULL, // obsolete ret_number, f_last_buffer_nr}, {"len", 1, 1, FEARG_1, NULL, ret_number, f_len}, @@ -1199,7 +1263,7 @@ static funcentry_T global_functions[] = ret_string, f_libcall}, {"libcallnr", 3, 3, FEARG_3, NULL, ret_number, f_libcallnr}, - {"line", 1, 2, FEARG_1, NULL, + {"line", 1, 2, FEARG_1, arg2_string_nr, ret_number, f_line}, {"line2byte", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_line2byte}, @@ -1237,7 +1301,7 @@ static funcentry_T global_functions[] = ret_first_cont, f_mapnew}, {"mapset", 3, 3, FEARG_1, NULL, ret_void, f_mapset}, - {"match", 2, 4, FEARG_1, NULL, + {"match", 2, 4, FEARG_1, arg4_match_func, ret_any, f_match}, {"matchadd", 2, 5, FEARG_1, NULL, ret_number, f_matchadd}, @@ -1247,19 +1311,19 @@ static funcentry_T global_functions[] = ret_list_string, f_matcharg}, {"matchdelete", 1, 2, FEARG_1, arg2_number, ret_number_bool, f_matchdelete}, - {"matchend", 2, 4, FEARG_1, NULL, + {"matchend", 2, 4, FEARG_1, arg4_match_func, ret_number, f_matchend}, {"matchfuzzy", 2, 3, FEARG_1, NULL, ret_list_string, f_matchfuzzy}, {"matchfuzzypos", 2, 3, FEARG_1, NULL, ret_list_any, f_matchfuzzypos}, - {"matchlist", 2, 4, FEARG_1, NULL, + {"matchlist", 2, 4, FEARG_1, arg4_match_func, ret_list_string, f_matchlist}, - {"matchstr", 2, 4, FEARG_1, NULL, + {"matchstr", 2, 4, FEARG_1, arg4_match_func, ret_string, f_matchstr}, - {"matchstrpos", 2, 4, FEARG_1, NULL, + {"matchstrpos", 2, 4, FEARG_1, arg4_match_func, ret_list_any, f_matchstrpos}, - {"max", 1, 1, FEARG_1, NULL, + {"max", 1, 1, FEARG_1, arg1_list_or_dict, ret_number, f_max}, {"menu_info", 1, 2, FEARG_1, arg2_string, ret_dict_any, @@ -1269,13 +1333,13 @@ static funcentry_T global_functions[] = NULL #endif }, - {"min", 1, 1, FEARG_1, NULL, + {"min", 1, 1, FEARG_1, arg1_list_or_dict, ret_number, f_min}, {"mkdir", 1, 3, FEARG_1, arg3_string_string_nr, ret_number_bool, f_mkdir}, - {"mode", 0, 1, FEARG_1, NULL, + {"mode", 0, 1, FEARG_1, arg1_bool, ret_string, f_mode}, - {"mzeval", 1, 1, FEARG_1, NULL, + {"mzeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_MZSCHEME f_mzeval @@ -1289,9 +1353,9 @@ static funcentry_T global_functions[] = ret_string, f_nr2char}, {"or", 2, 2, FEARG_1, arg2_number, ret_number, f_or}, - {"pathshorten", 1, 2, FEARG_1, NULL, + {"pathshorten", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_pathshorten}, - {"perleval", 1, 1, FEARG_1, NULL, + {"perleval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PERL f_perleval @@ -1299,47 +1363,47 @@ static funcentry_T global_functions[] = NULL #endif }, - {"popup_atcursor", 2, 2, FEARG_1, NULL, + {"popup_atcursor", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_atcursor)}, - {"popup_beval", 2, 2, FEARG_1, NULL, + {"popup_beval", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_beval)}, - {"popup_clear", 0, 1, 0, NULL, + {"popup_clear", 0, 1, 0, arg1_bool, ret_void, PROP_FUNC(f_popup_clear)}, {"popup_close", 1, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_close)}, - {"popup_create", 2, 2, FEARG_1, NULL, + {"popup_create", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_create)}, - {"popup_dialog", 2, 2, FEARG_1, NULL, + {"popup_dialog", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_dialog)}, - {"popup_filter_menu", 2, 2, 0, NULL, + {"popup_filter_menu", 2, 2, 0, arg2_nr_string, ret_bool, PROP_FUNC(f_popup_filter_menu)}, - {"popup_filter_yesno", 2, 2, 0, NULL, + {"popup_filter_yesno", 2, 2, 0, arg2_nr_string, ret_bool, PROP_FUNC(f_popup_filter_yesno)}, {"popup_findinfo", 0, 0, 0, NULL, ret_number, PROP_FUNC(f_popup_findinfo)}, {"popup_findpreview", 0, 0, 0, NULL, ret_number, PROP_FUNC(f_popup_findpreview)}, - {"popup_getoptions", 1, 1, FEARG_1, NULL, + {"popup_getoptions", 1, 1, FEARG_1, arg1_number, ret_dict_any, PROP_FUNC(f_popup_getoptions)}, - {"popup_getpos", 1, 1, FEARG_1, NULL, + {"popup_getpos", 1, 1, FEARG_1, arg1_number, ret_dict_any, PROP_FUNC(f_popup_getpos)}, - {"popup_hide", 1, 1, FEARG_1, NULL, + {"popup_hide", 1, 1, FEARG_1, arg1_number, ret_void, PROP_FUNC(f_popup_hide)}, {"popup_list", 0, 0, 0, NULL, ret_list_number, PROP_FUNC(f_popup_list)}, {"popup_locate", 2, 2, 0, arg2_number, ret_number, PROP_FUNC(f_popup_locate)}, - {"popup_menu", 2, 2, FEARG_1, NULL, + {"popup_menu", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_menu)}, - {"popup_move", 2, 2, FEARG_1, NULL, + {"popup_move", 2, 2, FEARG_1, arg2_nr_dict_any, ret_void, PROP_FUNC(f_popup_move)}, - {"popup_notification", 2, 2, FEARG_1, NULL, + {"popup_notification", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_notification)}, - {"popup_setoptions", 2, 2, FEARG_1, NULL, + {"popup_setoptions", 2, 2, FEARG_1, arg2_nr_dict_any, ret_void, PROP_FUNC(f_popup_setoptions)}, {"popup_settext", 2, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_settext)}, - {"popup_show", 1, 1, FEARG_1, NULL, + {"popup_show", 1, 1, FEARG_1, arg1_number, ret_void, PROP_FUNC(f_popup_show)}, {"pow", 2, 2, FEARG_1, arg2_float_or_nr, ret_float, FLOAT_FUNC(f_pow)}, @@ -1353,7 +1417,7 @@ static funcentry_T global_functions[] = ret_void, JOB_FUNC(f_prompt_setcallback)}, {"prompt_setinterrupt", 2, 2, FEARG_1, NULL, ret_void, JOB_FUNC(f_prompt_setinterrupt)}, - {"prompt_setprompt", 2, 2, FEARG_1, NULL, + {"prompt_setprompt", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, JOB_FUNC(f_prompt_setprompt)}, {"prop_add", 3, 3, FEARG_1, NULL, ret_void, PROP_FUNC(f_prop_add)}, @@ -1361,7 +1425,7 @@ static funcentry_T global_functions[] = ret_void, PROP_FUNC(f_prop_clear)}, {"prop_find", 1, 2, FEARG_1, arg2_dict_string, ret_dict_any, PROP_FUNC(f_prop_find)}, - {"prop_list", 1, 2, FEARG_1, NULL, + {"prop_list", 1, 2, FEARG_1, arg2_nr_dict_any, ret_list_dict_any, PROP_FUNC(f_prop_list)}, {"prop_remove", 1, 3, FEARG_1, NULL, ret_number, PROP_FUNC(f_prop_remove)}, @@ -1373,13 +1437,13 @@ static funcentry_T global_functions[] = ret_void, PROP_FUNC(f_prop_type_delete)}, {"prop_type_get", 1, 2, FEARG_1, arg2_string_dict, ret_dict_any, PROP_FUNC(f_prop_type_get)}, - {"prop_type_list", 0, 1, FEARG_1, NULL, + {"prop_type_list", 0, 1, FEARG_1, arg1_dict_any, ret_list_string, PROP_FUNC(f_prop_type_list)}, {"pum_getpos", 0, 0, 0, NULL, ret_dict_number, f_pum_getpos}, {"pumvisible", 0, 0, 0, NULL, ret_number_bool, f_pumvisible}, - {"py3eval", 1, 1, FEARG_1, NULL, + {"py3eval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PYTHON3 f_py3eval @@ -1387,7 +1451,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"pyeval", 1, 1, FEARG_1, NULL, + {"pyeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PYTHON f_pyeval @@ -1395,7 +1459,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"pyxeval", 1, 1, FEARG_1, NULL, + {"pyxeval", 1, 1, FEARG_1, arg1_string, ret_any, #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) f_pyxeval @@ -1433,7 +1497,7 @@ static funcentry_T global_functions[] = ret_string, f_remote_foreground}, {"remote_peek", 1, 2, FEARG_1, arg2_string, ret_number, f_remote_peek}, - {"remote_read", 1, 2, FEARG_1, NULL, + {"remote_read", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_remote_read}, {"remote_send", 2, 3, FEARG_1, NULL, ret_string, f_remote_send}, @@ -1451,7 +1515,7 @@ static funcentry_T global_functions[] = ret_first_arg, f_reverse}, {"round", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_round)}, - {"rubyeval", 1, 1, FEARG_1, NULL, + {"rubyeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_RUBY f_rubyeval @@ -1475,7 +1539,7 @@ static funcentry_T global_functions[] = ret_string, f_screenstring}, {"search", 1, 5, FEARG_1, NULL, ret_number, f_search}, - {"searchcount", 0, 1, FEARG_1, arg1_dict, + {"searchcount", 0, 1, FEARG_1, arg1_dict_any, ret_dict_any, f_searchcount}, {"searchdecl", 1, 3, FEARG_1, NULL, ret_number_bool, f_searchdecl}, @@ -1489,15 +1553,15 @@ static funcentry_T global_functions[] = ret_number_bool, f_server2client}, {"serverlist", 0, 0, 0, NULL, ret_string, f_serverlist}, - {"setbufline", 3, 3, FEARG_3, NULL, + {"setbufline", 3, 3, FEARG_3, arg3_setbufline, ret_number_bool, f_setbufline}, {"setbufvar", 3, 3, FEARG_3, NULL, ret_void, f_setbufvar}, - {"setcellwidths", 1, 1, FEARG_1, NULL, + {"setcellwidths", 1, 1, FEARG_1, arg1_list_any, ret_void, f_setcellwidths}, {"setcharpos", 2, 2, FEARG_2, NULL, ret_number_bool, f_setcharpos}, - {"setcharsearch", 1, 1, FEARG_1, arg1_dict, + {"setcharsearch", 1, 1, FEARG_1, arg1_dict_any, ret_void, f_setcharsearch}, {"setcmdpos", 1, 1, FEARG_1, arg1_number, ret_number_bool, f_setcmdpos}, @@ -1507,7 +1571,7 @@ static funcentry_T global_functions[] = ret_void, f_setenv}, {"setfperm", 2, 2, FEARG_1, arg2_string, ret_number_bool, f_setfperm}, - {"setline", 2, 2, FEARG_2, NULL, + {"setline", 2, 2, FEARG_2, arg2_setline, ret_number_bool, f_setline}, {"setloclist", 2, 4, FEARG_2, NULL, ret_number_bool, f_setloclist}, @@ -1539,9 +1603,9 @@ static funcentry_T global_functions[] = ret_string, f_shellescape}, {"shiftwidth", 0, 1, FEARG_1, arg1_number, ret_number, f_shiftwidth}, - {"sign_define", 1, 2, FEARG_1, arg2_string_dict, + {"sign_define", 1, 2, FEARG_1, arg2_string_or_list_dict, ret_any, SIGN_FUNC(f_sign_define)}, - {"sign_getdefined", 0, 1, FEARG_1, NULL, + {"sign_getdefined", 0, 1, FEARG_1, arg1_string, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)}, {"sign_getplaced", 0, 2, FEARG_1, NULL, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)}, @@ -1549,13 +1613,13 @@ static funcentry_T global_functions[] = ret_number, SIGN_FUNC(f_sign_jump)}, {"sign_place", 4, 5, FEARG_1, NULL, ret_number, SIGN_FUNC(f_sign_place)}, - {"sign_placelist", 1, 1, FEARG_1, NULL, + {"sign_placelist", 1, 1, FEARG_1, arg1_list_any, ret_list_number, SIGN_FUNC(f_sign_placelist)}, - {"sign_undefine", 0, 1, FEARG_1, arg1_string_or_list, + {"sign_undefine", 0, 1, FEARG_1, arg1_string_or_list_string, ret_number_bool, SIGN_FUNC(f_sign_undefine)}, {"sign_unplace", 1, 2, FEARG_1, arg2_string_dict, ret_number_bool, SIGN_FUNC(f_sign_unplace)}, - {"sign_unplacelist", 1, 2, FEARG_1, NULL, + {"sign_unplacelist", 1, 2, FEARG_1, arg1_list_any, ret_list_number, SIGN_FUNC(f_sign_unplacelist)}, {"simplify", 1, 1, FEARG_1, arg1_string, ret_string, f_simplify}, @@ -1591,19 +1655,19 @@ static funcentry_T global_functions[] = ret_string, f_state}, {"str2float", 1, 1, FEARG_1, arg1_string, ret_float, FLOAT_FUNC(f_str2float)}, - {"str2list", 1, 2, FEARG_1, NULL, + {"str2list", 1, 2, FEARG_1, arg2_string_bool, ret_list_number, f_str2list}, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_str2nr}, - {"strcharlen", 1, 1, FEARG_1, NULL, + {"strcharlen", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_strcharlen}, {"strcharpart", 2, 4, FEARG_1, NULL, ret_string, f_strcharpart}, - {"strchars", 1, 2, FEARG_1, NULL, + {"strchars", 1, 2, FEARG_1, arg2_string_bool, ret_number, f_strchars}, - {"strdisplaywidth", 1, 2, FEARG_1, NULL, + {"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr, ret_number, f_strdisplaywidth}, - {"strftime", 1, 2, FEARG_1, NULL, + {"strftime", 1, 2, FEARG_1, arg2_string_nr, ret_string, #ifdef HAVE_STRFTIME f_strftime @@ -1611,7 +1675,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"strgetchar", 2, 2, FEARG_1, NULL, + {"strgetchar", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_strgetchar}, {"stridx", 2, 3, FEARG_1, arg3_string_string_nr, ret_number, f_stridx}, @@ -1649,9 +1713,9 @@ static funcentry_T global_functions[] = ret_string, f_synIDattr}, {"synIDtrans", 1, 1, FEARG_1, arg1_number, ret_number, f_synIDtrans}, - {"synconcealed", 2, 2, 0, NULL, + {"synconcealed", 2, 2, 0, arg2_string_or_nr_nr, ret_list_any, f_synconcealed}, - {"synstack", 2, 2, 0, NULL, + {"synstack", 2, 2, 0, arg2_string_or_nr_nr, ret_list_number, f_synstack}, {"system", 1, 2, FEARG_1, NULL, ret_string, f_system}, @@ -1661,7 +1725,7 @@ static funcentry_T global_functions[] = ret_list_number, f_tabpagebuflist}, {"tabpagenr", 0, 1, 0, arg1_string, ret_number, f_tabpagenr}, - {"tabpagewinnr", 1, 2, FEARG_1, NULL, + {"tabpagewinnr", 1, 2, FEARG_1, arg2_nr_string, ret_number, f_tabpagewinnr}, {"tagfiles", 0, 0, 0, NULL, ret_list_string, f_tagfiles}, @@ -1689,7 +1753,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"term_getattr", 2, 2, FEARG_1, NULL, + {"term_getattr", 2, 2, FEARG_1, arg2_nr_string, ret_number, TERM_FUNC(f_term_getattr)}, {"term_getcursor", 1, 1, FEARG_1, arg1_string_or_nr, ret_list_any, TERM_FUNC(f_term_getcursor)}, @@ -1711,7 +1775,7 @@ static funcentry_T global_functions[] = ret_list_number, TERM_FUNC(f_term_list)}, {"term_scrape", 2, 2, FEARG_1, NULL, ret_list_dict_any, TERM_FUNC(f_term_scrape)}, - {"term_sendkeys", 2, 2, FEARG_1, NULL, + {"term_sendkeys", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_sendkeys)}, {"term_setansicolors", 2, 2, FEARG_1, NULL, ret_void, @@ -1721,17 +1785,17 @@ static funcentry_T global_functions[] = NULL #endif }, - {"term_setapi", 2, 2, FEARG_1, NULL, + {"term_setapi", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setapi)}, - {"term_setkill", 2, 2, FEARG_1, NULL, + {"term_setkill", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setkill)}, - {"term_setrestore", 2, 2, FEARG_1, NULL, + {"term_setrestore", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setrestore)}, {"term_setsize", 3, 3, FEARG_1, NULL, ret_void, TERM_FUNC(f_term_setsize)}, {"term_start", 1, 2, FEARG_1, NULL, ret_number, TERM_FUNC(f_term_start)}, - {"term_wait", 1, 2, FEARG_1, NULL, + {"term_wait", 1, 2, FEARG_1, arg2_string_or_nr_nr, ret_void, TERM_FUNC(f_term_wait)}, {"terminalprops", 0, 0, 0, NULL, ret_dict_string, f_terminalprops}, @@ -1771,7 +1835,7 @@ static funcentry_T global_functions[] = ret_string, f_test_null_string}, {"test_option_not_set", 1, 1, FEARG_1, arg1_string, ret_void, f_test_option_not_set}, - {"test_override", 2, 2, FEARG_2, NULL, + {"test_override", 2, 2, FEARG_2, arg2_string_nr, ret_void, f_test_override}, {"test_refcount", 1, 1, FEARG_1, NULL, ret_number, f_test_refcount}, @@ -1823,15 +1887,15 @@ static funcentry_T global_functions[] = ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, NULL, ret_list_any, f_uniq}, - {"values", 1, 1, FEARG_1, arg1_dict, + {"values", 1, 1, FEARG_1, arg1_dict_any, ret_list_any, f_values}, - {"virtcol", 1, 1, FEARG_1, arg1_string_or_list, + {"virtcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_virtcol}, - {"visualmode", 0, 1, 0, NULL, + {"visualmode", 0, 1, 0, arg1_bool, ret_string, f_visualmode}, {"wildmenumode", 0, 0, 0, NULL, ret_number, f_wildmenumode}, - {"win_execute", 2, 3, FEARG_2, NULL, + {"win_execute", 2, 3, FEARG_2, arg23_win_execute, ret_string, f_win_execute}, {"win_findbuf", 1, 1, FEARG_1, arg1_number, ret_list_number, f_win_findbuf}, @@ -1865,7 +1929,7 @@ static funcentry_T global_functions[] = ret_number, f_winnr}, {"winrestcmd", 0, 0, 0, NULL, ret_string, f_winrestcmd}, - {"winrestview", 1, 1, FEARG_1, arg1_dict, + {"winrestview", 1, 1, FEARG_1, arg1_dict_any, ret_void, f_winrestview}, {"winsaveview", 0, 0, 0, NULL, ret_dict_number, f_winsaveview}, @@ -2413,8 +2477,12 @@ f_changenr(typval_T *argvars UNUSED, typval_T *rettv) static void f_char2nr(typval_T *argvars, typval_T *rettv) { - if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) return; + if (has_mbyte) { int utf8 = 0; @@ -2728,8 +2796,12 @@ f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) static void f_echoraw(typval_T *argvars, typval_T *rettv UNUSED) { - char_u *str = tv_get_string_chk(&argvars[0]); + char_u *str; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + + str = tv_get_string_chk(&argvars[0]); if (str != NULL && *str != NUL) { out_str(str); @@ -5956,12 +6028,19 @@ f_islocked(typval_T *argvars, typval_T *rettv) dictitem_T *di; rettv->vval.v_number = -1; + + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE, GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START); if (end != NULL && lv.ll_name != NULL) { if (*end != NUL) - semsg(_(e_trailing_arg), end); + { + semsg(_(lv.ll_name == lv.ll_name_end + ? e_invarg2 : e_trailing_arg), end); + } else { if (lv.ll_tv == NULL) @@ -6119,6 +6198,12 @@ f_line(typval_T *argvars, typval_T *rettv) win_T *save_curwin; tabpage_T *save_curtab; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) { // use window specified in the second argument @@ -6262,6 +6347,17 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) rettv->vval.v_string = NULL; } + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_LIST + && check_for_string_arg(argvars, 0) == FAIL) + || (check_for_string_arg(argvars, 1) == FAIL) + || (argvars[2].v_type != VAR_UNKNOWN + && (check_for_number_arg(argvars, 2) == FAIL + || (argvars[3].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 3) == FAIL))))) + goto theend; + if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL) @@ -8919,6 +9015,13 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) rettv_list_set(rettv, NULL); + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) lnum = tv_get_lnum(argvars); // -1 on type error col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error @@ -8975,6 +9078,13 @@ f_synstack(typval_T *argvars UNUSED, typval_T *rettv) rettv_list_set(rettv, NULL); + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + #ifdef FEAT_SYN_HL lnum = tv_get_lnum(argvars); // -1 on type error col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error diff --git a/src/evalvars.c b/src/evalvars.c index e0cc73df01..70e51ce8b2 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2662,7 +2662,8 @@ eval_variable( } else if (rettv != NULL) { - if (ht != NULL && ht == get_script_local_ht()) + if (ht != NULL && ht == get_script_local_ht() + && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv) { svar_T *sv = find_typval_in_script(tv); @@ -3202,6 +3203,7 @@ set_var_const( typval_T *tv = tv_arg; typval_T bool_tv; dictitem_T *di; + typval_T *dest_tv = NULL; char_u *varname; hashtab_T *ht; int is_script_local; @@ -3242,182 +3244,215 @@ set_var_const( di = find_var_in_ht(ht, 0, varname, TRUE); - // Search in parent scope which is possible to reference from lambda - if (di == NULL) - di = find_var_in_scoped_ht(name, TRUE); - - if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) - && var_wrong_func_name(name, di == NULL)) - goto failed; - - if (need_convert_to_bool(type, tv)) + if (di == NULL && var_in_vim9script) { - // Destination is a bool and the value is not, but it can be converted. - CLEAR_FIELD(bool_tv); - bool_tv.v_type = VAR_BOOL; - bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE; - tv = &bool_tv; - } + imported_T *import = find_imported(varname, 0, NULL); - if (di != NULL) - { - // Item already exists. Allowed to replace when reloading. - if ((di->di_flags & DI_FLAGS_RELOAD) == 0) + if (import != NULL) { - if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) - && (flags & ASSIGN_FOR_LOOP) == 0) + scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); + svar_T *sv; + + // imported variable from another script + if ((flags & ASSIGN_NO_DECL) == 0) { - emsg(_(e_cannot_mod)); + semsg(_(e_redefining_imported_item_str), name); goto failed; } + sv = ((svar_T *)si->sn_var_vals.ga_data) + + import->imp_var_vals_idx; + // TODO: check the type + // TODO: check for const and locked + dest_tv = sv->sv_tv; + clear_tv(dest_tv); + } + } - if (is_script_local && vim9script + if (dest_tv == NULL) + { + // Search in parent scope which is possible to reference from lambda + if (di == NULL) + di = find_var_in_scoped_ht(name, TRUE); + + if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) + && var_wrong_func_name(name, di == NULL)) + goto failed; + + if (need_convert_to_bool(type, tv)) + { + // Destination is a bool and the value is not, but it can be + // converted. + CLEAR_FIELD(bool_tv); + bool_tv.v_type = VAR_BOOL; + bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE; + tv = &bool_tv; + } + + if (di != NULL) + { + // Item already exists. Allowed to replace when reloading. + if ((di->di_flags & DI_FLAGS_RELOAD) == 0) + { + if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) + && (flags & ASSIGN_FOR_LOOP) == 0) + { + emsg(_(e_cannot_mod)); + goto failed; + } + + if (is_script_local && vim9script && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) + { + semsg(_(e_redefining_script_item_str), name); + goto failed; + } + + if (var_in_vim9script) + { + where_T where; + + // check the type and adjust to bool if needed + where.wt_index = var_idx; + where.wt_variable = TRUE; + if (check_script_var_type(&di->di_tv, tv, name, where) + == FAIL) + goto failed; + } + + if (var_check_permission(di, name) == FAIL) + goto failed; + } + else + { + // can only redefine once + di->di_flags &= ~DI_FLAGS_RELOAD; + + // A Vim9 script-local variable is also present in sn_all_vars + // and sn_var_vals. It may set "type" from "tv". + if (var_in_vim9script) + update_vim9_script_var(FALSE, di, flags, tv, &type, + (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + } + + // existing variable, need to clear the value + + // Handle setting internal di: variables separately where needed to + // prevent changing the type. + if (ht == &vimvarht) + { + if (di->di_tv.v_type == VAR_STRING) + { + VIM_CLEAR(di->di_tv.vval.v_string); + if (copy || tv->v_type != VAR_STRING) + { + char_u *val = tv_get_string(tv); + + // Careful: when assigning to v:errmsg and + // tv_get_string() causes an error message the variable + // will already be set. + if (di->di_tv.vval.v_string == NULL) + di->di_tv.vval.v_string = vim_strsave(val); + } + else + { + // Take over the string to avoid an extra alloc/free. + di->di_tv.vval.v_string = tv->vval.v_string; + tv->vval.v_string = NULL; + } + goto failed; + } + else if (di->di_tv.v_type == VAR_NUMBER) + { + di->di_tv.vval.v_number = tv_get_number(tv); + if (STRCMP(varname, "searchforward") == 0) + set_search_direction(di->di_tv.vval.v_number + ? '/' : '?'); +#ifdef FEAT_SEARCH_EXTRA + else if (STRCMP(varname, "hlsearch") == 0) + { + no_hlsearch = !di->di_tv.vval.v_number; + redraw_all_later(SOME_VALID); + } +#endif + goto failed; + } + else if (di->di_tv.v_type != tv->v_type) + { + semsg(_("E963: setting %s to value with wrong type"), name); + goto failed; + } + } + + clear_tv(&di->di_tv); + } + else + { + // Item not found, check if a function already exists. + if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 + && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) { semsg(_(e_redefining_script_item_str), name); goto failed; } - if (var_in_vim9script) + // add a new variable + if (var_in_vim9script && (flags & ASSIGN_NO_DECL)) { - where_T where; - - // check the type and adjust to bool if needed - where.wt_index = var_idx; - where.wt_variable = TRUE; - if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL) - goto failed; - } - - if (var_check_permission(di, name) == FAIL) - goto failed; - } - else - { - // can only redefine once - di->di_flags &= ~DI_FLAGS_RELOAD; - - // A Vim9 script-local variable is also present in sn_all_vars and - // sn_var_vals. It may set "type" from "tv". - if (var_in_vim9script) - update_vim9_script_var(FALSE, di, flags, tv, &type, - (flags & ASSIGN_NO_MEMBER_TYPE) == 0); - } - - // existing variable, need to clear the value - - // Handle setting internal di: variables separately where needed to - // prevent changing the type. - if (ht == &vimvarht) - { - if (di->di_tv.v_type == VAR_STRING) - { - VIM_CLEAR(di->di_tv.vval.v_string); - if (copy || tv->v_type != VAR_STRING) - { - char_u *val = tv_get_string(tv); - - // Careful: when assigning to v:errmsg and tv_get_string() - // causes an error message the variable will already be set. - if (di->di_tv.vval.v_string == NULL) - di->di_tv.vval.v_string = vim_strsave(val); - } - else - { - // Take over the string to avoid an extra alloc/free. - di->di_tv.vval.v_string = tv->vval.v_string; - tv->vval.v_string = NULL; - } + semsg(_(e_unknown_variable_str), name); goto failed; } - else if (di->di_tv.v_type == VAR_NUMBER) + + // Can't add "v:" or "a:" variable. + if (ht == &vimvarht || ht == get_funccal_args_ht()) { - di->di_tv.vval.v_number = tv_get_number(tv); - if (STRCMP(varname, "searchforward") == 0) - set_search_direction(di->di_tv.vval.v_number ? '/' : '?'); -#ifdef FEAT_SEARCH_EXTRA - else if (STRCMP(varname, "hlsearch") == 0) - { - no_hlsearch = !di->di_tv.vval.v_number; - redraw_all_later(SOME_VALID); - } -#endif + semsg(_(e_illvar), name); goto failed; } - else if (di->di_tv.v_type != tv->v_type) - { - semsg(_("E963: setting %s to value with wrong type"), name); - goto failed; - } - } - clear_tv(&di->di_tv); - } - else - { - // Item not found, check if a function already exists. - if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 - && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) - { - semsg(_(e_redefining_script_item_str), name); - goto failed; - } - - // add a new variable - if (var_in_vim9script && (flags & ASSIGN_NO_DECL)) - { - semsg(_(e_unknown_variable_str), name); - goto failed; - } - - // Can't add "v:" or "a:" variable. - if (ht == &vimvarht || ht == get_funccal_args_ht()) - { - semsg(_(e_illvar), name); - goto failed; - } - - // Make sure the variable name is valid. In Vim9 script an autoload - // variable must be prefixed with "g:". - if (!valid_varname(varname, !vim9script + // Make sure the variable name is valid. In Vim9 script an autoload + // variable must be prefixed with "g:". + if (!valid_varname(varname, !vim9script || STRNCMP(name, "g:", 2) == 0)) - goto failed; + goto failed; - di = alloc(sizeof(dictitem_T) + STRLEN(varname)); - if (di == NULL) - goto failed; - STRCPY(di->di_key, varname); - if (hash_add(ht, DI2HIKEY(di)) == FAIL) - { - vim_free(di); - goto failed; - } - di->di_flags = DI_FLAGS_ALLOC; - if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) - di->di_flags |= DI_FLAGS_LOCK; + di = alloc(sizeof(dictitem_T) + STRLEN(varname)); + if (di == NULL) + goto failed; + STRCPY(di->di_key, varname); + if (hash_add(ht, DI2HIKEY(di)) == FAIL) + { + vim_free(di); + goto failed; + } + di->di_flags = DI_FLAGS_ALLOC; + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) + di->di_flags |= DI_FLAGS_LOCK; - // A Vim9 script-local variable is also added to sn_all_vars and - // sn_var_vals. It may set "type" from "tv". - if (var_in_vim9script) - update_vim9_script_var(TRUE, di, flags, tv, &type, + // A Vim9 script-local variable is also added to sn_all_vars and + // sn_var_vals. It may set "type" from "tv". + if (var_in_vim9script) + update_vim9_script_var(TRUE, di, flags, tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + } + + dest_tv = &di->di_tv; } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) - copy_tv(tv, &di->di_tv); + copy_tv(tv, dest_tv); else { - di->di_tv = *tv; - di->di_tv.v_lock = 0; + *dest_tv = *tv; + dest_tv->v_lock = 0; init_tv(tv); } if (vim9script && type != NULL) { - if (type->tt_type == VAR_DICT && di->di_tv.vval.v_dict != NULL) - di->di_tv.vval.v_dict->dv_type = alloc_type(type); - else if (type->tt_type == VAR_LIST && di->di_tv.vval.v_list != NULL) - di->di_tv.vval.v_list->lv_type = alloc_type(type); + if (type->tt_type == VAR_DICT && dest_tv->vval.v_dict != NULL) + dest_tv->vval.v_dict->dv_type = alloc_type(type); + else if (type->tt_type == VAR_LIST && dest_tv->vval.v_list != NULL) + dest_tv->vval.v_list->lv_type = alloc_type(type); } // ":const var = value" locks the value @@ -3426,8 +3461,9 @@ set_var_const( // Like :lockvar! name: lock the value and what it contains, but only // if the reference count is up to one. That locks only literal // values. - item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); + item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE); return; + failed: if (!copy) clear_tv(tv_arg); diff --git a/src/evalwindow.c b/src/evalwindow.c index 0e1a202da3..329413d0bd 100644 --- a/src/evalwindow.c +++ b/src/evalwindow.c @@ -653,6 +653,12 @@ f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) int nr = 1; tabpage_T *tp; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_string_arg(argvars, 1) == FAIL))) + return; + tp = find_tabpage((int)tv_get_number(&argvars[0])); if (tp == NULL) nr = 0; diff --git a/src/filepath.c b/src/filepath.c index a7774d0d47..ae9bef12c7 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -1447,6 +1447,12 @@ f_pathshorten(typval_T *argvars, typval_T *rettv) char_u *p; int trim_len = 1; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) { trim_len = (int)tv_get_number(&argvars[1]); diff --git a/src/globals.h b/src/globals.h index c99a93a353..8e2ab48b25 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1703,6 +1703,8 @@ EXTERN char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%s\"")); EXTERN char e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\"")); EXTERN char e_stringreq[] INIT(= N_("E928: String required")); +EXTERN char e_numberreq[] INIT(= N_("E889: Number required")); +EXTERN char e_boolreq[] INIT(= N_("E839: Number required")); EXTERN char e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary")); EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required")); EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld")); diff --git a/src/indent.c b/src/indent.c index a26344b7d6..cf07f4af6e 100644 --- a/src/indent.c +++ b/src/indent.c @@ -854,6 +854,7 @@ briopt_check(win_T *wp) int bri_shift = 0; long bri_min = 20; int bri_sbr = FALSE; + int bri_list = 0; p = wp->w_p_briopt; while (*p != NUL) @@ -874,6 +875,11 @@ briopt_check(win_T *wp) p += 3; bri_sbr = TRUE; } + else if (STRNCMP(p, "list:", 5) == 0) + { + p += 5; + bri_list = getdigits(&p); + } if (*p != ',' && *p != NUL) return FAIL; if (*p == ',') @@ -883,6 +889,7 @@ briopt_check(win_T *wp) wp->w_briopt_shift = bri_shift; wp->w_briopt_min = bri_min; wp->w_briopt_sbr = bri_sbr; + wp->w_briopt_list = bri_list; return OK; } @@ -941,9 +948,25 @@ get_breakindent_win( // Add offset for number column, if 'n' is in 'cpoptions' bri += win_col_off2(wp); + // add additional indent for numbered lists + if (wp->w_briopt_list > 0) + { + regmatch_T regmatch; + + regmatch.regprog = vim_regcomp(curbuf->b_p_flp, + RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT); + if (regmatch.regprog != NULL) + { + if (vim_regexec(®match, line, 0)) + bri += wp->w_briopt_list; + vim_regfree(regmatch.regprog); + } + } + // never indent past left window margin if (bri < 0) bri = 0; + // always leave at least bri_min characters on the left, // if text width is sufficient else if (bri > eff_wwidth - wp->w_briopt_min) diff --git a/src/job.c b/src/job.c index fe5e33cd42..ea1db48a72 100644 --- a/src/job.c +++ b/src/job.c @@ -1737,6 +1737,13 @@ f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED) buf_T *buf; char_u *text; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + if (check_secure()) return; buf = tv_get_buf(&argvars[0], FALSE); diff --git a/src/list.c b/src/list.c index d138d868cd..417f735e0d 100644 --- a/src/list.c +++ b/src/list.c @@ -1566,12 +1566,32 @@ list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) vimlist_remove(l, item, item2); if (rettv_list_alloc(rettv) == OK) { - l = rettv->vval.v_list; - l->lv_first = item; - l->lv_u.mat.lv_last = item2; - item->li_prev = NULL; - item2->li_next = NULL; - l->lv_len = cnt; + list_T *rl = rettv->vval.v_list; + + if (l->lv_with_items > 0) + { + // need to copy the list items and move the value + while (item != NULL) + { + li = listitem_alloc(); + if (li == NULL) + return; + li->li_tv = item->li_tv; + init_tv(&item->li_tv); + list_append(rl, li); + if (item == item2) + break; + item = item->li_next; + } + } + else + { + rl->lv_first = item; + rl->lv_u.mat.lv_last = item2; + item->li_prev = NULL; + item2->li_next = NULL; + rl->lv_len = cnt; + } } } } diff --git a/src/message.c b/src/message.c index a78d2dbbb1..283c621833 100644 --- a/src/message.c +++ b/src/message.c @@ -3618,6 +3618,12 @@ verbose_open(void) */ void give_warning(char_u *message, int hl) +{ + give_warning_with_source(message, hl, FALSE); +} + + void +give_warning_with_source(char_u *message, int hl, int with_source) { // Don't do this for ":silent". if (msg_silent != 0) @@ -3634,8 +3640,21 @@ give_warning(char_u *message, int hl) keep_msg_attr = HL_ATTR(HLF_W); else keep_msg_attr = 0; - if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) + + if (with_source) + { + // Do what msg() does, but with a column offset if the warning should + // be after the mode message. + msg_start(); + msg_source(HL_ATTR(HLF_W)); + msg_puts(" "); + msg_puts_attr((char *)message, HL_ATTR(HLF_W) | MSG_HIST); + msg_clr_eos(); + (void)msg_end(); + } + else if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) set_keep_msg(message, keep_msg_attr); + msg_didout = FALSE; // overwrite this message msg_nowait = TRUE; // don't wait for this message msg_col = 0; diff --git a/src/misc1.c b/src/misc1.c index 5bf26b7e7c..79409cdaf7 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -2607,8 +2607,8 @@ path_is_url(char_u *p) } /* - * Check if "fname" starts with "name://". Return URL_SLASH if it does. - * Return URL_BACKSLASH for "name:\\". + * Check if "fname" starts with "name://" or "name:\\". + * Return URL_SLASH for "name://", URL_BACKSLASH for "name:\\". * Return zero otherwise. */ int @@ -2616,7 +2616,22 @@ path_with_url(char_u *fname) { char_u *p; - for (p = fname; isalpha(*p); ++p) + // We accept alphabetic characters and a dash in scheme part. + // RFC 3986 allows for more, but it increases the risk of matching + // non-URL text. + + // first character must be alpha + if (!isalpha(*fname)) + return 0; + + // check body: alpha or dash + for (p = fname; (isalpha(*p) || (*p == '-')); ++p) ; + + // check last char is not a dash + if (p[-1] == '-') + return 0; + + // "://" or ":\\" must follow return path_is_url(p); } diff --git a/src/popupwin.c b/src/popupwin.c index 8751bb4059..0f6166aca1 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2359,13 +2359,21 @@ filter_handle_drag(win_T *wp, int c, typval_T *rettv) void f_popup_filter_menu(typval_T *argvars, typval_T *rettv) { - int id = tv_get_number(&argvars[0]); - win_T *wp = win_id2wp(id); - char_u *key = tv_get_string(&argvars[1]); + int id; + win_T *wp; + char_u *key; typval_T res; int c; linenr_T old_lnum; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + id = tv_get_number(&argvars[0]); + wp = win_id2wp(id); + key = tv_get_string(&argvars[1]); // If the popup has been closed do not consume the key. if (wp == NULL) return; @@ -2416,12 +2424,20 @@ f_popup_filter_menu(typval_T *argvars, typval_T *rettv) void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv) { - int id = tv_get_number(&argvars[0]); - win_T *wp = win_id2wp(id); - char_u *key = tv_get_string(&argvars[1]); + int id; + win_T *wp; + char_u *key; typval_T res; int c; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + id = tv_get_number(&argvars[0]); + wp = win_id2wp(id); + key = tv_get_string(&argvars[1]); // If the popup has been closed don't consume the key. if (wp == NULL) return; @@ -2727,9 +2743,16 @@ close_all_popups(int force) f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) { dict_T *dict; - int id = (int)tv_get_number(argvars); - win_T *wp = find_popup_win(id); + int id; + win_T *wp; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL)) + return; + + id = (int)tv_get_number(argvars); + wp = find_popup_win(id); if (wp == NULL) return; // invalid {id} @@ -2754,10 +2777,17 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED) { dict_T *dict; - int id = (int)tv_get_number(argvars); - win_T *wp = find_popup_win(id); + int id; + win_T *wp; linenr_T old_firstline; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL)) + return; + + id = (int)tv_get_number(argvars); + wp = find_popup_win(id); if (wp == NULL) return; // invalid {id} diff --git a/src/proto/message.pro b/src/proto/message.pro index 16c3354840..d3ec949030 100644 --- a/src/proto/message.pro +++ b/src/proto/message.pro @@ -69,6 +69,7 @@ void verbose_leave_scroll(void); void verbose_stop(void); int verbose_open(void); void give_warning(char_u *message, int hl); +void give_warning_with_source(char_u *message, int hl, int with_source); void give_warning2(char_u *message, char_u *a1, int hl); void msg_advance(int col); int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index f6dd01ebb3..ccde9a6b68 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -11,6 +11,9 @@ varnumber_T tv_get_bool_chk(typval_T *varp, int *denote); float_T tv_get_float(typval_T *varp); int check_for_string_arg(typval_T *args, int idx); int check_for_nonempty_string_arg(typval_T *args, int idx); +int check_for_number_arg(typval_T *args, int idx); +int check_for_bool_arg(typval_T *args, int idx); +int check_for_list_arg(typval_T *args, int idx); int check_for_dict_arg(typval_T *args, int idx); char_u *tv_get_string(typval_T *varp); char_u *tv_get_string_strict(typval_T *varp); diff --git a/src/quickfix.c b/src/quickfix.c index 4ac4a01a10..39424ca680 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3461,6 +3461,7 @@ qf_jump_newwin(qf_info_T *qi, } qfl->qf_index = qf_index; + qfl->qf_ptr = qf_ptr; if (qf_win_pos_update(qi, old_qf_index)) // No need to print the error message if it's visible in the error // window diff --git a/src/sign.c b/src/sign.c index fd373b5c3e..bd8cb6c6b2 100644 --- a/src/sign.c +++ b/src/sign.c @@ -2274,7 +2274,11 @@ f_sign_getdefined(typval_T *argvars, typval_T *rettv) return; if (argvars[0].v_type != VAR_UNKNOWN) + { + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; name = tv_get_string(&argvars[0]); + } sign_getlist(name, rettv->vval.v_list); } diff --git a/src/strings.c b/src/strings.c index 61ffd84fe9..98d420c6aa 100644 --- a/src/strings.c +++ b/src/strings.c @@ -795,9 +795,15 @@ byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) char_u *str; varnumber_T idx; + rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + str = tv_get_string_chk(&argvars[0]); idx = tv_get_number_chk(&argvars[1], NULL); - rettv->vval.v_number = -1; if (str == NULL || idx < 0) return; @@ -896,6 +902,12 @@ f_str2list(typval_T *argvars, typval_T *rettv) if (rettv_list_alloc(rettv) == FAIL) return; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) utf8 = (int)tv_get_bool_chk(&argvars[1], NULL); @@ -981,6 +993,12 @@ f_strgetchar(typval_T *argvars, typval_T *rettv) int byteidx = 0; rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + str = tv_get_string_chk(&argvars[0]); if (str == NULL) return; @@ -1096,6 +1114,12 @@ f_strchars(typval_T *argvars, typval_T *rettv) { varnumber_T skipcc = FALSE; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) skipcc = tv_get_bool(&argvars[1]); if (skipcc < 0 || skipcc > 1) @@ -1110,9 +1134,18 @@ f_strchars(typval_T *argvars, typval_T *rettv) void f_strdisplaywidth(typval_T *argvars, typval_T *rettv) { - char_u *s = tv_get_string(&argvars[0]); + char_u *s; int col = 0; + rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + s = tv_get_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) col = (int)tv_get_number(&argvars[1]); diff --git a/src/structs.h b/src/structs.h index e30c59bd4f..bf6e6af497 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3683,6 +3683,7 @@ struct window_S int w_briopt_min; // minimum width for breakindent int w_briopt_shift; // additional shift for breakindent int w_briopt_sbr; // sbr in 'briopt' + int w_briopt_list; // additional indent for lists #endif // transform a pointer to a "onebuf" option into a "allbuf" option diff --git a/src/tag.c b/src/tag.c index 256f885c82..4e96e0d430 100644 --- a/src/tag.c +++ b/src/tag.c @@ -3312,7 +3312,6 @@ jumpto_tag( int forceit, // :ta with ! int keep_help) // keep help flag (FALSE for cscope) { - int save_secure; optmagic_T save_magic_overruled; int save_p_ws, save_p_scs, save_p_ic; linenr_T save_lnum; @@ -3500,11 +3499,6 @@ jumpto_tag( curwin->w_set_curswant = TRUE; postponed_split = 0; - save_secure = secure; - secure = 1; -#ifdef HAVE_SANDBOX - ++sandbox; -#endif save_magic_overruled = magic_overruled; magic_overruled = OPTION_MAGIC_OFF; // always execute with 'nomagic' #ifdef FEAT_SEARCH_EXTRA @@ -3621,22 +3615,28 @@ jumpto_tag( } else { + int save_secure = secure; + + // Setup the sandbox for executing the command from the tags file. + secure = 1; +#ifdef HAVE_SANDBOX + ++sandbox; +#endif curwin->w_cursor.lnum = 1; // start command in line 1 do_cmdline_cmd(pbuf); retval = OK; + + // When the command has done something that is not allowed make + // sure the error message can be seen. + if (secure == 2) + wait_return(TRUE); + secure = save_secure; +#ifdef HAVE_SANDBOX + --sandbox; +#endif } - /* - * When the command has done something that is not allowed make sure - * the error message can be seen. - */ - if (secure == 2) - wait_return(TRUE); - secure = save_secure; magic_overruled = save_magic_overruled; -#ifdef HAVE_SANDBOX - --sandbox; -#endif #ifdef FEAT_SEARCH_EXTRA // restore no_hlsearch when keeping the old search pattern if (search_options) diff --git a/src/terminal.c b/src/terminal.c index 37659dfab1..c66ba9ba49 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -5694,6 +5694,11 @@ f_term_getattr(typval_T *argvars, typval_T *rettv) {"reverse", HL_INVERSE}, }; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + attr = tv_get_number(&argvars[0]); name = tv_get_string_chk(&argvars[1]); if (name == NULL) @@ -6093,10 +6098,18 @@ f_term_scrape(typval_T *argvars, typval_T *rettv) void f_term_sendkeys(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_sendkeys()"); + buf_T *buf; char_u *msg; term_T *term; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_sendkeys()"); if (buf == NULL) return; @@ -6193,10 +6206,18 @@ f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED) void f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_setapi()"); + buf_T *buf; term_T *term; char_u *api; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setapi()"); if (buf == NULL) return; term = buf->b_term; @@ -6215,10 +6236,18 @@ f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED) f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #if defined(FEAT_SESSION) - buf_T *buf = term_get_buf(argvars, "term_setrestore()"); + buf_T *buf; term_T *term; char_u *cmd; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setrestore()"); if (buf == NULL) return; term = buf->b_term; @@ -6237,10 +6266,18 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED) void f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_setkill()"); + buf_T *buf; term_T *term; char_u *how; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setkill()"); if (buf == NULL) return; term = buf->b_term; @@ -6286,8 +6323,17 @@ f_term_start(typval_T *argvars, typval_T *rettv) void f_term_wait(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_wait()"); + buf_T *buf; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) || + (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + buf = term_get_buf(argvars, "term_wait()"); if (buf == NULL) return; if (buf->b_term->tl_job == NULL) diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim index bb0f6dd4a9..bfca06aec0 100644 --- a/src/testdir/test_breakindent.vim +++ b/src/testdir/test_breakindent.vim @@ -15,6 +15,10 @@ func s:screen_lines(lnum, width) abort return ScreenLines([a:lnum, a:lnum + 2], a:width) endfunc +func s:screen_lines2(lnums, lnume, width) abort + return ScreenLines([a:lnums, a:lnume], a:width) +endfunc + func s:compare_lines(expect, actual) call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) endfunc @@ -708,4 +712,70 @@ func Test_breakindent20_cpo_n_nextpage() call s:close_windows('set breakindent& briopt& cpo& number&') endfunc +func Test_breakindent20_list() + call s:test_windows('setl breakindent breakindentopt= linebreak') + " default: + call setline(1, [' 1. Congress shall make no law', + \ ' 2.) Congress shall make no law', + \ ' 3.] Congress shall make no law']) + norm! 1gg + redraw! + let lines = s:screen_lines2(1, 6, 20) + let expect = [ + \ " 1. Congress ", + \ "shall make no law ", + \ " 2.) Congress ", + \ "shall make no law ", + \ " 3.] Congress ", + \ "shall make no law ", + \ ] + call s:compare_lines(expect, lines) + " set mininum indent + setl briopt=min:5 + redraw! + let lines = s:screen_lines2(1, 6, 20) + let expect = [ + \ " 1. Congress ", + \ " shall make no law ", + \ " 2.) Congress ", + \ " shall make no law ", + \ " 3.] Congress ", + \ " shall make no law ", + \ ] + call s:compare_lines(expect, lines) + " set additional handing indent + setl briopt+=list:4 + redraw! + let expect = [ + \ " 1. Congress ", + \ " shall make no ", + \ " law ", + \ " 2.) Congress ", + \ " shall make no ", + \ " law ", + \ " 3.] Congress ", + \ " shall make no ", + \ " law ", + \ ] + let lines = s:screen_lines2(1, 9, 20) + call s:compare_lines(expect, lines) + " reset linebreak option + " Note: it indents by one additional + " space, because of the leading space. + setl linebreak&vim list listchars=eol:$,space:_ + redraw! + let expect = [ + \ "__1.__Congress_shall", + \ " _make_no_law$ ", + \ "__2.)_Congress_shall", + \ " _make_no_law$ ", + \ "__3.]_Congress_shall", + \ " _make_no_law$ ", + \ ] + let lines = s:screen_lines2(1, 6, 20) + call s:compare_lines(expect, lines) + + call s:close_windows('set breakindent& briopt& linebreak& list& listchars&') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim index 960a760ebd..aa2fe7ac64 100644 --- a/src/testdir/test_buffer.vim +++ b/src/testdir/test_buffer.vim @@ -381,6 +381,35 @@ func Test_balt() call assert_equal('OtherBuffer', bufname()) endfunc +" Test for buffer match URL(scheme) check +" scheme is alpha and inner hyphen only. +func Test_buffer_scheme() + CheckMSWindows + + set noshellslash + %bwipe! + let bufnames = [ + \ #{id: 'b0', name: 'test://xyz/foo/b0' , match: 1}, + \ #{id: 'b1', name: 'test+abc://xyz/foo/b1', match: 0}, + \ #{id: 'b2', name: 'test_abc://xyz/foo/b2', match: 0}, + \ #{id: 'b3', name: 'test-abc://xyz/foo/b3', match: 1}, + \ #{id: 'b4', name: '-test://xyz/foo/b4' , match: 0}, + \ #{id: 'b5', name: 'test-://xyz/foo/b5' , match: 0}, + \] + for buf in bufnames + new `=buf.name` + if buf.match + call assert_equal(buf.name, getbufinfo(buf.id)[0].name) + else + " slashes will have become backslashes + call assert_notequal(buf.name, getbufinfo(buf.id)[0].name) + endif + bwipe + endfor + + set shellslash& +endfunc + " Test for the 'maxmem' and 'maxmemtot' options func Test_buffer_maxmem() " use 1KB per buffer and 2KB for all the buffers diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index a18dfa3d17..883c899cfe 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -162,8 +162,8 @@ func Test_uncrypt_xchacha20_2() call assert_equal(range(1, 4000)->map( {_, v -> string(v)}), getline(1,'$')) set key= w! ++ff=unix - " enryption removed - call assert_match('"Xcrypt_sodium.txt" 4000L, 18893B written', execute(':message')) + " enryption removed (on MS-Windows the .* matches [unix]) + call assert_match('"Xcrypt_sodium.txt".*4000L, 18893B written', execute(':message')) bw! call delete('Xcrypt_sodium.txt') set cryptmethod&vim diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index a4ca5d45ff..e0b0314d39 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -95,6 +95,11 @@ func Test_test_void() call assert_fails('let x = copy([test_void()])', 'E1031:') endfunc +func Test_islocked() + call assert_fails('call islocked(99)', 'E475:') + call assert_fails('call islocked("s: x")', 'E488:') +endfunc + func Test_len() call assert_equal(1, len(0)) call assert_equal(2, len(12)) diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 63acebc6e1..f8dbf8aeda 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -2614,7 +2614,7 @@ func Test_normal40_ctrl_bsl() set noim call assert_equal('are some words', getline(1)) call assert_false(&insertmode) - call assert_beeps("normal! \\", 'xt') + call assert_beeps("normal! \\") if has('cmdwin') " Using CTRL-\ CTRL-N in cmd window should close the window diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index c8e8cd91c2..09f56f81fc 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -941,6 +941,28 @@ func Test_opt_local_to_global() set autoread& endfunc +func Test_set_in_sandbox() + " Some boolean options cannot be set in sandbox, some can. + call assert_fails('sandbox set modelineexpr', 'E48:') + sandbox set number + call assert_true(&number) + set number& + + " Some boolean options cannot be set in sandbox, some can. + if has('python') || has('python3') + call assert_fails('sandbox set pyxversion=3', 'E48:') + endif + sandbox set tabstop=4 + call assert_equal(4, &tabstop) + set tabstop& + + " Some string options cannot be set in sandbox, some can. + call assert_fails('sandbox set backupdir=/tmp', 'E48:') + sandbox set filetype=perl + call assert_equal('perl', &filetype) + set filetype& +endfunc + " Test for incrementing, decrementing and multiplying a number option value func Test_opt_num_op() set shiftwidth=4 @@ -1157,4 +1179,26 @@ func Test_opt_errorbells() set noerrorbells endfunc +func Test_opt_scrolljump() + help + resize 10 + + " Test with positive 'scrolljump'. + set scrolljump=2 + norm! Lj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':3, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + " Test with negative 'scrolljump' (percentage of window height). + set scrolljump=-40 + norm! ggLj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':5, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + set scrolljump& + bw +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index a6a20a8451..e5a6d6cdbc 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -5554,4 +5554,37 @@ func Test_vimgrep_fuzzy_match() call delete('Xfile2') endfunc +func Test_locationlist_open_in_newtab() + call s:create_test_file('Xqftestfile1') + call s:create_test_file('Xqftestfile2') + call s:create_test_file('Xqftestfile3') + + %bwipe! + + lgetexpr ['Xqftestfile1:5:Line5', + \ 'Xqftestfile2:10:Line10', + \ 'Xqftestfile3:16:Line16'] + + silent! llast + call assert_equal(1, tabpagenr('$')) + call assert_equal('Xqftestfile3', bufname()) + + set switchbuf=newtab + + silent! lfirst + call assert_equal(2, tabpagenr('$')) + call assert_equal('Xqftestfile1', bufname()) + + silent! lnext + call assert_equal(3, tabpagenr('$')) + call assert_equal('Xqftestfile2', bufname()) + + call delete('Xqftestfile1') + call delete('Xqftestfile2') + call delete('Xqftestfile3') + set switchbuf&vim + + %bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim index f4ce5de118..c76d7a1684 100644 --- a/src/testdir/test_reltime.vim +++ b/src/testdir/test_reltime.vim @@ -24,8 +24,8 @@ func Test_reltime() call assert_true(reltimefloat(differs) < 0.1) call assert_true(reltimefloat(differs) > 0.0) - call assert_equal(0, reltime({})) - call assert_equal(0, reltime({}, {})) + call assert_equal([], reltime({})) + call assert_equal([], reltime({}, {})) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_set.vim b/src/testdir/test_set.vim index 2b1e9eeee0..7215772a00 100644 --- a/src/testdir/test_set.vim +++ b/src/testdir/test_set.vim @@ -26,4 +26,23 @@ function Test_set_add() let &wig = wig_save endfunction + +" :set, :setlocal, :setglobal without arguments show values of options. +func Test_set_no_arg() + set textwidth=79 + let a = execute('set') + call assert_match("^\n--- Options ---\n.*textwidth=79\\>", a) + set textwidth& + + setlocal textwidth=78 + let a = execute('setlocal') + call assert_match("^\n--- Local option values ---\n.*textwidth=78\\>", a) + setlocal textwidth& + + setglobal textwidth=77 + let a = execute('setglobal') + call assert_match("^\n--- Global option values ---\n.*textwidth=77\\>", a) + setglobal textwidth& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim index c38424f1ee..f0f056f88c 100644 --- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -1,5 +1,7 @@ " Tests for user defined commands +source vim9.vim + " Test for in user defined commands function Test_cmdmods() let g:mods = '' @@ -275,6 +277,24 @@ func Test_CmdErrors() call assert_fails('com! -count=x DoCmd :', 'E178:') call assert_fails('com! -range=x DoCmd :', 'E178:') + com! -complete=file DoCmd : + call assert_match('E1208:', v:warningmsg) + let v:warningmsg = '' + com! -nargs=0 -complete=file DoCmd : + call assert_match('E1208:', v:warningmsg) + + let lines =<< trim END + vim9script + com! -complete=file DoCmd : + END + call CheckScriptFailure(lines, 'E1208', 2) + + let lines =<< trim END + vim9script + com! -nargs=0 -complete=file DoCmd : + END + call CheckScriptFailure(lines, 'E1208', 2) + com! -nargs=0 DoCmd : call assert_fails('DoCmd x', 'E488:') @@ -338,34 +358,30 @@ func Test_CmdCompletion() call feedkeys(":com DoC\\\"\", 'tx') call assert_equal('"com DoC', @:) - com! -complete=behave DoCmd : + com! -nargs=1 -complete=behave DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd mswin xterm', @:) - " This does not work. Why? - "call feedkeys(":DoCmd x\\\"\", 'tx') - "call assert_equal('"DoCmd xterm', @:) - - com! -complete=custom,CustomComplete DoCmd : + com! -nargs=* -complete=custom,CustomComplete DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd January February Mars', @:) - com! -complete=customlist,CustomCompleteList DoCmd : + com! -nargs=? -complete=customlist,CustomCompleteList DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd Monday Tuesday Wednesday', @:) - com! -complete=custom,CustomCompleteList DoCmd : + com! -nargs=+ -complete=custom,CustomCompleteList DoCmd : call assert_fails("call feedkeys(':DoCmd \', 'tx')", 'E730:') - com! -complete=customlist,CustomComp DoCmd : + com! -nargs=+ -complete=customlist,CustomComp DoCmd : call assert_fails("call feedkeys(':DoCmd \', 'tx')", 'E117:') " custom completion without a function - com! -complete=custom, DoCmd + com! -nargs=? -complete=custom, DoCmd call assert_beeps("call feedkeys(':DoCmd \t', 'tx')") " custom completion failure with the wrong function - com! -complete=custom,min DoCmd + com! -nargs=? -complete=custom,min DoCmd call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:') delcom DoCmd @@ -500,21 +516,21 @@ func Test_command_list() \ execute('command DoCmd')) " Test with various -complete= argument values (non-exhaustive list) - command! -complete=arglist DoCmd : + command! -nargs=1 -complete=arglist DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 arglist :", + \ .. "\n DoCmd 1 arglist :", \ execute('command DoCmd')) - command! -complete=augroup DoCmd : + command! -nargs=* -complete=augroup DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 augroup :", + \ .. "\n DoCmd * augroup :", \ execute('command DoCmd')) - command! -complete=custom,CustomComplete DoCmd : + command! -nargs=? -complete=custom,CustomComplete DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 custom :", + \ .. "\n DoCmd ? custom :", \ execute('command DoCmd')) - command! -complete=customlist,CustomComplete DoCmd : + command! -nargs=+ -complete=customlist,CustomComplete DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 customlist :", + \ .. "\n DoCmd + customlist :", \ execute('command DoCmd')) " Test with various -narg= argument values. diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 6bbbc3681e..a33038c9a1 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1632,6 +1632,13 @@ def Test_script_local_in_legacy() let s:legvar = 'one' END CheckScriptFailure(lines, 'E476:', 1) + + edit! Xfile + lines =<< trim END + var edit: bool + legacy edit + END + CheckDefAndScriptSuccess(lines) enddef def Test_var_type_check() @@ -1667,6 +1674,16 @@ def Test_var_type_check() s:d = {} END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d = {a: 1, b: [2]} + def Func(b: bool) + var l: list = b ? d.b : [3] + enddef + defcompile + END + CheckScriptSuccess(lines) enddef let g:dict_number = #{one: 1, two: 2} diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 6b6278b8d0..76987b68a3 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -75,6 +75,41 @@ def Test_abs() endif enddef +def Test_add_blob() + var b1: blob = 0z12 + add(b1, 0x34) + assert_equal(0z1234, b1) + + var b2: blob # defaults to empty blob + add(b2, 0x67) + assert_equal(0z67, b2) + + var lines =<< trim END + var b: blob + add(b, "x") + END + CheckDefFailure(lines, 'E1012:', 2) + + lines =<< trim END + add(test_null_blob(), 123) + END + CheckDefExecAndScriptFailure(lines, 'E1131:', 1) + + lines =<< trim END + var b: blob = test_null_blob() + add(b, 123) + END + CheckDefExecFailure(lines, 'E1131:', 2) + + # Getting variable with NULL blob allocates a new blob at script level + lines =<< trim END + vim9script + var b: blob = test_null_blob() + add(b, 123) + END + CheckScriptSuccess(lines) +enddef + def Test_add_list() var l: list # defaults to empty list add(l, 9) @@ -120,41 +155,6 @@ def Test_add_list() CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 3) enddef -def Test_add_blob() - var b1: blob = 0z12 - add(b1, 0x34) - assert_equal(0z1234, b1) - - var b2: blob # defaults to empty blob - add(b2, 0x67) - assert_equal(0z67, b2) - - var lines =<< trim END - var b: blob - add(b, "x") - END - CheckDefFailure(lines, 'E1012:', 2) - - lines =<< trim END - add(test_null_blob(), 123) - END - CheckDefExecAndScriptFailure(lines, 'E1131:', 1) - - lines =<< trim END - var b: blob = test_null_blob() - add(b, 123) - END - CheckDefExecFailure(lines, 'E1131:', 2) - - # Getting variable with NULL blob allocates a new blob at script level - lines =<< trim END - vim9script - var b: blob = test_null_blob() - add(b, 123) - END - CheckScriptSuccess(lines) -enddef - def Test_and() CheckDefAndScriptFailure2(['and("x", 0x2)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') CheckDefAndScriptFailure2(['and(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number') @@ -171,6 +171,30 @@ def Test_append() append(0, 'zero') assert_equal('zero', getline(1)) + append(0, {a: 10}) + assert_equal("{'a': 10}", getline(1)) + append(0, function('min')) + assert_equal("function('min')", getline(1)) + CheckDefAndScriptFailure2(['append([1], "x")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') + bwipe! +enddef + +def Test_appendbufline() + new + var bnum: number = bufnr() + :wincmd w + appendbufline(bnum, 0, range(3)) + var res1: number = appendbufline(bnum, 1, 'one') + assert_equal(0, res1) + var res2: bool = appendbufline(bnum, 3, 'two') + assert_equal(false, res2) + assert_equal(['0', 'one', '1', 'two', '2', ''], getbufline(bnum, 1, '$')) + appendbufline(bnum, 0, 'zero') + assert_equal(['zero'], getbufline(bnum, 1)) + CheckDefFailure(['appendbufline([1], 1, "x")'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['appendbufline(1, [1], "x")'], 'E1013: Argument 2: type mismatch, expected string but got list') + CheckDefFailure(['appendbufline(1, 1, {"a": 10})'], 'E1013: Argument 3: type mismatch, expected string but got dict') + bnum->bufwinid()->win_gotoid() bwipe! enddef @@ -190,6 +214,10 @@ def Test_argv() CheckDefFailure(['argv("x", "y")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_assert_beeps() + CheckDefAndScriptFailure2(['assert_beeps(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + def Test_assert_equalfile() CheckDefFailure(['assert_equalfile(1, "f2")'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['assert_equalfile("f1", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool') @@ -207,18 +235,29 @@ def Test_assert_match() CheckDefFailure(['assert_match("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special') enddef +def Test_assert_nobeep() + CheckDefAndScriptFailure2(['assert_nobeep(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + def Test_assert_notmatch() CheckDefFailure(['assert_notmatch({}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict') CheckDefFailure(['assert_notmatch("a", 1)'], 'E1013: Argument 2: type mismatch, expected string but got number') CheckDefFailure(['assert_notmatch("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special') enddef +def Test_assert_report() + CheckDefAndScriptFailure2(['assert_report([1, 2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') +enddef + def Test_balloon_show() CheckGui CheckFeature balloon_eval assert_fails('balloon_show(10)', 'E1174:') assert_fails('balloon_show(true)', 'E1174:') + + CheckDefAndScriptFailure2(['balloon_show(1.2)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['balloon_show({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E1174: String required for argument 1') enddef def Test_balloon_split() @@ -321,6 +360,16 @@ def Test_byte2line() assert_equal(-1, byte2line(0)) enddef +def Test_byteidx() + CheckDefAndScriptFailure2(['byteidx(1, 2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['byteidx("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_byteidxcomp() + CheckDefAndScriptFailure2(['byteidxcomp(1, 2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['byteidxcomp("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_call_call() var l = [3, 2, 1] call('reverse', [l]) @@ -348,6 +397,16 @@ def Test_ch_close_in() CheckDefFailure(['ch_close_in(true)'], 'E1013: Argument 1: type mismatch, expected channel but got bool') enddef +def Test_ch_getjob() + if !has('channel') + CheckFeature channel + else + CheckDefAndScriptFailure2(['ch_getjob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument:') + CheckDefAndScriptFailure2(['ch_getjob({"a": 10})'], 'E1013: Argument 1: type mismatch, expected channel but got dict', 'E731: Using a Dictionary as a String') + assert_equal(0, ch_getjob(test_null_channel())) + endif +enddef + def Test_ch_info() if !has('channel') CheckFeature channel @@ -374,10 +433,56 @@ def Test_ch_open() CheckDefAndScriptFailure2(['ch_open("a", [1])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') enddef +def Test_ch_read() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_read(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_read(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_readblob() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_readblob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_readblob(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_readraw() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_readraw(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_readraw(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_setoptions() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_setoptions(1, {})'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefFailure(['ch_setoptions(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list') +enddef + +def Test_ch_status() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_status(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_status(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + def Test_char2nr() char2nr('あ', true)->assert_equal(12354) assert_fails('char2nr(true)', 'E1174:') + CheckDefAndScriptFailure2(['char2nr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['char2nr("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal(97, char2nr('a', 1)) + assert_equal(97, char2nr('a', 0)) + assert_equal(97, char2nr('a', true)) + assert_equal(97, char2nr('a', false)) enddef def Test_charclass() @@ -387,6 +492,13 @@ enddef def Test_charcol() CheckDefFailure(['charcol(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['charcol({a: 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict') + new + setline(1, ['abcdefgh']) + cursor(1, 4) + assert_equal(4, charcol('.')) + assert_equal(9, charcol([1, '$'])) + assert_equal(0, charcol([10, '$'])) + bw! enddef def Test_charidx() @@ -412,8 +524,11 @@ enddef def Test_col() new - setline(1, 'asdf') - col([1, '$'])->assert_equal(5) + setline(1, 'abcdefgh') + cursor(1, 4) + assert_equal(4, col('.')) + col([1, '$'])->assert_equal(9) + assert_equal(0, col([10, '$'])) assert_fails('col(true)', 'E1174:') @@ -423,6 +538,13 @@ def Test_col() bw! enddef +def Test_complete_info() + CheckDefFailure(['complete_info("")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['complete_info({})'], 'E1013: Argument 1: type mismatch, expected list but got dict') + assert_equal({'pum_visible': 0, 'mode': '', 'selected': -1, 'items': []}, complete_info()) + assert_equal({'mode': '', 'items': []}, complete_info(['mode', 'items'])) +enddef + def Test_confirm() if !has('dialog_con') && !has('dialog_gui') CheckFeature dialog_con @@ -433,13 +555,6 @@ def Test_confirm() assert_fails('confirm("yes", "maybe", 2, true)', 'E1174:') enddef -def Test_complete_info() - CheckDefFailure(['complete_info("")'], 'E1013: Argument 1: type mismatch, expected list but got string') - CheckDefFailure(['complete_info({})'], 'E1013: Argument 1: type mismatch, expected list but got dict') - assert_equal({'pum_visible': 0, 'mode': '', 'selected': -1, 'items': []}, complete_info()) - assert_equal({'mode': '', 'items': []}, complete_info(['mode', 'items'])) -enddef - def Test_copy_return_type() var l = copy([1, 2, 3]) var res = 0 @@ -474,7 +589,7 @@ def Test_cursor() var lines =<< trim END cursor('2', 1) END - CheckDefExecAndScriptFailure(lines, 'E475:') + CheckDefExecAndScriptFailure(lines, 'E1209:') enddef def Test_debugbreak() @@ -497,6 +612,16 @@ def Test_diff_filler() assert_equal(0, diff_filler('.')) enddef +def Test_diff_hlID() + CheckDefAndScriptFailure2(['diff_hlID(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['diff_hlID(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_echoraw() + CheckDefAndScriptFailure2(['echoraw(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['echoraw(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') +enddef + def Test_escape() CheckDefFailure(['escape("a", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') CheckDefFailure(['escape(10, " ")'], 'E1013: Argument 1: type mismatch, expected string but got number') @@ -587,25 +712,6 @@ def Test_extend_arg_types() CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') enddef -def Test_extendnew() - assert_equal([1, 2, 'a'], extendnew([1, 2], ['a'])) - assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'})) - - CheckDefFailure(['extendnew({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') - CheckDefFailure(['extendnew({a: 1}, [42])'], 'E1013: Argument 2: type mismatch, expected dict but got list') - CheckDefFailure(['extendnew([1, 2], "x")'], 'E1013: Argument 2: type mismatch, expected list but got string') - CheckDefFailure(['extendnew([1, 2], {x: 1})'], 'E1013: Argument 2: type mismatch, expected list but got dict') -enddef - -def Test_extend_return_type() - var l = extend([1, 2], [3]) - var res = 0 - for n in l - res += n - endfor - res->assert_equal(6) -enddef - func g:ExtendDict(d) call extend(a:d, #{xx: 'x'}) endfunc @@ -656,6 +762,15 @@ def Test_extend_list_item_type() CheckScriptFailure(['vim9script'] + lines, 'E1012:', 1) enddef +def Test_extend_return_type() + var l = extend([1, 2], [3]) + var res = 0 + for n in l + res += n + endfor + res->assert_equal(6) +enddef + def Test_extend_with_error_function() var lines =<< trim END vim9script @@ -676,6 +791,16 @@ def Test_extend_with_error_function() CheckScriptFailure(lines, 'E1001: Variable not found: m') enddef +def Test_extendnew() + assert_equal([1, 2, 'a'], extendnew([1, 2], ['a'])) + assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'})) + + CheckDefFailure(['extendnew({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') + CheckDefFailure(['extendnew({a: 1}, [42])'], 'E1013: Argument 2: type mismatch, expected dict but got list') + CheckDefFailure(['extendnew([1, 2], "x")'], 'E1013: Argument 2: type mismatch, expected list but got string') + CheckDefFailure(['extendnew([1, 2], {x: 1})'], 'E1013: Argument 2: type mismatch, expected list but got dict') +enddef + def Test_feedkeys() CheckDefFailure(['feedkeys(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['feedkeys("x", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') @@ -686,36 +811,6 @@ def Test_feedkeys() unlet g:TestVar enddef -def Test_indent() - CheckDefAndScriptFailure2(['indent([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') - CheckDefAndScriptFailure2(['indent(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1138: Using a Bool as a Number') - assert_equal(0, indent(1)) -enddef - -def Test_input() - CheckDefFailure(['input(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['input(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') - CheckDefFailure(['input("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['input("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E180: Invalid complete value') -enddef - -def Test_inputdialog() - CheckDefFailure(['inputdialog(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['inputdialog(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') - CheckDefFailure(['inputdialog("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') - CheckDefFailure(['inputdialog("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number') -enddef - -def Test_job_info_return_type() - if has('job') - job_start(&shell) - var jobs = job_info() - assert_equal('list', typename(jobs)) - assert_equal('dict', typename(job_info(jobs[0]))) - job_stop(jobs[0]) - endif -enddef - def Test_filereadable() assert_false(filereadable("")) assert_false(filereadable(test_null_string())) @@ -911,6 +1006,8 @@ enddef def Test_garbagecollect() garbagecollect(true) + CheckDefAndScriptFailure2(['garbagecollect("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') + CheckDefAndScriptFailure2(['garbagecollect(20)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') enddef def Test_getbufinfo() @@ -950,6 +1047,19 @@ def Test_getchar() while getchar(0) endwhile getchar(true)->assert_equal(0) + getchar(1)->assert_equal(0) + CheckDefAndScriptFailure2(['getchar(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') + CheckDefAndScriptFailure2(['getchar("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') +enddef + +def Test_getcharpos() + CheckDefAndScriptFailure2(['getcharpos(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['getcharpos(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + +def Test_getcharstr() + CheckDefAndScriptFailure2(['getcharstr(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') + CheckDefAndScriptFailure2(['getcharstr("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') enddef def Test_getenv() @@ -986,14 +1096,6 @@ def Test_getcwd() CheckDefFailure(['getcwd(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef -def Test_getloclist_return_type() - var l = getloclist(1) - l->assert_equal([]) - - var d = getloclist(1, {items: 0}) - d->assert_equal({items: []}) -enddef - def Test_getfontname() CheckDefFailure(['getfontname(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') enddef @@ -1036,6 +1138,38 @@ def Test_getjumplist() CheckDefFailure(['getjumplist(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_getline() + var lines =<< trim END + new + setline(1, ['hello', 'there', 'again']) + assert_equal('hello', getline(1)) + assert_equal('hello', getline('.')) + + normal 2Gvjv + assert_equal('there', getline("'<")) + assert_equal('again', getline("'>")) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + echo getline('1') + END + CheckDefExecAndScriptFailure(lines, 'E1209:') +enddef + +def Test_getloclist() + CheckDefAndScriptFailure2(['getloclist("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['getloclist(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_getloclist_return_type() + var l = getloclist(1) + l->assert_equal([]) + + var d = getloclist(1, {items: 0}) + d->assert_equal({items: []}) +enddef + def Test_getmarklist() CheckDefFailure(['getmarklist([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal([], getmarklist(10000)) @@ -1049,7 +1183,7 @@ enddef def Test_getpos() CheckDefFailure(['getpos(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal([0, 1, 1, 0], getpos('.')) - assert_equal([0, 0, 0, 0], getpos('a')) + CheckDefExecFailure(['getpos("a")'], 'E1209:') enddef def Test_getqflist() @@ -1131,6 +1265,12 @@ def Test_has() enddef def Test_has_key() + var d = {123: 'xx'} + assert_true(has_key(d, '123')) + assert_true(has_key(d, 123)) + assert_false(has_key(d, 'x')) + assert_false(has_key(d, 99)) + CheckDefAndScriptFailure2(['has_key([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') CheckDefAndScriptFailure2(['has_key({"a": 10}, ["a"])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef @@ -1155,6 +1295,11 @@ def Test_histadd() assert_equal('skyblue', histget('/', -1)) enddef +def Test_histget() + CheckDefAndScriptFailure2(['histget(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['histget("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_histnr() CheckDefFailure(['histnr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal(-1, histnr('abc')) @@ -1177,10 +1322,30 @@ def Test_iconv() assert_equal('abc', iconv('abc', 'fromenc', 'toenc')) enddef +def Test_indent() + CheckDefAndScriptFailure2(['indent([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') + CheckDefAndScriptFailure2(['indent(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1138: Using a Bool as a Number') + assert_equal(0, indent(1)) +enddef + def Test_index() index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef +def Test_input() + CheckDefFailure(['input(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['input(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + CheckDefFailure(['input("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['input("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E180: Invalid complete value') +enddef + +def Test_inputdialog() + CheckDefFailure(['inputdialog(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['inputdialog(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + CheckDefFailure(['inputdialog("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefFailure(['inputdialog("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number') +enddef + def Test_inputlist() CheckDefFailure(['inputlist(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') CheckDefFailure(['inputlist("abc")'], 'E1013: Argument 1: type mismatch, expected list but got string') @@ -1247,12 +1412,61 @@ def Test_isdirectory() assert_false(isdirectory('NonExistingDir')) enddef +def Test_islocked() + CheckDefAndScriptFailure2(['islocked(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['var n1: number = 10', 'islocked(n1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + g:v1 = 10 + assert_false(islocked('g:v1')) + lockvar g:v1 + assert_true(islocked('g:v1')) + unlet g:v1 +enddef + def Test_items() CheckDefFailure(['[]->items()'], 'E1013: Argument 1: type mismatch, expected dict but got list') assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items()) assert_equal([], {}->items()) enddef +def Test_job_getchannel() + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_getchannel("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_getchannel(test_null_job())', 'E916: not a valid job') + endif +enddef + +def Test_job_info() + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_info("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_info(test_null_job())', 'E916: not a valid job') + endif +enddef + +def Test_job_info_return_type() + if !has('job') + CheckFeature job + else + job_start(&shell) + var jobs = job_info() + assert_equal('list', typename(jobs)) + assert_equal('dict', typename(job_info(jobs[0]))) + job_stop(jobs[0]) + endif +enddef + +def Test_job_status() + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_status("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_equal('fail', job_status(test_null_job())) + endif +enddef + def Test_js_decode() CheckDefFailure(['js_decode(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal([1, 2], js_decode('[1,2]')) @@ -1276,6 +1490,8 @@ enddef def Test_line() assert_fails('line(true)', 'E1174:') + CheckDefAndScriptFailure2(['line(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['line(".", "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') enddef def Test_line2byte() @@ -1412,6 +1628,21 @@ def Test_map_failure() delete('Xtmpfile') enddef +def Test_match() + CheckDefAndScriptFailure2(['match(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['match(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['match("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['match("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(2, match('ab12cd', '12')) + assert_equal(-1, match('ab12cd', '34')) + assert_equal(6, match('ab12cd12ef', '12', 4)) + assert_equal(2, match('abcd', '..', 0, 3)) + assert_equal(1, match(['a', 'b', 'c'], 'b')) + assert_equal(-1, match(['a', 'b', 'c'], 'd')) + assert_equal(3, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(5, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + def Test_matcharg() CheckDefFailure(['matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef @@ -1422,6 +1653,71 @@ def Test_matchdelete() CheckDefFailure(['matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_matchend() + CheckDefAndScriptFailure2(['matchend(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchend(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchend("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchend("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(4, matchend('ab12cd', '12')) + assert_equal(-1, matchend('ab12cd', '34')) + assert_equal(8, matchend('ab12cd12ef', '12', 4)) + assert_equal(4, matchend('abcd', '..', 0, 3)) + assert_equal(1, matchend(['a', 'b', 'c'], 'b')) + assert_equal(-1, matchend(['a', 'b', 'c'], 'd')) + assert_equal(3, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(5, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchlist() + CheckDefAndScriptFailure2(['matchlist(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchlist(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchlist("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchlist("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + var l: list = ['12', '', '', '', '', '', '', '', '', ''] + assert_equal(l, matchlist('ab12cd', '12')) + assert_equal([], matchlist('ab12cd', '34')) + assert_equal(l, matchlist('ab12cd12ef', '12', 4)) + l[0] = 'cd' + assert_equal(l, matchlist('abcd', '..', 0, 3)) + l[0] = 'b' + assert_equal(l, matchlist(['a', 'b', 'c'], 'b')) + assert_equal([], matchlist(['a', 'b', 'c'], 'd')) + assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchstr() + CheckDefAndScriptFailure2(['matchstr(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchstr(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchstr("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchstr("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal('12', matchstr('ab12cd', '12')) + assert_equal('', matchstr('ab12cd', '34')) + assert_equal('12', matchstr('ab12cd12ef', '12', 4)) + assert_equal('cd', matchstr('abcd', '..', 0, 3)) + assert_equal('b', matchstr(['a', 'b', 'c'], 'b')) + assert_equal('', matchstr(['a', 'b', 'c'], 'd')) + assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchstrpos() + CheckDefAndScriptFailure2(['matchstrpos(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchstrpos(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchstrpos("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchstrpos("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(['12', 2, 4], matchstrpos('ab12cd', '12')) + assert_equal(['', -1, -1], matchstrpos('ab12cd', '34')) + assert_equal(['12', 6, 8], matchstrpos('ab12cd12ef', '12', 4)) + assert_equal(['cd', 2, 4], matchstrpos('abcd', '..', 0, 3)) + assert_equal(['b', 1, 0, 1], matchstrpos(['a', 'b', 'c'], 'b')) + assert_equal(['', -1, -1, -1], matchstrpos(['a', 'b', 'c'], 'd')) + assert_equal(['b', 3, 0, 1], + matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(['b', 5, 0, 1], + matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + def Test_max() g:flag = true var l1: list = g:flag @@ -1434,6 +1730,7 @@ def Test_max() ? [1, max([2, 3])] : [4, 5] assert_equal([4, 5], l2) + CheckDefAndScriptFailure2(['max(5)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E712: Argument of max() must be a List or Dictionary') enddef def Test_menu_info() @@ -1455,6 +1752,7 @@ def Test_min() ? [1, min([2, 3])] : [4, 5] assert_equal([4, 5], l2) + CheckDefAndScriptFailure2(['min(5)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E712: Argument of min() must be a List or Dictionary') enddef def Test_mkdir() @@ -1464,6 +1762,18 @@ def Test_mkdir() delete('a', 'rf') enddef +def Test_mode() + CheckDefFailure(['mode("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string') + CheckDefFailure(['mode(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number') +enddef + +def Test_mzeval() + if !has('mzscheme') + CheckFeature mzscheme + endif + CheckDefAndScriptFailure2(['mzeval(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_nextnonblank() CheckDefFailure(['nextnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') assert_equal(0, nextnonblank(1)) @@ -1478,29 +1788,140 @@ def Test_or() CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_pathshorten() + CheckDefAndScriptFailure2(['pathshorten(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['pathshorten("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_perleval() + if !has('perl') + CheckFeature perl + endif + CheckDefAndScriptFailure2(['perleval(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + +def Test_popup_atcursor() + CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') + + # Pass variable of type 'any' to popup_atcursor() + var what: any = 'Hello' + var popupID = what->popup_atcursor({moved: 'any'}) + assert_equal(0, popupID->popup_getoptions().tabpage) + popupID->popup_close() +enddef + +def Test_popup_beval() + CheckDefAndScriptFailure2(['popup_beval({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_clear() + CheckDefAndScriptFailure2(['popup_clear(["a"])'], 'E1013: Argument 1: type mismatch, expected bool but got list', 'E745: Using a List as a Number') + CheckDefAndScriptFailure2(['popup_clear(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') +enddef + +def Test_popup_create() + # Pass variable of type 'any' to popup_create() + var what: any = 'Hello' + var popupID = what->popup_create({}) + assert_equal(0, popupID->popup_getoptions().tabpage) + popupID->popup_close() +enddef + +def Test_popup_dialog() + CheckDefAndScriptFailure2(['popup_dialog({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_filter_menu() + CheckDefAndScriptFailure2(['popup_filter_menu("x", "")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_filter_menu(1, 1)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + +def Test_popup_filter_yesno() + CheckDefAndScriptFailure2(['popup_filter_yesno("x", "")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_filter_yesno(1, 1)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + +def Test_popup_getoptions() + CheckDefAndScriptFailure2(['popup_getoptions("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_getoptions(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + +def Test_popup_getpos() + CheckDefAndScriptFailure2(['popup_getpos("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_getpos(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + +def Test_popup_hide() + CheckDefAndScriptFailure2(['popup_hide("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_hide(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + def Test_popup_locate() CheckDefAndScriptFailure2(['popup_locate("a", 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number') enddef +def Test_popup_menu() + CheckDefAndScriptFailure2(['popup_menu({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_menu("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_move() + CheckDefAndScriptFailure2(['popup_move("x", {})'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_move(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + +def Test_popup_notification() + CheckDefAndScriptFailure2(['popup_notification({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_notification("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_setoptions() + CheckDefAndScriptFailure2(['popup_setoptions("x", {})'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_setoptions(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + +def Test_popup_show() + CheckDefAndScriptFailure2(['popup_show("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_show(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + def Test_prevnonblank() CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') assert_equal(0, prevnonblank(1)) enddef def Test_prompt_getprompt() - if has('channel') + if !has('channel') + CheckFeature channel + else CheckDefFailure(['prompt_getprompt([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal('', prompt_getprompt('NonExistingBuf')) endif enddef +def Test_prompt_setprompt() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['prompt_setprompt([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['prompt_setprompt(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + def Test_prop_find() CheckDefAndScriptFailure2(['prop_find([1, 2])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') CheckDefAndScriptFailure2(['prop_find([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') CheckDefAndScriptFailure2(['prop_find({"a": 10}, ["a"])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef +def Test_prop_list() + CheckDefAndScriptFailure2(['prop_list("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['prop_list(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + def Test_prop_type_add() CheckDefAndScriptFailure2(['prop_type_add({"a": 10}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E731: Using a Dictionary as a String') CheckDefAndScriptFailure2(['prop_type_add("a", "b")'], 'E1013: Argument 2: type mismatch, expected dict but got string', 'E715: Dictionary required') @@ -1523,6 +1944,32 @@ def Test_prop_type_get() CheckDefAndScriptFailure2(['prop_type_get("a", "b")'], 'E1013: Argument 2: type mismatch, expected dict but got string', 'E715: Dictionary required') enddef +def Test_prop_type_list() + CheckDefAndScriptFailure2(['prop_type_list(["a"])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') + CheckDefAndScriptFailure2(['prop_type_list(2)'], 'E1013: Argument 1: type mismatch, expected dict but got number', 'E715: Dictionary required') +enddef + +def Test_py3eval() + if !has('python3') + CheckFeature python3 + endif + CheckDefAndScriptFailure2(['py3eval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + +def Test_pyeval() + if !has('python') + CheckFeature python + endif + CheckDefAndScriptFailure2(['pyeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + +def Test_pyxeval() + if !has('python') && !has('python3') + CheckFeature python + endif + CheckDefAndScriptFailure2(['pyxeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_rand() CheckDefFailure(['rand(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') CheckDefFailure(['rand(["a"])'], 'E1013: Argument 1: type mismatch, expected list but got list') @@ -1571,6 +2018,11 @@ def Test_readfile() enddef def Test_reltime() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltime()'], 'E474:') + CheckDefExecAndScriptFailure(['[]->reltime([])'], 'E474:') + CheckDefFailure(['reltime("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') CheckDefFailure(['reltime(["x", "y"])'], 'E1013: Argument 1: type mismatch, expected list but got list') CheckDefFailure(['reltime([1, 2], 10)'], 'E1013: Argument 2: type mismatch, expected list but got number') @@ -1582,12 +2034,20 @@ def Test_reltime() enddef def Test_reltimefloat() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltimefloat()'], 'E474:') + CheckDefFailure(['reltimefloat("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') CheckDefFailure(['reltimefloat([1.1])'], 'E1013: Argument 1: type mismatch, expected list but got list') assert_true(type(reltimefloat(reltime())) == v:t_float) enddef def Test_reltimestr() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltimestr()'], 'E474:') + CheckDefFailure(['reltimestr(true)'], 'E1013: Argument 1: type mismatch, expected list but got bool') CheckDefFailure(['reltimestr([true])'], 'E1013: Argument 1: type mismatch, expected list but got list') assert_true(type(reltimestr(reltime())) == v:t_string) @@ -1610,12 +2070,25 @@ def Test_remote_peek() CheckDefAndScriptFailure2(['remote_peek("a5b6c7", [1])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E573: Invalid server id used') enddef +def Test_remote_read() + CheckFeature clientserver + CheckEnv DISPLAY + CheckDefAndScriptFailure2(['remote_read(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['remote_read("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_remote_startserver() CheckFeature clientserver CheckEnv DISPLAY CheckDefFailure(['remote_startserver({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') enddef +def Test_remove_const_list() + var l: list = [1, 2, 3, 4] + assert_equal([1, 2], remove(l, 0, 1)) + assert_equal([3, 4], l) +enddef + def Test_remove_return_type() var l = remove({one: [1, 2], two: [3, 4]}, 'one') var res = 0 @@ -1649,6 +2122,13 @@ def Test_reverse_return_type() res->assert_equal(6) enddef +def Test_rubyeval() + if !has('ruby') + CheckFeature ruby + endif + CheckDefAndScriptFailure2(['rubyeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_screenattr() CheckDefFailure(['screenattr("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['screenattr(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') @@ -1719,6 +2199,7 @@ def Test_searchcount() maxcount: 99, incomplete: 0}) bwipe! + CheckDefAndScriptFailure2(['searchcount([1])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef def Test_searchpair() @@ -1862,6 +2343,41 @@ def Test_setfperm() CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob') enddef +def Test_setbufline() + new + var bnum = bufnr('%') + :wincmd w + setbufline(bnum, 1, range(1, 3)) + setbufline(bnum, 4, 'one') + setbufline(bnum, 5, 10) + setbufline(bnum, 6, ['two', 11]) + assert_equal(['1', '2', '3', 'one', '10', 'two', '11'], getbufline(bnum, 1, '$')) + CheckDefFailure(['setbufline([1], 1, "x")'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['setbufline(1, [1], "x")'], 'E1013: Argument 2: type mismatch, expected string but got list') + CheckDefFailure(['setbufline(1, 1, {"a": 10})'], 'E1013: Argument 3: type mismatch, expected string but got dict') + bnum->bufwinid()->win_gotoid() + bw! +enddef + +def Test_setcellwidths() + CheckDefAndScriptFailure2(['setcellwidths(1)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E714: List required') + CheckDefAndScriptFailure2(['setcellwidths({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + +def Test_setline() + new + setline(1, range(1, 4)) + assert_equal(['1', '2', '3', '4'], getline(1, '$')) + setline(1, ['a', 'b', 'c', 'd']) + assert_equal(['a', 'b', 'c', 'd'], getline(1, '$')) + setline(1, 'one') + assert_equal(['one', 'b', 'c', 'd'], getline(1, '$')) + setline(1, 10) + assert_equal(['10', 'b', 'c', 'd'], getline(1, '$')) + CheckDefAndScriptFailure2(['setline([1], "x")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') + bw! +enddef + def Test_setloclist() var items = [{filename: '/tmp/file', lnum: 1, valid: true}] var what = {items: items} @@ -1893,6 +2409,16 @@ def Test_sign_define() CheckDefAndScriptFailure2(['sign_define("a", ["b"])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_sign_getdefined() + CheckDefAndScriptFailure2(['sign_getdefined(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['sign_getdefined(2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + +def Test_sign_placelist() + CheckDefAndScriptFailure2(['sign_placelist("x")'], 'E1013: Argument 1: type mismatch, expected list but got string', 'E714: List required') + CheckDefAndScriptFailure2(['sign_placelist({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + def Test_sign_undefine() CheckDefAndScriptFailure2(['sign_undefine({})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E731: Using a Dictionary as a String') CheckDefAndScriptFailure2(['sign_undefine([1])'], 'E1013: Argument 1: type mismatch, expected list but got list', 'E155: Unknown sign:') @@ -1904,6 +2430,11 @@ def Test_sign_unplace() CheckDefAndScriptFailure2(['sign_unplace("a", ["b"])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_sign_unplacelist() + CheckDefAndScriptFailure2(['sign_unplacelist("x")'], 'E1013: Argument 1: type mismatch, expected list but got string', 'E714: List required') + CheckDefAndScriptFailure2(['sign_unplacelist({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + def Test_simplify() CheckDefFailure(['simplify(100)'], 'E1013: Argument 1: type mismatch, expected string but got number') call assert_equal('NonExistingFile', simplify('NonExistingFile')) @@ -1934,7 +2465,7 @@ enddef def Test_spellsuggest() if !has('spell') - MissingFeature 'spell' + CheckFeature spell else spellsuggest('marrch', 1, true)->assert_equal(['March']) endif @@ -1991,7 +2522,7 @@ enddef def Run_str2float() if !has('float') - MissingFeature 'float' + CheckFeature float endif str2float("1.00")->assert_equal(1.00) str2float("2e-2")->assert_equal(0.02) @@ -2001,6 +2532,14 @@ def Run_str2float() endif enddef +def Test_str2list() + CheckDefAndScriptFailure2(['str2list(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['str2list("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal([97], str2list('a')) + assert_equal([97], str2list('a', 1)) + assert_equal([97], str2list('a', true)) +enddef + def Test_str2nr() str2nr("1'000'000", 10, true)->assert_equal(1000000) @@ -2012,8 +2551,34 @@ def Test_str2nr() CheckScriptFailure(['vim9script', 'echo str2nr("123", 10, "x")'], 'E1135:') enddef +def Test_strcharlen() + CheckDefAndScriptFailure2(['strcharlen([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + "abc"->strcharlen()->assert_equal(3) + strcharlen(99)->assert_equal(2) +enddef + def Test_strchars() strchars("A\u20dd", true)->assert_equal(1) + CheckDefAndScriptFailure2(['strchars(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strchars("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal(3, strchars('abc')) + assert_equal(3, strchars('abc', 1)) + assert_equal(3, strchars('abc', true)) +enddef + +def Test_strdisplaywidth() + CheckDefAndScriptFailure2(['strdisplaywidth(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strdisplaywidth("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_strftime() + CheckDefAndScriptFailure2(['strftime(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strftime("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_strgetchar() + CheckDefAndScriptFailure2(['strgetchar(1, 1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strgetchar("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') enddef def Test_stridx() @@ -2094,6 +2659,16 @@ def Test_synIDtrans() CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_synconcealed() + CheckDefAndScriptFailure2(['synconcealed(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['synconcealed(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_synstack() + CheckDefAndScriptFailure2(['synstack(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['synstack(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_tabpagebuflist() CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string') assert_equal([bufnr('')], tabpagebuflist()) @@ -2106,6 +2681,11 @@ def Test_tabpagenr() assert_equal(1, tabpagenr()) enddef +def Test_tabpagewinnr() + CheckDefAndScriptFailure2(['tabpagewinnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['tabpagewinnr(1, 2)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + def Test_taglist() CheckDefAndScriptFailure2(['taglist([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') CheckDefAndScriptFailure2(['taglist("a", [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') @@ -2125,9 +2705,16 @@ enddef def Test_term_getansicolors() CheckRunVimInTerminal + CheckFeature termguicolors CheckDefAndScriptFailure2(['term_getansicolors(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') enddef +def Test_term_getattr() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_getattr("x", "a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['term_getattr(1, 2)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + def Test_term_getcursor() CheckRunVimInTerminal CheckDefAndScriptFailure2(['term_getcursor({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E728: Using a Dictionary as a Number') @@ -2160,7 +2747,7 @@ enddef def Test_term_gettty() if !has('terminal') - MissingFeature 'terminal' + CheckFeature terminal else var buf = Run_shell_in_terminal({}) term_gettty(buf, true)->assert_notequal('') @@ -2168,9 +2755,32 @@ def Test_term_gettty() endif enddef +def Test_term_sendkeys() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_sendkeys([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_sendkeys(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setapi() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setapi([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setapi(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setkill() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setkill([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setkill(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setrestore() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setrestore([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setrestore(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef def Test_term_start() if !has('terminal') - MissingFeature 'terminal' + CheckFeature terminal else botright new var winnr = winnr() @@ -2180,6 +2790,12 @@ def Test_term_start() endif enddef +def Test_term_wait() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_wait(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_wait(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_test_alloc_fail() CheckDefAndScriptFailure2(['test_alloc_fail("a", 10, 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument') CheckDefAndScriptFailure2(['test_alloc_fail(10, "b", 20)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument') @@ -2204,6 +2820,11 @@ def Test_test_option_not_set() CheckDefAndScriptFailure2(['test_option_not_set([])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E474: Invalid argument') enddef +def Test_test_override() + CheckDefAndScriptFailure2(['test_override(1, 1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['test_override("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_test_setmouse() CheckDefAndScriptFailure2(['test_setmouse("a", 10)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument') CheckDefAndScriptFailure2(['test_setmouse(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument') @@ -2276,10 +2897,25 @@ enddef def Test_virtcol() CheckDefAndScriptFailure2(['virtcol(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1') + new + setline(1, ['abcdefgh']) + cursor(1, 4) + assert_equal(4, virtcol('.')) + assert_equal(4, virtcol([1, 4])) + assert_equal(9, virtcol([1, '$'])) + assert_equal(0, virtcol([10, '$'])) + bw! +enddef + +def Test_visualmode() + CheckDefFailure(['visualmode("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string') + CheckDefFailure(['visualmode(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number') enddef def Test_win_execute() assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()')) + assert_equal("\n" .. winnr(), 'echo winnr()'->win_execute(win_getid())) + assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()', 'silent')) assert_equal('', win_execute(342343, 'echo winnr()')) enddef @@ -2295,12 +2931,44 @@ def Test_win_getid() assert_equal(win_getid(), win_getid(1, 1)) enddef +def Test_win_gettype() + CheckDefAndScriptFailure2(['win_gettype("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_gotoid() + CheckDefAndScriptFailure2(['win_gotoid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_id2tabwin() + CheckDefAndScriptFailure2(['win_id2tabwin("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_id2win() + CheckDefAndScriptFailure2(['win_id2win("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_screenpos() + CheckDefAndScriptFailure2(['win_screenpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + def Test_win_splitmove() split win_splitmove(1, 2, {vertical: true, rightbelow: true}) close enddef +def Test_winbufnr() + CheckDefAndScriptFailure2(['winbufnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_winheight() + CheckDefAndScriptFailure2(['winheight("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_winlayout() + CheckDefAndScriptFailure2(['winlayout("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + def Test_winnr() CheckDefFailure(['winnr([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal(1, winnr()) @@ -2333,38 +3001,6 @@ def Test_winsaveview() CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected list but got dict', 1) enddef -def Test_win_gettype() - CheckDefAndScriptFailure2(['win_gettype("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_gotoid() - CheckDefAndScriptFailure2(['win_gotoid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_id2tabwin() - CheckDefAndScriptFailure2(['win_id2tabwin("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_id2win() - CheckDefAndScriptFailure2(['win_id2win("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_screenpos() - CheckDefAndScriptFailure2(['win_screenpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winbufnr() - CheckDefAndScriptFailure2(['winbufnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winheight() - CheckDefAndScriptFailure2(['winheight("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winlayout() - CheckDefAndScriptFailure2(['winlayout("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - def Test_winwidth() CheckDefAndScriptFailure2(['winwidth("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') enddef diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 79a4ea36e5..e7c08f4af0 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -401,6 +401,13 @@ def Test_expr2_fails() # comment END CheckScriptFailure(lines, 'E1004: White space required before and after ''||'' at "||true"', 3) + + lines =<< trim END + var x = false + || false + || a.b + END + CheckDefFailure(lines, 'E1001:', 3) enddef " test && @@ -653,13 +660,36 @@ def Test_expr4_equal() CheckDefExecAndScriptFailure(["var x: any = true", 'echo x == ""'], 'E1072: Cannot compare bool with string', 2) CheckDefExecAndScriptFailure2(["var x: any = 99", 'echo x == true'], 'E1138', 'E1072:', 2) CheckDefExecAndScriptFailure2(["var x: any = 'a'", 'echo x == 99'], 'E1030:', 'E1072:', 2) +enddef +def Test_expr4_wrong_type() for op in ['>', '>=', '<', '<=', '=~', '!~'] CheckDefExecAndScriptFailure([ "var a: any = 'a'", 'var b: any = true', 'echo a ' .. op .. ' b'], 'E1072:', 3) endfor + for op in ['>', '>=', '<', '<='] + CheckDefExecAndScriptFailure2([ + "var n: any = 2", + 'echo n ' .. op .. ' "3"'], 'E1030:', 'E1072:', 2) + endfor + for op in ['=~', '!~'] + CheckDefExecAndScriptFailure([ + "var n: any = 2", + 'echo n ' .. op .. ' "3"'], 'E1072:', 2) + endfor + + CheckDefAndScriptFailure([ + 'echo v:none == true'], 'E1072:', 1) + CheckDefAndScriptFailure([ + 'echo false >= true'], 'E1072:', 1) + CheckDefExecAndScriptFailure([ + "var n: any = v:none", + 'echo n == true'], 'E1072:', 2) + CheckDefExecAndScriptFailure([ + "var n: any = v:none", + 'echo n < true'], 'E1072:', 2) enddef " test != comperator @@ -2075,7 +2105,8 @@ def Test_expr7_lambda_block() var Func = (nr: number): int => { return nr END - CheckDefAndScriptFailure(lines, 'E1171', 1) # line nr is function start + CheckDefFailure(lines, 'E1171', 0) # line nr is function start + CheckScriptFailure(['vim9script'] + lines, 'E1171', 2) lines =<< trim END var Func = (nr: number): int => { @@ -2478,6 +2509,13 @@ def Test_expr7_dict_vim9script() else CheckDefAndScriptFailure(lines, 'E117:', 0) endif + + lines =<< trim END + vim9script + var x = 99 + assert_equal({x: 99}, s:) + END + CheckScriptSuccess(lines) enddef def Test_expr7_call_2bool() @@ -2975,7 +3013,7 @@ def Test_expr7_method_call() enddef RetVoid()->byteidx(3) END - CheckDefExecAndScriptFailure(lines, 'E1031:') + CheckDefExecFailure(lines, 'E1013:') enddef diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 08e68d147c..a2c4e7daed 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2255,6 +2255,32 @@ def Test_nested_inline_lambda() assert_equal('--there', F('unused')('there')('--')) END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + echo range(4)->mapnew((_, v) => { + return range(v) ->mapnew((_, s) => { + return string(s) + }) + }) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + def s:func() + range(10) + ->mapnew((_, _) => ({ + key: range(10)->mapnew((_, _) => { + return ' ' + }), + })) + enddef + + defcomp + END + CheckScriptSuccess(lines) enddef def Shadowed(): list diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index b21b63cbe0..203c5c905a 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1062,6 +1062,12 @@ let s:export_script_lines =<< trim END export def Exported(): string return 'Exported' enddef + export def ExportedValue(): number + return exported + enddef + export def ExportedInc() + exported += 5 + enddef export final theList = [1] END @@ -1073,10 +1079,21 @@ enddef def Test_vim9_import_export() var import_script_lines =<< trim END vim9script - import {exported, Exported} from './Xexport.vim' - g:imported = exported + import {exported, Exported, ExportedValue} from './Xexport.vim' + g:exported1 = exported exported += 3 - g:imported_added = exported + g:exported2 = exported + g:exported3 = ExportedValue() + + import ExportedInc from './Xexport.vim' + ExportedInc() + g:exported_i1 = exported + g:exported_i2 = ExportedValue() + + exported = 11 + g:exported_s1 = exported + g:exported_s2 = ExportedValue() + g:imported_func = Exported() def GetExported(): string @@ -1085,11 +1102,13 @@ def Test_vim9_import_export() enddef g:funcref_result = GetExported() - import {exp_name} from './Xexport.vim' + var dir = './' + var ext = ".vim" + import {exp_name} from dir .. 'Xexport' .. ext g:imported_name = exp_name exp_name ..= ' Doe' g:imported_name_appended = exp_name - g:imported_later = exported + g:exported_later = exported import theList from './Xexport.vim' theList->add(2) @@ -1103,9 +1122,17 @@ def Test_vim9_import_export() assert_equal('bobbie', g:result) assert_equal('bob', g:localname) - assert_equal(9876, g:imported) - assert_equal(9879, g:imported_added) - assert_equal(9879, g:imported_later) + assert_equal(9876, g:exported1) + assert_equal(9879, g:exported2) + assert_equal(9879, g:exported3) + + assert_equal(9884, g:exported_i1) + assert_equal(9884, g:exported_i2) + + assert_equal(11, g:exported_s1) + assert_equal(11, g:exported_s2) + assert_equal(11, g:exported_later) + assert_equal('Exported', g:imported_func) assert_equal('Exported', g:funcref_result) assert_equal('John', g:imported_name) @@ -1113,9 +1140,12 @@ def Test_vim9_import_export() assert_false(exists('g:name')) Undo_export_script_lines() - unlet g:imported - unlet g:imported_added - unlet g:imported_later + unlet g:exported1 + unlet g:exported2 + unlet g:exported3 + unlet g:exported_i1 + unlet g:exported_i2 + unlet g:exported_later unlet g:imported_func unlet g:imported_name g:imported_name_appended delete('Ximport.vim') @@ -1129,60 +1159,43 @@ def Test_vim9_import_export() } from './Xexport.vim' - g:imported = exported - exported += 5 - g:imported_added = exported + g:exported = exported + exported += 7 + g:exported_added = exported g:imported_func = Exported() END writefile(import_line_break_script_lines, 'Ximport_lbr.vim') source Ximport_lbr.vim - assert_equal(9876, g:imported) - assert_equal(9881, g:imported_added) + assert_equal(11, g:exported) + assert_equal(18, g:exported_added) assert_equal('Exported', g:imported_func) # exported script not sourced again assert_false(exists('g:result')) - unlet g:imported - unlet g:imported_added + unlet g:exported + unlet g:exported_added unlet g:imported_func delete('Ximport_lbr.vim') - # import inside :def function - var import_in_def_lines =<< trim END - vim9script - def ImportInDef() - import exported from './Xexport.vim' - g:imported = exported - exported += 7 - g:imported_added = exported - enddef - ImportInDef() - END - writefile(import_in_def_lines, 'Ximport2.vim') - source Ximport2.vim - # TODO: this should be 9879 - assert_equal(9876, g:imported) - assert_equal(9883, g:imported_added) - unlet g:imported - unlet g:imported_added - delete('Ximport2.vim') - var import_star_as_lines =<< trim END vim9script import * as Export from './Xexport.vim' def UseExport() - g:imported_def = Export.exported + g:exported_def = Export.exported enddef - g:imported_script = Export.exported + g:exported_script = Export.exported assert_equal(1, exists('Export.exported')) assert_equal(0, exists('Export.notexported')) UseExport() END writefile(import_star_as_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9883, g:imported_def) - assert_equal(9883, g:imported_script) + + assert_equal(18, g:exported_def) + assert_equal(18, g:exported_script) + unlet g:exported_def + unlet g:exported_script var import_star_as_lines_no_dot =<< trim END vim9script @@ -1251,13 +1264,14 @@ def Test_vim9_import_export() from './Xexport.vim' def UseExport() - g:imported = Export.exported + g:exported = Export.exported enddef UseExport() END writefile(import_star_as_lbr_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9883, g:imported) + assert_equal(18, g:exported) + unlet g:exported var import_star_lines =<< trim END vim9script @@ -1345,7 +1359,7 @@ def Test_vim9_import_export() import name from Xexport.vim END writefile(import_invalid_string_lines, 'Ximport.vim') - assert_fails('source Ximport.vim', 'E1071:', '', 2, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim') var import_wrong_name_lines =<< trim END vim9script @@ -1659,22 +1673,6 @@ def Test_vim9script_reload_import() source Xreload.vim source Xreload.vim - var testlines =<< trim END - vim9script - def TheFunc() - import GetValtwo from './Xreload.vim' - assert_equal(222, GetValtwo()) - enddef - TheFunc() - END - writefile(testlines, 'Ximport.vim') - source Ximport.vim - - # Test that when not using "morelines" GetValtwo() and valtwo are still - # defined, because import doesn't reload a script. - writefile(lines, 'Xreload.vim') - source Ximport.vim - # cannot declare a var twice lines =<< trim END vim9script @@ -2557,6 +2555,12 @@ def Test_for_loop() dd.counter = 12 endfor assert_equal([{a: 'Cat', counter: 12}], foo) + + reslist = [] + for _ in range(3) + reslist->add('x') + endfor + assert_equal(['x', 'x', 'x'], reslist) END CheckDefAndScriptSuccess(lines) enddef @@ -3699,6 +3703,46 @@ def Test_script_var_in_autocmd() CheckScriptSuccess(lines) enddef +def Test_error_in_autoload_script() + var save_rtp = &rtp + var dir = getcwd() .. '/Xruntime' + &rtp = dir + mkdir(dir .. '/autoload', 'p') + + var lines =<< trim END + vim9script noclear + def script#autoloaded() + enddef + def Broken() + var x: any = '' + eval x != 0 + enddef + Broken() + END + writefile(lines, dir .. '/autoload/script.vim') + + lines =<< trim END + vim9script + def CallAutoloaded() + script#autoloaded() + enddef + + function Legacy() + try + call s:CallAutoloaded() + catch + call assert_match('E1030: Using a String as a Number', v:exception) + endtry + endfunction + + Legacy() + END + CheckScriptSuccess(lines) + + &rtp = save_rtp + delete(dir, 'rf') +enddef + def Test_cmdline_win() # if the Vim syntax highlighting uses Vim9 constructs they can be used from # the command line window. @@ -4167,6 +4211,58 @@ def Test_option_modifier() set hlsearch& enddef +" This must be called last, it may cause following :def functions to fail +def Test_xxx_echoerr_line_number() + var lines =<< trim END + echoerr 'some' + .. ' error' + .. ' continued' + END + CheckDefExecAndScriptFailure(lines, 'some error continued', 1) +enddef + +def ProfiledWithLambda() + var n = 3 + echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) +enddef + +def ProfiledNested() + var x = 0 + def Nested(): any + return x + enddef + Nested() +enddef + +def ProfiledNestedProfiled() + var x = 0 + def Nested(): any + return x + enddef + Nested() +enddef + +" Execute this near the end, profiling doesn't stop until Vim exists. +" This only tests that it works, not the profiling output. +def Test_xx_profile_with_lambda() + CheckFeature profile + + profile start Xprofile.log + profile func ProfiledWithLambda + ProfiledWithLambda() + + profile func ProfiledNested + ProfiledNested() + + # Also profile the nested function. Use a different function, although the + # contents is the same, to make sure it was not already compiled. + profile func * + ProfiledNestedProfiled() + + profdel func * + profile pause +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/testing.c b/src/testing.c index c2389bdeeb..42030d726d 100644 --- a/src/testing.c +++ b/src/testing.c @@ -340,10 +340,14 @@ assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, char_u *cmd) static int assert_beeps(typval_T *argvars, int no_beep) { - char_u *cmd = tv_get_string_chk(&argvars[0]); + char_u *cmd; garray_T ga; int ret = 0; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return 0; + + cmd = tv_get_string_chk(&argvars[0]); called_vim_beep = FALSE; suppress_errthrow = TRUE; emsg_silent = FALSE; @@ -367,7 +371,7 @@ assert_beeps(typval_T *argvars, int no_beep) } /* - * "assert_beeps(cmd [, error])" function + * "assert_beeps(cmd)" function */ void f_assert_beeps(typval_T *argvars, typval_T *rettv) @@ -376,7 +380,7 @@ f_assert_beeps(typval_T *argvars, typval_T *rettv) } /* - * "assert_nobeep(cmd [, error])" function + * "assert_nobeep(cmd)" function */ void f_assert_nobeep(typval_T *argvars, typval_T *rettv) @@ -824,6 +828,9 @@ f_assert_report(typval_T *argvars, typval_T *rettv) { garray_T ga; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + prepare_assert_error(&ga); ga_concat(&ga, tv_get_string(&argvars[0])); assert_error(&ga); @@ -944,6 +951,11 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED) int val; static int save_starting = -1; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + if (argvars[0].v_type != VAR_STRING || (argvars[1].v_type) != VAR_NUMBER) emsg(_(e_invarg)); diff --git a/src/textprop.c b/src/textprop.c index 78696fc650..c2000a3c3e 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -769,9 +769,16 @@ f_prop_find(typval_T *argvars, typval_T *rettv) void f_prop_list(typval_T *argvars, typval_T *rettv) { - linenr_T lnum = tv_get_number(&argvars[0]); + linenr_T lnum; buf_T *buf = curbuf; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN && + check_for_dict_arg(argvars, 1) == FAIL))) + return; + + lnum = tv_get_number(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) diff --git a/src/time.c b/src/time.c index 6d4ad5d51e..796fc58c96 100644 --- a/src/time.c +++ b/src/time.c @@ -169,6 +169,10 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) # ifdef FEAT_RELTIME proftime_T res; proftime_T start; + long n1, n2; + + if (rettv_list_alloc(rettv) != OK) + return; if (argvars[0].v_type == VAR_UNKNOWN) { @@ -178,7 +182,11 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) else if (argvars[1].v_type == VAR_UNKNOWN) { if (list2proftime(&argvars[0], &res) == FAIL) + { + if (in_vim9script()) + emsg(_(e_invarg)); return; + } profile_end(&res); } else @@ -186,24 +194,23 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) // Two arguments: compute the difference. if (list2proftime(&argvars[0], &start) == FAIL || list2proftime(&argvars[1], &res) == FAIL) + { + if (in_vim9script()) + emsg(_(e_invarg)); return; + } profile_sub(&res, &start); } - if (rettv_list_alloc(rettv) == OK) - { - long n1, n2; - # ifdef MSWIN - n1 = res.HighPart; - n2 = res.LowPart; + n1 = res.HighPart; + n2 = res.LowPart; # else - n1 = res.tv_sec; - n2 = res.tv_usec; + n1 = res.tv_sec; + n2 = res.tv_usec; # endif - list_append_number(rettv->vval.v_list, (varnumber_T)n1); - list_append_number(rettv->vval.v_list, (varnumber_T)n2); - } + list_append_number(rettv->vval.v_list, (varnumber_T)n1); + list_append_number(rettv->vval.v_list, (varnumber_T)n2); # endif } @@ -223,6 +230,8 @@ f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) # ifdef FEAT_RELTIME if (list2proftime(&argvars[0], &tm) == OK) rettv->vval.v_float = profile_float(&tm); + else if (in_vim9script()) + emsg(_(e_invarg)); # endif } # endif @@ -242,6 +251,8 @@ f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) # ifdef FEAT_RELTIME if (list2proftime(&argvars[0], &tm) == OK) rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); + else if (in_vim9script()) + emsg(_(e_invarg)); # endif } @@ -257,6 +268,12 @@ f_strftime(typval_T *argvars, typval_T *rettv) time_t seconds; char_u *p; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + rettv->v_type = VAR_STRING; p = tv_get_string(&argvars[0]); diff --git a/src/typval.c b/src/typval.c index b223318311..9d5903f649 100644 --- a/src/typval.c +++ b/src/typval.c @@ -352,7 +352,7 @@ tv_get_float(typval_T *varp) #endif /* - * Give an error and return FAIL unless "tv" is a string. + * Give an error and return FAIL unless "args[idx]" is a string. */ int check_for_string_arg(typval_T *args, int idx) @@ -385,7 +385,61 @@ check_for_nonempty_string_arg(typval_T *args, int idx) } /* - * Give an error and return FAIL unless "tv" is a dict. + * Give an error and return FAIL unless "args[idx]" is a number. + */ + int +check_for_number_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_NUMBER) + { + if (idx >= 0) + semsg(_(e_number_required_for_argument_nr), idx + 1); + else + emsg(_(e_numberreq)); + return FAIL; + } + return OK; +} + +/* + * Give an error and return FAIL unless "args[idx]" is a bool. + */ + int +check_for_bool_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_BOOL + && !(args[idx].v_type == VAR_NUMBER + && (args[idx].vval.v_number == 0 + || args[idx].vval.v_number == 1))) + { + if (idx >= 0) + semsg(_(e_bool_required_for_argument_nr), idx + 1); + else + emsg(_(e_boolreq)); + return FAIL; + } + return OK; +} + +/* + * Give an error and return FAIL unless "args[idx]" is a list. + */ + int +check_for_list_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_LIST) + { + if (idx >= 0) + semsg(_(e_list_required_for_argument_nr), idx + 1); + else + emsg(_(e_listreq)); + return FAIL; + } + return OK; +} + +/* + * Give an error and return FAIL unless "args[idx]" is a dict. */ int check_for_dict_arg(typval_T *args, int idx) @@ -883,7 +937,9 @@ typval_compare( } } else if (in_vim9script() && (typ1->v_type == VAR_BOOL - || typ2->v_type == VAR_BOOL)) + || typ2->v_type == VAR_BOOL + || (typ1->v_type == VAR_SPECIAL + && typ2->v_type == VAR_SPECIAL))) { if (typ1->v_type != typ2->v_type) { @@ -901,13 +957,23 @@ typval_compare( case EXPR_ISNOT: case EXPR_NEQUAL: n1 = (n1 != n2); break; default: - emsg(_(e_invalid_operation_for_bool)); + semsg(_(e_invalid_operation_for_str), + vartype_name(typ1->v_type)); clear_tv(typ1); return FAIL; } } else { + if (in_vim9script() + && ((typ1->v_type != VAR_STRING && typ1->v_type != VAR_SPECIAL) + || (typ2->v_type != VAR_STRING && typ2->v_type != VAR_SPECIAL))) + { + semsg(_(e_cannot_compare_str_with_str), + vartype_name(typ1->v_type), vartype_name(typ2->v_type)); + clear_tv(typ1); + return FAIL; + } s1 = tv_get_string_buf(typ1, buf1); s2 = tv_get_string_buf(typ2, buf2); if (type != EXPR_MATCH && type != EXPR_NOMATCH) diff --git a/src/usercmd.c b/src/usercmd.c index a4bbfd77cf..42b9014f38 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -1019,20 +1019,22 @@ ex_command(exarg_T *eap) // we are listing commands p = skipwhite(end); if (!has_attr && ends_excmd2(eap->arg, p)) - { uc_list(name, end - name); - } else if (!ASCII_ISUPPER(*name)) - { emsg(_("E183: User defined commands must start with an uppercase letter")); - return; - } else if ((name_len == 1 && *name == 'X') || (name_len <= 4 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) - { emsg(_("E841: Reserved name, cannot be used for user defined command")); - return; + else if (compl > 0 && (argt & EX_EXTRA) == 0) + { + // Some plugins rely on silently ignoring the mistake, only make this + // an error in Vim9 script. + if (in_vim9script()) + emsg(_(e_complete_used_without_nargs)); + else + give_warning_with_source( + (char_u *)_(e_complete_used_without_nargs), TRUE, TRUE); } else uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, diff --git a/src/userfunc.c b/src/userfunc.c index 4234681cd7..3dfa680972 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -634,6 +634,7 @@ get_function_body( || eap->cmdidx == CMD_block; #define MAX_FUNC_NESTING 50 char nesting_def[MAX_FUNC_NESTING]; + char nesting_inline[MAX_FUNC_NESTING]; int nesting = 0; getline_opt_T getline_options; int indent = 2; @@ -658,7 +659,8 @@ get_function_body( ((char_u **)(newlines->ga_data))[newlines->ga_len++] = NULL; } - nesting_def[nesting] = vim9_function; + nesting_def[0] = vim9_function; + nesting_inline[0] = eap->cmdidx == CMD_block; getline_options = vim9_function ? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT; for (;;) @@ -705,10 +707,10 @@ get_function_body( SOURCING_LNUM = sourcing_lnum_top; if (skip_until != NULL) semsg(_(e_missing_heredoc_end_marker_str), skip_until); + else if (nesting_inline[nesting]) + emsg(_(e_missing_end_block)); else if (eap->cmdidx == CMD_def) emsg(_(e_missing_enddef)); - else if (eap->cmdidx == CMD_block) - emsg(_(e_missing_end_block)); else emsg(_("E126: Missing :endfunction")); goto theend; @@ -765,7 +767,8 @@ get_function_body( } else { - int c; + int c; + char_u *end; // skip ':' and blanks for (p = theline; VIM_ISWHITE(*p) || *p == ':'; ++p) @@ -773,7 +776,7 @@ get_function_body( // Check for "endfunction", "enddef" or "}". // When a ":" follows it must be a dict key; "enddef: value," - if ((nesting == 0 && eap->cmdidx == CMD_block) + if (nesting_inline[nesting] ? *p == '}' : (checkforcmd(&p, nesting_def[nesting] ? "enddef" : "endfunction", 4) @@ -857,6 +860,31 @@ get_function_body( { ++nesting; nesting_def[nesting] = (c == 'd'); + nesting_inline[nesting] = FALSE; + indent += 2; + } + } + } + + // Check for nested inline function. + end = p + STRLEN(p) - 1; + while (end > p && VIM_ISWHITE(*end)) + --end; + if (end > p && *end == '{') + { + --end; + while (end > p && VIM_ISWHITE(*end)) + --end; + if (end > p + 2 && end[-1] == '=' && end[0] == '>') + { + // found trailing "=> {", start of an inline function + if (nesting == MAX_FUNC_NESTING - 1) + emsg(_(e_function_nesting_too_deep)); + else + { + ++nesting; + nesting_def[nesting] = TRUE; + nesting_inline[nesting] = TRUE; indent += 2; } } diff --git a/src/version.c b/src/version.c index 35474bcfd6..f5c2ca2999 100644 --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,90 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3182, +/**/ + 3181, +/**/ + 3180, +/**/ + 3179, +/**/ + 3178, +/**/ + 3177, +/**/ + 3176, +/**/ + 3175, +/**/ + 3174, +/**/ + 3173, +/**/ + 3172, +/**/ + 3171, +/**/ + 3170, +/**/ + 3169, +/**/ + 3168, +/**/ + 3167, +/**/ + 3166, +/**/ + 3165, +/**/ + 3164, +/**/ + 3163, +/**/ + 3162, +/**/ + 3161, +/**/ + 3160, +/**/ + 3159, +/**/ + 3158, +/**/ + 3157, +/**/ + 3156, +/**/ + 3155, +/**/ + 3154, +/**/ + 3153, +/**/ + 3152, +/**/ + 3151, +/**/ + 3150, +/**/ + 3149, +/**/ + 3148, +/**/ + 3147, +/**/ + 3146, +/**/ + 3145, +/**/ + 3144, +/**/ + 3143, +/**/ + 3142, +/**/ + 3141, /**/ 3140, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c27a1cc34a..12dd19823a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1051,7 +1051,8 @@ need_type( // If the actual type can be the expected type add a runtime check. // If it's a constant a runtime check makes no sense. - if (!actual_is_const && use_typecheck(actual, expected)) + if ((!actual_is_const || actual == &t_any) + && use_typecheck(actual, expected)) { generate_TYPECHECK(cctx, expected, offset, arg_idx); return OK; @@ -1781,6 +1782,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) garray_T *stack = &cctx->ctx_type_stack; int argoff; type_T **argtypes = NULL; + type_T *shuffled_argtypes[MAX_FUNC_ARGS]; type_T *maptype = NULL; RETURN_OK_IF_SKIP(cctx); @@ -1800,6 +1802,16 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) { // Check the types of the arguments. argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount; + if (method_call && argoff > 1) + { + int i; + + for (i = 0; i < argcount; ++i) + shuffled_argtypes[i] = (i < argoff - 1) + ? argtypes[i + 1] + : (i == argoff - 1) ? argtypes[0] : argtypes[i]; + argtypes = shuffled_argtypes; + } if (internal_func_check_arg_types(argtypes, func_idx, argcount, cctx) == FAIL) return FAIL; @@ -3624,6 +3636,13 @@ compile_lambda(char_u **arg, cctx_T *cctx) ufunc->uf_ret_type = &t_unknown; compile_def_function(ufunc, FALSE, cctx->ctx_compile_type, cctx); +#ifdef FEAT_PROFILE + // When the outer function is compiled for profiling, the lambda may be + // called without profiling. Compile it here in the right context. + if (cctx->ctx_compile_type == CT_PROFILE) + compile_def_function(ufunc, FALSE, CT_NONE, cctx); +#endif + // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" // points into it. Point to the original line to avoid a dangling pointer. if (evalarg.eval_tofree_cmdline != NULL) @@ -4316,7 +4335,6 @@ compile_subscript( semsg(_(e_missing_paren), *arg); return FAIL; } - // TODO: base value may not be the first argument if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) return FAIL; } @@ -5077,6 +5095,7 @@ compile_and_or( while (p[0] == opchar && p[1] == opchar) { long start_lnum = SOURCING_LNUM; + long save_sourcing_lnum; int start_ctx_lnum = cctx->ctx_lnum; int save_lnum; @@ -5098,6 +5117,7 @@ compile_and_or( generate_ppconst(cctx, ppconst); // Every part must evaluate to a bool. + save_sourcing_lnum = SOURCING_LNUM; SOURCING_LNUM = start_lnum; save_lnum = cctx->ctx_lnum; cctx->ctx_lnum = start_ctx_lnum; @@ -5120,6 +5140,7 @@ compile_and_or( ? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0); // eval the next expression + SOURCING_LNUM = save_sourcing_lnum; if (may_get_next_line_error(p + 2, arg, cctx) == FAIL) { ga_clear(&end_ga); @@ -5552,6 +5573,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) char_u *lambda_name; ufunc_T *ufunc; int r = FAIL; + compiletype_T compile_type; if (eap->forceit) { @@ -5618,14 +5640,27 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) } } - if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx) - == FAIL) + compile_type = COMPILE_TYPE(ufunc); +#ifdef FEAT_PROFILE + // If the outer function is profiled, also compile the nested function for + // profiling. + if (cctx->ctx_compile_type == CT_PROFILE) + compile_type = CT_PROFILE; +#endif + if (func_needs_compiling(ufunc, compile_type) + && compile_def_function(ufunc, TRUE, compile_type, cctx) == FAIL) { func_ptr_unref(ufunc); goto theend; } +#ifdef FEAT_PROFILE + // When the outer function is compiled for profiling, the nested function + // may be called without profiling. Compile it here in the right context. + if (compile_type == CT_PROFILE && func_needs_compiling(ufunc, CT_NONE)) + compile_def_function(ufunc, FALSE, CT_NONE, cctx); +#endif + if (is_global) { char_u *func_name = vim_strnsave(name_start + 2, @@ -7257,15 +7292,6 @@ compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx) return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd; } -/* - * Compile an :import command. - */ - static char_u * -compile_import(char_u *arg, cctx_T *cctx) -{ - return handle_import(arg, &cctx->ctx_imports, 0, NULL, cctx); -} - /* * generate a jump to the ":endif"/":endfor"/":endwhile"/":finally"/":endtry". */ @@ -9474,7 +9500,8 @@ compile_def_function( } } } - p = find_ex_command(&ea, NULL, starts_with_colon + p = find_ex_command(&ea, NULL, + starts_with_colon || (local_cmdmod.cmod_flags & CMOD_LEGACY) ? NULL : item_exists, &cctx); if (p == NULL) @@ -9601,7 +9628,8 @@ compile_def_function( break; case CMD_import: - line = compile_import(p, &cctx); + emsg(_(e_import_can_only_be_used_in_script)); + line = NULL; break; case CMD_if: diff --git a/src/vim9execute.c b/src/vim9execute.c index 87f3c424ea..b882c4d111 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -197,6 +197,7 @@ call_dfunc( int idx; estack_T *entry; funclocal_T *floc = NULL; + int res = OK; if (dfunc->df_deleted) { @@ -219,14 +220,6 @@ call_dfunc( (((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx)->df_ufunc); } - - // Profiling might be enabled/disabled along the way. This should not - // fail, since the function was compiled before and toggling profiling - // doesn't change any errors. - if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) - == FAIL) - return FAIL; } #endif @@ -235,10 +228,14 @@ call_dfunc( // When debugging and using "cont" switches to the not-debugged // instructions, may need to still compile them. - if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) - == FAIL) - || INSTRUCTIONS(dfunc) == NULL) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))) + { + res = compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL); + + // compile_def_function() may cause def_functions.ga_data to change + dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx; + } + if (res == FAIL || INSTRUCTIONS(dfunc) == NULL) { if (did_emsg_cumul + did_emsg == did_emsg_before) semsg(_(e_function_is_not_compiled_str), @@ -4740,7 +4737,8 @@ failed_early: // Not sure if this is necessary. suppress_errthrow = save_suppress_errthrow; - if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before) + if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before + && !need_rethrow) semsg(_(e_unknown_error_while_executing_str), printable_func_name(ufunc)); funcdepth_restore(orig_funcdepth); diff --git a/src/vim9script.c b/src/vim9script.c index d40e334aef..85d601c7ae 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -412,6 +412,7 @@ handle_import( garray_T names; garray_T as_names; + tv.v_type = VAR_UNKNOWN; ga_init2(&names, sizeof(char_u *), 10); ga_init2(&as_names, sizeof(char_u *), 10); if (*arg == '{') @@ -496,14 +497,14 @@ handle_import( goto erret; } + // The name of the file can be an expression, which must evaluate to a + // string. arg = skipwhite_and_linebreak(arg + 4, evalarg); - tv.v_type = VAR_UNKNOWN; - // TODO: should we accept any expression? - if (*arg == '\'') - ret = eval_lit_string(&arg, &tv, TRUE); - else if (*arg == '"') - ret = eval_string(&arg, &tv, TRUE); - if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) + ret = eval0(arg, &tv, NULL, evalarg); + if (ret == FAIL) + goto erret; + if (tv.v_type != VAR_STRING + || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) { emsg(_(e_invalid_string_after_from)); goto erret; @@ -524,10 +525,7 @@ handle_import( len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2; from_name = alloc((int)len); if (from_name == NULL) - { - clear_tv(&tv); goto erret; - } vim_strncpy(from_name, si->sn_name, tail - si->sn_name); add_pathsep(from_name); STRCAT(from_name, tv.vval.v_string); @@ -550,7 +548,6 @@ handle_import( from_name = alloc((int)len); if (from_name == NULL) { - clear_tv(&tv); goto erret; } vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string); @@ -561,10 +558,8 @@ handle_import( if (res == FAIL || sid <= 0) { semsg(_(e_could_not_import_str), tv.vval.v_string); - clear_tv(&tv); goto erret; } - clear_tv(&tv); if (*arg_start == '*') { @@ -669,6 +664,7 @@ handle_import( } } erret: + clear_tv(&tv); ga_clear_strings(&names); ga_clear_strings(&as_names); return cmd_end;