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/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/doc/various.txt b/runtime/doc/various.txt index 59ebf2a8ff..91c7bb006b 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -411,6 +411,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/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/runtime/menu.vim b/runtime/menu.vim index e134c0826e..30395463b1 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. @@ -443,7 +443,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/Makefile b/src/Makefile index 9c443b9b67..19685fb969 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 08878794f4..a1ad83fcde 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4294,13 +4294,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"] @@ -4315,11 +4315,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/errors.h b/src/errors.h index 9dd1d50a85..ff0b4c9779 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3015,7 +3015,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/evalfunc.c b/src/evalfunc.c index 8780f4ad9f..9741ef0413 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -485,6 +485,82 @@ 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; + if (type->tt_argcount == -1) + t_func_exp.tt_argcount = -1; + + 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 +574,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; } /* @@ -521,6 +584,24 @@ arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) */ static int arg_map_func(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) + return check_map_filter_arg2(type, context, TRUE); + semsg(_(e_string_or_function_required_for_argument_nr), 2); + 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 @@ -530,75 +611,29 @@ arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) 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; - } - } + 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] != NULL) + || args[0] != &t_unknown) { 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; - + 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); } + + return OK; } - else - { - semsg(_(e_string_or_function_required_for_argument_nr), 2); - return FAIL; - } - return OK; + semsg(_(e_string_or_function_required_for_argument_nr), 2); + return FAIL; } /* @@ -1012,7 +1047,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}; @@ -5769,7 +5804,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 @@ -6395,6 +6430,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 18d5c75e8a..8e7ec86f63 100644 --- a/src/feature.h +++ b/src/feature.h @@ -964,6 +964,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/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/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/option.c b/src/option.c index 29a014ec83..567d37e616 100644 --- a/src/option.c +++ b/src/option.c @@ -4587,6 +4587,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/os_unix.c b/src/os_unix.c index 4cca07e021..11e8caf36d 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 @@ -6468,7 +6486,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(); @@ -7194,6 +7212,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 @@ -7203,6 +7264,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/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/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/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/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_exit.vim b/src/testdir/test_exit.vim index 93b8f5171a..c05374cb86 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,21 @@ func Test_exit_code() call delete('Xtestout') 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', 'b') + + if RunVim([], [], '" bwipe! let &encoding = save_encoding + set nocompatible linebreak& list& revins& smarttab& vartabstop& endfunc 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/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 41060e1a2e..7577aecd2a 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']) @@ -1315,17 +1330,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 +1339,72 @@ def Test_filter() return range(3)->filter(Odd) 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']) + + 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() @@ -3737,19 +3807,52 @@ 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) + + 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() + 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/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 6bf5e95243..22ff79746a 100644 --- a/src/version.c +++ b/src/version.c @@ -380,7 +380,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 @@ -765,6 +769,54 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4460, +/**/ + 4459, +/**/ + 4458, +/**/ + 4457, +/**/ + 4456, +/**/ + 4455, +/**/ + 4454, +/**/ + 4453, +/**/ + 4452, +/**/ + 4451, +/**/ + 4450, +/**/ + 4449, +/**/ + 4448, +/**/ + 4447, +/**/ + 4446, +/**/ + 4445, +/**/ + 4444, +/**/ + 4443, +/**/ + 4442, +/**/ + 4441, +/**/ + 4440, +/**/ + 4439, +/**/ + 4438, +/**/ + 4437, /**/ 4436, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 803f19c080..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; } @@ -1331,6 +1335,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/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 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, diff --git a/src/window.c b/src/window.c index 7cf1431f41..0a51a26202 100644 --- a/src/window.c +++ b/src/window.c @@ -2861,6 +2861,10 @@ win_free_all(void) { int dummy; +#ifdef FEAT_CMDWIN + // avoid an error for switching tabpage with the cmdline window open + cmdwin_type = 0; +#endif while (first_tabpage->tp_next != NULL) tabpage_close(TRUE);