Compare commits

..

6 Commits

Author SHA1 Message Date
Bram Moolenaar
75783bd84e patch 8.2.1243: Vim9: cannot have a comment line halfway a list
Problem:    Vim9: cannot have a comment or empty line halfway a list at script
            level.
Solution:   Skip more than one line if needed.
2020-07-19 14:41:58 +02:00
Bram Moolenaar
65b9545f44 patch 8.2.1242: Vim9: no error if calling a function with wrong type
Problem:    Vim9: no error if calling a function with wrong argument type.
Solution:   Check types of arguments. (closes #6469)
2020-07-19 14:03:09 +02:00
Bram Moolenaar
6434fc574d patch 8.2.1241: cannot use getbufinfo() as a method
Problem:    Cannot use getbufinfo() as a method.
Solution:   Support using getbufinfo() as a method. (closes #6458)
2020-07-18 22:24:22 +02:00
Bram Moolenaar
10e1d01aaf patch 8.2.1240: GUI tests sometimes fail because of translations
Problem:    GUI tests sometimes fail because of translations.
Solution:   Reload the menus without translation. (Taro Muraoka, closes #6486)
2020-07-18 22:03:11 +02:00
Bram Moolenaar
de2396fc87 patch 8.2.1239: "maxwidth" in 'completepopup' not obeyed
Problem:    "maxwidth" in 'completepopup' not obeyed. (Jay Sitter)
Solution:   Add separate field for value from option. (closes #6470)
2020-07-18 21:40:41 +02:00
Bram Moolenaar
d032f34a51 patch 8.2.1238: Vim9: a few remaining errors not caught by try/catch
Problem:    Vim9: a few remaining errors not caught by try/catch.
Solution:   Do not bail out if an error is inside try/catch.
2020-07-18 18:13:02 +02:00
16 changed files with 201 additions and 43 deletions

View File

@@ -4929,8 +4929,11 @@ getbufinfo([{dict}])
<
To get buffer-local options use: >
getbufvar({bufnr}, '&option_name')
<
Can also be used as a |method|: >
GetBufnr()->getbufinfo()
<
*getbufline()*
getbufline({expr}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {end}

View File

@@ -1913,7 +1913,7 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
&& evalarg != NULL
&& (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)
&& (*arg == NUL || (VIM_ISWHITE(arg[-1])
&& *arg == '#' && arg[1] != '{')))
&& vim9_comment_start(arg))))
{
char_u *p;

View File

@@ -611,7 +611,7 @@ static funcentry_T global_functions[] =
{"function", 1, 3, FEARG_1, ret_f_function, f_function},
{"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
{"get", 2, 3, FEARG_1, ret_any, f_get},
{"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
{"getbufinfo", 0, 1, FEARG_1, ret_list_dict_any, f_getbufinfo},
{"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
{"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
{"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},

View File

@@ -642,6 +642,7 @@ pum_position_info_popup(win_T *wp)
int col = pum_col + pum_width + pum_scrollbar + 1;
int row = pum_row;
int botpos = POPPOS_BOTLEFT;
int used_maxwidth_opt = FALSE;
wp->w_popup_pos = POPPOS_TOPLEFT;
if (Columns - col < 20 && Columns - col < pum_col)
@@ -654,6 +655,12 @@ pum_position_info_popup(win_T *wp)
else
wp->w_maxwidth = Columns - col + 1;
wp->w_maxwidth -= popup_extra_width(wp);
if (wp->w_maxwidth_opt > 0 && wp->w_maxwidth > wp->w_maxwidth_opt)
{
// option value overrules computed value
wp->w_maxwidth = wp->w_maxwidth_opt;
used_maxwidth_opt = TRUE;
}
row -= popup_top_extra(wp);
if (wp->w_popup_flags & POPF_INFO_MENU)
@@ -673,7 +680,7 @@ pum_position_info_popup(win_T *wp)
row += pum_selected - pum_first + 1;
wp->w_popup_flags &= ~POPF_HIDDEN;
if (wp->w_maxwidth < 10)
if (wp->w_maxwidth < 10 && !used_maxwidth_opt)
// The popup is not going to fit or will overlap with the cursor
// position, hide the popup.
wp->w_popup_flags |= POPF_HIDDEN;

View File

@@ -1620,6 +1620,7 @@ parse_popup_option(win_T *wp, int is_preview)
if (is_preview)
wp->w_minwidth = x;
wp->w_maxwidth = x;
wp->w_maxwidth_opt = x;
}
}
else if (STRNCMP(s, "highlight:", 10) == 0)

View File

@@ -3,6 +3,7 @@ int check_defined(char_u *p, size_t len, cctx_T *cctx);
void clear_type_list(garray_T *gap);
type_T *typval2type(typval_T *tv);
int check_type(type_T *expected, type_T *actual, int give_msg);
int check_argtype(type_T *expected, typval_T *actual_tv);
int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2);
char_u *skip_type(char_u *start);
type_T *parse_type(char_u **arg, garray_T *type_gap);
@@ -10,6 +11,7 @@ char *vartype_name(vartype_T type);
char *type_name(type_T *type, char **tofree);
int get_script_item_idx(int sid, char_u *name, int check_writable);
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
int vim9_comment_start(char_u *p);
char_u *peek_next_line_from_context(cctx_T *cctx);
char_u *next_line_from_context(cctx_T *cctx, int skip_comment);
char_u *to_name_const_end(char_u *arg);

View File

@@ -1763,10 +1763,13 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
// backslash. We always need to read the next line, keep it in
// sp->nextline.
/* Also check for a comment in between continuation lines: "\ */
// Also check for a Vim9 comment and empty line.
sp->nextline = get_one_sourceline(sp);
if (sp->nextline != NULL
&& (*(p = skipwhite(sp->nextline)) == '\\'
|| (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
|| (p[0] == '"' && p[1] == '\\' && p[2] == ' ')
|| (in_vim9script()
&& (*p == NUL || vim9_comment_start(p)))))
{
garray_T ga;
@@ -1794,8 +1797,11 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
}
ga_concat(&ga, p + 1);
}
else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
else if (!(p[0] == '"' && p[1] == '\\' && p[2] == ' ')
&& !(in_vim9script()
&& (*p == NUL || vim9_comment_start(p))))
break;
/* drop a # comment or "\ comment line */
}
ga_append(&ga, NUL);
vim_free(line);

View File

@@ -3302,6 +3302,7 @@ struct window_S
int w_minwidth; // "minwidth" for popup window
int w_maxheight; // "maxheight" for popup window
int w_maxwidth; // "maxwidth" for popup window
int w_maxwidth_opt; // maxwidth from option
int w_wantline; // "line" for popup window
int w_wantcol; // "col" for popup window
int w_firstline; // "firstline" for popup window

View File

@@ -0,0 +1,14 @@
|a+0&#ffffff0|w|o|r|d| @69
|t|e|s|a|w|o|r|d> @66
|~+0#4040ff13&| | +0#0000001#e0e0e08|w|r|d| @4|W| |e|x|t|r|a| |t|e|x|t| @1| +0#0000000#0000001| +0#0000001#e0e0e08|w|o|r|d|s| |a|r|e| @1| +0#4040ff13#ffffff0@36
|~| | +0#0000001#ffd7ff255|a|n|o|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| @1| +0#0000000#0000001| +0#0000001#e0e0e08|c|o@1|l| @6| +0#4040ff13#ffffff0@36
|~| | +0#0000001#ffd7ff255|n|o|a|w|r|d| @1|W| |e|x|t|r|a| |t|e|x|t| @1| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@48
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |4| +0#0000000&@26

View File

@@ -105,6 +105,13 @@ set nomore
" Output all messages in English.
lang mess C
" suppress menu translation
if has('gui_running') && exists('did_install_default_menus')
source $VIMRUNTIME/delmenu.vim
set langmenu=none
source $VIMRUNTIME/menu.vim
endif
" Always use forward slashes.
set shellslash

View File

@@ -23,6 +23,9 @@ func Test_getbufwintabinfo()
call assert_equal('vim', l[0].variables.editor)
call assert_notequal(-1, index(l[0].windows, '%'->bufwinid()))
let l = '%'->getbufinfo()
call assert_equal(bufnr('%'), l[0].bufnr)
" Test for getbufinfo() with 'bufmodified'
call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
call setbufline('Xtestfile1', 1, ["Line1"])

View File

@@ -407,6 +407,17 @@ def Test_vim9script_call_fail_decl()
delete('Xcall_decl.vim')
enddef
def Test_vim9script_call_fail_type()
let lines =<< trim END
vim9script
def MyFunc(arg: string)
echo arg
enddef
MyFunc(1234)
END
CheckScriptFailure(lines, 'E1013: type mismatch, expected string but got number')
enddef
def Test_vim9script_call_fail_const()
let lines =<< trim END
vim9script

View File

@@ -498,6 +498,10 @@ def Test_cmd_modifier()
call CheckDefFailure(['5tab echo 3'], 'E16:')
enddef
func g:NoSuchFunc()
echo 'none'
endfunc
def Test_try_catch()
let l = []
try # comment
@@ -656,6 +660,57 @@ def Test_try_catch()
n = 344
endtry
assert_equal(344, n)
try
echo len(v:true)
catch /E701:/
n = 355
endtry
assert_equal(355, n)
let P = function('g:NoSuchFunc')
delfunc g:NoSuchFunc
try
echo P()
catch /E117:/
n = 366
endtry
assert_equal(366, n)
try
echo g:NoSuchFunc()
catch /E117:/
n = 377
endtry
assert_equal(377, n)
try
echo g:alist + 4
catch /E745:/
n = 388
endtry
assert_equal(388, n)
try
echo 4 + g:alist
catch /E745:/
n = 399
endtry
assert_equal(399, n)
try
echo g:alist.member
catch /E715:/
n = 400
endtry
assert_equal(400, n)
try
echo d.member
catch /E716:/
n = 411
endtry
assert_equal(411, n)
enddef
def DeletedFunc(): list<any>
@@ -2029,7 +2084,7 @@ def Test_vim9_comment()
CheckScriptFailure([
'vim9script',
'syntax region Word start=/pat/ end=/pat/# comment',
], 'E475:')
], 'E402:')
CheckScriptSuccess([
'vim9script',

View File

@@ -754,6 +754,18 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1243,
/**/
1242,
/**/
1241,
/**/
1240,
/**/
1239,
/**/
1238,
/**/
1237,
/**/

View File

@@ -560,6 +560,50 @@ check_type(type_T *expected, type_T *actual, int give_msg)
return ret;
}
/*
* Return FAIl if "expected" and "actual" don't match.
* TODO: better type comparison
*/
int
check_argtype(type_T *expected, typval_T *actual_tv)
{
type_T actual;
type_T member;
// TODO: should should be done with more levels
CLEAR_FIELD(actual);
actual.tt_type = actual_tv->v_type;
if (actual_tv->v_type == VAR_LIST
&& actual_tv->vval.v_list != NULL
&& actual_tv->vval.v_list->lv_first != NULL)
{
// Use the type of the first member, it is the most specific.
CLEAR_FIELD(member);
member.tt_type = actual_tv->vval.v_list->lv_first->li_tv.v_type;
member.tt_member = &t_any;
actual.tt_member = &member;
}
else if (actual_tv->v_type == VAR_DICT
&& actual_tv->vval.v_dict != NULL
&& actual_tv->vval.v_dict->dv_hashtab.ht_used > 0)
{
dict_iterator_T iter;
typval_T *value;
// Use the type of the first value, it is the most specific.
dict_iterate_start(actual_tv, &iter);
dict_iterate_next(&iter, &value);
CLEAR_FIELD(member);
member.tt_type = value->v_type;
member.tt_member = &t_any;
actual.tt_member = &member;
}
else
actual.tt_member = &t_any;
return check_type(expected, &actual, TRUE);
}
/////////////////////////////////////////////////////////////////////
// Following generate_ functions expect the caller to call ga_grow().
@@ -2419,7 +2463,7 @@ free_imported(cctx_T *cctx)
/*
* Return TRUE if "p" points at a "#" but not at "#{".
*/
static int
int
vim9_comment_start(char_u *p)
{
return p[0] == '#' && p[1] != '{';

View File

@@ -737,6 +737,9 @@ call_def_function(
// Put arguments on the stack.
for (idx = 0; idx < argc; ++idx)
{
if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
&& check_argtype(ufunc->uf_arg_types[idx], &argv[idx]) == FAIL)
goto failed_early;
copy_tv(&argv[idx], STACK_TV_BOT(0));
++ectx.ec_stack.ga_len;
}
@@ -1512,6 +1515,7 @@ call_def_function(
item->di_tv.v_lock = 0;
if (dict_add(dict, item) == FAIL)
{
// can this ever happen?
dict_unref(dict);
goto failed;
}
@@ -1544,7 +1548,7 @@ call_def_function(
if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
iptr->isn_arg.bfunc.cbf_argcount,
&ectx) == FAIL)
goto failed;
goto on_error;
break;
// call a funcref or partial
@@ -1571,7 +1575,7 @@ call_def_function(
if (tv == &partial_tv)
clear_tv(&partial_tv);
if (r == FAIL)
goto failed;
goto on_error;
}
break;
@@ -1592,7 +1596,7 @@ call_def_function(
SOURCING_LNUM = iptr->isn_lnum;
if (call_eval_func(cufunc->cuf_name,
cufunc->cuf_argcount, &ectx, iptr) == FAIL)
goto failed;
goto on_error;
}
break;
@@ -1614,19 +1618,7 @@ call_def_function(
trycmd->tcd_return = TRUE;
}
else
{
// Restore previous function. If the frame pointer
// is zero then there is none and we are done.
if (ectx.ec_frame_idx == initial_frame_idx)
{
if (handle_closure_in_use(&ectx, FALSE) == FAIL)
goto failed;
goto done;
}
if (func_return(&ectx) == FAIL)
goto failed;
}
goto func_return;
}
break;
@@ -1735,8 +1727,6 @@ call_def_function(
{
listitem_T *li = list_find(list, idxtv->vval.v_number);
if (li == NULL)
goto failed;
copy_tv(&li->li_tv, STACK_TV_BOT(0));
++ectx.ec_stack.ga_len;
}
@@ -1814,19 +1804,7 @@ call_def_function(
}
if (trycmd->tcd_return)
{
// Restore previous function. If the frame pointer
// is zero then there is none and we are done.
if (ectx.ec_frame_idx == initial_frame_idx)
{
if (handle_closure_in_use(&ectx, FALSE) == FAIL)
goto failed;
goto done;
}
if (func_return(&ectx) == FAIL)
goto failed;
}
goto func_return;
}
}
break;
@@ -2068,7 +2046,7 @@ call_def_function(
{
n1 = tv_get_number_chk(tv1, &error);
if (error)
goto failed;
goto on_error;
#ifdef FEAT_FLOAT
if (tv2->v_type == VAR_FLOAT)
f1 = n1;
@@ -2085,7 +2063,7 @@ call_def_function(
{
n2 = tv_get_number_chk(tv2, &error);
if (error)
goto failed;
goto on_error;
#ifdef FEAT_FLOAT
if (tv1->v_type == VAR_FLOAT)
f2 = n2;
@@ -2268,7 +2246,7 @@ call_def_function(
if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
{
emsg(_(e_dictreq));
goto failed;
goto on_error;
}
dict = tv->vval.v_dict;
@@ -2276,7 +2254,7 @@ call_def_function(
== NULL)
{
semsg(_(e_dictkey), iptr->isn_arg.string);
goto failed;
goto on_error;
}
// Clear the dict after getting the item, to avoid that it
// make the item invalid.
@@ -2409,6 +2387,20 @@ call_def_function(
}
continue;
func_return:
// Restore previous function. If the frame pointer is zero then there
// is none and we are done.
if (ectx.ec_frame_idx == initial_frame_idx)
{
if (handle_closure_in_use(&ectx, FALSE) == FAIL)
// only fails when out of memory
goto failed;
goto done;
}
if (func_return(&ectx) == FAIL)
// only fails when out of memory
goto failed;
on_error:
if (trylevel == 0)
goto failed;