mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 04:39:07 +00:00
vim-patch:b0e0b22: runtime(zip): Improve Compatibility for powershell 5 and pwsh 7
related: vim/vim#20832
b0e0b22535
Co-authored-by: curbe454 <asu454@outlook.com>
Co-Authored-By: curbe454 <asu454@outlook.com>
This commit is contained in:
90
runtime/pack/dist/opt/old-zip/autoload/zip.vim
vendored
90
runtime/pack/dist/opt/old-zip/autoload/zip.vim
vendored
@@ -25,6 +25,7 @@
|
||||
" 2026 Apr 14 by Vim Project: Detect more path traversal attacks on Windows
|
||||
" 2026 Apr 15 by Vim Project: Detect more path traversal attacks on Windows
|
||||
" 2026 Jun 20 by Vim Project: Fix wrong escaping for the powershell calls
|
||||
" 2026 Jul 25 by Vim Project: Improved Compatibility for powershell 5 and pwsh 7
|
||||
" License: Vim License (see vim's :help license)
|
||||
" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1
|
||||
" Permission is hereby granted to use and distribute this code,
|
||||
@@ -61,6 +62,9 @@ endif
|
||||
if !exists("g:zip_extractcmd")
|
||||
let g:zip_extractcmd= g:zip_unzipcmd
|
||||
endif
|
||||
if !exists("g:zip_pwsh")
|
||||
let g:zip_pwsh=''
|
||||
endif
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" required early
|
||||
@@ -77,15 +81,54 @@ if !has('nvim-0.10') && v:version < 901
|
||||
call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later")
|
||||
finish
|
||||
endif
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" Compatibility checks
|
||||
" PowerShell: {{{2
|
||||
" Existence of powershell always means a Windows OS. By default the
|
||||
" `zip`/`unzip` is not installed on Windows, but the runtime of
|
||||
" powershell support relative functionalities about zip compression
|
||||
" and extraction.
|
||||
" In the following implementations we'll use some powershell scripts
|
||||
" to manipulate zip files. All these scripts should available to both
|
||||
" Windows PowerShell 5 and pwsh 7+.
|
||||
|
||||
let s:ps = ''
|
||||
" order: `g:zip_pwsh` > `&shell`, with executable check
|
||||
if &shell =~# 'powershell' || g:zip_pwsh =~# 'powershell'
|
||||
if executable('powershell')
|
||||
let s:ps = 'powershell'
|
||||
endif
|
||||
endif
|
||||
if (empty(g:zip_pwsh) && &shell =~# 'pwsh') || g:zip_pwsh =~# 'pwsh'
|
||||
if executable('pwsh')
|
||||
let s:ps = 'pwsh'
|
||||
endif
|
||||
endif
|
||||
|
||||
fun! s:isPS()
|
||||
return !empty(s:ps)
|
||||
endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" sanity checks
|
||||
if !executable(g:zip_unzipcmd) && &shell !~ 'pwsh'
|
||||
call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
|
||||
finish
|
||||
endif
|
||||
if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd) && &shell !~ 'pwsh'
|
||||
call s:Mess('Error', "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!")
|
||||
finish
|
||||
endif
|
||||
" s:SafeExecutable: {{{2
|
||||
fun! s:SafeExecutable(exe)
|
||||
if !executable(a:exe) && !s:isPS()
|
||||
call s:Mess('Error', "***error*** (zip) '".a:exe."' not available on your system")
|
||||
return v:false
|
||||
endif
|
||||
if !dist#vim#IsSafeExecutable('zip', a:exe) && !s:isPS()
|
||||
call s:Mess('Error', "Warning: NOT executing " .. a:exe .. " from current directory!")
|
||||
return v:false
|
||||
endif
|
||||
return v:true
|
||||
endfun
|
||||
" guarantee default command is exist and not be injected by environment
|
||||
" every default command should be checked
|
||||
if !s:SafeExecutable(g:zip_zipcmd) | finish | endif
|
||||
if !s:SafeExecutable(g:zip_unzipcmd) | finish | endif
|
||||
if !s:SafeExecutable(g:zip_extractcmd) | finish | endif
|
||||
|
||||
" ----------------
|
||||
" PowerShell: {{{1
|
||||
@@ -94,8 +137,8 @@ endif
|
||||
function! s:TryExecGnuFallBackToPs(executable, gnu_func_call, ...)
|
||||
" Check that a gnu executable is available, run the gnu_func_call if so. If
|
||||
" the gnu executable is not available or if gnu_func_call fails, try
|
||||
" ps_func_call if &shell =~ 'pwsh'. If all attempts fail, print errors.
|
||||
" a:executable - one of (g:zip_zipcmd, g:zip_unzipcmd, g:zip_extractcmd)
|
||||
" ps_func_call if `s:isPS()`. If all attempts fail, print errors.
|
||||
" a:executable - (string) name of the executable program
|
||||
" a:gnu_func_call - (string) a gnu function call to execute
|
||||
" a:1 - (optional string) a PowerShell function call to execute.
|
||||
let failures = []
|
||||
@@ -109,12 +152,12 @@ function! s:TryExecGnuFallBackToPs(executable, gnu_func_call, ...)
|
||||
else
|
||||
call add(failures, a:executable.' not available on your system')
|
||||
endif
|
||||
if &shell =~ 'pwsh' && a:0 == 1
|
||||
if s:isPS() && a:0 == 1
|
||||
try
|
||||
exe a:1
|
||||
return
|
||||
catch
|
||||
call add(failures, 'Fallback to PowerShell attempted but failed')
|
||||
call add(failures, 'Fallback to PowerShell attempted but failed: '.a:1)
|
||||
endtry
|
||||
endif
|
||||
for msg in failures
|
||||
@@ -127,20 +170,22 @@ function! s:ZipBrowsePS(zipfile)
|
||||
" Browse the contents of a zip file using PowerShell's
|
||||
" Equivalent `unzip -Z1 -- zipfile`
|
||||
let cmds = [
|
||||
\ 'Add-Type -AssemblyName System.IO.Compression.FileSystem;',
|
||||
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:PSEscape(a:zipfile) . ');',
|
||||
\ '$zip.Entries | ForEach-Object { $_.FullName };',
|
||||
\ '$zip.Dispose()'
|
||||
\ ]
|
||||
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
|
||||
return s:ps . ' -NoProfile -Command ' . s:Escape(join(cmds, ' '), 1)
|
||||
endfunction
|
||||
|
||||
function! s:ZipReadPS(zipfile, fname, tempfile)
|
||||
" Read a filename within a zipped file to a temporary file.
|
||||
" Equivalent to `unzip -p -- zipfile fname > tempfile`
|
||||
if &shell =~ 'pwsh'
|
||||
if s:isPS()
|
||||
call s:Mess('WarningMsg', "***warning*** PowerShell can display, but cannot update, files in archive subfolders")
|
||||
endif
|
||||
let cmds = [
|
||||
\ 'Add-Type -AssemblyName System.IO.Compression.FileSystem;',
|
||||
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:PSEscape(a:zipfile) . ');',
|
||||
\ '$fileEntry = $zip.Entries | Where-Object { $_.FullName -eq ' . s:PSEscape(a:fname) . ' };',
|
||||
\ '$stream = $fileEntry.Open();',
|
||||
@@ -150,13 +195,13 @@ function! s:ZipReadPS(zipfile, fname, tempfile)
|
||||
\ '$stream.Close();',
|
||||
\ '$zip.Dispose()'
|
||||
\ ]
|
||||
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
return s:ps . ' -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
endfunction
|
||||
|
||||
function! s:ZipUpdatePS(zipfile, fname)
|
||||
" Update a filename within a zipped file
|
||||
" Equivalent to `zip -u zipfile fname`
|
||||
if &shell =~ 'pwsh' && a:fname =~ '/'
|
||||
if s:isPS() && a:fname =~ '/'
|
||||
call s:Mess('Error', "***error*** PowerShell cannot update files in archive subfolders")
|
||||
return ':'
|
||||
endif
|
||||
@@ -171,6 +216,7 @@ function! s:ZipExtractFilePS(zipfile, fname)
|
||||
return ':'
|
||||
endif
|
||||
let cmds = [
|
||||
\ 'Add-Type -AssemblyName System.IO.Compression.FileSystem;',
|
||||
\ '$zip = [System.IO.Compression.ZipFile]::OpenRead(' . s:PSEscape(a:zipfile) . ');',
|
||||
\ '$fileEntry = $zip.Entries | Where-Object { $_.FullName -eq ' . s:PSEscape(a:fname) . ' };',
|
||||
\ '$stream = $fileEntry.Open();',
|
||||
@@ -180,7 +226,7 @@ function! s:ZipExtractFilePS(zipfile, fname)
|
||||
\ '$stream.Close();',
|
||||
\ '$zip.Dispose()'
|
||||
\ ]
|
||||
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
return s:ps . ' -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
endfunction
|
||||
|
||||
function! s:ZipDeleteFilePS(zipfile, fname)
|
||||
@@ -193,7 +239,7 @@ function! s:ZipDeleteFilePS(zipfile, fname)
|
||||
\ 'if ($entry) { $entry.Delete(); $zip.Dispose() }',
|
||||
\ 'else { $zip.Dispose() }'
|
||||
\ ]
|
||||
return 'pwsh -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
return s:ps . ' -NoProfile -Command ' . s:Escape(join(cmds, ' '))
|
||||
endfunction
|
||||
|
||||
" ----------------
|
||||
@@ -214,7 +260,7 @@ fun! zip#Browse(zipfile)
|
||||
defer s:RestoreOpts(dict)
|
||||
|
||||
" sanity checks
|
||||
if !executable(g:zip_unzipcmd) && &shell !~ 'pwsh'
|
||||
if !executable(g:zip_unzipcmd) && !s:isPS()
|
||||
call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
|
||||
return
|
||||
endif
|
||||
@@ -322,7 +368,7 @@ fun! zip#Read(fname,mode)
|
||||
endif
|
||||
let fname = fname->substitute('[', '[[]', 'g')->escape('?*\\')
|
||||
" sanity check
|
||||
if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','','')) && &shell !~ 'pwsh'
|
||||
if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','','')) && !s:isPS()
|
||||
call s:Mess('Error', "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program")
|
||||
return
|
||||
endif
|
||||
@@ -442,7 +488,7 @@ fun! zip#Write(fname)
|
||||
let ps_cmd = s:ZipUpdatePS(zip, fname)
|
||||
let ps_cmd = 'call system(''' . substitute(ps_cmd, "'", "''", 'g') . ''')'
|
||||
call s:TryExecGnuFallBackToPs(g:zip_zipcmd, gnu_cmd, ps_cmd)
|
||||
if &shell =~ 'pwsh'
|
||||
if s:isPS()
|
||||
" Vim flashes 'creation in progress ...' from what I believe is the
|
||||
" ProgressAction stream of PowerShell. Unfortunately, this cannot be
|
||||
" suppressed (as of 250824) due to an open PowerShell issue.
|
||||
@@ -540,7 +586,7 @@ fun! zip#Extract()
|
||||
|
||||
if v:shell_error != 0
|
||||
call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
|
||||
elseif !filereadable(fname) && &shell !~ 'pwsh'
|
||||
elseif !filereadable(fname) && !s:isPS()
|
||||
call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
|
||||
else
|
||||
echomsg "***note*** successfully extracted ".fname
|
||||
|
||||
21
runtime/pack/dist/opt/old-zip/doc/pi_zip.txt
vendored
21
runtime/pack/dist/opt/old-zip/doc/pi_zip.txt
vendored
@@ -71,16 +71,22 @@ Copyright: Copyright (C) 2005-2015 Charles E Campbell *zip-copyright*
|
||||
"0": >
|
||||
let g:zip_exec=0
|
||||
<
|
||||
FALLBACK TO POWERSHELL CORE~
|
||||
FALLBACK TO POWERSHELL~
|
||||
|
||||
*g:zip_pwsh*
|
||||
This plugin will first attempt to use the (more capable) GNU zip/unzip
|
||||
commands. If these commands are not available or fail, and the user is
|
||||
using PowerShell Core (i.e., the 'shell' option matches "pwsh"), the
|
||||
plugin will fall back to a PowerShell Core cmdlet. The PowerShell Core
|
||||
cmdlets are limited: they cannot write or extract files within
|
||||
subdirectories of a zip archive. The advantage, however, is that no
|
||||
separate unzip binary needs to be installed.
|
||||
|
||||
using PowerShell, the plugin will fall back to a PowerShell cmdlet.
|
||||
The PowerShell cmdlets are limited: they cannot write or extract files
|
||||
within subdirectories of a zip archive. The advantage, however, is that
|
||||
no separate unzip binary needs to be installed. The 'shell' option will
|
||||
be checked whether to choose "pwsh" or "powershell", or set `g:zip_pwsh`.
|
||||
If both are available, this plugin will prefer pwsh. Default value of
|
||||
"g:zip_pwsh" is an empty string, which would not overwrite the 'shell'
|
||||
option configuration. This functionality is not turned on by default on
|
||||
MS-Windows, since the default 'shell' is "cmd.exe". For example: >
|
||||
let g:zip_pwsh='powershell'
|
||||
<
|
||||
PREVENTING LOADING~
|
||||
|
||||
If for some reason you do not wish to use vim to examine zipped files,
|
||||
@@ -116,6 +122,7 @@ Copyright: Copyright (C) 2005-2015 Charles E Campbell *zip-copyright*
|
||||
==============================================================================
|
||||
4. History *zip-history* {{{1
|
||||
unreleased:
|
||||
Jul 25, 2026 * support both Windows PowerShell 5 and pwsh 7+
|
||||
Sep 19, 2025 * support PowerShell Core
|
||||
Jul 12, 2025 * drop ../ on write to prevent path traversal attacks
|
||||
Mar 11, 2025 * handle filenames with leading '-' correctly
|
||||
|
||||
Reference in New Issue
Block a user