diff --git a/ale_linters/elixir/mix.vim b/ale_linters/elixir/mix.vim index 948c6d3648..f90a779b55 100644 --- a/ale_linters/elixir/mix.vim +++ b/ale_linters/elixir/mix.vim @@ -1,45 +1,89 @@ " Author: evnu - https://github.com/evnu " Author: colbydehart - https://github.com/colbydehart +" Author: toupeira - https://github.com/toupeira " Description: Mix compile checking for Elixir files function! ale_linters#elixir#mix#Handle(buffer, lines) abort - " Matches patterns like the following: + " Example output from Elixir 1.20.0: " - " Error format - " ** (CompileError) apps/sim/lib/sim/server.ex:87: undefined function update_in/4 + " warning: variable "a" is unused (if the variable is not meant to be used, prefix it with an underscore) + " │ + " 16 │ a = missing_var + " │ ~ + " │ + " └─ lib/foo.ex:16:5: Foo.hello/0 " - " TODO: Warning format - " warning: variable "foobar" does not exist and is being expanded to "foobar()", please use parentheses to remove the ambiguity or change the variable name - let l:pattern = '\v\(([^\)]+Error)\) ([^:]+):([^:]+): (.+)$' + " warning: variable "b" is unused (if the variable is not meant to be used, prefix it with an underscore) + " │ + " 17 │ b = another_missing_var + " │ ~ + " │ + " └─ lib/foo.ex:17:5: Foo.hello/0 + " + " error: undefined variable "another_missing_var" + " │ + " 17 │ b = another_missing_var + " │ ^^^^^^^^^^^^^^^^^^^ + " │ + " └─ lib/foo.ex:17:9: Foo.hello/0 + " + " error: undefined variable "missing_var" + " │ + " 16 │ a = missing_var + " │ ^^^^^^^^^^^ + " │ + " └─ lib/foo.ex:16:9: Foo.hello/0 + " + " + " == Compilation error in file lib/foo.ex == + " ** (CompileError) lib/foo.ex: cannot compile module Foo (errors have been logged) + " + " NOTE: The line with the error class is not captured because it always + " seems to be either a `CompileError` or a `SyntaxError`, with a generic + " message. + " + let l:pattern_text = '\v^ (warning|error): (.+)$' + let l:pattern_file = '\v^ └─ ([^ :]+):([0-9]+):([0-9]+)?' + + let l:match_texts = ale#util#GetMatches(a:lines, l:pattern_text) + let l:match_files = ale#util#GetMatches(a:lines, l:pattern_file) + let l:output = [] + let l:index = 0 + let l:bufname = bufname(a:buffer) + + " Always add the full output as detail + let l:detail = join(a:lines, "\n") - for l:match in ale#util#GetMatches(a:lines, l:pattern) - let l:type = 'E' - let l:text = l:match[4] + for l:match_text in l:match_texts + let l:type = toupper(l:match_text[1][0]) + let l:match_file = get(l:match_files, l:index, []) + + if get(l:match_file, 1) != bufname + continue + endif call add(l:output, { \ 'bufnr': a:buffer, - \ 'lnum': l:match[3] + 0, - \ 'col': 0, \ 'type': l:type, - \ 'text': l:text, + \ 'detail': l:detail, + \ 'text': get(l:match_text, 2, v:null), + \ 'lnum': get(l:match_file, 2, v:null), + \ 'col': get(l:match_file, 3, v:null), \}) + + let l:index += 1 endfor return l:output endfunction -function! ale_linters#elixir#mix#GetCommand(buffer) abort - let l:temp_dir = ale#command#CreateDirectory(a:buffer) - - return ale#Env('MIX_BUILD_PATH', l:temp_dir) . 'mix compile %s' -endfunction - call ale#linter#Define('elixir', { \ 'name': 'mix', \ 'executable': 'mix', \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'), -\ 'command': function('ale_linters#elixir#mix#GetCommand'), +\ 'command': '%e compile', +\ 'output_stream': 'stderr', \ 'callback': 'ale_linters#elixir#mix#Handle', \ 'lint_file': 1, \}) diff --git a/test/linter/test_elixir_mix.vader b/test/linter/test_elixir_mix.vader index a04bee552e..6ac225a2e1 100644 --- a/test/linter/test_elixir_mix.vader +++ b/test/linter/test_elixir_mix.vader @@ -1,19 +1,16 @@ Before: call ale#assert#SetUpLinterTest('elixir', 'mix') call ale#test#SetFilename('../test-files/elixir/mix_project/lib/app.ex') - let g:env_prefix = ale#Env('MIX_BUILD_PATH', 'TEMP_DIR') After: - unlet! g:env_prefix - call ale#assert#TearDownLinterTest() Execute(The default mix command should be correct): AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/mix_project') - AssertLinter 'mix', g:env_prefix . 'mix compile %s' + AssertLinter 'mix', '"mix" compile' Execute(Build mix commands with an umbrella root): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/mix_project/lib/app.ex') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') - AssertLinter 'mix', g:env_prefix . 'mix compile %s' + AssertLinter 'mix', '"mix" compile'