summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--ale_linters/go/gobuild.vim5
-rw-r--r--ale_linters/go/golangci_lint.vim2
-rw-r--r--ale_linters/go/govet.vim7
-rw-r--r--ale_linters/haskell/hlint.vim15
-rw-r--r--ale_linters/julia/languageserver.vim2
-rw-r--r--ale_linters/php/psalm.vim28
-rw-r--r--ale_linters/python/flake8.vim6
-rw-r--r--ale_linters/python/mypy.vim6
-rw-r--r--ale_linters/python/prospector.vim7
-rw-r--r--ale_linters/python/pycodestyle.vim6
-rw-r--r--ale_linters/python/pyflakes.vim6
-rw-r--r--ale_linters/python/pylint.vim6
-rw-r--r--ale_linters/python/pyls.vim6
-rw-r--r--ale_linters/python/pyre.vim6
-rw-r--r--ale_linters/ruby/brakeman.vim12
-rw-r--r--ale_linters/ruby/rails_best_practices.vim14
-rw-r--r--ale_linters/ruby/reek.vim13
-rw-r--r--ale_linters/ruby/rubocop.vim12
-rw-r--r--ale_linters/ruby/solargraph.vim20
-rw-r--r--ale_linters/thrift/thrift.vim2
-rw-r--r--autoload/ale/c.vim2
-rw-r--r--autoload/ale/completion.vim16
-rw-r--r--autoload/ale/cursor.vim79
-rw-r--r--autoload/ale/engine.vim16
-rw-r--r--autoload/ale/events.vim6
-rw-r--r--autoload/ale/fix.vim9
-rw-r--r--autoload/ale/fix/registry.vim5
-rw-r--r--autoload/ale/fixers/eslint.vim2
-rw-r--r--autoload/ale/fixers/generic_python.vim17
-rw-r--r--autoload/ale/fixers/gomod.vim10
-rw-r--r--autoload/ale/fixers/rubocop.vim10
-rw-r--r--autoload/ale/fixers/shfmt.vim17
-rw-r--r--autoload/ale/handlers/eslint.vim7
-rw-r--r--autoload/ale/handlers/rubocop.vim6
-rw-r--r--autoload/ale/handlers/ruby.vim7
-rw-r--r--autoload/ale/lsp_linter.vim16
-rw-r--r--autoload/ale/preview.vim2
-rw-r--r--autoload/ale/python.vim7
-rw-r--r--autoload/ale/toggle.vim19
-rw-r--r--autoload/ale/util.vim2
-rw-r--r--doc/ale-go.txt9
-rw-r--r--doc/ale-haskell.txt9
-rw-r--r--doc/ale-php.txt10
-rw-r--r--doc/ale-python.txt80
-rw-r--r--doc/ale-ruby.txt43
-rw-r--r--doc/ale-thrift.txt2
-rw-r--r--doc/ale.txt74
-rw-r--r--plugin/ale.vim14
-rw-r--r--test/command_callback/test_brakeman_command_callback.vader17
-rw-r--r--test/command_callback/test_flake8_command_callback.vader11
-rw-r--r--test/command_callback/test_gobuild_command_callback.vader12
-rw-r--r--test/command_callback/test_golangci_lint_command_callback.vader6
-rw-r--r--test/command_callback/test_govet_command_callback.vader11
-rw-r--r--test/command_callback/test_haskell_hlint_command_callbacks.vader16
-rw-r--r--test/command_callback/test_julia_languageserver_callbacks.vader8
-rw-r--r--test/command_callback/test_mypy_command_callback.vader8
-rw-r--r--test/command_callback/test_prospector_command_callback.vader8
-rw-r--r--test/command_callback/test_psalm_command_callbacks.vader12
-rw-r--r--test/command_callback/test_pycodestyle_command_callback.vader7
-rw-r--r--test/command_callback/test_pyflakes_command_callback.vader7
-rw-r--r--test/command_callback/test_pylint_command_callback.vader9
-rw-r--r--test/command_callback/test_pyls_command_callback.vader7
-rw-r--r--test/command_callback/test_pyre_command_callback.vader7
-rw-r--r--test/command_callback/test_reek_command_callback.vader30
-rw-r--r--test/command_callback/test_ruby_solargraph.vader11
-rw-r--r--test/command_callback/test_thrift_command_callback.vader10
-rw-r--r--test/completion/test_completion_filtering.vader26
-rw-r--r--test/completion/test_lsp_completion_parsing.vader24
-rw-r--r--test/fixers/test_eslint_fixer_callback.vader7
-rw-r--r--test/fixers/test_gomod_fixer_callback.vader24
-rw-r--r--test/fixers/test_python_add_blank_lines_fixer.vader56
-rw-r--r--test/fixers/test_shfmt_fixer_callback.vader37
-rw-r--r--test/go_files/go.mod1
-rw-r--r--test/handler/test_eslint_handler.vader12
-rw-r--r--test/handler/test_php_psalm_handler.vader24
-rw-r--r--test/python_fixtures/pipenv/Pipfile.lock0
-rw-r--r--test/test_autocmd_commands.vader17
-rw-r--r--test/test_c_flag_parsing.vader2
-rw-r--r--test/test_python_pipenv.vader13
-rw-r--r--test/test_redundant_tsserver_rendering_avoided.vader136
-rw-r--r--test/test_writefile_function.vader21
82 files changed, 1098 insertions, 184 deletions
diff --git a/README.md b/README.md
index da8a4b1f..dbc8652c 100644
--- a/README.md
+++ b/README.md
@@ -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) !!, [golangserver](https://github.com/sourcegraph/go-langserver), [golangci-lint](https://github.com/golangci/golangci-lint) !! |
+| Go | [gofmt](https://golang.org/cmd/gofmt/), [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports), [go mod](https://golang.org/cmd/go/) !!, [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) |
@@ -155,21 +155,21 @@ formatting.
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server), [ocamlformat](https://github.com/ocaml-ppx/ocamlformat) |
| Pawn | [uncrustify](https://github.com/uncrustify/uncrustify) |
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic), [perltidy](https://metacpan.org/pod/distribution/Perl-Tidy/bin/perltidy) |
-| PHP | [langserver](https://github.com/felixfbecker/php-language-server), [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions, [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer), [php-cs-fixer](http://cs.sensiolabs.org/) |
+| PHP | [langserver](https://github.com/felixfbecker/php-language-server), [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions, [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer), [php-cs-fixer](http://cs.sensiolabs.org/), [psalm](https://getpsalm.org) !! |
| PO | [alex](https://github.com/wooorm/alex) !!, [msgfmt](https://www.gnu.org/software/gettext/manual/html_node/msgfmt-Invocation.html), [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| Pod | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| Pony | [ponyc](https://github.com/ponylang/ponyc) |
| proto | [protoc-gen-lint](https://github.com/ckaznocha/protoc-gen-lint) |
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [languageserver](https://github.com/lingua-pupuli/puppet-editor-services), [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
-| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](http://github.com/landscapeio/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pyre](https://github.com/facebook/pyre-check), [pylint](https://www.pylint.org/) !!, [vulture](https://github.com/jendrikseipp/vulture) !!, [yapf](https://github.com/google/yapf) |
+| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](https://github.com/PyCQA/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pyre](https://github.com/facebook/pyre-check), [pylint](https://www.pylint.org/) !!, [vulture](https://github.com/jendrikseipp/vulture) !!, [yapf](https://github.com/google/yapf) |
| QML | [qmlfmt](https://github.com/jesperhh/qmlfmt), [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint) |
| R | [lintr](https://github.com/jimhester/lintr) |
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-reasonml-ols` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server), [refmt](https://github.com/reasonml/reason-cli) |
| reStructuredText | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [rstcheck](https://github.com/myint/rstcheck), [vale](https://github.com/ValeLint/vale), [write-good](https://github.com/btford/write-good) |
| Re:VIEW | [redpen](http://redpen.cc/) |
| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) |
-| Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org), [rufo](https://github.com/ruby-formatter/rufo), [solargraph]([solargraph](https://solargraph.org) |
+| Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org), [rufo](https://github.com/ruby-formatter/rufo), [solargraph](https://solargraph.org) |
| Rust | cargo !! (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/), [rustfmt](https://github.com/rust-lang-nursery/rustfmt) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [prettier](https://github.com/prettier/prettier), [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
diff --git a/ale_linters/go/gobuild.vim b/ale_linters/go/gobuild.vim
index a44449f1..cef1ff88 100644
--- a/ale_linters/go/gobuild.vim
+++ b/ale_linters/go/gobuild.vim
@@ -3,6 +3,7 @@
" Description: go build for Go files
" inspired by work from dzhou121 <dzhou121@gmail.com>
+call ale#Set('go_go_executable', 'go')
call ale#Set('go_gobuild_options', '')
function! ale_linters#go#gobuild#GetCommand(buffer) abort
@@ -10,7 +11,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
" Run go test in local directory with relative path
return ale#path#BufferCdString(a:buffer)
- \ . 'go test'
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./'
endfunction
@@ -47,7 +48,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gobuild',
\ 'aliases': ['go build'],
-\ 'executable': 'go',
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
\ 'command_callback': 'ale_linters#go#gobuild#GetCommand',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#go#gobuild#Handler',
diff --git a/ale_linters/go/golangci_lint.vim b/ale_linters/go/golangci_lint.vim
index b44a6239..dd9a3c64 100644
--- a/ale_linters/go/golangci_lint.vim
+++ b/ale_linters/go/golangci_lint.vim
@@ -18,7 +18,7 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . '%e run '
- \ . ale#util#EscapePCRE(l:filename)
+ \ . ale#Escape(l:filename)
\ . ' ' . l:options
endfunction
diff --git a/ale_linters/go/govet.vim b/ale_linters/go/govet.vim
index 84c23236..3d0d2adf 100644
--- a/ale_linters/go/govet.vim
+++ b/ale_linters/go/govet.vim
@@ -4,20 +4,23 @@
" Author: John Eikenberry <jae@zhar.net>
" Description: updated to work with go1.10
+call ale#Set('go_go_executable', 'go')
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 .'
+ return ale#path#BufferCdString(a:buffer) . ' '
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
\ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' .'
endfunction
call ale#linter#Define('go', {
\ 'name': 'govet',
\ 'aliases': ['go vet'],
\ 'output_stream': 'stderr',
-\ 'executable': 'go',
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
\ 'command_callback': 'ale_linters#go#govet#GetCommand',
\ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1,
diff --git a/ale_linters/haskell/hlint.vim b/ale_linters/haskell/hlint.vim
index be40d92c..3ee864bf 100644
--- a/ale_linters/haskell/hlint.vim
+++ b/ale_linters/haskell/hlint.vim
@@ -1,6 +1,9 @@
" Author: jparoz <jesse.paroz@gmail.com>
" Description: hlint for Haskell files
+call ale#Set('haskell_hlint_executable', 'hlint')
+call ale#Set('haskell_hlint_options', get(g:, 'hlint_options', ''))
+
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:output = []
@@ -26,9 +29,17 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#haskell#hlint#GetCommand(buffer) abort
+ let l:hlintopts = '--color=never --json'
+
+ return '%e'
+ \ . ' ' . ale#Var(a:buffer, 'haskell_hlint_options')
+ \ . ' ' . l:hlintopts . ' -'
+endfunction
+
call ale#linter#Define('haskell', {
\ 'name': 'hlint',
-\ 'executable': 'hlint',
-\ 'command': 'hlint --color=never --json -',
+\ 'executable_callback': ale#VarFunc('haskell_hlint_executable'),
+\ 'command_callback': 'ale_linters#haskell#hlint#GetCommand',
\ 'callback': 'ale_linters#haskell#hlint#Handle',
\})
diff --git a/ale_linters/julia/languageserver.vim b/ale_linters/julia/languageserver.vim
index b6bf8e73..cd2000de 100644
--- a/ale_linters/julia/languageserver.vim
+++ b/ale_linters/julia/languageserver.vim
@@ -6,7 +6,7 @@ call ale#Set('julia_executable', 'julia')
function! ale_linters#julia#languageserver#GetCommand(buffer) abort
let l:julia_executable = ale#Var(a:buffer, 'julia_executable')
- let l:cmd_string = 'using LanguageServer; server = LanguageServer.LanguageServerInstance(STDIN, STDOUT, false); server.runlinter = true; run(server);'
+ let l:cmd_string = 'using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);'
return ale#Escape(l:julia_executable) . ' --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string)
endfunction
diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim
new file mode 100644
index 00000000..cd20ab81
--- /dev/null
+++ b/ale_linters/php/psalm.vim
@@ -0,0 +1,28 @@
+" Author: richard marmorstein <https://github.com/twitchard>
+" Description: plugin for Psalm, static analyzer for PHP
+
+call ale#Set('php_psalm_executable', 'psalm')
+
+function! ale_linters#php#psalm#Handle(buffer, lines) abort
+ " Matches patterns like the following:
+ let l:pattern = '^.*:\(\d\+\):\(\d\+\):\(\w\+\) - \(.*\)$'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'lnum': l:match[1] + 0,
+ \ 'text': l:match[4],
+ \ 'type': l:match[3][:0] is# 'e' ? 'E' : 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('php', {
+\ 'name': 'psalm',
+\ 'command': '%e --diff --output-format=emacs %s',
+\ 'executable_callback': ale#VarFunc('php_psalm_executable'),
+\ 'callback': 'ale_linters#php#psalm#Handle',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim
index 358f51a4..9dcdacc6 100644
--- a/ale_linters/python/flake8.vim
+++ b/ale_linters/python/flake8.vim
@@ -5,12 +5,18 @@ call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 1)
+call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort
return ale#Var(a:buffer, 'python_flake8_options') =~# ' *-m flake8'
endfunction
function! ale_linters#python#flake8#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flake8_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
if !s:UsingModule(a:buffer)
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
endif
diff --git a/ale_linters/python/mypy.vim b/ale_linters/python/mypy.vim
index b38ccdeb..0c90a3c7 100644
--- a/ale_linters/python/mypy.vim
+++ b/ale_linters/python/mypy.vim
@@ -5,8 +5,14 @@ call ale#Set('python_mypy_executable', 'mypy')
call ale#Set('python_mypy_ignore_invalid_syntax', 0)
call ale#Set('python_mypy_options', '')
call ale#Set('python_mypy_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_mypy_auto_pipenv', 0)
function! ale_linters#python#mypy#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_mypy_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy'])
endfunction
diff --git a/ale_linters/python/prospector.vim b/ale_linters/python/prospector.vim
index fff37147..b01cec87 100644
--- a/ale_linters/python/prospector.vim
+++ b/ale_linters/python/prospector.vim
@@ -1,6 +1,8 @@
" Author: chocoelho <carlospecter@gmail.com>
" Description: prospector linter python files
+call ale#Set('python_prospector_auto_pipenv', 0)
+
let g:ale_python_prospector_executable =
\ get(g:, 'ale_python_prospector_executable', 'prospector')
@@ -10,6 +12,11 @@ let g:ale_python_prospector_options =
let g:ale_python_prospector_use_global = get(g:, 'ale_python_prospector_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#python#prospector#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_prospector_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_prospector', ['prospector'])
endfunction
diff --git a/ale_linters/python/pycodestyle.vim b/ale_linters/python/pycodestyle.vim
index de96363f..f0269585 100644
--- a/ale_linters/python/pycodestyle.vim
+++ b/ale_linters/python/pycodestyle.vim
@@ -4,8 +4,14 @@
call ale#Set('python_pycodestyle_executable', 'pycodestyle')
call ale#Set('python_pycodestyle_options', '')
call ale#Set('python_pycodestyle_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pycodestyle_auto_pipenv', 0)
function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycodestyle_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle'])
endfunction
diff --git a/ale_linters/python/pyflakes.vim b/ale_linters/python/pyflakes.vim
index 86ff8773..091408d5 100644
--- a/ale_linters/python/pyflakes.vim
+++ b/ale_linters/python/pyflakes.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyflakes_executable', 'pyflakes')
call ale#Set('python_pyflakes_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyflakes_auto_pipenv', 0)
function! ale_linters#python#pyflakes#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyflakes_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyflakes', ['pyflakes'])
endfunction
diff --git a/ale_linters/python/pylint.vim b/ale_linters/python/pylint.vim
index 9239f835..01c3cb37 100644
--- a/ale_linters/python/pylint.vim
+++ b/ale_linters/python/pylint.vim
@@ -5,8 +5,14 @@ call ale#Set('python_pylint_executable', 'pylint')
call ale#Set('python_pylint_options', '')
call ale#Set('python_pylint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pylint_change_directory', 1)
+call ale#Set('python_pylint_auto_pipenv', 0)
function! ale_linters#python#pylint#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylint_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction
diff --git a/ale_linters/python/pyls.vim b/ale_linters/python/pyls.vim
index ae71f022..83fe8066 100644
--- a/ale_linters/python/pyls.vim
+++ b/ale_linters/python/pyls.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyls_executable', 'pyls')
call ale#Set('python_pyls_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyls_auto_pipenv', 0)
function! ale_linters#python#pyls#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyls_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyls', ['pyls'])
endfunction
diff --git a/ale_linters/python/pyre.vim b/ale_linters/python/pyre.vim
index 5efef409..adc185f2 100644
--- a/ale_linters/python/pyre.vim
+++ b/ale_linters/python/pyre.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyre_executable', 'pyre')
call ale#Set('python_pyre_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyre_auto_pipenv', 0)
function! ale_linters#python#pyre#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyre_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyre', ['pyre'])
endfunction
diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim
index 85cfc184..122e0b5b 100644
--- a/ale_linters/ruby/brakeman.vim
+++ b/ale_linters/ruby/brakeman.vim
@@ -1,8 +1,9 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: Brakeman, a static analyzer for Rails security
-let g:ale_ruby_brakeman_options =
-\ get(g:, 'ale_ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_executable', 'brakeman')
+call ale#Set('ruby_brakeman_options', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
let l:output = []
@@ -33,14 +34,17 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
return ''
endif
- return 'brakeman -f json -q '
+ let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
+ \ . ' -f json -q '
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
\ . ' -p ' . ale#Escape(l:rails_root)
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'brakeman',
-\ 'executable': 'brakeman',
+\ 'executable_callback': ale#VarFunc('ruby_brakeman_executable'),
\ 'command_callback': 'ale_linters#ruby#brakeman#GetCommand',
\ 'callback': 'ale_linters#ruby#brakeman#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/ruby/rails_best_practices.vim b/ale_linters/ruby/rails_best_practices.vim
index 4ba1f3fe..20cadca8 100644
--- a/ale_linters/ruby/rails_best_practices.vim
+++ b/ale_linters/ruby/rails_best_practices.vim
@@ -22,26 +22,18 @@ function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#ruby#rails_best_practices#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
-endfunction
-
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
- let l:executable = ale_linters#ruby#rails_best_practices#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rails_best_practices'
- \ : ''
-
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
if l:rails_root is? ''
return ''
endif
+ let l:executable = ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
let l:output_file = ale#Has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = ale#Has('win32') ? '; type %t' : ''
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
\ . ' --silent -f json --output-file ' . l:output_file
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
\ . ale#Escape(l:rails_root)
@@ -50,7 +42,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
-\ 'executable_callback': 'ale_linters#ruby#rails_best_practices#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rails_best_practices_executable'),
\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim
index aa5d8d70..eefc4ecf 100644
--- a/ale_linters/ruby/reek.vim
+++ b/ale_linters/ruby/reek.vim
@@ -3,6 +3,8 @@
call ale#Set('ruby_reek_show_context', 0)
call ale#Set('ruby_reek_show_wiki_link', 0)
+call ale#Set('ruby_reek_options', '')
+call ale#Set('ruby_reek_executable', 'reek')
function! ale_linters#ruby#reek#VersionCheck(buffer) abort
" If we have previously stored the version number in a cache, then
@@ -12,18 +14,23 @@ function! ale_linters#ruby#reek#VersionCheck(buffer) abort
return ''
endif
- return 'reek --version'
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' --version'
endfunction
function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort
let l:version = ale#semver#GetVersion('reek', a:version_output)
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
" Tell reek what the filename is if the version of reek is new enough.
let l:display_name_args = ale#semver#GTE(l:version, [5, 0, 0])
\ ? ' --stdin-filename %s'
\ : ''
- return 'reek -f json --no-progress --no-color'
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' -f json --no-progress --no-color'
\ . l:display_name_args
endfunction
@@ -62,7 +69,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'reek',
-\ 'executable': 'reek',
+\ 'executable_callback': ale#VarFunc('ruby_reek_executable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#ruby#reek#VersionCheck'},
\ {'callback': 'ale_linters#ruby#reek#GetCommand'},
diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim
index 777f457a..45218394 100644
--- a/ale_linters/ruby/rubocop.vim
+++ b/ale_linters/ruby/rubocop.vim
@@ -1,13 +1,13 @@
" Author: ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow
" Description: RuboCop, a code style analyzer for Ruby files
+call ale#Set('ruby_rubocop_executable', 'rubocop')
+call ale#Set('ruby_rubocop_options', '')
+
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
- let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rubocop'
- \ : ''
+ let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
@@ -55,7 +55,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rubocop',
-\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rubocop_executable'),
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
\})
diff --git a/ale_linters/ruby/solargraph.vim b/ale_linters/ruby/solargraph.vim
index 2aad3af6..7ca0399f 100644
--- a/ale_linters/ruby/solargraph.vim
+++ b/ale_linters/ruby/solargraph.vim
@@ -1,20 +1,20 @@
" Author: Horacio Sanson - https://github.com/hsanson
" Description: Solargraph Language Server https://solargraph.org/
+"
+" Author: Devon Meunier <devon.meunier@gmail.com>
+" Description: updated to use stdio
-call ale#Set('ruby_solargraph_host', '127.0.0.1')
-call ale#Set('ruby_solargraph_port', '7658')
+call ale#Set('ruby_solargraph_executable', 'solargraph')
-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
+function! ale_linters#ruby#solargraph#GetCommand(buffer) abort
+ return '%e' . ale#Pad('stdio')
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'solargraph',
-\ 'lsp': 'socket',
-\ 'address_callback': 'ale_linters#ruby#solargraph#GetAddress',
+\ 'lsp': 'stdio',
\ 'language': 'ruby',
-\ 'project_root_callback': 'ale#ruby#FindProjectRoot'
+\ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'),
+\ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand',
+\ 'project_root_callback': 'ale#ruby#FindProjectRoot',
\})
diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim
index 396a2355..36a8656e 100644
--- a/ale_linters/thrift/thrift.vim
+++ b/ale_linters/thrift/thrift.vim
@@ -2,7 +2,7 @@
call ale#Set('thrift_thrift_executable', 'thrift')
call ale#Set('thrift_thrift_generators', ['cpp'])
-call ale#Set('thrift_thrift_includes', [])
+call ale#Set('thrift_thrift_includes', ['.'])
call ale#Set('thrift_thrift_options', '-strict')
function! ale_linters#thrift#thrift#GetCommand(buffer) abort
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim
index e7b43d88..ce59ae31 100644
--- a/autoload/ale/c.vim
+++ b/autoload/ale/c.vim
@@ -55,7 +55,7 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
" 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# ' '
+ if len(l:option_list) > 0 && l:option_list[-1] isnot# ' '
continue
endif
diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim
index e96774c3..9dd913f5 100644
--- a/autoload/ale/completion.vim
+++ b/autoload/ale/completion.vim
@@ -98,14 +98,15 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return ''
endfunction
-function! ale#completion#Filter(buffer, suggestions, prefix) abort
+function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
+ let l:triggers = s:GetFiletypeValue(s:trigger_character_map, a:filetype)
" For completing...
" foo.
" ^
" We need to include all of the given suggestions.
- if a:prefix is# '.'
+ if index(l:triggers, a:prefix) >= 0
let l:filtered_suggestions = a:suggestions
else
let l:filtered_suggestions = []
@@ -359,17 +360,23 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:kind = 'v'
endif
+ let l:doc = get(l:item, 'documentation', '')
+
+ if type(l:doc) is v:t_dict && has_key(l:doc, 'value')
+ let l:doc = l:doc.value
+ endif
+
call add(l:results, {
\ 'word': l:word,
\ 'kind': l:kind,
\ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''),
- \ 'info': get(l:item, 'documentation', ''),
+ \ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\})
endfor
if has_key(l:info, 'prefix')
- return ale#completion#Filter(l:buffer, l:results, l:info.prefix)
+ return ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
endif
return l:results
@@ -390,6 +397,7 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
if l:command is# 'completions'
let l:names = ale#completion#Filter(
\ l:buffer,
+ \ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix,
\)[: g:ale_completion_max_suggestions - 1]
diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim
index 3fa4e5ba..c3b48ca3 100644
--- a/autoload/ale/cursor.vim
+++ b/autoload/ale/cursor.vim
@@ -1,4 +1,6 @@
+scriptencoding utf-8
" Author: w0rp <devw0rp@gmail.com>
+" Author: João Paulo S. de Souza <joao.paulo.silvasouza@hotmail.com>
" Description: Echoes lint message for the current line, if any
" Controls the milliseconds delay before echoing a message.
@@ -37,12 +39,11 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endtry
endfunction
-function! s:FindItemAtCursor() abort
- let l:buf = bufnr('')
- let l:info = get(g:ale_buffer_info, l:buf, {})
+function! s:FindItemAtCursor(buffer) abort
+ let l:info = get(g:ale_buffer_info, a:buffer, {})
let l:loclist = get(l:info, 'loclist', [])
let l:pos = getcurpos()
- let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2])
+ let l:index = ale#util#BinarySearch(l:loclist, a:buffer, l:pos[1], l:pos[2])
let l:loc = l:index >= 0 ? l:loclist[l:index] : {}
return [l:info, l:loc]
@@ -56,7 +57,9 @@ function! s:StopCursorTimer() abort
endfunction
function! ale#cursor#EchoCursorWarning(...) abort
- if !g:ale_echo_cursor
+ let l:buffer = bufnr('')
+
+ if !g:ale_echo_cursor && !g:ale_cursor_detail
return
endif
@@ -65,28 +68,39 @@ function! ale#cursor#EchoCursorWarning(...) abort
return
endif
- if ale#ShouldDoNothing(bufnr(''))
+ if ale#ShouldDoNothing(l:buffer)
return
endif
- let l:buffer = bufnr('')
- let [l:info, l:loc] = s:FindItemAtCursor()
+ let [l:info, l:loc] = s:FindItemAtCursor(l:buffer)
+
+ if g:ale_echo_cursor
+ if !empty(l:loc)
+ let l:format = ale#Var(l:buffer, 'echo_msg_format')
+ let l:msg = ale#GetLocItemMessage(l:loc, l:format)
+ call ale#cursor#TruncatedEcho(l:msg)
+ let l:info.echoed = 1
+ elseif get(l:info, 'echoed')
+ " We'll only clear the echoed message when moving off errors once,
+ " so we don't continually clear the echo line.
+ execute 'echo'
+ let l:info.echoed = 0
+ endif
+ endif
- if !empty(l:loc)
- let l:format = ale#Var(l:buffer, 'echo_msg_format')
- let l:msg = ale#GetLocItemMessage(l:loc, l:format)
- call ale#cursor#TruncatedEcho(l:msg)
- let l:info.echoed = 1
- elseif get(l:info, 'echoed')
- " We'll only clear the echoed message when moving off errors once,
- " so we don't continually clear the echo line.
- execute 'echo'
- let l:info.echoed = 0
+ if g:ale_cursor_detail
+ if !empty(l:loc)
+ call s:ShowCursorDetailForItem(l:loc, {'stay_here': 1})
+ else
+ call ale#preview#CloseIfTypeMatches('ale-preview')
+ endif
endif
endfunction
function! ale#cursor#EchoCursorWarningWithDelay() abort
- if !g:ale_echo_cursor
+ let l:buffer = bufnr('')
+
+ if !g:ale_echo_cursor && !g:ale_cursor_detail
return
endif
@@ -104,7 +118,7 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
" we should echo something. Otherwise we can end up doing processing
" the echo message far too frequently.
if l:pos != s:last_pos
- let l:delay = ale#Var(bufnr(''), 'echo_delay')
+ let l:delay = ale#Var(l:buffer, 'echo_delay')
let s:last_pos = l:pos
let s:cursor_timer = timer_start(
@@ -114,24 +128,37 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
endif
endfunction
+function! s:ShowCursorDetailForItem(loc, options) abort
+ let l:stay_here = get(a:options, 'stay_here', 0)
+
+ let s:last_detailed_line = line('.')
+ let l:message = get(a:loc, 'detail', a:loc.text)
+ let l:lines = split(l:message, "\n")
+ call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
+
+ " Clear the echo message if we manually displayed details.
+ if !l:stay_here
+ execute 'echo'
+ endif
+endfunction
+
function! ale#cursor#ShowCursorDetail() abort
+ let l:buffer = bufnr('')
+
" Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n'
return
endif
- if ale#ShouldDoNothing(bufnr(''))
+ if ale#ShouldDoNothing(l:buffer)
return
endif
call s:StopCursorTimer()
- let [l:info, l:loc] = s:FindItemAtCursor()
+ let [l:info, l:loc] = s:FindItemAtCursor(l:buffer)
if !empty(l:loc)
- let l:message = get(l:loc, 'detail', l:loc.text)
-
- call ale#preview#Show(split(l:message, "\n"))
- execute 'echo'
+ call s:ShowCursorDetailForItem(l:loc, {'stay_here': 0})
endif
endfunction
diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim
index b6c2d3c9..05db0e49 100644
--- a/autoload/ale/engine.vim
+++ b/autoload/ale/engine.vim
@@ -18,6 +18,22 @@ if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {}
endif
+
+function! ale#engine#CleanupEveryBuffer() abort
+ for l:key in keys(g:ale_buffer_info)
+ " The key could be a filename or a buffer number, so try and
+ " convert it to a number. We need a number for the other
+ " functions.
+ let l:buffer = str2nr(l:key)
+
+ if l:buffer > 0
+ " Stop all jobs and clear the results for everything, and delete
+ " all of the data we stored for the buffer.
+ call ale#engine#Cleanup(l:buffer)
+ endif
+ endfor
+endfunction
+
function! ale#engine#ResetExecutableCache() abort
let s:executable_cache_map = {}
endfunction
diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim
index 300aefcc..e48ad488 100644
--- a/autoload/ale/events.vim
+++ b/autoload/ale/events.vim
@@ -131,13 +131,17 @@ function! ale#events#Init() abort
autocmd InsertLeave * call ale#Queue(0)
endif
- if g:ale_echo_cursor
+ if g:ale_echo_cursor || g:ale_cursor_detail
autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif
" Look for a warning to echo as soon as we leave Insert mode.
" The script's position variable used when moving the cursor will
" not be changed here.
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif
endif
+
+ if g:ale_close_preview_on_insert
+ autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
+ endif
endif
augroup END
endfunction
diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim
index 1ae1a4a1..03652ecf 100644
--- a/autoload/ale/fix.vim
+++ b/autoload/ale/fix.vim
@@ -30,7 +30,14 @@ function! ale#fix#ApplyQueuedFixes() abort
call winrestview(l:save)
endif
- call setline(1, l:data.output)
+ " If the file is in DOS mode, we have to remove carriage returns from
+ " the ends of lines before calling setline(), or we will see them
+ " twice.
+ let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos'
+ \ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
+ \ : l:data.output
+
+ call setline(1, l:lines_to_set)
if l:data.should_save
if empty(&buftype)
diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim
index eb12f22d..76cce87f 100644
--- a/autoload/ale/fix/registry.vim
+++ b/autoload/ale/fix/registry.vim
@@ -145,6 +145,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['go'],
\ 'description': 'Fix Go files imports with goimports.',
\ },
+\ 'gomod': {
+\ 'function': 'ale#fixers#gomod#Fix',
+\ 'suggested_filetypes': ['gomod'],
+\ 'description': 'Fix Go module files with go mod edit -fmt.',
+\ },
\ 'tslint': {
\ 'function': 'ale#fixers#tslint#Fix',
\ 'suggested_filetypes': ['typescript'],
diff --git a/autoload/ale/fixers/eslint.vim b/autoload/ale/fixers/eslint.vim
index 36f47510..ea5b2a63 100644
--- a/autoload/ale/fixers/eslint.vim
+++ b/autoload/ale/fixers/eslint.vim
@@ -25,7 +25,7 @@ endfunction
function! ale#fixers#eslint#ProcessEslintDOutput(buffer, output) abort
" If the output is an error message, don't use it.
for l:line in a:output[:10]
- if l:line =~# '^Error:'
+ if l:line =~# '\v^Error:|^Could not connect'
return []
endif
endfor
diff --git a/autoload/ale/fixers/generic_python.vim b/autoload/ale/fixers/generic_python.vim
index 124146be..d55a23c3 100644
--- a/autoload/ale/fixers/generic_python.vim
+++ b/autoload/ale/fixers/generic_python.vim
@@ -6,13 +6,28 @@ function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, line
let l:new_lines = []
let l:last_indent_size = 0
let l:last_line_is_blank = 0
+ let l:in_docstring = 0
for l:line in a:lines
let l:indent_size = len(matchstr(l:line, '^ *'))
+ if !l:in_docstring
+ " Make sure it is not just a single line docstring and then verify
+ " it's starting a new docstring
+ if match(l:line, '\v^ *("""|'''''').*("""|'''''')') == -1
+ \&& match(l:line, '\v^ *("""|'''''')') >= 0
+ let l:in_docstring = 1
+ endif
+ else
+ if match(l:line, '\v^ *.*("""|'''''')') >= 0
+ let l:in_docstring = 0
+ endif
+ endif
+
if !l:last_line_is_blank
+ \&& !l:in_docstring
\&& l:indent_size <= l:last_indent_size
- \&& match(l:line, '\v^ *(return|if|for|while|break|continue)') >= 0
+ \&& match(l:line, '\v^ *(return|if|for|while|break|continue)(\(| |$)') >= 0
call add(l:new_lines, '')
endif
diff --git a/autoload/ale/fixers/gomod.vim b/autoload/ale/fixers/gomod.vim
new file mode 100644
index 00000000..68895f9b
--- /dev/null
+++ b/autoload/ale/fixers/gomod.vim
@@ -0,0 +1,10 @@
+call ale#Set('go_go_executable', 'go')
+
+function! ale#fixers#gomod#Fix(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'go_go_executable')
+
+ return {
+ \ 'command': ale#Escape(l:executable) . ' mod edit -fmt %t',
+ \ 'read_temporary_file': 1,
+ \}
+endfunction
diff --git a/autoload/ale/fixers/rubocop.vim b/autoload/ale/fixers/rubocop.vim
index 0a39ef62..a4613817 100644
--- a/autoload/ale/fixers/rubocop.vim
+++ b/autoload/ale/fixers/rubocop.vim
@@ -1,12 +1,12 @@
+call ale#Set('ruby_rubocop_options', '')
+call ale#Set('ruby_rubocop_executable', 'rubocop')
+
function! ale#fixers#rubocop#GetCommand(buffer) abort
- let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rubocop'
- \ : ''
+ let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options')
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --auto-correct %t'
diff --git a/autoload/ale/fixers/shfmt.vim b/autoload/ale/fixers/shfmt.vim
index fc55f425..06e8da57 100644
--- a/autoload/ale/fixers/shfmt.vim
+++ b/autoload/ale/fixers/shfmt.vim
@@ -5,12 +5,27 @@ scriptencoding utf-8
call ale#Set('sh_shfmt_executable', 'shfmt')
call ale#Set('sh_shfmt_options', '')
+function! s:DefaultOption(buffer) abort
+ if getbufvar(a:buffer, '&expandtab') == 0
+ " Tab is used by default
+ return ''
+ endif
+
+ let l:tabsize = getbufvar(a:buffer, '&shiftwidth')
+
+ if l:tabsize == 0
+ let l:tabsize = getbufvar(a:buffer, '&tabstop')
+ endif
+
+ return ' -i ' . l:tabsize
+endfunction
+
function! ale#fixers#shfmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'sh_shfmt_executable')
let l:options = ale#Var(a:buffer, 'sh_shfmt_options')
return {
\ 'command': ale#Escape(l:executable)
- \ . (empty(l:options) ? '' : ' ' . l:options)
+ \ . (empty(l:options) ? s:DefaultOption(a:buffer) : ' ' . l:options)
\}
endfunction
diff --git a/autoload/ale/handlers/eslint.vim b/autoload/ale/handlers/eslint.vim
index bc10ec21..eda033e4 100644
--- a/autoload/ale/handlers/eslint.vim
+++ b/autoload/ale/handlers/eslint.vim
@@ -99,6 +99,13 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
\}]
endif
+ if a:lines == ['Could not connect']
+ return [{
+ \ 'lnum': 1,
+ \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.',
+ \}]
+ endif
+
" Matches patterns line the following:
"
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
diff --git a/autoload/ale/handlers/rubocop.vim b/autoload/ale/handlers/rubocop.vim
deleted file mode 100644
index f6367cf5..00000000
--- a/autoload/ale/handlers/rubocop.vim
+++ /dev/null
@@ -1,6 +0,0 @@
-call ale#Set('ruby_rubocop_options', '')
-call ale#Set('ruby_rubocop_executable', 'rubocop')
-
-function! ale#handlers#rubocop#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_rubocop_executable')
-endfunction
diff --git a/autoload/ale/handlers/ruby.vim b/autoload/ale/handlers/ruby.vim
index 110fe156..c28b8b75 100644
--- a/autoload/ale/handlers/ruby.vim
+++ b/autoload/ale/handlers/ruby.vim
@@ -37,3 +37,10 @@ function! ale#handlers#ruby#HandleSyntaxErrors(buffer, lines) abort
return s:HandleSyntaxError(a:buffer, a:lines)
endfunction
+function! ale#handlers#ruby#EscapeExecutable(executable, bundle_exec) abort
+ let l:exec_args = a:executable =~? 'bundle'
+ \ ? ' exec ' . a:bundle_exec
+ \ : ''
+
+ return ale#Escape(a:executable) . l:exec_args
+endfunction
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 8fbad12f..a11c76bc 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -55,16 +55,29 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
endif
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
+ let l:no_changes = 0
" tsserver sends syntax and semantic errors in separate messages, so we
" have to collect the messages separately for each buffer and join them
" back together again.
if a:error_type is# 'syntax'
+ if len(l:thislist) is 0 && len(get(l:info, 'syntax_loclist', [])) is 0
+ let l:no_changes = 1
+ endif
+
let l:info.syntax_loclist = l:thislist
else
+ if len(l:thislist) is 0 && len(get(l:info, 'semantic_loclist', [])) is 0
+ let l:no_changes = 1
+ endif
+
let l:info.semantic_loclist = l:thislist
endif
+ if l:no_changes
+ return
+ endif
+
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
@@ -99,9 +112,10 @@ endfunction
function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '')
- let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
+ let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
+
call s:HandleLSPErrorMessage(l:linter_name, a:response)
elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response)
diff --git a/autoload/ale/preview.vim b/autoload/ale/preview.vim
index aefbb691..180a37d0 100644
--- a/autoload/ale/preview.vim
+++ b/autoload/ale/preview.vim
@@ -15,13 +15,13 @@ function! ale#preview#Show(lines, ...) abort
setlocal modifiable
setlocal noreadonly
setlocal nobuflisted
- let &l:filetype = get(l:options, 'filetype', 'ale-preview')
setlocal buftype=nofile
setlocal bufhidden=wipe
:%d
call setline(1, a:lines)
setlocal nomodifiable
setlocal readonly
+ let &l:filetype = get(l:options, 'filetype', 'ale-preview')
if get(l:options, 'stay_here')
wincmd p
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index 1f963431..8d6bf1f0 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -1,6 +1,8 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Functions for integrating with Python linters.
+call ale#Set('python_auto_pipenv', '0')
+
let s:sep = has('win32') ? '\' : '/'
" bin is used for Unix virtualenv directories, and Scripts is for Windows.
let s:bin_dir = has('unix') ? 'bin' : 'Scripts'
@@ -107,3 +109,8 @@ function! ale#python#FindExecutable(buffer, base_var_name, path_list) abort
return ale#Var(a:buffer, a:base_var_name . '_executable')
endfunction
+
+" Detects whether a pipenv environment is present.
+function! ale#python#PipenvPresent(buffer) abort
+ return findfile('Pipfile.lock', expand('#' . a:buffer . ':p:h') . ';') isnot# ''
+endfunction
diff --git a/autoload/ale/toggle.vim b/autoload/ale/toggle.vim
index 1d052b4f..8e642b3f 100644
--- a/autoload/ale/toggle.vim
+++ b/autoload/ale/toggle.vim
@@ -15,21 +15,6 @@ function! s:DisablePostamble() abort
endif
endfunction
-function! s:CleanupEveryBuffer() abort
- for l:key in keys(g:ale_buffer_info)
- " The key could be a filename or a buffer number, so try and
- " convert it to a number. We need a number for the other
- " functions.
- let l:buffer = str2nr(l:key)
-
- if l:buffer > 0
- " Stop all jobs and clear the results for everything, and delete
- " all of the data we stored for the buffer.
- call ale#engine#Cleanup(l:buffer)
- endif
- endfor
-endfunction
-
function! ale#toggle#Toggle() abort
let g:ale_enabled = !get(g:, 'ale_enabled')
@@ -40,7 +25,7 @@ function! ale#toggle#Toggle() abort
call ale#balloon#Enable()
endif
else
- call s:CleanupEveryBuffer()
+ call ale#engine#CleanupEveryBuffer()
call s:DisablePostamble()
if exists('*ale#balloon#Disable')
@@ -64,7 +49,7 @@ function! ale#toggle#Disable() abort
endfunction
function! ale#toggle#Reset() abort
- call s:CleanupEveryBuffer()
+ call ale#engine#CleanupEveryBuffer()
call ale#highlight#UpdateHighlights()
endfunction
diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim
index 58a2065e..e0491653 100644
--- a/autoload/ale/util.vim
+++ b/autoload/ale/util.vim
@@ -405,7 +405,7 @@ endfunction
" the buffer.
function! ale#util#Writefile(buffer, lines, filename) abort
let l:corrected_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
- \ ? map(copy(a:lines), 'v:val . "\r"')
+ \ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines
call writefile(l:corrected_lines, a:filename) " no-custom-checks
diff --git a/doc/ale-go.txt b/doc/ale-go.txt
index 1d55763e..71b248ee 100644
--- a/doc/ale-go.txt
+++ b/doc/ale-go.txt
@@ -20,6 +20,15 @@ the benefit of running a number of linters, more than ALE would by default,
while ensuring it doesn't run any linters known to be slow or resource
intensive.
+g:ale_go_go_executable *g:ale_go_go_options*
+ *b:ale_go_go_options*
+
+ Type: |String|
+ Default: `'go'`
+
+ The executable that will be run for the `gobuild` and `govet` linters, and
+ the gomod` fixer.
+
===============================================================================
gobuild *ale-go-gobuild*
diff --git a/doc/ale-haskell.txt b/doc/ale-haskell.txt
index c1f1e889..a59fa4e2 100644
--- a/doc/ale-haskell.txt
+++ b/doc/ale-haskell.txt
@@ -77,6 +77,15 @@ g:ale_haskell_hlint_executable *g:ale_haskell_hlint_executable*
This variable can be changed to use a different executable for hlint.
+
+g:ale_haskell_hlint_options g:ale_haskell_hlint_options
+ b:ale_haskell_hlint_options
+ Type: String
+ Default: ''
+
+ This variable can be used to pass extra options to the underlying hlint
+ executable.
+
===============================================================================
stack-build *ale-haskell-stack-build*
diff --git a/doc/ale-php.txt b/doc/ale-php.txt
index f38c3f88..2eed838e 100644
--- a/doc/ale-php.txt
+++ b/doc/ale-php.txt
@@ -170,6 +170,16 @@ g:ale_php_phpstan_configuration *g:ale_php_phpstan_configuration*
===============================================================================
+psalm *ale-php-psalm*
+
+g:ale_php_psalm_executable *g:ale_php_psalm_executable*
+ *b:ale_php_psalm_executable*
+ Type: |String|
+ Default: `'psalm'`
+
+ This variable sets the executable used for psalm.
+
+===============================================================================
php-cs-fixer *ale-php-php-cs-fixer*
g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable*
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index b5c469b1..0b8e1746 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -2,6 +2,14 @@
ALE Python Integration *ale-python-options*
+g:ale_python_auto_pipenv *g:ale_python_auto_pipenv*
+ *b:ale_python_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
===============================================================================
ALE Python Project Root Behavior *ale-python-root*
@@ -137,6 +145,15 @@ g:ale_python_flake8_use_global *g:ale_python_flake8_use_global*
Both variables can be set with `b:` buffer variables instead.
+g:ale_python_flake8_auto_pipenv *g:ale_python_flake8_auto_pipenv*
+ *b:ale_python_flake8_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
isort *ale-python-isort*
@@ -211,6 +228,15 @@ g:ale_python_mypy_use_global *g:ale_python_mypy_use_global*
See |ale-integrations-local-executables|
+g:ale_python_mypy_auto_pipenv *g:ale_python_mypy_auto_pipenv*
+ *b:ale_python_mypy_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
prospector *ale-python-prospector*
@@ -253,6 +279,15 @@ g:ale_python_prospector_use_global *g:ale_python_prospector_use_global*
See |ale-integrations-local-executables|
+g:ale_python_prospector_auto_pipenv *g:ale_python_prospector_auto_pipenv*
+ *b:ale_python_prospector_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pycodestyle *ale-python-pycodestyle*
@@ -284,6 +319,15 @@ g:ale_python_pycodestyle_use_global *g:ale_python_pycodestyle_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pycodestyle_auto_pipenv *g:ale_python_pycodestyle_auto_pipenv*
+ *b:ale_python_pycodestyle_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyflakes *ale-python-pyflakes*
@@ -298,6 +342,15 @@ g:ale_python_pyflakes_executable *g:ale_python_pyflakes_executable*
Set this to `'pipenv'` to invoke `'pipenv` `run` `pyflakes'`.
+g:ale_python_pyflakes_auto_pipenv *g:ale_python_pyflakes_auto_pipenv*
+ *b:ale_python_pyflakes_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pylint *ale-python-pylint*
@@ -350,6 +403,15 @@ g:ale_python_pylint_use_global *g:ale_python_pylint_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pylint_auto_pipenv *g:ale_python_pylint_auto_pipenv*
+ *b:ale_python_pylint_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyls *ale-python-pyls*
@@ -374,6 +436,15 @@ g:ale_python_pyls_use_global *g:ale_python_pyls_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pyls_auto_pipenv *g:ale_python_pyls_auto_pipenv*
+ *b:ale_python_pyls_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyre *ale-python-pyre*
@@ -398,6 +469,15 @@ g:ale_python_pyre_use_global *g:ale_python_pyre_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv*
+ *b:ale_python_pyre_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
vulture *ale-python-vulture*
diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt
index ec7b07cf..f8a41999 100644
--- a/doc/ale-ruby.txt
+++ b/doc/ale-ruby.txt
@@ -5,6 +5,15 @@ ALE Ruby Integration *ale-ruby-options*
===============================================================================
brakeman *ale-ruby-brakeman*
+g:ale_ruby_brakeman_executable *g:ale_ruby_brakeman_executable*
+ *b:ale_ruby_brakeman_executable*
+ Type: String
+ Default: `'brakeman'`
+
+ Override the invoked brakeman binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` brakeman'.
+
+
g:ale_ruby_brakeman_options *g:ale_ruby_brakeman_options*
*b:ale_ruby_brakeman_options*
Type: |String|
@@ -20,10 +29,11 @@ g:ale_ruby_rails_best_practices_executable
*g:ale_ruby_rails_best_practices_executable*
*b:ale_ruby_rails_best_practices_executable*
Type: String
- Default: 'rails_best_practices'
+ Default: `'rails_best_practices'`
Override the invoked rails_best_practices binary. Set this to `'bundle'` to
- invoke `'bundle` `exec` `rails_best_practices'`.
+ invoke `'bundle` `exec` rails_best_practices'.
+
g:ale_ruby_rails_best_practices_options
*g:ale_ruby_rails_best_practices_options*
@@ -37,6 +47,15 @@ g:ale_ruby_rails_best_practices_options
===============================================================================
reek *ale-ruby-reek*
+g:ale_ruby_reek_executable *g:ale_ruby_reek_executable*
+ *b:ale_ruby_reek_executable*
+ Type: String
+ Default: `'reek'`
+
+ Override the invoked reek binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` reek'.
+
+
g:ale_ruby_reek_show_context *g:ale_ruby_reek_show_context*
*b:ale_ruby_reek_show_context*
Type: |Number|
@@ -63,8 +82,8 @@ g:ale_ruby_rubocop_executable *g:ale_ruby_rubocop_executable*
Type: String
Default: `'rubocop'`
- Override the invoked rubocop binary. This is useful for running rubocop
- from binstubs or a bundle.
+ Override the invoked rubocop binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` rubocop'.
g:ale_ruby_rubocop_options *g:ale_ruby_rubocop_options*
@@ -101,19 +120,13 @@ g:ale_ruby_rufo_executable *g:ale_ruby_rufo_executable*
===============================================================================
solargraph *ale-ruby-solargraph*
-g:ale_ruby_solargraph_host *g:ale_ruby_solargraph_host*
- *b:ale_ruby_solargraph_host*
+g:ale_ruby_solargraph_executable *g:ale_ruby_solargraph_executable*
+ *b:ale_ruby_solargraph_executable*
Type: String
- Default: `'127.0.0.1'`
-
- The host/ip where the solargraph language server is running.
+ Default: `'solargraph'`
-g:ale_ruby_solargraph_port *g:ale_ruby_solargraph_port*
- *b:ale_ruby_solargraph_port*
- Type: String
- Default: `'7658'`
-
- The listening port where the solargraph language server is running.
+ Override the invoked solargraph binary. This is useful for running solargraph
+ from binstubs or a bundle.
===============================================================================
diff --git a/doc/ale-thrift.txt b/doc/ale-thrift.txt
index ed858db8..bb2ec058 100644
--- a/doc/ale-thrift.txt
+++ b/doc/ale-thrift.txt
@@ -28,7 +28,7 @@ g:ale_thrift_thrift_generators *g:ale_thrift_thrift_generators*
g:ale_thrift_thrift_includes *g:ale_thrift_thrift_includes*
*b:ale_thrift_thrift_includes*
Type: |List| of |String|s
- Default: `[]`
+ Default: `['.']`
This list contains paths that will be searched for thrift `include`
directives.
diff --git a/doc/ale.txt b/doc/ale.txt
index ac8925f7..1cf2945f 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -206,6 +206,7 @@ CONTENTS *ale-contents*
phpcs...............................|ale-php-phpcs|
phpmd...............................|ale-php-phpmd|
phpstan.............................|ale-php-phpstan|
+ psalm...............................|ale-php-psalm|
php-cs-fixer........................|ale-php-php-cs-fixer|
po....................................|ale-po-options|
write-good..........................|ale-po-write-good|
@@ -402,7 +403,7 @@ Notes:
* FusionScript: `fusion-lint`
* Git Commit Messages: `gitlint`
* GLSL: glslang, `glslls`
-* Go: `gofmt`, `goimports`, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!!, `golangserver`, `golangci-lint`!!
+* Go: `gofmt`, `goimports`, `go mod`!!, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!!, `golangserver`, `golangci-lint`!!
* GraphQL: `eslint`, `gqlint`, `prettier`
* Hack: `hack`, `hackfmt`, `hhast`
* Haml: `haml-lint`
@@ -433,7 +434,7 @@ Notes:
* OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`, `ocamlformat`
* Pawn: `uncrustify`
* Perl: `perl -c`, `perl-critic`, `perltidy`
-* PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`
+* PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`, `psalm`!!
* PO: `alex`!!, `msgfmt`, `proselint`, `write-good`
* Pod: `alex`!!, `proselint`, `write-good`
* Pony: `ponyc`
@@ -527,12 +528,13 @@ circumstances.
ALE will report problems with your code in the following ways, listed with
their relevant options.
-* By updating loclist. (On by default) - |g:ale_set_loclist|
-* By updating quickfix. (Off by default) - |g:ale_set_quickfix|
-* By setting error highlights. - |g:ale_set_highlights|
-* By creating signs in the sign column. - |g:ale_set_signs|
-* By echoing messages based on your cursor. - |g:ale_echo_cursor|
-* By showing balloons for your mouse cursor - |g:ale_set_balloons|
+* By updating loclist. (On by default) - |g:ale_set_loclist|
+* By updating quickfix. (Off by default) - |g:ale_set_quickfix|
+* By setting error highlights. - |g:ale_set_highlights|
+* By creating signs in the sign column. - |g:ale_set_signs|
+* By echoing messages based on your cursor. - |g:ale_echo_cursor|
+* By displaying the preview based on your cursor. - |g:ale_cursor_detail|
+* By showing balloons for your mouse cursor - |g:ale_set_balloons|
Please consult the documentation for each option, which can reveal some other
ways of tweaking the behaviour of each way of displaying problems. You can
@@ -805,6 +807,20 @@ g:ale_change_sign_column_color *g:ale_change_sign_column_color*
windows.
+g:ale_close_preview_on_insert *g:ale_close_preview_on_insert*
+
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, ALE's |preview-window| will be automatically
+ closed upon entering Insert Mode. This option can be used in combination
+ with |g:ale_cursor_detail| for automatically displaying the preview window
+ on problem lines, and automatically closing it again when editing text.
+
+ This setting must be set to `1` before ALE is loaded for this behavior
+ to be enabled. See |ale-lint-settings-on-startup|.
+
+
g:ale_command_wrapper *g:ale_command_wrapper*
*b:ale_command_wrapper*
Type: |String|
@@ -893,6 +909,27 @@ g:ale_completion_max_suggestions *g:ale_completion_max_suggestions*
Adjust this option as needed, depending on the complexity of your codebase
and your available processing power.
+g:ale_cursor_detail *g:ale_cursor_detail*
+
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, ALE's |preview-window| will be automatically
+ opened when the cursor moves onto lines with problems. ALE will search for
+ problems using the same logic that |g:ale_echo_cursor| uses. The preview
+ window will be closed automatically when you move away from the line.
+
+ Messages are only displayed after a short delay. See |g:ale_echo_delay|.
+
+ The preview window is opened without stealing focus, which means your cursor
+ will stay in the same buffer as it currently is.
+
+ The preview window can be closed automatically upon entering Insert mode
+ by setting |g:ale_close_preview_on_insert| to `1`.
+
+ Either this setting or |g:ale_echo_cursor| must be set to `1` before ALE is
+ loaded for messages to be displayed. See |ale-lint-settings-on-startup|.
+
g:ale_echo_cursor *g:ale_echo_cursor*
@@ -903,11 +940,14 @@ g:ale_echo_cursor *g:ale_echo_cursor*
cursor is near a warning or error. ALE will attempt to find the warning or
error at a column nearest to the cursor when the cursor is resting on a line
which contains a warning or error. This option can be set to `0` to disable
- this behaviour.
- The format of the message can be customizable in |g:ale_echo_msg_format|.
+ this behavior.
- You should set this setting once before ALE is loaded, and restart Vim if
- you want to change your preferences. See |ale-lint-settings-on-startup|.
+ Messages are only displayed after a short delay. See |g:ale_echo_delay|.
+
+ The format of the message can be customized with |g:ale_echo_msg_format|.
+
+ Either this setting or |g:ale_cursor_detail| must be set to `1` before ALE
+ is loaded for messages to be displayed. See |ale-lint-settings-on-startup|.
g:ale_echo_delay *g:ale_echo_delay*
@@ -916,7 +956,7 @@ g:ale_echo_delay *g:ale_echo_delay*
Default: `10`
Given any integer, this option controls the number of milliseconds before
- ALE will echo a message for a problem near the cursor.
+ ALE will echo or preview a message for a problem near the cursor.
The value can be increased to decrease the amount of processing ALE will do
for files displaying a large number of problems.
@@ -1163,6 +1203,12 @@ g:ale_lint_on_text_changed *g:ale_lint_on_text_changed*
ALE will check buffers after a short delay, with a timer which resets on
each change. The delay can be configured by adjusting the |g:ale_lint_delay|
variable.
+ *ale-linting-interrupts-mapping*
+
+ Due to a bug in Vim, ALE can interrupt mappings with pending key presses,
+ per |timeoutlen|. If this happens, follow the advice for enabling
+ |g:ale_lint_on_insert_leave| below, and set this option to `'normal'`, or
+ disable it entirely.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
@@ -1178,7 +1224,7 @@ g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave*
ALE will not lint files when you escape insert mode with |CTRL-C| by
default. You can make ALE lint files with this option when you use |CTRL-C|
- with the following keybind. >
+ with the following mapping. >
" Make using Ctrl+C do the same as Escape, to trigger autocmd commands
inoremap <C-c> <Esc>
diff --git a/plugin/ale.vim b/plugin/ale.vim
index ffb5da8a..41da7c74 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -109,6 +109,13 @@ let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax'))
" This flag can be set to 0 to disable echoing when the cursor moves.
let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
+" This flag can be set to 1 to automatically show errors in the preview window.
+let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', 0)
+
+" This flag can be set to 1 to automatically close the preview window upon
+" entering Insert Mode.
+let g:ale_close_preview_on_insert = get(g:, 'ale_close_preview_on_insert', 0)
+
" This flag can be set to 0 to disable balloon support.
let g:ale_set_balloons = get(g:, 'ale_set_balloons', has('balloon_eval') && has('gui_running'))
@@ -126,6 +133,9 @@ let g:ale_history_log_output = get(g:, 'ale_history_log_output', 1)
" Enable automatic completion with LSP servers and tsserver
let g:ale_completion_enabled = get(g:, 'ale_completion_enabled', 0)
+" Enable automatic detection of pipenv for Python linters.
+let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
+
if g:ale_set_balloons
call ale#balloon#Enable()
endif
@@ -217,4 +227,8 @@ augroup ALECleanupGroup
" Clean up buffers automatically when they are unloaded.
autocmd BufDelete * if exists('*ale#engine#Cleanup') | call ale#engine#Cleanup(str2nr(expand('<abuf>'))) | endif
autocmd QuitPre * call ale#events#QuitEvent(str2nr(expand('<abuf>')))
+
+ if exists('##VimSuspend')
+ autocmd VimSuspend * if exists('*ale#engine#CleanupEveryBuffer') | call ale#engine#CleanupEveryBuffer() | endif
+ endif
augroup END
diff --git a/test/command_callback/test_brakeman_command_callback.vader b/test/command_callback/test_brakeman_command_callback.vader
index 61be4caf..15dbbe1c 100644
--- a/test/command_callback/test_brakeman_command_callback.vader
+++ b/test/command_callback/test_brakeman_command_callback.vader
@@ -12,7 +12,8 @@ Execute(The brakeman command callback should detect absence of a valid Rails app
Execute(The brakeman command callback should find a valid Rails app root):
call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/db/test.rb')
- AssertLinter 'brakeman', 'brakeman -f json -q -p '
+ AssertLinter 'brakeman', ale#Escape('brakeman')
+ \ . ' -f json -q -p '
\ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
Execute(The brakeman command callback should include configured options):
@@ -20,5 +21,17 @@ Execute(The brakeman command callback should include configured options):
let g:ale_ruby_brakeman_options = '--combobulate'
- AssertLinter 'brakeman', 'brakeman -f json -q --combobulate -p '
+ AssertLinter 'brakeman', ale#Escape('brakeman')
+ \ . ' -f json -q --combobulate -p '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
+
+Execute(Setting bundle appends 'exec brakeman'):
+ call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/db/test.rb')
+
+ let g:ale_ruby_brakeman_executable = 'bundle'
+ let g:ale_ruby_brakeman_options = '--combobulate'
+
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec brakeman'
+ \ . ' -f json -q --combobulate -p '
\ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader
index f12b6747..ede511e0 100644
--- a/test/command_callback/test_flake8_command_callback.vader
+++ b/test/command_callback/test_flake8_command_callback.vader
@@ -1,5 +1,6 @@
Before:
call ale#assert#SetUpLinterTest('python', 'flake8')
+
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
WithChainResults ['3.0.0']
@@ -152,8 +153,16 @@ Execute(Using `python -m flake8` should be supported for running flake8):
Execute(Setting executable to 'pipenv' should append 'run flake8'):
let g:ale_python_flake8_executable = 'path/to/pipenv'
- " FIXME: pipenv should check the vresion with flake8.
+ " FIXME: pipenv should check the version with flake8.
WithChainResults []
AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run flake8 --format=default -'
+
+Execute(Pipenv is detected when python_flake8_auto_pipenv is set):
+ let g:ale_python_flake8_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -'
diff --git a/test/command_callback/test_gobuild_command_callback.vader b/test/command_callback/test_gobuild_command_callback.vader
index f9673213..8acbec56 100644
--- a/test/command_callback/test_gobuild_command_callback.vader
+++ b/test/command_callback/test_gobuild_command_callback.vader
@@ -1,9 +1,12 @@
Before:
+ Save g:ale_go_go_executable
+
call ale#assert#SetUpLinterTest('go', 'gobuild')
WithChainResults ['/foo/bar', '/foo/baz']
After:
+ Restore
call ale#assert#TearDownLinterTest()
Execute(The default commands should be correct):
@@ -17,3 +20,12 @@ Execute(Extra options should be supported):
AssertLinter 'go',
\ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
\ . 'go test --foo-bar -c -o /dev/null ./'
+
+ let g:ale_go_gobuild_options = ''
+
+Execute(The executable should be configurable):
+ let g:ale_go_go_executable = 'foobar'
+
+ AssertLinter 'foobar',
+ \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ . 'foobar test -c -o /dev/null ./'
diff --git a/test/command_callback/test_golangci_lint_command_callback.vader b/test/command_callback/test_golangci_lint_command_callback.vader
index 6cb73246..b3805f3a 100644
--- a/test/command_callback/test_golangci_lint_command_callback.vader
+++ b/test/command_callback/test_golangci_lint_command_callback.vader
@@ -9,7 +9,7 @@ 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'))
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all'
Execute(The golangci-lint callback should use a configured executable):
@@ -18,7 +18,7 @@ Execute(The golangci-lint callback should use a configured executable):
AssertLinter 'something else',
\ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
\ . ale#Escape('something else')
- \ . ' run ' . ale#util#EscapePCRE(expand('%' . ':t'))
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all'
Execute(The golangci-lint callback should use configured options):
@@ -27,7 +27,7 @@ Execute(The golangci-lint callback should use configured options):
AssertLinter 'golangci-lint',
\ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
\ . ale#Escape('golangci-lint')
- \ . ' run ' . ale#util#EscapePCRE(expand('%' . ':t'))
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --foobar'
Execute(The golangci-lint `lint_package` option should use the correct command):
diff --git a/test/command_callback/test_govet_command_callback.vader b/test/command_callback/test_govet_command_callback.vader
index 3718e0a7..ab93a5cb 100644
--- a/test/command_callback/test_govet_command_callback.vader
+++ b/test/command_callback/test_govet_command_callback.vader
@@ -1,12 +1,19 @@
Before:
+ Save g:ale_go_go_executable
+ Save g:ale_go_govet_options
call ale#assert#SetUpLinterTest('go', 'govet')
After:
+ Restore
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'go', 'cd ' . ale#Escape(expand('%:p:h')) . ' && go vet .'
+ AssertLinter 'go', 'cd ' . ale#Escape(expand('%:p:h')) . ' && go vet .'
Execute(Extra options should be supported):
let g:ale_go_govet_options = '--foo-bar'
- AssertLinter 'go', 'cd ' . ale#Escape(expand('%:p:h')) . ' && go vet . --foo-bar'
+ AssertLinter 'go', 'cd ' . ale#Escape(expand('%:p:h')) . ' && go vet --foo-bar .'
+
+Execute(The executable should be configurable):
+ let g:ale_go_go_executable = 'foobar'
+ AssertLinter 'foobar', 'cd ' . ale#Escape(expand('%:p:h')) . ' && foobar vet .'
diff --git a/test/command_callback/test_haskell_hlint_command_callbacks.vader b/test/command_callback/test_haskell_hlint_command_callbacks.vader
new file mode 100644
index 00000000..fb354ed4
--- /dev/null
+++ b/test/command_callback/test_haskell_hlint_command_callbacks.vader
@@ -0,0 +1,16 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'hlint')
+ let b:base_opts = '--color=never --json -'
+
+After:
+ unlet! b:base_opts
+ call ale#assert#TearDownLinterTest()
+
+Execute(executable should be configurable):
+ AssertLinter 'hlint', ale#Escape('hlint') . ' ' . b:base_opts
+ let b:ale_haskell_hlint_executable = 'myHlint'
+ AssertLinter 'myHlint', ale#Escape('myHlint') . ' ' . b:base_opts
+
+Execute(should accept options):
+ let b:ale_haskell_hlint_options= '-h myhlintfile.yaml'
+ AssertLinter 'hlint', ale#Escape('hlint') . ' -h myhlintfile.yaml ' . b:base_opts
diff --git a/test/command_callback/test_julia_languageserver_callbacks.vader b/test/command_callback/test_julia_languageserver_callbacks.vader
index a1f3a1ae..3bc46e3d 100644
--- a/test/command_callback/test_julia_languageserver_callbacks.vader
+++ b/test/command_callback/test_julia_languageserver_callbacks.vader
@@ -1,14 +1,18 @@
Before:
+ Save g:ale_julia_executable
+
call ale#assert#SetUpLinterTest('julia', 'languageserver')
After:
+ Restore
+
call ale#assert#TearDownLinterTest()
Execute(The default executable path should be correct):
AssertLinter 'julia',
\ ale#Escape('julia') .
\' --startup-file=no --history-file=no -e ' .
- \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(STDIN, STDOUT, false); server.runlinter = true; run(server);')
+ \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
Execute(The executable should be configurable):
let g:ale_julia_executable = 'julia-new'
@@ -16,7 +20,7 @@ Execute(The executable should be configurable):
AssertLinter 'julia-new',
\ ale#Escape('julia-new') .
\' --startup-file=no --history-file=no -e ' .
- \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(STDIN, STDOUT, false); server.runlinter = true; run(server);')
+ \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
Execute(The project root should be detected correctly):
AssertLSPProject ''
diff --git a/test/command_callback/test_mypy_command_callback.vader b/test/command_callback/test_mypy_command_callback.vader
index 988dfb1b..037d8176 100644
--- a/test/command_callback/test_mypy_command_callback.vader
+++ b/test/command_callback/test_mypy_command_callback.vader
@@ -69,3 +69,11 @@ Execute(Setting executable to 'pipenv' appends 'run mypy'):
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run mypy'
\ . ' --show-column-numbers --shadow-file %s %t %s'
+
+Execute(Pipenv is detected when python_mypy_auto_pipenv is set):
+ let g:ale_python_mypy_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run mypy --show-column-numbers --shadow-file %s %t %s'
diff --git a/test/command_callback/test_prospector_command_callback.vader b/test/command_callback/test_prospector_command_callback.vader
index 316b9883..0d692bde 100644
--- a/test/command_callback/test_prospector_command_callback.vader
+++ b/test/command_callback/test_prospector_command_callback.vader
@@ -10,3 +10,11 @@ Execute(Setting executable to 'pipenv' appends 'run prospector'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run prospector'
\ . ' --messages-only --absolute-paths --zero-exit --output-format json %s'
+
+Execute(Pipenv is detected when python_prospector_auto_pipenv is set):
+ let g:ale_python_prospector_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run prospector'
+ \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s'
diff --git a/test/command_callback/test_psalm_command_callbacks.vader b/test/command_callback/test_psalm_command_callbacks.vader
new file mode 100644
index 00000000..4c31b7b4
--- /dev/null
+++ b/test/command_callback/test_psalm_command_callbacks.vader
@@ -0,0 +1,12 @@
+Before:
+ call ale#assert#SetUpLinterTest('php', 'psalm')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Custom executables should be used for the executable and command):
+ let g:ale_php_psalm_executable = 'psalm_test'
+
+ AssertLinter 'psalm_test',
+ \ ale#Escape('psalm_test') . ' --diff --output-format=emacs %s'
+
diff --git a/test/command_callback/test_pycodestyle_command_callback.vader b/test/command_callback/test_pycodestyle_command_callback.vader
index 851eede9..a3a338a9 100644
--- a/test/command_callback/test_pycodestyle_command_callback.vader
+++ b/test/command_callback/test_pycodestyle_command_callback.vader
@@ -24,3 +24,10 @@ Execute(Setting executable to 'pipenv' appends 'run pycodestyle'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pycodestyle -'
+
+Execute(Pipenv is detected when python_pycodestyle_auto_pipenv is set):
+ let g:ale_python_pycodestyle_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pycodestyle -'
diff --git a/test/command_callback/test_pyflakes_command_callback.vader b/test/command_callback/test_pyflakes_command_callback.vader
index efc925fe..92f83820 100644
--- a/test/command_callback/test_pyflakes_command_callback.vader
+++ b/test/command_callback/test_pyflakes_command_callback.vader
@@ -37,3 +37,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyflakes'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pyflakes %t',
+
+Execute(Pipenv is detected when python_pyflakes_auto_pipenv is set):
+ let g:ale_python_pyflakes_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyflakes %t'
diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader
index be2908f9..6b21b127 100644
--- a/test/command_callback/test_pylint_command_callback.vader
+++ b/test/command_callback/test_pylint_command_callback.vader
@@ -68,3 +68,12 @@ Execute(Setting executable to 'pipenv' appends 'run pylint'):
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
+
+Execute(Pipenv is detected when python_pylint_auto_pipenv is set):
+ let g:ale_python_pylint_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run pylint'
+ \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
diff --git a/test/command_callback/test_pyls_command_callback.vader b/test/command_callback/test_pyls_command_callback.vader
index 53bf3000..531b5b3b 100644
--- a/test/command_callback/test_pyls_command_callback.vader
+++ b/test/command_callback/test_pyls_command_callback.vader
@@ -38,3 +38,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyls'):
let g:ale_python_pyls_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run pyls'
+
+Execute(Pipenv is detected when python_pyls_auto_pipenv is set):
+ let g:ale_python_pyls_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyls'
diff --git a/test/command_callback/test_pyre_command_callback.vader b/test/command_callback/test_pyre_command_callback.vader
index 6ad19b56..ba57c117 100644
--- a/test/command_callback/test_pyre_command_callback.vader
+++ b/test/command_callback/test_pyre_command_callback.vader
@@ -37,3 +37,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyre'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pyre persistent'
+
+Execute(Pipenv is detected when python_pyre_auto_pipenv is set):
+ let g:ale_python_pyre_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyre persistent'
diff --git a/test/command_callback/test_reek_command_callback.vader b/test/command_callback/test_reek_command_callback.vader
index 059e5e36..963247aa 100644
--- a/test/command_callback/test_reek_command_callback.vader
+++ b/test/command_callback/test_reek_command_callback.vader
@@ -7,8 +7,8 @@ After:
Execute(The reek callbacks should return the correct default values):
WithChainResults ['reek 5.0.0']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --stdin-filename %s',
\]
" Try with older versions.
@@ -16,19 +16,35 @@ Execute(The reek callbacks should return the correct default values):
WithChainResults ['reek 4.8.2']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color',
\]
+Execute(Setting bundle appends 'exec reek'):
+ let g:ale_ruby_reek_executable = 'bundle'
+
+ WithChainResults ['reek 5.0.0']
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec reek'
+ \ . ' -f json --no-progress --no-color --stdin-filename %s',
+
+ " Try with older versions.
+ call ale#semver#ResetVersionCache()
+
+ WithChainResults ['reek 4.8.2']
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec reek'
+ \ . ' -f json --no-progress --no-color'
+
Execute(The reek version check should be cached):
WithChainResults ['reek 5.0.0']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --stdin-filename %s',
\]
WithChainResults []
AssertLinter 'reek', [
\ '',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --stdin-filename %s',
\]
diff --git a/test/command_callback/test_ruby_solargraph.vader b/test/command_callback/test_ruby_solargraph.vader
index b9dd46d8..b39f686e 100644
--- a/test/command_callback/test_ruby_solargraph.vader
+++ b/test/command_callback/test_ruby_solargraph.vader
@@ -7,30 +7,33 @@ Before:
After:
call ale#assert#TearDownLinterTest()
+Execute(command callback should return default string):
+ AssertLinter 'solargraph', ale#Escape('solargraph') . ' stdio'
+
+Execute(command callback executable can be overridden):
+ let g:ale_ruby_solargraph_executable = 'foobar'
+ AssertLinter 'foobar', ale#Escape('foobar') . ' stdio'
+
Execute(should set solargraph for rails app):
call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/app/models/thing.rb')
AssertLSPLanguage 'ruby'
AssertLSPOptions {}
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_rails_app')
- AssertLSPAddress '127.0.0.1:7658'
Execute(should set solargraph for ruby app1):
call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app1/lib/file.rb')
AssertLSPLanguage 'ruby'
AssertLSPOptions {}
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app1')
- AssertLSPAddress '127.0.0.1:7658'
Execute(should set solargraph for ruby app2):
call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app2/lib/file.rb')
AssertLSPLanguage 'ruby'
AssertLSPOptions {}
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app2')
- AssertLSPAddress '127.0.0.1:7658'
Execute(should set solargraph for ruby app3):
call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app3/lib/file.rb')
AssertLSPLanguage 'ruby'
AssertLSPOptions {}
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app3')
- AssertLSPAddress '127.0.0.1:7658'
diff --git a/test/command_callback/test_thrift_command_callback.vader b/test/command_callback/test_thrift_command_callback.vader
index ea217259..cbada818 100644
--- a/test/command_callback/test_thrift_command_callback.vader
+++ b/test/command_callback/test_thrift_command_callback.vader
@@ -23,22 +23,22 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -I . -strict' . b:suffix
Execute(The executable should be configurable):
let b:ale_thrift_thrift_executable = 'foobar'
- AssertLinter 'foobar', ale#Escape('foobar') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --gen cpp -I . -strict' . b:suffix
Execute(The list of generators should be configurable):
let b:ale_thrift_thrift_generators = ['java', 'py:dynamic']
AssertLinter 'thrift', ale#Escape('thrift')
- \ . ' --gen java --gen py:dynamic -strict' . b:suffix
+ \ . ' --gen java --gen py:dynamic -I . -strict' . b:suffix
let b:ale_thrift_thrift_generators = []
- AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -I . -strict' . b:suffix
Execute(The list of include paths should be configurable):
let b:ale_thrift_thrift_includes = ['included/path']
@@ -50,4 +50,4 @@ Execute(The string of compiler options should be configurable):
let b:ale_thrift_thrift_options = '-strict --allow-64bit-consts'
AssertLinter 'thrift', ale#Escape('thrift')
- \ . ' --gen cpp -strict --allow-64bit-consts' . b:suffix
+ \ . ' --gen cpp -I . -strict --allow-64bit-consts' . b:suffix
diff --git a/test/completion/test_completion_filtering.vader b/test/completion/test_completion_filtering.vader
index ae91a952..ffb313ef 100644
--- a/test/completion/test_completion_filtering.vader
+++ b/test/completion/test_completion_filtering.vader
@@ -12,16 +12,17 @@ After:
Execute(Prefix filtering should work for Lists of strings):
AssertEqual
\ ['FooBar', 'foo'],
- \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], 'foo')
+ \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo')
AssertEqual
\ ['FooBar', 'FongBar', 'baz', 'foo'],
- \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], '.')
+ \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.')
Execute(Prefix filtering should work for completion items):
AssertEqual
\ [{'word': 'FooBar'}, {'word': 'foo'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'FooBar'},
\ {'word': 'FongBar'},
@@ -40,6 +41,7 @@ Execute(Prefix filtering should work for completion items):
\ ],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'FooBar'},
\ {'word': 'FongBar'},
@@ -56,6 +58,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Italian'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'Italian'},
\ {'word': 'it'},
@@ -67,6 +70,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Deutsch'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'describe'},
\ {'word': 'Deutsch'},
@@ -78,6 +82,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Deutsch'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'describe'},
\ {'word': 'Deutsch'},
@@ -90,19 +95,26 @@ Execute(Excluding words from completion results should work with lists of String
AssertEqual
\ ['Italian'],
- \ ale#completion#Filter(bufnr(''), ['Italian', 'it'], 'it')
+ \ ale#completion#Filter(bufnr(''), '', ['Italian', 'it'], 'it')
AssertEqual
\ ['Deutsch'],
- \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], 'de')
+ \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], 'de')
AssertEqual
\ ['Deutsch'],
- \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], '.')
+ \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], '.')
Execute(Filtering shouldn't modify the original list):
let b:ale_completion_excluded_words = ['it', 'describe']
let b:suggestions = [{'word': 'describe'}]
- AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, '.')
+ AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, '.')
AssertEqual b:suggestions, [{'word': 'describe'}]
- AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, 'de')
+ AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, 'de')
AssertEqual b:suggestions, [{'word': 'describe'}]
+
+Execute(Filtering should respect filetype triggers):
+ let b:suggestions = [{'word': 'describe'}]
+
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), '', b:suggestions, '.')
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '.')
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '::')
diff --git a/test/completion/test_lsp_completion_parsing.vader b/test/completion/test_lsp_completion_parsing.vader
index d5a45b54..71e53ab6 100644
--- a/test/completion/test_lsp_completion_parsing.vader
+++ b/test/completion/test_lsp_completion_parsing.vader
@@ -447,3 +447,27 @@ Execute(Should handle missing keys):
\ ]
\ }
\ })
+
+Execute(Should handle documentation in the markdown format):
+ AssertEqual
+ \ [
+ \ {'word': 'migrations', 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1},
+ \ ],
+ \ ale#completion#ParseLSPCompletions({
+ \ 'jsonrpc': '2.0',
+ \ 'id': 6,
+ \ 'result': {
+ \ 'isIncomplete': v:false,
+ \ 'items': [
+ \ {
+ \ 'label': 'migrations',
+ \ 'kind': 3,
+ \ 'detail': 'xxx',
+ \ 'documentation': {
+ \ 'kind': 'markdown',
+ \ 'value': 'Markdown documentation',
+ \ },
+ \ },
+ \ ],
+ \ },
+ \ })
diff --git a/test/fixers/test_eslint_fixer_callback.vader b/test/fixers/test_eslint_fixer_callback.vader
index be33825c..774595e3 100644
--- a/test/fixers/test_eslint_fixer_callback.vader
+++ b/test/fixers/test_eslint_fixer_callback.vader
@@ -170,3 +170,10 @@ Execute(The eslint_d post-processor should handle error messages correctly):
\ ale#fixers#eslint#ProcessEslintDOutput(bufnr(''), [
\ 'Error: No ESLint configuration found.',
\ ])
+
+Execute(The eslint_d post-processor should handle failing to connect properly):
+ AssertEqual
+ \ [],
+ \ ale#fixers#eslint#ProcessEslintDOutput(bufnr(''), [
+ \ 'Could not connect',
+ \ ])
diff --git a/test/fixers/test_gomod_fixer_callback.vader b/test/fixers/test_gomod_fixer_callback.vader
new file mode 100644
index 00000000..a378e961
--- /dev/null
+++ b/test/fixers/test_gomod_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_go_go_executable
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_go_go_executable = 'xxxinvalid'
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The gomod callback should return the correct default values):
+ call ale#test#SetFilename('../go_files/go.mod')
+ setl ft=gomod
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' mod edit -fmt'
+ \ . ' %t',
+ \ },
+ \ ale#fixers#gomod#Fix(bufnr(''))
diff --git a/test/fixers/test_python_add_blank_lines_fixer.vader b/test/fixers/test_python_add_blank_lines_fixer.vader
index 4a91aa10..7d042c8a 100644
--- a/test/fixers/test_python_add_blank_lines_fixer.vader
+++ b/test/fixers/test_python_add_blank_lines_fixer.vader
@@ -6,15 +6,22 @@ After:
Given python(Some Python without blank lines):
def foo():
+ """ This is a simple test docstring """
return 1
def bar():
+ '''This is another simple test docstring'''
return 1
return 4
def bar():
+ """
+ This is a multi-line
+ docstring
+ """
+
if x:
pass
for l in x:
@@ -44,16 +51,25 @@ Execute(Blank lines should be added appropriately):
Expect python(Newlines should be added):
def foo():
+ """ This is a simple test docstring """
+
return 1
def bar():
+ '''This is another simple test docstring'''
+
return 1
return 4
def bar():
+ """
+ This is a multi-line
+ docstring
+ """
+
if x:
pass
@@ -109,3 +125,43 @@ Expect python(extra newlines shouldn't be added to the main block):
if __name__ == '__main__':
main()
+
+
+Given python(A file with variables/docstring that start with a control statement):
+ def some():
+ """
+ This is a docstring that contains an
+ break control statement and also contains a
+ return something funny.
+ """
+
+ continue_some_var = True
+ forward_something = False
+
+ if (
+ continue_some_var and
+ forwarded_something
+ ):
+ return True
+
+
+Execute(Fix the file):
+ let g:ale_fixers = {'python': ['add_blank_lines_for_python_control_statements']}
+ ALEFix
+
+Expect python(Extra new lines are not added to the file):
+ def some():
+ """
+ This is a docstring that contains an
+ break control statement and also contains a
+ return something funny.
+ """
+
+ continue_some_var = True
+ forward_something = False
+
+ if (
+ continue_some_var and
+ forwarded_something
+ ):
+ return True
diff --git a/test/fixers/test_shfmt_fixer_callback.vader b/test/fixers/test_shfmt_fixer_callback.vader
index 5dc6e863..99cb0987 100644
--- a/test/fixers/test_shfmt_fixer_callback.vader
+++ b/test/fixers/test_shfmt_fixer_callback.vader
@@ -1,17 +1,52 @@
Before:
Save g:ale_sh_shfmt_executable
Save g:ale_sh_shfmt_options
+ Save &l:expandtab
+ Save &l:shiftwidth
+ Save &l:tabstop
After:
Restore
-Execute(The shfmt callback should return the correct default values):
+Execute(The shfmt callback should return 'shfmt' as default command):
+ setlocal noexpandtab
+ Assert
+ \ ale#fixers#shfmt#Fix(bufnr('')).command =~# '^' . ale#Escape('shfmt'),
+ \ "Default command name is expected to be 'shfmt'"
+
+Execute(The shfmt callback should return the command with no option as default when noexpandtab is set):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal noexpandtab
AssertEqual
\ {
\ 'command': ale#Escape('shfmt'),
\ },
\ ale#fixers#shfmt#Fix(bufnr(''))
+Execute(The shfmt callback should return the command specifying indent width by looking shiftwidth as default):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal expandtab
+ setlocal shiftwidth=4
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('shfmt') . ' -i 4',
+ \ },
+ \ ale#fixers#shfmt#Fix(bufnr(''))
+
+Execute(The shfmt callback should return the command specifying indent width by looking tabstop when shiftwidth is 0 as default):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal expandtab
+ setlocal shiftwidth=0
+ setlocal tabstop=8
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('shfmt') . ' -i 8',
+ \ },
+ \ ale#fixers#shfmt#Fix(bufnr(''))
+
Execute(The shfmt executable and options should be configurable):
let g:ale_sh_shfmt_executable = 'foobar'
let g:ale_sh_shfmt_options = '--some-option'
diff --git a/test/go_files/go.mod b/test/go_files/go.mod
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/go_files/go.mod
@@ -0,0 +1 @@
+
diff --git a/test/handler/test_eslint_handler.vader b/test/handler/test_eslint_handler.vader
index 2e8bfd2a..4a57927b 100644
--- a/test/handler/test_eslint_handler.vader
+++ b/test/handler/test_eslint_handler.vader
@@ -365,3 +365,15 @@ Execute(eslint should handle react errors correctly):
\ ale#handlers#eslint#Handle(bufnr(''), [
\ '/path/editor-help.jsx:59:9: Property should be placed on the same line as the component declaration [Error/react/jsx-first-prop-new-line]',
\ ])
+
+Execute(Failing to connect to eslint_d should be handled correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.',
+ \ },
+ \ ],
+ \ ale#handlers#eslint#Handle(bufnr(''), [
+ \ 'Could not connect',
+ \ ])
diff --git a/test/handler/test_php_psalm_handler.vader b/test/handler/test_php_psalm_handler.vader
new file mode 100644
index 00000000..fd62a467
--- /dev/null
+++ b/test/handler/test_php_psalm_handler.vader
@@ -0,0 +1,24 @@
+Before:
+ runtime ale_linters/php/psalm.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The php static analyzer handler should parse errors from psalm):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'type': 'W',
+ \ 'text': 'somewarning',
+ \ },
+ \ {
+ \ 'lnum': 11,
+ \ 'type': 'E',
+ \ 'text': 'someerror',
+ \ },
+ \ ],
+ \ ale_linters#php#psalm#Handle(347, [
+ \ "/file:1:3:warning - somewarning",
+ \ "/file:11:33:error - someerror",
+ \ ])
diff --git a/test/python_fixtures/pipenv/Pipfile.lock b/test/python_fixtures/pipenv/Pipfile.lock
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/python_fixtures/pipenv/Pipfile.lock
diff --git a/test/test_autocmd_commands.vader b/test/test_autocmd_commands.vader
index 8d5048f0..4bb894ba 100644
--- a/test/test_autocmd_commands.vader
+++ b/test/test_autocmd_commands.vader
@@ -175,10 +175,19 @@ Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event):
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''\v^FileType''')
Execute (ALECleanupGroup should include the right commands):
- AssertEqual [
- \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
- \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
- \], CheckAutocmd('ALECleanupGroup')
+ if exists('##VimSuspend')
+ AssertEqual [
+ \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
+ \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
+ \ 'VimSuspend * if exists(''*ale#engine#CleanupEveryBuffer'') | call ale#engine#CleanupEveryBuffer() | endif',
+ \], CheckAutocmd('ALECleanupGroup')
+ else
+ AssertEqual [
+ \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
+ \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
+ \], CheckAutocmd('ALECleanupGroup')
+ endif
+
Execute(Enabling completion should set up autocmd events correctly):
let g:ale_completion_enabled = 0
diff --git a/test/test_c_flag_parsing.vader b/test/test_c_flag_parsing.vader
index a4e00452..f7bfaa04 100644
--- a/test/test_c_flag_parsing.vader
+++ b/test/test_c_flag_parsing.vader
@@ -74,7 +74,7 @@ Execute(ParseCFlags should ignore -T and other arguments):
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir --sysroot=subdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
diff --git a/test/test_python_pipenv.vader b/test/test_python_pipenv.vader
new file mode 100644
index 00000000..91d957f8
--- /dev/null
+++ b/test/test_python_pipenv.vader
@@ -0,0 +1,13 @@
+Execute(ale#python#PipenvPresent is true when a pipenv environment is present):
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertEqual
+ \ ale#python#PipenvPresent(bufnr('%')),
+ \ 1
+
+Execute(ale#python#PipenvPresent is false true when no pipenv environment is present):
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/no_pipenv/whatever.py')
+
+ AssertEqual
+ \ ale#python#PipenvPresent(bufnr('%')),
+ \ 0
diff --git a/test/test_redundant_tsserver_rendering_avoided.vader b/test/test_redundant_tsserver_rendering_avoided.vader
new file mode 100644
index 00000000..41cbe5e0
--- /dev/null
+++ b/test/test_redundant_tsserver_rendering_avoided.vader
@@ -0,0 +1,136 @@
+Before:
+ Save g:ale_buffer_info
+
+ function! CreateError(type, message) abort
+ let l:diagnostics = []
+
+ if !empty(a:message)
+ let l:diagnostics = [{
+ \ 'start': {'line': 1, 'offset': 1},
+ \ 'end': {'line': 1, 'offset':1},
+ \ 'text': a:message,
+ \ 'code': 1005,
+ \}]
+ endif
+
+ return {
+ \ 'seq': 0,
+ \ 'type': 'event',
+ \ 'event': a:type,
+ \ 'body': {'file': expand('%:p'), 'diagnostics': l:diagnostics},
+ \}
+ endfunction
+
+ function! CreateLoclist(message) abort
+ let l:list = []
+
+ if !empty(a:message)
+ let l:list = [{
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'end_lnum': 1,
+ \ 'end_col': 1,
+ \ 'text': a:message,
+ \}]
+ endif
+
+ return l:list
+ endfunction
+
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('filename.ts')
+
+ runtime autoload/ale/engine.vim
+
+ let g:ale_buffer_info = {bufnr(''): {'loclist': []}}
+ let g:ale_handle_loclist_called = 0
+
+ function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
+ let g:ale_handle_loclist_called = 1
+ endfunction
+
+After:
+ Restore
+
+ delfunction CreateError
+ delfunction CreateLoclist
+
+ call ale#test#RestoreDirectory()
+
+ runtime autoload/ale/engine.vim
+
+Execute(An initial empty list of syntax errors should be ignored):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(An initial list of syntax errors should be handled):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Subsequent empty lists should be ignored):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(Empty then non-empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then non-empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(An initial empty list of semantic errors should be ignored):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(An initial list of semantic errors should be handled):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Subsequent empty lists should be ignored):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(Empty then non-empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then non-empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
diff --git a/test/test_writefile_function.vader b/test/test_writefile_function.vader
index 4e4aab53..8c8a6f17 100644
--- a/test/test_writefile_function.vader
+++ b/test/test_writefile_function.vader
@@ -28,7 +28,26 @@ Execute(Carriage returns should be included for ale#util#Writefile):
AssertEqual
\ ["first\r", "second\r", "third\r", ''],
\ readfile('.newline-test', 'b')
- \
+
+Given(A file with extra carriage returns):
+ first
+ second
+ third
+ fourth
+
+Execute(Carriage returns should be de-depulicated):
+ call ale#test#SetFilename('.newline-test')
+
+ setlocal buftype=
+ noautocmd :w
+ noautocmd :e! ++ff=dos
+
+ call ale#util#Writefile(bufnr(''), getline(1, '$'), '.newline-test')
+
+ AssertEqual
+ \ ["first\r", "second\r", "third\r", "fourth\r", ''],
+ \ readfile('.newline-test', 'b')
+
Given(A file with Unix line ending characters):
first
second