diff options
81 files changed, 591 insertions, 46 deletions
@@ -124,7 +124,7 @@ formatting. | FusionScript | [fusion-lint](https://github.com/RyanSquared/fusionscript) | | Git Commit Messages | [gitlint](https://github.com/jorisroovers/gitlint) | | GLSL | [glslang](https://github.com/KhronosGroup/glslang), [glslls](https://github.com/svenstaro/glsl-language-server) | -| Go | [gofmt](https://golang.org/cmd/gofmt/), [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports), [go vet](https://golang.org/cmd/vet/) !!, [golint](https://godoc.org/github.com/golang/lint), [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) !!, [gometalinter](https://github.com/alecthomas/gometalinter) !!, [go build](https://golang.org/cmd/go/) !!, [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) !!, [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) !! | +| Go | [gofmt](https://golang.org/cmd/gofmt/), [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports), [go vet](https://golang.org/cmd/vet/) !!, [golint](https://godoc.org/github.com/golang/lint), [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) !!, [gometalinter](https://github.com/alecthomas/gometalinter) !!, [go build](https://golang.org/cmd/go/) !!, [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) !!, [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) !!, [golangserver](https://github.com/sourcegraph/go-langserver), [golangci-lint](https://github.com/golangci/golangci-lint) !! | | GraphQL | [eslint](http://eslint.org/), [gqlint](https://github.com/happylinks/gqlint), [prettier](https://github.com/prettier/prettier) | | Hack | [hack](http://hacklang.org/), [hackfmt](https://github.com/facebook/hhvm/tree/master/hphp/hack/hackfmt), [hhast](https://github.com/hhvm/hhast) (disabled by default; see `:help ale-integration-hack`) | | Haml | [haml-lint](https://github.com/brigade/haml-lint) | diff --git a/ale_linters/apiblueprint/drafter.vim b/ale_linters/apiblueprint/drafter.vim index 198709f9..5d40c53a 100644 --- a/ale_linters/apiblueprint/drafter.vim +++ b/ale_linters/apiblueprint/drafter.vim @@ -16,10 +16,12 @@ function! ale_linters#apiblueprint#drafter#HandleErrors(buffer, lines) abort \ 'lnum': l:match[3] + 0, \ 'col': l:match[4] + 0, \} + if l:match[5] isnot# '' let l:item.end_lnum = l:match[6] + 0 let l:item.end_col = l:match[7] + 0 endif + call add(l:output, l:item) endfor diff --git a/ale_linters/c/clangd.vim b/ale_linters/c/clangd.vim index 2c7c5c13..6cad601a 100644 --- a/ale_linters/c/clangd.vim +++ b/ale_linters/c/clangd.vim @@ -6,6 +6,7 @@ call ale#Set('c_clangd_options', '') function! ale_linters#c#clangd#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endfunction diff --git a/ale_linters/clojure/joker.vim b/ale_linters/clojure/joker.vim index 7a3330a8..2f61148b 100644 --- a/ale_linters/clojure/joker.vim +++ b/ale_linters/clojure/joker.vim @@ -9,9 +9,11 @@ function! ale_linters#clojure#joker#HandleJokerFormat(buffer, lines) abort for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:type = 'E' + if l:match[4] is? 'Parse warning' let l:type = 'W' endif + call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, diff --git a/ale_linters/cpp/clangd.vim b/ale_linters/cpp/clangd.vim index 1d716c33..9139f054 100644 --- a/ale_linters/cpp/clangd.vim +++ b/ale_linters/cpp/clangd.vim @@ -6,6 +6,7 @@ call ale#Set('cpp_clangd_options', '') function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endfunction diff --git a/ale_linters/cucumber/cucumber.vim b/ale_linters/cucumber/cucumber.vim index 6708d32f..e8ae09ff 100644 --- a/ale_linters/cucumber/cucumber.vim +++ b/ale_linters/cucumber/cucumber.vim @@ -22,6 +22,7 @@ function! ale_linters#cucumber#cucumber#Handle(buffer, lines) abort endtry let l:output = [] + for l:element in get(l:json, 'elements', []) for l:step in l:element['steps'] if l:step['result']['status'] is# 'undefined' diff --git a/ale_linters/cuda/nvcc.vim b/ale_linters/cuda/nvcc.vim index a3678910..f4442cb8 100644 --- a/ale_linters/cuda/nvcc.vim +++ b/ale_linters/cuda/nvcc.vim @@ -8,7 +8,6 @@ function! ale_linters#cuda#nvcc#GetCommand(buffer) abort " Unused: use ale#util#nul_file " let l:output_file = ale#util#Tempname() . '.ii' " call ale#engine#ManageFile(a:buffer, l:output_file) - return '%e -cuda' \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))) \ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options')) @@ -23,7 +22,6 @@ function! ale_linters#cuda#nvcc#HandleNVCCFormat(buffer, lines) abort let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) - let l:item = { \ 'lnum': str2nr(l:match[2]), \ 'type': l:match[4] =~# 'error' ? 'E' : 'W', diff --git a/ale_linters/dafny/dafny.vim b/ale_linters/dafny/dafny.vim index 8bbf1b13..b5b90675 100644 --- a/ale_linters/dafny/dafny.vim +++ b/ale_linters/dafny/dafny.vim @@ -13,6 +13,7 @@ function! ale_linters#dafny#dafny#Handle(buffer, lines) abort \ 'type': l:match[4] =~# '^Error' ? 'E' : 'W' \ }) endfor + return l:output endfunction diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim index 7772afbd..dc0f5b9e 100644 --- a/ale_linters/dockerfile/hadolint.vim +++ b/ale_linters/dockerfile/hadolint.vim @@ -82,9 +82,11 @@ endfunction function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer) + if l:command is# 'docker' return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image') endif + return 'hadolint -' endfunction diff --git a/ale_linters/elixir/mix.vim b/ale_linters/elixir/mix.vim index 1a95e37f..4552ace5 100644 --- a/ale_linters/elixir/mix.vim +++ b/ale_linters/elixir/mix.vim @@ -10,7 +10,6 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort " " 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)\) ([^:]+):([^:]+): (.+)$' let l:output = [] @@ -32,9 +31,11 @@ endfunction function! ale_linters#elixir#mix#FindProjectRoot(buffer) abort let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs') + if !empty(l:mix_file) return fnamemodify(l:mix_file, ':p:h') endif + return '.' endfunction diff --git a/ale_linters/go/gobuild.vim b/ale_linters/go/gobuild.vim index 2d6febdd..a44449f1 100644 --- a/ale_linters/go/gobuild.vim +++ b/ale_linters/go/gobuild.vim @@ -21,7 +21,6 @@ function! ale_linters#go#gobuild#GetMatches(lines) abort " file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args " file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) " file.go:5:2: expected declaration, found 'STRING' "log" - " go test returns relative paths so use tail of filename as part of pattern matcher let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? (.+)$' diff --git a/ale_linters/go/golangci_lint.vim b/ale_linters/go/golangci_lint.vim new file mode 100644 index 00000000..b44a6239 --- /dev/null +++ b/ale_linters/go/golangci_lint.vim @@ -0,0 +1,56 @@ +" Author: Sascha Grunert <mail@saschagrunert.de> +" Description: Adds support of golangci-lint + +call ale#Set('go_golangci_lint_options', '--enable-all') +call ale#Set('go_golangci_lint_executable', 'golangci-lint') +call ale#Set('go_golangci_lint_package', 0) + +function! ale_linters#go#golangci_lint#GetCommand(buffer) abort + let l:filename = expand('#' . a:buffer . ':t') + let l:options = ale#Var(a:buffer, 'go_golangci_lint_options') + let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package') + + if l:lint_package + return ale#path#BufferCdString(a:buffer) + \ . '%e run ' + \ . l:options + endif + + return ale#path#BufferCdString(a:buffer) + \ . '%e run ' + \ . ale#util#EscapePCRE(l:filename) + \ . ' ' . l:options +endfunction + +function! ale_linters#go#golangci_lint#GetMatches(lines) abort + let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:?:?:?\s\*?(.+)$' + + return ale#util#GetMatches(a:lines, l:pattern) +endfunction + +function! ale_linters#go#golangci_lint#Handler(buffer, lines) abort + let l:dir = expand('#' . a:buffer . ':p:h') + let l:output = [] + + for l:match in ale_linters#go#golangci_lint#GetMatches(a:lines) + " l:match[1] will already be an absolute path, output from + " golangci_lint + call add(l:output, { + \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), + \ 'lnum': l:match[2] + 0, + \ 'col': l:match[3] + 0, + \ 'type': 'E', + \ 'text': l:match[4], + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('go', { +\ 'name': 'golangci-lint', +\ 'executable_callback': ale#VarFunc('go_golangci_lint_executable'), +\ 'command_callback': 'ale_linters#go#golangci_lint#GetCommand', +\ 'callback': 'ale_linters#go#golangci_lint#Handler', +\ 'lint_file': 1, +\}) diff --git a/ale_linters/go/govet.vim b/ale_linters/go/govet.vim index 59fea499..84c23236 100644 --- a/ale_linters/go/govet.vim +++ b/ale_linters/go/govet.vim @@ -8,6 +8,7 @@ call ale#Set('go_govet_options', '') function! ale_linters#go#govet#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_govet_options') + return ale#path#BufferCdString(a:buffer) . ' go vet .' \ . (!empty(l:options) ? ' ' . l:options : '') endfunction diff --git a/ale_linters/go/langserver.vim b/ale_linters/go/langserver.vim new file mode 100644 index 00000000..df956483 --- /dev/null +++ b/ale_linters/go/langserver.vim @@ -0,0 +1,28 @@ +" Author: Horacio Sanson <https://github.com/hsanson> +" Description: Support for go-langserver https://github.com/sourcegraph/go-langserver + +call ale#Set('go_langserver_executable', 'go-langserver') +call ale#Set('go_langserver_options', '') + +function! ale_linters#go#langserver#GetCommand(buffer) abort + let l:executable = [ale#Escape(ale#Var(a:buffer, 'go_langserver_executable'))] + let l:options = ale#Var(a:buffer, 'go_langserver_options') + let l:options = substitute(l:options, '-gocodecompletion', '', 'g') + let l:options = filter(split(l:options, ' '), 'empty(v:val) != 1') + + if(ale#Var(a:buffer, 'completion_enabled') == 1) + call add(l:options, '-gocodecompletion') + endif + + let l:options = uniq(sort(l:options)) + + return join(extend(l:executable, l:options), ' ') +endfunction + +call ale#linter#Define('go', { +\ 'name': 'golangserver', +\ 'lsp': 'stdio', +\ 'executable_callback': ale#VarFunc('go_langserver_executable'), +\ 'command_callback': 'ale_linters#go#langserver#GetCommand', +\ 'project_root_callback': 'ale#go#FindProjectRoot', +\}) diff --git a/ale_linters/html/tidy.vim b/ale_linters/html/tidy.vim index cab8bc24..4ec29091 100644 --- a/ale_linters/html/tidy.vim +++ b/ale_linters/html/tidy.vim @@ -25,6 +25,7 @@ function! ale_linters#html#tidy#GetCommand(buffer) abort " On macOS, old tidy (released on 31 Oct 2006) is installed. It does not " consider HTML5 so we should avoid it. let l:executable = ale#Var(a:buffer, 'html_tidy_executable') + if has('mac') && l:executable is# 'tidy' && exists('*exepath') \ && exepath(l:executable) is# '/usr/bin/tidy' return '' @@ -40,7 +41,6 @@ endfunction function! ale_linters#html#tidy#Handle(buffer, lines) abort " Matches patterns lines like the following: " line 7 column 5 - Warning: missing </title> before </head> - let l:pattern = '^line \(\d\+\) column \(\d\+\) - \(Warning\|Error\): \(.\+\)$' let l:output = [] diff --git a/ale_linters/idris/idris.vim b/ale_linters/idris/idris.vim index b3275b40..feac0f10 100644 --- a/ale_linters/idris/idris.vim +++ b/ale_linters/idris/idris.vim @@ -12,7 +12,7 @@ endfunction function! ale_linters#idris#idris#Handle(buffer, lines) abort " This was copied almost verbatim from ale#handlers#haskell#HandleGHCFormat - + " " Look for lines like the following: " foo.idr:2:6:When checking right hand side of main with expected type " bar.idr:11:11-13: @@ -30,6 +30,7 @@ function! ale_linters#idris#idris#Handle(buffer, lines) abort else let l:corrected_lines[-1] .= l:line endif + let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g') endif endfor diff --git a/ale_linters/java/javac.vim b/ale_linters/java/javac.vim index 76445c18..63dcdd94 100644 --- a/ale_linters/java/javac.vim +++ b/ale_linters/java/javac.vim @@ -16,6 +16,7 @@ function! ale_linters#java#javac#GetImportPaths(buffer) abort endif let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer) + if !empty(l:classpath_command) return l:classpath_command endif @@ -90,7 +91,6 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort " " Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated " Main.java:16: error: ';' expected - let l:directory = expand('#' . a:buffer . ':p:h') let l:pattern = '\v^(.*):(\d+): (.+):(.+)$' let l:col_pattern = '\v^(\s*\^)$' diff --git a/ale_linters/java/javalsp.vim b/ale_linters/java/javalsp.vim index f335e83c..5d1a0c63 100644 --- a/ale_linters/java/javalsp.vim +++ b/ale_linters/java/javalsp.vim @@ -9,6 +9,7 @@ endfunction function! ale_linters#java#javalsp#Command(buffer) abort let l:jar = ale#Var(a:buffer, 'java_javalsp_jar') + return ale#Escape('java -cp ' . l:jar . ' -Xverify:none org.javacs.Main') endfunction diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim index d555184e..cdb289c7 100755 --- a/ale_linters/javascript/flow.vim +++ b/ale_linters/javascript/flow.vim @@ -91,7 +91,6 @@ function! s:GetDetails(error) abort let l:detail = '' for l:extra_error in a:error.extra - if has_key(l:extra_error, 'message') for l:extra_message in l:extra_error.message let l:detail = s:ExtraErrorMsg(l:detail, l:extra_message.descr) @@ -105,7 +104,6 @@ function! s:GetDetails(error) abort endfor endfor endif - endfor return l:detail @@ -161,7 +159,6 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort endif call add(l:output, l:errorToAdd) - endfor return l:output diff --git a/ale_linters/json/jsonlint.vim b/ale_linters/json/jsonlint.vim index 75f47088..f01553d6 100644 --- a/ale_linters/json/jsonlint.vim +++ b/ale_linters/json/jsonlint.vim @@ -3,7 +3,6 @@ function! ale_linters#json#jsonlint#Handle(buffer, lines) abort " Matches patterns like the following: " line 2, col 15, found: 'STRING' - expected: 'EOF', '}', ',', ']'. - let l:pattern = '^line \(\d\+\), col \(\d*\), \(.\+\)$' let l:output = [] diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim index 00f94be5..4a993986 100644 --- a/ale_linters/kotlin/kotlinc.vim +++ b/ale_linters/kotlin/kotlinc.vim @@ -17,12 +17,14 @@ function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort return '' else let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') + if !empty(l:pom_path) && executable('mvn') return ale#path#CdString(fnamemodify(l:pom_path, ':h')) \ . 'mvn dependency:build-classpath' endif let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer) + if !empty(l:classpath_command) return l:classpath_command endif @@ -78,12 +80,13 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort endif let l:fname = '' + if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') isnot# '' let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' ' else " Find the src directory for files in this project. - let l:project_root = ale#gradle#FindProjectRoot(a:buffer) + if !empty(l:project_root) let l:src_dir = l:project_root else @@ -93,6 +96,7 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort let l:fname .= expand(l:src_dir, 1) . ' ' endif + let l:fname .= ale#Escape(expand('#' . a:buffer . ':p')) let l:command .= l:kotlinc_opts . ' ' . l:fname @@ -124,6 +128,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort if l:buf_abspath isnot# l:curbuf_abspath continue endif + let l:type_marker_str = l:type is# 'warning' ? 'W' : 'E' call add(l:output, { diff --git a/ale_linters/make/checkmake.vim b/ale_linters/make/checkmake.vim index 63c35db3..5ebdf91e 100644 --- a/ale_linters/make/checkmake.vim +++ b/ale_linters/make/checkmake.vim @@ -13,6 +13,7 @@ function! ale_linters#make#checkmake#Handle(buffer, lines) abort \ 'text': l:match[3], \}) endfor + return l:output endfunction diff --git a/ale_linters/markdown/remark_lint.vim b/ale_linters/markdown/remark_lint.vim index 88dfb9dd..4f8d48fa 100644 --- a/ale_linters/markdown/remark_lint.vim +++ b/ale_linters/markdown/remark_lint.vim @@ -24,10 +24,12 @@ function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort \ 'type': l:match[6] is# 'error' ? 'E' : 'W', \ 'text': l:match[7], \} + if l:match[3] isnot# '' let l:item.end_lnum = l:match[4] + 0 let l:item.end_col = l:match[5] + 0 endif + call add(l:output, l:item) endfor diff --git a/ale_linters/objc/clangd.vim b/ale_linters/objc/clangd.vim index 161d2cc7..f090e6ce 100644 --- a/ale_linters/objc/clangd.vim +++ b/ale_linters/objc/clangd.vim @@ -6,6 +6,7 @@ call ale#Set('objc_clangd_options', '') function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endfunction diff --git a/ale_linters/objcpp/clangd.vim b/ale_linters/objcpp/clangd.vim index 7e06796f..a09753be 100644 --- a/ale_linters/objcpp/clangd.vim +++ b/ale_linters/objcpp/clangd.vim @@ -6,6 +6,7 @@ call ale#Set('objcpp_clangd_options', '') function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endfunction diff --git a/ale_linters/perl/perl.vim b/ale_linters/perl/perl.vim index d1dcbc9c..1cb20fa7 100644 --- a/ale_linters/perl/perl.vim +++ b/ale_linters/perl/perl.vim @@ -14,11 +14,16 @@ let s:begin_failed_skip_pattern = '\v' . join([ \], '|') function! ale_linters#perl#perl#Handle(buffer, lines) abort + if empty(a:lines) + return [] + endif + let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)' let l:output = [] let l:basename = expand('#' . a:buffer . ':t') let l:type = 'E' + if a:lines[-1] =~# 'syntax OK' let l:type = 'W' endif diff --git a/ale_linters/puppet/languageserver.vim b/ale_linters/puppet/languageserver.vim index a08b7653..a3060e65 100644 --- a/ale_linters/puppet/languageserver.vim +++ b/ale_linters/puppet/languageserver.vim @@ -8,6 +8,7 @@ function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort " there's no requirement to have it, so fall back to the other possible " Puppet module directories let l:root_path = ale#path#FindNearestFile(a:buffer, 'metadata.json') + if !empty(l:root_path) return fnamemodify(l:root_path, ':h') endif @@ -17,6 +18,7 @@ function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort \ 'templates', \] let l:root_path = ale#path#FindNearestDirectory(a:buffer, l:test_path) + if !empty(l:root_path) return fnamemodify(l:root_path, ':h:h') endif diff --git a/ale_linters/puppet/puppet.vim b/ale_linters/puppet/puppet.vim index d44bb517..0e37bdbd 100644 --- a/ale_linters/puppet/puppet.vim +++ b/ale_linters/puppet/puppet.vim @@ -8,7 +8,6 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort " Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12 " Error: Could not parse for environment production: Syntax error at '='; expected '}' at /root/puppetcode/modules/pancakes/manifests/init.pp:5" " Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 4, column: 5) - let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)' let l:output = [] diff --git a/ale_linters/rst/rstcheck.vim b/ale_linters/rst/rstcheck.vim index b660627f..8504738b 100644 --- a/ale_linters/rst/rstcheck.vim +++ b/ale_linters/rst/rstcheck.vim @@ -8,6 +8,7 @@ function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort let l:pattern = '\v^(.+):(\d*): \(([a-zA-Z]*)/\d*\) (.+)$' let l:dir = expand('#' . a:buffer . ':p:h') let l:output = [] + for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), diff --git a/ale_linters/ruby/solargraph.vim b/ale_linters/ruby/solargraph.vim index a53bcaa3..2aad3af6 100644 --- a/ale_linters/ruby/solargraph.vim +++ b/ale_linters/ruby/solargraph.vim @@ -7,6 +7,7 @@ call ale#Set('ruby_solargraph_port', '7658') function! ale_linters#ruby#solargraph#GetAddress(buffer) abort let l:host = ale#Var(a:buffer, 'ruby_solargraph_host') let l:port = ale#Var(a:buffer, 'ruby_solargraph_port') + return l:host . ':' . l:port endfunction diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim index e6c3870a..5aefe72c 100644 --- a/ale_linters/rust/cargo.vim +++ b/ale_linters/rust/cargo.vim @@ -42,6 +42,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort \ && ale#semver#GTE(l:version, [0, 22, 0]) let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') + if !empty(l:include_features) let l:include_features = ' --features ' . ale#Escape(l:include_features) endif @@ -59,6 +60,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort endif let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior') + if l:default_feature_behavior is# 'all' let l:include_features = '' let l:default_feature = ' --all-features' diff --git a/ale_linters/scala/sbtserver.vim b/ale_linters/scala/sbtserver.vim index d75c38ca..694241d7 100644 --- a/ale_linters/scala/sbtserver.vim +++ b/ale_linters/scala/sbtserver.vim @@ -6,15 +6,19 @@ call ale#Set('scala_sbtserver_project_root', '') function! ale_linters#scala#sbtserver#GetProjectRoot(buffer) abort let l:project_root = ale#Var(a:buffer, 'scala_sbtserver_project_root') + if l:project_root is? '' let l:project_root = ale#path#FindNearestFile(a:buffer, 'build.sbt') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endif + return l:project_root endfunction function! ale_linters#scala#sbtserver#GetAddress(buffer) abort let l:address = ale#Var(a:buffer, 'scala_sbtserver_address') + return l:address endfunction diff --git a/ale_linters/scala/scalastyle.vim b/ale_linters/scala/scalastyle.vim index 3232d70b..42228cf6 100644 --- a/ale_linters/scala/scalastyle.vim +++ b/ale_linters/scala/scalastyle.vim @@ -53,12 +53,14 @@ function! ale_linters#scala#scalastyle#GetCommand(buffer) abort \ 'scalastyle_config.xml', \ 'scalastyle-config.xml' \] + for l:config in l:potential_configs let l:scalastyle_config = ale#path#ResolveLocalPath( \ a:buffer, \ l:config, \ '' \) + if !empty(l:scalastyle_config) break endif diff --git a/ale_linters/sml/smlnj_cm.vim b/ale_linters/sml/smlnj_cm.vim index 7a482307..bfa4bc05 100644 --- a/ale_linters/sml/smlnj_cm.vim +++ b/ale_linters/sml/smlnj_cm.vim @@ -3,6 +3,7 @@ function! ale_linters#sml#smlnj_cm#GetCommand(buffer) abort let l:cmfile = ale#handlers#sml#GetCmFile(a:buffer) + return 'sml -m ' . l:cmfile . ' < /dev/null' endfunction diff --git a/ale_linters/solidity/solhint.vim b/ale_linters/solidity/solhint.vim index 519fd49d..8ea33e07 100644 --- a/ale_linters/solidity/solhint.vim +++ b/ale_linters/solidity/solhint.vim @@ -4,7 +4,6 @@ function! ale_linters#solidity#solhint#Handle(buffer, lines) abort " Matches patterns like the following: " /path/to/file/file.sol: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars) - let l:pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (.*) \((.*)\)$' let l:output = [] diff --git a/ale_linters/tcl/nagelfar.vim b/ale_linters/tcl/nagelfar.vim index 183ea9e7..05fe581b 100644 --- a/ale_linters/tcl/nagelfar.vim +++ b/ale_linters/tcl/nagelfar.vim @@ -15,7 +15,6 @@ function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort " Line 5: W Found constant "bepa" which is also a variable. " Line 13: E Wrong number of arguments (3) to "set" " Line 93: N Close brace not aligned with line 90 (4 0) - let l:pattern = '^Line\s\+\([0-9]\+\): \([NEW]\) \(.*\)$' let l:output = [] diff --git a/ale_linters/terraform/tflint.vim b/ale_linters/terraform/tflint.vim index b8e9c96d..0d77835a 100644 --- a/ale_linters/terraform/tflint.vim +++ b/ale_linters/terraform/tflint.vim @@ -40,6 +40,7 @@ function! ale_linters#terraform#tflint#GetCommand(buffer) abort endif let l:opts = ale#Var(a:buffer, 'terraform_tflint_options') + if !empty(l:opts) let l:cmd .= ' ' . l:opts endif diff --git a/ale_linters/tex/lacheck.vim b/ale_linters/tex/lacheck.vim index 38135b85..5e5a94f1 100644 --- a/ale_linters/tex/lacheck.vim +++ b/ale_linters/tex/lacheck.vim @@ -8,7 +8,6 @@ function! ale_linters#tex#lacheck#Handle(buffer, lines) abort " " "book.tex", line 37: possible unwanted space at "{" " "book.tex", line 38: missing `\ ' after "etc." - let l:pattern = '^".\+", line \(\d\+\): \(.\+\)$' let l:output = [] diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim index ac1f69fc..396a2355 100644 --- a/ale_linters/thrift/thrift.vim +++ b/ale_linters/thrift/thrift.vim @@ -42,12 +42,14 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort let l:line = a:lines[l:index] let l:match = matchlist(l:line, l:pattern) + if empty(l:match) let l:index += 1 continue endif let l:severity = l:match[1] + if l:severity is# 'WARNING' let l:type = 'W' else @@ -57,6 +59,7 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort " If our text looks like "(last token was ';')", the *next* line " should contain a more descriptive error message. let l:text = l:match[4] + if l:text =~# '\(last token was .*\)' let l:index += 1 let l:text = get(a:lines, l:index, 'Unknown error ' . l:text) diff --git a/ale_linters/vim/ale_custom_linting_rules.vim b/ale_linters/vim/ale_custom_linting_rules.vim index f4e111ee..3da44206 100644 --- a/ale_linters/vim/ale_custom_linting_rules.vim +++ b/ale_linters/vim/ale_custom_linting_rules.vim @@ -25,7 +25,13 @@ endfunction function! ale_linters#vim#ale_custom_linting_rules#GetCommand(buffer) abort let l:dir = s:GetALEProjectDir(a:buffer) - return ale#path#CdString(l:dir) . '%e .' + let l:temp_dir = ale#engine#CreateDirectory(a:buffer) + let l:temp_file = l:temp_dir . '/example.vim' + + let l:lines = getbufline(a:buffer, 1, '$') + call ale#util#Writefile(a:buffer, l:lines, l:temp_file) + + return ale#path#CdString(l:dir) . '%e ' . ale#Escape(l:temp_dir) endfunction function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort @@ -34,15 +40,17 @@ function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+) (.+)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) - let l:filename = ale#path#GetAbsPath(l:dir, l:match[1]) - - if bufnr(l:filename) is a:buffer - call add(l:output, { - \ 'lnum': l:match[2], - \ 'text': l:match[3], - \ 'type': 'W', - \}) + " Ignore trailing whitespace errors if we've turned them off. + if !ale#Var(a:buffer, 'warn_about_trailing_whitespace') + \&& l:match[3] is# 'Trailing whitespace' + continue endif + + call add(l:output, { + \ 'lnum': l:match[2], + \ 'text': l:match[3], + \ 'type': 'W', + \}) endfor return l:output @@ -53,5 +61,5 @@ call ale#linter#Define('vim', { \ 'executable_callback': 'ale_linters#vim#ale_custom_linting_rules#GetExecutable', \ 'command_callback': 'ale_linters#vim#ale_custom_linting_rules#GetCommand', \ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle', -\ 'lint_file': 1, +\ 'read_buffer': 0, \}) diff --git a/ale_linters/xml/xmllint.vim b/ale_linters/xml/xmllint.vim index a0f97c3a..59f43d16 100644 --- a/ale_linters/xml/xmllint.vim +++ b/ale_linters/xml/xmllint.vim @@ -25,9 +25,9 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort let l:output = [] for l:line in a:lines - " Parse error/warning lines let l:match_message = matchlist(l:line, l:pattern_message) + if !empty(l:match_message) let l:line = l:match_message[2] + 0 let l:type = l:match_message[4] =~? 'warning' ? 'W' : 'E' @@ -44,13 +44,13 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort " Parse column position let l:match_column_token = matchlist(l:line, l:pattern_column_token) + if !empty(l:output) && !empty(l:match_column_token) let l:previous = l:output[len(l:output) - 1] let l:previous['col'] = len(l:match_column_token[0]) continue endif - endfor return l:output diff --git a/ale_linters/yang/yang_lsp.vim b/ale_linters/yang/yang_lsp.vim index a60e9113..45776f98 100644 --- a/ale_linters/yang/yang_lsp.vim +++ b/ale_linters/yang/yang_lsp.vim @@ -2,6 +2,7 @@ call ale#Set('yang_lsp_executable', 'yang-language-server') function! ale_linters#yang#yang_lsp#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, 'yang.settings') + return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' endfunction diff --git a/autoload/ale.vim b/autoload/ale.vim index 3747539b..41d78753 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -27,7 +27,7 @@ let s:getcmdwintype_exists = exists('*getcmdwintype') function! ale#ShouldDoNothing(buffer) abort " The checks are split into separate if statements to make it possible to " profile each check individually with Vim's profiling tools. - + " " Do nothing if ALE is disabled. if !getbufvar(a:buffer, 'ale_enabled', get(g:, 'ale_enabled', 0)) return 1 diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim index 5ec62011..e7b43d88 100644 --- a/autoload/ale/c.vim +++ b/autoload/ale/c.vim @@ -54,6 +54,7 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort call add(l:previous_options, l:option) " Check if cflag contained a '-' and should not have been splitted let l:option_list = split(l:option, '\zs') + if l:option_list[-1] isnot# ' ' continue endif diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index abe0f56e..c1736678 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -75,6 +75,7 @@ endfunction " Check if we should look for completions for a language. function! ale#completion#GetPrefix(filetype, line, column) abort let l:regex = s:GetFiletypeValue(s:should_complete_map, a:filetype) + " The column we're using completions for is where we are inserting text, " like so: " abc diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index fdf883f5..b6c2d3c9 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -231,6 +231,7 @@ function! s:HandleExit(job_id, exit_code) abort if l:next_chain_index < len(get(l:linter, 'command_chain', [])) call s:InvokeChain(l:buffer, l:executable, l:linter, l:next_chain_index, l:output) + return endif @@ -595,9 +596,8 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort \) endif + " If we have a command to run, execute that. if !empty(l:command) - " We hit a command to run, so we'll execute that - " The chain item can override the output_stream option. if has_key(l:chain_item, 'output_stream') let l:output_stream = l:chain_item.output_stream diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index 4d82b367..1ae1a4a1 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -71,6 +71,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort if l:data.lines_before != l:lines call remove(g:ale_fix_buffer_data, a:buffer) execute 'echoerr ''The file was changed before fixing finished''' + return endif endif diff --git a/autoload/ale/fixers/fixjson.vim b/autoload/ale/fixers/fixjson.vim index 64c6ba81..33ce0af3 100644 --- a/autoload/ale/fixers/fixjson.vim +++ b/autoload/ale/fixers/fixjson.vim @@ -17,6 +17,7 @@ function! ale#fixers#fixjson#Fix(buffer) abort let l:command = l:executable . ' --stdin-filename ' . l:filename let l:options = ale#Var(a:buffer, 'json_fixjson_options') + if l:options isnot# '' let l:command .= ' ' . l:options endif diff --git a/autoload/ale/fixers/importjs.vim b/autoload/ale/fixers/importjs.vim index 50d3d74e..b5487b2c 100644 --- a/autoload/ale/fixers/importjs.vim +++ b/autoload/ale/fixers/importjs.vim @@ -5,6 +5,7 @@ call ale#Set('javascript_importjs_executable', 'importjs') function! ale#fixers#importjs#ProcessOutput(buffer, output) abort let l:result = ale#util#FuzzyJSONDecode(a:output, []) + return split(get(l:result, 'fileContent', ''), "\n") endfunction diff --git a/autoload/ale/fixers/php_cs_fixer.vim b/autoload/ale/fixers/php_cs_fixer.vim index 26b8e5de..5c59e262 100644 --- a/autoload/ale/fixers/php_cs_fixer.vim +++ b/autoload/ale/fixers/php_cs_fixer.vim @@ -14,6 +14,7 @@ endfunction function! ale#fixers#php_cs_fixer#Fix(buffer) abort let l:executable = ale#fixers#php_cs_fixer#GetExecutable(a:buffer) + return { \ 'command': ale#Escape(l:executable) \ . ' ' . ale#Var(a:buffer, 'php_cs_fixer_options') diff --git a/autoload/ale/fixers/phpcbf.vim b/autoload/ale/fixers/phpcbf.vim index 487f369a..f14b8406 100644 --- a/autoload/ale/fixers/phpcbf.vim +++ b/autoload/ale/fixers/phpcbf.vim @@ -18,6 +18,7 @@ function! ale#fixers#phpcbf#Fix(buffer) abort let l:standard_option = !empty(l:standard) \ ? '--standard=' . l:standard \ : '' + return { \ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ' -' \} diff --git a/autoload/ale/fixers/puppetlint.vim b/autoload/ale/fixers/puppetlint.vim index 81f34e89..bf36e486 100644 --- a/autoload/ale/fixers/puppetlint.vim +++ b/autoload/ale/fixers/puppetlint.vim @@ -4,6 +4,7 @@ if !exists('g:ale_puppet_puppetlint_executable') let g:ale_puppet_puppetlint_executable = 'puppet-lint' endif + if !exists('g:ale_puppet_puppetlint_options') let g:ale_puppet_puppetlint_options = '' endif diff --git a/autoload/ale/fixers/rubocop.vim b/autoload/ale/fixers/rubocop.vim index 35569b19..0a39ef62 100644 --- a/autoload/ale/fixers/rubocop.vim +++ b/autoload/ale/fixers/rubocop.vim @@ -10,7 +10,6 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' --auto-correct %t' - endfunction function! ale#fixers#rubocop#Fix(buffer) abort diff --git a/autoload/ale/fixers/scalafmt.vim b/autoload/ale/fixers/scalafmt.vim index 07d28275..dd0e7745 100644 --- a/autoload/ale/fixers/scalafmt.vim +++ b/autoload/ale/fixers/scalafmt.vim @@ -15,7 +15,6 @@ function! ale#fixers#scalafmt#GetCommand(buffer) abort return ale#Escape(l:executable) . l:exec_args \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t' - endfunction function! ale#fixers#scalafmt#Fix(buffer) abort diff --git a/autoload/ale/fixers/shfmt.vim b/autoload/ale/fixers/shfmt.vim index 882cf3a4..fc55f425 100644 --- a/autoload/ale/fixers/shfmt.vim +++ b/autoload/ale/fixers/shfmt.vim @@ -13,5 +13,4 @@ function! ale#fixers#shfmt#Fix(buffer) abort \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \} - endfunction diff --git a/autoload/ale/fixers/xmllint.vim b/autoload/ale/fixers/xmllint.vim index 9beaa48c..b14ffd36 100644 --- a/autoload/ale/fixers/xmllint.vim +++ b/autoload/ale/fixers/xmllint.vim @@ -11,12 +11,14 @@ function! ale#fixers#xmllint#Fix(buffer) abort let l:command = l:executable . ' --format ' . l:filename let l:indent = ale#Var(a:buffer, 'xml_xmllint_indentsize') + if l:indent isnot# '' let l:env = ale#Env('XMLLINT_INDENT', repeat(' ', l:indent)) let l:command = l:env . l:command endif let l:options = ale#Var(a:buffer, 'xml_xmllint_options') + if l:options isnot# '' let l:command .= ' ' . l:options endif diff --git a/autoload/ale/go.vim b/autoload/ale/go.vim new file mode 100644 index 00000000..a166480a --- /dev/null +++ b/autoload/ale/go.vim @@ -0,0 +1,27 @@ +" Author: Horacio Sanson https://github.com/hsanson +" Description: Functions for integrating with Go tools + +" Find the nearest dir listed in GOPATH and assume it the root of the go +" project. +function! ale#go#FindProjectRoot(buffer) abort + let l:sep = has('win32') ? ';' : ':' + + let l:filename = ale#path#Simplify(expand('#' . a:buffer . ':p')) + + for l:name in split($GOPATH, l:sep) + let l:path_dir = ale#path#Simplify(l:name) + + " Use the directory from GOPATH if the current filename starts with it. + if l:filename[: len(l:path_dir) - 1] is? l:path_dir + return l:path_dir + endif + endfor + + let l:default_go_path = ale#path#Simplify(expand('~/go')) + + if isdirectory(l:default_go_path) + return l:default_go_path + endif + + return '' +endfunction diff --git a/autoload/ale/handlers/gawk.vim b/autoload/ale/handlers/gawk.vim index 942bc2b2..50bc4c45 100644 --- a/autoload/ale/handlers/gawk.vim +++ b/autoload/ale/handlers/gawk.vim @@ -9,9 +9,11 @@ function! ale#handlers#gawk#HandleGawkFormat(buffer, lines) abort for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:ecode = 'E' + if l:match[2] is? 'warning:' let l:ecode = 'W' endif + call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': 0, diff --git a/autoload/ale/handlers/go.vim b/autoload/ale/handlers/go.vim index 224df664..f17cd862 100644 --- a/autoload/ale/handlers/go.vim +++ b/autoload/ale/handlers/go.vim @@ -21,5 +21,6 @@ function! ale#handlers#go#Handler(buffer, lines) abort \ 'type': 'E', \}) endfor + return l:output endfunction diff --git a/autoload/ale/handlers/ols.vim b/autoload/ale/handlers/ols.vim index 1dda7f92..74130a26 100644 --- a/autoload/ale/handlers/ols.vim +++ b/autoload/ale/handlers/ols.vim @@ -3,6 +3,7 @@ function! ale#handlers#ols#GetExecutable(buffer) abort let l:ols_setting = ale#handlers#ols#GetLanguage(a:buffer) . '_ols' + return ale#node#FindExecutable(a:buffer, l:ols_setting, [ \ 'node_modules/.bin/ocaml-language-server', \]) diff --git a/autoload/ale/handlers/pony.vim b/autoload/ale/handlers/pony.vim index 0ac18e76..ea84ac4b 100644 --- a/autoload/ale/handlers/pony.vim +++ b/autoload/ale/handlers/pony.vim @@ -14,7 +14,6 @@ endfunction function! ale#handlers#pony#HandlePonycFormat(buffer, lines) abort " Look for lines like the following. " /home/code/pony/classes/Wombat.pony:22:30: can't lookup private fields from outside the type - let l:pattern = '\v^([^:]+):(\d+):(\d+)?:? (.+)$' let l:output = [] diff --git a/autoload/ale/handlers/redpen.vim b/autoload/ale/handlers/redpen.vim index c136789c..84e331ed 100644 --- a/autoload/ale/handlers/redpen.vim +++ b/autoload/ale/handlers/redpen.vim @@ -6,15 +6,18 @@ function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort " element. let l:res = json_decode(join(a:lines))[0] let l:output = [] + for l:err in l:res.errors let l:item = { \ 'text': l:err.message, \ 'type': 'W', \ 'code': l:err.validator, \} + if has_key(l:err, 'startPosition') let l:item.lnum = l:err.startPosition.lineNum let l:item.col = l:err.startPosition.offset + 1 + if has_key(l:err, 'endPosition') let l:item.end_lnum = l:err.endPosition.lineNum let l:item.end_col = l:err.endPosition.offset @@ -28,29 +31,35 @@ function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort " Adjust column number for multibyte string let l:line = getline(l:item.lnum) + if l:line is# '' let l:line = l:err.sentence endif + let l:line = split(l:line, '\zs') if l:item.col >= 2 let l:col = 0 + for l:strlen in map(l:line[0:(l:item.col - 2)], 'strlen(v:val)') let l:col = l:col + l:strlen endfor + let l:item.col = l:col + 1 endif if has_key(l:item, 'end_col') let l:col = 0 + for l:strlen in map(l:line[0:(l:item.end_col - 1)], 'strlen(v:val)') let l:col = l:col + l:strlen endfor + let l:item.end_col = l:col endif call add(l:output, l:item) endfor + return l:output endfunction - diff --git a/autoload/ale/handlers/ruby.vim b/autoload/ale/handlers/ruby.vim index 555c13b1..110fe156 100644 --- a/autoload/ale/handlers/ruby.vim +++ b/autoload/ale/handlers/ruby.vim @@ -13,8 +13,10 @@ function! s:HandleSyntaxError(buffer, lines) abort for l:line in a:lines let l:match = matchlist(l:line, l:pattern) + if len(l:match) == 0 let l:match = matchlist(l:line, l:column) + if len(l:match) != 0 let l:output[len(l:output) - 1]['col'] = len(l:match[1]) endif diff --git a/autoload/ale/handlers/sml.vim b/autoload/ale/handlers/sml.vim index 377eade5..92c5f83b 100644 --- a/autoload/ale/handlers/sml.vim +++ b/autoload/ale/handlers/sml.vim @@ -11,8 +11,10 @@ function! ale#handlers#sml#GetCmFile(buffer) abort let l:as_list = 1 let l:cmfile = '' + for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) let l:results = glob(l:path . '/' . l:pattern, 0, l:as_list) + if len(l:results) > 0 " If there is more than one CM file, we take the first one " See :help ale-sml-smlnj for how to configure this. @@ -46,6 +48,7 @@ endfunction function! ale#handlers#sml#GetExecutableSmlnjCm(buffer) abort return s:GetExecutable(a:buffer, 'smlnj-cm') endfunction + function! ale#handlers#sml#GetExecutableSmlnjFile(buffer) abort return s:GetExecutable(a:buffer, 'smlnj-file') endfunction @@ -53,7 +56,6 @@ endfunction function! ale#handlers#sml#Handle(buffer, lines) abort " Try to match basic sml errors " TODO(jez) We can get better errorfmt strings from Syntastic - let l:out = [] let l:pattern = '^.*\:\([0-9\.]\+\)\ \(\w\+\)\:\ \(.*\)' let l:pattern2 = '^.*\:\([0-9]\+\)\.\?\([0-9]\+\).* \(\(Warning\|Error\): .*\)' @@ -83,7 +85,6 @@ function! ale#handlers#sml#Handle(buffer, lines) abort \}) continue endif - endfor return l:out diff --git a/autoload/ale/handlers/vale.vim b/autoload/ale/handlers/vale.vim index 9dc0872f..2da72fc7 100644 --- a/autoload/ale/handlers/vale.vim +++ b/autoload/ale/handlers/vale.vim @@ -23,6 +23,7 @@ function! ale#handlers#vale#Handle(buffer, lines) abort endif let l:output = [] + for l:error in l:errors[keys(l:errors)[0]] call add(l:output, { \ 'lnum': l:error['Line'], diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim index e0266cba..0117c7dd 100644 --- a/autoload/ale/job.vim +++ b/autoload/ale/job.vim @@ -249,6 +249,11 @@ function! ale#job#Start(command, options) abort let l:job_options.exit_cb = function('s:VimExitCallback') endif + " Use non-blocking writes for Vim versions that support the option. + if has('patch-8.1.350') + let l:job_options.noblock = 1 + endif + " Vim 8 will read the stdin from the file's buffer. let l:job_info.job = job_start(a:command, l:job_options) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job_info.job)) @@ -278,11 +283,13 @@ function! ale#job#IsRunning(job_id) abort try " In NeoVim, if the job isn't running, jobpid() will throw. call jobpid(a:job_id) + return 1 catch endtry elseif has_key(s:job_map, a:job_id) let l:job = s:job_map[a:job_id].job + return job_status(l:job) is# 'run' endif diff --git a/autoload/ale/list.vim b/autoload/ale/list.vim index 35304a09..3417575c 100644 --- a/autoload/ale/list.vim +++ b/autoload/ale/list.vim @@ -25,6 +25,7 @@ function! ale#list#IsQuickfixOpen() abort return 1 endif endfor + return 0 endfunction @@ -112,9 +113,11 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort " open windows vertically instead of default horizontally let l:open_type = '' + if ale#Var(a:buffer, 'list_vertical') == 1 let l:open_type = 'vert ' endif + if g:ale_set_quickfix if !ale#list#IsQuickfixOpen() silent! execute l:open_type . 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim index dae45e70..196cbe80 100644 --- a/autoload/ale/lsp.vim +++ b/autoload/ale/lsp.vim @@ -99,6 +99,7 @@ function! s:CreateTSServerMessageData(message) abort endif let l:data = json_encode(l:obj) . "\n" + return [l:is_notification ? 0 : l:obj.seq, l:data] endfunction diff --git a/autoload/ale/socket.vim b/autoload/ale/socket.vim index 0ca4dea6..7e069fb5 100644 --- a/autoload/ale/socket.vim +++ b/autoload/ale/socket.vim @@ -55,11 +55,18 @@ function! ale#socket#Open(address, options) abort if !has('nvim') " Vim - let l:channel_info.channel = ch_open(a:address, { + let l:channel_options = { \ 'mode': l:mode, \ 'waittime': 0, \ 'callback': function('s:VimOutputCallback'), - \}) + \} + + " Use non-blocking writes for Vim versions that support the option. + if has('patch-8.1.350') + let l:channel_options.noblock = 1 + endif + + let l:channel_info.channel = ch_open(a:address, l:channel_options) let l:vim_info = ch_info(l:channel_info.channel) let l:channel_id = !empty(l:vim_info) ? l:vim_info.id : -1 elseif exists('*chansend') && exists('*sockconnect') @@ -104,6 +111,7 @@ function! ale#socket#IsOpen(channel_id) abort endif let l:channel = s:channel_map[a:channel_id].channel + return ch_status(l:channel) is# 'open' endfunction diff --git a/autoload/ale/toggle.vim b/autoload/ale/toggle.vim index da108782..1d052b4f 100644 --- a/autoload/ale/toggle.vim +++ b/autoload/ale/toggle.vim @@ -76,6 +76,7 @@ function! ale#toggle#ToggleBuffer(buffer) abort " linting locally when linting is disabled globally if l:enabled && !g:ale_enabled execute 'echom ''ALE cannot be enabled locally when disabled globally''' + return endif diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index 8c69c54f..58a2065e 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -54,6 +54,7 @@ endif function! ale#util#JoinNeovimOutput(job, last_line, data, mode, callback) abort if a:mode is# 'raw' call a:callback(a:job, join(a:data, "\n")) + return '' endif diff --git a/doc/ale-go.txt b/doc/ale-go.txt index baf403b7..1d55763e 100644 --- a/doc/ale-go.txt +++ b/doc/ale-go.txt @@ -7,7 +7,7 @@ Integration Information The `gometalinter` linter is disabled by default. ALE enables `gofmt`, `golint` and `go vet` by default. It also supports `staticcheck`, `go -build` and `gosimple`. +build`, `gosimple`, and `golangserver`. To enable `gometalinter`, update |g:ale_linters| as appropriate: > @@ -115,4 +115,57 @@ g:ale_go_staticcheck_lint_package *g:ale_go_staticcheck_lint_package* =============================================================================== +golangserver *ale-go-golangserver* + +g:ale_go_langserver_executable *g:ale_go_langserver_executable* + *b:ale_go_langserver_executable* + Type: |String| + Default: `'go-langserver'` + + Location of the go-langserver binary file. + +g:ale_go_langserver_options *g:ale_go_langserver_options* + *b:ale_go_langserver_options* + Type: |String| + Default: `''` + + Additional options passed to the go-langserver command. Note that the + `-gocodecompletion` option is ignored because it is handled automatically + by the |g:ale_completion_enabled| variable. + + +=============================================================================== +golangci-lint *ale-go-golangci-lint* + +`golangci-lint` is a `lint_file` linter, which only lints files that are +written to disk. This differs from the default behavior of linting the buffer. +See: |ale-lint-file| + +g:ale_go_golangci_lint_executable *g:ale_go_golangci_lint_executable* + *b:ale_go_golangci_lint_executable* + Type: |String| + Default: `'golangci-lint'` + + The executable that will be run for golangci-lint. + + +g:ale_go_golangci_lint_options *g:ale_go_golangci_lint_options* + *b:ale_go_golangci_lint_options* + Type: |String| + Default: `'--enable-all'` + + This variable can be changed to alter the command-line arguments to the + golangci-lint invocation. + + +g:ale_go_golangci_lint_package *g:ale_go_golangci_lint_package* + *b:ale_go_golangci_lint_package* + Type: |Number| + Default: `0` + + When set to `1`, the whole Go package will be checked instead of only the + current file. + + +=============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale.txt b/doc/ale.txt index 4334510f..e08946e5 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -95,6 +95,8 @@ CONTENTS *ale-contents* govet...............................|ale-go-govet| gometalinter........................|ale-go-gometalinter| staticcheck.........................|ale-go-staticcheck| + golangserver........................|ale-go-golangserver| + golangci-lint.......................|ale-go-golangci-lint| graphql...............................|ale-graphql-options| eslint..............................|ale-graphql-eslint| gqlint..............................|ale-graphql-gqlint| @@ -384,7 +386,7 @@ Notes: * FusionScript: `fusion-lint` * Git Commit Messages: `gitlint` * GLSL: glslang, `glslls` -* Go: `gofmt`, `goimports`, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!! +* Go: `gofmt`, `goimports`, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!!, `golangserver`, `golangci-lint`!! * GraphQL: `eslint`, `gqlint`, `prettier` * Hack: `hack`, `hackfmt`, `hhast` * Haml: `haml-lint` diff --git a/test/command_callback/go_paths/go1/prj1/file.go b/test/command_callback/go_paths/go1/prj1/file.go new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/go_paths/go1/prj1/file.go diff --git a/test/command_callback/go_paths/go2/prj2/file.go b/test/command_callback/go_paths/go2/prj2/file.go new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/go_paths/go2/prj2/file.go diff --git a/test/command_callback/test_golangci_lint_command_callback.vader b/test/command_callback/test_golangci_lint_command_callback.vader new file mode 100644 index 00000000..6cb73246 --- /dev/null +++ b/test/command_callback/test_golangci_lint_command_callback.vader @@ -0,0 +1,38 @@ +Before: + call ale#assert#SetUpLinterTest('go', 'golangci_lint') + call ale#test#SetFilename('test.go') + +After: + call ale#assert#TearDownLinterTest() + +Execute(The golangci-lint defaults should be correct): + AssertLinter 'golangci-lint', + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('golangci-lint') + \ . ' run ' . ale#util#EscapePCRE(expand('%' . ':t')) + \ . ' --enable-all' + +Execute(The golangci-lint callback should use a configured executable): + let b:ale_go_golangci_lint_executable = 'something else' + + AssertLinter 'something else', + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('something else') + \ . ' run ' . ale#util#EscapePCRE(expand('%' . ':t')) + \ . ' --enable-all' + +Execute(The golangci-lint callback should use configured options): + let b:ale_go_golangci_lint_options = '--foobar' + + AssertLinter 'golangci-lint', + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('golangci-lint') + \ . ' run ' . ale#util#EscapePCRE(expand('%' . ':t')) + \ . ' --foobar' + +Execute(The golangci-lint `lint_package` option should use the correct command): + let b:ale_go_golangci_lint_package = 1 + + AssertLinter 'golangci-lint', + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('golangci-lint') . ' run --enable-all' diff --git a/test/command_callback/test_golangserver_command_callback.vader b/test/command_callback/test_golangserver_command_callback.vader new file mode 100644 index 00000000..ee88e1a4 --- /dev/null +++ b/test/command_callback/test_golangserver_command_callback.vader @@ -0,0 +1,67 @@ +Before: + Save $GOPATH + Save g:ale_completion_enabled + + let g:ale_completion_enabled = 0 + let g:sep = has('win32') ? ';' : ':' + + call ale#assert#SetUpLinterTest('go', 'langserver') + let $GOPATH = ale#path#Simplify(g:dir . '/go_paths/go1') + \ . g:sep + \ . ale#path#Simplify(g:dir . '/go_paths/go2') + +After: + Restore + + unlet! b:ale_completion_enabled + unlet! g:sep + + call ale#assert#TearDownLinterTest() + +Execute(should set correct defaults): + AssertLinter 'go-langserver', ale#Escape('go-langserver') + +Execute(should configure go-langserver callback executable): + let b:ale_go_langserver_executable = 'boo' + + AssertLinter 'boo', ale#Escape('boo') + +Execute(should set go-langserver options): + call ale#test#SetFilename('go_paths/go1/prj1/file.go') + let b:ale_completion_enabled = 1 + let b:ale_go_langserver_options = '' + + AssertLinter 'go-langserver', + \ ale#Escape('go-langserver') . ' -gocodecompletion' + + let b:ale_go_langserver_options = '-trace' + + AssertLinter 'go-langserver', + \ ale#Escape('go-langserver') . ' -gocodecompletion -trace' + +Execute(should ignore go-langserver -gocodecompletion option): + call ale#test#SetFilename('go_paths/go1/prj1/file.go') + + let b:ale_go_langserver_options = '-trace -gocodecompletion' + let b:ale_completion_enabled = 1 + + AssertLinter 'go-langserver', + \ ale#Escape('go-langserver') . ' -gocodecompletion -trace' + + let b:ale_completion_enabled = 0 + + AssertLinter 'go-langserver', ale#Escape('go-langserver') . ' -trace' + +Execute(should set go-langserver for go app1): + call ale#test#SetFilename('go_paths/go1/prj1/file.go') + + AssertLSPLanguage 'go' + AssertLSPOptions {} + AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go1') + +Execute(should set go-langserver for go app2): + call ale#test#SetFilename('go_paths/go2/prj1/file.go') + + AssertLSPLanguage 'go' + AssertLSPOptions {} + AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go2') diff --git a/test/handler/test_golangci_lint_handler.vader b/test/handler/test_golangci_lint_handler.vader new file mode 100644 index 00000000..fb6841f4 --- /dev/null +++ b/test/handler/test_golangci_lint_handler.vader @@ -0,0 +1,55 @@ +Before: + runtime ale_linters/go/golangci_lint.vim + +After: + call ale#linter#Reset() + +Execute (The golangci-lint handler should handle names with spaces): + " We can't test Windows paths with the path resovling on Linux, but we can + " test the regex. + AssertEqual + \ [ + \ [ + \ 'C:\something\file with spaces.go', + \ '12', + \ '3', + \ 'expected ''package'', found ''IDENT'' gibberish (staticcheck)', + \ ], + \ [ + \ 'C:\something\file with spaces.go', + \ '37', + \ '5', + \ 'expected ''package'', found ''IDENT'' gibberish (golint)', + \ ], + \ ], + \ map(ale_linters#go#golangci_lint#GetMatches([ + \ 'C:\something\file with spaces.go:12:3: expected ''package'', found ''IDENT'' gibberish (staticcheck)', + \ 'C:\something\file with spaces.go:37:5: expected ''package'', found ''IDENT'' gibberish (golint)', + \ ]), 'v:val[1:4]') + +Execute (The golangci-lint handler should handle paths correctly): + call ale#test#SetFilename('app/test.go') + + let file = ale#path#GetAbsPath(expand('%:p:h'), 'test.go') + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'col': 3, + \ 'text': 'expected ''package'', found ''IDENT'' gibberish (staticcheck)', + \ 'type': 'E', + \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'), + \ }, + \ { + \ 'lnum': 37, + \ 'col': 5, + \ 'text': 'expected ''package'', found ''IDENT'' gibberish (golint)', + \ 'type': 'E', + \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'), + \ }, + \ ], + \ ale_linters#go#golangci_lint#Handler(bufnr(''), [ + \ file . ':12:3: expected ''package'', found ''IDENT'' gibberish (staticcheck)', + \ file . ':37:5: expected ''package'', found ''IDENT'' gibberish (golint)', + \ ]) diff --git a/test/handler/test_perl_handler.vader b/test/handler/test_perl_handler.vader index c5791d76..e769550c 100644 --- a/test/handler/test_perl_handler.vader +++ b/test/handler/test_perl_handler.vader @@ -7,6 +7,11 @@ After: call ale#test#RestoreDirectory() call ale#linter#Reset() +Execute(The Perl linter should handle empty output): + call ale#test#SetFilename('bar.pl') + + AssertEqual [], ale_linters#perl#perl#Handle(bufnr(''), []) + Execute(The Perl linter should ignore errors from other files): call ale#test#SetFilename('bar.pl') diff --git a/test/script/block-padding-checker b/test/script/block-padding-checker new file mode 100755 index 00000000..b13c9b92 --- /dev/null +++ b/test/script/block-padding-checker @@ -0,0 +1,117 @@ +#!/usr/bin/env python +""" +This script checks for missing or forbidden blank lines before or after +particular Vim commands. This script ensures that VimL scripts are padded +correctly, so they are easier to read. +""" + +import sys +import re + +INDENTATION_RE = re.compile(r'^ *') +COMMENT_LINE_RE = re.compile(r'^ *"') +COMMAND_RE = re.compile(r'^ *([a-zA-Z]+)') + +START_BLOCKS = set(['if', 'for', 'while', 'try', 'function']) +END_BLOCKS = set(['endif', 'endfor', 'endwhile', 'endtry', 'endfunction']) +MIDDLE_BLOCKS = set(['else', 'elseif', 'catch', 'finally']) +TERMINATORS = set(['return', 'throw']) + +WHITESPACE_BEFORE_SET = START_BLOCKS | TERMINATORS +WHITESPACE_FORBIDDEN_BEFORE_SET = END_BLOCKS | MIDDLE_BLOCKS +WHITESPACE_AFTER_SET = END_BLOCKS +WHITESPACE_FORBIDDEN_AFTER_SET = START_BLOCKS | MIDDLE_BLOCKS + + +def remove_comment_lines(line_iter): + for line_number, line in enumerate(line_iter, 1): + if not COMMENT_LINE_RE.match(line): + yield (line_number, line) + + +def check_lines(line_iter): + previous_indentation_level = None + previous_command = None + previous_line_blank = False + + for line_number, line in remove_comment_lines(line_iter): + if len(line) == 0: + # Check for commands where we shouldn't have blank lines after + # them, like `else` or the start of blocks like `function`. + if ( + previous_command is not None + and previous_command in WHITESPACE_FORBIDDEN_AFTER_SET + ): + yield ( + line_number, + 'Blank line forbidden after `%s`' % (command,) + ) + + previous_line_blank = True + previous_command = None + else: + indentation_level = INDENTATION_RE.match(line).end() + command_match = COMMAND_RE.match(line) + + if command_match: + command = command_match.group(1) + + # Check for commands requiring blank lines before them, if they + # aren't at the start of a block. + if ( + command in WHITESPACE_BEFORE_SET + and previous_indentation_level is not None + and indentation_level == previous_indentation_level + and previous_line_blank is False + ): + yield ( + line_number, + 'Blank line required before `%s`' % (command,) + ) + + # Check for commands where we shouldn't have blank lines before + # them, like `else` or the end of blocks like `endfunction`. + if ( + command in WHITESPACE_FORBIDDEN_BEFORE_SET + and previous_line_blank is True + ): + yield ( + line_number - 1, + 'Blank line forbidden before `%s`' % (command,) + ) + + # Check for commands requiring blank lines after them, if they + # aren't at the end of a block. + if ( + previous_command is not None + and previous_command in WHITESPACE_AFTER_SET + and previous_indentation_level is not None + and indentation_level == previous_indentation_level + and previous_line_blank is False + ): + yield ( + line_number - 1, + 'Blank line required after `%s`' % (command,) + ) + + previous_command = command + previous_line_blank = False + previous_indentation_level = indentation_level + + +def main(): + status = 0 + + for filename in sys.argv[1:]: + with open(filename) as vim_file: + line_iter = (line.rstrip() for line in vim_file) + + for line_number, message in check_lines(line_iter): + print('%s:%d %s' % (filename, line_number, message)) + status = 1 + + sys.exit(status) + + +if __name__ == "__main__": + main() diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules index 7aafe995..77e87db4 100755 --- a/test/script/custom-linting-rules +++ b/test/script/custom-linting-rules @@ -60,10 +60,10 @@ check_errors() { for directory in "${directories[@]}"; do # shellcheck disable=SC2086 - while IFS= read -r match; do + while read -r; do RETURN_CODE=1 - echo "$match $message" - done < <(grep -n "$regex" $include_arg "$directory"/**/*.vim \ + echo "$REPLY $message" + done < <(grep -H -n "$regex" $include_arg "$directory"/**/*.vim \ | grep -v 'no-custom-checks' \ | grep -o '^[^:]\+:[0-9]\+' \ | sed 's:^\./::') @@ -126,4 +126,13 @@ check_errors '\(!=.\?\|isnot\) type(\[\])' "Use 'isnot v:t_list' instead" check_errors '\(!=.\?\|isnot\) type({})' "Use 'isnot v:t_dict' instead" check_errors '\(!=.\?\|isnot\) type(function([^)]\+))' "Use 'isnot v:t_func' instead" +# Run a Python script to find lines that require padding around them. For +# users without Python installed, we'll skip these checks. Travis CI will run +# the script. +if command -v python > /dev/null; then + if ! test/script/block-padding-checker "$directory"/**/*.vim; then + RETURN_CODE=1 + fi +fi + exit $RETURN_CODE |