diff --git a/autoload/diff.vim b/autoload/diff.vim index 2989029..c52e6fe 100644 --- a/autoload/diff.vim +++ b/autoload/diff.vim @@ -4,15 +4,15 @@ let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@' function! diff#run_diff(realtime, use_external_grep) - let cmd = 'git ls-files --error-unmatch ' . shellescape(utility#file()) . ' && (' + let cmd = 'git ls-files --error-unmatch ' . utility#shellescape(utility#file()) . ' && (' if a:realtime - let blob_name = ':' . shellescape(utility#file_relative_to_repo_root()) + let blob_name = ':' . utility#shellescape(utility#file_relative_to_repo_root()) let blob_file = tempname() let cmd .= 'git show ' . blob_name . ' > ' . blob_file . \ ' && diff -U0 ' . g:gitgutter_diff_args . ' ' . blob_file . ' - ' else - let cmd .= 'git diff --no-ext-diff --no-color -U0 ' . g:gitgutter_diff_args . ' ' . shellescape(utility#file()) + let cmd .= 'git diff --no-ext-diff --no-color -U0 ' . g:gitgutter_diff_args . ' ' . utility#shellescape(utility#file()) endif if a:use_external_grep && s:grep_available diff --git a/autoload/utility.vim b/autoload/utility.vim index e649288..16cc614 100644 --- a/autoload/utility.vim +++ b/autoload/utility.vim @@ -8,6 +8,23 @@ function! utility#slash() return !exists("+shellslash") || &shellslash ? '/' : '\' endfunction +" A replacement for the built-in `shellescape(arg)`. +" +" Recent versions of Vim handle shell escaping pretty well. However older +" versions aren't as good. This attempts to do the right thing. +" +" See: +" https://github.com/tpope/vim-fugitive/blob/8f0b8edfbd246c0026b7a2388e1d883d579ac7f6/plugin/fugitive.vim#L29-L37 +function! utility#shellescape(arg) + if a:arg =~ '^[A-Za-z0-9_/.-]\+$' + return a:arg + elseif &shell =~# 'cmd' + return '"' . substitute(substitute(a:arg, '"', '""', 'g'), '%', '"%"', 'g') . '"' + else + return shellescape(a:arg) + endif +endfunction + function! utility#current_file() return expand('%:p') endfunction @@ -58,7 +75,7 @@ function! utility#file_relative_to_repo_root() endfunction function! utility#command_in_directory_of_file(cmd) - let directory_of_file = shellescape(fnamemodify(utility#file(), ':h')) + let directory_of_file = utility#shellescape(fnamemodify(utility#file(), ':h')) return 'cd ' . directory_of_file . ' && ' . a:cmd endfunction