Compare commits

...

13 Commits

Author SHA1 Message Date
w0rp cedc3e1a1f Fix #560 #763 - Silence errors for setting signs, and do nothing for dirvish 2017-07-16 01:17:48 +01:00
w0rp 30aef6b19a Fix #749 - Use /bin/sh when the shell is fish 2017-07-10 21:36:42 +01:00
w0rp bd0f31147e Fix #730 - Lint files on save even when nothing was fixed 2017-07-10 13:41:38 +01:00
daa84 74f2afbe2e Fix windows path check on rust linter (#736)
* Fix rust linter on windows

* Add windows path test

* Use ale#path#IsBufferPath to compare paths

* Fix errors
2017-07-07 17:04:16 +01:00
w0rp d438f8f268 Fix #735 - Support old versions of Flow by only adding --respect-pragma for supported versions 2017-07-07 11:00:38 +01:00
w0rp 2f2af4315b #710 - Fix a parsing bug caused by the last fix 2017-07-07 11:00:26 +01:00
w0rp a040878ebc #710 - Show warnings as warnings for ghc 2017-07-07 00:28:52 +01:00
w0rp a72c1edfcc #732 - Use the configuration files when fixing files with rubocop 2017-07-06 23:08:38 +01:00
w0rp acda19776a Initialize rubocop variables in one place 2017-07-06 23:08:24 +01:00
w0rp e9a1cd600a Store the output of commands by default so I don't have to ask people to turn it on any more. 2017-07-04 00:16:53 +01:00
w0rp 0819c4cd56 Fix #216 - Filter out errors for other files for ansible-lint 2017-07-03 23:18:49 +01:00
w0rp 448600fe4f Merge pull request #716 from sobrinho/master
Fix brakeman handler when there is no output
2017-07-01 15:43:41 +01:00
w0rp bb1f413bf3 Fix #706 - Skip fixers with jobs that return empty output, in case they have failed 2017-06-29 12:03:05 +01:00
26 changed files with 287 additions and 95 deletions

View File

@ -15,11 +15,11 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
" test.yml:35: [EANSIBLE0002] Trailing whitespace " test.yml:35: [EANSIBLE0002] Trailing whitespace
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$' let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$'
let l:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[3] let l:code = l:match[4]
if (l:code ==# 'EANSIBLE002') if (l:code ==# 'EANSIBLE002')
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
@ -27,14 +27,14 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
continue continue
endif endif
let l:item = { if ale#path#IsBufferPath(a:buffer, l:match[1])
\ 'lnum': l:match[1] + 0, call add(l:output, {
\ 'col': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'text': l:code . ': ' . l:match[4], \ 'col': l:match[3] + 0,
\ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', \ 'text': l:code . ': ' . l:match[5],
\} \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
\})
call add(l:output, l:item) endif
endfor endfor
return l:output return l:output

View File

@ -10,7 +10,12 @@ function! ale_linters#javascript#flow#GetExecutable(buffer) abort
\]) \])
endfunction endfunction
function! ale_linters#javascript#flow#GetCommand(buffer) abort function! ale_linters#javascript#flow#VersionCheck(buffer) abort
return ale#Escape(ale_linters#javascript#flow#GetExecutable(a:buffer))
\ . ' --version'
endfunction
function! ale_linters#javascript#flow#GetCommand(buffer, version_lines) abort
let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig') let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig')
if empty(l:flow_config) if empty(l:flow_config)
@ -18,8 +23,21 @@ function! ale_linters#javascript#flow#GetCommand(buffer) abort
return '' return ''
endif endif
let l:use_respect_pragma = 1
" If we can parse the version number, then only use --respect-pragma
" if the version is >= 0.36.0, which added the argument.
for l:match in ale#util#GetMatches(a:version_lines, '\v\d+\.\d+\.\d+$')
let l:use_respect_pragma = ale#semver#GreaterOrEqual(
\ ale#semver#Parse(l:match[0]),
\ [0, 36, 0]
\)
endfor
return ale#Escape(ale_linters#javascript#flow#GetExecutable(a:buffer)) return ale#Escape(ale_linters#javascript#flow#GetExecutable(a:buffer))
\ . ' check-contents --respect-pragma --json --from ale %s' \ . ' check-contents'
\ . (l:use_respect_pragma ? ' --respect-pragma': '')
\ . ' --json --from ale %s'
endfunction endfunction
function! ale_linters#javascript#flow#Handle(buffer, lines) abort function! ale_linters#javascript#flow#Handle(buffer, lines) abort
@ -74,6 +92,10 @@ endfunction
call ale#linter#Define('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'flow', \ 'name': 'flow',
\ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable', \ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#flow#GetCommand', \ 'command_chain': [
\ {'callback': 'ale_linters#javascript#flow#VersionCheck'},
\ {'callback': 'ale_linters#javascript#flow#GetCommand'},
\ ],
\ 'callback': 'ale_linters#javascript#flow#Handle', \ 'callback': 'ale_linters#javascript#flow#Handle',
\ 'add_newline': 1,
\}) \})

View File

@ -5,6 +5,10 @@ let g:ale_ruby_brakeman_options =
\ get(g:, 'ale_ruby_brakeman_options', '') \ get(g:, 'ale_ruby_brakeman_options', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
if len(a:lines) == 0
return []
endif
let l:result = json_decode(join(a:lines, '')) let l:result = json_decode(join(a:lines, ''))
let l:output = [] let l:output = []

View File

@ -1,22 +1,8 @@
" Author: ynonp - https://github.com/ynonp " Author: ynonp - https://github.com/ynonp
" Description: rubocop for Ruby files " Description: rubocop for Ruby files
" Set this option to change Rubocop options.
if !exists('g:ale_ruby_rubocop_options')
" let g:ale_ruby_rubocop_options = '--lint'
let g:ale_ruby_rubocop_options = ''
endif
if !exists('g:ale_ruby_rubocop_executable')
let g:ale_ruby_rubocop_executable = 'rubocop'
endif
function! ale_linters#ruby#rubocop#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rubocop_executable')
endfunction
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable') let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'bundle$' let l:exec_args = l:executable =~? 'bundle$'
\ ? ' exec rubocop' \ ? ' exec rubocop'
\ : '' \ : ''
@ -52,7 +38,7 @@ endfunction
call ale#linter#Define('ruby', { call ale#linter#Define('ruby', {
\ 'name': 'rubocop', \ 'name': 'rubocop',
\ 'executable_callback': 'ale_linters#ruby#rubocop#GetExecutable', \ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand', \ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
\ 'callback': 'ale_linters#ruby#rubocop#Handle', \ 'callback': 'ale_linters#ruby#rubocop#Handle',
\}) \})

View File

@ -388,6 +388,16 @@ function! s:RunJob(options) abort
let l:read_buffer = 0 let l:read_buffer = 0
endif endif
" Add a newline to commands which need it.
" This is only used for Flow for now, and is not documented.
if l:linter.add_newline
if has('win32')
let l:command = l:command . '; echo.'
else
let l:command = l:command . '; echo'
endif
endif
let l:command = ale#job#PrepareCommand(l:command) let l:command = ale#job#PrepareCommand(l:command)
let l:job_options = { let l:job_options = {
\ 'mode': 'nl', \ 'mode': 'nl',

View File

@ -77,8 +77,6 @@ function! ale#fix#ApplyFixes(buffer, output) abort
echoerr 'The file was changed before fixing finished' echoerr 'The file was changed before fixing finished'
return return
endif endif
let l:data.done = 1
endif endif
if !bufexists(a:buffer) if !bufexists(a:buffer)
@ -86,6 +84,8 @@ function! ale#fix#ApplyFixes(buffer, output) abort
call remove(g:ale_fix_buffer_data, a:buffer) call remove(g:ale_fix_buffer_data, a:buffer)
endif endif
let l:data.done = 1
" We can only change the lines of a buffer which is currently open, " We can only change the lines of a buffer which is currently open,
" so try and apply the fixes to the current buffer. " so try and apply the fixes to the current buffer.
call ale#fix#ApplyQueuedFixes() call ale#fix#ApplyQueuedFixes()
@ -102,9 +102,15 @@ function! s:HandleExit(job_id, exit_code) abort
let l:job_info.output = readfile(l:job_info.file_to_read) let l:job_info.output = readfile(l:job_info.file_to_read)
endif endif
" Use the output of the job for changing the file if it isn't empty,
" otherwise skip this job and use the input from before.
let l:input = !empty(l:job_info.output)
\ ? l:job_info.output
\ : l:job_info.input
call s:RunFixer({ call s:RunFixer({
\ 'buffer': l:job_info.buffer, \ 'buffer': l:job_info.buffer,
\ 'input': l:job_info.output, \ 'input': l:input,
\ 'callback_list': l:job_info.callback_list, \ 'callback_list': l:job_info.callback_list,
\ 'callback_index': l:job_info.callback_index + 1, \ 'callback_index': l:job_info.callback_index + 1,
\}) \})
@ -172,6 +178,7 @@ function! s:RunJob(options) abort
let l:job_info = { let l:job_info = {
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input,
\ 'output': [], \ 'output': [],
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index,

View File

@ -1,24 +1,12 @@
" Set this option to change Rubocop options.
if !exists('g:ale_ruby_rubocop_options')
" let g:ale_ruby_rubocop_options = '--lint'
let g:ale_ruby_rubocop_options = ''
endif
if !exists('g:ale_ruby_rubocop_executable')
let g:ale_ruby_rubocop_executable = 'rubocop'
endif
function! ale#fixers#rubocop#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rubocop_executable')
endfunction
function! ale#fixers#rubocop#GetCommand(buffer) abort function! ale#fixers#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable') let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'bundle$' let l:exec_args = l:executable =~? 'bundle$'
\ ? ' exec rubocop' \ ? ' exec rubocop'
\ : '' \ : ''
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
return ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . ' --auto-correct %t' \ . ' --auto-correct %t'
endfunction endfunction

View File

@ -35,17 +35,21 @@ function! ale#handlers#haskell#HandleGHCFormat(buffer, lines) abort
continue continue
endif endif
let l:errors = matchlist(l:match[4], '\(warning:\|error:\)\(.*\)') let l:errors = matchlist(l:match[4], '\v([wW]arning|[eE]rror): ?(.*)')
if len(l:errors) > 0 if len(l:errors) > 0
let l:type = l:errors[1] let l:ghc_type = l:errors[1]
let l:text = l:errors[2] let l:text = l:errors[2]
else else
let l:type = '' let l:ghc_type = ''
let l:text = l:match[4] let l:text = l:match[4][:0] ==# ' ' ? l:match[4][1:] : l:match[4]
endif endif
let l:type = l:type ==# '' ? 'E' : toupper(l:type[0]) if l:ghc_type ==? 'Warning'
let l:type = 'W'
else
let l:type = 'E'
endif
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,

View File

@ -0,0 +1,6 @@
call ale#Set('ruby_rubocop_options', '')
call ale#Set('ruby_rubocop_executable', 'rubocop')
function! ale#handlers#rubocop#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rubocop_executable')
endfunction

View File

@ -8,13 +8,13 @@ if !exists('g:ale_rust_ignore_error_codes')
endif endif
" returns: a list [lnum, col] with the location of the error or [] " returns: a list [lnum, col] with the location of the error or []
function! s:FindErrorInExpansion(span, file_name) abort function! s:FindErrorInExpansion(span, buffer) abort
if a:span.file_name ==# a:file_name if ale#path#IsBufferPath(a:buffer, a:span.file_name)
return [a:span.line_start, a:span.line_end, a:span.byte_start, a:span.byte_end] return [a:span.line_start, a:span.line_end, a:span.byte_start, a:span.byte_end]
endif endif
if !empty(a:span.expansion) if !empty(a:span.expansion)
return s:FindErrorInExpansion(a:span.expansion.span, a:file_name) return s:FindErrorInExpansion(a:span.expansion.span, a:buffer)
endif endif
return [] return []
@ -22,7 +22,6 @@ endfunction
" A handler function which accepts a file name, to make unit testing easier. " A handler function which accepts a file name, to make unit testing easier.
function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines) abort function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines) abort
let l:filename = fnamemodify(a:full_filename, ':t')
let l:output = [] let l:output = []
for l:errorline in a:lines for l:errorline in a:lines
@ -48,7 +47,7 @@ function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines
for l:span in l:error.spans for l:span in l:error.spans
if ( if (
\ l:span.is_primary \ l:span.is_primary
\ && (a:full_filename =~ (l:span.file_name . '$') || l:span.file_name ==# '<anon>') \ && (ale#path#IsBufferPath(a:buffer, l:span.file_name) || l:span.file_name ==# '<anon>')
\) \)
call add(l:output, { call add(l:output, {
\ 'lnum': l:span.line_start, \ 'lnum': l:span.line_start,
@ -61,7 +60,7 @@ function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines
else else
" when the error is caused in the expansion of a macro, we have " when the error is caused in the expansion of a macro, we have
" to bury deeper " to bury deeper
let l:root_cause = s:FindErrorInExpansion(l:span, l:filename) let l:root_cause = s:FindErrorInExpansion(l:span, a:buffer)
if !empty(l:root_cause) if !empty(l:root_cause)
call add(l:output, { call add(l:output, {

View File

@ -174,9 +174,15 @@ function! ale#job#PrepareCommand(command) abort
" NeoVim handles this issue automatically if the command is a String, " NeoVim handles this issue automatically if the command is a String,
" but we'll do this explicitly, so we use thes same exact command for both " but we'll do this explicitly, so we use thes same exact command for both
" versions. " versions.
return has('win32') if ale#Has('win32')
\ ? 'cmd /c ' . a:command return 'cmd /c ' . a:command
\ : split(&shell) + split(&shellcmdflag) + [a:command] endif
if &shell =~? 'fish$'
return ['/bin/sh', '-c', a:command]
endif
return split(&shell) + split(&shellcmdflag) + [a:command]
endfunction endfunction
" Start a job with options which are agnostic to Vim and NeoVim. " Start a job with options which are agnostic to Vim and NeoVim.

View File

@ -50,6 +50,7 @@ function! ale#linter#PreProcess(linter) abort
endif endif
let l:obj = { let l:obj = {
\ 'add_newline': get(a:linter, 'add_newline', 0),
\ 'name': get(a:linter, 'name'), \ 'name': get(a:linter, 'name'),
\ 'lsp': get(a:linter, 'lsp', ''), \ 'lsp': get(a:linter, 'lsp', ''),
\ 'callback': get(a:linter, 'callback'), \ 'callback': get(a:linter, 'callback'),

View File

@ -65,7 +65,7 @@ sign define ALEDummySign
" Read sign data for a buffer to a list of lines. " Read sign data for a buffer to a list of lines.
function! ale#sign#ReadSigns(buffer) abort function! ale#sign#ReadSigns(buffer) abort
redir => l:output redir => l:output
silent exec 'sign place buffer=' . a:buffer silent execute 'sign place buffer=' . a:buffer
redir end redir end
return split(l:output, "\n") return split(l:output, "\n")
@ -154,7 +154,7 @@ function! s:SetDummySignIfNeeded(buffer, current_sign_list, new_signs) abort
" If we haven't already set a dummy sign, and we have some previous signs " If we haven't already set a dummy sign, and we have some previous signs
" or always want a dummy sign, then set one, to keep the sign column open. " or always want a dummy sign, then set one, to keep the sign column open.
if !l:is_dummy_sign_set && (a:new_signs || g:ale_sign_column_always) if !l:is_dummy_sign_set && (a:new_signs || g:ale_sign_column_always)
execute 'sign place ' . g:ale_sign_offset silent! execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign buffer=' \ . ' line=1 name=ALEDummySign buffer='
\ . a:buffer \ . a:buffer
@ -223,7 +223,7 @@ function! s:PlaceNewSigns(buffer, grouped_items, current_sign_offset) abort
let l:obj.sign_id = l:sign_id let l:obj.sign_id = l:sign_id
endfor endfor
execute 'sign place ' . l:sign_id silent! execute 'sign place ' . l:sign_id
\ . ' line=' . l:sublist[0].lnum \ . ' line=' . l:sublist[0].lnum
\ . ' name=' . l:type \ . ' name=' . l:type
\ . ' buffer=' . a:buffer \ . ' buffer=' . a:buffer
@ -295,7 +295,7 @@ function! ale#sign#SetSigns(buffer, loclist) abort
for [l:line, l:sign_id, l:name] in l:current_sign_list for [l:line, l:sign_id, l:name] in l:current_sign_list
if l:sign_id != g:ale_sign_offset if l:sign_id != g:ale_sign_offset
\&& !has_key(l:items_by_sign_id, l:sign_id) \&& !has_key(l:items_by_sign_id, l:sign_id)
exec 'sign unplace ' . l:sign_id . ' buffer=' . a:buffer execute 'sign unplace ' . l:sign_id . ' buffer=' . a:buffer
endif endif
endfor endfor

View File

@ -354,7 +354,7 @@ g:ale_history_enabled *g:ale_history_enabled*
g:ale_history_log_output *g:ale_history_log_output* g:ale_history_log_output *g:ale_history_log_output*
Type: |Number| Type: |Number|
Default: `0` Default: `1`
When set to `1`, ALE will store the output of commands which have completed When set to `1`, ALE will store the output of commands which have completed
successfully in the command history, and the output will be displayed when successfully in the command history, and the output will be displayed when
@ -363,8 +363,9 @@ g:ale_history_log_output *g:ale_history_log_output*
|g:ale_history_enabled| must be set to `1` for this output to be stored or |g:ale_history_enabled| must be set to `1` for this output to be stored or
printed. printed.
ALE will likely consume a lot of memory if this option is on, so it should Some memory will be consumed by this option. It is very useful for figuring
only be used for debugging problems with linters. out what went wrong with linters, and for bug reports. Turn this option off
if you want to save on some memory usage.
g:ale_keep_list_window_open *g:ale_keep_list_window_open* g:ale_keep_list_window_open *g:ale_keep_list_window_open*

View File

@ -55,7 +55,13 @@ let g:ale_buffer_info = {}
" This option prevents ALE autocmd commands from being run for particular " This option prevents ALE autocmd commands from being run for particular
" filetypes which can cause issues. " filetypes which can cause issues.
let g:ale_filetype_blacklist = ['nerdtree', 'unite', 'tags'] let g:ale_filetype_blacklist = [
\ 'dirvish',
\ 'nerdtree',
\ 'qf',
\ 'tags',
\ 'unite',
\]
" This Dictionary configures which linters are enabled for which languages. " This Dictionary configures which linters are enabled for which languages.
let g:ale_linters = get(g:, 'ale_linters', {}) let g:ale_linters = get(g:, 'ale_linters', {})
@ -167,7 +173,7 @@ let g:ale_max_buffer_history_size = get(g:, 'ale_max_buffer_history_size', 20)
let g:ale_history_enabled = get(g:, 'ale_history_enabled', 1) let g:ale_history_enabled = get(g:, 'ale_history_enabled', 1)
" A flag for storing the full output of commands in the history. " A flag for storing the full output of commands in the history.
let g:ale_history_log_output = get(g:, 'ale_history_log_output', 0) let g:ale_history_log_output = get(g:, 'ale_history_log_output', 1)
" A dictionary mapping regular expression patterns to arbitrary buffer " A dictionary mapping regular expression patterns to arbitrary buffer
" variables to be set. Useful for configuration ALE based on filename " variables to be set. Useful for configuration ALE based on filename

View File

@ -19,10 +19,24 @@ After:
unlet! g:dir unlet! g:dir
Execute(The rubocop callback should return the correct default values): Execute(The rubocop callback should return the correct default values):
silent execute 'file ' . fnameescape(g:dir . '/ruby_paths/dummy.rb') call ale#test#SetFilename('ruby_paths/dummy.rb')
AssertEqual AssertEqual
\ {'read_temporary_file': 1, \ {
\ 'command': "'" . g:ale_ruby_rubocop_executable . "' " \ 'read_temporary_file': 1,
\ . '--auto-correct %t' }, \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --auto-correct %t',
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
Execute(The rubocop callback should include configuration files):
call ale#test#SetFilename('ruby_paths/with_config/dummy.rb')
AssertEqual
\ {
\ 'read_temporary_file': 1,
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(g:dir . '/ruby_paths/with_config/.rubocop.yml')
\ . ' --auto-correct %t',
\ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))

View File

@ -1,5 +1,6 @@
Before: Before:
runtime ale_linters/ansible/ansible_lint.vim runtime ale_linters/ansible/ansible_lint.vim
call ale#test#SetFilename('main.yml')
After: After:
call ale#linter#Reset() call ale#linter#Reset()
@ -11,11 +12,11 @@ Execute(The ansible-lint handler should handle basic errors):
\ 'lnum': 35, \ 'lnum': 35,
\ 'col': 0, \ 'col': 0,
\ 'type': 'E', \ 'type': 'E',
\ 'text': "EANSIBLE0002: Trailing whitespace", \ 'text': 'EANSIBLE0002: Trailing whitespace',
\ }, \ },
\ ], \ ],
\ ale_linters#ansible#ansible_lint#Handle(42, [ \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [
\ "test.yml:35: [EANSIBLE0002] Trailing whitespace", \ '/tmp/vxepmGL/1/main.yml:35: [EANSIBLE0002] Trailing whitespace',
\ ]) \ ])
Execute (The ansible-lint handler should handle names with spaces): Execute (The ansible-lint handler should handle names with spaces):
@ -28,6 +29,14 @@ Execute (The ansible-lint handler should handle names with spaces):
\ 'text': 'E111: indentation is not a multiple of four', \ 'text': 'E111: indentation is not a multiple of four',
\ }, \ },
\ ], \ ],
\ ale_linters#ansible#ansible_lint#Handle(42, [ \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [
\ 'C:\something\with spaces.yml:6:6: E111 indentation is not a multiple of four', \ '/tmp/vxepm GL/1/main.yml:6:6: E111 indentation is not a multiple of four',
\ ])
Execute (The ansible-lint handler should ignore errors from other files):
AssertEqual
\ [
\ ],
\ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [
\ '/foo/bar/roles/main.yml:6:6: E111 indentation is not a multiple of four',
\ ]) \ ])

View File

@ -73,3 +73,9 @@ Execute(The brakeman handler should parse JSON correctly):
\ ']', \ ']',
\ '}' \ '}'
\ ]) \ ])
Execute(The brakeman handler should parse JSON correctly when there is no output from brakeman):
AssertEqual
\ [],
\ ale_linters#ruby#brakeman#Handle(347, [
\ ])

View File

@ -25,13 +25,13 @@ Execute(The ghc handler should handle ghc 8 output):
\ 'lnum': 6, \ 'lnum': 6,
\ 'type': 'E', \ 'type': 'E',
\ 'col': 1, \ 'col': 1,
\ 'text': ' Failed to load interface for GitHub.Data Use -v to see a list of the files searched for.', \ 'text': 'Failed to load interface for GitHub.Data Use -v to see a list of the files searched for.',
\ }, \ },
\ { \ {
\ 'lnum': 7, \ 'lnum': 7,
\ 'type': 'W', \ 'type': 'W',
\ 'col': 1, \ 'col': 1,
\ 'text': ' Failed to load interface for GitHub.Endpoints.PullRequests Use -v to see a list of the files searched for.', \ 'text': 'Failed to load interface for GitHub.Endpoints.PullRequests Use -v to see a list of the files searched for.',
\ }, \ },
\ ], \ ],
\ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [
@ -54,10 +54,25 @@ Execute(The ghc handler should handle ghc 7 output):
\ 'lnum': 168, \ 'lnum': 168,
\ 'type': 'E', \ 'type': 'E',
\ 'col': 1, \ 'col': 1,
\ 'text': ' parse error (possibly incorrect indentation or mismatched brackets)', \ 'text': 'parse error (possibly incorrect indentation or mismatched brackets)',
\ },
\ {
\ 'lnum': 84,
\ 'col': 1,
\ 'type': 'W',
\ 'text': 'Top-level binding with no type signature:^@ myLayout :: Choose Tall (Choose (Mirror Tall) Full) a',
\ },
\ {
\ 'lnum': 94,
\ 'col': 5,
\ 'type': 'E',
\ 'text': 'Some other error',
\ }, \ },
\ ], \ ],
\ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [
\ 'src/Main.hs:168:1:', \ 'src/Main.hs:168:1:',
\ ' parse error (possibly incorrect indentation or mismatched brackets)', \ ' parse error (possibly incorrect indentation or mismatched brackets)',
\ 'src/Main.hs:84:1:Warning: Top-level binding with no type signature:^@ myLayout :: Choose Tall (Choose (Mirror Tall) Full) a',
\ 'src/Main.hs:94:5:Error:',
\ ' Some other error',
\ ]) \ ])

View File

@ -13,13 +13,13 @@ Execute(HandleGhcFormat should handle ghc-mod problems):
\ 'lnum': 2, \ 'lnum': 2,
\ 'col': 1, \ 'col': 1,
\ 'type': 'E', \ 'type': 'E',
\ 'text': ' Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...', \ 'text': 'Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...',
\ }, \ },
\ { \ {
\ 'lnum': 6, \ 'lnum': 6,
\ 'col': 1, \ 'col': 1,
\ 'type': 'E', \ 'type': 'W',
\ 'text': ' Warning: Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', \ 'text': 'Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ',
\ }, \ },
\ ], \ ],
\ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [

View File

@ -1,4 +1,6 @@
Execute(The Rust handler should handle rustc output): Execute(The Rust handler should handle rustc output):
call ale#test#SetFilename('src/playpen.rs')
AssertEqual AssertEqual
\ [ \ [
\ { \ {
@ -18,7 +20,7 @@ Execute(The Rust handler should handle rustc output):
\ 'text': 'no method named `wat` found for type `std::string::String` in the current scope', \ 'text': 'no method named `wat` found for type `std::string::String` in the current scope',
\ }, \ },
\ ], \ ],
\ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/playpen.rs', [ \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/playpen.rs', [
\ '', \ '',
\ 'ignore this', \ 'ignore this',
\ '{"message":"expected one of `.`, `;`, `?`, `}`, or an operator, found `for`","code":null,"level":"error","spans":[{"file_name":"<anon>","byte_start":418,"byte_end":421,"line_start":15,"line_end":15,"column_start":5,"column_end":8,"is_primary":true,"text":[{"text":" for chr in source.trim().chars() {","highlight_start":5,"highlight_end":8}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}', \ '{"message":"expected one of `.`, `;`, `?`, `}`, or an operator, found `for`","code":null,"level":"error","spans":[{"file_name":"<anon>","byte_start":418,"byte_end":421,"line_start":15,"line_end":15,"column_start":5,"column_end":8,"is_primary":true,"text":[{"text":" for chr in source.trim().chars() {","highlight_start":5,"highlight_end":8}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}',
@ -28,6 +30,8 @@ Execute(The Rust handler should handle rustc output):
\ ]) \ ])
Execute(The Rust handler should handle cargo output): Execute(The Rust handler should handle cargo output):
call ale#test#SetFilename('src/playpen.rs')
AssertEqual AssertEqual
\ [ \ [
\ { \ {
@ -47,7 +51,7 @@ Execute(The Rust handler should handle cargo output):
\ 'text': 'no method named `wat` found for type `std::string::String` in the current scope', \ 'text': 'no method named `wat` found for type `std::string::String` in the current scope',
\ }, \ },
\ ], \ ],
\ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/playpen.rs', [ \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/playpen.rs', [
\ '', \ '',
\ 'ignore this', \ 'ignore this',
\ '{"message":{"children":[],"code":null,"level":"error","message":"expected one of `.`, `;`, `?`, `}`, or an operator, found `for`","rendered":null,"spans":[{"byte_end":11508,"byte_start":11505,"column_end":8,"column_start":5,"expansion":null,"file_name":"src/playpen.rs","is_primary":true,"label":null,"line_end":15,"line_start":15,"suggested_replacement":null,"text":[{"highlight_end":8,"highlight_start":5,"text":" for chr in source.trim().chars() {"}]}]},"package_id":"update 0.0.1 (path+file:///home/w0rp/Downloads/rust-by-example)","reason":"compiler-message","target":{"kind":["bin"],"name":"update","src_path":"/home/w0rp/Downloads/rust-by-example/src/main.rs"}}', \ '{"message":{"children":[],"code":null,"level":"error","message":"expected one of `.`, `;`, `?`, `}`, or an operator, found `for`","rendered":null,"spans":[{"byte_end":11508,"byte_start":11505,"column_end":8,"column_start":5,"expansion":null,"file_name":"src/playpen.rs","is_primary":true,"label":null,"line_end":15,"line_start":15,"suggested_replacement":null,"text":[{"highlight_end":8,"highlight_start":5,"text":" for chr in source.trim().chars() {"}]}]},"package_id":"update 0.0.1 (path+file:///home/w0rp/Downloads/rust-by-example)","reason":"compiler-message","target":{"kind":["bin"],"name":"update","src_path":"/home/w0rp/Downloads/rust-by-example/src/main.rs"}}',
@ -55,7 +59,27 @@ Execute(The Rust handler should handle cargo output):
\ '{"message":{"children":[],"code":null,"level":"error","message":"aborting due to previous error","rendered":null,"spans":[]},"package_id":"update 0.0.1 (path+file:///home/w0rp/Downloads/rust-by-example)","reason":"compiler-message","target":{"kind":["bin"],"name":"update","src_path":"/home/w0rp/Downloads/rust-by-example/src/main.rs"}}', \ '{"message":{"children":[],"code":null,"level":"error","message":"aborting due to previous error","rendered":null,"spans":[]},"package_id":"update 0.0.1 (path+file:///home/w0rp/Downloads/rust-by-example)","reason":"compiler-message","target":{"kind":["bin"],"name":"update","src_path":"/home/w0rp/Downloads/rust-by-example/src/main.rs"}}',
\ ]) \ ])
" Execute(The Rust handler should handle cargo output on Windows):
" call ale#test#SetFilename('src\nvim.rs')
"
" AssertEqual
" \ [
" \ {
" \ 'lnum': 467,
" \ 'end_lnum': 467,
" \ 'type': 'E',
" \ 'col': 43198,
" \ 'end_col': 43199,
" \ 'text': 'expected one of `!` or `::`, found `#`: unexpected token',
" \ },
" \ ],
" \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src\nvim.rs', [
" \ '{"message":{"children":[],"code":null,"level":"error","message":"expected one of `!` or `::`, found `#`","rendered":null,"spans":[{"byte_end":43199,"byte_start":43198,"column_end":2,"column_start":1,"expansion":null,"file_name":"src\\nvim.rs","is_primary":true,"label":"unexpected token","line_end":467,"line_start":467,"suggested_replacement":null,"text":[{"highlight_end":2,"highlight_start":1,"text":"#[cfg(test)]\r"}]}]},"package_id":"nvim-gtk 0.1.2 (path+file:///E:/daa/local/neovim-gtk)","reason":"compiler-message","target":{"crate_types":["bin"],"kind":["bin"],"name":"nvim-gtk","src_path":"E:\\daa\\local\\neovim-gtk\\src\\main.rs"}}',
" \ ])
Execute(The Rust handler should show detailed errors): Execute(The Rust handler should show detailed errors):
call ale#test#SetFilename('src/playpen.rs')
AssertEqual AssertEqual
\ [ \ [
\ { \ {
@ -67,7 +91,7 @@ Execute(The Rust handler should show detailed errors):
\ 'text': 'mismatched types: expected bool, found integral variable', \ 'text': 'mismatched types: expected bool, found integral variable',
\ }, \ },
\ ], \ ],
\ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/playpen.rs', [ \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/playpen.rs', [
\ '', \ '',
\ 'ignore this', \ 'ignore this',
\ '{"message":{"children":[],"code":null,"level":"error","message":"mismatched types","rendered":null,"spans":[{"byte_end":54,"byte_start":52,"column_end":23,"column_start":21,"expansion":null,"file_name":"src/playpen.rs","is_primary":true,"label":"expected bool, found integral variable","line_end":4,"line_start":4,"suggested_replacement":null,"text":[{"highlight_end":23,"highlight_start":21,"text":" let foo: bool = 42;"}]}]},"package_id":"ale-rust-details 0.1.1 (path+file:///home/jon/tmp/ale-rust-details)","reason":"compiler-message","target":{"crate_types":["bin"],"kind":["bin"],"name":"ale-rust-details","src_path":"/home/jon/tmp/ale-rust-details/src/main.rs"}}', \ '{"message":{"children":[],"code":null,"level":"error","message":"mismatched types","rendered":null,"spans":[{"byte_end":54,"byte_start":52,"column_end":23,"column_start":21,"expansion":null,"file_name":"src/playpen.rs","is_primary":true,"label":"expected bool, found integral variable","line_end":4,"line_start":4,"suggested_replacement":null,"text":[{"highlight_end":23,"highlight_start":21,"text":" let foo: bool = 42;"}]}]},"package_id":"ale-rust-details 0.1.1 (path+file:///home/jon/tmp/ale-rust-details)","reason":"compiler-message","target":{"crate_types":["bin"],"kind":["bin"],"name":"ale-rust-details","src_path":"/home/jon/tmp/ale-rust-details/src/main.rs"}}',
@ -75,9 +99,11 @@ Execute(The Rust handler should show detailed errors):
\ ]) \ ])
Execute(The Rust handler should find correct files): Execute(The Rust handler should find correct files):
call ale#test#SetFilename('src/noerrors/mod.rs')
AssertEqual AssertEqual
\ [], \ [],
\ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/noerrors/mod.rs', [ \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/noerrors/mod.rs', [
\ '', \ '',
\ 'ignore this', \ 'ignore this',
\ '{"message":{"children":[],"code":null,"level":"error","message":"unresolved import `Undefined`","rendered":null,"spans":[{"byte_end":103,"byte_start":94,"column_end":14,"column_start":5,"expansion":null,"file_name":"src/haserrors/mod.rs","is_primary":true,"label":"no `Undefined` in the root","line_end":1,"line_start":1,"suggested_replacement":null,"text":[{"highlight_end":14,"highlight_start":5,"text":"use Undefined;"}]}]},"package_id":"sample 0.1.0 (path+file:///private/tmp/sample)","reason":"compiler-message","target":{"crate_types":["lib"],"kind":["lib"],"name":"sample","src_path":"/private/tmp/sample/src/lib.rs"}}', \ '{"message":{"children":[],"code":null,"level":"error","message":"unresolved import `Undefined`","rendered":null,"spans":[{"byte_end":103,"byte_start":94,"column_end":14,"column_start":5,"expansion":null,"file_name":"src/haserrors/mod.rs","is_primary":true,"label":"no `Undefined` in the root","line_end":1,"line_start":1,"suggested_replacement":null,"text":[{"highlight_end":14,"highlight_start":5,"text":"use Undefined;"}]}]},"package_id":"sample 0.1.0 (path+file:///private/tmp/sample)","reason":"compiler-message","target":{"crate_types":["lib"],"kind":["lib"],"name":"sample","src_path":"/private/tmp/sample/src/lib.rs"}}',

View File

@ -86,6 +86,8 @@ After:
call delete('fix_test_file') call delete('fix_test_file')
endif endif
call setloclist(0, [])
let g:ale_fix_buffer_data = {} let g:ale_fix_buffer_data = {}
Given testft (A file with three lines): Given testft (A file with three lines):
@ -305,6 +307,38 @@ Expect(The buffer should be the same):
b b
c c
Execute(ALEFix should still lint when nothing was fixed on save):
let g:ale_fix_on_save = 1
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
noautocmd silent file fix_test_file
let g:ale_fixers.testft = ['DoNothing']
call SetUpLinters()
call ale#events#SaveEvent()
Assert !filereadable('fix_test_file'), 'The file should not have been saved'
" We have run the linter.
AssertEqual [{
\ 'bufnr': bufnr('%'),
\ 'lnum': 1,
\ 'vcol': 0,
\ 'col': 1,
\ 'text': 'xxx',
\ 'type': 'E',
\ 'nr': -1,
\ 'pattern': '',
\ 'valid': 1,
\}], getloclist(0)
Expect(The buffer should be the same):
a
b
c
Given testft (A file with three lines): Given testft (A file with three lines):
a a
b b

View File

@ -8,10 +8,21 @@ Execute(flow should return a command to run if a .flowconfig file exists):
silent! cd /testplugin/test silent! cd /testplugin/test
:e! flow/a/sub/dummy :e! flow/a/sub/dummy
AssertEqual '''flow'' check-contents --respect-pragma --json --from ale %s', ale_linters#javascript#flow#GetCommand(bufnr('%')) AssertEqual '''flow'' check-contents --respect-pragma --json --from ale %s', ale_linters#javascript#flow#GetCommand(bufnr('%'), [])
Execute(flow should should not use --respect-pragma for old versions):
silent! cd /testplugin/test
:e! flow/a/sub/dummy
AssertEqual
\ '''flow'' check-contents --json --from ale %s',
\ ale_linters#javascript#flow#GetCommand(bufnr('%'), [
\ 'Warning: `flow --version` is deprecated in favor of `flow version`',
\ 'Flow, a static type checker for JavaScript, version 0.27.0',
\ ])
Execute(flow should not return a command to run if no .flowconfig file exists): Execute(flow should not return a command to run if no .flowconfig file exists):
silent! cd /testplugin/test silent! cd /testplugin/test
:e! flow/b/sub/dummy :e! flow/b/sub/dummy
AssertEqual '', ale_linters#javascript#flow#GetCommand(bufnr('%')) AssertEqual '', ale_linters#javascript#flow#GetCommand(bufnr('%'), [])

View File

@ -1,8 +1,8 @@
Before: Before:
Save g:ale_linters, g:ale_linter_aliases Save g:ale_linters, g:ale_linter_aliases
let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': ''} let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': '', 'add_newline': 0}
let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout', 'read_buffer': 0, 'lint_file': 1, 'aliases': [], 'lsp': ''} let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout', 'read_buffer': 0, 'lint_file': 1, 'aliases': [], 'lsp': '', 'add_newline': 0}
call ale#linter#Reset() call ale#linter#Reset()
After: After:
@ -105,7 +105,7 @@ Execute (The local alias option shouldn't completely replace the global one):
AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1') AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1')
Execute (Linters should be loaded from disk appropriately): Execute (Linters should be loaded from disk appropriately):
AssertEqual [{'name': 'testlinter', 'output_stream': 'stdout', 'executable': 'testlinter', 'command': 'testlinter', 'callback': 'testCB', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': ''}], ale#linter#Get('testft') AssertEqual [{'name': 'testlinter', 'output_stream': 'stdout', 'executable': 'testlinter', 'command': 'testlinter', 'callback': 'testCB', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': '', 'add_newline': 0}], ale#linter#Get('testft')
Execute (Linters for later filetypes should replace the former ones): Execute (Linters for later filetypes should replace the former ones):
@ -123,5 +123,5 @@ Execute (Linters for later filetypes should replace the former ones):
\}) \})
AssertEqual [ AssertEqual [
\ {'output_stream': 'stdout', 'lint_file': 0, 'read_buffer': 1, 'name': 'eslint', 'executable': 'x', 'lsp': '', 'aliases': [], 'command': 'x', 'callback': 'x'} \ {'output_stream': 'stdout', 'lint_file': 0, 'read_buffer': 1, 'name': 'eslint', 'executable': 'x', 'lsp': '', 'aliases': [], 'command': 'x', 'callback': 'x', 'add_newline': 0}
\], ale#linter#Get('javascript.typescript') \], ale#linter#Get('javascript.typescript')

View File

@ -0,0 +1,37 @@
Before:
Save &shell
Save &shellcmdflag
After:
Restore
let g:ale_has_override = {}
Execute(sh should be used when the shell is fish):
" Set something else, so we will replace that too.
let &shellcmdflag = '-f'
let &shell = 'fish'
AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
let &shell = '/usr/bin/fish'
AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
let &shell = '/usr/local/bin/fish'
AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
Execute(Other shells should be used when set):
let &shell = '/bin/bash'
let &shellcmdflag = '-c'
AssertEqual ['/bin/bash', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
Execute(cmd /c as a string should be used on Windows):
let &shell = 'who cares'
let &shellcmdflag = 'whatever'
let g:ale_has_override = {'win32': 1}
AssertEqual 'cmd /c foobar', ale#job#PrepareCommand('foobar')