diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | ale_linters/cpp/cpplint.vim | 15 | ||||
-rw-r--r-- | ale_linters/javascript/eslint.vim | 18 | ||||
-rw-r--r-- | autoload/ale/command.vim | 57 | ||||
-rw-r--r-- | autoload/ale/engine.vim | 61 | ||||
-rw-r--r-- | autoload/ale/handlers/cpplint.vim | 20 | ||||
-rw-r--r-- | autoload/ale/handlers/gcc.vim | 9 | ||||
-rw-r--r-- | autoload/ale/handlers/rust.vim | 32 | ||||
-rw-r--r-- | autoload/ale/highlight.vim | 2 | ||||
-rw-r--r-- | autoload/ale/job.vim | 2 | ||||
-rw-r--r-- | autoload/ale/lsp.vim | 32 | ||||
-rw-r--r-- | doc/ale-cpp.txt | 11 | ||||
-rw-r--r-- | doc/ale.txt | 3 | ||||
-rw-r--r-- | test/handler/test_cpplint_handler.vader | 27 | ||||
-rw-r--r-- | test/handler/test_eslint_handler.vader | 58 | ||||
-rw-r--r-- | test/handler/test_gcc_handler.vader | 26 | ||||
-rw-r--r-- | test/handler/test_rust_handler.vader | 18 | ||||
-rw-r--r-- | test/test_format_command.vader | 21 | ||||
-rw-r--r-- | test/test_highlight_placement.vader | 13 | ||||
-rw-r--r-- | test/test_loclist_corrections.vader | 36 |
20 files changed, 370 insertions, 93 deletions
@@ -58,7 +58,7 @@ name. That seems to be the fairest way to arrange this table. | Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) | | Bourne Shell | [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/) | | C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)| -| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)| +| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [gcc](https://gcc.gnu.org/)| | C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) | | Chef | [foodcritic](http://www.foodcritic.io/) | | CMake | [cmakelint](https://github.com/richq/cmake-lint) | diff --git a/ale_linters/cpp/cpplint.vim b/ale_linters/cpp/cpplint.vim new file mode 100644 index 00000000..0f43996b --- /dev/null +++ b/ale_linters/cpp/cpplint.vim @@ -0,0 +1,15 @@ +" Author: Dawid Kurek https://github.com/dawikur +" Description: cpplint for cpp files + +if !exists('g:ale_cpp_cpplint_options') + let g:ale_cpp_cpplint_options = '' +endif + +call ale#linter#Define('cpp', { +\ 'name': 'cpplint', +\ 'output_stream': 'stderr', +\ 'executable': 'cpplint', +\ 'command': 'cpplint %s', +\ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat', +\ 'lint_file': 1, +\}) diff --git a/ale_linters/javascript/eslint.vim b/ale_linters/javascript/eslint.vim index d5e51acb..f1c3bb01 100644 --- a/ale_linters/javascript/eslint.vim +++ b/ale_linters/javascript/eslint.vim @@ -39,6 +39,13 @@ function! ale_linters#javascript#eslint#GetCommand(buffer) abort \ . ' -f unix --stdin --stdin-filename %s' endfunction +let s:col_end_patterns = [ +\ '\vParsing error: Unexpected token (.+) ', +\ '\v''(.+)'' is not defined.', +\ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]', +\ '\vUnexpected (console) statement', +\] + function! ale_linters#javascript#eslint#Handle(buffer, lines) abort let l:config_error_pattern = '\v^ESLint couldn''t find a configuration file' \ . '|^Cannot read config file' @@ -77,13 +84,18 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines) abort let l:text .= ' [' . l:match[4] . ']' endif - call add(l:output, { - \ 'bufnr': a:buffer, + let l:obj = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:text, \ 'type': l:type ==# 'Warning' ? 'W' : 'E', - \}) + \} + + for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns) + let l:obj.end_col = l:obj.col + len(l:col_match[1]) - 1 + endfor + + call add(l:output, l:obj) endfor return l:output diff --git a/autoload/ale/command.vim b/autoload/ale/command.vim new file mode 100644 index 00000000..f8d04ff2 --- /dev/null +++ b/autoload/ale/command.vim @@ -0,0 +1,57 @@ +" Author: w0rp <devw0rp@gmail.com> +" Description: Special command formatting for creating temporary files and +" passing buffer filenames easily. + +function! s:TemporaryFilename(buffer) abort + let l:filename = fnamemodify(bufname(a:buffer), ':t') + + if empty(l:filename) + " If the buffer's filename is empty, create a dummy filename. + let l:ft = getbufvar(a:buffer, '&filetype') + let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft) + endif + + " Create a temporary filename, <temp_dir>/<original_basename> + " The file itself will not be created by this function. + return tempname() . (has('win32') ? '\' : '/') . l:filename +endfunction + +" Given a command string, replace every... +" %s -> with the current filename +" %t -> with the name of an unused file in a temporary directory +" %% -> with a literal % +function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort + let l:temporary_file = '' + let l:command = a:command + + " First replace all uses of %%, used for literal percent characters, + " with an ugly string. + let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g') + + " Replace all %s occurences in the string with the name of the current + " file. + if l:command =~# '%s' + let l:filename = fnamemodify(bufname(a:buffer), ':p') + let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g') + endif + + if l:command =~# '%t' + " Create a temporary filename, <temp_dir>/<original_basename> + " The file itself will not be created by this function. + let l:temporary_file = s:TemporaryFilename(a:buffer) + let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g') + endif + + " Finish formatting so %% becomes %. + let l:command = substitute(l:command, '<<PERCENTS>>', '%', 'g') + + if a:pipe_file_if_needed && empty(l:temporary_file) + " If we are to send the Vim buffer to a command, we'll do it + " in the shell. We'll write out the file to a temporary file, + " and then read it back in, in the shell. + let l:temporary_file = s:TemporaryFilename(a:buffer) + let l:command = l:command . ' < ' . ale#Escape(l:temporary_file) + endif + + return [l:temporary_file, l:command] +endfunction diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index c778f253..af074c00 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -288,6 +288,11 @@ function! ale#engine#FixLocList(buffer, linter, loclist) abort let l:item.detail = l:old_item.detail endif + " Pass on a col_length key if set, used for highlights. + if has_key(l:old_item, 'end_col') + let l:item.end_col = str2nr(l:old_item.end_col) + endif + if l:item.lnum == 0 " When errors appear at line 0, put them at line 1 instead. let l:item.lnum = 1 @@ -308,52 +313,6 @@ function! ale#engine#EscapeCommandPart(command_part) abort return substitute(a:command_part, '%', '%%', 'g') endfunction -function! s:TemporaryFilename(buffer) abort - let l:filename = fnamemodify(bufname(a:buffer), ':t') - - if empty(l:filename) - " If the buffer's filename is empty, create a dummy filename. - let l:ft = getbufvar(a:buffer, '&filetype') - let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft) - endif - - " Create a temporary filename, <temp_dir>/<original_basename> - " The file itself will not be created by this function. - return tempname() . (has('win32') ? '\' : '/') . l:filename -endfunction - -" Given a command string, replace every... -" %s -> with the current filename -" %t -> with the name of an unused file in a temporary directory -" %% -> with a literal % -function! ale#engine#FormatCommand(buffer, command) abort - let l:temporary_file = '' - let l:command = a:command - - " First replace all uses of %%, used for literal percent characters, - " with an ugly string. - let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g') - - " Replace all %s occurences in the string with the name of the current - " file. - if l:command =~# '%s' - let l:filename = fnamemodify(bufname(a:buffer), ':p') - let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g') - endif - - if l:command =~# '%t' - " Create a temporary filename, <temp_dir>/<original_basename> - " The file itself will not be created by this function. - let l:temporary_file = s:TemporaryFilename(a:buffer) - let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g') - endif - - " Finish formatting so %% becomes %. - let l:command = substitute(l:command, '<<PERCENTS>>', '%', 'g') - - return [l:temporary_file, l:command] -endfunction - function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort if empty(a:temporary_file) " There is no file, so we didn't create anything. @@ -380,15 +339,7 @@ function! s:RunJob(options) abort let l:next_chain_index = a:options.next_chain_index let l:read_buffer = a:options.read_buffer - let [l:temporary_file, l:command] = ale#engine#FormatCommand(l:buffer, l:command) - - if l:read_buffer && empty(l:temporary_file) - " If we are to send the Vim buffer to a command, we'll do it - " in the shell. We'll write out the file to a temporary file, - " and then read it back in, in the shell. - let l:temporary_file = s:TemporaryFilename(l:buffer) - let l:command = l:command . ' < ' . ale#Escape(l:temporary_file) - endif + let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer) if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file) " If a temporary filename has been formatted in to the command, then diff --git a/autoload/ale/handlers/cpplint.vim b/autoload/ale/handlers/cpplint.vim new file mode 100644 index 00000000..46078633 --- /dev/null +++ b/autoload/ale/handlers/cpplint.vim @@ -0,0 +1,20 @@ +" Author: Dawid Kurek https://github.com/dawikur +" Description: Handle errors for cpplint. + +function! ale#handlers#cpplint#HandleCppLintFormat(buffer, lines) abort + " Look for lines like the following. + " test.cpp:5: Estra space after ( in function call [whitespace/parents] [4] + let l:pattern = '^.\{-}:\(\d\+\): \(.\+\)' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + call add(l:output, { + \ 'lnum': l:match[1] + 0, + \ 'col': 0, + \ 'text': l:match[2], + \ 'type': 'W', + \}) + endfor + + return l:output +endfunction diff --git a/autoload/ale/handlers/gcc.vim b/autoload/ale/handlers/gcc.vim index eb42b27a..09a1848d 100644 --- a/autoload/ale/handlers/gcc.vim +++ b/autoload/ale/handlers/gcc.vim @@ -99,12 +99,17 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort continue endif - call add(l:output, { + let l:obj = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] =~# 'error' ? 'E' : 'W', \ 'text': s:RemoveUnicodeQuotes(l:match[5]), - \}) + \} + + " clang++ and some other tools can output duplicated errors. + if empty(l:output) || l:output[-1] != l:obj + call add(l:output, l:obj) + endif endif endfor diff --git a/autoload/ale/handlers/rust.vim b/autoload/ale/handlers/rust.vim index 4fa7f059..7724ed72 100644 --- a/autoload/ale/handlers/rust.vim +++ b/autoload/ale/handlers/rust.vim @@ -20,17 +20,37 @@ function! s:FindErrorInExpansion(span, file_name) abort return [] endfunction +" The JSON output for Rust can be split over many lines. +" Those lines should be joined together again. +function! s:JoinJSONLines(lines) abort + let l:corrected_lines = [] + let l:object_continues = 0 + + for l:line in a:lines + if l:object_continues + let l:corrected_lines[-1] .= l:line + + if l:line =~# '}$' + let l:object_continues = 0 + endif + elseif l:line =~# '^{' + call add(l:corrected_lines, l:line) + + if l:line !~# '}$' + let l:object_continues = 1 + endif + endif + endfor + + return l:corrected_lines +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 - " ignore everything that is not Json - if l:errorline !~# '^{' - continue - endif - + for l:errorline in s:JoinJSONLines(a:lines) let l:error = json_decode(l:errorline) if has_key(l:error, 'message') && type(l:error.message) == type({}) diff --git a/autoload/ale/highlight.vim b/autoload/ale/highlight.vim index f3a479e3..4ac1d1e4 100644 --- a/autoload/ale/highlight.vim +++ b/autoload/ale/highlight.vim @@ -86,7 +86,7 @@ function! ale#highlight#UpdateHighlights() abort let l:col = l:item.col let l:group = l:item.type ==# 'E' ? 'ALEError' : 'ALEWarning' let l:line = l:item.lnum - let l:size = 1 + let l:size = has_key(l:item, 'end_col') ? l:item.end_col - l:col + 1 : 1 " Rememeber the match ID for the item. " This ID will be used to preserve loclist items which are set diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim index d0572f51..11a36045 100644 --- a/autoload/ale/job.vim +++ b/autoload/ale/job.vim @@ -220,7 +220,7 @@ function! ale#job#SendRaw(job_id, string) abort if has('nvim') call jobsend(a:job_id, a:string) else - call ch_sendraw(job_getchannel(s:job_map[a:job_id]), a:string) + call ch_sendraw(job_getchannel(s:job_map[a:job_id].job), a:string) endif endfunction diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim index acf47408..36620228 100644 --- a/autoload/ale/lsp.vim +++ b/autoload/ale/lsp.vim @@ -160,22 +160,28 @@ function! ale#lsp#SendMessageToProgram(executable, command, message, ...) abort let [l:id, l:data] = ale#lsp#CreateMessageData(a:message) let l:matches = filter(s:connections[:], 'v:val.executable ==# a:executable') - - if empty(l:matches) - " We haven't looked at this executable before. - " Create a new connection. - let l:conn = NewConnection() - endif + " Get the current connection or a new one. + let l:conn = !empty(l:matches) ? l:matches[0] : s:NewConnection() if !ale#job#IsRunning(l:conn.job_id) - let l:options = {'mode': 'raw', 'out_cb': 's:HandleCommandMessage'} + let l:options = { + \ 'mode': 'raw', + \ 'out_cb': function('s:HandleCommandMessage'), + \} let l:job_id = ale#job#Start(ale#job#PrepareCommand(a:command), l:options) endif - if l:job_id > 0 + if l:job_id <= 0 return 0 endif + " The ID is 0 when the message is a Notification, which is a JSON-RPC + " request for which the server must not return a response. + if l:id != 0 + " Add the callback, which the server will respond to later. + let l:conn.callback_map[l:id] = a:1 + endif + call ale#job#SendRaw(l:job_id, l:data) let l:conn.job_id = l:job_id @@ -201,18 +207,14 @@ function! ale#lsp#SendMessageToAddress(address, message, ...) abort let [l:id, l:data] = ale#lsp#CreateMessageData(a:message) let l:matches = filter(s:connections[:], 'v:val.address ==# a:address') - - if empty(l:matches) - " We haven't looked at this address before. - " Create a new connection. - let l:conn = NewConnection() - endif + " Get the current connection or a new one. + let l:conn = !empty(l:matches) ? l:matches[0] : s:NewConnection() if !has_key(l:conn, 'channel') || ch_status(l:conn.channel) !=# 'open' let l:conn.channnel = ch_open(a:address, { \ 'mode': 'raw', \ 'waittime': 0, - \ 'callback': 's:HandleChannelMessage', + \ 'callback': function('s:HandleChannelMessage'), \}) endif diff --git a/doc/ale-cpp.txt b/doc/ale-cpp.txt index 71673826..a64f87b1 100644 --- a/doc/ale-cpp.txt +++ b/doc/ale-cpp.txt @@ -59,6 +59,17 @@ g:ale_cpp_cppcheck_options *g:ale_cpp_cppcheck_options* ------------------------------------------------------------------------------- +cpplint *ale-cpp-cpplint* + +g:ale_cpp_cpplint_options *g:ale_cpp_cpplint_options* + *b:ale_cpp_cpplint_options* + Type: |String| + Default: `''` + + This variable can be changed to modify flags given to cpplint. + + +------------------------------------------------------------------------------- gcc *ale-cpp-gcc* g:ale_cpp_gcc_options *g:ale_cpp_gcc_options* diff --git a/doc/ale.txt b/doc/ale.txt index 85dc6d20..52a709bb 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -22,6 +22,7 @@ CONTENTS *ale-contents* clang...............................|ale-cpp-clang| clangtidy...........................|ale-cpp-clangtidy| cppcheck............................|ale-cpp-cppcheck| + cpplint.............................|ale-cpp-cpplint| gcc.................................|ale-cpp-gcc| css...................................|ale-css-options| stylelint...........................|ale-css-stylelint| @@ -120,7 +121,7 @@ The following languages and tools are supported. * Bash: 'shell' (-n flag), 'shellcheck' * Bourne Shell: 'shell' (-n flag), 'shellcheck' * C: 'cppcheck', 'gcc', 'clang' -* C++ (filetype cpp): 'clang', 'clangtidy', 'cppcheck', 'gcc' +* C++ (filetype cpp): 'clang', 'clangtidy', 'cppcheck', 'cpplint', 'gcc' * C#: 'mcs' * Chef: 'foodcritic' * CMake: 'cmakelint' diff --git a/test/handler/test_cpplint_handler.vader b/test/handler/test_cpplint_handler.vader new file mode 100644 index 00000000..6df84ccd --- /dev/null +++ b/test/handler/test_cpplint_handler.vader @@ -0,0 +1,27 @@ +Before: + runtime ale_linters/cpp/cpplint.vim + +Execute(cpplint warnings from included files should be parsed correctly): + + AssertEqual + \ [ + \ { + \ 'lnum': 5, + \ 'col': 0, + \ 'text': ' Estra space after ( in function call [whitespace/parents] [4]', + \ 'type': 'W', + \ }, + \ { + \ 'lnum': 120, + \ 'col': 0, + \ 'text': ' At least two spaces is best between code and comments [whitespace/comments] [2]', + \ 'type': 'W', + \ }, + \ ], + \ ale#handlers#cpplint#HandleCppLintFormat(347, [ + \ 'test.cpp:5: Estra space after ( in function call [whitespace/parents] [4]', + \ 'keymap_keys.hpp:120: At least two spaces is best between code and comments [whitespace/comments] [2]', + \ ]) + +After: + call ale#linter#Reset() diff --git a/test/handler/test_eslint_handler.vader b/test/handler/test_eslint_handler.vader index 6d84ff7e..9d5e98fc 100644 --- a/test/handler/test_eslint_handler.vader +++ b/test/handler/test_eslint_handler.vader @@ -5,21 +5,18 @@ Execute(The eslint handler should parse lines correctly): AssertEqual \ [ \ { - \ 'bufnr': 347, \ 'lnum': 47, \ 'col': 14, \ 'text': 'Missing trailing comma. [Warning/comma-dangle]', \ 'type': 'W', \ }, \ { - \ 'bufnr': 347, \ 'lnum': 56, \ 'col': 41, \ 'text': 'Missing semicolon. [Error/semi]', \ 'type': 'E', \ }, \ { - \ 'bufnr': 347, \ 'lnum': 13, \ 'col': 3, \ 'text': 'Parsing error: Unexpected token', @@ -117,3 +114,58 @@ Execute(The eslint handler should print a message for invalid configuration sett \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale_linters#javascript#eslint#Handle(347, g:config_error_lines[:]) + +Execute(The eslint handler should output end_col values where appropriate): + AssertEqual + \ [ + \ { + \ 'lnum': 4, + \ 'col': 3, + \ 'end_col': 15, + \ 'text': 'Parsing error: Unexpected token ''some string'' [Error]', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 70, + \ 'col': 3, + \ 'end_col': 5, + \ 'text': '''foo'' is not defined. [Error/no-undef]', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 71, + \ 'col': 2, + \ 'end_col': 6, + \ 'text': 'Unexpected `await` inside a loop. [Error/no-await-in-loop]', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 72, + \ 'col': 6, + \ 'end_col': 10, + \ 'text': 'Redundant use of `await` on a return value. [Error/no-return-await]', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 73, + \ 'col': 4, + \ 'end_col': 10, + \ 'text': 'Unexpected console statement [Error/no-console]', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 74, + \ 'col': 4, + \ 'end_col': 11, + \ 'text': 'Unexpected ''debugger'' statement. [Error/no-debugger]', + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#javascript#eslint#Handle(347, [ + \ 'app.js:4:3: Parsing error: Unexpected token ''some string'' [Error]', + \ 'app.js:70:3: ''foo'' is not defined. [Error/no-undef]', + \ 'app.js:71:2: Unexpected `await` inside a loop. [Error/no-await-in-loop]', + \ 'app.js:72:6: Redundant use of `await` on a return value. [Error/no-return-await]', + \ 'app.js:73:4: Unexpected console statement [Error/no-console]', + \ 'app.js:74:4: Unexpected ''debugger'' statement. [Error/no-debugger]', + \ ]) diff --git a/test/handler/test_gcc_handler.vader b/test/handler/test_gcc_handler.vader index 72b7c541..2934bbee 100644 --- a/test/handler/test_gcc_handler.vader +++ b/test/handler/test_gcc_handler.vader @@ -94,3 +94,29 @@ Execute(The GCC handler shouldn't complain about #pragma once for headers): \ ale#handlers#gcc#HandleGCCFormat(347, [ \ '<stdin>:1:1: warning: #pragma once in main file [enabled by default]', \ ]) + +Execute(The GCC handler should eliminate duplicated clang errors): + AssertEqual + \ [ + \ {'lnum': 2, 'col': 10, 'type': 'E', 'text': '''a.h'' file not found'}, + \ {'lnum': 4, 'col': 10, 'type': 'E', 'text': 'empty filename'}, + \ ], + \ ale#handlers#gcc#HandleGCCFormat(347, [ + \ '<stdin>:2:10: fatal error: ''a.h'' file not found', + \ '#include "a.h"', + \ ' ^~~~~', + \ '', + \ '<stdin>:2:10: fatal error: ''a.h'' file not found', + \ '#include "a.h"', + \ ' ^~~~~', + \ '', + \ '<stdin>:4:10: error: empty filename', + \ '', + \ '<stdin>:4:10: error: empty filename', + \ '#include ""', + \ ' ^', + \ '', + \ '<stdin>:4:10: error: empty filename', + \ '#include ""', + \ ' ^', + \ ]) diff --git a/test/handler/test_rust_handler.vader b/test/handler/test_rust_handler.vader index 3e0ed43d..052d722b 100644 --- a/test/handler/test_rust_handler.vader +++ b/test/handler/test_rust_handler.vader @@ -46,3 +46,21 @@ Execute(The Rust handler should handle cargo output): \ '{"message":{"children":[],"code":null,"level":"error","message":"no method named `wat` found for type `std::string::String` in the current scope","rendered":null,"spans":[{"byte_end":11497,"byte_start":11494,"column_end":10,"column_start":7,"expansion":null,"file_name":"src/playpen.rs","is_primary":true,"label":null,"line_end":13,"line_start":13,"suggested_replacement":null,"text":[{"highlight_end":10,"highlight_start":7,"text":" s.wat()"}]}]},"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 JSON split over many lines): + AssertEqual + \ [ + \ { + \ 'lnum': 15, + \ 'type': 'E', + \ 'col': 11505, + \ 'text': 'expected one of `.`, `;`, `?`, `}`, or an operator, found `for`', + \ }, + \ ], + \ ale#handlers#rust#HandleRustErrorsForFile(347, '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"}}', + \ ]) diff --git a/test/test_format_command.vader b/test/test_format_command.vader index 08496c18..156ced9b 100644 --- a/test/test_format_command.vader +++ b/test/test_format_command.vader @@ -7,16 +7,16 @@ After: unlet! g:match Execute(FormatCommand should do nothing to basic command strings): - AssertEqual ['', 'awesome-linter do something'], ale#engine#FormatCommand(bufnr('%'), 'awesome-linter do something') + AssertEqual ['', 'awesome-linter do something'], ale#command#FormatCommand(bufnr('%'), 'awesome-linter do something', 0) Execute(FormatCommand should handle %%, and ignore other percents): - AssertEqual ['', '% %%d %%f %x %'], ale#engine#FormatCommand(bufnr('%'), '%% %%%d %%%f %x %') + AssertEqual ['', '% %%d %%f %x %'], ale#command#FormatCommand(bufnr('%'), '%% %%%d %%%f %x %', 0) Execute(FormatCommand should convert %s to the current filename): - AssertEqual ['', 'foo ' . shellescape(expand('%:p')) . ' bar ' . shellescape(expand('%:p'))], ale#engine#FormatCommand(bufnr('%'), 'foo %s bar %s') + AssertEqual ['', 'foo ' . shellescape(expand('%:p')) . ' bar ' . shellescape(expand('%:p'))], ale#command#FormatCommand(bufnr('%'), 'foo %s bar %s', 0) Execute(FormatCommand should convert %t to a new temporary filename): - let g:result = ale#engine#FormatCommand(bufnr('%'), 'foo %t bar %t') + let g:result = ale#command#FormatCommand(bufnr('%'), 'foo %t bar %t', 0) let g:match = matchlist(g:result[1], '\v^foo (''/tmp/[^'']*/dummy.txt'') bar (''/tmp/[^'']*/dummy.txt'')$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] @@ -27,7 +27,7 @@ Execute(FormatCommand should convert %t to a new temporary filename): AssertEqual g:match[1], g:match[2] Execute(FormatCommand should let you combine %s and %t): - let g:result = ale#engine#FormatCommand(bufnr('%'), 'foo %t bar %s') + let g:result = ale#command#FormatCommand(bufnr('%'), 'foo %t bar %s', 0) let g:match = matchlist(g:result[1], '\v^foo (''/tmp/.*/dummy.txt'') bar (''.*/dummy.txt'')$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] @@ -39,3 +39,14 @@ Execute(FormatCommand should let you combine %s and %t): Execute(EscapeCommandPart should escape all percent signs): AssertEqual '%%s %%t %%%% %%s %%t %%%%', ale#engine#EscapeCommandPart('%s %t %% %s %t %%') + +Execute(EscapeCommandPart should pipe in temporary files appropriately): + let g:result = ale#command#FormatCommand(bufnr('%'), 'foo bar', 1) + let g:match = matchlist(g:result[1], '\v^foo bar \< (''/tmp/[^'']*/dummy.txt'')$') + Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] + AssertEqual shellescape(g:result[0]), g:match[1] + + let g:result = ale#command#FormatCommand(bufnr('%'), 'foo bar %t', 1) + let g:match = matchlist(g:result[1], '\v^foo bar (''/tmp/[^'']*/dummy.txt'')$') + Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] + AssertEqual shellescape(g:result[0]), g:match[1] diff --git a/test/test_highlight_placement.vader b/test/test_highlight_placement.vader index 25c98784..b5878922 100644 --- a/test/test_highlight_placement.vader +++ b/test/test_highlight_placement.vader @@ -137,3 +137,16 @@ Execute(Only ALE highlights should be restored when buffers are restored): " Only our matches should appear again. AssertEqual 1, len(getmatches()), 'The highlights weren''t set again!' + +Execute(Higlight end columns should set an appropriate size): + call ale#highlight#SetHighlights(bufnr('%'), [ + \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2, 'end_col': 5}, + \ {'bufnr': bufnr('%'), 'type': 'W', 'lnum': 4, 'col': 1, 'end_col': 5}, + \]) + + AssertEqual + \ [ + \ {'group': 'ALEError', 'id': 15, 'priority': 10, 'pos1': [3, 2, 4]}, + \ {'group': 'ALEWarning', 'id': 16, 'priority': 10, 'pos1': [4, 1, 5]}, + \ ], + \ getmatches() diff --git a/test/test_loclist_corrections.vader b/test/test_loclist_corrections.vader index 281f6787..8e01dfbc 100644 --- a/test/test_loclist_corrections.vader +++ b/test/test_loclist_corrections.vader @@ -128,3 +128,39 @@ Execute(FixLocList should convert line and column numbers correctly): \ {'name': 'foobar'}, \ [{'text': 'a', 'lnum': '010', 'col': '010'}], \ ) + +Execute(FixLocList should pass on col_length values): + " The numbers should be 10, not 8 as octals. + AssertEqual + \ [ + \ { + \ 'text': 'a', + \ 'lnum': 10, + \ 'col': 10, + \ 'end_col': 12, + \ 'bufnr': bufnr('%'), + \ 'vcol': 0, + \ 'type': 'E', + \ 'nr': -1, + \ 'linter_name': 'foobar', + \ }, + \ { + \ 'text': 'a', + \ 'lnum': 10, + \ 'col': 11, + \ 'end_col': 12, + \ 'bufnr': bufnr('%'), + \ 'vcol': 0, + \ 'type': 'E', + \ 'nr': -1, + \ 'linter_name': 'foobar', + \ }, + \], + \ ale#engine#FixLocList( + \ bufnr('%'), + \ {'name': 'foobar'}, + \ [ + \ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012'}, + \ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12}, + \ ], + \ ) |