1
0
forked from aniani/vim

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)
This commit is contained in:
Mike Williams
2021-06-28 20:53:58 +02:00
committed by Bram Moolenaar
parent ffec6dd16a
commit 127950241e
9 changed files with 206 additions and 49 deletions

View File

@@ -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 = '/';

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3071,
/**/
3070,
/**/