]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0006: powershell commands wrongly wrapped when executed v9.2.0006
authorPeter Lustig <tiamatX18@gmail.com>
Sun, 15 Feb 2026 16:14:11 +0000 (16:14 +0000)
committerChristian Brabandt <cb@256bit.org>
Sun, 15 Feb 2026 16:14:11 +0000 (16:14 +0000)
Problem:  powershell commands wrongly wrapped when executed
Solution: Use &{ ... } to wrap commands when powershell/pwsh is in use
          (Peter Lustig).

Allow compound commands with 'system()' when 'shell' is 'pwsh'

When the 'shell' option was set to 'powershell' or 'pwsh' and the
'system()' vimscript function was called with an argument containing two
or more shell commands (delimited by ';' or '&'), the function would
always fail with 'E282'.

The cause of the error was that VIM would wrap the shell command string
with parentheses (to allow the entire output to be redirected to a
temporary file for capturing) before actually passing it to the
PowerShell process for execution.

Unlike the typical shell that uses parentheses to group commands (and
possibly spawn a subshell), PowerShell uses them to resolve a single
command (pipeline) to an expression. To group multiple commands with
PowerShell, you must instead wrap them with either the subexpression
operator '$(...)' or an immediately evaluated script block '& { ... }'.
The latter option may be more efficient since it does not buffer its
output like for the former one does.

closes: #19401

Signed-off-by: Peter Lustig <tiamatX18@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/ex_cmds.c
src/testdir/test_system.vim
src/testdir/util/check.vim
src/version.c

index bd31de6d1b58a11a648bcdb86b0c9e9be19a1507..b56ee268b1041142adf2326871c76a0a58581cb5 100644 (file)
@@ -1810,14 +1810,17 @@ make_filter_cmd(
                                || fnamecmp(shell_name, "powershell.exe") == 0
                                || fnamecmp(shell_name, "pwsh") == 0
                                || fnamecmp(shell_name, "pwsh.exe") == 0);
-       len = (long_u)STRLEN(cmd) + 3;          // "()" + NUL
+       if (is_powershell)
+           len = (long_u)STRLEN(cmd) + 7; // "& { " + " }" + NUL
+       else
+           len = (long_u)STRLEN(cmd) + 3; // "()" + NUL
     }
 
     if (itmp != NULL)
     {
        if (is_powershell)
-           // "& { Get-Content " + " | & " + " }"
-           len += (long_u)STRLEN(itmp) + 24;
+           // "Get-Content " + " | & "
+           len += (long_u)STRLEN(itmp) + 17;
        else
            len += (long_u)STRLEN(itmp) + 9;    // " { < " + " } "
     }
@@ -1836,7 +1839,7 @@ make_filter_cmd(
            vim_snprintf((char *)buf, len, "& { Get-Content %s | & %s }",
                                                                itmp, cmd);
        else
-           vim_snprintf((char *)buf, len, "(%s)", cmd);
+           vim_snprintf((char *)buf, len, "& { %s }", cmd);
     }
     else
     {
index b4f5e688b61292d2b342326961fb2a1fc6db98d2..3eb9508608b22f02a1c5d010e4ff0c00b84087f8 100644 (file)
@@ -178,4 +178,36 @@ func Test_windows_external_cmd_in_cwd()
   set guioptions&
 endfunc
 
+func Test_system_with_powershell()
+  CheckPowerShell
+
+  let shell_save = &shell
+  let shellcmdflag_save = &shellcmdflag
+  let shellxquote_save = &shellxquote
+  let shellpipe_save = &shellpipe
+  let shellredir_save = &shellredir
+  try
+    if executable('powershell')
+       let &shell = 'powershell'
+       let &shellcmdflag = '-Command'
+       let &shellredir = '2>&1 | Out-File -Encoding default'
+    else
+       let &shell = 'pwsh'
+       let &shellcmdflag = '-c'
+       let &shellredir = '>%s 2>&1'
+    endif
+    let &shellxquote = has('win32') ? '"' : ''
+    let &shellpipe = &shellredir
+
+    " Make sure compound commands are handled properly.
+    call assert_equal("123\n456\n", system('echo 123; echo 456'))
+  finally
+    let &shell = shell_save
+    let &shellcmdflag = shellcmdflag_save
+    let &shellxquote = shellxquote_save
+    let &shellpipe = shellpipe_save
+    let &shellredir = shellredir_save
+  endtry
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 717101607712cf0d390fc3d4630dd8aa67eba60d..8df985091cb10bee228a2ae7a5b65289dcaccdd3 100644 (file)
@@ -142,6 +142,14 @@ func CheckNotMacM1()
   endif
 endfunc
 
+" Command to check whether PowerShell is available
+command CheckPowerShell call CheckPowerShell()
+func CheckPowerShell()
+  if !executable('powershell') && !executable('pwsh')
+    throw 'Skipped: requires Powershell to be installed'
+  endif
+endfunc
+
 func SetupWindowSizeToForVisualDumps()
   " The dumps used as reference in these tests were created with a terminal
   " width of 75 columns. The vim window that uses the remainder of the GUI
index 2c6404fb05853a17410ff6962ad0e234e5a71b87..8c18d1c3edbe4d1513c714cff774f23984268613 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    6,
 /**/
     5,
 /**/