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:
committed by
Bram Moolenaar
parent
ffec6dd16a
commit
127950241e
@@ -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 = '/';
|
||||
|
49
src/misc2.c
49
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
|
||||
|
53
src/option.c
53
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;
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -755,6 +755,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
3071,
|
||||
/**/
|
||||
3070,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user