diff options
author | Mike Williams <mikew@globalgraphics.com> | 2021-06-28 20:53:58 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-06-28 20:53:58 +0200 |
commit | 127950241e84c822d3c50f46a00d42a70d2d5cb6 (patch) | |
tree | 6b5a0ac43a29edeb6e1cc3c3fb9f7c6f966cb28e /src | |
parent | ffec6dd16a766180429addaa78928c773a3c9832 (diff) |
patch 8.2.3071: shell options are not set properly for PowerShellv8.2.3071
Problem: Shell options are not set properly for PowerShell.
Solution: Use better option defaults. (Mike Willams, closes #8459)
Diffstat (limited to 'src')
-rw-r--r-- | src/fileio.c | 5 | ||||
-rw-r--r-- | src/misc2.c | 49 | ||||
-rw-r--r-- | src/option.c | 53 | ||||
-rw-r--r-- | src/os_win32.c | 3 | ||||
-rw-r--r-- | src/testdir/test_shell.vim | 31 | ||||
-rw-r--r-- | src/version.c | 2 |
6 files changed, 124 insertions, 19 deletions
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 "<cfile>". @@ -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 @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3071, +/**/ 3070, /**/ 3069, |