Fix mcsc paths and escaping for Windows

This commit is contained in:
w0rp 2017-12-19 17:34:34 +00:00
parent 647c798eb7
commit 0ad2547997
4 changed files with 74 additions and 49 deletions

View file

@ -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',

View file

@ -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.

View file

@ -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()

View file

@ -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
\ [