summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMike Williams <mikew@globalgraphics.com>2021-06-28 20:53:58 +0200
committerBram Moolenaar <Bram@vim.org>2021-06-28 20:53:58 +0200
commit127950241e84c822d3c50f46a00d42a70d2d5cb6 (patch)
tree6b5a0ac43a29edeb6e1cc3c3fb9f7c6f966cb28e /src
parentffec6dd16a766180429addaa78928c773a3c9832 (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.c5
-rw-r--r--src/misc2.c49
-rw-r--r--src/option.c53
-rw-r--r--src/os_win32.c3
-rw-r--r--src/testdir/test_shell.vim31
-rw-r--r--src/version.c2
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,