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 call ale#Set('cs_mcsc_options', '')
" source trees like -pkg:dotnet call ale#Set('cs_mcsc_source', '')
let g:ale_cs_mcsc_options = get(g:, 'ale_cs_mcsc_options', '') call ale#Set('cs_mcsc_assembly_path', [])
call ale#Set('cs_mcsc_assemblies', [])
" path string pointing the linter to the base path of the function! s:GetWorkingDirectory(buffer) abort
" source tree to check let l:working_directory = ale#Var(a:buffer, 'cs_mcsc_source')
let g:ale_cs_mcsc_source = get(g:, 'ale_cs_mcsc_source','.')
" list of search paths for additional assemblies to consider if !empty(l:working_directory)
let g:ale_cs_mcsc_assembly_path = get(g:, 'ale_cs_mcsc_assembly_path',[]) 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 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 let l:lib_option = !empty(l:path_list)
" appropriate -lib: parameter of mcs \ ? '-lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',')
let l:path = ale#Var(a:buffer, 'cs_mcsc_assembly_path') \ : ''
if !empty(l:path) " Pass paths to DLL files via the -r: parameter.
let l:path = '-lib:"' . join(l:path, '","') .'"' let l:assembly_list = ale#Var(a:buffer, 'cs_mcsc_assemblies')
else
let l:path =''
endif
" if list of assemblies to link is not empty convert it to the let l:r_option = !empty(l:assembly_list)
" appropriate -r: parameter of mcs \ ? '-r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',')
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
" register temporary module target file with ale " register temporary module target file with ale
let l:out = tempname() let l:out = tempname()
call ale#engine#ManageFile(a:buffer, l:out) call ale#engine#ManageFile(a:buffer, l:out)
" assemble linter command string to be executed by ale " The code is compiled as a module and the output is redirected to a
" implicitly set -unsafe mcs flag set compilation " temporary file.
" target to module (-t:module), direct mcs output to return ale#path#CdString(s:GetWorkingDirectory(a:buffer))
" temporary file (-out)
"
return 'cd "' . ale#Var(a:buffer, 'cs_mcsc_source') . '";'
\ . 'mcs -unsafe' \ . 'mcs -unsafe'
\ . ' ' . ale#Var(a:buffer, 'cs_mcsc_options') \ . ' ' . ale#Var(a:buffer, 'cs_mcsc_options')
\ . ' ' . l:path \ . ' ' . l:lib_option
\ . ' ' . l:assemblies \ . ' ' . l:r_option
\ . ' -out:' . l:out \ . ' -out:' . l:out
\ . ' -t:module' \ . ' -t:module'
\ . ' -recurse:"*.cs"' \ . ' -recurse:' . ale#Escape('*.cs')
endfunction endfunction
function! ale_linters#cs#mcsc#Handle(buffer, lines) abort 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 " path and not just the file loaded in the buffer
let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$'
let l:output = [] 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) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { 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, \ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ '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: `''` Default: `''`
This variable defines the root path of the directory tree searched for the 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 NOTE: Currently it is not possible to specify sub directories and
directory sub trees which shall not be searched for *.cs files. 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_assembly_path
unlet! g:ale_cs_mcsc_assemblies unlet! g:ale_cs_mcsc_assemblies
let g:prefix = ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
function! GetCommand() function! GetCommand()
let l:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) let l:command = ale_linters#cs#mcsc#GetCommand(bufnr(''))
let l:command = join(split(l:command)) let l:command = join(split(l:command))
@ -28,52 +30,64 @@ After:
unlet! g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_source
unlet! g:ale_cs_mcsc_assembly_path unlet! g:ale_cs_mcsc_assembly_path
unlet! g:ale_cs_mcsc_assemblies unlet! g:ale_cs_mcsc_assemblies
unlet! g:ale_prefix
delfunction GetCommand delfunction GetCommand
call ale#linter#Reset() call ale#linter#Reset()
Execute(Check for proper default command): Execute(The mcsc linter should return the correct default command):
AssertEqual AssertEqual
\ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', \ ale#path#BufferCdString(bufnr(''))
\ . 'mcs -unsafe' . g:prefix,
\ GetCommand() \ GetCommand()
Execute(The options should be be used in the command): Execute(The options should be be used in the command):
let g:ale_cs_mcsc_options = '-pkg:dotnet' let g:ale_cs_mcsc_options = '-pkg:dotnet'
AssertEqual 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() \ GetCommand()
Execute(The souce path should be be used in the command): 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 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() \ GetCommand()
Execute(The list of search pathes for assemblies should be be used in the command if not empty): 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'] let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar']
AssertEqual 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() \ GetCommand()
let g:ale_cs_mcsc_assembly_path = [] let g:ale_cs_mcsc_assembly_path = []
AssertEqual AssertEqual
\ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', \ ale#path#BufferCdString(bufnr(''))
\ . 'mcs -unsafe' . g:prefix,
\ GetCommand() \ GetCommand()
Execute(The list of assemblies should be be used in the command if not empty): 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'] let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll']
AssertEqual 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() \ GetCommand()
let g:ale_cs_mcsc_assemblies = [] let g:ale_cs_mcsc_assemblies = []
AssertEqual AssertEqual
\ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', \ ale#path#BufferCdString(bufnr(''))
\ . 'mcs -unsafe' . g:prefix,
\ GetCommand() \ GetCommand()

View file

@ -9,6 +9,23 @@ After:
unlet! g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_source
call ale#linter#Reset() 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): 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'