From 127950241e84c822d3c50f46a00d42a70d2d5cb6 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Mon, 28 Jun 2021 20:53:58 +0200 Subject: [PATCH 01/38] patch 8.2.3071: shell options are not set properly for PowerShell Problem: Shell options are not set properly for PowerShell. Solution: Use better option defaults. (Mike Willams, closes #8459) --- runtime/doc/eval.txt | 11 +++++--- runtime/doc/options.txt | 56 ++++++++++++++++++++++---------------- runtime/doc/os_dos.txt | 45 ++++++++++++++++++++++++++++-- src/fileio.c | 5 ++-- src/misc2.c | 49 ++++++++++++++++++++++++++------- src/option.c | 53 +++++++++++++++++++++++++++++++++--- src/os_win32.c | 3 +- src/testdir/test_shell.vim | 31 +++++++++++++++++++-- src/version.c | 2 ++ 9 files changed, 206 insertions(+), 49 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 4356381580..7fb2534538 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9878,9 +9878,11 @@ sha256({string}) *sha256()* shellescape({string} [, {special}]) *shellescape()* Escape {string} for use as a shell command argument. - On MS-Windows, when 'shellslash' is not set, it will enclose - {string} in double quotes and double all double quotes within - {string}. + On MS-Windows, when the 'shell' contains powershell then it + will enclose {string} in single quotes and will double up all + internal single quotes. With other values for 'shell' when + 'shellslash' is not set, it will enclose {string} in double + quotes and double all double quotes within {string}. Otherwise it will enclose {string} in single quotes and replace all "'" with "'\''". @@ -11040,7 +11042,8 @@ tempname() *tempname()* *temp-file-name* :exe "redir > " . tmpfile < For Unix, the file will be in a private directory |tempfile|. For MS-Windows forward slashes are used when the 'shellslash' - option is set or when 'shellcmdflag' starts with '-'. + option is set or when 'shellcmdflag' starts with '-' except + when when 'shell' contains powershell. term_ functions are documented here: |terminal-function-details| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 05489d7f63..b958cf63ed 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6594,23 +6594,25 @@ A jump table for the options with a short description can be found at |Q_op|. *'shellcmdflag'* *'shcf'* 'shellcmdflag' 'shcf' string (default: "-c"; - Win32, when 'shell' does not contain "sh" + Win32, when 'shell' contains "powershell": + "-Command", or when it does not contain "sh" somewhere: "/c") global Flag passed to the shell to execute "!" and ":!" commands; e.g., - "bash.exe -c ls" or "cmd.exe /c dir". For MS-Windows, the default is - set according to the value of 'shell', to reduce the need to set this - option by the user. + "bash.exe -c ls", "powershell.exe -Command dir", or "cmd.exe /c dir". + For MS-Windows, the default is set according to the value of 'shell', + to reduce the need to set this option by the user. On Unix it can have more than one flag. Each white space separated part is passed as an argument to the shell command. See |option-backslash| about including spaces and backslashes. - Also see |dos-shell| for MS-Windows. + Also see |dos-shell| and |dos-powershell| for MS-Windows. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. *'shellpipe'* *'sp'* -'shellpipe' 'sp' string (default ">", ">%s 2>&1", "| tee", "|& tee" or - "2>&1| tee") +'shellpipe' 'sp' string (default ">", ">%s 2>&1", "| tee", "|& tee" + "2>&1| tee", or + "2>&1 | Out-File -Encoding default") global {not available when compiled without the |+quickfix| feature} @@ -6620,9 +6622,10 @@ A jump table for the options with a short description can be found at |Q_op|. The name of the temporary file can be represented by "%s" if necessary (the file name is appended automatically if no %s appears in the value of this option). - For the Amiga the default is ">". For MS-Windows the default is - ">%s 2>&1". The output is directly saved in a file and not echoed to - the screen. + For the Amiga the default is ">". For MS-Windows using powershell the + default is "2>&1 | Out-File -Encoding default", otherwise the default + is ">%s 2>&1". The output is directly saved in a file and not echoed + to the screen. For Unix the default is "| tee". The stdout of the compiler is saved in a file and echoed to the screen. If the 'shell' option is "csh" or "tcsh" after initializations, the default becomes "|& tee". If the @@ -6645,8 +6648,9 @@ A jump table for the options with a short description can be found at |Q_op|. security reasons. *'shellquote'* *'shq'* -'shellquote' 'shq' string (default: ""; Win32, when 'shell' - contains "sh" somewhere: "\"") +'shellquote' 'shq' string (default: ""; Win32, when 'shell' does not + contain powershell but contains "sh" + somewhere: "\"") global Quoting character(s), put around the command passed to the shell, for the "!" and ":!" commands. The redirection is kept outside of the @@ -6661,7 +6665,8 @@ A jump table for the options with a short description can be found at |Q_op|. security reasons. *'shellredir'* *'srr'* -'shellredir' 'srr' string (default ">", ">&" or ">%s 2>&1") +'shellredir' 'srr' string (default ">", ">&", ">%s 2>&1", or + "2>&1 | Out-File -Encoding default") global String to be used to put the output of a filter command in a temporary file. See also |:!|. See |option-backslash| about including spaces @@ -6674,8 +6679,10 @@ A jump table for the options with a short description can be found at |Q_op|. 'shell' option is "sh", "ksh", "mksh", "pdksh", "zsh", "zsh-beta", "bash" or "fish", the default becomes ">%s 2>&1". This means that stderr is also included. For Win32, the Unix checks are done and - additionally "cmd" is checked for, which makes the default ">%s 2>&1". - Also, the same names with ".exe" appended are checked for. + additionally "cmd" is checked for, which makes the default ">%s 2>&1", + and "powershell" is checked for which makes the default + "2>&1 | Out-File -Encoding default". Also, the same names with ".exe" + appended are checked for. The initialization of this option is done after reading the ".vimrc" and the other initializations, so that when the 'shell' option is set there, the 'shellredir' option changes automatically unless it was @@ -6690,9 +6697,9 @@ A jump table for the options with a short description can be found at |Q_op|. global {only for MS-Windows} When set, a forward slash is used when expanding file names. This is - useful when a Unix-like shell is used instead of cmd.exe. Backward - slashes can still be typed, but they are changed to forward slashes by - Vim. + useful when a Unix-like shell is used instead of cmd.exe or + powershell.exe. Backward slashes can still be typed, but they are + changed to forward slashes by Vim. Note that setting or resetting this option has no effect for some existing file names, thus this option needs to be set before opening any file for best results. This might change in the future. @@ -6746,6 +6753,8 @@ A jump table for the options with a short description can be found at |Q_op|. *'shellxquote'* *'sxq'* 'shellxquote' 'sxq' string (default: ""; for Win32, when 'shell' is cmd.exe: "(" + for Win32, when 'shell' is + powershell.exe: "\"" for Win32, when 'shell' contains "sh" somewhere: "\"" for Unix, when using system(): "\"") @@ -6758,11 +6767,12 @@ A jump table for the options with a short description can be found at |Q_op|. then ')"' is appended. When the value is '(' then also see 'shellxescape'. This is an empty string by default on most systems, but is known to be - useful for on Win32 version, either for cmd.exe which automatically - strips off the first and last quote on a command, or 3rd-party shells - such as the MKS Korn Shell or bash, where it should be "\"". The - default is adjusted according the value of 'shell', to reduce the need - to set this option by the user. See |dos-shell|. + useful for on Win32 version, either for cmd.exe and powershell.exe + which automatically strips off the first and last quote on a command, + or 3rd-party shells such as the MKS Korn Shell or bash, where it + should be "\"". The default is adjusted according the value of + 'shell', to reduce the need to set this option by the user. See + |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. diff --git a/runtime/doc/os_dos.txt b/runtime/doc/os_dos.txt index 925c7e0915..b45cb088cb 100644 --- a/runtime/doc/os_dos.txt +++ b/runtime/doc/os_dos.txt @@ -17,6 +17,7 @@ versions of Vim. Also see |os_win32.txt| and |os_msdos.txt|. 7. Interrupting |dos-CTRL-Break| 8. Temp files |dos-temp-files| 9. Shell option default |dos-shell| +10. PowerShell |dos-powershell| ============================================================================== 1. File locations *dos-locations* @@ -297,8 +298,46 @@ For Win32 as: -c "command name >file" For DOS 32 bit, DJGPP does this internally somehow. -When starting up, Vim checks for the presence of "sh" anywhere in the 'shell' -option. If it is present, Vim sets the 'shellcmdflag' and 'shellquote' or -'shellxquote' options will be set as described above. +When starting up, if Vim does not recognise a standard Windows shell it checks +for the presence of "sh" anywhere in the 'shell' option. If it is present, +Vim sets the 'shellcmdflag' and 'shellquote' or 'shellxquote' options will be +set as described above. + +============================================================================== +10. PowerShell *dos-powershell* + +Vim also supports Windows PowerShell. If 'shell' has been set to +"powershell.exe" at startup then VIM sets 'shellcmdflag', 'shellxquote', +'shellpipe', and 'shellredir' options to the following values: + +'shellcmdflag' -Command +'shellxquote' " +'shellpipe' 2>&1 | Out-File -Encoding default +'shellredir' 2>&1 | Out-File -Encoding default + +If you find that PowerShell commands are taking a long time to run then try +setting 'shellcmdflag' to "-NoProfile -Command". Note this will prevent any +PowerShell environment setup by the profile from taking place. + +If you have problems running PowerShell scripts through the 'shell' then try +setting 'shellcmdflag' to "-ExecutionPolicy RemoteSigned -Command". See +online Windows documentation for more information on PowerShell Execution +Policy settings. + +The 'shellpipe' and 'shellredir' option values re-encode the UTF-16le output +from Windows PowerShell to your currently configured console codepage. The +output can be forced into a different encoding by changing "default" to one of +the following: + + unicode - UTF-16le (default output from PowerShell 5.1) + bigendianunicode - UTF-16 + utf8 - UTF-8 + utf7 - UTF-7 (no-BOM) + utf32 - UTF-32 + ascii - 7-bit ASCII character set + default - System's active code page (typically ANSI) + oem - System's current OEM code page + +Note Multi-byte Unicode encodings include a leading BOM. vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/src/fileio.c b/src/fileio.c index 4bd773e0bd..55012bfcbd 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5245,9 +5245,10 @@ vim_tempname( // Backslashes in a temp file name cause problems when filtering with // "sh". NOTE: This also checks 'shellcmdflag' to help those people who - // didn't set 'shellslash'. + // didn't set 'shellslash' but only if not using PowerShell. retval = utf16_to_enc(itmp, NULL); - if (*p_shcf == '-' || p_ssl) + if ((strstr((char *)gettail(p_sh), "powershell") == NULL + && *p_shcf == '-') || p_ssl) for (p = retval; *p; ++p) if (*p == '\\') *p = '/'; diff --git a/src/misc2.c b/src/misc2.c index 0553c2ce14..6bbfbd775c 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1396,7 +1396,9 @@ csh_like_shell(void) /* * Escape "string" for use as a shell argument with system(). * This uses single quotes, except when we know we need to use double quotes - * (MS-DOS and MS-Windows without 'shellslash' set). + * (MS-DOS and MS-Windows not using PowerShell and without 'shellslash' set). + * PowerShell also uses a novel escaping for enclosed single quotes - double + * them up. * Escape a newline, depending on the 'shell' option. * When "do_special" is TRUE also replace "!", "%", "#" and things starting * with "<" like "". @@ -1412,6 +1414,10 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) char_u *escaped_string; int l; int csh_like; +# ifdef MSWIN + int powershell; + int double_quotes; +# endif // Only csh and similar shells expand '!' within single quotes. For sh and // the like we must not put a backslash before it, it will be taken @@ -1419,12 +1425,18 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) // Csh also needs to have "\n" escaped twice when do_special is set. csh_like = csh_like_shell(); +# ifdef MSWIN + // PowerShell only accepts single quotes so override p_ssl. + powershell = strstr((char *)gettail(p_sh), "powershell") != NULL; + double_quotes = !powershell && !p_ssl; +# endif + // First count the number of extra bytes required. length = (unsigned)STRLEN(string) + 3; // two quotes and a trailing NUL for (p = string; *p != NUL; MB_PTR_ADV(p)) { # ifdef MSWIN - if (!p_ssl) + if (double_quotes) { if (*p == '"') ++length; // " -> "" @@ -1432,7 +1444,14 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) else # endif if (*p == '\'') - length += 3; // ' => '\'' + { +# ifdef MSWIN + if (powershell) + length +=2; // ' => '' + else +# endif + length += 3; // ' => '\'' + } if ((*p == '\n' && (csh_like || do_newline)) || (*p == '!' && (csh_like || do_special))) { @@ -1455,7 +1474,7 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) // add opening quote # ifdef MSWIN - if (!p_ssl) + if (double_quotes) *d++ = '"'; else # endif @@ -1464,7 +1483,7 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) for (p = string; *p != NUL; ) { # ifdef MSWIN - if (!p_ssl) + if (double_quotes) { if (*p == '"') { @@ -1478,10 +1497,20 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) # endif if (*p == '\'') { - *d++ = '\''; - *d++ = '\\'; - *d++ = '\''; - *d++ = '\''; +# ifdef MSWIN + if (powershell) + { + *d++ = '\''; + *d++ = '\''; + } + else +# endif + { + *d++ = '\''; + *d++ = '\\'; + *d++ = '\''; + *d++ = '\''; + } ++p; continue; } @@ -1507,7 +1536,7 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) // add terminating quote and finish with a NUL # ifdef MSWIN - if (!p_ssl) + if (double_quotes) *d++ = '"'; else # endif diff --git a/src/option.c b/src/option.c index 07bb71e4d6..5fc059e29d 100644 --- a/src/option.c +++ b/src/option.c @@ -932,6 +932,27 @@ set_init_3(void) options[idx_srr].def_val[VI_DEFAULT] = p_srr; } } +# ifdef MSWIN + // PowerShell 5.1/.NET outputs UTF-16 with BOM so re-encode to the + // current codepage + else if ( fnamecmp(p, "powershell") == 0 + || fnamecmp(p, "powershell.exe") == 0 + ) + { +# if defined(FEAT_QUICKFIX) + if (do_sp) + { + p_sp = (char_u *)"2>&1 | Out-File -Encoding default"; + options[idx_sp].def_val[VI_DEFAULT] = p_sp; + } +# endif + if (do_srr) + { + p_srr = (char_u *)"2>&1 | Out-File -Encoding default"; + options[idx_srr].def_val[VI_DEFAULT] = p_srr; + } + } +#endif else // Always use POSIX shell style redirection if we reach this if ( fnamecmp(p, "sh") == 0 @@ -984,11 +1005,35 @@ set_init_3(void) * Set 'shellcmdflag', 'shellxquote', and 'shellquote' depending on the * 'shell' option. * This is done after other initializations, where 'shell' might have been - * set, but only if they have not been set before. Default for p_shcf is - * "/c", for p_shq is "". For "sh" like shells it is changed here to - * "-c" and "\"". And for Win32 we need to set p_sxq instead. + * set, but only if they have not been set before. + * Default values depend on shell (cmd.exe is default shell): + * + * p_shcf p_sxq + * cmd.exe - "/c" "(" + * powershell.exe - "-Command" "\"" + * "sh" like shells - "-c" "\"" + * + * For Win32 p_sxq is set instead of p_shq to include shell redirection. */ - if (strstr((char *)gettail(p_sh), "sh") != NULL) + if (strstr((char *)gettail(p_sh), "powershell") != NULL) + { + int idx_opt; + + idx_opt = findoption((char_u *)"shcf"); + if (idx_opt >= 0 && !(options[idx_opt].flags & P_WAS_SET)) + { + p_shcf = (char_u*)"-Command"; + options[idx_opt].def_val[VI_DEFAULT] = p_shcf; + } + + idx_opt = findoption((char_u *)"sxq"); + if (idx_opt >= 0 && !(options[idx_opt].flags & P_WAS_SET)) + { + p_sxq = (char_u*)"\""; + options[idx_opt].def_val[VI_DEFAULT] = p_sxq; + } + } + else if (strstr((char *)gettail(p_sh), "sh") != NULL) { int idx3; diff --git a/src/os_win32.c b/src/os_win32.c index a966c53495..1a005c9d53 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -2142,7 +2142,8 @@ executable_exists(char *name, char_u **path, int use_path, int use_pathext) return FALSE; // Using the name directly when a Unix-shell like 'shell'. - if (strstr((char *)gettail(p_sh), "sh") != NULL) + if (strstr((char *)gettail(p_sh), "powershell") == NULL + && strstr((char *)gettail(p_sh), "sh") != NULL) noext = TRUE; if (use_pathext) diff --git a/src/testdir/test_shell.vim b/src/testdir/test_shell.vim index f992b8ede6..753a0d5249 100644 --- a/src/testdir/test_shell.vim +++ b/src/testdir/test_shell.vim @@ -24,8 +24,10 @@ func Test_shell_options() if has('win32') let shells += [['cmd', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', ''], \ ['cmd.exe', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '('], - \ ['powershell.exe', '-c', '>', '', '>', '"&|<>()@^', '"'], - \ ['powershell', '-c', '>', '', '>', '"&|<>()@^', '"'], + \ ['powershell.exe', '-Command', '2>&1 | Out-File -Encoding default', + \ '', '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], + \ ['powershell', '-Command', '2>&1 | Out-File -Encoding default', '', + \ '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], \ ['sh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['ksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['mksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], @@ -58,6 +60,9 @@ func Test_shell_options() if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" + elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' + let str1 = "'cmd \"arg1\" ''arg2'' !%#'" + let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" else let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'" @@ -135,6 +140,28 @@ func Test_shellescape() let &shell = save_shell endfunc +" Test for 'shellslash' +func Test_shellslash() + CheckOption shellslash + let save_shellslash = &shellslash + " The shell and cmdflag, and expected slash in tempname with shellslash set or + " unset. The assert checks the file separator before the leafname. + " ".*\\\\[^\\\\]*$" + let shells = [['cmd', '/c', '\\', '/'], + \ ['powershell', '-Command', '\\', '/'], + \ ['sh', '-c', '/', '/']] + for e in shells + exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] + set noshellslash + let file = tempname() + call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') + set shellslash + let file = tempname() + call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') + endfor + let &shellslash = save_shellslash +endfunc + " Test for 'shellxquote' func Test_shellxquote() CheckUnix diff --git a/src/version.c b/src/version.c index 9ec6877d84..dd74d2dbee 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3071, /**/ 3070, /**/ From 7d7bcc6ba01454c1cbb1dcbf5f11c3a4051535d6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 28 Jun 2021 21:54:27 +0200 Subject: [PATCH 02/38] patch 8.2.3072: "zy" does not work well when "virtualedit' is "block" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: The "zy" command does not work well when 'virtualedit' is set to "block". (Johann Höchtl) Solution: Make endspaces zero. (Christian Brabandt, closes #8468, closes #8448) --- src/register.c | 4 +++- src/testdir/test_visual.vim | 20 ++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/register.c b/src/register.c index 4774e2a995..93ee7aad97 100644 --- a/src/register.c +++ b/src/register.c @@ -1455,6 +1455,8 @@ yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space) { char_u *pnew; + if (exclude_trailing_space) + bd->endspaces = 0; if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1)) == NULL) return FAIL; @@ -2747,7 +2749,7 @@ write_reg_contents_lst( &yank_type) == FAIL) return; - str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, TRUE); + str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE); finish_write_reg(name, old_y_previous, old_y_current); } diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index fb26750829..fbd3ca4fcd 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1,6 +1,7 @@ " Tests for various Visual modes. source shared.vim +source check.vim func Test_block_shift_multibyte() " Uses double-wide character. @@ -1225,5 +1226,24 @@ func Test_visual_put_in_block_using_zy_and_zp() bwipe! endfunc +func Test_visual_put_blockedit_zy_and_zp() + new + + call setline(1, ['aa', 'bbbbb', 'ccc', '', 'XX', 'GGHHJ', 'RTZU']) + exe "normal! gg0\2j$zy" + norm! 5gg0zP + call assert_equal(['aa', 'bbbbb', 'ccc', '', 'aaXX', 'bbbbbGGHHJ', 'cccRTZU'], getline(1, 7)) + " + " now with blockmode editing + sil %d + :set ve=block + call setline(1, ['aa', 'bbbbb', 'ccc', '', 'XX', 'GGHHJ', 'RTZU']) + exe "normal! gg0\2j$zy" + norm! 5gg0zP + call assert_equal(['aa', 'bbbbb', 'ccc', '', 'aaXX', 'bbbbbGGHHJ', 'cccRTZU'], getline(1, 7)) + set ve&vim + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index dd74d2dbee..f33d7dd6be 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3072, /**/ 3071, /**/ From 4067bd3604215b48e4b4201e28f9e401b08418e4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 29 Jun 2021 18:54:35 +0200 Subject: [PATCH 03/38] patch 8.2.3073: when cursor is move for block append wrong text is inserted Problem: When cursor is move for block append wrong text is inserted. Solution: Calculate an offset. (Christian Brabandt, closes #8433, closes #8288) --- src/ops.c | 69 ++++++++++++++++++++++++---------- src/testdir/test_blockedit.vim | 48 +++++++++++++++++++++++ src/testdir/test_visual.vim | 6 +-- src/version.c | 2 + 4 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/ops.c b/src/ops.c index 8f2ca8e369..59d5bff50d 100644 --- a/src/ops.c +++ b/src/ops.c @@ -545,6 +545,8 @@ block_insert( spaces -= off; count -= off; } + if (spaces < 0) // can happen when the cursor was moved + spaces = 0; newp = alloc(STRLEN(oldp) + s_len + count + 1); if (newp == NULL) @@ -1455,6 +1457,9 @@ op_insert(oparg_T *oap, long count1) struct block_def bd; int i; pos_T t1; + pos_T start_insert; + // offset when cursor was moved in insert mode + int offset = 0; // edit() changes this - record it for OP_APPEND bd.is_MAX = (curwin->w_curswant == MAXCOL); @@ -1526,6 +1531,7 @@ op_insert(oparg_T *oap, long count1) } t1 = oap->start; + start_insert = curwin->w_cursor; (void)edit(NUL, FALSE, (linenr_T)count1); // When a tab was inserted, and the characters in front of the tab @@ -1564,30 +1570,38 @@ op_insert(oparg_T *oap, long count1) if (oap->start.lnum == curbuf->b_op_start_orig.lnum && !bd.is_MAX && !did_indent) { - if (oap->op_type == OP_INSERT - && oap->start.col + oap->start.coladd - != curbuf->b_op_start_orig.col - + curbuf->b_op_start_orig.coladd) + int t = getviscol2(curbuf->b_op_start_orig.col, + curbuf->b_op_start_orig.coladd); + + if (!bd.is_MAX) { - int t = getviscol2(curbuf->b_op_start_orig.col, - curbuf->b_op_start_orig.coladd); - oap->start.col = curbuf->b_op_start_orig.col; - pre_textlen -= t - oap->start_vcol; - oap->start_vcol = t; + if (oap->op_type == OP_INSERT + && oap->start.col + oap->start.coladd + != curbuf->b_op_start_orig.col + + curbuf->b_op_start_orig.coladd) + { + oap->start.col = curbuf->b_op_start_orig.col; + pre_textlen -= t - oap->start_vcol; + oap->start_vcol = t; + } + else if (oap->op_type == OP_APPEND + && oap->end.col + oap->end.coladd + >= curbuf->b_op_start_orig.col + + curbuf->b_op_start_orig.coladd) + { + oap->start.col = curbuf->b_op_start_orig.col; + // reset pre_textlen to the value of OP_INSERT + pre_textlen += bd.textlen; + pre_textlen -= t - oap->start_vcol; + oap->start_vcol = t; + oap->op_type = OP_INSERT; + } } - else if (oap->op_type == OP_APPEND - && oap->end.col + oap->end.coladd - >= curbuf->b_op_start_orig.col - + curbuf->b_op_start_orig.coladd) + else if (bd.is_MAX && oap->op_type == OP_APPEND) { - int t = getviscol2(curbuf->b_op_start_orig.col, - curbuf->b_op_start_orig.coladd); - oap->start.col = curbuf->b_op_start_orig.col; // reset pre_textlen to the value of OP_INSERT pre_textlen += bd.textlen; pre_textlen -= t - oap->start_vcol; - oap->start_vcol = t; - oap->op_type = OP_INSERT; } } @@ -1617,13 +1631,28 @@ op_insert(oparg_T *oap, long count1) len = STRLEN(firstline); add = bd.textcol; if (oap->op_type == OP_APPEND) + { add += bd.textlen; + // account for pressing cursor in insert mode when '$' was used + if (bd.is_MAX + && (start_insert.lnum == Insstart.lnum + && start_insert.col > Insstart.col)) + { + offset = (start_insert.col - Insstart.col); + add -= offset; + if (oap->end_vcol > offset) + oap->end_vcol -= (offset + 1); + else + // moved outside of the visual block, what to do? + return; + } + } if ((size_t)add > len) firstline += len; // short line, point to the NUL else firstline += add; - if (pre_textlen >= 0 - && (ins_len = (long)STRLEN(firstline) - pre_textlen) > 0) + if (pre_textlen >= 0 && (ins_len = + (long)STRLEN(firstline) - pre_textlen - offset) > 0) { ins_text = vim_strnsave(firstline, ins_len); if (ins_text != NULL) diff --git a/src/testdir/test_blockedit.vim b/src/testdir/test_blockedit.vim index de56f23cbb..29e24759fa 100644 --- a/src/testdir/test_blockedit.vim +++ b/src/testdir/test_blockedit.vim @@ -28,4 +28,52 @@ func Test_blockinsert_delete() bwipe! endfunc +func Test_blockappend_eol_cursor() + new + " Test 1 Move 1 char left + call setline(1, ['aaa', 'bbb', 'ccc']) + exe "norm! gg$\2jA\x\" + call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$')) + " Test 2 Move 2 chars left + sil %d + call setline(1, ['aaa', 'bbb', 'ccc']) + exe "norm! gg$\2jA\\x\" + call assert_equal(['axaa', 'bxbb', 'cxcc'], getline(1, '$')) + " Test 3 Move 3 chars left (outside of the visual selection) + sil %d + call setline(1, ['aaa', 'bbb', 'ccc']) + exe "norm! ggl$\2jA\\\x\" + call assert_equal(['xaaa', 'bbb', 'ccc'], getline(1, '$')) + bw! +endfunc + +func Test_blockappend_eol_cursor2() + new + " Test 1 Move 1 char left + call setline(1, ['aaaaa', 'bbb', 'ccccc']) + exe "norm! gg\$2jA\x\" + call assert_equal(['aaaaxa', 'bbbx', 'ccccxc'], getline(1, '$')) + " Test 2 Move 2 chars left + sil %d + call setline(1, ['aaaaa', 'bbb', 'ccccc']) + exe "norm! gg\$2jA\\x\" + call assert_equal(['aaaxaa', 'bbbx', 'cccxcc'], getline(1, '$')) + " Test 3 Move 3 chars left (to the beginning of the visual selection) + sil %d + call setline(1, ['aaaaa', 'bbb', 'ccccc']) + exe "norm! gg\$2jA\\\x\" + call assert_equal(['aaxaaa', 'bbxb', 'ccxccc'], getline(1, '$')) + " Test 4 Move 3 chars left (outside of the visual selection) + sil %d + call setline(1, ['aaaaa', 'bbb', 'ccccc']) + exe "norm! ggl\$2jA\\\x\" + call assert_equal(['aaxaaa', 'bbxb', 'ccxccc'], getline(1, '$')) + " Test 5 Move 4 chars left (outside of the visual selection) + sil %d + call setline(1, ['aaaaa', 'bbb', 'ccccc']) + exe "norm! ggl\$2jA\\\\x\" + call assert_equal(['axaaaa', 'bxbb', 'cxcccc'], getline(1, '$')) + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index fbd3ca4fcd..789ff6f608 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -807,11 +807,7 @@ func Test_visual_block_mode() %d _ call setline(1, ['aaa', 'bbb', 'ccc']) exe "normal $\2jA\x" - " BUG: Instead of adding x as the third character in all the three lines, - " 'a' is added in the second and third lines at the end. This bug is not - " reproducible if this operation is performed manually. - "call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$')) - call assert_equal(['aaxa', 'bbba', 'ccca'], getline(1, '$')) + call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$')) " Repeat the previous test but use 'l' to move the cursor instead of '$' call setline(1, ['aaa', 'bbb', 'ccc']) exe "normal! gg2l\2jA\x" diff --git a/src/version.c b/src/version.c index f33d7dd6be..125325176b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3073, /**/ 3072, /**/ From ea042677ab5cab736540f3164909cac2c685de74 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 29 Jun 2021 20:22:32 +0200 Subject: [PATCH 04/38] patch 8.2.3074: popup_atcursor() uses wrong position with concealing Problem: popup_atcursor() uses wrong position with concealing. Solution: Keep w_wcol in conceal_check_cursor_line(). (closes #8476) --- src/edit.c | 15 ++++++++++++--- src/normal.c | 8 ++++---- src/proto/screen.pro | 2 +- src/screen.c | 14 ++++++++++++-- src/testdir/dumps/Test_popupwin_atcursor_pos.dump | 8 ++++---- src/testdir/test_popupwin.vim | 7 +++++++ src/ui.c | 2 +- src/version.c | 2 ++ 8 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/edit.c b/src/edit.c index 9162fe6298..d944080300 100644 --- a/src/edit.c +++ b/src/edit.c @@ -147,6 +147,9 @@ edit( #ifdef FEAT_JOB_CHANNEL int cmdchar_todo = cmdchar; #endif +#ifdef FEAT_CONCEAL + int cursor_line_was_concealed; +#endif // Remember whether editing was restarted after CTRL-O. did_restart_edit = restart_edit; @@ -222,9 +225,9 @@ edit( } #ifdef FEAT_CONCEAL - // Check if the cursor line needs redrawing before changing State. If - // 'concealcursor' is "n" it needs to be redrawn without concealing. - conceal_check_cursor_line(); + // Check if the cursor line was concealed before changing State. + cursor_line_was_concealed = curwin->w_p_cole > 0 + && conceal_cursor_line(curwin); #endif /* @@ -283,6 +286,12 @@ edit( stop_insert_mode = FALSE; +#ifdef FEAT_CONCEAL + // Check if the cursor line needs redrawing after changing State. If + // 'concealcursor' is "n" it needs to be redrawn without concealing. + conceal_check_cursor_line(cursor_line_was_concealed); +#endif + /* * Need to recompute the cursor position, it might move when the cursor is * on a TAB or special character. diff --git a/src/normal.c b/src/normal.c index 18f14ec4e1..56f89f518c 100644 --- a/src/normal.c +++ b/src/normal.c @@ -5747,8 +5747,8 @@ may_start_select(int c) n_start_visual_mode(int c) { #ifdef FEAT_CONCEAL - // Check for redraw before changing the state. - conceal_check_cursor_line(); + int cursor_line_was_concealed = curwin->w_p_cole > 0 + && conceal_cursor_line(curwin); #endif VIsual_mode = c; @@ -5770,8 +5770,8 @@ n_start_visual_mode(int c) setmouse(); #ifdef FEAT_CONCEAL - // Check for redraw after changing the state. - conceal_check_cursor_line(); + // Check if redraw is needed after changing the state. + conceal_check_cursor_line(cursor_line_was_concealed); #endif if (p_smd && msg_silent == 0) diff --git a/src/proto/screen.pro b/src/proto/screen.pro index fc45fa15fe..6d1993d2b5 100644 --- a/src/proto/screen.pro +++ b/src/proto/screen.pro @@ -1,6 +1,6 @@ /* screen.c */ int conceal_cursor_line(win_T *wp); -void conceal_check_cursor_line(void); +void conceal_check_cursor_line(int was_concealed); int get_wcr_attr(win_T *wp); void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl); int compute_foldcolumn(win_T *wp, int col); diff --git a/src/screen.c b/src/screen.c index 7c27e2ca42..bfb6bf7baf 100644 --- a/src/screen.c +++ b/src/screen.c @@ -83,16 +83,26 @@ conceal_cursor_line(win_T *wp) /* * Check if the cursor line needs to be redrawn because of 'concealcursor'. + * To be called after changing the state, "was_concealed" is the value of + * "conceal_cursor_line()" before the change. + * " */ void -conceal_check_cursor_line(void) +conceal_check_cursor_line(int was_concealed) { - if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)) + if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin) != was_concealed) { + int wcol = curwin->w_wcol; + need_cursor_line_redraw = TRUE; // Need to recompute cursor column, e.g., when starting Visual mode // without concealing. curs_columns(TRUE); + + // When concealing now w_wcol will be computed wrong, keep the previous + // value, it will be updated in win_line(). + if (!was_concealed) + curwin->w_wcol = wcol; } } #endif diff --git a/src/testdir/dumps/Test_popupwin_atcursor_pos.dump b/src/testdir/dumps/Test_popupwin_atcursor_pos.dump index a42b6e6ff5..3a4f0c2c7f 100644 --- a/src/testdir/dumps/Test_popupwin_atcursor_pos.dump +++ b/src/testdir/dumps/Test_popupwin_atcursor_pos.dump @@ -1,12 +1,12 @@ |-+0&#ffffff0@59| @14 |-@59| @14 -|-@25|%|-@16>@|-@14| @14 +|-@25|%|-@16|@|-@14| @14 |-@25|f+0#0000001#ffd7ff255|i|R|S|t| |-+0#0000000#ffffff0@6|F+0#0000001#ffd7ff255|i|r|s|t| |-+0#0000000#ffffff0@14| @14 |-@25|s+0#0000001#ffd7ff255|e|C|O|n|d|-+0#0000000#ffffff0@6|S+0#0000001#ffd7ff255|e|c|o|n|D|-+0#0000000#ffffff0@14| @14 |-@59| @14 |-@1|f+0#0000001#ffd7ff255|i|r|s|t| |-+0#0000000#ffffff0@6|F+0#0000001#ffd7ff255|I|r|s|T| |-+0#0000000#ffffff0@38| @14 -|-@1|s+0#0000001#ffd7ff255|e|c|o|n|d|-+0#0000000#ffffff0@6|S+0#0000001#ffd7ff255|E|c|o|N|D|-+0#0000000#ffffff0@38| @14 -|-@1|#|-@16|&|-@38| @14 +|-@1|s+0#0000001#ffd7ff255|e|c|o|n|d|-+0#0000000#ffffff0@6|S+0#0000001#ffd7ff255|E|c|o|N|D|-+0#0000000#ffffff0@6|m+0#0000001#ffd7ff255|a|r|k|-+0#0000000#ffffff0@27| @14 +|-@1|#|-@16|&|-@4| @1>X|-@21| @23 |-@59| @14 |-@59| @14 -@57|3|,|4|5| @9|T|o|p| +@57|9|,|3|8| @9|T|o|p| diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 68d7db87ea..cdfa3a987b 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1462,6 +1462,13 @@ func Test_popup_atcursor_pos() \ moved: range(3), \ mousemoved: range(3), \ }) + + normal 9G27|Rconcealed X + syn match Hidden /concealed/ conceal + set conceallevel=2 concealcursor=n + redraw + normal 0fX + call popup_atcursor('mark', {}) END call writefile(lines, 'XtestPopupAtcursorPos') let buf = RunVimInTerminal('-S XtestPopupAtcursorPos', #{rows: 12}) diff --git a/src/ui.c b/src/ui.c index 65ac626d2f..b3d125cd5a 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1082,7 +1082,7 @@ ui_cursor_shape_forced(int forced) # endif # ifdef FEAT_CONCEAL - conceal_check_cursor_line(); + conceal_check_cursor_line(FALSE); # endif } diff --git a/src/version.c b/src/version.c index 125325176b..f60abafe17 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3074, /**/ 3073, /**/ From 80b2ba3e9602e09ab523e78946fbb26da311b68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FJ=3DC3=3DBCrgen=3D20Weigert=3F=3D?= Date: Tue, 29 Jun 2021 20:36:25 +0200 Subject: [PATCH 05/38] patch 8.2.3075: xxd always reports an old version string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Xxd always reports an old version string. (Åsmund Ervik) Solution: Update the version string with the last known change date. (Jürgen Weigert, closes #8475) --- src/testdir/test_xxd.vim | 2 +- src/version.c | 2 ++ src/xxd/xxd.c | 10 +++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim index 4eef7a4e53..922c5ab3a6 100644 --- a/src/testdir/test_xxd.vim +++ b/src/testdir/test_xxd.vim @@ -226,7 +226,7 @@ endfunc func Test_xxd_version() new exe 'r! ' . s:xxd_cmd . ' -v' - call assert_match("xxd V1.10 .* by Juergen Weigert", join(getline(1, 3))) + call assert_match('xxd 20\d\d-\d\d-\d\d by Juergen Weigert et al\.', join(getline(1, 3))) bwipe! endfunc diff --git a/src/version.c b/src/version.c index f60abafe17..466cde1b13 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3075, /**/ 3074, /**/ diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c index 20f06ab7c5..94cc220bfb 100644 --- a/src/xxd/xxd.c +++ b/src/xxd/xxd.c @@ -55,16 +55,12 @@ * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen. * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen * - * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de) + * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com) * * I hereby grant permission to distribute and use xxd * under X11-MIT or GPL-2.0 (at the user's choice). * - * Small changes made afterwards by Bram Moolenaar et al. - * - * Distribute freely and credit me, - * make money and share with me, - * lose money and don't ask me. + * Contributions by Bram Moolenaar et al. */ /* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */ @@ -135,7 +131,7 @@ extern void perror __P((char *)); extern long int strtol(); extern long int ftell(); -char version[] = "xxd V1.10 27oct98 by Juergen Weigert"; +char version[] = "xxd 2020-02-04 by Juergen Weigert et al."; #ifdef WIN32 char osver[] = " (Win32)"; #else From 3f987b59173926420998ca92eb71688ee3e4a3e3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 30 Jun 2021 12:02:24 +0200 Subject: [PATCH 06/38] patch 8.2.3076: Vim9: using try in catch block causes a hang Problem: Vim9: using try in catch block causes a hang. Solution: Save and restore the ec_in_catch flag. (closes #8478) --- src/testdir/test_vim9_script.vim | 26 ++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 5 ++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 3ff34a2475..40cdfa39c1 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -605,6 +605,32 @@ def Test_try_catch_throw() unlet g:caught enddef +def Test_try_in_catch() + var lines =<< trim END + vim9script + var seq = [] + def DoIt() + try + seq->add('throw 1') + eval [][0] + seq->add('notreached') + catch + seq->add('catch') + try + seq->add('throw 2') + eval [][0] + seq->add('notreached') + catch /nothing/ + seq->add('notreached') + endtry + seq->add('done') + endtry + enddef + DoIt() + assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq) + END +enddef + " :while at the very start of a function that :continue jumps to def TryContinueFunc() while g:Count < 2 diff --git a/src/version.c b/src/version.c index 466cde1b13..70e0ff2f9d 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3076, /**/ 3075, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 3233e3ca3a..0de11bab0b 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -26,6 +26,7 @@ typedef struct { int tcd_frame_idx; // ec_frame_idx at ISN_TRY int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY + int tcd_save_in_catch; // saved ec_in_catch int tcd_catch_idx; // instruction of the first :catch or :finally int tcd_finally_idx; // instruction of the :finally block or zero int tcd_endtry_idx; // instruction of the :endtry @@ -3166,6 +3167,8 @@ exec_instructions(ectx_T *ectx) CLEAR_POINTER(trycmd); trycmd->tcd_frame_idx = ectx->ec_frame_idx; trycmd->tcd_stack_len = ectx->ec_stack.ga_len; + trycmd->tcd_save_in_catch = ectx->ec_in_catch; + ectx->ec_in_catch = FALSE; trycmd->tcd_catch_idx = iptr->isn_arg.try.try_ref->try_catch; trycmd->tcd_finally_idx = @@ -3263,9 +3266,9 @@ exec_instructions(ectx_T *ectx) --trystack->ga_len; --trylevel; - ectx->ec_in_catch = FALSE; trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len; + ectx->ec_in_catch = trycmd->tcd_save_in_catch; if (trycmd->tcd_caught && current_exception != NULL) { // discard the exception From d3d8feeb897a6b956fc82c81448b938a53312d71 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 30 Jun 2021 19:54:43 +0200 Subject: [PATCH 07/38] patch 8.2.3077: Vim9: an error in a catch block is not reported Problem: Vim9: an error in a catch block is not reported. Solution: Put the "in catch" flag in the try stack. (closes #8478) --- src/testdir/test_vim9_script.vim | 35 ++++++++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 29 ++++++++++++++++++-------- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 40cdfa39c1..a258bcb7a8 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -631,6 +631,17 @@ def Test_try_in_catch() END enddef +def Test_error_in_catch() + var lines =<< trim END + try + eval [][0] + catch /E684:/ + eval [][0] + endtry + END + CheckDefExecFailure(lines, 'E684:', 4) +enddef + " :while at the very start of a function that :continue jumps to def TryContinueFunc() while g:Count < 2 @@ -768,6 +779,30 @@ def Test_try_catch_nested() assert_equal('intry', ReturnFinally()) assert_equal('finally', g:in_finally) + + var l = [] + try + l->add('1') + throw 'bad' + l->add('x') + catch /bad/ + l->add('2') + try + l->add('3') + throw 'one' + l->add('x') + catch /one/ + l->add('4') + try + l->add('5') + throw 'more' + l->add('x') + catch /more/ + l->add('6') + endtry + endtry + endtry + assert_equal(['1', '2', '3', '4', '5', '6'], l) enddef def TryOne(): number diff --git a/src/version.c b/src/version.c index 70e0ff2f9d..655aaaea33 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3077, /**/ 3076, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 0de11bab0b..4013c06cda 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -26,7 +26,8 @@ typedef struct { int tcd_frame_idx; // ec_frame_idx at ISN_TRY int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY - int tcd_save_in_catch; // saved ec_in_catch + int tcd_in_catch; // in catch or finally block + int tcd_did_throw; // set did_throw in :endtry int tcd_catch_idx; // instruction of the first :catch or :finally int tcd_finally_idx; // instruction of the :finally block or zero int tcd_endtry_idx; // instruction of the :endtry @@ -83,7 +84,6 @@ struct ectx_S { funclocal_T ec_funclocal; garray_T ec_trystack; // stack of trycmd_T values - int ec_in_catch; // when TRUE in catch or finally block int ec_dfunc_idx; // current function index isn_T *ec_instr; // array with instructions @@ -1566,20 +1566,31 @@ exec_instructions(ectx_T *ectx) *msg_list = NULL; } - if (did_throw && !ectx->ec_in_catch) + if (did_throw) { garray_T *trystack = &ectx->ec_trystack; trycmd_T *trycmd = NULL; + int index = trystack->ga_len; // An exception jumps to the first catch, finally, or returns from // the current function. - if (trystack->ga_len > 0) - trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; + while (index > 0) + { + trycmd = ((trycmd_T *)trystack->ga_data) + index - 1; + if (!trycmd->tcd_in_catch) + break; + // In the catch and finally block of this try we have to go up + // one level. + --index; + trycmd = NULL; + } if (trycmd != NULL && trycmd->tcd_frame_idx == ectx->ec_frame_idx) { // jump to ":catch" or ":finally" - ectx->ec_in_catch = TRUE; + trycmd->tcd_in_catch = TRUE; ectx->ec_iidx = trycmd->tcd_catch_idx; + did_throw = FALSE; // don't come back here until :endtry + trycmd->tcd_did_throw = TRUE; } else { @@ -3167,8 +3178,6 @@ exec_instructions(ectx_T *ectx) CLEAR_POINTER(trycmd); trycmd->tcd_frame_idx = ectx->ec_frame_idx; trycmd->tcd_stack_len = ectx->ec_stack.ga_len; - trycmd->tcd_save_in_catch = ectx->ec_in_catch; - ectx->ec_in_catch = FALSE; trycmd->tcd_catch_idx = iptr->isn_arg.try.try_ref->try_catch; trycmd->tcd_finally_idx = @@ -3205,6 +3214,7 @@ exec_instructions(ectx_T *ectx) trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; trycmd->tcd_caught = TRUE; + trycmd->tcd_did_throw = FALSE; } did_emsg = got_int = did_throw = FALSE; force_abort = need_rethrow = FALSE; @@ -3268,7 +3278,8 @@ exec_instructions(ectx_T *ectx) --trylevel; trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len; - ectx->ec_in_catch = trycmd->tcd_save_in_catch; + if (trycmd->tcd_did_throw) + did_throw = TRUE; if (trycmd->tcd_caught && current_exception != NULL) { // discard the exception From 834193afd7195bc96026d2aed696d64f8075cd35 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 30 Jun 2021 20:39:15 +0200 Subject: [PATCH 08/38] patch 8.2.3078: Vim9: profile test fails Problem: Vim9: profile test fails. Solution: Make throw in :catch jump to :finally. --- src/testdir/test_vim9_script.vim | 19 +++++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 9 ++++++++- src/vim9execute.c | 13 ++++++++++--- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index a258bcb7a8..dfb1a41bb1 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -803,6 +803,25 @@ def Test_try_catch_nested() endtry endtry assert_equal(['1', '2', '3', '4', '5', '6'], l) + + l = [] + try + try + l->add('1') + throw 'foo' + l->add('x') + catch + l->add('2') + throw 'bar' + l->add('x') + finally + l->add('3') + endtry + l->add('x') + catch /bar/ + l->add('4') + endtry + assert_equal(['1', '2', '3', '4'], l) enddef def TryOne(): number diff --git a/src/version.c b/src/version.c index 655aaaea33..3c626bb670 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3078, /**/ 3077, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index e3e1721f13..533c0b33eb 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -8397,10 +8397,17 @@ compile_finally(char_u *arg, cctx_T *cctx) this_instr = instr->ga_len; #ifdef FEAT_PROFILE if (cctx->ctx_compile_type == CT_PROFILE - && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + && ((isn_T *)instr->ga_data)[this_instr - 1] .isn_type == ISN_PROF_START) + { // jump to the profile start of the "finally" --this_instr; + + // jump to the profile end above it + if (this_instr > 0 && ((isn_T *)instr->ga_data)[this_instr - 1] + .isn_type == ISN_PROF_END) + --this_instr; + } #endif // Fill in the "end" label in jumps at the end of the blocks. diff --git a/src/vim9execute.c b/src/vim9execute.c index 4013c06cda..b194e6a2a2 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1577,7 +1577,7 @@ exec_instructions(ectx_T *ectx) while (index > 0) { trycmd = ((trycmd_T *)trystack->ga_data) + index - 1; - if (!trycmd->tcd_in_catch) + if (!trycmd->tcd_in_catch || trycmd->tcd_finally_idx != 0) break; // In the catch and finally block of this try we have to go up // one level. @@ -1586,9 +1586,16 @@ exec_instructions(ectx_T *ectx) } if (trycmd != NULL && trycmd->tcd_frame_idx == ectx->ec_frame_idx) { - // jump to ":catch" or ":finally" + if (trycmd->tcd_in_catch) + { + // exception inside ":catch", jump to ":finally" once + ectx->ec_iidx = trycmd->tcd_finally_idx; + trycmd->tcd_finally_idx = 0; + } + else + // jump to first ":catch" + ectx->ec_iidx = trycmd->tcd_catch_idx; trycmd->tcd_in_catch = TRUE; - ectx->ec_iidx = trycmd->tcd_catch_idx; did_throw = FALSE; // don't come back here until :endtry trycmd->tcd_did_throw = TRUE; } From a3d1b29bd36487167c98b3cefa30f06c529e412d Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Wed, 30 Jun 2021 20:56:00 +0200 Subject: [PATCH 09/38] patch 8.2.3079: Powershell core not supported by default Problem: Powershell core not supported by default. Solution: Set option defaults for "pwsh". (Mike Williams, closes #8481) --- runtime/doc/eval.txt | 16 +++++----- runtime/doc/options.txt | 28 ++++++++--------- runtime/doc/os_dos.txt | 64 +++++++++++++++++++++++++++++++------- runtime/doc/os_win32.txt | 1 + src/fileio.c | 7 +++-- src/misc2.c | 14 ++++----- src/option.c | 12 +++++-- src/os_win32.c | 7 +++-- src/testdir/test_shell.vim | 19 ++++++++--- src/version.c | 2 ++ 10 files changed, 118 insertions(+), 52 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 7fb2534538..2eceece64b 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9878,11 +9878,13 @@ sha256({string}) *sha256()* shellescape({string} [, {special}]) *shellescape()* Escape {string} for use as a shell command argument. - On MS-Windows, when the 'shell' contains powershell then it - will enclose {string} in single quotes and will double up all - internal single quotes. With other values for 'shell' when - 'shellslash' is not set, it will enclose {string} in double - quotes and double all double quotes within {string}. + When the 'shell' contains powershell (MS-Windows) or pwsh + (MS-Windows, Linux, and MacOS) then it will enclose {string} + in single quotes and will double up all internal single + quotes. + On MS-Windows, when 'shellslash' is not set, it will enclose + {string} in double quotes and double all double quotes within + {string}. Otherwise it will enclose {string} in single quotes and replace all "'" with "'\''". @@ -11042,8 +11044,8 @@ tempname() *tempname()* *temp-file-name* :exe "redir > " . tmpfile < For Unix, the file will be in a private directory |tempfile|. For MS-Windows forward slashes are used when the 'shellslash' - option is set or when 'shellcmdflag' starts with '-' except - when when 'shell' contains powershell. + option is set, or when 'shellcmdflag' starts with '-' and + 'shell' does not contain powershell or pwsh. term_ functions are documented here: |terminal-function-details| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index b958cf63ed..af2e23eca7 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6633,6 +6633,8 @@ A jump table for the options with a short description can be found at |Q_op|. "bash", "fish", "ash" or "dash" the default becomes "2>&1| tee". This means that stderr is also included. Before using the 'shell' option a path is removed, thus "/bin/sh" uses "sh". + For Unix and MS-Windows, when the 'shell' option is "pwsh" the default + becomes ">%s 2>&1" and the output is not echoed to the screen. The initialization of this option is done after reading the ".vimrc" and the other initializations, so that when the 'shell' option is set there, the 'shellpipe' option changes automatically, unless it was @@ -6648,9 +6650,7 @@ A jump table for the options with a short description can be found at |Q_op|. security reasons. *'shellquote'* *'shq'* -'shellquote' 'shq' string (default: ""; Win32, when 'shell' does not - contain powershell but contains "sh" - somewhere: "\"") +'shellquote' 'shq' string (default: "") global Quoting character(s), put around the command passed to the shell, for the "!" and ":!" commands. The redirection is kept outside of the @@ -6658,9 +6658,7 @@ A jump table for the options with a short description can be found at |Q_op|. probably not useful to set both options. This is an empty string by default. Only known to be useful for third-party shells on MS-Windows-like systems, such as the MKS Korn - Shell or bash, where it should be "\"". The default is adjusted - according the value of 'shell', to reduce the need to set this option - by the user. See |dos-shell|. + Shell or bash, where it should be "\"". See |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. @@ -6677,12 +6675,12 @@ A jump table for the options with a short description can be found at |Q_op|. The default is ">". For Unix, if the 'shell' option is "csh" or "tcsh" during initializations, the default becomes ">&". If the 'shell' option is "sh", "ksh", "mksh", "pdksh", "zsh", "zsh-beta", - "bash" or "fish", the default becomes ">%s 2>&1". This means that - stderr is also included. For Win32, the Unix checks are done and + "bash", "fish", or "pwsh", the default becomes ">%s 2>&1". This means + that stderr is also included. For Win32, the Unix checks are done and additionally "cmd" is checked for, which makes the default ">%s 2>&1", and "powershell" is checked for which makes the default - "2>&1 | Out-File -Encoding default". Also, the same names with ".exe" - appended are checked for. + "2>&1 | Out-File -Encoding default" (see |dos-powershell|). Also, the + same names with ".exe" appended are checked for. The initialization of this option is done after reading the ".vimrc" and the other initializations, so that when the 'shell' option is set there, the 'shellredir' option changes automatically unless it was @@ -6697,7 +6695,7 @@ A jump table for the options with a short description can be found at |Q_op|. global {only for MS-Windows} When set, a forward slash is used when expanding file names. This is - useful when a Unix-like shell is used instead of cmd.exe or + useful when a Unix-like shell is used instead of cmd.exe, pwsh.exe, or powershell.exe. Backward slashes can still be typed, but they are changed to forward slashes by Vim. Note that setting or resetting this option has no effect for some @@ -6767,10 +6765,10 @@ A jump table for the options with a short description can be found at |Q_op|. then ')"' is appended. When the value is '(' then also see 'shellxescape'. This is an empty string by default on most systems, but is known to be - useful for on Win32 version, either for cmd.exe and powershell.exe - which automatically strips off the first and last quote on a command, - or 3rd-party shells such as the MKS Korn Shell or bash, where it - should be "\"". The default is adjusted according the value of + useful for on Win32 version, either for cmd.exe, powershell.exe, or + pwsh.exe which automatically strips off the first and last quote on a + command, or 3rd-party shells such as the MKS Korn Shell or bash, where + it should be "\"". The default is adjusted according the value of 'shell', to reduce the need to set this option by the user. See |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for diff --git a/runtime/doc/os_dos.txt b/runtime/doc/os_dos.txt index b45cb088cb..b473134ce1 100644 --- a/runtime/doc/os_dos.txt +++ b/runtime/doc/os_dos.txt @@ -304,40 +304,80 @@ Vim sets the 'shellcmdflag' and 'shellquote' or 'shellxquote' options will be set as described above. ============================================================================== -10. PowerShell *dos-powershell* +10. PowerShell *dos-powershell* *dos-pwsh* -Vim also supports Windows PowerShell. If 'shell' has been set to -"powershell.exe" at startup then VIM sets 'shellcmdflag', 'shellxquote', -'shellpipe', and 'shellredir' options to the following values: +Vim supports PowerShell Desktop and PowerShell Core. PowerShell Desktop is +the version of PowerShell that is installed with Windows, while PowerShell +Core is a separate downloadable version that works cross-platform. To see +which version you are using then enter the following in a PowerShell prompt - +$PSVersionTable.PSEdition + +If 'shell' includes "powershell" in the filename at startup then VIM sets +'shellcmdflag', 'shellxquote', 'shellpipe', and 'shellredir' options to the +following values: 'shellcmdflag' -Command 'shellxquote' " 'shellpipe' 2>&1 | Out-File -Encoding default 'shellredir' 2>&1 | Out-File -Encoding default +If 'shell' includes "pwsh" in the filename at startup then VIM sets +'shellcmdflag', 'shellxquote', 'shellpipe', and 'shellredir' options to the +following values: + +'shellcmdflag' -c +'shellxquote' " +'shellpipe' >%s 2>&1 +'shellredir' >%s 2>&1 + If you find that PowerShell commands are taking a long time to run then try -setting 'shellcmdflag' to "-NoProfile -Command". Note this will prevent any -PowerShell environment setup by the profile from taking place. +with "-NoProfile" at the beginning of the 'shellcmdflag'. Note this will +prevent any PowerShell environment setup by the profile from taking place. If you have problems running PowerShell scripts through the 'shell' then try -setting 'shellcmdflag' to "-ExecutionPolicy RemoteSigned -Command". See -online Windows documentation for more information on PowerShell Execution -Policy settings. +with "-ExecutionPolicy RemoteSigned -Command" at the beginning of +'shellcmdflag'. See online Windows documentation for more information on +PowerShell Execution Policy settings. + +See |option-backslash| about including spaces in 'shellcmdflag' when using +multiple flags. The 'shellpipe' and 'shellredir' option values re-encode the UTF-16le output -from Windows PowerShell to your currently configured console codepage. The +from PowerShell Desktop to your currently configured console codepage. The output can be forced into a different encoding by changing "default" to one of the following: unicode - UTF-16le (default output from PowerShell 5.1) bigendianunicode - UTF-16 utf8 - UTF-8 - utf7 - UTF-7 (no-BOM) + utf7 - UTF-7 (no BOM) utf32 - UTF-32 ascii - 7-bit ASCII character set default - System's active code page (typically ANSI) oem - System's current OEM code page -Note Multi-byte Unicode encodings include a leading BOM. +Note The abovce multi-byte Unicode encodings include a leading BOM unless +otherwise indicated. + +By default PowerShell Core's output is UTF-8 encoded without a BOM. If you +want to force the output of PowerShell Core into a different encoding then set +'shellredir' and 'shellpipe' to "2>&1 | Out-File -Encoding encoding" where +encoding is one of the following: + + ascii - 7-bit ASCII character set + bigendianunicode - UTF-16be + bigendianutf32 - UTF-32be + oem - System's current OEM code page + unicode - UTF-16le + utf7 - UTF-7 + utf8 - UTF-8 + utf8BOM - UTF-8, with BOM + utf8NoBOM - UTF-8, no BOM (default output from PowerShell Core) + utf32 - UTF-32 + +Since PowerShell Core 6.2, the Encoding parameter also supports specifying a +numeric ID of a registered code page (-Encoding 1251) or string names of +registered code pages (-Encoding "windows-1251"). The .NET documentation for +Encoding.CodePage has more information vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/os_win32.txt b/runtime/doc/os_win32.txt index 6c366083f6..3767cb8a98 100644 --- a/runtime/doc/os_win32.txt +++ b/runtime/doc/os_win32.txt @@ -30,6 +30,7 @@ File formats |dos-file-formats| Interrupting |dos-CTRL-Break| Temp files |dos-temp-files| Shell option default |dos-shell| +PowerShell defaults |dos-powershell| Win32 GUI |gui-w32| diff --git a/src/fileio.c b/src/fileio.c index 55012bfcbd..bd4038c36a 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5222,6 +5222,7 @@ vim_tempname( WCHAR *chartab = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char_u *retval; char_u *p; + char_u *shname; long i; wcscpy(itmp, L""); @@ -5247,8 +5248,10 @@ vim_tempname( // "sh". NOTE: This also checks 'shellcmdflag' to help those people who // didn't set 'shellslash' but only if not using PowerShell. retval = utf16_to_enc(itmp, NULL); - if ((strstr((char *)gettail(p_sh), "powershell") == NULL - && *p_shcf == '-') || p_ssl) + shname = gettail(p_sh); + if ((*p_shcf == '-' && !(strstr((char *)shname, "powershell") != NULL + || strstr((char *)shname, "pwsh") != NULL )) + || p_ssl) for (p = retval; *p; ++p) if (*p == '\\') *p = '/'; diff --git a/src/misc2.c b/src/misc2.c index 6bbfbd775c..ead1e63555 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1414,8 +1414,9 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) char_u *escaped_string; int l; int csh_like; -# ifdef MSWIN + char_u *shname; int powershell; +# ifdef MSWIN int double_quotes; # endif @@ -1425,9 +1426,12 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) // Csh also needs to have "\n" escaped twice when do_special is set. csh_like = csh_like_shell(); + // PowerShell uses it's own version for quoting single quotes + shname = gettail(p_sh); + powershell = strstr((char *)shname, "pwsh") != NULL; # ifdef MSWIN - // PowerShell only accepts single quotes so override p_ssl. - powershell = strstr((char *)gettail(p_sh), "powershell") != NULL; + powershell = powershell || strstr((char *)shname, "powershell") != NULL; + // PowerShell only accepts single quotes so override shellslash. double_quotes = !powershell && !p_ssl; # endif @@ -1445,11 +1449,9 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) # endif if (*p == '\'') { -# ifdef MSWIN if (powershell) length +=2; // ' => '' else -# endif length += 3; // ' => '\'' } if ((*p == '\n' && (csh_like || do_newline)) @@ -1497,14 +1499,12 @@ vim_strsave_shellescape(char_u *string, int do_special, int do_newline) # endif if (*p == '\'') { -# ifdef MSWIN if (powershell) { *d++ = '\''; *d++ = '\''; } else -# endif { *d++ = '\''; *d++ = '\\'; diff --git a/src/option.c b/src/option.c index 5fc059e29d..ae303106ad 100644 --- a/src/option.c +++ b/src/option.c @@ -933,8 +933,8 @@ set_init_3(void) } } # ifdef MSWIN - // PowerShell 5.1/.NET outputs UTF-16 with BOM so re-encode to the - // current codepage + // Windows PowerShell output is UTF-16 with BOM so re-encode to the + // current codepage. else if ( fnamecmp(p, "powershell") == 0 || fnamecmp(p, "powershell.exe") == 0 ) @@ -965,6 +965,7 @@ set_init_3(void) || fnamecmp(p, "fish") == 0 || fnamecmp(p, "ash") == 0 || fnamecmp(p, "dash") == 0 + || fnamecmp(p, "pwsh") == 0 # ifdef MSWIN || fnamecmp(p, "cmd") == 0 || fnamecmp(p, "sh.exe") == 0 @@ -976,6 +977,7 @@ set_init_3(void) || fnamecmp(p, "bash.exe") == 0 || fnamecmp(p, "cmd.exe") == 0 || fnamecmp(p, "dash.exe") == 0 + || fnamecmp(p, "pwsh.exe") == 0 # endif ) { @@ -985,7 +987,10 @@ set_init_3(void) # ifdef MSWIN p_sp = (char_u *)">%s 2>&1"; # else - p_sp = (char_u *)"2>&1| tee"; + if (fnamecmp(p, "pwsh") == 0) + p_sp = (char_u *)">%s 2>&1"; + else + p_sp = (char_u *)"2>&1| tee"; # endif options[idx_sp].def_val[VI_DEFAULT] = p_sp; } @@ -1011,6 +1016,7 @@ set_init_3(void) * p_shcf p_sxq * cmd.exe - "/c" "(" * powershell.exe - "-Command" "\"" + * pwsh.exe - "-c" "\"" * "sh" like shells - "-c" "\"" * * For Win32 p_sxq is set instead of p_shq to include shell redirection. diff --git a/src/os_win32.c b/src/os_win32.c index 1a005c9d53..eff2269f8c 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -2135,6 +2135,7 @@ executable_exists(char *name, char_u **path, int use_path, int use_pathext) char_u *pathbuf = NULL; char_u *pathext = NULL; char_u *pathextbuf = NULL; + char_u *shname = NULL; int noext = FALSE; int retval = FALSE; @@ -2142,8 +2143,10 @@ executable_exists(char *name, char_u **path, int use_path, int use_pathext) return FALSE; // Using the name directly when a Unix-shell like 'shell'. - if (strstr((char *)gettail(p_sh), "powershell") == NULL - && strstr((char *)gettail(p_sh), "sh") != NULL) + shname = gettail(p_sh); + if (strstr((char *)shname, "sh") != NULL && + !(strstr((char *)shname, "powershell") != NULL + || strstr((char *)shname, "pwsh") != NULL)) noext = TRUE; if (use_pathext) diff --git a/src/testdir/test_shell.vim b/src/testdir/test_shell.vim index 753a0d5249..f5a3e98997 100644 --- a/src/testdir/test_shell.vim +++ b/src/testdir/test_shell.vim @@ -19,7 +19,8 @@ func Test_shell_options() \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['csh', '-c', '|& tee', '', '>&', '', ''], - \ ['tcsh', '-c', '|& tee', '', '>&', '', '']] + \ ['tcsh', '-c', '|& tee', '', '>&', '', ''], + \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '', '']] endif if has('win32') let shells += [['cmd', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', ''], @@ -28,6 +29,8 @@ func Test_shell_options() \ '', '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], \ ['powershell', '-Command', '2>&1 | Out-File -Encoding default', '', \ '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], + \ ['pwsh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], + \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['sh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['ksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['mksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], @@ -61,6 +64,7 @@ func Test_shell_options() let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' + \ || e[0] =~# '.*pwsh$' || e[0] =~# '.*pwsh.exe$' let str1 = "'cmd \"arg1\" ''arg2'' !%#'" let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" else @@ -76,9 +80,14 @@ func Test_shell_options() let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, \ &shellxescape, &shellxquote] = e[1:6] new - r !echo hello - call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) - bwipe! + try + r !echo hello + call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) + catch + call assert_report('Failed to run shell command, shell: ' .. e[0]) + finally + bwipe! + endtry endif endfor set shell& shellcmdflag& shellpipe& shellquote& @@ -149,6 +158,8 @@ func Test_shellslash() " ".*\\\\[^\\\\]*$" let shells = [['cmd', '/c', '\\', '/'], \ ['powershell', '-Command', '\\', '/'], + \ ['pwsh', '-Command', '\\', '/'], + \ ['pwsh', '-c', '\\', '/'], \ ['sh', '-c', '/', '/']] for e in shells exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] diff --git a/src/version.c b/src/version.c index 3c626bb670..e9ad71b816 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3079, /**/ 3078, /**/ From 576cb75ceb38ed077938d4a1c1265095050f6105 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Wed, 30 Jun 2021 21:30:10 +0200 Subject: [PATCH 10/38] patch 8.2.3080: recover test fails on 32bit systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Recover test fails on 32bit systems. (Ondřej Súkup) Solution: Detect 32/64 bit systems. (Yegappan Lakshmanan, closes #8485, closes #8479) --- src/testdir/test_recover.vim | 28 +++++++++++++++++++++++----- src/version.c | 2 ++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 2db662f017..6ef4376def 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -202,10 +202,16 @@ func Test_recover_corrupted_swap_file() " Not all fields are written in a system-independent manner. Detect whether " the test is running on a little or big-endian system, so the correct " corruption values can be set. - let little_endian = b[1008:1015] == 0z33323130.00000000 + let little_endian = b[1008:1011] == 0z33323130 + " The swap file header fields can be either 32-bit or 64-bit. + let system_64bit = b[1012:1015] == 0z00000000 " clear the B0_MAGIC_LONG field - let b[1008:1015] = 0z0000000000000000 + if system_64bit + let b[1008:1015] = 0z00000000.00000000 + else + let b[1008:1011] = 0z00000000 + endif call writefile(b, sn) let msg = execute('recover Xfile1') call assert_match('the file has been damaged', msg) @@ -243,7 +249,11 @@ func Test_recover_corrupted_swap_file() " set the block number in a pointer entry to a negative number let b = copy(save_b) - let b[4104:4111] = little_endian ? 0z00000000.00000080 : 0z80000000.00000000 + if system_64bit + let b[4104:4111] = little_endian ? 0z00000000.00000080 : 0z80000000.00000000 + else + let b[4104:4107] = little_endian ? 0z00000080 : 0z80000000 + endif call writefile(b, sn) call assert_fails('recover Xfile1', 'E312:') call assert_equal('Xfile1', @%) @@ -261,7 +271,11 @@ func Test_recover_corrupted_swap_file() " set the number of lines in the data block to zero let b = copy(save_b) - let b[8208:8215] = 0z00000000.00000000 + if system_64bit + let b[8208:8215] = 0z00000000.00000000 + else + let b[8208:8211] = 0z00000000 + endif call writefile(b, sn) call assert_fails('recover Xfile1', 'E312:') call assert_equal('Xfile1', @%) @@ -271,7 +285,11 @@ func Test_recover_corrupted_swap_file() " use an invalid text start for the lines in a data block let b = copy(save_b) - let b[8216:8219] = 0z00000000 + if system_64bit + let b[8216:8219] = 0z00000000 + else + let b[8212:8215] = 0z00000000 + endif call writefile(b, sn) call assert_fails('recover Xfile1', 'E312:') call assert_equal('Xfile1', @%) diff --git a/src/version.c b/src/version.c index e9ad71b816..ed97a521b8 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3080, /**/ 3079, /**/ From 11a632d60bde616feb298d180108819ebb1d04a0 Mon Sep 17 00:00:00 2001 From: Alisue Date: Wed, 30 Jun 2021 22:01:02 +0200 Subject: [PATCH 11/38] patch 8.2.3081: cannot catch errors in a channel command Problem: Cannot catch errors in a channel command. Solution: Instead of skipping the error make it silent. (closes #8477) --- src/channel.c | 5 +++-- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/channel.c b/src/channel.c index 5818dc399b..5d89413503 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2545,7 +2545,8 @@ channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv) char_u *json = NULL; // Don't pollute the display with errors. - ++emsg_skip; + // Do generate the errors so that try/catch works. + ++emsg_silent; if (!is_call) { ch_log(channel, "Evaluating expression '%s'", (char *)arg); @@ -2581,7 +2582,7 @@ channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv) vim_free(json); } } - --emsg_skip; + --emsg_silent; if (tv == &res_tv) clear_tv(tv); else diff --git a/src/version.c b/src/version.c index ed97a521b8..e3bdedefbd 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3081, /**/ 3080, /**/ From b836f631dba2534efd314a8f77439cebc75acd4e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 1 Jul 2021 22:11:28 +0200 Subject: [PATCH 12/38] patch 8.2.3082: a channel command "echoerr" does not show anything Problem: A channel command "echoerr" does not show anything. Solution: Do not use silent errors when using an "echoerr" command. (closes #8494) --- src/channel.c | 11 ++++++++--- src/testdir/test_channel.py | 5 +++++ src/testdir/test_channel.vim | 12 ++++++++++++ src/version.c | 2 ++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/channel.c b/src/channel.c index 5d89413503..65757f1d7e 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2486,12 +2486,17 @@ channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv) if (STRCMP(cmd, "ex") == 0) { - int called_emsg_before = called_emsg; + int called_emsg_before = called_emsg; + char_u *p = arg; + int do_emsg_silent; ch_log(channel, "Executing ex command '%s'", (char *)arg); - ++emsg_silent; + do_emsg_silent = !checkforcmd(&p, "echoerr", 5); + if (do_emsg_silent) + ++emsg_silent; do_cmdline_cmd(arg); - --emsg_silent; + if (do_emsg_silent) + --emsg_silent; if (called_emsg > called_emsg_before) ch_log(channel, "Ex command error: '%s'", (char *)get_vim_var_str(VV_ERRMSG)); diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py index 8dba3ba4ca..9684bb933a 100644 --- a/src/testdir/test_channel.py +++ b/src/testdir/test_channel.py @@ -109,6 +109,11 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): print("sending: {0}".format(cmd)) self.request.sendall(cmd.encode('utf-8')) response = "ok" + elif decoded[1] == 'echoerr': + cmd = '["ex","echoerr \\\"this is an error\\\""]' + print("sending: {0}".format(cmd)) + self.request.sendall(cmd.encode('utf-8')) + response = "ok" elif decoded[1] == 'bad command': cmd = '["ex","foo bar"]' print("sending: {0}".format(cmd)) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index e9cc258f04..37dfd25861 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -115,6 +115,18 @@ func Ch_communicate(port) call WaitForAssert({-> assert_equal("added2", getline("$"))}) call assert_equal('added1', getline(line('$') - 1)) + " Request command "echoerr 'this is an error'". + " This will throw an exception, catch it here. + let caught = 'no' + try + call assert_equal('ok', ch_evalexpr(handle, 'echoerr')) + catch /this is an error/ + let caught = 'yes' + endtry + if caught != 'yes' + call assert_report("Expected exception from error message") + endif + " Request command "foo bar", which fails silently. call assert_equal('ok', ch_evalexpr(handle, 'bad command')) call WaitForAssert({-> assert_match("E492:.*foo bar", v:errmsg)}) diff --git a/src/version.c b/src/version.c index e3bdedefbd..532e747871 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3082, /**/ 3081, /**/ From 72463f883cdfd08e29ab0018ef3889284848d5f1 Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Fri, 2 Jul 2021 20:19:31 +0200 Subject: [PATCH 13/38] patch 8.2.3083: crash when passing null string to charclass() Problem: Crash when passing null string to charclass(). Solution: Bail out when string pointer is NULL. (Christian Brabandt, closes #8498, closes #8260) --- src/mbyte.c | 3 ++- src/testdir/test_functions.vim | 2 ++ src/version.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mbyte.c b/src/mbyte.c index 8ac15d38a9..b2519ecbaa 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -5587,7 +5587,8 @@ f_setcellwidths(typval_T *argvars, typval_T *rettv UNUSED) void f_charclass(typval_T *argvars, typval_T *rettv UNUSED) { - if (check_for_string_arg(argvars, 0) == FAIL) + if (check_for_string_arg(argvars, 0) == FAIL + || argvars[0].vval.v_string == NULL) return; rettv->vval.v_number = mb_get_class(argvars[0].vval.v_string); } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 23af53274d..3164ca2174 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2169,6 +2169,8 @@ func Test_charclass() call assert_equal(1, charclass('.')) call assert_equal(2, charclass('x')) call assert_equal(3, charclass("\u203c")) + " this used to crash vim + call assert_equal(0, "xxx"[-1]->charclass()) endfunc func Test_eventhandler() diff --git a/src/version.c b/src/version.c index 532e747871..540fa2b6c8 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3083, /**/ 3082, /**/ From a26f56f67502c72d44c61afdede2206cdde47c17 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sat, 3 Jul 2021 11:58:12 +0200 Subject: [PATCH 14/38] patch 8.2.3084: Vim9: builtin function argument types are not checked Problem: Vim9: builtin function argument types are not checked at compile time. Solution: Add argument types. (Yegappan Lakshmanan, closes #8503) --- src/evalfunc.c | 253 +++++++++------ src/testdir/test_functions.vim | 8 +- src/testdir/test_glob2regpat.vim | 3 +- src/testdir/test_vim9_builtin.vim | 518 ++++++++++++++++++++++++++++-- src/testdir/test_vim9_expr.vim | 7 - src/version.c | 2 + 6 files changed, 645 insertions(+), 146 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 6c467d8ae5..e635116786 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -267,6 +267,33 @@ arg_number(type_T *type, argcontext_T *context) return check_arg_type(&t_number, type, context); } +/* + * Check "type" is a dict of 'any'. + */ + static int +arg_dict_any(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_dict_any, type, context); +} + +/* + * Check "type" is a list of numbers. + */ + static int +arg_list_number(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_list_number, type, context); +} + +/* + * Check "type" is a list of strings. + */ + static int +arg_list_string(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_list_string, type, context); +} + /* * Check "type" is a string. */ @@ -301,6 +328,18 @@ arg_list_or_blob(type_T *type, argcontext_T *context) return FAIL; } +/* + * Check "type" is a string or a number + */ + static int +arg_string_or_nr(type_T *type, argcontext_T *context) +{ + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER) + return OK; + arg_type_mismatch(&t_string, type, context->arg_idx + 1); + return FAIL; +} /* * Check "type" is a string or a list of strings. */ @@ -404,14 +443,22 @@ arg_extend3(type_T *type, argcontext_T *context) */ argcheck_T arg1_string[] = {arg_string}; argcheck_T arg1_number[] = {arg_number}; +argcheck_T arg1_dict[] = {arg_dict_any}; +argcheck_T arg1_list_number[] = {arg_list_number}; +argcheck_T arg1_string_list[] = {arg_list_string}; argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; +argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; +argcheck_T arg1_string_or_list[] = {arg_string_or_list}; argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; argcheck_T arg2_number[] = {arg_number, arg_number}; +argcheck_T arg2_string[] = {arg_string, arg_string}; +argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number}; argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; +argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; @@ -732,7 +779,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"balloon_show", 1, 1, FEARG_1, NULL, + {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list, ret_void, #ifdef FEAT_BEVAL f_balloon_show @@ -740,7 +787,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"balloon_split", 1, 1, FEARG_1, NULL, + {"balloon_split", 1, 1, FEARG_1, arg1_string, ret_list_string, #if defined(FEAT_BEVAL_TERM) f_balloon_split @@ -752,31 +799,31 @@ static funcentry_T global_functions[] = ret_string, f_browse}, {"browsedir", 2, 2, 0, NULL, ret_string, f_browsedir}, - {"bufadd", 1, 1, FEARG_1, NULL, + {"bufadd", 1, 1, FEARG_1, arg1_string, ret_number, f_bufadd}, - {"bufexists", 1, 1, FEARG_1, NULL, + {"bufexists", 1, 1, FEARG_1, arg1_string_or_nr, ret_number_bool, f_bufexists}, - {"buffer_exists", 1, 1, FEARG_1, NULL, // obsolete + {"buffer_exists", 1, 1, FEARG_1, arg1_string_or_nr, // obsolete ret_number_bool, f_bufexists}, - {"buffer_name", 0, 1, FEARG_1, NULL, // obsolete + {"buffer_name", 0, 1, FEARG_1, arg1_string_or_nr, // obsolete ret_string, f_bufname}, {"buffer_number", 0, 1, FEARG_1, NULL, // obsolete ret_number, f_bufnr}, - {"buflisted", 1, 1, FEARG_1, NULL, + {"buflisted", 1, 1, FEARG_1, arg1_string_or_nr, ret_number_bool, f_buflisted}, - {"bufload", 1, 1, FEARG_1, NULL, + {"bufload", 1, 1, FEARG_1, arg1_string_or_nr, ret_void, f_bufload}, - {"bufloaded", 1, 1, FEARG_1, NULL, + {"bufloaded", 1, 1, FEARG_1, arg1_string_or_nr, ret_number_bool, f_bufloaded}, - {"bufname", 0, 1, FEARG_1, NULL, + {"bufname", 0, 1, FEARG_1, arg1_string_or_nr, ret_string, f_bufname}, {"bufnr", 0, 2, FEARG_1, NULL, ret_number, f_bufnr}, - {"bufwinid", 1, 1, FEARG_1, NULL, + {"bufwinid", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_bufwinid}, - {"bufwinnr", 1, 1, FEARG_1, NULL, + {"bufwinnr", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_bufwinnr}, - {"byte2line", 1, 1, FEARG_1, NULL, + {"byte2line", 1, 1, FEARG_1, arg1_number, ret_number, f_byte2line}, {"byteidx", 2, 2, FEARG_1, NULL, ret_number, f_byteidx}, @@ -826,15 +873,15 @@ static funcentry_T global_functions[] = ret_number, f_changenr}, {"char2nr", 1, 2, FEARG_1, NULL, ret_number, f_char2nr}, - {"charclass", 1, 1, FEARG_1, NULL, + {"charclass", 1, 1, FEARG_1, arg1_string, ret_number, f_charclass}, {"charcol", 1, 1, FEARG_1, NULL, ret_number, f_charcol}, {"charidx", 2, 3, FEARG_1, NULL, ret_number, f_charidx}, - {"chdir", 1, 1, FEARG_1, NULL, + {"chdir", 1, 1, FEARG_1, arg1_string, ret_string, f_chdir}, - {"cindent", 1, 1, FEARG_1, NULL, + {"cindent", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_cindent}, {"clearmatches", 0, 1, FEARG_1, arg1_number, ret_void, f_clearmatches}, @@ -846,7 +893,7 @@ static funcentry_T global_functions[] = ret_number, f_complete_add}, {"complete_check", 0, 0, 0, NULL, ret_number_bool, f_complete_check}, - {"complete_info", 0, 1, FEARG_1, NULL, + {"complete_info", 0, 1, FEARG_1, arg1_string_list, ret_dict_any, f_complete_info}, {"confirm", 1, 4, FEARG_1, NULL, ret_number, f_confirm}, @@ -878,7 +925,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_deletebufline}, {"did_filetype", 0, 0, 0, NULL, ret_number_bool, f_did_filetype}, - {"diff_filler", 1, 1, FEARG_1, NULL, + {"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_diff_filler}, {"diff_hlID", 2, 2, FEARG_1, NULL, ret_number, f_diff_hlID}, @@ -888,37 +935,37 @@ static funcentry_T global_functions[] = ret_number_bool, f_empty}, {"environ", 0, 0, 0, NULL, ret_dict_string, f_environ}, - {"escape", 2, 2, FEARG_1, NULL, + {"escape", 2, 2, FEARG_1, arg2_string, ret_string, f_escape}, - {"eval", 1, 1, FEARG_1, NULL, + {"eval", 1, 1, FEARG_1, arg1_string, ret_any, f_eval}, {"eventhandler", 0, 0, 0, NULL, ret_number_bool, f_eventhandler}, - {"executable", 1, 1, FEARG_1, NULL, + {"executable", 1, 1, FEARG_1, arg1_string, ret_number, f_executable}, {"execute", 1, 2, FEARG_1, arg2_execute, ret_string, f_execute}, - {"exepath", 1, 1, FEARG_1, NULL, + {"exepath", 1, 1, FEARG_1, arg1_string, ret_string, f_exepath}, - {"exists", 1, 1, FEARG_1, NULL, + {"exists", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_exists}, {"exp", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_exp)}, {"expand", 1, 3, FEARG_1, NULL, ret_any, f_expand}, - {"expandcmd", 1, 1, FEARG_1, NULL, + {"expandcmd", 1, 1, FEARG_1, arg1_string, ret_string, f_expandcmd}, {"extend", 2, 3, FEARG_1, arg23_extend, ret_first_arg, f_extend}, {"extendnew", 2, 3, FEARG_1, arg23_extendnew, ret_first_cont, f_extendnew}, - {"feedkeys", 1, 2, FEARG_1, NULL, + {"feedkeys", 1, 2, FEARG_1, arg2_string, ret_void, f_feedkeys}, - {"file_readable", 1, 1, FEARG_1, NULL, // obsolete + {"file_readable", 1, 1, FEARG_1, arg1_string, // obsolete ret_number_bool, f_filereadable}, - {"filereadable", 1, 1, FEARG_1, NULL, + {"filereadable", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_filereadable}, - {"filewritable", 1, 1, FEARG_1, NULL, + {"filewritable", 1, 1, FEARG_1, arg1_string, ret_number, f_filewritable}, {"filter", 2, 2, FEARG_1, NULL, ret_first_arg, f_filter}, @@ -936,19 +983,19 @@ static funcentry_T global_functions[] = ret_float, FLOAT_FUNC(f_floor)}, {"fmod", 2, 2, FEARG_1, arg2_float_or_nr, ret_float, FLOAT_FUNC(f_fmod)}, - {"fnameescape", 1, 1, FEARG_1, NULL, + {"fnameescape", 1, 1, FEARG_1, arg1_string, ret_string, f_fnameescape}, - {"fnamemodify", 2, 2, FEARG_1, NULL, + {"fnamemodify", 2, 2, FEARG_1, arg2_string, ret_string, f_fnamemodify}, - {"foldclosed", 1, 1, FEARG_1, NULL, + {"foldclosed", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_foldclosed}, - {"foldclosedend", 1, 1, FEARG_1, NULL, + {"foldclosedend", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_foldclosedend}, - {"foldlevel", 1, 1, FEARG_1, NULL, + {"foldlevel", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_foldlevel}, {"foldtext", 0, 0, 0, NULL, ret_string, f_foldtext}, - {"foldtextresult", 1, 1, FEARG_1, NULL, + {"foldtextresult", 1, 1, FEARG_1, arg1_string_or_nr, ret_string, f_foldtextresult}, {"foreground", 0, 0, 0, NULL, ret_void, f_foreground}, @@ -968,7 +1015,7 @@ static funcentry_T global_functions[] = ret_list_string, f_getbufline}, {"getbufvar", 2, 3, FEARG_1, NULL, ret_any, f_getbufvar}, - {"getchangelist", 0, 1, FEARG_1, NULL, + {"getchangelist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_any, f_getchangelist}, {"getchar", 0, 1, 0, NULL, ret_any, f_getchar}, @@ -996,17 +1043,17 @@ static funcentry_T global_functions[] = ret_list_number, f_getcursorcharpos}, {"getcwd", 0, 2, FEARG_1, arg2_number, ret_string, f_getcwd}, - {"getenv", 1, 1, FEARG_1, NULL, + {"getenv", 1, 1, FEARG_1, arg1_string, ret_any, f_getenv}, - {"getfontname", 0, 1, 0, NULL, + {"getfontname", 0, 1, 0, arg1_string, ret_string, f_getfontname}, - {"getfperm", 1, 1, FEARG_1, NULL, + {"getfperm", 1, 1, FEARG_1, arg1_string, ret_string, f_getfperm}, - {"getfsize", 1, 1, FEARG_1, NULL, + {"getfsize", 1, 1, FEARG_1, arg1_string, ret_number, f_getfsize}, - {"getftime", 1, 1, FEARG_1, NULL, + {"getftime", 1, 1, FEARG_1, arg1_string, ret_number, f_getftime}, - {"getftype", 1, 1, FEARG_1, NULL, + {"getftype", 1, 1, FEARG_1, arg1_string, ret_string, f_getftype}, {"getimstatus", 0, 0, 0, NULL, ret_number_bool, f_getimstatus}, @@ -1016,7 +1063,7 @@ static funcentry_T global_functions[] = ret_f_getline, f_getline}, {"getloclist", 1, 2, 0, NULL, ret_list_or_dict_1, f_getloclist}, - {"getmarklist", 0, 1, FEARG_1, NULL, + {"getmarklist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_dict_any, f_getmarklist}, {"getmatches", 0, 1, 0, arg1_number, ret_list_dict_any, f_getmatches}, @@ -1024,15 +1071,15 @@ static funcentry_T global_functions[] = ret_dict_number, f_getmousepos}, {"getpid", 0, 0, 0, NULL, ret_number, f_getpid}, - {"getpos", 1, 1, FEARG_1, NULL, + {"getpos", 1, 1, FEARG_1, arg1_string, ret_list_number, f_getpos}, - {"getqflist", 0, 1, 0, NULL, + {"getqflist", 0, 1, 0, arg1_dict, ret_list_or_dict_0, f_getqflist}, {"getreg", 0, 3, FEARG_1, NULL, ret_getreg, f_getreg}, - {"getreginfo", 0, 1, FEARG_1, NULL, + {"getreginfo", 0, 1, FEARG_1, arg1_string, ret_dict_any, f_getreginfo}, - {"getregtype", 0, 1, FEARG_1, NULL, + {"getregtype", 0, 1, FEARG_1, arg1_string, ret_string, f_getregtype}, {"gettabinfo", 0, 1, FEARG_1, arg1_number, ret_list_dict_any, f_gettabinfo}, @@ -1042,7 +1089,7 @@ static funcentry_T global_functions[] = ret_any, f_gettabwinvar}, {"gettagstack", 0, 1, FEARG_1, arg1_number, ret_dict_any, f_gettagstack}, - {"gettext", 1, 1, FEARG_1, NULL, + {"gettext", 1, 1, FEARG_1, arg1_string, ret_string, f_gettext}, {"getwininfo", 0, 1, FEARG_1, arg1_number, ret_list_dict_any, f_getwininfo}, @@ -1056,7 +1103,7 @@ static funcentry_T global_functions[] = ret_any, f_getwinvar}, {"glob", 1, 4, FEARG_1, NULL, ret_any, f_glob}, - {"glob2regpat", 1, 1, FEARG_1, NULL, + {"glob2regpat", 1, 1, FEARG_1, arg1_string, ret_string, f_glob2regpat}, {"globpath", 2, 5, FEARG_2, NULL, ret_any, f_globpath}, @@ -1072,21 +1119,21 @@ static funcentry_T global_functions[] = ret_number, f_hlID}, {"highlight_exists",1, 1, FEARG_1, NULL, // obsolete ret_number_bool, f_hlexists}, - {"histadd", 2, 2, FEARG_2, NULL, + {"histadd", 2, 2, FEARG_2, arg2_string, ret_number_bool, f_histadd}, {"histdel", 1, 2, FEARG_1, NULL, ret_number_bool, f_histdel}, {"histget", 1, 2, FEARG_1, NULL, ret_string, f_histget}, - {"histnr", 1, 1, FEARG_1, NULL, + {"histnr", 1, 1, FEARG_1, arg1_string, ret_number, f_histnr}, - {"hlID", 1, 1, FEARG_1, NULL, + {"hlID", 1, 1, FEARG_1, arg1_string, ret_number, f_hlID}, - {"hlexists", 1, 1, FEARG_1, NULL, + {"hlexists", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_hlexists}, {"hostname", 0, 0, 0, NULL, ret_string, f_hostname}, - {"iconv", 3, 3, FEARG_1, NULL, + {"iconv", 3, 3, FEARG_1, arg3_string, ret_string, f_iconv}, {"indent", 1, 1, FEARG_1, NULL, ret_number, f_indent}, @@ -1096,13 +1143,13 @@ static funcentry_T global_functions[] = ret_string, f_input}, {"inputdialog", 1, 3, FEARG_1, NULL, ret_string, f_inputdialog}, - {"inputlist", 1, 1, FEARG_1, NULL, + {"inputlist", 1, 1, FEARG_1, arg1_string_list, ret_number, f_inputlist}, {"inputrestore", 0, 0, 0, NULL, ret_number_bool, f_inputrestore}, {"inputsave", 0, 0, 0, NULL, ret_number_bool, f_inputsave}, - {"inputsecret", 1, 2, FEARG_1, NULL, + {"inputsecret", 1, 2, FEARG_1, arg2_string, ret_string, f_inputsecret}, {"insert", 2, 3, FEARG_1, arg3_insert, ret_first_arg, f_insert}, @@ -1110,7 +1157,7 @@ static funcentry_T global_functions[] = ret_void, f_interrupt}, {"invert", 1, 1, FEARG_1, arg1_number, ret_number, f_invert}, - {"isdirectory", 1, 1, FEARG_1, NULL, + {"isdirectory", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_isdirectory}, {"isinf", 1, 1, FEARG_1, arg1_float_or_nr, ret_number, MATH_FUNC(f_isinf)}, @@ -1118,7 +1165,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_islocked}, {"isnan", 1, 1, FEARG_1, arg1_float_or_nr, ret_number_bool, MATH_FUNC(f_isnan)}, - {"items", 1, 1, FEARG_1, NULL, + {"items", 1, 1, FEARG_1, arg1_dict, ret_list_any, f_items}, {"job_getchannel", 1, 1, FEARG_1, NULL, ret_channel, JOB_FUNC(f_job_getchannel)}, @@ -1134,15 +1181,15 @@ static funcentry_T global_functions[] = ret_number_bool, JOB_FUNC(f_job_stop)}, {"join", 1, 2, FEARG_1, NULL, ret_string, f_join}, - {"js_decode", 1, 1, FEARG_1, NULL, + {"js_decode", 1, 1, FEARG_1, arg1_string, ret_any, f_js_decode}, {"js_encode", 1, 1, FEARG_1, NULL, ret_string, f_js_encode}, - {"json_decode", 1, 1, FEARG_1, NULL, + {"json_decode", 1, 1, FEARG_1, arg1_string, ret_any, f_json_decode}, {"json_encode", 1, 1, FEARG_1, NULL, ret_string, f_json_encode}, - {"keys", 1, 1, FEARG_1, NULL, + {"keys", 1, 1, FEARG_1, arg1_dict, ret_list_string, f_keys}, {"last_buffer_nr", 0, 0, 0, NULL, // obsolete ret_number, f_last_buffer_nr}, @@ -1154,9 +1201,9 @@ static funcentry_T global_functions[] = ret_number, f_libcallnr}, {"line", 1, 2, FEARG_1, NULL, ret_number, f_line}, - {"line2byte", 1, 1, FEARG_1, NULL, + {"line2byte", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_line2byte}, - {"lispindent", 1, 1, FEARG_1, NULL, + {"lispindent", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_lispindent}, {"list2str", 1, 2, FEARG_1, NULL, ret_string, f_list2str}, @@ -1214,7 +1261,7 @@ static funcentry_T global_functions[] = ret_list_any, f_matchstrpos}, {"max", 1, 1, FEARG_1, NULL, ret_number, f_max}, - {"menu_info", 1, 2, FEARG_1, NULL, + {"menu_info", 1, 2, FEARG_1, arg2_string, ret_dict_any, #ifdef FEAT_MENU f_menu_info @@ -1236,7 +1283,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"nextnonblank", 1, 1, FEARG_1, NULL, + {"nextnonblank", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_nextnonblank}, {"nr2char", 1, 2, FEARG_1, NULL, ret_string, f_nr2char}, @@ -1296,11 +1343,11 @@ static funcentry_T global_functions[] = ret_void, PROP_FUNC(f_popup_show)}, {"pow", 2, 2, FEARG_1, arg2_float_or_nr, ret_float, FLOAT_FUNC(f_pow)}, - {"prevnonblank", 1, 1, FEARG_1, NULL, + {"prevnonblank", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_prevnonblank}, {"printf", 1, 19, FEARG_2, NULL, ret_string, f_printf}, - {"prompt_getprompt", 1, 1, FEARG_1, NULL, + {"prompt_getprompt", 1, 1, FEARG_1, arg1_string_or_nr, ret_string, JOB_FUNC(f_prompt_getprompt)}, {"prompt_setcallback", 2, 2, FEARG_1, NULL, ret_void, JOB_FUNC(f_prompt_setcallback)}, @@ -1356,11 +1403,11 @@ static funcentry_T global_functions[] = NULL #endif }, - {"rand", 0, 1, FEARG_1, NULL, + {"rand", 0, 1, FEARG_1, arg1_list_number, ret_number, f_rand}, {"range", 1, 3, FEARG_1, NULL, ret_list_number, f_range}, - {"readblob", 1, 1, FEARG_1, NULL, + {"readblob", 1, 1, FEARG_1, arg1_string, ret_blob, f_readblob}, {"readdir", 1, 3, FEARG_1, NULL, ret_list_string, f_readdir}, @@ -1374,15 +1421,15 @@ static funcentry_T global_functions[] = ret_string, f_reg_executing}, {"reg_recording", 0, 0, 0, NULL, ret_string, f_reg_recording}, - {"reltime", 0, 2, FEARG_1, NULL, + {"reltime", 0, 2, FEARG_1, arg2_list_number, ret_list_any, f_reltime}, - {"reltimefloat", 1, 1, FEARG_1, NULL, + {"reltimefloat", 1, 1, FEARG_1, arg1_list_number, ret_float, FLOAT_FUNC(f_reltimefloat)}, - {"reltimestr", 1, 1, FEARG_1, NULL, + {"reltimestr", 1, 1, FEARG_1, arg1_list_number, ret_string, f_reltimestr}, {"remote_expr", 2, 4, FEARG_1, NULL, ret_string, f_remote_expr}, - {"remote_foreground", 1, 1, FEARG_1, NULL, + {"remote_foreground", 1, 1, FEARG_1, arg1_string, ret_string, f_remote_foreground}, {"remote_peek", 1, 2, FEARG_1, NULL, ret_number, f_remote_peek}, @@ -1390,15 +1437,15 @@ static funcentry_T global_functions[] = ret_string, f_remote_read}, {"remote_send", 2, 3, FEARG_1, NULL, ret_string, f_remote_send}, - {"remote_startserver", 1, 1, FEARG_1, NULL, + {"remote_startserver", 1, 1, FEARG_1, arg1_string, ret_void, f_remote_startserver}, {"remove", 2, 3, FEARG_1, NULL, ret_remove, f_remove}, - {"rename", 2, 2, FEARG_1, NULL, + {"rename", 2, 2, FEARG_1, arg2_string, ret_number_bool, f_rename}, {"repeat", 2, 2, FEARG_1, NULL, ret_first_arg, f_repeat}, - {"resolve", 1, 1, FEARG_1, NULL, + {"resolve", 1, 1, FEARG_1, arg1_string, ret_string, f_resolve}, {"reverse", 1, 1, FEARG_1, NULL, ret_first_arg, f_reverse}, @@ -1420,7 +1467,7 @@ static funcentry_T global_functions[] = ret_list_number, f_screenchars}, {"screencol", 0, 0, 0, NULL, ret_number, f_screencol}, - {"screenpos", 3, 3, FEARG_1, NULL, + {"screenpos", 3, 3, FEARG_1, arg3_number, ret_dict_number, f_screenpos}, {"screenrow", 0, 0, 0, NULL, ret_number, f_screenrow}, @@ -1428,7 +1475,7 @@ static funcentry_T global_functions[] = ret_string, f_screenstring}, {"search", 1, 5, FEARG_1, NULL, ret_number, f_search}, - {"searchcount", 0, 1, FEARG_1, NULL, + {"searchcount", 0, 1, FEARG_1, arg1_dict, ret_dict_any, f_searchcount}, {"searchdecl", 1, 3, FEARG_1, NULL, ret_number_bool, f_searchdecl}, @@ -1450,7 +1497,7 @@ static funcentry_T global_functions[] = ret_void, f_setcellwidths}, {"setcharpos", 2, 2, FEARG_2, NULL, ret_number_bool, f_setcharpos}, - {"setcharsearch", 1, 1, FEARG_1, NULL, + {"setcharsearch", 1, 1, FEARG_1, arg1_dict, ret_void, f_setcharsearch}, {"setcmdpos", 1, 1, FEARG_1, arg1_number, ret_number_bool, f_setcmdpos}, @@ -1458,7 +1505,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_setcursorcharpos}, {"setenv", 2, 2, FEARG_2, NULL, ret_void, f_setenv}, - {"setfperm", 2, 2, FEARG_1, NULL, + {"setfperm", 2, 2, FEARG_1, arg2_string, ret_number_bool, f_setfperm}, {"setline", 2, 2, FEARG_2, NULL, ret_number_bool, f_setline}, @@ -1480,7 +1527,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_settagstack}, {"setwinvar", 3, 3, FEARG_3, NULL, ret_void, f_setwinvar}, - {"sha256", 1, 1, FEARG_1, NULL, + {"sha256", 1, 1, FEARG_1, arg1_string, ret_string, #ifdef FEAT_CRYPT f_sha256 @@ -1510,7 +1557,7 @@ static funcentry_T global_functions[] = ret_number_bool, SIGN_FUNC(f_sign_unplace)}, {"sign_unplacelist", 1, 2, FEARG_1, NULL, ret_list_number, SIGN_FUNC(f_sign_unplacelist)}, - {"simplify", 1, 1, FEARG_1, NULL, + {"simplify", 1, 1, FEARG_1, arg1_string, ret_string, f_simplify}, {"sin", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_sin)}, @@ -1526,11 +1573,11 @@ static funcentry_T global_functions[] = ret_number, SOUND_FUNC(f_sound_playevent)}, {"sound_playfile", 1, 2, FEARG_1, NULL, ret_number, SOUND_FUNC(f_sound_playfile)}, - {"sound_stop", 1, 1, FEARG_1, NULL, + {"sound_stop", 1, 1, FEARG_1, arg1_number, ret_void, SOUND_FUNC(f_sound_stop)}, - {"soundfold", 1, 1, FEARG_1, NULL, + {"soundfold", 1, 1, FEARG_1, arg1_string, ret_string, f_soundfold}, - {"spellbadword", 0, 1, FEARG_1, NULL, + {"spellbadword", 0, 1, FEARG_1, arg1_string, ret_list_string, f_spellbadword}, {"spellsuggest", 1, 3, FEARG_1, NULL, ret_list_string, f_spellsuggest}, @@ -1538,9 +1585,9 @@ static funcentry_T global_functions[] = ret_list_string, f_split}, {"sqrt", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_sqrt)}, - {"srand", 0, 1, FEARG_1, NULL, + {"srand", 0, 1, FEARG_1, arg1_number, ret_list_number, f_srand}, - {"state", 0, 1, FEARG_1, NULL, + {"state", 0, 1, FEARG_1, arg1_string, ret_string, f_state}, {"str2float", 1, 1, FEARG_1, arg1_string, ret_float, FLOAT_FUNC(f_str2float)}, @@ -1570,11 +1617,11 @@ static funcentry_T global_functions[] = ret_number, f_stridx}, {"string", 1, 1, FEARG_1, NULL, ret_string, f_string}, - {"strlen", 1, 1, FEARG_1, NULL, + {"strlen", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_strlen}, {"strpart", 2, 4, FEARG_1, NULL, ret_string, f_strpart}, - {"strptime", 2, 2, FEARG_1, NULL, + {"strptime", 2, 2, FEARG_1, arg2_string, ret_number, #ifdef HAVE_STRPTIME f_strptime @@ -1584,23 +1631,23 @@ static funcentry_T global_functions[] = }, {"strridx", 2, 3, FEARG_1, NULL, ret_number, f_strridx}, - {"strtrans", 1, 1, FEARG_1, NULL, + {"strtrans", 1, 1, FEARG_1, arg1_string, ret_string, f_strtrans}, - {"strwidth", 1, 1, FEARG_1, NULL, + {"strwidth", 1, 1, FEARG_1, arg1_string, ret_number, f_strwidth}, {"submatch", 1, 2, FEARG_1, NULL, ret_string, f_submatch}, {"substitute", 4, 4, FEARG_1, NULL, ret_string, f_substitute}, - {"swapinfo", 1, 1, FEARG_1, NULL, + {"swapinfo", 1, 1, FEARG_1, arg1_string, ret_dict_any, f_swapinfo}, - {"swapname", 1, 1, FEARG_1, NULL, + {"swapname", 1, 1, FEARG_1, arg1_string_or_nr, ret_string, f_swapname}, {"synID", 3, 3, 0, NULL, ret_number, f_synID}, {"synIDattr", 2, 3, FEARG_1, NULL, ret_string, f_synIDattr}, - {"synIDtrans", 1, 1, FEARG_1, NULL, + {"synIDtrans", 1, 1, FEARG_1, arg1_number, ret_number, f_synIDtrans}, {"synconcealed", 2, 2, 0, NULL, ret_list_any, f_synconcealed}, @@ -1610,9 +1657,9 @@ static funcentry_T global_functions[] = ret_string, f_system}, {"systemlist", 1, 2, FEARG_1, NULL, ret_list_string, f_systemlist}, - {"tabpagebuflist", 0, 1, FEARG_1, NULL, + {"tabpagebuflist", 0, 1, FEARG_1, arg1_number, ret_list_number, f_tabpagebuflist}, - {"tabpagenr", 0, 1, 0, NULL, + {"tabpagenr", 0, 1, 0, arg1_string, ret_number, f_tabpagenr}, {"tabpagewinnr", 1, 2, FEARG_1, NULL, ret_number, f_tabpagewinnr}, @@ -1746,13 +1793,13 @@ static funcentry_T global_functions[] = ret_any, f_test_unknown}, {"test_void", 0, 0, 0, NULL, ret_void, f_test_void}, - {"timer_info", 0, 1, FEARG_1, NULL, + {"timer_info", 0, 1, FEARG_1, arg1_number, ret_list_dict_any, TIMER_FUNC(f_timer_info)}, {"timer_pause", 2, 2, FEARG_1, NULL, ret_void, TIMER_FUNC(f_timer_pause)}, {"timer_start", 2, 3, FEARG_1, NULL, ret_number, TIMER_FUNC(f_timer_start)}, - {"timer_stop", 1, 1, FEARG_1, NULL, + {"timer_stop", 1, 1, FEARG_1, arg1_number, ret_void, TIMER_FUNC(f_timer_stop)}, {"timer_stopall", 0, 0, 0, NULL, ret_void, TIMER_FUNC(f_timer_stopall)}, @@ -1770,13 +1817,13 @@ static funcentry_T global_functions[] = ret_number, f_type}, {"typename", 1, 1, FEARG_1, NULL, ret_string, f_typename}, - {"undofile", 1, 1, FEARG_1, NULL, + {"undofile", 1, 1, FEARG_1, arg1_string, ret_string, f_undofile}, {"undotree", 0, 0, 0, NULL, ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, NULL, ret_list_any, f_uniq}, - {"values", 1, 1, FEARG_1, NULL, + {"values", 1, 1, FEARG_1, arg1_dict, ret_list_any, f_values}, {"virtcol", 1, 1, FEARG_1, NULL, ret_number, f_virtcol}, @@ -1786,9 +1833,9 @@ static funcentry_T global_functions[] = ret_number, f_wildmenumode}, {"win_execute", 2, 3, FEARG_2, NULL, ret_string, f_win_execute}, - {"win_findbuf", 1, 1, FEARG_1, NULL, + {"win_findbuf", 1, 1, FEARG_1, arg1_number, ret_list_number, f_win_findbuf}, - {"win_getid", 0, 2, FEARG_1, NULL, + {"win_getid", 0, 2, FEARG_1, arg2_number, ret_number, f_win_getid}, {"win_gettype", 0, 1, FEARG_1, arg1_number, ret_string, f_win_gettype}, @@ -1814,11 +1861,11 @@ static funcentry_T global_functions[] = ret_list_any, f_winlayout}, {"winline", 0, 0, 0, NULL, ret_number, f_winline}, - {"winnr", 0, 1, FEARG_1, NULL, + {"winnr", 0, 1, FEARG_1, arg1_string, ret_number, f_winnr}, {"winrestcmd", 0, 0, 0, NULL, ret_string, f_winrestcmd}, - {"winrestview", 1, 1, FEARG_1, NULL, + {"winrestview", 1, 1, FEARG_1, arg1_dict, ret_void, f_winrestview}, {"winsaveview", 0, 0, 0, NULL, ret_dict_number, f_winsaveview}, diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 3164ca2174..a4ca5d45ff 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -169,7 +169,8 @@ func Test_strwidth() if has('float') call assert_equal(3, strwidth(1.2)) - call CheckDefExecAndScriptFailure(['echo strwidth(1.2)'], 'E806:') + call CheckDefFailure(['echo strwidth(1.2)'], 'E1013:') + call CheckScriptFailure(['vim9script', 'echo strwidth(1.2)'], 'E806:') endif set ambiwidth& @@ -236,7 +237,7 @@ func Test_str2nr() call assert_fails('call str2nr({->2})', 'E729:') if has('float') call assert_equal(1, str2nr(1.2)) - call CheckDefExecFailure(['echo str2nr(1.2)'], 'E1013:') + call CheckDefFailure(['echo str2nr(1.2)'], 'E1013:') call CheckScriptFailure(['vim9script', 'echo str2nr(1.2)'], 'E806:') endif call assert_fails('call str2nr(10, [])', 'E745:') @@ -499,7 +500,8 @@ func Test_simplify() call assert_fails('call simplify({})', 'E731:') if has('float') call assert_equal('1.2', simplify(1.2)) - call CheckDefExecAndScriptFailure(['echo simplify(1.2)'], 'E806:') + call CheckDefFailure(['echo simplify(1.2)'], 'E1013:') + call CheckScriptFailure(['vim9script', 'echo simplify(1.2)'], 'E806:') endif endfunc diff --git a/src/testdir/test_glob2regpat.vim b/src/testdir/test_glob2regpat.vim index ab459bba33..18e22dc662 100644 --- a/src/testdir/test_glob2regpat.vim +++ b/src/testdir/test_glob2regpat.vim @@ -5,7 +5,8 @@ source vim9.vim func Test_glob2regpat_invalid() if has('float') call assert_equal('^1\.33$', glob2regpat(1.33)) - call CheckDefExecAndScriptFailure(['echo glob2regpat(1.33)'], 'E806:') + call CheckDefFailure(['echo glob2regpat(1.2)'], 'E1013:') + call CheckScriptFailure(['vim9script', 'echo glob2regpat(1.2)'], 'E806:') endif call assert_fails('call glob2regpat("}")', 'E219:') call assert_fails('call glob2regpat("{")', 'E220:') diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index c40780f4ae..5a5b512d8c 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -180,12 +180,14 @@ def Test_balloon_show() CheckGui CheckFeature balloon_eval + assert_fails('balloon_show(10)', 'E1174:') assert_fails('balloon_show(true)', 'E1174:') enddef def Test_balloon_split() CheckFeature balloon_eval_term + assert_fails('balloon_split([])', 'E1174:') assert_fails('balloon_split(true)', 'E1174:') enddef @@ -206,14 +208,28 @@ def Test_browse() CheckDefExecAndScriptFailure(lines, 'E1174: String required for argument 4') enddef +def Test_bufadd() + assert_fails('bufadd([])', 'E730:') +enddef + def Test_bufexists() - assert_fails('bufexists(true)', 'E1174') + assert_fails('bufexists(true)', 'E1174:') enddef def Test_buflisted() var res: bool = buflisted('asdf') assert_equal(false, res) - assert_fails('buflisted(true)', 'E1174') + assert_fails('buflisted(true)', 'E1174:') + assert_fails('buflisted([])', 'E1174:') +enddef + +def Test_bufload() + assert_fails('bufload([])', 'E730:') +enddef + +def Test_bufloaded() + assert_fails('bufloaded(true)', 'E1174:') + assert_fails('bufloaded([])', 'E1174:') enddef def Test_bufname() @@ -222,6 +238,8 @@ def Test_bufname() edit OtherFile bufname('#')->assert_equal('SomeFile') close + assert_fails('bufname(true)', 'E1138:') + assert_fails('bufname([])', 'E745:') enddef def Test_bufnr() @@ -246,7 +264,19 @@ def Test_bufwinid() bwipe SomeFile bwipe OtherFile - assert_fails('bufwinid(true)', 'E1138') + assert_fails('bufwinid(true)', 'E1138:') + assert_fails('bufwinid([])', 'E745:') +enddef + +def Test_bufwinnr() + assert_fails('bufwinnr(true)', 'E1138:') + assert_fails('bufwinnr([])', 'E745:') +enddef + +def Test_byte2line() + CheckDefFailure(['byte2line("1")'], 'E1013: Argument 1: type mismatch, expected number but got string') + CheckDefFailure(['byte2line([])'], 'E1013: Argument 1: type mismatch, expected number but got list') + assert_equal(-1, byte2line(0)) enddef def Test_call_call() @@ -259,22 +289,29 @@ def Test_ch_logfile() if !has('channel') CheckFeature channel endif - assert_fails('ch_logfile(true)', 'E1174') - assert_fails('ch_logfile("foo", true)', 'E1174') + assert_fails('ch_logfile(true)', 'E1174:') + assert_fails('ch_logfile("foo", true)', 'E1174:') enddef def Test_char2nr() char2nr('あ', true)->assert_equal(12354) - assert_fails('char2nr(true)', 'E1174') + assert_fails('char2nr(true)', 'E1174:') enddef def Test_charclass() - assert_fails('charclass(true)', 'E1174') + assert_fails('charclass(true)', 'E1174:') enddef def Test_chdir() - assert_fails('chdir(true)', 'E1174') + assert_fails('chdir(true)', 'E1174:') +enddef + +def Test_cindent() + CheckDefFailure(['cindent([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['cindent(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') + assert_equal(-1, cindent(0)) + assert_equal(0, cindent('.')) enddef def Test_clearmatches() @@ -286,7 +323,7 @@ def Test_col() setline(1, 'asdf') col([1, '$'])->assert_equal(5) - assert_fails('col(true)', 'E1174') + assert_fails('col(true)', 'E1174:') enddef def Test_confirm() @@ -294,9 +331,16 @@ def Test_confirm() CheckFeature dialog_con endif - assert_fails('confirm(true)', 'E1174') - assert_fails('confirm("yes", true)', 'E1174') - assert_fails('confirm("yes", "maybe", 2, true)', 'E1174') + assert_fails('confirm(true)', 'E1174:') + assert_fails('confirm("yes", true)', 'E1174:') + assert_fails('confirm("yes", "maybe", 2, true)', 'E1174:') +enddef + +def Test_complete_info() + CheckDefFailure(['complete_info("")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['complete_info({})'], 'E1013: Argument 1: type mismatch, expected list but got dict') + assert_equal({'pum_visible': 0, 'mode': '', 'selected': -1, 'items': []}, complete_info()) + assert_equal({'mode': '', 'items': []}, complete_info(['mode', 'items'])) enddef def Test_copy_return_type() @@ -346,12 +390,32 @@ def Test_delete() assert_equal(true, res) enddef +def Test_diff_filler() + CheckDefFailure(['diff_filler([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['diff_filler(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool') + assert_equal(0, diff_filler(1)) + assert_equal(0, diff_filler('.')) +enddef + +def Test_escape() + CheckDefFailure(['escape("a", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefFailure(['escape(10, " ")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['escape(true, false)'], 'E1013: Argument 1: type mismatch, expected string but got bool') + assert_equal('a\:b', escape("a:b", ":")) +enddef + +def Test_eval() + CheckDefFailure(['eval(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['eval(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') + assert_equal(2, eval('1 + 1')) +enddef + def Test_executable() assert_false(executable("")) assert_false(executable(test_null_string())) - CheckDefExecFailure(['echo executable(123)'], 'E1174:') - CheckDefExecFailure(['echo executable(true)'], 'E1174:') + CheckDefExecFailure(['echo executable(123)'], 'E1013:') + CheckDefExecFailure(['echo executable(true)'], 'E1013:') enddef def Test_execute() @@ -367,11 +431,16 @@ def Test_execute() enddef def Test_exepath() - CheckDefExecFailure(['echo exepath(true)'], 'E1174:') - CheckDefExecFailure(['echo exepath(v:null)'], 'E1174:') + CheckDefExecFailure(['echo exepath(true)'], 'E1013:') + CheckDefExecFailure(['echo exepath(v:null)'], 'E1013:') CheckDefExecFailure(['echo exepath("")'], 'E1175:') enddef +def Test_exists() + CheckDefFailure(['exists(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + call assert_equal(1, exists('&tabstop')) +enddef + def Test_expand() split SomeFile expand('%', true, true)->assert_equal(['SomeFile']) @@ -507,6 +576,16 @@ def Test_extend_with_error_function() CheckScriptFailure(lines, 'E1001: Variable not found: m') enddef +def Test_feedkeys() + CheckDefFailure(['feedkeys(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['feedkeys("x", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefFailure(['feedkeys([], {})'], 'E1013: Argument 1: type mismatch, expected string but got list') + g:TestVar = 1 + feedkeys(":g:TestVar = 789\n", 'xt') + assert_equal(789, g:TestVar) + unlet g:TestVar +enddef + def Test_job_info_return_type() if has('job') job_start(&shell) @@ -521,16 +600,16 @@ def Test_filereadable() assert_false(filereadable("")) assert_false(filereadable(test_null_string())) - CheckDefExecFailure(['echo filereadable(123)'], 'E1174:') - CheckDefExecFailure(['echo filereadable(true)'], 'E1174:') + CheckDefExecFailure(['echo filereadable(123)'], 'E1013:') + CheckDefExecFailure(['echo filereadable(true)'], 'E1013:') enddef def Test_filewritable() assert_false(filewritable("")) assert_false(filewritable(test_null_string())) - CheckDefExecFailure(['echo filewritable(123)'], 'E1174:') - CheckDefExecFailure(['echo filewritable(true)'], 'E1174:') + CheckDefExecFailure(['echo filewritable(123)'], 'E1013:') + CheckDefExecFailure(['echo filewritable(true)'], 'E1013:') enddef def Test_finddir() @@ -620,15 +699,20 @@ def Test_float_funcs_args() CheckDefFailure(['echo trunc("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_fnameescape() + CheckDefFailure(['fnameescape(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal('\+a\%b\|', fnameescape('+a%b|')) +enddef + def Test_fnamemodify() CheckDefSuccess(['echo fnamemodify(test_null_string(), ":p")']) CheckDefSuccess(['echo fnamemodify("", ":p")']) CheckDefSuccess(['echo fnamemodify("file", test_null_string())']) CheckDefSuccess(['echo fnamemodify("file", "")']) - CheckDefExecFailure(['echo fnamemodify(true, ":p")'], 'E1174: String required for argument 1') - CheckDefExecFailure(['echo fnamemodify(v:null, ":p")'], 'E1174: String required for argument 1') - CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E1174: String required for argument 2') + CheckDefExecFailure(['echo fnamemodify(true, ":p")'], 'E1013: Argument 1: type mismatch, expected string but got bool') + CheckDefExecFailure(['echo fnamemodify(v:null, ":p")'], 'E1013: Argument 1: type mismatch, expected string but got special') + CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool') enddef def Wrong_dict_key_type(items: list): list @@ -654,6 +738,30 @@ def Test_filter_missing_argument() res->assert_equal({aa: [1], ac: [3]}) enddef +def Test_foldclosed() + CheckDefFailure(['foldclosed(function("min"))'], 'E1013: Argument 1: type mismatch, expected string but got func(...): any') + assert_equal(-1, foldclosed(1)) + assert_equal(-1, foldclosed('$')) +enddef + +def Test_foldclosedend() + CheckDefFailure(['foldclosedend(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool') + assert_equal(-1, foldclosedend(1)) + assert_equal(-1, foldclosedend('w0')) +enddef + +def Test_foldlevel() + CheckDefFailure(['foldlevel(0z10)'], 'E1013: Argument 1: type mismatch, expected string but got blob') + assert_equal(0, foldlevel(1)) + assert_equal(0, foldlevel('.')) +enddef + +def Test_foldtextresult() + CheckDefFailure(['foldtextresult(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float') + assert_equal('', foldtextresult(1)) + assert_equal('', foldtextresult('.')) +enddef + def Test_fullcommand() assert_equal('next', fullcommand('n')) assert_equal('noremap', fullcommand('no')) @@ -762,36 +870,40 @@ def Test_getloclist_return_type() d->assert_equal({items: []}) enddef +def Test_getfontname() + CheckDefFailure(['getfontname(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') +enddef + def Test_getfperm() assert_equal('', getfperm("")) assert_equal('', getfperm(test_null_string())) - CheckDefExecFailure(['echo getfperm(true)'], 'E1174:') - CheckDefExecFailure(['echo getfperm(v:null)'], 'E1174:') + CheckDefExecFailure(['echo getfperm(true)'], 'E1013:') + CheckDefExecFailure(['echo getfperm(v:null)'], 'E1013:') enddef def Test_getfsize() assert_equal(-1, getfsize("")) assert_equal(-1, getfsize(test_null_string())) - CheckDefExecFailure(['echo getfsize(true)'], 'E1174:') - CheckDefExecFailure(['echo getfsize(v:null)'], 'E1174:') + CheckDefExecFailure(['echo getfsize(true)'], 'E1013:') + CheckDefExecFailure(['echo getfsize(v:null)'], 'E1013:') enddef def Test_getftime() assert_equal(-1, getftime("")) assert_equal(-1, getftime(test_null_string())) - CheckDefExecFailure(['echo getftime(true)'], 'E1174:') - CheckDefExecFailure(['echo getftime(v:null)'], 'E1174:') + CheckDefExecFailure(['echo getftime(true)'], 'E1013:') + CheckDefExecFailure(['echo getftime(v:null)'], 'E1013:') enddef def Test_getftype() assert_equal('', getftype("")) assert_equal('', getftype(test_null_string())) - CheckDefExecFailure(['echo getftype(true)'], 'E1174:') - CheckDefExecFailure(['echo getftype(v:null)'], 'E1174:') + CheckDefExecFailure(['echo getftype(true)'], 'E1013:') + CheckDefExecFailure(['echo getftype(v:null)'], 'E1013:') enddef def Test_getjumplist() @@ -800,10 +912,27 @@ def Test_getjumplist() CheckDefFailure(['echo getjumplist(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_getmarklist() + CheckDefFailure(['getmarklist([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal([], getmarklist(10000)) + assert_fails('getmarklist("a%b@#")', 'E94:') +enddef + def Test_getmatches() CheckDefFailure(['echo getmatches("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_getpos() + CheckDefFailure(['getpos(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal([0, 1, 1, 0], getpos('.')) + assert_equal([0, 0, 0, 0], getpos('a')) +enddef + +def Test_getqflist() + CheckDefFailure(['getqflist([])'], 'E1013: Argument 1: type mismatch, expected dict but got list') + call assert_equal({}, getqflist({})) +enddef + def Test_getqflist_return_type() var l = getqflist() l->assert_equal([]) @@ -847,6 +976,11 @@ def Test_gettagstack() CheckDefFailure(['echo gettagstack("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_gettext() + CheckDefFailure(['gettext(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal('abc', gettext("abc")) +enddef + def Test_getwininfo() CheckDefFailure(['echo getwininfo("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef @@ -859,6 +993,11 @@ def Test_glob() glob('runtest.vim', true, true, true)->assert_equal(['runtest.vim']) enddef +def Test_glob2regpat() + CheckDefFailure(['glob2regpat(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') + assert_equal('^$', glob2regpat('')) +enddef + def Test_globpath() globpath('.', 'runtest.vim', true, true, true)->assert_equal(['./runtest.vim']) enddef @@ -880,10 +1019,56 @@ def Test_hasmapto() iunabbrev foo enddef +def Test_histadd() + CheckDefFailure(['histadd(1, "x")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['histadd(":", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + histadd("search", 'skyblue') + assert_equal('skyblue', histget('/', -1)) +enddef + +def Test_histnr() + CheckDefFailure(['histnr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal(-1, histnr('abc')) +enddef + +def Test_hlID() + CheckDefFailure(['hlID(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal(0, hlID('NonExistingHighlight')) +enddef + +def Test_hlexists() + CheckDefFailure(['hlexists([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal(0, hlexists('NonExistingHighlight')) +enddef + +def Test_iconv() + CheckDefFailure(['iconv(1, "from", "to")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['iconv("abc", 10, "to")'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefFailure(['iconv("abc", "from", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number') + assert_equal('abc', iconv('abc', 'fromenc', 'toenc')) +enddef + def Test_index() index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef +def Test_inputlist() + CheckDefFailure(['inputlist(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') + CheckDefFailure(['inputlist("abc")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['inputlist([1, 2, 3])'], 'E1013: Argument 1: type mismatch, expected list but got list') + feedkeys("2\", 't') + var r: number = inputlist(['a', 'b', 'c']) + assert_equal(2, r) +enddef + +def Test_inputsecret() + CheckDefFailure(['inputsecret(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['inputsecret("Pass:", 20)'], 'E1013: Argument 2: type mismatch, expected string but got number') + feedkeys("\", 't') + var ans: string = inputsecret('Pass:', '123') + assert_equal('123', ans) +enddef + let s:number_one = 1 let s:number_two = 2 let s:string_keep = 'keep' @@ -928,13 +1113,51 @@ def Test_invert() CheckDefFailure(['echo invert("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_isdirectory() + CheckDefFailure(['isdirectory(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float') + assert_false(isdirectory('NonExistingDir')) +enddef + +def Test_items() + CheckDefFailure(['[]->items()'], 'E1013: Argument 1: type mismatch, expected dict but got list') + assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items()) + assert_equal([], {}->items()) +enddef + +def Test_js_decode() + CheckDefFailure(['js_decode(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal([1, 2], js_decode('[1,2]')) +enddef + +def Test_json_decode() + CheckDefFailure(['json_decode(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool') + assert_equal(1.0, json_decode('1.0')) +enddef + +def Test_keys() + CheckDefFailure(['keys([])'], 'E1013: Argument 1: type mismatch, expected dict but got list') + assert_equal(['a'], {a: 'v'}->keys()) + assert_equal([], {}->keys()) +enddef + def Test_keys_return_type() const var: list = {a: 1, b: 2}->keys() var->assert_equal(['a', 'b']) enddef def Test_line() - assert_fails('line(true)', 'E1174') + assert_fails('line(true)', 'E1174:') +enddef + +def Test_line2byte() + CheckDefFailure(['line2byte(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool') + assert_equal(-1, line2byte(1)) + assert_equal(-1, line2byte(10000)) +enddef + +def Test_lispindent() + CheckDefFailure(['lispindent({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') + assert_equal(0, lispindent(1)) enddef def Test_list2str_str2list_utf8() @@ -1080,6 +1303,13 @@ def Test_max() assert_equal([4, 5], l2) enddef +def Test_menu_info() + CheckDefFailure(['menu_info(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['menu_info(10, "n")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['menu_info("File", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + assert_equal({}, menu_info('aMenu')) +enddef + def Test_min() g:flag = true var l1: list = g:flag @@ -1094,6 +1324,11 @@ def Test_min() assert_equal([4, 5], l2) enddef +def Test_nextnonblank() + CheckDefFailure(['nextnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') + assert_equal(0, nextnonblank(1)) +enddef + def Test_nr2char() nr2char(97, true)->assert_equal('a') enddef @@ -1103,6 +1338,23 @@ def Test_or() CheckDefFailure(['echo or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_prevnonblank() + CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') + assert_equal(0, prevnonblank(1)) +enddef + +def Test_prompt_getprompt() + CheckDefFailure(['prompt_getprompt([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal('', prompt_getprompt('NonExistingBuf')) +enddef + +def Test_rand() + CheckDefFailure(['rand(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') + CheckDefFailure(['rand(["a"])'], 'E1013: Argument 1: type mismatch, expected list but got list') + assert_true(rand() >= 0) + assert_true(rand(srand()) >= 0) +enddef + def Test_readdir() eval expand('sautest')->readdir((e) => e[0] !=# '.') eval expand('sautest')->readdirex((e) => e.name[0] !=# '.') @@ -1134,6 +1386,41 @@ def Test_readfile() delete('Xreadfile') enddef +def Test_reltime() + CheckDefFailure(['reltime("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['reltime(["x", "y"])'], 'E1013: Argument 1: type mismatch, expected list but got list') + CheckDefFailure(['reltime([1, 2], 10)'], 'E1013: Argument 2: type mismatch, expected list but got number') + CheckDefFailure(['reltime([1, 2], ["a", "b"])'], 'E1013: Argument 2: type mismatch, expected list but got list') + var start: list = reltime() + assert_true(type(reltime(start)) == v:t_list) + var end: list = reltime() + assert_true(type(reltime(start, end)) == v:t_list) +enddef + +def Test_reltimefloat() + CheckDefFailure(['reltimefloat("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['reltimefloat([1.1])'], 'E1013: Argument 1: type mismatch, expected list but got list') + assert_true(type(reltimefloat(reltime())) == v:t_float) +enddef + +def Test_reltimestr() + CheckDefFailure(['reltimestr(true)'], 'E1013: Argument 1: type mismatch, expected list but got bool') + CheckDefFailure(['reltimestr([true])'], 'E1013: Argument 1: type mismatch, expected list but got list') + assert_true(type(reltimestr(reltime())) == v:t_string) +enddef + +def Test_remote_foreground() + CheckFeature clientserver + # remote_foreground() doesn't fail on MS-Windows + CheckNotMSWindows + CheckDefFailure(['remote_foreground(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_fails('remote_foreground("NonExistingServer")', 'E241:') +enddef + +def Test_remote_startserver() + CheckDefFailure(['remote_startserver({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') +enddef + def Test_remove_return_type() var l = remove({one: [1, 2], two: [3, 4]}, 'one') var res = 0 @@ -1143,6 +1430,16 @@ def Test_remove_return_type() res->assert_equal(3) enddef +def Test_rename() + CheckDefFailure(['rename(1, "b")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['rename("a", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number') +enddef + +def Test_resolve() + CheckDefFailure(['resolve([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal('SomeFile', resolve('SomeFile')) +enddef + def Test_reverse_return_type() var l = reverse([1, 2, 3]) var res = 0 @@ -1167,6 +1464,13 @@ def Test_screenchars() CheckDefFailure(['echo screenchars(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_screenpos() + CheckDefFailure(['screenpos("a", 1, 1)'], 'E1013: Argument 1: type mismatch, expected number but got string') + CheckDefFailure(['screenpos(1, "b", 1)'], 'E1013: Argument 2: type mismatch, expected number but got string') + CheckDefFailure(['screenpos(1, 1, "c")'], 'E1013: Argument 3: type mismatch, expected number but got string') + assert_equal({col: 1, row: 1, endcol: 1, curscol: 1}, screenpos(1, 1, 1)) +enddef + def Test_screenstring() CheckDefFailure(['echo screenstring("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['echo screenstring(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') @@ -1334,10 +1638,23 @@ def Test_setbufvar() getbufvar('%', 'myvar')->assert_equal(123) enddef +def Test_setcharsearch() + CheckDefFailure(['setcharsearch("x")'], 'E1013: Argument 1: type mismatch, expected dict but got string') + CheckDefFailure(['setcharsearch([])'], 'E1013: Argument 1: type mismatch, expected dict but got list') + var d: dict = {char: 'x', forward: 1, until: 1} + setcharsearch(d) + assert_equal(d, getcharsearch()) +enddef + def Test_setcmdpos() CheckDefFailure(['echo setcmdpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_setfperm() + CheckDefFailure(['setfperm(1, "b")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob') +enddef + def Test_setloclist() var items = [{filename: '/tmp/file', lnum: 1, valid: true}] var what = {items: items} @@ -1353,10 +1670,21 @@ def Test_setreg() assert_fails('setreg("ab", 0)', 'E1162:') enddef +def Test_sha256() + CheckDefFailure(['sha256(100)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['sha256(0zABCD)'], 'E1013: Argument 1: type mismatch, expected string but got blob') + assert_equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', sha256('abc')) +enddef + def Test_shiftwidth() CheckDefFailure(['echo shiftwidth("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_simplify() + CheckDefFailure(['simplify(100)'], 'E1013: Argument 1: type mismatch, expected string but got number') + call assert_equal('NonExistingFile', simplify('NonExistingFile')) +enddef + def Test_slice() assert_equal('12345', slice('012345', 1)) assert_equal('123', slice('012345', 1, 4)) @@ -1388,6 +1716,16 @@ def Test_spellsuggest() endif enddef +def Test_sound_stop() + CheckFeature sound + CheckDefFailure(['sound_stop("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') +enddef + +def Test_soundfold() + CheckDefFailure(['soundfold(20)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal('abc', soundfold('abc')) +enddef + def Test_sort_return_type() var res: list res = [1, 2, 3]->sort() @@ -1408,10 +1746,25 @@ def Test_sort_argument() CheckDefAndScriptSuccess(lines) enddef +def Test_spellbadword() + CheckDefFailure(['spellbadword(100)'], 'E1013: Argument 1: type mismatch, expected string but got number') + spellbadword('good')->assert_equal(['', '']) +enddef + def Test_split() split(' aa bb ', '\W\+', true)->assert_equal(['', 'aa', 'bb', '']) enddef +def Test_srand() + CheckDefFailure(['srand("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') + type(srand(100))->assert_equal(v:t_list) +enddef + +def Test_state() + CheckDefFailure(['state({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') + assert_equal('', state('a')) +enddef + def Run_str2float() if !has('float') MissingFeature 'float' @@ -1439,6 +1792,33 @@ def Test_strchars() strchars("A\u20dd", true)->assert_equal(1) enddef +def Test_strlen() + CheckDefFailure(['strlen([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + "abc"->strlen()->assert_equal(3) + strlen(99)->assert_equal(2) +enddef + +def Test_strptime() + CheckFunction strptime + CheckDefFailure(['strptime(10, "2021")'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefFailure(['strptime("%Y", 2021)'], 'E1013: Argument 2: type mismatch, expected string but got number') + # BUG: Directly calling strptime() in this function gives an "E117: Unknown + # function" error on MS-Windows even with the above CheckFunction call for + # strptime(). + #assert_true(strptime('%Y', '2021') != 0) +enddef + +def Test_strtrans() + CheckDefFailure(['strtrans(20)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal('abc', strtrans('abc')) +enddef + +def Test_strwidth() + CheckDefFailure(['strwidth(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckScriptFailure(['vim9script', 'echo strwidth(10)'], 'E1024:') + assert_equal(4, strwidth('abcd')) +enddef + def Test_submatch() var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)' var Rep = () => range(10)->mapnew((_, v) => submatch(v, true))->string() @@ -1457,6 +1837,16 @@ def Test_substitute() endif enddef +def Test_swapinfo() + CheckDefFailure(['swapinfo({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') + call assert_equal({error: 'Cannot open file'}, swapinfo('x')) +enddef + +def Test_swapname() + CheckDefFailure(['swapname([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_fails('swapname("NonExistingBuf")', 'E94:') +enddef + def Test_synID() new setline(1, "text") @@ -1464,6 +1854,22 @@ def Test_synID() bwipe! enddef +def Test_synIDtrans() + CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') +enddef + +def Test_tabpagebuflist() + CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string') + assert_equal([bufnr('')], tabpagebuflist()) + assert_equal([bufnr('')], tabpagebuflist(1)) +enddef + +def Test_tabpagenr() + CheckDefFailure(['tabpagenr(1)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal(1, tabpagenr('$')) + assert_equal(1, tabpagenr()) +enddef + def Test_term_gettty() if !has('terminal') MissingFeature 'terminal' @@ -1486,6 +1892,12 @@ def Test_term_start() endif enddef +def Test_timer_info() + CheckDefFailure(['timer_info("id")'], 'E1013: Argument 1: type mismatch, expected number but got string') + assert_equal([], timer_info(100)) + assert_equal([], timer_info()) +enddef + def Test_timer_paused() var id = timer_start(50, () => 0) timer_pause(id, true) @@ -1494,6 +1906,11 @@ def Test_timer_paused() timer_stop(id) enddef +def Test_timer_stop() + CheckDefFailure(['timer_stop("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') + assert_equal(0, timer_stop(100)) +enddef + def Test_tolower() CheckDefFailure(['echo tolower(1)'], 'E1013: Argument 1: type mismatch, expected string but got number') enddef @@ -1508,17 +1925,46 @@ def Test_tr() CheckDefFailure(['echo tr("a", "a", 1)'], 'E1013: Argument 3: type mismatch, expected string but got number') enddef +def Test_undofile() + CheckDefFailure(['undofile(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') + assert_equal('.abc.un~', fnamemodify(undofile('abc'), ':t')) +enddef + +def Test_values() + CheckDefFailure(['values([])'], 'E1013: Argument 1: type mismatch, expected dict but got list') + assert_equal([], {}->values()) + assert_equal(['sun'], {star: 'sun'}->values()) +enddef + def Test_win_execute() assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()')) assert_equal('', win_execute(342343, 'echo winnr()')) enddef +def Test_win_findbuf() + CheckDefFailure(['win_findbuf("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') + assert_equal([], win_findbuf(1000)) + assert_equal([win_getid()], win_findbuf(bufnr(''))) +enddef + +def Test_win_getid() + CheckDefFailure(['win_getid(".")'], 'E1013: Argument 1: type mismatch, expected number but got string') + CheckDefFailure(['win_getid(1, ".")'], 'E1013: Argument 2: type mismatch, expected number but got string') + assert_equal(win_getid(), win_getid(1, 1)) +enddef + def Test_win_splitmove() split win_splitmove(1, 2, {vertical: true, rightbelow: true}) close enddef +def Test_winnr() + CheckDefFailure(['winnr([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal(1, winnr()) + assert_equal(1, winnr('$')) +enddef + def Test_winrestcmd() split var cmd = winrestcmd() @@ -1528,6 +1974,14 @@ def Test_winrestcmd() close enddef +def Test_winrestview() + CheckDefFailure(['winrestview([])'], 'E1013: Argument 1: type mismatch, expected dict but got list') + :%d _ + setline(1, 'Hello World') + winrestview({lnum: 1, col: 6}) + assert_equal([1, 7], [line('.'), col('.')]) +enddef + def Test_winsaveview() var view: dict = winsaveview() diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 9170cc9563..22c68f4ae4 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2970,13 +2970,6 @@ def Test_expr7_method_call() END CheckDefAndScriptSuccess(lines) - lines =<< trim END - def RetVoid() - enddef - RetVoid()->byte2line() - END - CheckDefExecAndScriptFailure(lines, 'E1031:') - lines =<< trim END def RetVoid() enddef diff --git a/src/version.c b/src/version.c index 540fa2b6c8..db88afd8d9 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3084, /**/ 3083, /**/ From acbb4b5720fc27b8b07357b763ed4e5a944ae1da Mon Sep 17 00:00:00 2001 From: Izhak Jakov Date: Sat, 3 Jul 2021 13:09:37 +0200 Subject: [PATCH 15/38] patch 8.2.3085: JSONC files are not recognized Problem: JSONC files are not recognized. Solution: Recognize .jsonc files. (Izhak Jakov, closes #8500) --- runtime/filetype.vim | 3 +++ src/testdir/test_filetype.vim | 1 + src/version.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index e38bc23de0..952a9a66fa 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -868,6 +868,9 @@ au BufNewFile,BufRead *.json-patch setf json " Jupyter Notebook is also json au BufNewFile,BufRead *.ipynb setf json +" JSONC +au BufNewFile,BufRead *.jsonc setf jsonc + " Kixtart au BufNewFile,BufRead *.kix setf kix diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 50293e524d..b0eb4aff61 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -260,6 +260,7 @@ let s:filename_checks = { \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'], \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'], + \ 'jsonc': ['file.jsonc'], \ 'jsp': ['file.jsp'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'], \ 'kivy': ['file.kv'], diff --git a/src/version.c b/src/version.c index db88afd8d9..70c1b6b97a 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3085, /**/ 3084, /**/ From 6fc016168249360f0524b68f72cf33efd0574d40 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 13:36:31 +0200 Subject: [PATCH 16/38] patch 8.2.3086: Vim9: breakpoint on "for" does not work Problem: Vim9: breakpoint on "for" does not work. Solution: Use the right line number in ISN_DEBUG. (closes #8486) --- src/testdir/test_debugger.vim | 16 ++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 12 ++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim index dbf2000462..bb3a24669d 100644 --- a/src/testdir/test_debugger.vim +++ b/src/testdir/test_debugger.vim @@ -1017,6 +1017,13 @@ func Test_debug_def_function() # comment echo "second" enddef + def g:FuncForLoop() + eval 1 + for i in [11, 22, 33] + eval i + endfor + echo "done" + enddef END call writefile(file, 'Xtest.vim') @@ -1062,6 +1069,15 @@ func Test_debug_def_function() call RunDbgCmd(buf, ':call FuncComment()', ['function FuncComment', 'line 2: echo "first" .. "one"']) call RunDbgCmd(buf, ':breakadd func 3 FuncComment') call RunDbgCmd(buf, 'cont', ['function FuncComment', 'line 5: echo "second"']) + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, ':breakadd func 2 FuncForLoop') + call RunDbgCmd(buf, ':call FuncForLoop()', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) + call RunDbgCmd(buf, 'echo i', ['11']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 3: eval i']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 4: endfor']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) + call RunDbgCmd(buf, 'echo i', ['22']) call RunDbgCmd(buf, 'cont') call StopVimInTerminal(buf) diff --git a/src/version.c b/src/version.c index 70c1b6b97a..6ca650fe0e 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3086, /**/ 3085, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 533c0b33eb..d074215713 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -7747,6 +7747,7 @@ compile_for(char_u *arg_start, cctx_T *cctx) type_T *vartype; type_T *item_type = &t_any; int idx; + int prev_lnum = cctx->ctx_prev_lnum; p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE); if (p == NULL) @@ -7774,7 +7775,11 @@ compile_for(char_u *arg_start, cctx_T *cctx) if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0 && ((isn_T *)instr->ga_data)[instr->ga_len - 1] .isn_type == ISN_DEBUG) + { --instr->ga_len; + prev_lnum = ((isn_T *)instr->ga_data)[instr->ga_len] + .isn_arg.debug.dbg_break_lnum; + } scope = new_scope(cctx, FOR_SCOPE); if (scope == NULL) @@ -7934,8 +7939,15 @@ compile_for(char_u *arg_start, cctx_T *cctx) } if (cctx->ctx_compile_type == CT_DEBUG) + { + int save_prev_lnum = cctx->ctx_prev_lnum; + // Add ISN_DEBUG here, so that the loop variables can be inspected. + // Use the prev_lnum from the ISN_DEBUG instruction removed above. + cctx->ctx_prev_lnum = prev_lnum; generate_instr_debug(cctx); + cctx->ctx_prev_lnum = save_prev_lnum; + } return arg_end; From fcde67c99fbb6d7294e01b9e87d8d2ae7af31255 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 13:51:44 +0200 Subject: [PATCH 17/38] patch 8.2.3087: Gemtext files are not recognized Problem: Gemtext files are not recognized. Solution: Recognize .gmi and .gemini files. (closes #8427) --- runtime/filetype.vim | 3 +++ src/testdir/test_filetype.vim | 1 + src/version.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 952a9a66fa..2cb3f0b1d0 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -650,6 +650,9 @@ au BufNewFile,BufRead *.mo,*.gdmo setf gdmo " Gedcom au BufNewFile,BufRead *.ged,lltxxxxx.txt setf gedcom +" Gemtext +au BufNewFile,BufRead *.gmi,*.gemini setf gemtext + " Gift (Moodle) autocmd BufRead,BufNewFile *.gift setf gift diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index b0eb4aff61..e78a1f4ec0 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -192,6 +192,7 @@ let s:filename_checks = { \ 'gdb': ['.gdbinit'], \ 'gdmo': ['file.mo', 'file.gdmo'], \ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'], + \ 'gemtext': ['file.gmi', 'file.gemini'], \ 'gift': ['file.gift'], \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'], \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'], diff --git a/src/version.c b/src/version.c index 6ca650fe0e..242b556ac4 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3087, /**/ 3086, /**/ From 9cee4a1c9c69542ccd73bcd2db05920150856361 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 15:08:37 +0200 Subject: [PATCH 18/38] patch 8.2.3088: with 'virtualedit' set to "block" Visual highlight is wrong Problem: With 'virtualedit' set to "block" Visual highlight is wrong after using "$". (Marco Trosi) Solution: Do not set w_old_cursor_lcol to MAXCOL. (closes #8495) --- src/drawscreen.c | 4 +++- .../Test_visual_block_with_virtualedit.dump | 8 +++++++ src/testdir/test_visual.vim | 21 +++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/testdir/dumps/Test_visual_block_with_virtualedit.dump diff --git a/src/drawscreen.c b/src/drawscreen.c index bb0d8878e8..77a8a7b276 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2007,7 +2007,9 @@ win_update(win_T *wp) ve_flags = save_ve_flags; #endif ++toc; - if (curwin->w_curswant == MAXCOL) + // Highlight to the end of the line, unless 'virtualedit' has + // "block". + if (curwin->w_curswant == MAXCOL && !(ve_flags & VE_BLOCK)) toc = MAXCOL; if (fromc != wp->w_old_cursor_fcol diff --git a/src/testdir/dumps/Test_visual_block_with_virtualedit.dump b/src/testdir/dumps/Test_visual_block_with_virtualedit.dump new file mode 100644 index 0000000000..2991a633b6 --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_with_virtualedit.dump @@ -0,0 +1,8 @@ +|a+0&#e0e0e08@5> +0&#ffffff0@43 +|b+0&#e0e0e08@3| @2| +0&#ffffff0@42 +|c+0&#e0e0e08@1| @4| +0&#ffffff0@42 +|~+0#4040ff13&| @48 +|~| @48 +|~| @48 +|~| @48 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@3|3|x|7| @6|1|,|7| @10|A|l@1| diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 789ff6f608..5b2a32cfee 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -2,6 +2,7 @@ source shared.vim source check.vim +source screendump.vim func Test_block_shift_multibyte() " Uses double-wide character. @@ -1241,5 +1242,25 @@ func Test_visual_put_blockedit_zy_and_zp() bw! endfunc +func Test_visual_block_with_virtualedit() + CheckScreendump + + let lines =<< trim END + call setline(1, ['aaaaaa', 'bbbb', 'cc']) + set virtualedit=block + normal G + END + call writefile(lines, 'XTest_block') + + let buf = RunVimInTerminal('-S XTest_block', {'rows': 8, 'cols': 50}) + call term_sendkeys(buf, "\gg$") + call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit', {}) + + " clean up + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) + call delete('XTest_beval') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 242b556ac4..0c98a98b32 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3088, /**/ 3087, /**/ From 20cc52832067d22a3cd47dfb0805251228c32e7d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 16:33:16 +0200 Subject: [PATCH 19/38] patch 8.2.3089: garbage collection has useless code Problem: Garbage collection has useless code. Solution: Bail out when aborting. (closes #8504) --- src/userfunc.c | 59 ++++++++++++++++++++++++-------------------------- src/version.c | 2 ++ 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/userfunc.c b/src/userfunc.c index 06fca0cf01..7e7c0f6f63 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -5478,35 +5478,32 @@ find_var_in_scoped_ht(char_u *name, int no_autoload) int set_ref_in_previous_funccal(int copyID) { - int abort = FALSE; funccall_T *fc; - for (fc = previous_funccal; !abort && fc != NULL; fc = fc->caller) + for (fc = previous_funccal; fc != NULL; fc = fc->caller) { fc->fc_copyID = copyID + 1; - abort = abort - || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_list_items(&fc->l_varlist, copyID + 1, NULL); + if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_list_items(&fc->l_varlist, copyID + 1, NULL)) + return TRUE; } - return abort; + return FALSE; } static int set_ref_in_funccal(funccall_T *fc, int copyID) { - int abort = FALSE; - if (fc->fc_copyID != copyID) { fc->fc_copyID = copyID; - abort = abort - || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) - || set_ref_in_list_items(&fc->l_varlist, copyID, NULL) - || set_ref_in_func(NULL, fc->func, copyID); + if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) + || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) + || set_ref_in_list_items(&fc->l_varlist, copyID, NULL) + || set_ref_in_func(NULL, fc->func, copyID)) + return TRUE; } - return abort; + return FALSE; } /* @@ -5515,19 +5512,19 @@ set_ref_in_funccal(funccall_T *fc, int copyID) int set_ref_in_call_stack(int copyID) { - int abort = FALSE; funccall_T *fc; funccal_entry_T *entry; - for (fc = current_funccal; !abort && fc != NULL; fc = fc->caller) - abort = abort || set_ref_in_funccal(fc, copyID); + for (fc = current_funccal; fc != NULL; fc = fc->caller) + if (set_ref_in_funccal(fc, copyID)) + return TRUE; // Also go through the funccal_stack. - for (entry = funccal_stack; !abort && entry != NULL; entry = entry->next) - for (fc = entry->top_funccal; !abort && fc != NULL; fc = fc->caller) - abort = abort || set_ref_in_funccal(fc, copyID); - - return abort; + for (entry = funccal_stack; entry != NULL; entry = entry->next) + for (fc = entry->top_funccal; fc != NULL; fc = fc->caller) + if (set_ref_in_funccal(fc, copyID)) + return TRUE; + return FALSE; } /* @@ -5538,7 +5535,6 @@ set_ref_in_functions(int copyID) { int todo; hashitem_T *hi = NULL; - int abort = FALSE; ufunc_T *fp; todo = (int)func_hashtab.ht_used; @@ -5548,11 +5544,12 @@ set_ref_in_functions(int copyID) { --todo; fp = HI2UF(hi); - if (!func_name_refcount(fp->uf_name)) - abort = abort || set_ref_in_func(NULL, fp, copyID); + if (!func_name_refcount(fp->uf_name) + && set_ref_in_func(NULL, fp, copyID)) + return TRUE; } } - return abort; + return FALSE; } /* @@ -5562,12 +5559,12 @@ set_ref_in_functions(int copyID) set_ref_in_func_args(int copyID) { int i; - int abort = FALSE; for (i = 0; i < funcargs.ga_len; ++i) - abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i], - copyID, NULL, NULL); - return abort; + if (set_ref_in_item(((typval_T **)funcargs.ga_data)[i], + copyID, NULL, NULL)) + return TRUE; + return FALSE; } /* diff --git a/src/version.c b/src/version.c index 0c98a98b32..eb9f9f3f12 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3089, /**/ 3088, /**/ From 00aaa512d5e775e0db21e251f43d7afb8fca910f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 18:04:11 +0200 Subject: [PATCH 20/38] patch 8.2.3090: in rare cases the cursor may be somewhere in a folded line Problem: With concealing enabled and indirectly closing a fold the cursor may be somewhere in a folded line. Solution: Recompute the cursor position when the cursor line can be concealed. (closes #8480) --- src/drawscreen.c | 6 ++++++ src/version.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/drawscreen.c b/src/drawscreen.c index 77a8a7b276..7927bedc23 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -1379,6 +1379,12 @@ fold_line( curwin->w_cline_folded = TRUE; curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); } + +# ifdef FEAT_CONCEAL + // When the line was not folded w_wrow may have been set, recompute it. + if (wp == curwin && lnum == wp->w_cursor.lnum && conceal_cursor_line(wp)) + curs_columns(TRUE); +# endif } #endif diff --git a/src/version.c b/src/version.c index eb9f9f3f12..0cefeba32b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3090, /**/ 3089, /**/ From e28d9b3bd4de2c7288add83ec35dc001ba280617 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 18:56:53 +0200 Subject: [PATCH 21/38] patch 8.2.3091: Vim9: default argument expr. cannot use previous argument Problem: Vim9: default argument expression cannot use previous argument Solution: Correct argument index. (closes #8496) --- src/structs.h | 2 ++ src/testdir/test_vim9_func.vim | 6 ++++++ src/version.c | 2 ++ src/vim9compile.c | 7 +++---- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/structs.h b/src/structs.h index d6f4988e72..be4082b935 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1610,6 +1610,8 @@ typedef struct int uf_dfunc_idx; // only valid if uf_def_status is UF_COMPILED garray_T uf_args; // arguments, including optional arguments garray_T uf_def_args; // default argument expressions + int uf_args_visible; // normally uf_args.ga_len, less when + // compiling default argument expression. // for :def (for :function uf_ret_type is NULL) type_T **uf_arg_types; // argument types (count == uf_args.ga_len) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 4816cb6674..f4142ee851 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -452,6 +452,12 @@ def Test_call_default_args() MyDefaultThird('->', 'xx', v:none)->assert_equal('->xxbb') MyDefaultThird('->', v:none, 'yy')->assert_equal('->aayy') MyDefaultThird('->', 'xx', 'yy')->assert_equal('->xxyy') + + def DefArg(mandatory: any, optional = mandatory): string + return mandatory .. optional + enddef + DefArg(1234)->assert_equal('12341234') + DefArg("ok")->assert_equal('okok') END CheckDefAndScriptSuccess(lines) diff --git a/src/version.c b/src/version.c index 0cefeba32b..5f07483581 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3091, /**/ 3090, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index d074215713..88086cefd6 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -274,7 +274,7 @@ arg_exists( if (len == 0) return FAIL; - for (idx = 0; idx < cctx->ctx_ufunc->uf_args.ga_len; ++idx) + for (idx = 0; idx < cctx->ctx_ufunc->uf_args_visible; ++idx) { char_u *arg = FUNCARG(cctx->ctx_ufunc, idx); @@ -9172,7 +9172,6 @@ compile_def_function( { int count = ufunc->uf_def_args.ga_len; int first_def_arg = ufunc->uf_args.ga_len - count; - int uf_args_len = ufunc->uf_args.ga_len; int i; char_u *arg; int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0); @@ -9195,12 +9194,11 @@ compile_def_function( goto erret; // Make sure later arguments are not found. - ufunc->uf_args.ga_len = i; + ufunc->uf_args_visible = arg_idx; arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i]; r = compile_expr0(&arg, &cctx); - ufunc->uf_args.ga_len = uf_args_len; if (r == FAIL) goto erret; @@ -9230,6 +9228,7 @@ compile_def_function( if (did_set_arg_type) set_function_type(ufunc); } + ufunc->uf_args_visible = ufunc->uf_args.ga_len; /* * Loop over all the lines of the function and generate instructions. From 74509239df107b04abe4f30ada12109629c85939 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Sat, 3 Jul 2021 19:27:37 +0200 Subject: [PATCH 22/38] patch 8.2.3092: Vim9: builtin function test fails without +channel feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Vim9: builtin function test fails without the +channel feature. Solution: Check the +channel feature is supported. (Dominique Pellé, closes #8507) --- runtime/doc/eval.txt | 7 +++++++ src/testdir/test_vim9_builtin.vim | 6 ++++-- src/version.c | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 2eceece64b..401f055f7d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -8219,6 +8219,8 @@ prompt_getprompt({buf}) *prompt_getprompt()* Can also be used as a |method|: > GetBuffer()->prompt_getprompt() +< {only available when compiled with the |+channel| feature} + prompt_setcallback({buf}, {expr}) *prompt_setcallback()* Set prompt callback for buffer {buf} to {expr}. When {expr} @@ -8252,6 +8254,7 @@ prompt_setcallback({buf}, {expr}) *prompt_setcallback()* < Can also be used as a |method|: > GetBuffer()->prompt_setcallback(callback) +< {only available when compiled with the |+channel| feature} prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()* Set a callback for buffer {buf} to {expr}. When {expr} is an @@ -8265,6 +8268,8 @@ prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()* Can also be used as a |method|: > GetBuffer()->prompt_setinterrupt(callback) +< {only available when compiled with the |+channel| feature} + prompt_setprompt({buf}, {text}) *prompt_setprompt()* Set prompt for buffer {buf} to {text}. You most likely want {text} to end in a space. @@ -8275,6 +8280,8 @@ prompt_setprompt({buf}, {text}) *prompt_setprompt()* Can also be used as a |method|: > GetBuffer()->prompt_setprompt('command: ') +< {only available when compiled with the |+channel| feature} + prop_ functions are documented here: |text-prop-functions| pum_getpos() *pum_getpos()* diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 5a5b512d8c..38bd8271c8 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1344,8 +1344,10 @@ def Test_prevnonblank() enddef def Test_prompt_getprompt() - CheckDefFailure(['prompt_getprompt([])'], 'E1013: Argument 1: type mismatch, expected string but got list') - assert_equal('', prompt_getprompt('NonExistingBuf')) + if has('channel') + CheckDefFailure(['prompt_getprompt([])'], 'E1013: Argument 1: type mismatch, expected string but got list') + assert_equal('', prompt_getprompt('NonExistingBuf')) + endif enddef def Test_rand() diff --git a/src/version.c b/src/version.c index 5f07483581..0d4fc1242d 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3092, /**/ 3091, /**/ From fb773a3e0aa9466bb953c29bad0bf4ba34461a40 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 21:37:59 +0200 Subject: [PATCH 23/38] patch 8.2.3093: tablabel_tooltip test fails with Athena MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: tablabel_tooltip test fails with Athena. (Dominique Pellé) Solution: Skip the test when using Athena. (closes #8508) --- src/testdir/check.vim | 11 +++++++++++ src/testdir/test_gui.vim | 2 ++ src/version.c | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/testdir/check.vim b/src/testdir/check.vim index 4c5f3eef5d..d6bfe004a6 100644 --- a/src/testdir/check.vim +++ b/src/testdir/check.vim @@ -14,6 +14,17 @@ func CheckFeature(name) endif endfunc +" Command to check for the absence of a feature. +command -nargs=1 CheckNotFeature call CheckNotFeature() +func CheckNotFeature(name) + if !has(a:name, 1) + throw 'Checking for non-existent feature ' .. a:name + endif + if has(a:name) + throw 'Skipped: ' .. a:name .. ' feature present' + endif +endfunc + " Command to check for the presence of a working option. command -nargs=1 CheckOption call CheckOption() func CheckOption(name) diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 762e332edc..b727372a26 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -1118,6 +1118,8 @@ func TestGuiTabToolTip() endfunc func Test_gui_tablabel_tooltip() + CheckNotFeature gui_athena + %bw! " Removing the tabline at the end of this test, reduces the window height by " one. Save and restore it after the test. diff --git a/src/version.c b/src/version.c index 0d4fc1242d..3b8a50a701 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3093, /**/ 3092, /**/ From c60e959cba03fae9cff9b2674fab646cc70819fc Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Sat, 3 Jul 2021 21:41:38 +0200 Subject: [PATCH 24/38] patch 8.2.3094: Test_popup_atcursor_pos() fails without the conceal feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Test_popup_atcursor_pos() fails without the conceal feature. Solution: Add a check for the conceal feature. (Dominique Pellé, closes #8505) --- src/testdir/test_popupwin.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index cdfa3a987b..8e02ef1f03 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1437,6 +1437,7 @@ endfunc func Test_popup_atcursor_pos() CheckScreendump + CheckFeature conceal let lines =<< trim END call setline(1, repeat([repeat('-', 60)], 15)) diff --git a/src/version.c b/src/version.c index 3b8a50a701..79a6a85998 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3094, /**/ 3093, /**/ From b17ab86e7b8712206aa9ea7198c28db969e25936 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 3 Jul 2021 22:15:17 +0200 Subject: [PATCH 25/38] patch 8.2.3095: with 'virtualedit' set to "block" block selection is wrong Problem: With 'virtualedit' set to "block" block selection is wrong after using "$". (Marco Trosi) Solution: Compute the longest selected line. (closes #8495) --- src/drawscreen.c | 33 +++++++++++++++++-- .../Test_visual_block_with_virtualedit2.dump | 8 +++++ src/testdir/test_visual.vim | 3 ++ src/version.c | 2 ++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/testdir/dumps/Test_visual_block_with_virtualedit2.dump diff --git a/src/drawscreen.c b/src/drawscreen.c index 7927bedc23..5f531f2d00 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2009,14 +2009,41 @@ win_update(win_T *wp) ve_flags = VE_ALL; #endif getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); + ++toc; #if defined(FEAT_LINEBREAK) ve_flags = save_ve_flags; #endif - ++toc; // Highlight to the end of the line, unless 'virtualedit' has // "block". - if (curwin->w_curswant == MAXCOL && !(ve_flags & VE_BLOCK)) - toc = MAXCOL; + if (curwin->w_curswant == MAXCOL) + { + if (ve_flags & VE_BLOCK) + { + pos_T pos; + int cursor_above = + curwin->w_cursor.lnum < VIsual.lnum; + + // Need to find the longest line. + toc = 0; + pos.coladd = 0; + for (pos.lnum = curwin->w_cursor.lnum; cursor_above + ? pos.lnum <= VIsual.lnum + : pos.lnum >= VIsual.lnum; + pos.lnum += cursor_above ? 1 : -1) + { + colnr_T t; + + pos.col = STRLEN(ml_get_buf(wp->w_buffer, + pos.lnum, FALSE)); + getvvcol(wp, &pos, NULL, NULL, &t); + if (toc < t) + toc = t; + } + ++toc; + } + else + toc = MAXCOL; + } if (fromc != wp->w_old_cursor_fcol || toc != wp->w_old_cursor_lcol) diff --git a/src/testdir/dumps/Test_visual_block_with_virtualedit2.dump b/src/testdir/dumps/Test_visual_block_with_virtualedit2.dump new file mode 100644 index 0000000000..3c62156128 --- /dev/null +++ b/src/testdir/dumps/Test_visual_block_with_virtualedit2.dump @@ -0,0 +1,8 @@ +|a+0&#e0e0e08@5| | +0&#ffffff0@42 +|b+0&#e0e0e08@3| @2| +0&#ffffff0@42 +|c+0&#e0e0e08@1> +0&#ffffff0| +0&#e0e0e08@3| +0&#ffffff0@42 +|~+0#4040ff13&| @48 +|~| @48 +|~| @48 +|~| @48 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@3|3|x|3| @6|3|,|3| @10|A|l@1| diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 5b2a32cfee..3df6533d1b 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1256,6 +1256,9 @@ func Test_visual_block_with_virtualedit() call term_sendkeys(buf, "\gg$") call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit', {}) + call term_sendkeys(buf, "\gg\G$") + call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit2', {}) + " clean up call term_sendkeys(buf, "\") call StopVimInTerminal(buf) diff --git a/src/version.c b/src/version.c index 79a6a85998..e4bb59685e 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3095, /**/ 3094, /**/ From 6c72fd51a899e6f0c272b08b9784d3c7a3cede20 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Sun, 4 Jul 2021 12:30:06 +0200 Subject: [PATCH 26/38] patch 8.2.3096: temp files remain after running tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Temp files remain after running tests. Solution: Delete the right files. (Dominique Pellé, closes #8509) --- src/testdir/test_debugger.vim | 3 +-- src/testdir/test_lambda.vim | 1 + src/testdir/test_visual.vim | 2 +- src/version.c | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim index bb3a24669d..97e115bf3e 100644 --- a/src/testdir/test_debugger.vim +++ b/src/testdir/test_debugger.vim @@ -975,8 +975,7 @@ func Test_debug_def_and_legacy_function() call RunDbgCmd(buf, 'cont') call StopVimInTerminal(buf) - call delete('Xtest1.vim') - call delete('Xtest2.vim') + call delete('XtestDebug.vim') endfunc func Test_debug_def_function() diff --git a/src/testdir/test_lambda.vim b/src/testdir/test_lambda.vim index 60d58c542b..e173ea3893 100644 --- a/src/testdir/test_lambda.vim +++ b/src/testdir/test_lambda.vim @@ -330,6 +330,7 @@ func Test_closure_error() let caught_932 = 1 endtry call assert_equal(1, caught_932) + call delete('Xscript') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 3df6533d1b..10929519b4 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1262,7 +1262,7 @@ func Test_visual_block_with_virtualedit() " clean up call term_sendkeys(buf, "\") call StopVimInTerminal(buf) - call delete('XTest_beval') + call delete('XTest_block') endfunc diff --git a/src/version.c b/src/version.c index e4bb59685e..fde11a75ec 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3096, /**/ 3095, /**/ From 1d97efce0ce31ddf0dd4c1ae2228ef4caee6880c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 13:27:11 +0200 Subject: [PATCH 27/38] patch 8.2.3097: crash when using "quit" at recovery prompt Problem: Crash when using "quit" at recovery prompt and autocommands are triggered. Solution: Block autocommands when creating an empty buffer to use as the current buffer. (closes #8506) --- src/buffer.c | 5 +++++ src/testdir/test_swap.vim | 12 ++++++++++++ src/version.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index 59f51aaf7a..60aa32f0c9 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1130,7 +1130,12 @@ handle_swap_exists(bufref_T *old_curbuf) close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE, FALSE); if (old_curbuf == NULL || !bufref_valid(old_curbuf) || old_curbuf->br_buf == curbuf) + { + // Block autocommands here because curwin->w_buffer is NULL. + block_autocmds(); buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); + unblock_autocmds(); + } else buf = old_curbuf->br_buf; if (buf != NULL) diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index caacd7e175..4bc325d333 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -360,6 +360,7 @@ func Test_swap_prompt_splitwin() let buf = RunVimInTerminal('', {'rows': 20}) call term_sendkeys(buf, ":set nomore\n") call term_sendkeys(buf, ":set noruler\n") + call term_sendkeys(buf, ":split Xfile1\n") call TermWait(buf) call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))}) @@ -371,8 +372,19 @@ func Test_swap_prompt_splitwin() call TermWait(buf) call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))}) call StopVimInTerminal(buf) + + " This caused Vim to crash when typing "q". + " TODO: it does not actually reproduce the crash. + call writefile(['au BufAdd * set virtualedit=all'], 'Xvimrc') + + let buf = RunVimInTerminal('-u Xvimrc Xfile1', {'rows': 20, 'wait_for_ruler': 0}) + call TermWait(buf) + call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 20))}) + call term_sendkeys(buf, "q") + %bwipe! call delete('Xfile1') + call delete('Xvimrc') endfunc func Test_swap_symlink() diff --git a/src/version.c b/src/version.c index fde11a75ec..f6d5758aca 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3097, /**/ 3096, /**/ From 999db2346b61e6f6e6fde2d0b56f4646a46b727d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 14:00:55 +0200 Subject: [PATCH 28/38] patch 8.2.3098: popup window test is flaky on MS-Windows with GUI Problem: Popup window test is flaky on MS-Windows with GUI. Solution: Skip the check in this situation. --- src/testdir/test_popupwin.vim | 12 ++++++++++-- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 8e02ef1f03..62e19fa5d2 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1550,24 +1550,32 @@ func Test_popup_filter() redraw " e is consumed by the filter + let g:eaten = '' call feedkeys('e', 'xt') call assert_equal('e', g:eaten) call feedkeys("\", 'xt') call assert_equal("\", g:eaten) " 0 is ignored by the filter + let g:ignored = '' normal $ call assert_equal(9, getcurpos()[2]) call feedkeys('0', 'xt') call assert_equal('0', g:ignored) - normal! l - call assert_equal(2, getcurpos()[2]) + + if has('win32') && has('gui_running') + echo "FIXME: this check is very flaky on MS-Windows GUI, the cursor doesn't move" + else + call assert_equal(1, getcurpos()[2]) + endif " x closes the popup call feedkeys('x', 'xt') call assert_equal("\", g:eaten) call assert_equal(-1, winbufnr(winid)) + unlet g:eaten + unlet g:ignored delfunc MyPopupFilter call popup_clear() endfunc diff --git a/src/version.c b/src/version.c index f6d5758aca..8d391d331d 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3098, /**/ 3097, /**/ From 4197828dc666f2d258594f7f9461534d23cc50e4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 14:47:30 +0200 Subject: [PATCH 29/38] patch 8.2.3099: Vim9: missing catch/finally not reported at script level Problem: Vim9: missing catch/finally not reported at script level. Solution: Give an error. (closes #8487) --- src/ex_eval.c | 14 ++++++++++++-- src/structs.h | 9 +++++---- src/testdir/test_vim9_script.vim | 9 +++++++++ src/version.c | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ex_eval.c b/src/ex_eval.c index d68e792449..dac70ab3ac 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -1670,6 +1670,8 @@ ex_catch(exarg_T *eap) for (idx = cstack->cs_idx; idx > 0; --idx) if (cstack->cs_flags[idx] & CSF_TRY) break; + if (cstack->cs_flags[idx] & CSF_TRY) + cstack->cs_flags[idx] |= CSF_CATCH; if (cstack->cs_flags[idx] & CSF_FINALLY) { // Give up for a ":catch" after ":finally" and ignore it. @@ -1963,8 +1965,8 @@ ex_endtry(exarg_T *eap) * made inactive by a ":continue", ":break", ":return", or ":finish" in * the finally clause. The latter case need not be tested since then * anything pending has already been discarded. */ - skip = did_emsg || got_int || did_throw || - !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); + skip = did_emsg || got_int || did_throw + || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) { @@ -1992,6 +1994,14 @@ ex_endtry(exarg_T *eap) { idx = cstack->cs_idx; + if (in_vim9script() + && (cstack->cs_flags[idx] & (CSF_CATCH|CSF_FINALLY)) == 0) + { + // try/endtry without any catch or finally: give an error and + // continue. + eap->errmsg = _(e_missing_catch_or_finally); + } + /* * If we stopped with the exception currently being thrown at this * try conditional since we didn't know that it doesn't have diff --git a/src/structs.h b/src/structs.h index be4082b935..f1f8f32583 100644 --- a/src/structs.h +++ b/src/structs.h @@ -936,13 +936,14 @@ typedef struct { # define CSF_TRY 0x0100 // is a ":try" # define CSF_FINALLY 0x0200 // ":finally" has been passed -# define CSF_THROWN 0x0400 // exception thrown to this try conditional -# define CSF_CAUGHT 0x0800 // exception caught by this try conditional -# define CSF_SILENT 0x1000 // "emsg_silent" reset by ":try" +# define CSF_CATCH 0x0400 // ":catch" has been seen +# define CSF_THROWN 0x0800 // exception thrown to this try conditional +# define CSF_CAUGHT 0x1000 // exception caught by this try conditional +# define CSF_SILENT 0x2000 // "emsg_silent" reset by ":try" // Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset // (an ":if"), and CSF_SILENT is only used when CSF_TRY is set. // -#define CSF_FUNC_DEF 0x2000 // a function was defined in this block +#define CSF_FUNC_DEF 0x4000 // a function was defined in this block /* * What's pending for being reactivated at the ":endtry" of this try diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index dfb1a41bb1..9cf098917c 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -603,6 +603,15 @@ def Test_try_catch_throw() CheckScriptSuccess(lines) assert_match('E808: Number or Float required', g:caught) unlet g:caught + + # missing catch and/or finally + lines =<< trim END + vim9script + try + echo 'something' + endtry + END + CheckScriptFailure(lines, 'E1032:') enddef def Test_try_in_catch() diff --git a/src/version.c b/src/version.c index 8d391d331d..062e856e04 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3099, /**/ 3098, /**/ From 7a40ff00edd35cc4313d74a43e7a7b67cd24372d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 15:54:08 +0200 Subject: [PATCH 30/38] patch 8.2.3100: Vim9: no error when using type with unknown number of args Problem: Vim9: no error when using type with unknown number of arguments. Solution: Do not ignore argument count of -1. (closes #8492) --- src/evalfunc.c | 12 ++++++++++++ src/proto/evalfunc.pro | 2 +- src/testdir/test_vim9_assign.vim | 9 +++++++++ src/testdir/test_vim9_expr.vim | 2 +- src/testdir/test_vim9_func.vim | 2 +- src/version.c | 2 ++ src/vim9type.c | 14 +++++++++----- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index e635116786..ec74fdeeae 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2054,6 +2054,18 @@ internal_func_check_arg_types( return OK; } +/* + * Get the argument count for function "idx". + * "argcount" is the total argument count, "min_argcount" the non-optional + * argument count. + */ + void +internal_func_get_argcount(int idx, int *argcount, int *min_argcount) +{ + *argcount = global_functions[idx].f_max_argc; + *min_argcount = global_functions[idx].f_min_argc; +} + /* * Call the "f_retfunc" function to obtain the return type of function "idx". * "argtypes" is the list of argument types or NULL when there are no diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro index c1ac55f5b9..3faff292a7 100644 --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -6,6 +6,7 @@ int find_internal_func(char_u *name); int has_internal_func(char_u *name); char *internal_func_name(int idx); int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx); +void internal_func_get_argcount(int idx, int *argcount, int *min_argcount); type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes); int internal_func_is_map(int idx); int check_internal_func(int idx, int argcount); @@ -21,7 +22,6 @@ void f_has(typval_T *argvars, typval_T *rettv); int dynamic_feature(char_u *feature); void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv); void range_list_materialize(list_T *list); -float_T vim_round(float_T f); long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit); void f_string(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 86f890ea09..92ffa0055c 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -650,6 +650,15 @@ def Test_assignment_list() d.dd[0] = 0 END CheckDefExecFailure(lines, 'E1147:', 2) + + lines =<< trim END + def OneArg(x: bool) + enddef + def TwoArgs(x: bool, y: bool) + enddef + var fl: list = [OneArg, TwoArgs] + END + CheckDefExecAndScriptFailure(lines, 'E1012:', 5) enddef def Test_assignment_list_any_index() diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 22c68f4ae4..1e99e9568d 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -57,7 +57,7 @@ def Test_expr1_trinary() assert_equal(function('len'), Res) var RetOne: func(string): number = function('len') - var RetTwo: func(string): number = function('winnr') + var RetTwo: func(string): number = function('charcol') var RetThat: func = g:atrue ? RetOne : RetTwo assert_equal(function('len'), RetThat) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index f4142ee851..89cdee7437 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1030,7 +1030,7 @@ def Test_pass_legacy_lambda_to_def_func() lines =<< trim END vim9script - def g:TestFunc(f: func()) + def g:TestFunc(f: func) enddef legacy call g:TestFunc({-> 0}) delfunc g:TestFunc diff --git a/src/version.c b/src/version.c index 062e856e04..298fd87996 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3100, /**/ 3099, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index 91dc3fe607..c92e063bb1 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -260,6 +260,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) type_T *type; type_T *member_type = &t_any; int argcount = 0; + int min_argcount = 0; if (tv->v_type == VAR_NUMBER) return &t_number; @@ -337,8 +338,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) if (idx >= 0) { - // TODO: get actual arg count and types - argcount = -1; + internal_func_get_argcount(idx, &argcount, &min_argcount); member_type = internal_func_ret_type(idx, 0, NULL); } else @@ -364,6 +364,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) return NULL; type->tt_type = tv->v_type; type->tt_argcount = argcount; + type->tt_min_argcount = min_argcount; type->tt_member = member_type; return type; @@ -525,9 +526,9 @@ check_type(type_T *expected, type_T *actual, int give_msg, where_T where) ret = check_type(expected->tt_member, actual->tt_member, FALSE, where); if (ret == OK && expected->tt_argcount != -1 - && actual->tt_argcount != -1 - && (actual->tt_argcount < expected->tt_min_argcount - || actual->tt_argcount > expected->tt_argcount)) + && (actual->tt_argcount == -1 + || (actual->tt_argcount < expected->tt_min_argcount + || actual->tt_argcount > expected->tt_argcount))) ret = FAIL; if (ret == OK && expected->tt_args != NULL && actual->tt_args != NULL) @@ -1032,7 +1033,10 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap) } } else + // Use -1 for "tt_argcount" to indicate an unknown number of + // arguments. *dest = alloc_func_type(common, -1, type_gap); + // Use the minimum of min_argcount. (*dest)->tt_min_argcount = type1->tt_min_argcount < type2->tt_min_argcount From 67b17a6fc62156383d24dcbd6e6df34e180d7235 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 16:50:55 +0200 Subject: [PATCH 31/38] patch 8.2.3101: missing function prototype for vim_round() Problem: Missing function prototype for vim_round(). Solution: Add the prototype. --- src/proto/float.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/proto/float.pro b/src/proto/float.pro index e14ce24735..806eba1f61 100644 --- a/src/proto/float.pro +++ b/src/proto/float.pro @@ -1,4 +1,4 @@ -/* math.c */ +/* float.c */ int string2float(char_u *text, float_T *value); void f_abs(typval_T *argvars, typval_T *rettv); void f_acos(typval_T *argvars, typval_T *rettv); @@ -17,6 +17,7 @@ void f_isnan(typval_T *argvars, typval_T *rettv); void f_log(typval_T *argvars, typval_T *rettv); void f_log10(typval_T *argvars, typval_T *rettv); void f_pow(typval_T *argvars, typval_T *rettv); +float_T vim_round(float_T f); void f_round(typval_T *argvars, typval_T *rettv); void f_sin(typval_T *argvars, typval_T *rettv); void f_sinh(typval_T *argvars, typval_T *rettv); From 26e88ec8e23fa04e559044199ccb369aed29e570 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 17:21:04 +0200 Subject: [PATCH 32/38] patch 8.2.3101: missing function prototype for vim_round() Problem: Missing function prototype for vim_round(). Solution: Add the prototype --- src/version.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/version.c b/src/version.c index 298fd87996..600af405a1 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3101, /**/ 3100, /**/ From 3777d6e32b22f0a70b774760c24160079e303bad Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 17:23:25 +0200 Subject: [PATCH 33/38] patch 8.2.3102: test for crash fix does not fail without the fix Problem: Test for crash fix does not fail without the fix. Solution: Adjust the test sequence. (closes #8506) --- src/testdir/test_swap.vim | 20 ++++++++++++-------- src/version.c | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index 4bc325d333..013b25caac 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -373,18 +373,22 @@ func Test_swap_prompt_splitwin() call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))}) call StopVimInTerminal(buf) - " This caused Vim to crash when typing "q". - " TODO: it does not actually reproduce the crash. - call writefile(['au BufAdd * set virtualedit=all'], 'Xvimrc') - - let buf = RunVimInTerminal('-u Xvimrc Xfile1', {'rows': 20, 'wait_for_ruler': 0}) - call TermWait(buf) - call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 20))}) + " This caused Vim to crash when typing "q" at the swap file prompt. + let buf = RunVimInTerminal('-c "au bufadd * let foo_w = wincol()"', {'rows': 18}) + call term_sendkeys(buf, ":e Xfile1\") + call WaitForAssert({-> assert_match('More', term_getline(buf, 18))}) + call term_sendkeys(buf, " ") + call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 18))}) call term_sendkeys(buf, "q") + call TermWait(buf) + " check that Vim is still running + call term_sendkeys(buf, ":echo 'hello'\") + call WaitForAssert({-> assert_match('^hello', term_getline(buf, 18))}) + call term_sendkeys(buf, ":%bwipe!\") + call StopVimInTerminal(buf) %bwipe! call delete('Xfile1') - call delete('Xvimrc') endfunc func Test_swap_symlink() diff --git a/src/version.c b/src/version.c index 600af405a1..6192832d10 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3102, /**/ 3101, /**/ From f33cae605064c8bdb908a8069d936f752572cd76 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 17:36:54 +0200 Subject: [PATCH 34/38] patch 8.2.3103: swap test may fail on some systems Problem: Swap test may fail on some systems when jobs take longer to exit. Solution: Use different file names. --- src/testdir/test_swap.vim | 26 +++++++++++++------------- src/version.c | 2 ++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index 013b25caac..e62412b10c 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -502,18 +502,18 @@ endfunc " Test for renaming a buffer when the swap file is deleted out-of-band func Test_missing_swap_file() CheckUnix - new Xfile1 + new Xfile2 call delete(swapname('')) - call assert_fails('file Xfile2', 'E301:') - call assert_equal('Xfile2', bufname()) - call assert_true(bufexists('Xfile1')) + call assert_fails('file Xfile3', 'E301:') + call assert_equal('Xfile3', bufname()) call assert_true(bufexists('Xfile2')) + call assert_true(bufexists('Xfile3')) %bw! endfunc " Test for :preserve command func Test_preserve() - new Xfile1 + new Xfile4 setlocal noswapfile call assert_fails('preserve', 'E313:') bw! @@ -521,8 +521,8 @@ endfunc " Test for the v:swapchoice variable func Test_swapchoice() - call writefile(['aaa', 'bbb'], 'Xfile1') - edit Xfile1 + call writefile(['aaa', 'bbb'], 'Xfile5') + edit Xfile5 preserve let swapfname = swapname('') let b = readblob(swapfname) @@ -536,7 +536,7 @@ func Test_swapchoice() autocmd! autocmd SwapExists * let v:swapchoice = 'o' augroup END - edit Xfile1 + edit Xfile5 call assert_true(&readonly) call assert_equal(['aaa', 'bbb'], getline(1, '$')) %bw! @@ -548,11 +548,11 @@ func Test_swapchoice() autocmd SwapExists * let v:swapchoice = 'a' augroup END try - edit Xfile1 + edit Xfile5 catch /^Vim:Interrupt$/ endtry call assert_equal('', @%) - call assert_true(bufexists('Xfile1')) + call assert_true(bufexists('Xfile5')) %bw! call assert_true(filereadable(swapfname)) @@ -561,12 +561,12 @@ func Test_swapchoice() autocmd! autocmd SwapExists * let v:swapchoice = 'd' augroup END - edit Xfile1 - call assert_equal('Xfile1', @%) + edit Xfile5 + call assert_equal('Xfile5', @%) %bw! call assert_false(filereadable(swapfname)) - call delete('Xfile1') + call delete('Xfile5') call delete(swapfname) augroup test_swapchoice autocmd! diff --git a/src/version.c b/src/version.c index 6192832d10..a9c29582a2 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3103, /**/ 3102, /**/ From b7480cd8931fa1696265f75c7d4d9fdf0be69e12 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 18:28:15 +0200 Subject: [PATCH 35/38] patch 8.2.3104: Vim9: unspecified function type causes type error Problem: Vim9: unspecified function type causes type error. Solution: Don't check type when min_argcount is negative. (issue #8492) --- src/globals.h | 2 +- src/testdir/test_vim9_assign.vim | 9 +++++++++ src/version.c | 2 ++ src/vim9type.c | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/globals.h b/src/globals.h index dd24cbbae3..b6076df5bb 100644 --- a/src/globals.h +++ b/src/globals.h @@ -421,7 +421,7 @@ EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL); // Special value used for @#. EXTERN type_T t_number_or_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL); -EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_unknown, NULL); +EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, -1, TTFLAG_STATIC, &t_unknown, NULL); EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_void, NULL); EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_any, NULL); EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_number, NULL); diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 92ffa0055c..5f5b5d740a 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -661,6 +661,15 @@ def Test_assignment_list() CheckDefExecAndScriptFailure(lines, 'E1012:', 5) enddef +def PartFunc(b: bool): string + return 'done' +enddef + +def Test_assignment_partial() + var Partial: func(): string = function(PartFunc, [true]) + assert_equal('done', Partial()) +enddef + def Test_assignment_list_any_index() var l: list = [1, 2] for [x, y, _] diff --git a/src/version.c b/src/version.c index a9c29582a2..1f2b18f0f4 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3104, /**/ 3103, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index c92e063bb1..b34940447d 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -526,6 +526,7 @@ check_type(type_T *expected, type_T *actual, int give_msg, where_T where) ret = check_type(expected->tt_member, actual->tt_member, FALSE, where); if (ret == OK && expected->tt_argcount != -1 + && actual->tt_min_argcount != -1 && (actual->tt_argcount == -1 || (actual->tt_argcount < expected->tt_min_argcount || actual->tt_argcount > expected->tt_argcount))) From 97f227d9c9351f12138d923ffdf9232dc5520bef Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 20:20:52 +0200 Subject: [PATCH 36/38] patch 8.2.3105: Vim9: type of partial is wrong when it has arguments Problem: Vim9: type of partial is wrong when it has arguments. Solution: Subtract arguments from the count. (issue #8492) --- src/testdir/test_vim9_assign.vim | 9 ++++++--- src/userfunc.c | 11 +++++++++++ src/version.c | 2 ++ src/vim9type.c | 13 +++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 5f5b5d740a..72884e5ed9 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -661,13 +661,16 @@ def Test_assignment_list() CheckDefExecAndScriptFailure(lines, 'E1012:', 5) enddef -def PartFunc(b: bool): string +def PartFuncBool(b: bool): string return 'done' enddef def Test_assignment_partial() - var Partial: func(): string = function(PartFunc, [true]) - assert_equal('done', Partial()) + var lines =<< trim END + var Partial: func(): string = function(PartFuncBool, [true]) + assert_equal('done', Partial()) + END + CheckDefAndScriptSuccess(lines) enddef def Test_assignment_list_any_index() diff --git a/src/userfunc.c b/src/userfunc.c index 7e7c0f6f63..404f85bb51 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3103,6 +3103,7 @@ call_func( int argv_clear = 0; int argv_base = 0; partial_T *partial = funcexe->partial; + type_T check_type; // Initialize rettv so that it is safe for caller to invoke clear_tv(rettv) // even when call_func() returns FAIL. @@ -3146,6 +3147,16 @@ call_func( argv[i + argv_clear] = argvars_in[i]; argvars = argv; argcount = partial->pt_argc + argcount_in; + + if (funcexe->check_type != NULL) + { + // Now funcexe->check_type is missing the added arguments, make + // a copy of the type with the correction. + check_type = *funcexe->check_type; + funcexe->check_type = &check_type; + check_type.tt_argcount += partial->pt_argc; + check_type.tt_min_argcount += partial->pt_argc; + } } } diff --git a/src/version.c b/src/version.c index 1f2b18f0f4..1f3747970b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3105, /**/ 3104, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index b34940447d..5cf1f42844 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -355,7 +355,20 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) if (ufunc->uf_func_type == NULL) set_function_type(ufunc); if (ufunc->uf_func_type != NULL) + { + if (tv->v_type == VAR_PARTIAL + && tv->vval.v_partial->pt_argc > 0) + { + type = get_type_ptr(type_gap); + if (type == NULL) + return NULL; + *type = *ufunc->uf_func_type; + type->tt_argcount -= tv->vval.v_partial->pt_argc; + type->tt_min_argcount -= tv->vval.v_partial->pt_argc; + return type; + } return ufunc->uf_func_type; + } } } From 6977dba04b68b91410585ada65079651788ca7dc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 22:48:12 +0200 Subject: [PATCH 37/38] patch 8.2.3106: Vim9: confusing line number reported for error Problem: Vim9: confusing line number reported for error. Solution: Use the start line number for the store instruction. (closes #8488) --- src/testdir/test_vim9_assign.vim | 10 ++++++++++ src/version.c | 2 ++ src/vim9compile.c | 14 +++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 72884e5ed9..a92a60bbdd 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -388,6 +388,16 @@ def Test_assign_linebreak() ->copy() END CheckDefFailure(lines, 'E1012:', 2) + + lines =<< trim END + var x: any + x.key = 1 + + 2 + + 3 + + 4 + + 5 + END + CheckDefExecAndScriptFailure2(lines, 'E1148:', 'E1203:', 2) enddef def Test_assign_index() diff --git a/src/version.c b/src/version.c index 1f3747970b..10231abd85 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3106, /**/ 3105, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 88086cefd6..9569f2f4d3 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6726,7 +6726,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) var_start = arg; for (var_idx = 0; var_idx == 0 || var_idx < var_count; var_idx++) { - int instr_count = -1; + int instr_count = -1; + int save_lnum; if (var_start[0] == '_' && !eval_isnamec(var_start[1])) { @@ -6979,13 +6980,20 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } + // Use the line number of the assignment for store instruction. + save_lnum = cctx->ctx_lnum; + cctx->ctx_lnum = start_lnum - 1; + if (lhs.lhs_has_index) { // Use the info in "lhs" to store the value at the index in the // list or dict. if (compile_assign_unlet(var_start, &lhs, TRUE, rhs_type, cctx) == FAIL) + { + cctx->ctx_lnum = save_lnum; goto theend; + } } else { @@ -7006,8 +7014,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_SETTYPE(cctx, lhs.lhs_type); if (generate_store_lhs(cctx, &lhs, instr_count) == FAIL) + { + cctx->ctx_lnum = save_lnum; goto theend; + } } + cctx->ctx_lnum = save_lnum; if (var_idx + 1 < var_count) var_start = skipwhite(lhs.lhs_dest_end + 1); From 22f85d04594e1a09936227ef62955a7939d584b4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Jul 2021 23:29:30 +0200 Subject: [PATCH 38/38] patch 8.2.3107: Vim9: error for arguments while type didn't specify arguments Problem: Vim9: error for arguments while type didn't specify arguments. Solution: Do not update that type to check when no argument count is specified. (closes #8492) --- src/testdir/test_vim9_assign.vim | 10 ++++++++++ src/userfunc.c | 3 ++- src/version.c | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index a92a60bbdd..6bbbc3681e 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -681,6 +681,16 @@ def Test_assignment_partial() assert_equal('done', Partial()) END CheckDefAndScriptSuccess(lines) + + lines =<< trim END + vim9script + def Func(b: bool) + enddef + var Ref: func = function(Func, [true]) + assert_equal('func()', typename(Ref)) + Ref() + END + CheckScriptSuccess(lines) enddef def Test_assignment_list_any_index() diff --git a/src/userfunc.c b/src/userfunc.c index 404f85bb51..4234681cd7 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3148,7 +3148,8 @@ call_func( argvars = argv; argcount = partial->pt_argc + argcount_in; - if (funcexe->check_type != NULL) + if (funcexe->check_type != NULL + && funcexe->check_type->tt_argcount != -1) { // Now funcexe->check_type is missing the added arguments, make // a copy of the type with the correction. diff --git a/src/version.c b/src/version.c index 10231abd85..060c2e770d 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3107, /**/ 3106, /**/