From 0f113e4f7b698fc94c1a8377afdb7249329beaee Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Tue, 22 Feb 2022 11:04:50 +0000 Subject: [PATCH 01/24] patch 8.2.4437: vartabs test fails on MS-Windows Problem: Vartabs test fails on MS-Windows. Solution: Use iso8859-1 'encoding'. (Ken Takata, closes #9818) --- src/testdir/test_vartabs.vim | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index d21acfe3a7..74b07ba146 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -445,10 +445,10 @@ endfunc func Test_vartabstop_latin1() let save_encoding = &encoding new - set encoding=iso8859 - silent norm :se  + set encoding=iso8859-1 + silent exe "norm :se \\" set vartabstop=400 - norm i00  + exe "norm i00\t\" bwipe! let &encoding = save_encoding endfunc diff --git a/src/version.c b/src/version.c index 6eae5e66fd..7001029010 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4437, /**/ 4436, /**/ From ca0c1caa36823ea8e61184268d7337e79995352f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 12:08:07 +0000 Subject: [PATCH 02/24] patch 8.2.4438: crash on exit when using cmdline window Problem: Crash on exit when using cmdline window. Solution: Reset "cmdwin_type" before exiting. (closes #9817) --- src/testdir/test_exit.vim | 14 ++++++++++++++ src/ui.c | 3 +++ src/version.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim index 93b8f5171a..b42eebfa85 100644 --- a/src/testdir/test_exit.vim +++ b/src/testdir/test_exit.vim @@ -1,6 +1,7 @@ " Tests for exiting Vim. source shared.vim +source check.vim func Test_exiting() let after =<< trim [CODE] @@ -109,4 +110,17 @@ func Test_exit_code() call delete('Xtestout') endfunc +func Test_exit_error_reading_input() + CheckNotGui + + call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew\q:"], 'Xscript') + + if RunVim([], [], '< Xscript') + call assert_equal(['l = 1'], readfile('Xtestout')) + endif + call delete('Xscript') + call delete('Xtestout') +endfun + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/ui.c b/src/ui.c index a6cee804ad..bf6ea858b0 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1065,6 +1065,9 @@ read_error_exit(void) if (silent_mode) // Normal way to exit for "ex -s" getout(0); STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); +#ifdef FEAT_CMDWIN + cmdwin_type = 0; +#endif preserve_exit(); } diff --git a/src/version.c b/src/version.c index 7001029010..399aef93c2 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4438, /**/ 4437, /**/ From 1349bd712cf7d24dc65408c523dd7deb30224f80 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 12:34:28 +0000 Subject: [PATCH 03/24] patch 8.2.4439: accepting "iso8859" 'encoding' as "iso-8859-" Problem: Accepting "iso8859" 'encoding' as "iso-8859-". Solution: use "iso8859" as "iso-8859-1". --- src/mbyte.c | 3 ++- src/testdir/test_options.vim | 25 +++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/mbyte.c b/src/mbyte.c index 2f4edd53af..78230f65e7 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -318,6 +318,7 @@ enc_alias_table[] = { {"ansi", IDX_LATIN_1}, {"iso-8859-1", IDX_LATIN_1}, + {"iso-8859", IDX_LATIN_1}, {"latin2", IDX_ISO_2}, {"latin3", IDX_ISO_3}, {"latin4", IDX_ISO_4}, @@ -4523,7 +4524,7 @@ enc_canonize(char_u *enc) } // "iso-8859n" -> "iso-8859-n" - if (STRNCMP(p, "iso-8859", 8) == 0 && p[8] != '-') + if (STRNCMP(p, "iso-8859", 8) == 0 && isdigit(p[8])) { STRMOVE(p + 9, p + 8); p[8] = '-'; diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index 2af13d94f4..9ba2ce441e 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -445,6 +445,31 @@ func Test_set_errors() call assert_fails('set t_#-&', 'E522:') endfunc +func Test_set_encoding() + let save_encoding = &encoding + + set enc=iso8859-1 + call assert_equal('latin1', &enc) + set enc=iso8859_1 + call assert_equal('latin1', &enc) + set enc=iso-8859-1 + call assert_equal('latin1', &enc) + set enc=iso_8859_1 + call assert_equal('latin1', &enc) + set enc=iso88591 + call assert_equal('latin1', &enc) + set enc=iso8859 + call assert_equal('latin1', &enc) + set enc=iso-8859 + call assert_equal('latin1', &enc) + set enc=iso_8859 + call assert_equal('latin1', &enc) + call assert_fails('set enc=iso8858', 'E474:') + call assert_equal('latin1', &enc) + + let &encoding = save_encoding +endfunc + func CheckWasSet(name) let verb_cm = execute('verbose set ' .. a:name .. '?') call assert_match('Last set from.*test_options.vim', verb_cm) diff --git a/src/version.c b/src/version.c index 399aef93c2..23f45b5c17 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4439, /**/ 4438, /**/ From 6456fae9ba8e72c74b2c0c499eaf09974604ff30 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 13:37:31 +0000 Subject: [PATCH 04/24] patch 8.2.4440: crash with specific regexp pattern and string Problem: Crash with specific regexp pattern and string. Solution: Stop at the start of the string. --- src/regexp_bt.c | 5 +++++ src/testdir/test_regexp_utf8.vim | 12 ++++++++++-- src/version.c | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/regexp_bt.c b/src/regexp_bt.c index 5f5e58f834..4082f59d35 100644 --- a/src/regexp_bt.c +++ b/src/regexp_bt.c @@ -4615,6 +4615,11 @@ regmatch( if (rex.input == rex.line) { // backup to last char of previous line + if (rex.lnum == 0) + { + status = RA_NOMATCH; + break; + } --rex.lnum; rex.line = reg_getline(rex.lnum); // Just in case regrepeat() didn't count diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim index 674eee571d..9f5b288160 100644 --- a/src/testdir/test_regexp_utf8.vim +++ b/src/testdir/test_regexp_utf8.vim @@ -508,7 +508,6 @@ endfunc " Check that [[:upper:]] matches for automatic engine func Test_match_char_class_upper() new - let _engine=®expengine " Test 1: [[:upper:]]\{2,\} set regexpengine=0 @@ -549,7 +548,7 @@ func Test_match_char_class_upper() call assert_equal(4, searchcount().total, 'TEST 3 lower') " clean up - let ®expengine=_engine + set regexpengine=0 bwipe! endfunc @@ -561,4 +560,13 @@ func Test_match_invalid_byte() call delete('Xinvalid') endfunc +func Test_match_too_complicated() + set regexpengine=1 + exe "vsplit \xeb\xdb\x99" + silent! buf \&\zs*\zs*0 + bwipe! + set regexpengine=0 +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 23f45b5c17..809b03f3e5 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4440, /**/ 4439, /**/ From 16f6c8ac94d8412075060945aa90ba90be08656f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 15:12:14 +0000 Subject: [PATCH 05/24] patch 8.2.4441: Vim9: function argument of filter() not checked like map() Problem: Vim9: function argument of filter() not checked like map(). Solution: Also check the function argument of filter(). --- src/evalfunc.c | 166 ++++++++++++++---------------- src/testdir/test_vim9_builtin.vim | 66 ++++++++++-- src/version.c | 2 + 3 files changed, 137 insertions(+), 97 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 38a7aa27cd..69b4a23ac6 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -485,6 +485,80 @@ arg_list_or_dict_or_blob_or_string(type_T *type, type_T *decl_type UNUSED, argco return FAIL; } +/* + * Check second argument of map() or filter(). + */ + static int +check_map_filter_arg2(type_T *type, argcontext_T *context, int is_map) +{ + type_T *expected_member = NULL; + type_T *(args[2]); + type_T t_func_exp = {VAR_FUNC, 2, 0, 0, NULL, args}; + + if (context->arg_types[0].type_curr->tt_type == VAR_LIST + || context->arg_types[0].type_curr->tt_type == VAR_DICT) + { + // Use the declared type if possible, so that an error is given if + // a declared list changes type, but not if a constant list changes + // type. + if (context->arg_types[0].type_decl->tt_type == VAR_LIST + || context->arg_types[0].type_decl->tt_type == VAR_DICT) + expected_member = context->arg_types[0].type_decl->tt_member; + else + expected_member = context->arg_types[0].type_curr->tt_member; + } + else if (context->arg_types[0].type_curr->tt_type == VAR_STRING) + expected_member = &t_string; + else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB) + expected_member = &t_number; + + args[0] = NULL; + args[1] = &t_unknown; + if (type->tt_argcount != -1) + { + if (!(type->tt_argcount == 2 || (type->tt_argcount == 1 + && (type->tt_flags & TTFLAG_VARARGS)))) + { + emsg(_(e_invalid_number_of_arguments)); + return FAIL; + } + if (type->tt_flags & TTFLAG_VARARGS) + // check the argument types at runtime + t_func_exp.tt_argcount = -1; + else + { + if (context->arg_types[0].type_curr->tt_type == VAR_STRING + || context->arg_types[0].type_curr->tt_type == VAR_BLOB + || context->arg_types[0].type_curr->tt_type == VAR_LIST) + args[0] = &t_number; + else if (context->arg_types[0].type_decl->tt_type == VAR_DICT) + args[0] = &t_string; + if (args[0] != NULL) + args[1] = expected_member; + } + } + + if ((type->tt_member != &t_any && type->tt_member != &t_unknown) + || args[0] != NULL) + { + where_T where = WHERE_INIT; + + if (is_map) + t_func_exp.tt_member = expected_member == NULL + || type->tt_member == &t_any + || type->tt_member == &t_unknown + ? &t_any : expected_member; + else + t_func_exp.tt_member = &t_bool; + if (args[0] == NULL) + args[0] = &t_unknown; + + where.wt_index = 2; + return check_type(&t_func_exp, type, TRUE, where); + } + return OK; +} + /* * Check second argument of filter(): func must return a bool. */ @@ -498,22 +572,9 @@ arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) return OK; if (type->tt_type == VAR_FUNC) - { - if (!(type->tt_member->tt_type == VAR_BOOL - || type->tt_member->tt_type == VAR_NUMBER - || type->tt_member->tt_type == VAR_UNKNOWN - || type->tt_member->tt_type == VAR_ANY)) - { - arg_type_mismatch(&t_func_bool, type, context->arg_idx + 1); - return FAIL; - } - } - else - { - semsg(_(e_string_or_function_required_for_argument_nr), 2); - return FAIL; - } - return OK; + return check_map_filter_arg2(type, context, FALSE); + semsg(_(e_string_or_function_required_for_argument_nr), 2); + return FAIL; } /* @@ -529,76 +590,9 @@ arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) return OK; if (type->tt_type == VAR_FUNC) - { - type_T *expected_ret = NULL; - type_T *(args[2]); - type_T t_func_exp = {VAR_FUNC, 2, 0, 0, NULL, args}; - - if (context->arg_types[0].type_curr->tt_type == VAR_LIST - || context->arg_types[0].type_curr->tt_type == VAR_DICT) - { - // Use the declared type if possible, so that an error is given if - // a declared list changes type, but not if a constant list changes - // type. - if (context->arg_types[0].type_decl->tt_type == VAR_LIST - || context->arg_types[0].type_decl->tt_type == VAR_DICT) - expected_ret = context->arg_types[0].type_decl->tt_member; - else - expected_ret = context->arg_types[0].type_curr->tt_member; - } - else if (context->arg_types[0].type_curr->tt_type == VAR_STRING) - expected_ret = &t_string; - else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB) - expected_ret = &t_number; - - args[0] = NULL; - args[1] = &t_unknown; - if (type->tt_argcount != -1) - { - if (!(type->tt_argcount == 2 || (type->tt_argcount == 1 - && (type->tt_flags & TTFLAG_VARARGS)))) - { - emsg(_(e_invalid_number_of_arguments)); - return FAIL; - } - if (type->tt_flags & TTFLAG_VARARGS) - // check the argument types at runtime - t_func_exp.tt_argcount = -1; - else - { - if (context->arg_types[0].type_curr->tt_type == VAR_STRING - || context->arg_types[0].type_curr->tt_type == VAR_BLOB - || context->arg_types[0].type_curr->tt_type == VAR_LIST) - args[0] = &t_number; - else if (context->arg_types[0].type_decl->tt_type == VAR_DICT) - args[0] = &t_string; - if (args[0] != NULL) - args[1] = expected_ret; - } - } - - if ((type->tt_member != &t_any && type->tt_member != &t_unknown) - || args[0] != NULL) - { - where_T where = WHERE_INIT; - - t_func_exp.tt_member = expected_ret == NULL - || type->tt_member == &t_any - || type->tt_member == &t_unknown - ? &t_any : expected_ret; - if (args[0] == NULL) - args[0] = &t_unknown; - - where.wt_index = 2; - return check_type(&t_func_exp, type, TRUE, where); - } - } - else - { - semsg(_(e_string_or_function_required_for_argument_nr), 2); - return FAIL; - } - return OK; + return check_map_filter_arg2(type, context, TRUE); + semsg(_(e_string_or_function_required_for_argument_nr), 2); + return FAIL; } /* diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 41060e1a2e..b91e9f2dce 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1315,17 +1315,6 @@ def Wrong_dict_key_type(items: list): list enddef def Test_filter() - v9.CheckDefAndScriptFailure(['filter(1.1, "1")'], ['E1013: Argument 1: type mismatch, expected list but got float', 'E1251: List, Dictionary, Blob or String required for argument 1']) - v9.CheckDefAndScriptFailure(['filter([1, 2], 4)'], ['E1256: String or function required for argument 2', 'E1024: Using a Number as a String']) - - var lines =<< trim END - def F(i: number, v: any): string - return 'bad' - enddef - echo filter([1, 2, 3], F) - END - v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(...): bool', 'E1135: Using a String as a Bool:']) - assert_equal([], filter([1, 2, 3], '0')) assert_equal([1, 2, 3], filter([1, 2, 3], '1')) assert_equal({b: 20}, filter({a: 10, b: 20}, 'v:val == 20')) @@ -1335,6 +1324,61 @@ def Test_filter() return range(3)->filter(Odd) enddef assert_equal([1], GetFiltered()) + + v9.CheckDefAndScriptFailure(['filter(1.1, "1")'], ['E1013: Argument 1: type mismatch, expected list but got float', 'E1251: List, Dictionary, Blob or String required for argument 1']) + v9.CheckDefAndScriptFailure(['filter([1, 2], 4)'], ['E1256: String or function required for argument 2', 'E1024: Using a Number as a String']) + + var lines =<< trim END + def F(i: number, v: any): string + return 'bad' + enddef + echo filter([1, 2, 3], F) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?any): bool but got func(number, any): string', 'E1135: Using a String as a Bool:']) + + # check first function argument type + lines =<< trim END + var l = [1, 2, 3] + filter(l, (i: string, v: number) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): bool but got func(string, number): bool', 'E1013: Argument 1: type mismatch, expected string but got number']) + lines =<< trim END + var d = {a: 1} + filter(d, (i: number, v: number) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?string, ?number): bool but got func(number, number): bool', 'E1013: Argument 1: type mismatch, expected number but got string']) + lines =<< trim END + var b = 0z1122 + filter(b, (i: string, v: number) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): bool but got func(string, number): bool', 'E1013: Argument 1: type mismatch, expected string but got number']) + lines =<< trim END + var s = 'text' + filter(s, (i: string, v: string) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?string): bool but got func(string, string): bool', 'E1013: Argument 1: type mismatch, expected string but got number']) + + # check second function argument type + lines =<< trim END + var l = [1, 2, 3] + filter(l, (i: number, v: string) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): bool but got func(number, string): bool', 'E1013: Argument 2: type mismatch, expected string but got number']) + lines =<< trim END + var d = {a: 1} + filter(d, (i: string, v: string) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?string, ?number): bool but got func(string, string): bool', 'E1013: Argument 2: type mismatch, expected string but got number']) + lines =<< trim END + var b = 0z1122 + filter(b, (i: number, v: string) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): bool but got func(number, string): bool', 'E1013: Argument 2: type mismatch, expected string but got number']) + lines =<< trim END + var s = 'text' + filter(s, (i: number, v: number) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?string): bool but got func(number, number): bool', 'E1013: Argument 2: type mismatch, expected number but got string']) enddef def Test_filter_wrong_dict_key_type() diff --git a/src/version.c b/src/version.c index 809b03f3e5..000183401e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4441, /**/ 4440, /**/ From 70b9e4f4c3a62e325fd16ac108bd12feb026ede5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 15:24:51 +0000 Subject: [PATCH 06/24] patch 8.2.4442: test for error reading input fails on MS-Windows Problem: Test for error reading input fails on MS-Windows. Solution: Don't run the test on MS-Windows. --- src/testdir/test_exit.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim index b42eebfa85..68659fb1f4 100644 --- a/src/testdir/test_exit.vim +++ b/src/testdir/test_exit.vim @@ -112,6 +112,7 @@ endfunc func Test_exit_error_reading_input() CheckNotGui + CheckNotMSWindows call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew\q:"], 'Xscript') diff --git a/src/version.c b/src/version.c index 000183401e..deb79ebaea 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4442, /**/ 4441, /**/ From 2457b2bbc28cce6e8c1106d427b8e867d4f58cfa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 16:19:37 +0000 Subject: [PATCH 07/24] patch 8.2.4443: regexp pattern test fails on Mac Problem: Regexp pattern test fails on Mac. Solution: Do not use a swapfile for the buffer. --- src/testdir/test_regexp_utf8.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim index 9f5b288160..d88e26321d 100644 --- a/src/testdir/test_regexp_utf8.vim +++ b/src/testdir/test_regexp_utf8.vim @@ -562,7 +562,7 @@ endfunc func Test_match_too_complicated() set regexpengine=1 - exe "vsplit \xeb\xdb\x99" + exe "noswapfile vsplit \xeb\xdb\x99" silent! buf \&\zs*\zs*0 bwipe! set regexpengine=0 diff --git a/src/version.c b/src/version.c index deb79ebaea..05e5229180 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4443, /**/ 4442, /**/ From 68eab67119734ea1efc7cef1287276d969f2713a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 17:42:48 +0000 Subject: [PATCH 08/24] patch 8.2.4444: beep caused by test Problem: Beep caused by test. ASAN reports leaks. Solution: Do not put a NL at the end of the script. Make the text work on MS-Windows. Do not run the test with ASAN. --- src/testdir/test_exit.vim | 7 ++++--- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim index 68659fb1f4..a5cabf8131 100644 --- a/src/testdir/test_exit.vim +++ b/src/testdir/test_exit.vim @@ -112,11 +112,12 @@ endfunc func Test_exit_error_reading_input() CheckNotGui - CheckNotMSWindows + " The early exit causes memory not to be freed somehow + CheckNotAsan - call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew\q:"], 'Xscript') + call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew", "q:"], 'Xscript', 'b') - if RunVim([], [], '< Xscript') + if RunVim([], [], ' Date: Tue, 22 Feb 2022 18:48:11 +0000 Subject: [PATCH 09/24] patch 8.2.4445: exit test fails on MS-Windows anyway Problem: Exit test fails on MS-Windows anyway. Solution: Skip the test on MS-Windows. --- src/testdir/test_exit.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim index a5cabf8131..7e50e78ba4 100644 --- a/src/testdir/test_exit.vim +++ b/src/testdir/test_exit.vim @@ -112,6 +112,7 @@ endfunc func Test_exit_error_reading_input() CheckNotGui + CheckNotMSWindows " The early exit causes memory not to be freed somehow CheckNotAsan diff --git a/src/version.c b/src/version.c index 646f1edaaa..cb6e8e3e87 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4445, /**/ 4444, /**/ From fe73255c92b6cb54851f82fa32458340b736298d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 19:39:13 +0000 Subject: [PATCH 10/24] patch 8.2.4446: Vim9: cannot refer to a global function like a local one Problem: Vim9: cannot refer to a global function like a local one. Solution: When g:name is not a variable but a function, use a function reference. (closes #9826) --- src/testdir/test_vim9_builtin.vim | 15 +++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 27 ++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index b91e9f2dce..2c183fd3c8 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -427,6 +427,21 @@ def Test_call_call() call('reverse', [l]) l->assert_equal([1, 2, 3]) + var lines =<< trim END + vim9script + def Outer() + def g:Inner() + g:done = 'Inner' + enddef + call(g:Inner, []) + enddef + Outer() + assert_equal('Inner', g:done) + unlet g:done + END + v9.CheckScriptSuccess(lines) + delfunc g:Inner + v9.CheckDefExecAndScriptFailure(['call(123, [2])'], 'E1256: String or function required for argument 1') v9.CheckDefExecAndScriptFailure(['call(true, [2])'], 'E1256: String or function required for argument 1') v9.CheckDefAndScriptFailure(['call("reverse", 2)'], ['E1013: Argument 2: type mismatch, expected list but got number', 'E1211: List required for argument 2']) diff --git a/src/version.c b/src/version.c index cb6e8e3e87..253cbe809d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4446, /**/ 4445, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 3c23ad4110..beca9e723d 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2333,16 +2333,33 @@ load_namespace_var(ectx_T *ectx, isntype_T isn_type, isn_T *iptr) if (di == NULL) { + if (isn_type == ISN_LOADG) + { + ufunc_T *ufunc = find_func(iptr->isn_arg.string, TRUE); + + // g:Something could be a function + if (ufunc != NULL) + { + typval_T *tv = STACK_TV_BOT(0); + + ++ectx->ec_stack.ga_len; + tv->v_type = VAR_FUNC; + tv->vval.v_string = alloc(STRLEN(iptr->isn_arg.string) + 3); + if (tv->vval.v_string == NULL) + return FAIL; + STRCPY(tv->vval.v_string, "g:"); + STRCPY(tv->vval.v_string + 2, iptr->isn_arg.string); + return OK; + } + } SOURCING_LNUM = iptr->isn_lnum; - if (vim_strchr(iptr->isn_arg.string, - AUTOLOAD_CHAR) != NULL) + if (vim_strchr(iptr->isn_arg.string, AUTOLOAD_CHAR) != NULL) // no check if the item exists in the script but // isn't exported, it is too complicated - semsg(_(e_item_not_found_in_script_str), - iptr->isn_arg.string); + semsg(_(e_item_not_found_in_script_str), iptr->isn_arg.string); else semsg(_(e_undefined_variable_char_str), - namespace, iptr->isn_arg.string); + namespace, iptr->isn_arg.string); return FAIL; } else From afa048f0d4b5d63f2192c9ba340a9eb8b0822985 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 20:43:36 +0000 Subject: [PATCH 11/24] patch 8.2.4447: Vim9: can still use s:var in a compiled function Problem: Vim9: can still use s:var in a compiled function. Solution: Disallow using s:var for Vim9 script. (closes #9824) --- runtime/doc/vim9.txt | 12 +++++---- src/testdir/test_vim9_assign.vim | 45 +++++++++++++++++++++++++++++++- src/version.c | 2 ++ src/vim9compile.c | 6 +++++ src/vim9expr.c | 11 ++++++-- 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 987495a326..a5bcb3f443 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2022 Feb 18 +*vim9.txt* For Vim version 8.2. Last change: 2022 Feb 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -245,9 +245,11 @@ that the name interferes with builtin functions. *vim9-s-namespace* The use of the "s:" prefix is not supported at the Vim9 script level. All functions and variables without a prefix are script-local. -In :def functions the use of "s:" is optional. This is because in legacy -script the "s:" might be needed. Disallowing the use of "s:" only in a :def -function in Vim9 script would be a bit confusing. + +In :def functions the use of "s:" depends on the script: Script-local +variables and functions in a legacy script do use "s:", while in a Vim9 script +they do not use "s:". This matches what you see in the rest of the file. + In legacy functions the use of "s:" for script items is required, as before. In all cases the function must be defined before used. That is when it is @@ -1467,7 +1469,7 @@ strings: > # typename(mylist) == "list", no error There is a subtle difference between using a list constant directly and -through a variable declaraiton. Because of type inference, when using a list +through a variable declaration. Because of type inference, when using a list constant to initialize a variable, this also sets the declared type: > var mylist = [1, 2, 3] # typename(mylist) == "list" diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 82521c8888..44247add1f 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -220,7 +220,7 @@ def Test_assignment() enddef defcompile END - v9.CheckScriptFailure(lines, 'E1089:') + v9.CheckScriptFailure(lines, 'E1268:') g:inc_counter += 1 assert_equal(2, g:inc_counter) @@ -2460,6 +2460,49 @@ def Run_Test_declare_command_line() g:StopVimInTerminal(buf) enddef +def Test_using_s_var_in_function() + var lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + echo s:scriptlevel + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + echo s:scriptlevel + enddef + call s:SomeFunc() + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + s:scriptlevel = 456 + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + s:scriptlevel = 456 + enddef + call s:SomeFunc() + call assert_equal(456, s:scriptlevel) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 253cbe809d..97a8f6e48c 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4447, /**/ 4446, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 803f19c080..6eb6e160e2 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1331,6 +1331,12 @@ compile_lhs( char_u *rawname = lhs->lhs_name + (lhs->lhs_name[1] == ':' ? 2 : 0); + if (script_namespace && current_script_is_vim9()) + { + semsg(_(e_cannot_use_s_colon_in_vim9_script_str), + var_start); + return FAIL; + } if (is_decl) { if (script_namespace) diff --git a/src/vim9expr.c b/src/vim9expr.c index 46d14dc05e..1485bd93cf 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -422,8 +422,15 @@ compile_load( { case 'v': res = generate_LOADV(cctx, name, error); break; - case 's': if (is_expr && ASCII_ISUPPER(*name) - && find_func(name, FALSE) != NULL) + case 's': if (current_script_is_vim9()) + { + semsg(_(e_cannot_use_s_colon_in_vim9_script_str), + *arg); + vim_free(name); + return FAIL; + } + if (is_expr && ASCII_ISUPPER(*name) + && find_func(name, FALSE) != NULL) res = generate_funcref(cctx, name, FALSE); else res = compile_load_scriptvar(cctx, name, From b2c72359dce4c4027dc0c05844eb2e76ea947014 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 21:17:40 +0000 Subject: [PATCH 12/24] patch 8.2.4448: filetype detection is failing Problem: Filetype detection is failing. Solution: Do not use "s:" where it is no longer allowed. --- runtime/autoload/dist/ft.vim | 14 +++++++------- src/version.c | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index a8ca90080e..4f5b88a7f7 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -83,7 +83,7 @@ export def FTbas() setf freebasic elseif match(lines, qb64_preproc) > -1 setf qb64 - elseif match(lines, s:ft_visual_basic_content) > -1 + elseif match(lines, ft_visual_basic_content) > -1 setf vb else setf basic @@ -241,7 +241,7 @@ export def FTfrm() var lines = getline(1, min([line("$"), 5])) - if match(lines, s:ft_visual_basic_content) > -1 + if match(lines, ft_visual_basic_content) > -1 setf vb else setf form @@ -434,7 +434,7 @@ export def FTinc() setf php # Pascal supports // comments but they're vary rarely used for file # headers so assume POV-Ray - elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords + elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? ft_pascal_keywords setf pascal else FTasmsyntax() @@ -496,7 +496,7 @@ export def FTprogress_pascal() var lnum = 1 while lnum <= 10 && lnum < line('$') var line = getline(lnum) - if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords + if line =~ ft_pascal_comments || line =~? ft_pascal_keywords setf pascal return elseif line !~ '^\s*$' || line =~ '^/\*' @@ -514,7 +514,7 @@ export def FTpp() exe "setf " .. g:filetype_pp else var line = getline(nextnonblank(1)) - if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords + if line =~ ft_pascal_comments || line =~? ft_pascal_keywords setf pascal else setf puppet @@ -685,8 +685,8 @@ export def FTRules() endtry var dir = expand(':p:h') for line in config_lines - if line =~ s:ft_rules_udev_rules_pattern - var udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "") + if line =~ ft_rules_udev_rules_pattern + var udev_rules = substitute(line, ft_rules_udev_rules_pattern, '\1', "") if dir == udev_rules setf udevrules endif diff --git a/src/version.c b/src/version.c index 97a8f6e48c..1c99de56cc 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4448, /**/ 4447, /**/ From e843efcc3503b7af838dca3cb9dd2e17d4fc1672 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 21:54:44 +0000 Subject: [PATCH 13/24] patch 8.2.4449: vim9: function argument of sort() not checked at compile time Problem: vim9: function argument of sort() not checked at compile time. Solution: Add a compile time check. --- src/evalfunc.c | 39 ++++++++++++++++++++++++++++++- src/testdir/test_vim9_builtin.vim | 28 +++++++++++++++++++--- src/version.c | 2 ++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 69b4a23ac6..cea002f11c 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -595,6 +595,43 @@ arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) return FAIL; } +/* + * Check second argument of sort() and uniq(), the "how" argument. + */ + static int +arg_sort_how(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) +{ + if (type->tt_type == VAR_STRING + || type->tt_type == VAR_PARTIAL + || type == &t_unknown + || type == &t_any) + return OK; + + if (type->tt_type == VAR_FUNC) + { + type_T *(args[2]); + type_T t_func_exp = {VAR_FUNC, 2, 0, 0, &t_number, args}; + + if (context->arg_types[0].type_curr->tt_type == VAR_LIST) + args[0] = context->arg_types[0].type_curr->tt_member; + else + args[0] = &t_unknown; + if ((type->tt_member != &t_any && type->tt_member != &t_unknown) + || args[0] != &t_unknown) + { + where_T where = WHERE_INIT; + + args[1] = args[0]; + where.wt_index = 2; + return check_type(&t_func_exp, type, TRUE, where); + } + + return OK; + } + semsg(_(e_string_or_function_required_for_argument_nr), 2); + return FAIL; +} + /* * Check an expression argument, can be a string, funcref or partial. * Also accept a bool, a constant resulting from compiling a string argument. @@ -1006,7 +1043,7 @@ static argcheck_T arg23_settagstack[] = {arg_number, arg_dict_any, arg_string}; static argcheck_T arg02_sign_getplaced[] = {arg_buffer, arg_dict_any}; static argcheck_T arg45_sign_place[] = {arg_number, arg_string, arg_string, arg_buffer, arg_dict_any}; static argcheck_T arg23_slice[] = {arg_slice1, arg_number, arg_number}; -static argcheck_T arg13_sortuniq[] = {arg_list_any, NULL, arg_dict_any}; +static argcheck_T arg13_sortuniq[] = {arg_list_any, arg_sort_how, arg_dict_any}; static argcheck_T arg24_strpart[] = {arg_string, arg_number, arg_number, arg_bool}; static argcheck_T arg12_system[] = {arg_string, arg_str_or_nr_or_list}; static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 2c183fd3c8..7366b8c3f7 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -3796,19 +3796,41 @@ def Test_sort_argument() assert_equal([1, 2, 3, 4, 5, 6, 7, 8], l) END v9.CheckDefAndScriptSuccess(lines) - v9.CheckDefAndScriptFailure(['sort("a")'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1211: List required for argument 1']) - v9.CheckDefAndScriptFailure(['sort([1], "", [1])'], ['E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3']) + + lines =<< trim END + sort([1, 2, 3], (a: any, b: any) => 1) + END + v9.CheckDefAndScriptSuccess(lines) enddef def Test_sort_compare_func_fails() + v9.CheckDefAndScriptFailure(['sort("a")'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1211: List required for argument 1']) + v9.CheckDefAndScriptFailure(['sort([1], "", [1])'], ['E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3']) + var lines =<< trim END vim9script echo ['a', 'b', 'c']->sort((a: number, b: number) => 0) END writefile(lines, 'Xbadsort') assert_fails('source Xbadsort', ['E1013:', 'E702:']) - delete('Xbadsort') + + lines =<< trim END + var l = [1, 2, 3] + sort(l, (a: string, b: number) => 1) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): number but got func(string, number): number', 'E1013: Argument 1: type mismatch, expected string but got number']) + + lines =<< trim END + var l = ['a', 'b', 'c'] + sort(l, (a: string, b: number) => 1) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?string, ?string): number but got func(string, number): number', 'E1013: Argument 2: type mismatch, expected number but got string']) + + lines =<< trim END + sort([1, 2, 3], (a: number, b: number) => true) + END + v9.CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(?number, ?number): number but got func(number, number): bool', 'E1138: Using a Bool as a Number']) enddef def Test_spellbadword() diff --git a/src/version.c b/src/version.c index 1c99de56cc..2cc4155215 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4449, /**/ 4448, /**/ From 2afeb408310f4f0185ce5eec079b51a3fe415a33 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 22:17:00 +0000 Subject: [PATCH 14/24] patch 8.2.4450: list sort test fails Problem: List sort test fails. Solution: Pass a valid "how" argument. --- src/testdir/test_listdict.vim | 6 +++++- src/version.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 5337254fdb..889c571b00 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -934,6 +934,9 @@ endfunc " Tests for reverse(), sort(), uniq() func Test_reverse_sort_uniq() + func g:RetOne() + return 1 + endfunc let lines =<< trim END VAR l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l))) @@ -949,12 +952,13 @@ func Test_reverse_sort_uniq() call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n')) LET l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] - call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1)) + call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), g:RetOne())) call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l))) endif END call v9.CheckLegacyAndVim9Success(lines) + delfunc g:RetOne call assert_fails('call reverse("")', 'E899:') call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:') diff --git a/src/version.c b/src/version.c index 2cc4155215..5dfdaf4f03 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4450, /**/ 4449, /**/ From 9cd4c0fb98cb4fe6164e4e1751c21a5a5229b9cc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 22 Feb 2022 22:53:10 +0000 Subject: [PATCH 15/24] patch 8.2.4451: sort() fails when ignoring case Problem: sort() fails when ignoring case. Solution: Accept a number one argument in sort(). --- src/evalfunc.c | 1 + src/testdir/test_listdict.vim | 6 +----- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index cea002f11c..e02b757e95 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -603,6 +603,7 @@ arg_sort_how(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_STRING || type->tt_type == VAR_PARTIAL + || type->tt_type == VAR_NUMBER // 1 means ignore case || type == &t_unknown || type == &t_any) return OK; diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 889c571b00..5337254fdb 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -934,9 +934,6 @@ endfunc " Tests for reverse(), sort(), uniq() func Test_reverse_sort_uniq() - func g:RetOne() - return 1 - endfunc let lines =<< trim END VAR l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l))) @@ -952,13 +949,12 @@ func Test_reverse_sort_uniq() call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n')) LET l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] - call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), g:RetOne())) + call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1)) call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l))) endif END call v9.CheckLegacyAndVim9Success(lines) - delfunc g:RetOne call assert_fails('call reverse("")', 'E899:') call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:') diff --git a/src/version.c b/src/version.c index 5dfdaf4f03..6f91b848dc 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4451, /**/ 4450, /**/ From 2dada73a4ebffe2582af472ce362abd3116b58c9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 10:52:41 +0000 Subject: [PATCH 16/24] patch 8.2.4452: test for what 8.2.4436 fixes does not check for regression Problem: Test for what 8.2.4436 fixes does not check for regression. Solution: Set several options. (Ken Takata, closes #9830) --- src/testdir/test_vartabs.vim | 3 ++- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index 74b07ba146..e15a072f72 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -446,11 +446,12 @@ func Test_vartabstop_latin1() let save_encoding = &encoding new set encoding=iso8859-1 - silent exe "norm :se \\" + set compatible linebreak list revins smarttab set vartabstop=400 exe "norm i00\t\" bwipe! let &encoding = save_encoding + set nocompatible linebreak& list& revins& smarttab& vartabstop& endfunc diff --git a/src/version.c b/src/version.c index 6f91b848dc..1786ceb4dd 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4452, /**/ 4451, /**/ From 4791fcd82565adcc60b86830e0bb6cd5b6eea0a6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 12:06:00 +0000 Subject: [PATCH 17/24] patch 8.2.4453: :helpgrep may free an option that was not allocated Problem: :helpgrep may free an option that was not allocated. (Yegappan Lakshmanan) Solution: Check if the value was allocated. --- src/option.c | 8 ++++++++ src/proto/option.pro | 1 + src/quickfix.c | 5 ++++- src/testdir/test_quickfix.vim | 27 +++++++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/option.c b/src/option.c index 91ea4138d3..44a0520ad0 100644 --- a/src/option.c +++ b/src/option.c @@ -4479,6 +4479,14 @@ get_encoding_default(void) return (char_u *)NULL; } + int +is_option_allocated(char *name) +{ + int idx = findoption((char_u *)name); + + return idx >= 0 && (options[idx].flags & P_ALLOCED); +} + /* * Translate a string like "t_xx", "" or "" to a key number. * When "has_lt" is true there is a '<' before "*arg_arg". diff --git a/src/proto/option.pro b/src/proto/option.pro index 11f342c3f5..b58e79afef 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -41,6 +41,7 @@ char *set_option_value(char_u *name, long number, char_u *string, int opt_flags) char_u *get_term_code(char_u *tname); char_u *get_highlight_default(void); char_u *get_encoding_default(void); +int is_option_allocated(char *name); int makeset(FILE *fd, int opt_flags, int local_only); int makefoldset(FILE *fd); void clear_termoptions(void); diff --git a/src/quickfix.c b/src/quickfix.c index 998ec6ec3d..16790b0304 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -8235,6 +8235,7 @@ ex_helpgrep(exarg_T *eap) { regmatch_T regmatch; char_u *save_cpo; + int save_cpo_allocated; qf_info_T *qi = &ql_info; int new_qi = FALSE; char_u *au_name = NULL; @@ -8265,6 +8266,7 @@ ex_helpgrep(exarg_T *eap) // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; + save_cpo_allocated = is_option_allocated("cpo"); p_cpo = empty_option; incr_quickfix_busy(); @@ -8302,7 +8304,8 @@ ex_helpgrep(exarg_T *eap) // changed and restored, need to restore in the complicated way. if (*p_cpo == NUL) set_option_value((char_u *)"cpo", 0L, save_cpo, 0); - free_string_option(save_cpo); + if (save_cpo_allocated) + free_string_option(save_cpo); } if (updated) diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 7d2373b828..ccfa340f6c 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -745,6 +745,33 @@ def Test_helpgrep_vim9_restore_cpo() helpclose enddef +func Test_helpgrep_restore_cpo_aucmd() + let save_cpo = &cpo + augroup QF_Test + au! + autocmd BufNew * set cpo=acd + augroup END + + helpgrep quickfix + call assert_equal('acd', &cpo) + %bw! + + set cpo&vim + augroup QF_Test + au! + autocmd BufReadPost * set cpo= + augroup END + + helpgrep buffer + call assert_equal('', &cpo) + + augroup QF_Test + au! + augroup END + %bw! + let &cpo = save_cpo +endfunc + def Test_vim9_cexpr() var text = 'somefile:95:error' cexpr text diff --git a/src/version.c b/src/version.c index 1786ceb4dd..57f32cbe4a 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4453, /**/ 4452, /**/ From 6a8b13614e5bcb233d20403ae9f008ccba152be3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 23 Feb 2022 12:23:08 +0000 Subject: [PATCH 18/24] patch 8.2.4454: resetting cmdwin_type only for one situation Problem: Resetting cmdwin_type only for one situation. Solution: Reset cmdwin_type before closing windows. (closes #9822) --- src/testdir/test_exit.vim | 1 + src/ui.c | 3 --- src/version.c | 2 ++ src/window.c | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim index 7e50e78ba4..c05374cb86 100644 --- a/src/testdir/test_exit.vim +++ b/src/testdir/test_exit.vim @@ -119,6 +119,7 @@ func Test_exit_error_reading_input() call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew", "q:"], 'Xscript', 'b') if RunVim([], [], 'tp_next != NULL) tabpage_close(TRUE); From 2007dd49f5cb36f944cab1cfbceb0f864e625f74 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 13:17:47 +0000 Subject: [PATCH 19/24] patch 8.2.4455: accepting one and zero for second sort() argument is strange Problem: Accepting one and zero for the second sort() argument is strange. Solution: Disallow using one and zero in Vim9 script. --- runtime/doc/builtin.txt | 23 ++++++++++++----------- runtime/menu.vim | 4 ++-- src/evalfunc.c | 1 - src/list.c | 3 ++- src/testdir/test_listdict.vim | 12 +++++++++++- src/version.c | 2 ++ 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index e7707ca0d5..c3bacf940b 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -539,8 +539,8 @@ sin({expr}) Float sine of {expr} sinh({expr}) Float hyperbolic sine of {expr} slice({expr}, {start} [, {end}]) String, List or Blob slice of a String, List or Blob -sort({list} [, {func} [, {dict}]]) - List sort {list}, using {func} to compare +sort({list} [, {how} [, {dict}]]) + List sort {list}, compare with {how} sound_clear() none stop playing all sounds sound_playevent({name} [, {callback}]) Number play an event sound @@ -8033,21 +8033,22 @@ slice({expr}, {start} [, {end}]) *slice()* GetList()->slice(offset) -sort({list} [, {func} [, {dict}]]) *sort()* *E702* +sort({list} [, {how} [, {dict}]]) *sort()* *E702* Sort the items in {list} in-place. Returns {list}. If you want a list to remain unmodified make a copy first: > :let sortedlist = sort(copy(mylist)) -< When {func} is omitted, is empty or zero, then sort() uses the +< When {how} is omitted or is an string, then sort() uses the string representation of each item to sort on. Numbers sort after Strings, |Lists| after Numbers. For sorting text in the current buffer use |:sort|. - When {func} is given and it is '1' or 'i' then case is - ignored. + When {how} is given and it is 'i' then case is ignored. + In legacy script, for backwards compatibility, the value one + can be used to ignore case. Zero means to not ignore case. - When {func} is given and it is 'l' then the current collation + When {how} is given and it is 'l' then the current collation locale is used for ordering. Implementation details: strcoll() is used to compare strings. See |:language| check or set the collation locale. |v:collate| can also be used to check the @@ -8064,19 +8065,19 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702* < ['n', 'o', 'O', 'p', 'z', 'รถ'] ~ This does not work properly on Mac. - When {func} is given and it is 'n' then all items will be + When {how} 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 Funcrefs will be considered as being 0). - When {func} is given and it is 'N' then all items will be + When {how} is given and it is 'N' then all items will be sorted numerical. This is like 'n' but a string containing digits will be used as the number they represent. - When {func} is given and it is 'f' then all items will be + When {how} is given and it is 'f' then all items will be sorted numerical. All values must be a Number or a Float. - When {func} is a |Funcref| or a function name, this function + When {how} is a |Funcref| or a function name, this function is called to compare items. The function is invoked with two items as argument and must return zero if they are equal, 1 or bigger if the first one sorts after the second one, -1 or diff --git a/runtime/menu.vim b/runtime/menu.vim index 12924af6fb..602c4d5455 100644 --- a/runtime/menu.vim +++ b/runtime/menu.vim @@ -2,7 +2,7 @@ " You can also use this as a start for your own set of menus. " " Maintainer: Bram Moolenaar -" Last Change: 2022 Feb 04 +" Last Change: 2022 Feb 23 " Note that ":an" (short for ":anoremenu") is often used to make a menu work " in all modes and avoid side effects from mappings defined by the user. @@ -378,7 +378,7 @@ def s:SetupColorSchemes() n += globpath(&packpath, "pack/*/opt/*/colors/*.vim", 1, 1) # Ignore case for VMS and windows, sort on name - var names = sort(map(n, 'substitute(v:val, "\\c.*[/\\\\:\\]]\\([^/\\\\:]*\\)\\.vim", "\\1", "")'), 1) + var names = sort(map(n, 'substitute(v:val, "\\c.*[/\\\\:\\]]\\([^/\\\\:]*\\)\\.vim", "\\1", "")'), 'i') # define all the submenu entries var idx = 100 diff --git a/src/evalfunc.c b/src/evalfunc.c index e02b757e95..cea002f11c 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -603,7 +603,6 @@ arg_sort_how(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_STRING || type->tt_type == VAR_PARTIAL - || type->tt_type == VAR_NUMBER // 1 means ignore case || type == &t_unknown || type == &t_any) return OK; diff --git a/src/list.c b/src/list.c index 578d6f1155..88f3102530 100644 --- a/src/list.c +++ b/src/list.c @@ -2198,7 +2198,8 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) if (in_vim9script() && (check_for_list_arg(argvars, 0) == FAIL || (argvars[1].v_type != VAR_UNKNOWN - && check_for_opt_dict_arg(argvars, 2) == FAIL))) + && (check_for_string_or_func_arg(argvars, 1) == FAIL + || check_for_opt_dict_arg(argvars, 2) == FAIL)))) return; if (argvars[0].v_type != VAR_LIST) diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 5337254fdb..89b7f041ac 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -949,7 +949,7 @@ func Test_reverse_sort_uniq() call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n')) LET l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] - call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1)) + call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l))) endif @@ -961,6 +961,16 @@ func Test_reverse_sort_uniq() call assert_fails("call sort([1, 2], function('min'), 1)", "E715:") call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:") call assert_fails("call sort([1, 2], function('min'))", "E118:") + + let lines =<< trim END + call sort(['a', 'b'], 0) + END + call v9.CheckDefAndScriptFailure(lines, 'E1256: String or function required for argument 2') + + let lines =<< trim END + call sort(['a', 'b'], 1) + END + call v9.CheckDefAndScriptFailure(lines, 'E1256: String or function required for argument 2') endfunc " reduce a list, blob or string diff --git a/src/version.c b/src/version.c index 5da1833d25..b5d93fb2a7 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4455, /**/ 4454, /**/ From dd2dfb3cb00d47d2e8248c4e9d2cdf51e1574b79 Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Wed, 23 Feb 2022 14:25:17 +0000 Subject: [PATCH 20/24] patch 8.2.4456: terminal test may fail on some machines Problem: Terminal test may fail on some machines. Solution: Increase wait time. (Zdenek Dohnal, closes #9834) --- src/testdir/test_terminal.vim | 3 ++- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 233994275d..8e7525847a 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -715,7 +715,8 @@ endfunction func Test_terminal_noblock() let g:test_is_flaky = 1 let buf = term_start(&shell) - let wait_time = 5000 + " Starting a terminal can be slow, esp. on busy CI machines. + let wait_time = 7500 let letters = 'abcdefghijklmnopqrstuvwxyz' if has('bsd') || has('mac') || has('sun') " The shell or something else has a problem dealing with more than 1000 diff --git a/src/version.c b/src/version.c index b5d93fb2a7..0bd499131e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4456, /**/ 4455, /**/ From 33fc4a63071c03ad46636b345a814e7e6d8f4ae0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 18:07:38 +0000 Subject: [PATCH 21/24] patch 8.2.4457: the GPM library can only be linked statically Problem: The GPM library can only be linked statically. Solution: Make it possible to load the GPM library dynamically. (Damien) --- runtime/doc/various.txt | 1 + src/Makefile | 2 ++ src/config.h.in | 3 ++ src/configure.ac | 16 ++++++---- src/evalfunc.c | 6 +++- src/feature.h | 6 ++++ src/os_unix.c | 68 ++++++++++++++++++++++++++++++++++++++++- src/proto/os_unix.pro | 1 + src/version.c | 6 ++++ 9 files changed, 101 insertions(+), 8 deletions(-) diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 5b35dca923..9ca65170f0 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -410,6 +410,7 @@ T *+mouse* Mouse handling |mouse-using| N *+mouseshape* |'mouseshape'| B *+mouse_dec* Unix only: Dec terminal mouse handling |dec-mouse| N *+mouse_gpm* Unix only: Linux console mouse handling |gpm-mouse| +m *+mouse_gpm/dyn* Same as |+mouse_gpm| with optional library dependency |/dyn| N *+mouse_jsbterm* JSB mouse handling |jsbterm-mouse| B *+mouse_netterm* Unix only: netterm mouse handling |netterm-mouse| N *+mouse_pterm* QNX only: pterm mouse handling |qnx-terminal| diff --git a/src/Makefile b/src/Makefile index 8b0b268789..24d39e8d0d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -526,6 +526,8 @@ CClink = $(CC) # though you have gpm libraries and includes. # For Debian/Ubuntu gpm support requires the libgpm-dev package. #CONF_OPT_GPM = --disable-gpm +# Use this to enable dynamic loading of the GPM library. +#CONF_OPT_GPM = --enable-gpm=dynamic # sysmouse - For mouse support on FreeBSD and DragonFly console via sysmouse # Uncomment this when you do not want do include sysmouse support, even diff --git a/src/config.h.in b/src/config.h.in index 20339de8a7..2653e8dda5 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -507,3 +507,6 @@ /* Define if _SC_SIGSTKSZ is available via sysconf() */ #undef HAVE_SYSCONF_SIGSTKSZ + +/* Define if you want to load libgpm dynamically */ +#undef DYNAMIC_GPM diff --git a/src/configure.ac b/src/configure.ac index 67b376a49e..4dd74fc2a8 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4096,13 +4096,13 @@ if test "x$GTK_CFLAGS" != "x"; then LIBS="$ac_save_LIBS" fi -AC_MSG_CHECKING(--disable-gpm argument) +AC_MSG_CHECKING(--enable-gpm argument) AC_ARG_ENABLE(gpm, - [ --disable-gpm Don't use gpm (Linux mouse daemon).], , + [ --enable-gpm=OPTS Use gpm (Linux mouse daemon). default=yes OPTS=yes/no/dynamic], , [enable_gpm="yes"]) -if test "$enable_gpm" = "yes"; then - AC_MSG_RESULT(no) +if test "$enable_gpm" = "yes" -o "$enable_gpm" = "dynamic"; then + AC_MSG_RESULT($enable_gpm) dnl Checking if gpm support can be compiled AC_CACHE_CHECK([for gpm], vi_cv_have_gpm, [olibs="$LIBS" ; LIBS="-lgpm"] @@ -4117,11 +4117,15 @@ if test "$enable_gpm" = "yes"; then [LIBS="$olibs"] ) if test $vi_cv_have_gpm = yes; then - LIBS="$LIBS -lgpm" + if test "$enable_gpm" = "yes"; then + LIBS="$LIBS -lgpm" + else + AC_DEFINE(DYNAMIC_GPM) + fi AC_DEFINE(HAVE_GPM) fi else - AC_MSG_RESULT(yes) + AC_MSG_RESULT(no) fi AC_MSG_CHECKING(--disable-sysmouse argument) diff --git a/src/evalfunc.c b/src/evalfunc.c index cea002f11c..eb42269cfa 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5786,7 +5786,7 @@ f_has(typval_T *argvars, typval_T *rettv) #endif }, {"mouse_gpm", -#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM) +#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM) && !defined(DYNAMIC_GPM) 1 #else 0 @@ -6391,6 +6391,10 @@ f_has(typval_T *argvars, typval_T *rettv) #if defined(FEAT_TERMINAL) && defined(MSWIN) else if (STRICMP(name, "terminal") == 0) n = terminal_enabled(); +#endif +#ifdef DYNAMIC_GPM + else if (STRICMP(name, "mouse_gpm") == 0) + n = gpm_available(); #endif } diff --git a/src/feature.h b/src/feature.h index 65185a2176..9564f8e100 100644 --- a/src/feature.h +++ b/src/feature.h @@ -952,6 +952,12 @@ */ #if defined(FEAT_NORMAL) && defined(HAVE_GPM) # define FEAT_MOUSE_GPM +/* + * +mouse_gpm/dyn Load libgpm dynamically. + */ +# ifndef DYNAMIC_GPM +// # define DYNAMIC_GPM +# endif #endif #if defined(FEAT_NORMAL) && defined(HAVE_SYSMOUSE) diff --git a/src/os_unix.c b/src/os_unix.c index a6f3a6c484..d36eb46a2c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -55,7 +55,25 @@ static int selinux_enabled = -1; #endif #ifdef FEAT_MOUSE_GPM + # include + +# ifdef DYNAMIC_GPM +# define Gpm_Open (*dll_Gpm_Open) +# define Gpm_Close (*dll_Gpm_Close) +# define Gpm_GetEvent (*dll_Gpm_GetEvent) +# define gpm_flag (dll_gpm_flag != NULL ? *dll_gpm_flag : 0) +# define gpm_fd (dll_gpm_fd != NULL ? *dll_gpm_fd : -1) + +static int (*dll_Gpm_Open) (Gpm_Connect *, int); +static int (*dll_Gpm_Close) (void); +static int (*dll_Gpm_GetEvent) (Gpm_Event *); +static int *dll_gpm_flag; +static int *dll_gpm_fd; + +static void *libgpm_hinst; +# endif + // contains defines conflicting with "keymap.h", // I just copied relevant defines here. A cleaner solution would be to put gpm // code into separate file and include there linux/keyboard.h @@ -6446,7 +6464,7 @@ select_eintr: } # endif # ifdef FEAT_MOUSE_GPM - if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0) + if (ret > 0 && check_for_gpm != NULL && gpm_flag && gpm_fd >= 0) { if (FD_ISSET(gpm_fd, &efds)) gpm_close(); @@ -7172,6 +7190,49 @@ mch_rename(const char *src, const char *dest) #endif // !HAVE_RENAME #if defined(FEAT_MOUSE_GPM) || defined(PROTO) +# if defined(DYNAMIC_GPM) || defined(PROTO) +/* + * Initialize Gpm's symbols for dynamic linking. + * Must be called only if libgpm_hinst is NULL. + */ + static int +load_libgpm(void) +{ + libgpm_hinst = dlopen("libgpm.so", RTLD_LAZY|RTLD_GLOBAL); + + if (libgpm_hinst == NULL) + { + if (p_verbose > 0) + smsg_attr(HL_ATTR(HLF_W), + _("Could not load gpm library: %s"), dlerror()); + return FAIL; + } + + if ( + (dll_Gpm_Open = dlsym(libgpm_hinst, "Gpm_Open")) == NULL + || (dll_Gpm_Close = dlsym(libgpm_hinst, "Gpm_Close")) == NULL + || (dll_Gpm_GetEvent = dlsym(libgpm_hinst, "Gpm_GetEvent")) == NULL + || (dll_gpm_flag = dlsym(libgpm_hinst, "gpm_flag")) == NULL + || (dll_gpm_fd = dlsym(libgpm_hinst, "gpm_fd")) == NULL + ) + { + semsg(_(e_could_not_load_library_str_str), "gpm", dlerror()); + dlclose(libgpm_hinst); + libgpm_hinst = NULL; + dll_gpm_flag = NULL; + dll_gpm_fd = NULL; + return FAIL; + } + return OK; +} + + int +gpm_available(void) +{ + return libgpm_hinst != NULL || load_libgpm() == OK; +} +# endif // DYNAMIC_GPM + /* * Initializes connection with gpm (if it isn't already opened) * Return 1 if succeeded (or connection already opened), 0 if failed @@ -7181,6 +7242,11 @@ gpm_open(void) { static Gpm_Connect gpm_connect; // Must it be kept till closing ? +#ifdef DYNAMIC_GPM + if (!gpm_available()) + return 0; +#endif + if (!gpm_flag) { gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN); diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index ee22b4a422..7dd8e231bc 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -85,4 +85,5 @@ void clip_xterm_set_selection(Clipboard_T *cbd); int xsmp_handle_requests(void); void xsmp_init(void); void xsmp_close(void); +int gpm_available(void); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 0bd499131e..85af241730 100644 --- a/src/version.c +++ b/src/version.c @@ -375,7 +375,11 @@ static char *(features[]) = "-mouse_dec", # endif # ifdef FEAT_MOUSE_GPM +# ifdef DYNAMIC_GPM + "+mouse_gpm/dyn", +# else "+mouse_gpm", +# endif # else "-mouse_gpm", # endif @@ -750,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4457, /**/ 4456, /**/ From 6e1a38745f794715dc624399c318f513b54797c4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 19:11:49 +0000 Subject: [PATCH 22/24] patch 8.2.4458: Vim9: compiling filter() call fails with unknown arguments Problem: Vim9: compiling filter() call fails with funcref that has unknown arguments. Solution: Do not check the arguments if they are unknown at compile time. (closes #9835) --- src/evalfunc.c | 2 ++ src/testdir/test_vim9_builtin.vim | 13 ++++++++++++- src/version.c | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index eb42269cfa..e8ed4bab04 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -552,6 +552,8 @@ check_map_filter_arg2(type_T *type, argcontext_T *context, int is_map) t_func_exp.tt_member = &t_bool; if (args[0] == NULL) args[0] = &t_unknown; + if (type->tt_argcount == -1) + t_func_exp.tt_argcount = -1; where.wt_index = 2; return check_type(&t_func_exp, type, TRUE, where); diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 7366b8c3f7..dfec991f8d 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1340,10 +1340,21 @@ def Test_filter() enddef assert_equal([1], GetFiltered()) + var lines =<< trim END + vim9script + def Func(): list + var MatchWord: func: bool = (_, v) => true + var l = ['xxx'] + return l->filter(MatchWord) + enddef + assert_equal(['xxx'], Func()) + END + v9.CheckScriptSuccess(lines) + v9.CheckDefAndScriptFailure(['filter(1.1, "1")'], ['E1013: Argument 1: type mismatch, expected list but got float', 'E1251: List, Dictionary, Blob or String required for argument 1']) v9.CheckDefAndScriptFailure(['filter([1, 2], 4)'], ['E1256: String or function required for argument 2', 'E1024: Using a Number as a String']) - var lines =<< trim END + lines =<< trim END def F(i: number, v: any): string return 'bad' enddef diff --git a/src/version.c b/src/version.c index 85af241730..800925df98 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4458, /**/ 4457, /**/ From fa02616718103be3f9e13e26d57905d4eddf836d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 21:03:32 +0000 Subject: [PATCH 23/24] patch 8.2.4459: Vim9: compiling sort() call fails with unknown arguments Problem: Vim9: compiling sort() call fails with a funcref that has unknown arguments. Solution: Do not check the arguments if they are unknown at compile time. (closes #9835) --- src/evalfunc.c | 2 ++ src/testdir/test_vim9_builtin.vim | 11 +++++++++++ src/version.c | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/evalfunc.c b/src/evalfunc.c index e8ed4bab04..1b93200367 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -624,6 +624,8 @@ arg_sort_how(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) where_T where = WHERE_INIT; args[1] = args[0]; + if (type->tt_argcount == -1) + t_func_exp.tt_argcount = -1; where.wt_index = 2; return check_type(&t_func_exp, type, TRUE, where); } diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index dfec991f8d..7577aecd2a 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -3812,6 +3812,17 @@ def Test_sort_argument() sort([1, 2, 3], (a: any, b: any) => 1) END v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + vim9script + def SortedList(): list + var Lambda: func: number = (a, b): number => a - b + var l = [3, 2, 1] + return l->sort(Lambda) + enddef + SortedList()->assert_equal([1, 2, 3]) + END + v9.CheckScriptSuccess(lines) enddef def Test_sort_compare_func_fails() diff --git a/src/version.c b/src/version.c index 800925df98..f8fb3139c9 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4459, /**/ 4458, /**/ From dea5ab0fc5bb51105078d5349f987496b1aa8d6f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Feb 2022 22:12:02 +0000 Subject: [PATCH 24/24] patch 8.2.4460: Vim9: wrong error for defining dict function Problem: Vim9: wrong error for defining dict function. Solution: Explicitly check for trying to define a dict function. (closes 9827) --- src/errors.h | 3 +- src/testdir/test_vim9_func.vim | 57 ++++++++++++++++++++++++++++++++++ src/userfunc.c | 17 ++++++++-- src/version.c | 2 ++ src/vim9compile.c | 6 +++- 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/errors.h b/src/errors.h index 5f2685ab3e..72c0d1284f 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3010,7 +3010,8 @@ EXTERN char e_variable_arguments_type_must_be_list_str[] INIT(= N_("E1180: Variable arguments type must be a list: %s")); EXTERN char e_cannot_use_underscore_here[] INIT(= N_("E1181: Cannot use an underscore here")); -// E1182 unused +EXTERN char e_cannot_define_dict_func_in_vim9_script_str[] + INIT(= N_("E1182: Cannot define a dict function in Vim9 script: %s")); EXTERN char e_cannot_use_range_with_assignment_operator_str[] INIT(= N_("E1183: Cannot use a range with an assignment operator: %s")); #endif diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 81a67d97fb..74883975bb 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -106,6 +106,63 @@ def Test_wrong_function_name() enddef END v9.CheckScriptFailure(lines, 'E1267:') + + lines =<< trim END + vim9script + var Object = {} + function Object.Method() + endfunction + END + v9.CheckScriptFailure(lines, 'E1182:') + + lines =<< trim END + vim9script + var Object = {} + def Object.Method() + enddef + END + v9.CheckScriptFailure(lines, 'E1182:') + + lines =<< trim END + vim9script + g:Object = {} + function g:Object.Method() + endfunction + END + v9.CheckScriptFailure(lines, 'E1182:') + + lines =<< trim END + let s:Object = {} + def Define() + function s:Object.Method() + endfunction + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1182:') + delfunc g:Define + + lines =<< trim END + let s:Object = {} + def Define() + def Object.Method() + enddef + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1182:') + delfunc g:Define + + lines =<< trim END + let g:Object = {} + def Define() + function g:Object.Method() + endfunction + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1182:') + delfunc g:Define enddef def Test_autoload_name_mismatch() diff --git a/src/userfunc.c b/src/userfunc.c index 3a66d27324..ed2fb8668c 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -4268,10 +4268,21 @@ define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free) } else { - if (vim9script && p[0] == 's' && p[1] == ':') + if (vim9script) { - semsg(_(e_cannot_use_s_colon_in_vim9_script_str), p); - return NULL; + if (p[0] == 's' && p[1] == ':') + { + semsg(_(e_cannot_use_s_colon_in_vim9_script_str), p); + return NULL; + } + p = to_name_end(p, TRUE); + if (*skipwhite(p) == '.' && vim_strchr(p, '(') != NULL) + { + semsg(_(e_cannot_define_dict_func_in_vim9_script_str), + eap->arg); + return NULL; + } + p = eap->arg; } name = save_function_name(&p, &is_global, eap->skip, diff --git a/src/version.c b/src/version.c index f8fb3139c9..a34bad1e75 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4460, /**/ 4459, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 6eb6e160e2..898712396e 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -831,7 +831,11 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free) { if (!ends_excmd2(name_start, name_end)) { - semsg(_(e_invalid_command_str), eap->cmd); + if (*skipwhite(name_end) == '.') + semsg(_(e_cannot_define_dict_func_in_vim9_script_str), + eap->cmd); + else + semsg(_(e_invalid_command_str), eap->cmd); return NULL; }