Fix mcsc paths and escaping for Windows
This commit is contained in:
parent
647c798eb7
commit
0ad2547997
4 changed files with 74 additions and 49 deletions
|
@ -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',
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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'
|
||||||
|
|
||||||
|
|
Reference in a new issue