From 0ad254799781ba1e00b13b26dfbee5c6fed9684f Mon Sep 17 00:00:00 2001 From: w0rp Date: Tue, 19 Dec 2017 17:34:34 +0000 Subject: [PATCH] Fix mcsc paths and escaping for Windows --- ale_linters/cs/mcsc.vim | 69 +++++++++---------- doc/ale-cs.txt | 3 +- .../test_cs_mcsc_command_callbacks.vader | 32 ++++++--- test/handler/test_mcsc_handler.vader | 19 ++++- 4 files changed, 74 insertions(+), 49 deletions(-) diff --git a/ale_linters/cs/mcsc.vim b/ale_linters/cs/mcsc.vim index 6e51ef3..f16e4b4 100644 --- a/ale_linters/cs/mcsc.vim +++ b/ale_linters/cs/mcsc.vim @@ -1,55 +1,47 @@ -" general mcs options which are likely to stay constant across -" source trees like -pkg:dotnet -let g:ale_cs_mcsc_options = get(g:, 'ale_cs_mcsc_options', '') +call ale#Set('cs_mcsc_options', '') +call ale#Set('cs_mcsc_source', '') +call ale#Set('cs_mcsc_assembly_path', []) +call ale#Set('cs_mcsc_assemblies', []) -" path string pointing the linter to the base path of the -" source tree to check -let g:ale_cs_mcsc_source = get(g:, 'ale_cs_mcsc_source','.') +function! s:GetWorkingDirectory(buffer) abort + let l:working_directory = ale#Var(a:buffer, 'cs_mcsc_source') -" list of search paths for additional assemblies to consider -let g:ale_cs_mcsc_assembly_path = get(g:, 'ale_cs_mcsc_assembly_path',[]) + if !empty(l:working_directory) + return l:working_directory + endif + + return fnamemodify(bufname(a:buffer), ':p:h') +endfunction -" list of assemblies to consider -let g:ale_cs_mcsc_assemblies = get(g:, 'ale_cs_mcsc_assemblies',[]) function! ale_linters#cs#mcsc#GetCommand(buffer) abort + " Pass assembly paths via the -lib: parameter. + let l:path_list = ale#Var(a:buffer, 'cs_mcsc_assembly_path') - " if list of assembly search paths is not empty convert it to - " appropriate -lib: parameter of mcs - let l:path = ale#Var(a:buffer, 'cs_mcsc_assembly_path') + let l:lib_option = !empty(l:path_list) + \ ? '-lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',') + \ : '' - if !empty(l:path) - let l:path = '-lib:"' . join(l:path, '","') .'"' - else - let l:path ='' - endif + " Pass paths to DLL files via the -r: parameter. + let l:assembly_list = ale#Var(a:buffer, 'cs_mcsc_assemblies') - " if list of assemblies to link is not empty convert it to the - " appropriate -r: parameter of mcs - let l:assemblies = ale#Var(a:buffer, 'cs_mcsc_assemblies') - - if !empty(l:assemblies) - let l:assemblies = '-r:"' . join(l:assemblies, '","') . '"' - else - let l:assemblies ='' - endif + let l:r_option = !empty(l:assembly_list) + \ ? '-r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',') + \ : '' " register temporary module target file with ale let l:out = tempname() call ale#engine#ManageFile(a:buffer, l:out) - " assemble linter command string to be executed by ale - " implicitly set -unsafe mcs flag set compilation - " target to module (-t:module), direct mcs output to - " temporary file (-out) - " - return 'cd "' . ale#Var(a:buffer, 'cs_mcsc_source') . '";' + " The code is compiled as a module and the output is redirected to a + " temporary file. + return ale#path#CdString(s:GetWorkingDirectory(a:buffer)) \ . 'mcs -unsafe' \ . ' ' . ale#Var(a:buffer, 'cs_mcsc_options') - \ . ' ' . l:path - \ . ' ' . l:assemblies + \ . ' ' . l:lib_option + \ . ' ' . l:r_option \ . ' -out:' . l:out \ . ' -t:module' - \ . ' -recurse:"*.cs"' + \ . ' -recurse:' . ale#Escape('*.cs') endfunction function! ale_linters#cs#mcsc#Handle(buffer, lines) abort @@ -62,11 +54,12 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort " path and not just the file loaded in the buffer let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' let l:output = [] - let l:source = ale#Var(a:buffer, 'cs_mcsc_source') + + let l:dir = s:GetWorkingDirectory(a:buffer) for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { - \ 'filename': fnamemodify(l:source . '/' . l:match[1], ':p'), + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] is# 'error' ? 'E' : 'W', diff --git a/doc/ale-cs.txt b/doc/ale-cs.txt index 38ee23e..ad8b2bb 100644 --- a/doc/ale-cs.txt +++ b/doc/ale-cs.txt @@ -63,7 +63,8 @@ g:ale_cs_mcsc_source *g:ale_cs_mcsc_source* Default: `''` This variable defines the root path of the directory tree searched for the - '*.cs' files to be linted. If empty the current working directory is used. + '*.cs' files to be linted. If this option is empty, the source file's + directory will be used. NOTE: Currently it is not possible to specify sub directories and directory sub trees which shall not be searched for *.cs files. diff --git a/test/command_callback/test_cs_mcsc_command_callbacks.vader b/test/command_callback/test_cs_mcsc_command_callbacks.vader index 441cef5..cb52c96 100644 --- a/test/command_callback/test_cs_mcsc_command_callbacks.vader +++ b/test/command_callback/test_cs_mcsc_command_callbacks.vader @@ -12,6 +12,8 @@ Before: unlet! g:ale_cs_mcsc_assembly_path unlet! g:ale_cs_mcsc_assemblies + let g:prefix = ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') + function! GetCommand() let l:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) let l:command = join(split(l:command)) @@ -28,52 +30,64 @@ After: unlet! g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_assembly_path unlet! g:ale_cs_mcsc_assemblies + unlet! g:ale_prefix delfunction GetCommand call ale#linter#Reset() -Execute(Check for proper default command): +Execute(The mcsc linter should return the correct default command): AssertEqual - \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe' . g:prefix, \ GetCommand() Execute(The options should be be used in the command): let g:ale_cs_mcsc_options = '-pkg:dotnet' AssertEqual - \ 'cd ".";mcs -unsafe ' . g:ale_cs_mcsc_options . ' -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe -pkg:dotnet' . g:prefix, \ GetCommand() Execute(The souce path should be be used in the command): - let g:ale_cs_mcsc_source='../foo/bar' + let g:ale_cs_mcsc_source = '../foo/bar' AssertEqual - \ 'cd "' . g:ale_cs_mcsc_source . '";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ 'cd ' . ale#Escape('../foo/bar') . ' && ' + \ . 'mcs -unsafe' . g:prefix, \ GetCommand() Execute(The list of search pathes for assemblies should be be used in the command if not empty): let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar'] AssertEqual - \ 'cd ".";mcs -unsafe -lib:"' . join(g:ale_cs_mcsc_assembly_path,'","') . '" -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe' + \ . ' -lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar') + \ . g:prefix, \ GetCommand() let g:ale_cs_mcsc_assembly_path = [] AssertEqual - \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe' . g:prefix, \ GetCommand() Execute(The list of assemblies should be be used in the command if not empty): let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll'] AssertEqual - \ 'cd ".";mcs -unsafe -r:"' . join(g:ale_cs_mcsc_assemblies,'","') . '" -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe' + \ . ' -r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll') + \ . g:prefix, \ GetCommand() let g:ale_cs_mcsc_assemblies = [] AssertEqual - \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ ale#path#BufferCdString(bufnr('')) + \ . 'mcs -unsafe' . g:prefix, \ GetCommand() diff --git a/test/handler/test_mcsc_handler.vader b/test/handler/test_mcsc_handler.vader index a000792..d97a2ed 100644 --- a/test/handler/test_mcsc_handler.vader +++ b/test/handler/test_mcsc_handler.vader @@ -9,8 +9,25 @@ After: unlet! g:ale_cs_mcsc_source call ale#linter#Reset() +Execute(The mcs handler should work with the default of the buffer's directory): + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'col' : 29, + \ 'text': '; expected', + \ 'code': 'CS1001', + \ 'type': 'E', + \ 'filename': ale#path#Winify(expand('%:p:h') . '/Test.cs', 'add_drive'), + \ }, + \ ], + \ ale_linters#cs#mcsc#Handle(347, [ + \ 'Test.cs(12,29): error CS1001: ; expected', + \ 'Compilation failed: 2 error(s), 1 warnings', + \ ]) + Execute(The mcs handler should handle cannot find symbol errors): - let g:ale_cs_mcsc_source='/home/foo/project/bar' + let g:ale_cs_mcsc_source = '/home/foo/project/bar' AssertEqual \ [