]> granicus.if.org Git - vim/commitdiff
patch 8.2.3071: shell options are not set properly for PowerShell v8.2.3071
authorMike Williams <mikew@globalgraphics.com>
Mon, 28 Jun 2021 18:53:58 +0000 (20:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 28 Jun 2021 18:53:58 +0000 (20:53 +0200)
Problem:    Shell options are not set properly for PowerShell.
Solution:   Use better option defaults. (Mike Willams, closes #8459)

runtime/doc/eval.txt
runtime/doc/options.txt
runtime/doc/os_dos.txt
src/fileio.c
src/misc2.c
src/option.c
src/os_win32.c
src/testdir/test_shell.vim
src/version.c

index 43563815807601c05dbcc33fead11d8cb7d8043b..7fb25345380091ef31daec106f5aedc90f328c9f 100644 (file)
@@ -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|
index 05489d7f63e97c6771463d2c0374d28d899e495e..b958cf63ed2d07f1b86f20e33d8f05bfcd371add 100644 (file)
@@ -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.
 
index 925c7e0915c994eec353ffa88554f23e04803e3e..b45cb088cb75bd03c58dfb94d25f0ce425975a89 100644 (file)
@@ -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:
        <shell> -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:
index 4bd773e0bd944614fa64e23bd878a5d03e48d79e..55012bfcbdf212ed2b523e5cc64b093bd8b8a038 100644 (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 = '/';
index 0553c2ce14169a390288f12932712065ae041e0b..6bbfbd775c13d5367d27ca9cf24105ce258afd3a 100644 (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
index 07bb71e4d6b46f455e1d8a333d92c491d605695a..5fc059e29de182f5d88a0a410f7baec0f045cab7 100644 (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;
 
index a966c53495fd2c6bad0c97631e212786e96316b6..1a005c9d531559c7f3826ceb50b15e40427e1b20 100644 (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)
index f992b8ede64f98e176a97deec46aa1910d0a73b1..753a0d524900656e23ee951f6ca56917ff73169b 100644 (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
index 9ec6877d84c9e499a3523b1d1e723fb2b744f30f..dd74d2dbeefc3a7adf5f924d97e3e552fdc24c64 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3071,
 /**/
     3070,
 /**/