Skip to content

Commit 95f56e3

Browse files
committed
vim: de-quote 'shell' option
De-quote only if first and last character of &shell are double-quotes. Avoid string escape issues when passing escaped '&shell' values.
1 parent 7ee29d8 commit 95f56e3

File tree

3 files changed

+48
-33
lines changed

3 files changed

+48
-33
lines changed

after/ftplugin/ps1.vim

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,18 @@ if !exists('*s:help')
2121
\ ? 'powershell.exe'
2222
\ : 'pwsh'
2323
let pager = has('win32') ? 'more' : 'less'
24-
if !executable(newshell)
25-
echomsg newshell 'is not in PATH'
26-
return
27-
endif
28-
2924
let shell = &shell
30-
" de-quote
31-
if shell[0] ==# '"'
32-
let shell = shell[1:-2]
25+
if !executable(newshell) || !SetShell(newshell)
26+
echoerr newshell 'cannot be set'
27+
return
3328
endif
3429

3530
try
36-
execute 'SetShell' newshell
3731
let help_fmt = 'Get-Help %s | ' . pager
3832
let cmd = printf(help_fmt, dotvim8#shellescape(expand('<cword>')))
3933
call dotvim8#bang(cmd)
4034
finally
41-
execute 'SetShell' shell
35+
call SetShell(shell)
4236
endtry
4337
endfunction
4438
endif

autoload/dotvim8.vim

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,7 @@ function! dotvim8#shellescape(arg, ...)
4848
endif
4949

5050
let opts = get(a:000, 0, {})
51-
let shell = fnamemodify(get(opts, 'shell', &shell), ':t')
52-
" de-quote
53-
if shell[0] ==# '"'
54-
let shell = shell[1:-2]
55-
endif
51+
let shell = fnamemodify(UnescapeShell(get(opts, 'shell', &shell)), ':t')
5652
let script = get(opts, 'script', 0)
5753
let arg = get(opts, 'escape_argv', 1) && (has('win32') || has('win32unix')) ?
5854
\ escape(a:arg, '"\') : a:arg
@@ -81,11 +77,7 @@ function! dotvim8#bang(cmd)
8177
echomsg 'Command is empty string'
8278
return
8379
endif
84-
let shell = &shell
85-
" de-quote
86-
if shell[0] ==# '"'
87-
let shell = shell[1:-2]
88-
endif
80+
let shell = UnescapeShell(&shell)
8981

9082
if s:has_term
9183
if has('nvim')

shared.vim

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,38 @@ endif
162162
if has('modify_fname')
163163
let s:base_dir = expand('<sfile>:p:h')
164164

165-
function! s:set_shell(shell)
166-
let shell = a:shell
167-
" de-quote
168-
if shell[0] ==# '"'
169-
let shell = shell[1:-2]
165+
" Unescape 'shell' option in case that the user escaped it.
166+
function! UnescapeShell(shell)
167+
if (has('nvim') || has('win32')) && a:shell =~# '^".\+"$'
168+
" de-quote
169+
return a:shell[1:-2]
170170
endif
171+
if !has('nvim') && has('unix') && a:shell =~# '\'
172+
" strip backslashes
173+
return substitute(a:shell, '\', '', 'g')
174+
endif
175+
return a:shell
176+
endfunction
177+
178+
" Escape 'shell' option depending on the editor.
179+
function! EscapeShell(shell)
180+
if a:shell =~# ' '
181+
if has('nvim') || (has('win32') && has('patch-8.1.2115'))
182+
" quote
183+
return '"' . a:shell . '"'
184+
endif
185+
" TODO: Investigate the patch that added support for escaped 'shell'.
186+
if !has('nvim') && has('unix') && has('patch-8.0.1176')
187+
" add backslashes
188+
return escape(a:shell, ' ')
189+
endif
190+
endif
191+
return a:shell
192+
endfunction
193+
194+
" If shell is supported, return 1. Else, return 0.
195+
function! SetShell(shell)
196+
let shell = UnescapeShell(a:shell)
171197
let tail = fnamemodify(shell, ':t')
172198

173199
if tail =~# '^cmd\.exe'
@@ -214,16 +240,19 @@ if has('modify_fname')
214240
let &shellxquote = (!has('nvim') && has('win32')) ? '"' : ''
215241
else
216242
echoerr a:shell 'is not supported in Vim' v:version
217-
return
243+
return 0
218244
endif
219-
let &shell = match(shell, ' ') == -1 ? shell : '"' . shell . '"'
245+
let &shell = EscapeShell(shell)
246+
return 1
220247
endfunction
221248

222-
if has('win32')
223-
call s:set_shell(has('nvim') || !executable($COMSPEC) ? 'cmd.exe' : $COMSPEC)
224-
elseif has('unix')
225-
call s:set_shell(filter([$SHELL, 'sh'], 'executable(v:val)')[0])
226-
endif
249+
let s:shells = filter(has('win32') ? [$COMSPEC, 'cmd.exe'] : [$SHELL, 'sh'], 'executable(v:val)')
250+
for s:shell in s:shells
251+
if SetShell(s:shell)
252+
break
253+
endif
254+
endfor
255+
unlet s:shell s:shells
227256
endif
228257

229258
" Moved from normal to tiny version since 8.1.1901
@@ -429,7 +458,7 @@ if has('user_commands')
429458
endif
430459

431460
if has('modify_fname')
432-
command! -nargs=1 -complete=shellcmd SetShell call s:set_shell(<f-args>)
461+
command! -nargs=1 -complete=shellcmd SetShell call SetShell(<f-args>)
433462
endif
434463

435464
if has('syntax')

0 commit comments

Comments
 (0)