Fix Support for PowerShell under Windows with VIM 8+ (#1326)

The following 'vim-plug' commands would fail and/or display errors
when executed by VIM 8+ on a Windows platform with the 'shell' option
set to 'powershell' or 'pwsh':
  - PlugInstall
  - PlugUpdate
  - PlugClean
  - PlugStatus
  - PlugDiff

There were two causes for these errors:
  - A bug in VIM itself (resolved by patch 9.2.6) with how compound
    PowerShell commands are handled by the 'system()' vimscript
    function.
  - A bug in the 's:vim8' branch of the private 'vim-plug' function
    's:spawn()' where the actual command to be executed was escaped
    for 'cmd.exe' but the 'cd' prefix added by 's:with_cd()" was escaped
    for PowerShell.
This commit is contained in:
tiamat18
2026-05-16 21:51:31 -04:00
committed by GitHub
parent 34467fc07d
commit d7db1b637c

View File

@@ -997,7 +997,7 @@ function! s:bang(cmd, ...)
let [sh, shellcmdflag, shrd] = s:chsh(a:0)
" FIXME: Escaping is incomplete. We could use shellescape with eval,
" but it won't work on Windows.
let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
let cmd = a:0 ? s:with_cd(a:cmd, a:1, {'shell': s:is_win ? 'cmd.exe' : &shell}) : a:cmd
if s:is_win
let [batchfile, cmd] = s:batchfile(cmd)
endif
@@ -1462,7 +1462,7 @@ function! s:spawn(name, spec, queue, opts)
elseif s:vim8
let cmd = join(map(copy(argv), 'plug#shellescape(v:val, {"script": 0})'))
if has_key(a:opts, 'dir')
let cmd = s:with_cd(cmd, a:opts.dir, 0)
let cmd = s:with_cd(cmd, a:opts.dir, {'shell': s:is_win ? 'cmd.exe' : 'sh', 'script': 0})
endif
let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd]
let jid = job_start(s:is_win ? join(argv, ' ') : argv, {
@@ -2328,11 +2328,18 @@ function! s:format_message(bullet, name, message)
endfunction
function! s:with_cd(cmd, dir, ...)
let script = a:0 > 0 ? a:1 : 1
let pwsh = s:is_powershell(&shell)
let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
let opts.shell = get(opts, 'shell', &shell)
let opts.script = get(opts, 'script', 1)
let pwsh = s:is_powershell(opts.shell)
let cd = s:is_win && !pwsh ? 'cd /d' : 'cd'
let sep = pwsh ? ';' : '&&'
return printf('%s %s %s %s', cd, plug#shellescape(a:dir, {'script': script, 'shell': &shell}), sep, a:cmd)
let pwsh_block_required = pwsh && !has('patch-9.2.6')
let start = pwsh_block_required ? '& { ' : ''
let end = pwsh_block_required ? ' }' : ''
return printf('%s%s %s %s %s%s', start, cd, plug#shellescape(a:dir, opts), sep, a:cmd, end)
endfunction
function! s:system_job(cmd) abort
@@ -2372,9 +2379,9 @@ function! s:system(cmd, ...)
let cmd = a:cmd
endif
if a:0 > 0
let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list)
let cmd = s:with_cd(cmd, a:1, {'script': type(a:cmd) != s:TYPE.list})
endif
if s:is_win && type(a:cmd) != s:TYPE.list
if s:is_win && type(a:cmd) != s:TYPE.list && !s:is_powershell(&shell)
let [batchfile, cmd] = s:batchfile(cmd)
endif
if s:vim8 && has('gui_running') && !s:is_win