diff --git a/autoload/ale.vim b/autoload/ale.vim index d8db3bfd..066bfa07 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -135,14 +135,26 @@ function! ale#Set(variable_name, default) abort return l:value endfunction +function! s:EscapePercents(str) abort + return substitute(a:str, '%', '%%', 'g') +endfunction + " Escape a string suitably for each platform. " shellescape does not work on Windows. function! ale#Escape(str) abort if fnamemodify(&shell, ':t') ==? 'cmd.exe' - " FIXME: Fix shell escaping for Windows. - return fnameescape(a:str) - else - " An extra space is used here to disable the custom-checks. - return shellescape (a:str) + if a:str =~# '\v^[a-zA-Z0-9-_\\/:%]+$' + return s:EscapePercents(a:str) + endif + + if a:str =~# ' ' + return '"' + \ . substitute(s:EscapePercents(a:str), '"', '""', 'g') + \ . '"' + endif + + return s:EscapePercents(substitute(a:str, '\v([&|<>^])', '^\1', 'g')) endif + + return shellescape (a:str) endfunction diff --git a/test/test_windows_escaping.vader b/test/test_windows_escaping.vader new file mode 100644 index 00000000..22cad888 --- /dev/null +++ b/test/test_windows_escaping.vader @@ -0,0 +1,42 @@ +Before: + Save &shell + let &shell = 'cmd.exe' + +After: + Restore + +Execute(ale#Escape for cmd.exe should allow not escape paths without special characters): + AssertEqual 'C:', ale#Escape('C:') + AssertEqual 'C:\', ale#Escape('C:\') + AssertEqual 'python', ale#Escape('python') + AssertEqual 'C:\foo\bar', ale#Escape('C:\foo\bar') + AssertEqual '/bar/baz', ale#Escape('/bar/baz') + AssertEqual 'nul', ale#Escape('nul') + AssertEqual '''foo''', ale#Escape('''foo''') + +Execute(ale#Escape for cmd.exe should escape Windows paths with spaces appropriately): + AssertEqual '"C:\foo bar\baz"', ale#Escape('C:\foo bar\baz') + AssertEqual '"^foo bar^"', ale#Escape('^foo bar^') + AssertEqual '"&foo bar&"', ale#Escape('&foo bar&') + AssertEqual '"|foo bar|"', ale#Escape('|foo bar|') + AssertEqual '"foo bar>"', ale#Escape('>foo bar>') + AssertEqual '"^foo bar^"', ale#Escape('^foo bar^') + AssertEqual '"''foo'' ''bar''"', ale#Escape('''foo'' ''bar''') + +Execute(ale#Escape for cmd.exe should use caret escapes on special characters): + AssertEqual '^^foo^^', ale#Escape('^foo^') + AssertEqual '^&foo^&', ale#Escape('&foo&') + AssertEqual '^|foo^|', ale#Escape('|foo|') + AssertEqual '^foo^>', ale#Escape('>foo>') + AssertEqual '^^foo^^', ale#Escape('^foo^') + AssertEqual '''foo''^^''bar''', ale#Escape('''foo''^''bar''') + +Execute(ale#Escape for cmd.exe should escape percent characters): + AssertEqual '%%foo%%', ale#Escape('%foo%') + AssertEqual 'C:\foo%%\bar\baz%%', ale#Escape('C:\foo%\bar\baz%') + AssertEqual '"C:\foo bar%%\baz%%"', ale#Escape('C:\foo bar%\baz%') + AssertEqual '^^%%foo%%', ale#Escape('^%foo%') + AssertEqual '"^%%foo%% %%bar%%"', ale#Escape('^%foo% %bar%') + AssertEqual '"^%%foo%% %%bar%% """""', ale#Escape('^%foo% %bar% ""')