Compare commits

...

9 Commits

Author SHA1 Message Date
Bram Moolenaar
e88c8e802c patch 8.2.1934: Vim9: command modifiers in :def function not tested
Problem:    Vim9: command modifiers in :def function not tested.
Solution:   Add tests.  Fix using modifier before filter command.
2020-11-01 17:03:37 +01:00
Bram Moolenaar
55e29611d2 patch 8.2.1933: cannot sort using locale ordering
Problem:    Cannot sort using locale ordering.
Solution:   Add a flag for :sort and sort() to use the locale. (Dominique
            Pellé, closes #7237)
2020-11-01 13:57:44 +01:00
Bram Moolenaar
963734e316 patch 8.2.1932: compiler warnings when building with Athena GUI
Problem:    Compiler warnings when building with Athena GUI.
Solution:   Fix function signatures.
2020-11-01 13:33:49 +01:00
Bram Moolenaar
fbcbffe1ad patch 8.2.1931: Vim9: arguments of extend() not checked at compile time
Problem:    Vim9: arguments of extend() not checked at compile time.
Solution:   Add argument type checking for extend().
2020-10-31 19:33:38 +01:00
Bram Moolenaar
749bc9521d patch 8.2.1930: wrong input if removing shift results in special key code
Problem:    Wrong input if removing shift results in special key code.
Solution:   Handle special key codes. (closes #7189)
2020-10-31 16:33:47 +01:00
Bram Moolenaar
0289065e41 patch 8.2.1929: MS-Windows: problem loading Perl 5.32
Problem:    MS-Windows: problem loading Perl 5.32.
Solution:   Define NO_THREAD_SAFE_LOCALE. (Ken Takata, closes #7234)
2020-10-31 13:05:11 +01:00
Bram Moolenaar
cd030c4b60 patch 8.2.1928: Vim9: "silent!" not effective when list index is wrong
Problem:    Vim9: "silent!" not effective when list index is wrong.
Solution:   Ignore list indes failure when emsg_silent is set. (closes #7232)
2020-10-30 21:49:40 +01:00
Bram Moolenaar
d66960bf57 patch 8.2.1927: Vim9: get unknown error with an error in a timer function
Problem:    Vim9: get unknown error with an error in a timer function.
Solution:   Use did_emsg instead of called_emsg. (closes #7231)
2020-10-30 20:46:26 +01:00
Bram Moolenaar
b2620202c7 patch 8.2.1926: cannot use a space in 'spellfile'
Problem:    Cannot use a space in 'spellfile'. (Filipe Brandenburger)
Solution:   Permit using a space. (closes #7230)
2020-10-30 19:25:09 +01:00
19 changed files with 459 additions and 52 deletions

View File

@@ -1801,7 +1801,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|.
*:sor* *:sort*
:[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/]
:[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/]
Sort lines in [range]. When no range is given all
lines are sorted.
@@ -1809,6 +1809,14 @@ found here: |sort()|, |uniq()|.
With [i] case is ignored.
With [l] sort uses the current locale. See
`language collate` to check or set the locale used
for ordering. For example, with "en_US.UTF8",
Ö will be ordered after O and before P,
whereas with the Swedish locale "sv_SE.UTF8",
it will be after Z.
Case is typically ignored by the locale.
Options [n][f][x][o][b] are mutually exclusive.
With [n] sorting is done on the first decimal number
@@ -1875,8 +1883,7 @@ found here: |sort()|, |uniq()|.
Note that using `:sort` with `:global` doesn't sort the matching lines, it's
quite useless.
The details about sorting depend on the library function used. There is no
guarantee that sorting obeys the current locale. You will have to try it out.
`:sort` does not use the current locale unless the l flag is used.
Vim does do a "stable" sort.
The sorting can be interrupted, but if you interrupt it too late in the

View File

@@ -9700,6 +9700,13 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
When {func} is given and it is '1' or 'i' then case is
ignored.
When {func} is given and it is 'l' then the current locale
is used for ordering. See `language collate` to check or set
the locale used for ordering. For example, with "en_US.UTF8",
Ö will be ordered after O and before P, whereas with the
Swedish locale "sv_SE.UTF8", it will be after Z.
Case is typically ignored by the locale.
When {func} is given and it is 'n' then all items will be
sorted numerical (Implementation detail: This uses the
strtod() function to parse numbers, Strings, Lists, Dicts and

View File

@@ -276,6 +276,9 @@ typedef struct {
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
typedef int (*argcheck_T)(type_T *, argcontext_T *);
/*
* Check "type" is a float or a number.
*/
static int
arg_float_or_nr(type_T *type, argcontext_T *context)
{
@@ -286,12 +289,27 @@ arg_float_or_nr(type_T *type, argcontext_T *context)
return FAIL;
}
/*
* Check "type" is a number.
*/
static int
arg_number(type_T *type, argcontext_T *context)
{
return check_type(&t_number, type, TRUE, context->arg_idx + 1);
}
/*
* Check "type" is a string.
*/
static int
arg_string(type_T *type, argcontext_T *context)
{
return check_type(&t_string, type, TRUE, context->arg_idx + 1);
}
/*
* Check "type" is a list or a blob.
*/
static int
arg_list_or_blob(type_T *type, argcontext_T *context)
{
@@ -303,7 +321,32 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
}
/*
* Check the type is an item of the list or blob of the previous arg.
* Check "type" is a list or a dict.
*/
static int
arg_list_or_dict(type_T *type, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
return OK;
arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
return FAIL;
}
/*
* Check "type" is the same type as the previous argument
* Must not be used for the first argcheck_T entry.
*/
static int
arg_same_as_prev(type_T *type, argcontext_T *context)
{
type_T *prev_type = context->arg_types[context->arg_idx - 1];
return check_type(prev_type, type, TRUE, context->arg_idx + 1);
}
/*
* Check "type" is an item of the list or blob of the previous arg.
* Must not be used for the first argcheck_T entry.
*/
static int
@@ -323,10 +366,28 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
return check_type(expected, type, TRUE, context->arg_idx + 1);
}
/*
* Check "type" which is the third argument of extend().
*/
static int
arg_extend3(type_T *type, argcontext_T *context)
{
type_T *first_type = context->arg_types[context->arg_idx - 2];
if (first_type->tt_type == VAR_LIST)
return arg_number(type, context);
if (first_type->tt_type == VAR_DICT)
return arg_string(type, context);
return OK;
}
/*
* Lists of functions that check the argument types of a builtin function.
*/
argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
/*
@@ -567,7 +628,7 @@ static funcentry_T global_functions[] =
ret_any, FLOAT_FUNC(f_abs)},
{"acos", 1, 1, FEARG_1, NULL,
ret_float, FLOAT_FUNC(f_acos)},
{"add", 2, 2, FEARG_1, NULL,
{"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */,
ret_first_arg, f_add},
{"and", 2, 2, FEARG_1, NULL,
ret_number, f_and},
@@ -793,7 +854,7 @@ static funcentry_T global_functions[] =
ret_any, f_expand},
{"expandcmd", 1, 1, FEARG_1, NULL,
ret_string, f_expandcmd},
{"extend", 2, 3, FEARG_1, NULL,
{"extend", 2, 3, FEARG_1, arg23_extend,
ret_first_arg, f_extend},
{"feedkeys", 1, 2, FEARG_1, NULL,
ret_void, f_feedkeys},

View File

@@ -277,6 +277,7 @@ linelen(int *has_tab)
static char_u *sortbuf1;
static char_u *sortbuf2;
static int sort_lc; // sort using locale
static int sort_ic; // ignore case
static int sort_nr; // sort on number
static int sort_rx; // sort on regex instead of skipping it
@@ -307,7 +308,13 @@ typedef struct
} st_u;
} sorti_T;
static int sort_compare(const void *s1, const void *s2);
static int
string_compare(const void *s1, const void *s2)
{
if (sort_lc)
return strcoll((char *)s1, (char *)s2);
return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2);
}
static int
sort_compare(const void *s1, const void *s2)
@@ -350,8 +357,7 @@ sort_compare(const void *s1, const void *s2)
l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
: STRCMP(sortbuf1, sortbuf2);
result = string_compare(sortbuf1, sortbuf2);
}
// If two lines have the same value, preserve the original line order.
@@ -398,7 +404,7 @@ ex_sort(exarg_T *eap)
if (nrs == NULL)
goto sortend;
sort_abort = sort_ic = sort_rx = sort_nr = 0;
sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = 0;
#ifdef FEAT_FLOAT
sort_flt = 0;
#endif
@@ -409,6 +415,8 @@ ex_sort(exarg_T *eap)
;
else if (*p == 'i')
sort_ic = TRUE;
else if (*p == 'l')
sort_lc = TRUE;
else if (*p == 'r')
sort_rx = TRUE;
else if (*p == 'n')
@@ -614,8 +622,7 @@ ex_sort(exarg_T *eap)
change_occurred = TRUE;
s = ml_get(get_lnum);
if (!unique || i == 0
|| (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0)
if (!unique || i == 0 || string_compare(s, sortbuf1) != 0)
{
// Copy the line into a buffer, it may become invalid in
// ml_append(). And it's needed for "unique".

View File

@@ -1782,14 +1782,27 @@ do_one_cmd(
*/
cmd = ea.cmd;
#ifdef FEAT_EVAL
// In Vim9 script a colon is required before the range.
may_have_range = !vim9script || starts_with_colon;
// In Vim9 script a colon is required before the range. This may also be
// after command modifiers.
if (vim9script)
{
may_have_range = FALSE;
for (p = ea.cmd; p >= *cmdlinep; --p)
{
if (*p == ':')
may_have_range = TRUE;
if (p < ea.cmd && !VIM_ISWHITE(*p))
break;
}
}
else
may_have_range = TRUE;
if (may_have_range)
#endif
ea.cmd = skip_range(ea.cmd, TRUE, NULL);
#ifdef FEAT_EVAL
if (vim9script && !starts_with_colon)
if (vim9script && !may_have_range)
{
if (ea.cmd == cmd + 1 && *cmd == '$')
// should be "$VAR = val"

View File

@@ -179,9 +179,9 @@ static void SFdrawLists(int doScroll);
static void SFdrawList(int n, int doScroll);
static void SFclearList(int n, int doScroll);
static char SFstatChar(stat_T *statBuf);
static void SFmotionList(Widget w, int n, XMotionEvent *event);
static void SFmotionList(Widget w, XtPointer np, XMotionEvent *event, Boolean *cont);
static void SFvSliderMovedCallback(Widget w, int n, int nw);
static Boolean SFworkProc(void);
static Boolean SFworkProc(void *);
static int SFcompareEntries(const void *p, const void *q);
////////////////// xstat.h
@@ -798,19 +798,22 @@ SFsetText(char *path)
static void
SFbuttonPressList(
Widget w UNUSED,
int n UNUSED,
XButtonPressedEvent *event UNUSED)
Widget w UNUSED,
XtPointer np UNUSED,
XEvent *event UNUSED,
Boolean *cont UNUSED)
{
SFbuttonPressed = 1;
}
static void
SFbuttonReleaseList(
Widget w,
int n,
XButtonReleasedEvent *event)
Widget w UNUSED,
XtPointer np,
XEvent *event UNUSED,
Boolean *cont UNUSED)
{
long n = (long)np;
SFDir *dir;
SFbuttonPressed = 0;
@@ -823,7 +826,7 @@ SFbuttonReleaseList(
dir = &(SFdirs[SFdirPtr + n]);
SFreplaceText(dir,
dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
SFmotionList(w, n, (XMotionEvent *) event);
SFmotionList(w, (XtPointer)(long)n, (XMotionEvent *)event, 0);
}
}
@@ -1600,9 +1603,14 @@ SFnewInvertEntry(int n, XMotionEvent *event)
}
static void
SFenterList(Widget w UNUSED, int n, XEnterWindowEvent *event)
SFenterList(
Widget w UNUSED,
XtPointer np,
XEvent *event,
Boolean *cont UNUSED)
{
int nw;
long n = (long)np;
int nw;
// sanity
if (SFcurrentInvert[n] != -1)
@@ -1620,8 +1628,14 @@ SFenterList(Widget w UNUSED, int n, XEnterWindowEvent *event)
}
static void
SFleaveList(Widget w UNUSED, int n, XEvent *event UNUSED)
SFleaveList(
Widget w UNUSED,
XtPointer np,
XEvent *event UNUSED,
Boolean *cont UNUSED)
{
long n = (long)np;
if (SFcurrentInvert[n] != -1)
{
SFinvertEntry(n);
@@ -1630,8 +1644,13 @@ SFleaveList(Widget w UNUSED, int n, XEvent *event UNUSED)
}
static void
SFmotionList(Widget w UNUSED, int n, XMotionEvent *event)
SFmotionList(
Widget w UNUSED,
XtPointer np,
XMotionEvent *event UNUSED,
Boolean *cont UNUSED)
{
long n = (long)np;
int nw;
nw = SFnewInvertEntry(n, event);
@@ -1954,7 +1973,7 @@ SFpathAreaSelectedCallback(
}
static Boolean
SFworkProc(void)
SFworkProc(void *arg UNUSED)
{
SFDir *dir;
SFEntry *entry;

View File

@@ -44,12 +44,13 @@
# define PERL_NO_INLINE_FUNCTIONS
#endif
/* Work around for using MSVC and ActivePerl 5.18. */
#ifdef _MSC_VER
// Work around for using MSVC and ActivePerl 5.18.
# define __inline__ __inline
// Work around for using MSVC and Strawberry Perl 5.30.
# define __builtin_expect(expr, val) (expr)
// Work around for using MSVC and Strawberry Perl 5.32.
# define NO_THREAD_SAFE_LOCALE
#endif
#ifdef __GNUC__

View File

@@ -1516,6 +1516,7 @@ typedef struct
typedef struct
{
int item_compare_ic;
int item_compare_lc;
int item_compare_numeric;
int item_compare_numbers;
#ifdef FEAT_FLOAT
@@ -1594,10 +1595,10 @@ item_compare(const void *s1, const void *s2)
p2 = (char_u *)"";
if (!sortinfo->item_compare_numeric)
{
if (sortinfo->item_compare_ic)
res = STRICMP(p1, p2);
if (sortinfo->item_compare_lc)
res = strcoll((char *)p1, (char *)p2);
else
res = STRCMP(p1, p2);
res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);
}
else
{
@@ -1706,6 +1707,7 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
goto theend; // short list sorts pretty quickly
info.item_compare_ic = FALSE;
info.item_compare_lc = FALSE;
info.item_compare_numeric = FALSE;
info.item_compare_numbers = FALSE;
#ifdef FEAT_FLOAT
@@ -1773,6 +1775,11 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
info.item_compare_func = NULL;
info.item_compare_ic = TRUE;
}
else if (STRCMP(info.item_compare_func, "l") == 0)
{
info.item_compare_func = NULL;
info.item_compare_lc = TRUE;
}
}
}

View File

@@ -4340,7 +4340,7 @@ valid_spellfile(char_u *val)
char_u *s;
for (s = val; *s != NUL; ++s)
if (!vim_isfilec(*s) && *s != ',')
if (!vim_isfilec(*s) && *s != ',' && *s != ' ')
return FALSE;
return TRUE;
}

View File

@@ -4462,7 +4462,8 @@ modifiers2keycode(int modifiers, int *key, char_u *string)
if (modifiers != 0)
{
// Some keys have the modifier included. Need to handle that here to
// make mappings work.
// make mappings work. This may result in a special key, such as
// K_S_TAB.
*key = simplify_key(*key, &modifiers);
if (modifiers != 0)
{
@@ -4793,7 +4794,13 @@ handle_key_with_modifier(
// insert modifiers with KS_MODIFIER
new_slen = modifiers2keycode(modifiers, &key, string);
if (has_mbyte)
if (IS_SPECIAL(key))
{
string[new_slen++] = K_SPECIAL;
string[new_slen++] = KEY2TERMCAP0(key);
string[new_slen++] = KEY2TERMCAP1(key);
}
else if (has_mbyte)
new_slen += (*mb_char2bytes)(key, string + new_slen);
else
string[new_slen++] = key;

View File

@@ -130,7 +130,7 @@ let test_values = {
\ 'selectmode': [['', 'mouse', 'key,cmd'], ['xxx']],
\ 'sessionoptions': [['', 'blank', 'help,options,slash'], ['xxx']],
\ 'signcolumn': [['', 'auto', 'no'], ['xxx', 'no,yes']],
\ 'spellfile': [['', 'file.en.add'], ['xxx', '/tmp/file']],
\ 'spellfile': [['', 'file.en.add', '/tmp/dir\ with\ space/en.utf-8.add'], ['xxx', '/tmp/file']],
\ 'spelllang': [['', 'xxx', 'sr@latin'], ['not&lang', "that\\\rthere"]],
\ 'spelloptions': [['', 'camel'], ['xxx']],
\ 'spellsuggest': [['', 'best', 'double,33'], ['xxx']],

View File

@@ -15,6 +15,25 @@ func Test_sort_strings()
" numbers compared as strings
call assert_equal([1, 2, 3], sort([3, 2, 1]))
call assert_equal([13, 28, 3], sort([3, 28, 13]))
call assert_equal(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ'],
\ sort(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ']))
call assert_equal(['A', 'a', 'o', 'O', 'p', 'P', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'i'))
let lc = execute('language collate')
" With the following locales, the accentuated letters are ordered
" similarly to the non-accentuated letters...
if lc =~? '"\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8"'
call assert_equal(['a', 'A', 'ä', 'Ä', 'o', 'O', 'ô', 'Ô', 'œ', 'œ', 'p', 'P'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l'))
" ... whereas with a Swedish locale, the accentuated letters are ordered
" after Z.
elseif lc =~? '"sv.*utf-\?8"'
call assert_equal(['a', 'A', 'o', 'O', 'p', 'P', 'ä', 'Ä', 'œ', 'œ', 'ô', 'Ô'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l'))
endif
endfunc
func Test_sort_numeric()
@@ -1204,6 +1223,57 @@ func Test_sort_cmd()
\ },
\ ]
" With the following locales, the accentuated letters are ordered
" similarly to the non-accentuated letters...
let lc = execute('language collate')
if lc =~? '"\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8"'
let tests += [
\ {
\ 'name' : 'sort with locale',
\ 'cmd' : '%sort l',
\ 'input' : [
\ 'A',
\ 'E',
\ 'O',
\ 'À',
\ 'È',
\ 'É',
\ 'Ô',
\ 'Œ',
\ 'Z',
\ 'a',
\ 'e',
\ 'o',
\ 'à',
\ 'è',
\ 'é',
\ 'ô',
\ 'œ',
\ 'z'
\ ],
\ 'expected' : [
\ 'a',
\ 'A',
\ 'à',
\ 'À',
\ 'e',
\ 'E',
\ 'é',
\ 'É',
\ 'è',
\ 'È',
\ 'o',
\ 'O',
\ 'ô',
\ 'Ô',
\ 'œ',
\ 'Œ',
\ 'z',
\ 'Z'
\ ]
\ },
\ ]
endif
if has('float')
let tests += [
\ {

View File

@@ -2029,6 +2029,23 @@ func Test_modifyOtherKeys_mapped()
set timeoutlen&
endfunc
" Whether Shift-Tab sends "ESC [ Z" or "ESC [ 27 ; 2 ; 9 ~" is unpredictable,
" both should work.
func Test_modifyOtherKeys_shift_tab()
set timeoutlen=10
call setline(1, '')
call feedkeys("a\<C-K>" .. GetEscCodeCSI27("\t", '2') .. "\<Esc>", 'Lx!')
eval getline(1)->assert_equal('<S-Tab>')
call setline(1, '')
call feedkeys("a\<C-K>\<Esc>[Z\<Esc>", 'Lx!')
eval getline(1)->assert_equal('<S-Tab>')
set timeoutlen&
bwipe!
endfunc
func RunTest_mapping_works_with_shift(func)
new
set timeoutlen=10

View File

@@ -191,6 +191,24 @@ def Test_expand()
close
enddef
def Test_extend_arg_types()
assert_equal([1, 2, 3], extend([1, 2], [3]))
assert_equal([3, 1, 2], extend([1, 2], [3], 0))
assert_equal([1, 3, 2], extend([1, 2], [3], 1))
assert_equal(#{a: 1, b: 2, c: 3}, extend(#{a: 1, b: 2}, #{c: 3}))
assert_equal(#{a: 1, b: 4}, extend(#{a: 1, b: 2}, #{b: 4}))
assert_equal(#{a: 1, b: 2}, extend(#{a: 1, b: 2}, #{b: 4}, 'keep'))
CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, expected list<number> but got number')
CheckDefFailure(['extend([1, 2], ["x"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
CheckDefFailure(['extend(#{a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
CheckDefFailure(['extend(#{a: 1}, #{b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
CheckDefFailure(['extend(#{a: 1}, #{b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
enddef
def Test_extend_return_type()
var l = extend([1, 2], [3])
var res = 0

View File

@@ -2,6 +2,7 @@
source check.vim
source vim9.vim
source term_util.vim
source view_util.vim
def Test_edit_wildcards()
@@ -312,7 +313,7 @@ def Test_filter_is_not_modifier()
assert_equal([#{x: 3, y: 4}], tags)
enddef
def Test_filter_is_recognized()
def Test_command_modifier_filter()
var lines =<< trim END
final expected = "\nType Name Content\n c \"c piyo"
@a = 'hoge'
@@ -324,6 +325,135 @@ def Test_filter_is_recognized()
CheckDefAndScriptSuccess(lines)
enddef
def Test_win_command_modifiers()
assert_equal(1, winnr('$'))
set splitright
vsplit
assert_equal(2, winnr())
close
aboveleft vsplit
assert_equal(1, winnr())
close
set splitright&
vsplit
assert_equal(1, winnr())
close
belowright vsplit
assert_equal(2, winnr())
close
rightbelow vsplit
assert_equal(2, winnr())
close
browse set
assert_equal('option-window', expand('%'))
close
vsplit
botright split
assert_equal(3, winnr())
assert_equal(&columns, winwidth(0))
close
close
vsplit
topleft split
assert_equal(1, winnr())
assert_equal(&columns, winwidth(0))
close
close
gettabinfo()->len()->assert_equal(1)
tab split
gettabinfo()->len()->assert_equal(2)
tabclose
vertical new
assert_inrange(&columns / 2 - 2, &columns / 2 + 1, winwidth(0))
close
enddef
func Test_command_modifier_confirm()
CheckNotGui
CheckRunVimInTerminal
" Test for saving all the modified buffers
let lines =<< trim END
call setline(1, 'changed')
def Getout()
confirm write Xfile
enddef
END
call writefile(lines, 'Xconfirmscript')
call writefile(['empty'], 'Xfile')
let buf = RunVimInTerminal('-S Xconfirmscript', {'rows': 8})
call term_sendkeys(buf, ":call Getout()\n")
call WaitForAssert({-> assert_match('(Y)es, \[N\]o: ', term_getline(buf, 8))}, 1000)
call term_sendkeys(buf, "y")
call StopVimInTerminal(buf)
call assert_equal(['changed'], readfile('Xfile'))
call delete('Xfile')
call delete('Xconfirmscript')
endfunc
def Test_command_modifiers_keep()
if has('unix')
def DoTest(addRflag: bool, keepMarks: bool, hasMarks: bool)
new
setline(1, ['one', 'two', 'three'])
normal 1Gma
normal 2Gmb
normal 3Gmc
if addRflag
set cpo+=R
else
set cpo-=R
endif
if keepMarks
keepmarks :%!cat
else
:%!cat
endif
if hasMarks
assert_equal(1, line("'a"))
assert_equal(2, line("'b"))
assert_equal(3, line("'c"))
else
assert_equal(0, line("'a"))
assert_equal(0, line("'b"))
assert_equal(0, line("'c"))
endif
quit!
enddef
DoTest(false, false, true)
DoTest(true, false, false)
DoTest(false, true, true)
DoTest(true, true, true)
set cpo&vim
endif
# TODO
# lockmarks
# keepalt
# keeppatterns
# keepjumps
enddef
def Test_command_modifier_other()
# TODO
# hide
# noautocmd
# noswapfile
# sandbox
# silent
# silent!
# unsilent
# verbose
enddef
def Test_eval_command()
var from = 3
var to = 5

View File

@@ -1477,7 +1477,6 @@ def SilentlyUserError()
enddef
" This can't be a :def function, because the assert would not be reached.
" And this must not be inside a try/endtry.
func Test_ignore_silent_error()
let g:did_it = 'no'
call SilentlyError()
@@ -1490,6 +1489,23 @@ func Test_ignore_silent_error()
unlet g:did_it
endfunc
def Test_ignore_silent_error_in_filter()
var lines =<< trim END
vim9script
def Filter(winid: number, key: string): bool
if key == 'o'
silent! eval [][0]
return true
endif
return popup_filter_menu(winid, key)
enddef
popup_create('popup', #{filter: Filter})
feedkeys("o\r", 'xnt')
END
CheckScriptSuccess(lines)
enddef
def Fibonacci(n: number): number
if n < 2
return n

View File

@@ -750,6 +750,24 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1934,
/**/
1933,
/**/
1932,
/**/
1931,
/**/
1930,
/**/
1929,
/**/
1928,
/**/
1927,
/**/
1926,
/**/
1925,
/**/

View File

@@ -2642,6 +2642,7 @@ compile_call(
type_T *type = ((type_T **)stack->ga_data)[
stack->ga_len - 2];
// add() can be compiled to instructions if we know the type
if (type->tt_type == VAR_LIST)
{
// inline "add(list, item)" so that the type can be checked
@@ -6998,12 +6999,11 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
char *errormsg = NULL; // error message
cctx_T cctx;
garray_T *instr;
int called_emsg_before = called_emsg;
int did_emsg_before = did_emsg;
int ret = FAIL;
sctx_T save_current_sctx = current_sctx;
int save_estack_compiling = estack_compiling;
int do_estack_push;
int emsg_before = called_emsg;
int new_def_function = FALSE;
// When using a function that was compiled before: Free old instructions.
@@ -7107,7 +7107,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
// Bail out on the first error to avoid a flood of errors and report
// the right line number when inside try/catch.
if (emsg_before != called_emsg)
if (did_emsg_before != did_emsg)
goto erret;
if (line != NULL && *line == '|')
@@ -7127,7 +7127,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
// beyond the last line
break;
}
emsg_before = called_emsg;
CLEAR_FIELD(ea);
ea.cmdlinep = &line;
@@ -7175,10 +7174,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
continue;
}
break;
case ':':
starts_with_colon = TRUE;
break;
}
/*
@@ -7197,6 +7192,16 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
generate_cmdmods(&cctx, &local_cmdmod);
undo_cmdmod(&local_cmdmod);
// Check if there was a colon after the last command modifier or before
// the current position.
for (p = ea.cmd; p >= line; --p)
{
if (*p == ':')
starts_with_colon = TRUE;
if (p < ea.cmd && !VIM_ISWHITE(*p))
break;
}
// Skip ":call" to get to the function name.
p = ea.cmd;
if (checkforcmd(&ea.cmd, "call", 3))
@@ -7585,7 +7590,7 @@ erret:
if (errormsg != NULL)
emsg(errormsg);
else if (called_emsg == called_emsg_before)
else if (did_emsg == did_emsg_before)
emsg(_(e_compiling_def_function_failed));
}

View File

@@ -828,7 +828,7 @@ call_def_function(
int defcount = ufunc->uf_args.ga_len - argc;
sctx_T save_current_sctx = current_sctx;
int breakcheck_count = 0;
int called_emsg_before = called_emsg;
int did_emsg_before = did_emsg;
int save_suppress_errthrow = suppress_errthrow;
msglist_T **saved_msg_list = NULL;
msglist_T *private_msg_list = NULL;
@@ -853,7 +853,7 @@ call_def_function(
|| (ufunc->uf_def_status == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, FALSE, NULL) == FAIL))
{
if (called_emsg == called_emsg_before)
if (did_emsg == did_emsg_before)
semsg(_(e_function_is_not_compiled_str),
printable_func_name(ufunc));
return FAIL;
@@ -2869,6 +2869,10 @@ func_return:
continue;
on_error:
// If "emsg_silent" is set then ignore the error.
if (did_emsg == did_emsg_before && emsg_silent)
continue;
// If we are not inside a try-catch started here, abort execution.
if (trylevel <= trylevel_at_start)
goto failed;
@@ -2924,7 +2928,7 @@ failed_early:
// Not sure if this is necessary.
suppress_errthrow = save_suppress_errthrow;
if (ret != OK && called_emsg == called_emsg_before)
if (ret != OK && did_emsg == did_emsg_before)
semsg(_(e_unknown_error_while_executing_str),
printable_func_name(ufunc));
return ret;