diff --git a/ale_linters/ansible/ansible_lint.vim b/ale_linters/ansible/ansible_lint.vim index 3efd95f..192e65b 100644 --- a/ale_linters/ansible/ansible_lint.vim +++ b/ale_linters/ansible/ansible_lint.vim @@ -15,11 +15,11 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort " Matches patterns line the following: " " 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 = [] 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') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') @@ -27,14 +27,14 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort continue endif - let l:item = { - \ 'lnum': l:match[1] + 0, - \ 'col': l:match[2] + 0, - \ 'text': l:code . ': ' . l:match[4], - \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', - \} - - call add(l:output, l:item) + if ale#path#IsBufferPath(a:buffer, l:match[1]) + call add(l:output, { + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'text': l:code . ': ' . l:match[5], + \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', + \}) + endif endfor return l:output diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim index 1b13e5d..416a1ed 100644 --- a/ale_linters/javascript/flow.vim +++ b/ale_linters/javascript/flow.vim @@ -10,7 +10,12 @@ function! ale_linters#javascript#flow#GetExecutable(buffer) abort \]) 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') if empty(l:flow_config) @@ -18,8 +23,21 @@ function! ale_linters#javascript#flow#GetCommand(buffer) abort return '' 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)) - \ . ' check-contents --respect-pragma --json --from ale %s' + \ . ' check-contents' + \ . (l:use_respect_pragma ? ' --respect-pragma': '') + \ . ' --json --from ale %s' endfunction function! ale_linters#javascript#flow#Handle(buffer, lines) abort @@ -74,6 +92,10 @@ endfunction call ale#linter#Define('javascript', { \ 'name': 'flow', \ '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', +\ 'add_newline': 1, \}) diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim index fa5617d..5ea531f 100644 --- a/ale_linters/ruby/brakeman.vim +++ b/ale_linters/ruby/brakeman.vim @@ -5,6 +5,10 @@ let g:ale_ruby_brakeman_options = \ get(g:, 'ale_ruby_brakeman_options', '') 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:output = [] diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim index f8b0725..9b77f89 100644 --- a/ale_linters/ruby/rubocop.vim +++ b/ale_linters/ruby/rubocop.vim @@ -1,22 +1,8 @@ " Author: ynonp - https://github.com/ynonp " 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 - 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$' \ ? ' exec rubocop' \ : '' @@ -52,7 +38,7 @@ endfunction call ale#linter#Define('ruby', { \ 'name': 'rubocop', -\ 'executable_callback': 'ale_linters#ruby#rubocop#GetExecutable', +\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable', \ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand', \ 'callback': 'ale_linters#ruby#rubocop#Handle', \}) diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index f7c25b0..5d9c541 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -388,6 +388,16 @@ function! s:RunJob(options) abort let l:read_buffer = 0 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:job_options = { \ 'mode': 'nl', diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index b4fd3e1..45855a5 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -77,8 +77,6 @@ function! ale#fix#ApplyFixes(buffer, output) abort echoerr 'The file was changed before fixing finished' return endif - - let l:data.done = 1 endif if !bufexists(a:buffer) @@ -86,6 +84,8 @@ function! ale#fix#ApplyFixes(buffer, output) abort call remove(g:ale_fix_buffer_data, a:buffer) endif + let l:data.done = 1 + " We can only change the lines of a buffer which is currently open, " so try and apply the fixes to the current buffer. 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) 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({ \ 'buffer': l:job_info.buffer, - \ 'input': l:job_info.output, + \ 'input': l:input, \ 'callback_list': l:job_info.callback_list, \ 'callback_index': l:job_info.callback_index + 1, \}) @@ -172,6 +178,7 @@ function! s:RunJob(options) abort let l:job_info = { \ 'buffer': l:buffer, + \ 'input': l:input, \ 'output': [], \ 'callback_list': a:options.callback_list, \ 'callback_index': a:options.callback_index, diff --git a/autoload/ale/fixers/rubocop.vim b/autoload/ale/fixers/rubocop.vim index 7bc6c9e..88dc1c4 100644 --- a/autoload/ale/fixers/rubocop.vim +++ b/autoload/ale/fixers/rubocop.vim @@ -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 - 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$' \ ? ' exec rubocop' \ : '' + let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') return ale#Escape(l:executable) . l:exec_args + \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . ' --auto-correct %t' endfunction diff --git a/autoload/ale/handlers/haskell.vim b/autoload/ale/handlers/haskell.vim index 17d9d24..5d417c8 100644 --- a/autoload/ale/handlers/haskell.vim +++ b/autoload/ale/handlers/haskell.vim @@ -35,17 +35,21 @@ function! ale#handlers#haskell#HandleGHCFormat(buffer, lines) abort continue 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 - let l:type = l:errors[1] + let l:ghc_type = l:errors[1] let l:text = l:errors[2] else - let l:type = '' - let l:text = l:match[4] + let l:ghc_type = '' + let l:text = l:match[4][:0] ==# ' ' ? l:match[4][1:] : l:match[4] 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, { \ 'lnum': l:match[2] + 0, diff --git a/autoload/ale/handlers/rubocop.vim b/autoload/ale/handlers/rubocop.vim new file mode 100644 index 0000000..f6367cf --- /dev/null +++ b/autoload/ale/handlers/rubocop.vim @@ -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 diff --git a/autoload/ale/handlers/rust.vim b/autoload/ale/handlers/rust.vim index 47b3c7f..3f9083a 100644 --- a/autoload/ale/handlers/rust.vim +++ b/autoload/ale/handlers/rust.vim @@ -8,13 +8,13 @@ if !exists('g:ale_rust_ignore_error_codes') endif " returns: a list [lnum, col] with the location of the error or [] -function! s:FindErrorInExpansion(span, file_name) abort - if a:span.file_name ==# a:file_name +function! s:FindErrorInExpansion(span, buffer) abort + 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] endif 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 return [] @@ -22,7 +22,6 @@ endfunction " A handler function which accepts a file name, to make unit testing easier. function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines) abort - let l:filename = fnamemodify(a:full_filename, ':t') let l:output = [] 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 if ( \ l:span.is_primary - \ && (a:full_filename =~ (l:span.file_name . '$') || l:span.file_name ==# '') + \ && (ale#path#IsBufferPath(a:buffer, l:span.file_name) || l:span.file_name ==# '') \) call add(l:output, { \ 'lnum': l:span.line_start, @@ -61,7 +60,7 @@ function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines else " when the error is caused in the expansion of a macro, we have " 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) call add(l:output, { diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim index b9ab86b..93f2882 100644 --- a/autoload/ale/job.vim +++ b/autoload/ale/job.vim @@ -174,9 +174,15 @@ function! ale#job#PrepareCommand(command) abort " 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 " versions. - return has('win32') - \ ? 'cmd /c ' . a:command - \ : split(&shell) + split(&shellcmdflag) + [a:command] + if ale#Has('win32') + return 'cmd /c ' . a:command + endif + + if &shell =~? 'fish$' + return ['/bin/sh', '-c', a:command] + endif + + return split(&shell) + split(&shellcmdflag) + [a:command] endfunction " Start a job with options which are agnostic to Vim and NeoVim. diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index 3c2ddd3..c732ec5 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -50,6 +50,7 @@ function! ale#linter#PreProcess(linter) abort endif let l:obj = { + \ 'add_newline': get(a:linter, 'add_newline', 0), \ 'name': get(a:linter, 'name'), \ 'lsp': get(a:linter, 'lsp', ''), \ 'callback': get(a:linter, 'callback'), diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim index eee1027..37105f9 100644 --- a/autoload/ale/sign.vim +++ b/autoload/ale/sign.vim @@ -65,7 +65,7 @@ sign define ALEDummySign " Read sign data for a buffer to a list of lines. function! ale#sign#ReadSigns(buffer) abort redir => l:output - silent exec 'sign place buffer=' . a:buffer + silent execute 'sign place buffer=' . a:buffer redir end 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 " 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) - execute 'sign place ' . g:ale_sign_offset + silent! execute 'sign place ' . g:ale_sign_offset \ . ' line=1 name=ALEDummySign 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 endfor - execute 'sign place ' . l:sign_id + silent! execute 'sign place ' . l:sign_id \ . ' line=' . l:sublist[0].lnum \ . ' name=' . l:type \ . ' 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 if l:sign_id != g:ale_sign_offset \&& !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 endfor diff --git a/doc/ale.txt b/doc/ale.txt index 8804622..8054747 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -354,7 +354,7 @@ g:ale_history_enabled *g:ale_history_enabled* g:ale_history_log_output *g:ale_history_log_output* Type: |Number| - Default: `0` + Default: `1` 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 @@ -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 printed. - ALE will likely consume a lot of memory if this option is on, so it should - only be used for debugging problems with linters. + Some memory will be consumed by this option. It is very useful for figuring + 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* diff --git a/plugin/ale.vim b/plugin/ale.vim index a42eb50..f36da0a 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -55,7 +55,13 @@ let g:ale_buffer_info = {} " This option prevents ALE autocmd commands from being run for particular " 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. 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) " 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 " variables to be set. Useful for configuration ALE based on filename diff --git a/test/command_callback/ruby_paths/with_config/.rubocop.yml b/test/command_callback/ruby_paths/with_config/.rubocop.yml new file mode 100644 index 0000000..e69de29 diff --git a/test/fixers/test_rubocop_fixer_callback.vader b/test/fixers/test_rubocop_fixer_callback.vader index e9352e7..74160c7 100644 --- a/test/fixers/test_rubocop_fixer_callback.vader +++ b/test/fixers/test_rubocop_fixer_callback.vader @@ -19,10 +19,24 @@ After: unlet! g:dir 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 - \ {'read_temporary_file': 1, - \ 'command': "'" . g:ale_ruby_rubocop_executable . "' " - \ . '--auto-correct %t' }, + \ { + \ 'read_temporary_file': 1, + \ '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('')) diff --git a/test/handler/test_ansible_lint_handler.vader b/test/handler/test_ansible_lint_handler.vader index cffe29f..b14b1f6 100644 --- a/test/handler/test_ansible_lint_handler.vader +++ b/test/handler/test_ansible_lint_handler.vader @@ -1,5 +1,6 @@ Before: runtime ale_linters/ansible/ansible_lint.vim + call ale#test#SetFilename('main.yml') After: call ale#linter#Reset() @@ -11,11 +12,11 @@ Execute(The ansible-lint handler should handle basic errors): \ 'lnum': 35, \ 'col': 0, \ 'type': 'E', - \ 'text': "EANSIBLE0002: Trailing whitespace", + \ 'text': 'EANSIBLE0002: Trailing whitespace', \ }, \ ], - \ ale_linters#ansible#ansible_lint#Handle(42, [ - \ "test.yml:35: [EANSIBLE0002] Trailing whitespace", + \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [ + \ '/tmp/vxepmGL/1/main.yml:35: [EANSIBLE0002] Trailing whitespace', \ ]) 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', \ }, \ ], - \ ale_linters#ansible#ansible_lint#Handle(42, [ - \ 'C:\something\with spaces.yml:6:6: E111 indentation is not a multiple of four', + \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [ + \ '/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', \ ]) diff --git a/test/handler/test_brakeman_handler.vader b/test/handler/test_brakeman_handler.vader index bc7182e..6a577be 100644 --- a/test/handler/test_brakeman_handler.vader +++ b/test/handler/test_brakeman_handler.vader @@ -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, [ + \ ]) diff --git a/test/handler/test_ghc_handler.vader b/test/handler/test_ghc_handler.vader index 524f08b..bf54386 100644 --- a/test/handler/test_ghc_handler.vader +++ b/test/handler/test_ghc_handler.vader @@ -25,13 +25,13 @@ Execute(The ghc handler should handle ghc 8 output): \ 'lnum': 6, \ 'type': 'E', \ '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, \ 'type': 'W', \ '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(''), [ @@ -54,10 +54,25 @@ Execute(The ghc handler should handle ghc 7 output): \ 'lnum': 168, \ 'type': 'E', \ '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(''), [ \ 'src/Main.hs:168:1:', \ ' 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', \ ]) diff --git a/test/handler/test_ghc_mod_handler.vader b/test/handler/test_ghc_mod_handler.vader index 53991bb..b8d09a5 100644 --- a/test/handler/test_ghc_mod_handler.vader +++ b/test/handler/test_ghc_mod_handler.vader @@ -13,13 +13,13 @@ Execute(HandleGhcFormat should handle ghc-mod problems): \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', - \ 'text': ' Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...', + \ 'text': 'Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...', \ }, \ { \ 'lnum': 6, \ 'col': 1, - \ 'type': 'E', - \ 'text': ' Warning: Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', + \ 'type': 'W', + \ 'text': 'Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ diff --git a/test/handler/test_rust_handler.vader b/test/handler/test_rust_handler.vader index 11dcf17..510ae69 100644 --- a/test/handler/test_rust_handler.vader +++ b/test/handler/test_rust_handler.vader @@ -1,4 +1,6 @@ Execute(The Rust handler should handle rustc output): + call ale#test#SetFilename('src/playpen.rs') + 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', \ }, \ ], - \ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/playpen.rs', [ + \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/playpen.rs', [ \ '', \ 'ignore this', \ '{"message":"expected one of `.`, `;`, `?`, `}`, or an operator, found `for`","code":null,"level":"error","spans":[{"file_name":"","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): + call ale#test#SetFilename('src/playpen.rs') + 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', \ }, \ ], - \ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/playpen.rs', [ + \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/playpen.rs', [ \ '', \ '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"}}', @@ -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"}}', \ ]) +" 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): + call ale#test#SetFilename('src/playpen.rs') + AssertEqual \ [ \ { @@ -67,7 +91,7 @@ Execute(The Rust handler should show detailed errors): \ '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', \ '{"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): + call ale#test#SetFilename('src/noerrors/mod.rs') + AssertEqual \ [], - \ ale#handlers#rust#HandleRustErrorsForFile(347, 'src/noerrors/mod.rs', [ + \ ale#handlers#rust#HandleRustErrorsForFile(bufnr(''), 'src/noerrors/mod.rs', [ \ '', \ '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"}}', diff --git a/test/test_ale_fix.vader b/test/test_ale_fix.vader index f7c6d69..d7c3fb3 100644 --- a/test/test_ale_fix.vader +++ b/test/test_ale_fix.vader @@ -86,6 +86,8 @@ After: call delete('fix_test_file') endif + call setloclist(0, []) + let g:ale_fix_buffer_data = {} Given testft (A file with three lines): @@ -305,6 +307,38 @@ Expect(The buffer should be the same): b 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): a b diff --git a/test/test_flow_command.vader b/test/test_flow_command.vader index f7754f6..f45c93c 100644 --- a/test/test_flow_command.vader +++ b/test/test_flow_command.vader @@ -8,10 +8,21 @@ Execute(flow should return a command to run if a .flowconfig file exists): silent! cd /testplugin/test :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): silent! cd /testplugin/test :e! flow/b/sub/dummy - AssertEqual '', ale_linters#javascript#flow#GetCommand(bufnr('%')) + AssertEqual '', ale_linters#javascript#flow#GetCommand(bufnr('%'), []) diff --git a/test/test_linter_retrieval.vader b/test/test_linter_retrieval.vader index d701234..afb540d 100644 --- a/test/test_linter_retrieval.vader +++ b/test/test_linter_retrieval.vader @@ -1,8 +1,8 @@ Before: 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:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout', 'read_buffer': 0, 'lint_file': 1, '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': '', 'add_newline': 0} call ale#linter#Reset() 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') 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): @@ -123,5 +123,5 @@ Execute (Linters for later filetypes should replace the former ones): \}) 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') diff --git a/test/test_prepare_command.vader b/test/test_prepare_command.vader new file mode 100644 index 0000000..5707be7 --- /dev/null +++ b/test/test_prepare_command.vader @@ -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')