summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--ale_linters/cpp/cpplint.vim15
-rw-r--r--ale_linters/javascript/eslint.vim18
-rw-r--r--autoload/ale/command.vim57
-rw-r--r--autoload/ale/engine.vim61
-rw-r--r--autoload/ale/handlers/cpplint.vim20
-rw-r--r--autoload/ale/handlers/gcc.vim9
-rw-r--r--autoload/ale/handlers/rust.vim32
-rw-r--r--autoload/ale/highlight.vim2
-rw-r--r--autoload/ale/job.vim2
-rw-r--r--autoload/ale/lsp.vim32
-rw-r--r--doc/ale-cpp.txt11
-rw-r--r--doc/ale.txt3
-rw-r--r--test/handler/test_cpplint_handler.vader27
-rw-r--r--test/handler/test_eslint_handler.vader58
-rw-r--r--test/handler/test_gcc_handler.vader26
-rw-r--r--test/handler/test_rust_handler.vader18
-rw-r--r--test/test_format_command.vader21
-rw-r--r--test/test_highlight_placement.vader13
-rw-r--r--test/test_loclist_corrections.vader36
20 files changed, 370 insertions, 93 deletions
diff --git a/README.md b/README.md
index 7a5ad732..fc3d1d35 100644
--- a/README.md
+++ b/README.md
@@ -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},
+ \ ],
+ \ )