mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-07 05:04:28 +08:00
Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a94f7aaa7e | ||
|
|
21c4b9033a | ||
|
|
f382afbe23 | ||
|
|
4da8c3607d | ||
|
|
c3844db973 | ||
|
|
8a374a69a3 | ||
|
|
68bae8a1d1 | ||
|
|
b8dcdc984b | ||
|
|
c6d3d646ac | ||
|
|
c8de2d9766 | ||
|
|
6d50074984 | ||
|
|
6b87dd24ee | ||
|
|
11fafbfd66 | ||
|
|
06c3ee61e4 | ||
|
|
5a88395bbb | ||
|
|
73ec83d055 | ||
|
|
908e94622e | ||
|
|
b9cf450684 | ||
|
|
e13651c16d | ||
|
|
cdd1ddffdb | ||
|
|
8f8d015dae | ||
|
|
4bea50b82f | ||
|
|
623fdf212c | ||
|
|
0507503aa7 | ||
|
|
80c7fbcefe | ||
|
|
2f19cf874b | ||
|
|
1a524ca63e | ||
|
|
47a8ebc8b9 | ||
|
|
9d3bda4441 | ||
|
|
b356d56448 | ||
|
|
a3299bf03a | ||
|
|
cc02eb8a5a | ||
|
|
456378cb53 | ||
|
|
47e681529b | ||
|
|
4c6b58f70c | ||
|
|
d646ebda72 | ||
|
|
c7193e775e | ||
|
|
753cf5da95 | ||
|
|
5a9a365aed | ||
|
|
e5d0a17694 | ||
|
|
7112776d1b | ||
|
|
fb0adc602e | ||
|
|
9d6883561c | ||
|
|
b2d3764a18 | ||
|
|
20e64fbae0 | ||
|
|
f8de08faf0 | ||
|
|
18cb9a725d | ||
|
|
e9e1bec772 | ||
|
|
fb0c931b2d | ||
|
|
5c839c4825 | ||
|
|
9c6e25d8d8 | ||
|
|
be4347084e | ||
|
|
8cc7cd3aa1 | ||
|
|
41c4f3431c | ||
|
|
2560cdd56e | ||
|
|
2365fd2948 | ||
|
|
0a282eb76a | ||
|
|
342e83db60 | ||
|
|
17a76a7403 | ||
|
|
797b03b35e | ||
|
|
5af82312fb | ||
|
|
1680f7af63 | ||
|
|
79701f6f20 | ||
|
|
2d02de33d4 | ||
|
|
ea124c49d0 | ||
|
|
a5d7bb449b | ||
|
|
626568d66d | ||
|
|
ae6cecabb6 | ||
|
|
f67fc43d9b | ||
|
|
c6d11f4281 | ||
|
|
b6f0b17eaf | ||
|
|
bc548b2ef9 | ||
|
|
e6b6146731 | ||
|
|
b300b0646d | ||
|
|
c14886e479 | ||
|
|
c52a4910bf | ||
|
|
7614560a6e | ||
|
|
8e9130d66e | ||
|
|
78b9ae0f1c | ||
|
|
d5ae3201a4 | ||
|
|
b1462ac66c | ||
|
|
322910dc0b | ||
|
|
dcf7cbe366 | ||
|
|
34aa3437e0 | ||
|
|
0c26e8945c | ||
|
|
9ae2df1958 | ||
|
|
7dee9da0f2 | ||
|
|
2dcd2ee4da | ||
|
|
b9f31621e4 | ||
|
|
abcf2909e6 | ||
|
|
4709e67627 | ||
|
|
2b546a50dc | ||
|
|
fe95fcd357 | ||
|
|
670858f774 | ||
|
|
ac8cc6d991 | ||
|
|
16772298ab | ||
|
|
a535d07f28 | ||
|
|
5010ddc28f | ||
|
|
16cfedf04a | ||
|
|
2edea15358 | ||
|
|
c18451fba9 | ||
|
|
2c4700ab7f | ||
|
|
39ebb431b6 | ||
|
|
f7d7abe5b2 | ||
|
|
2d608b9329 | ||
|
|
593cafa18b | ||
|
|
747d4fe80b | ||
|
|
666cfc6ee2 | ||
|
|
9ac74c44fe | ||
|
|
d1023e9c2c | ||
|
|
09d50ebe31 | ||
|
|
a3d2fb5688 | ||
|
|
617582c5d3 | ||
|
|
6e07cf5b12 | ||
|
|
1356cf8e01 | ||
|
|
db531171ac | ||
|
|
d6557b2c5c | ||
|
|
ad4c7f92cf | ||
|
|
bc1cf285c2 | ||
|
|
7eb84242ee | ||
|
|
35913d9ce7 | ||
|
|
a4ffd2f37c | ||
|
|
ec82530247 | ||
|
|
7c32ef104b | ||
|
|
eaeb71993f | ||
|
|
79d4935ccf | ||
|
|
2c252c0f12 | ||
|
|
6000d956f0 | ||
|
|
5810d7faa0 | ||
|
|
84af543907 | ||
|
|
63b9d9e9df | ||
|
|
fa33faad9e | ||
|
|
db4d68eae7 | ||
|
|
ded1bc14df | ||
|
|
810e884dbe | ||
|
|
fbf59fd4ce | ||
|
|
cfdb41f4d2 | ||
|
|
e6f527f954 | ||
|
|
cd860e3e8d | ||
|
|
86297a7c65 | ||
|
|
e45c16d9bb | ||
|
|
e0c014ab8c | ||
|
|
b4d23d700b | ||
|
|
d1424de1f9 | ||
|
|
8ab632e6f2 | ||
|
|
a0059cfe03 | ||
|
|
12217480f9 | ||
|
|
c1998b170c | ||
|
|
78e37dabb7 | ||
|
|
f3fec6685e | ||
|
|
ee6dabcc4e | ||
|
|
af6830a722 | ||
|
|
ce845e51f2 | ||
|
|
87616c5e91 | ||
|
|
7d1fde292d | ||
|
|
a5f754a5e0 | ||
|
|
ca83f11bee | ||
|
|
f133ce96f8 | ||
|
|
cbdf10a129 | ||
|
|
0b50ebb0f0 | ||
|
|
235fc90e22 | ||
|
|
aa94d0902a | ||
|
|
5a6ffc2804 | ||
|
|
0931e99ea4 | ||
|
|
a8a4df05e6 | ||
|
|
da410caff8 | ||
|
|
a6cc492a99 | ||
|
|
27feab7e3a | ||
|
|
eab77b7072 | ||
|
|
3b1bc2bd13 | ||
|
|
92918fd841 | ||
|
|
23ea62d40a | ||
|
|
3352a6c9df | ||
|
|
fe70742bb9 | ||
|
|
9e83878900 | ||
|
|
58717e05a3 | ||
|
|
54ff573174 | ||
|
|
bd5ff5b1e5 | ||
|
|
7d174b0056 | ||
|
|
1aea6a34ff | ||
|
|
4fa66ab627 | ||
|
|
15c48650e7 | ||
|
|
cad9fc19c6 | ||
|
|
507e32e91c | ||
|
|
5afbc9b701 | ||
|
|
4c50aec79c | ||
|
|
4c6c5bf84f | ||
|
|
b50ae96413 | ||
|
|
f7f6f6541d | ||
|
|
bc97735b6d | ||
|
|
dcbb0ffee5 | ||
|
|
5885954197 | ||
|
|
bc32e24203 | ||
|
|
400580e4e8 | ||
|
|
9e0d7a9d8c | ||
|
|
ff80b23ee1 | ||
|
|
b2be833744 | ||
|
|
340c0bbac5 | ||
|
|
d12e990f73 | ||
|
|
bbabdd0043 | ||
|
|
a96cc92edf | ||
|
|
7b73204f25 | ||
|
|
505d114a68 | ||
|
|
5c7b55edec | ||
|
|
768f761017 | ||
|
|
05d3bb12dd | ||
|
|
78e0029488 | ||
|
|
eb79b52a9a | ||
|
|
d787050fa8 | ||
|
|
29d0a20dc3 | ||
|
|
751d965265 | ||
|
|
b44f6053d1 | ||
|
|
82dd80c692 | ||
|
|
6a84605c57 | ||
|
|
b50a7318fb | ||
|
|
47ff514878 | ||
|
|
025f3407d6 | ||
|
|
ab0e76dbd5 | ||
|
|
836a2cfe3b | ||
|
|
c67d3b7e60 | ||
|
|
a70591fa76 | ||
|
|
ab47011ef2 | ||
|
|
1b55e5edab | ||
|
|
4fd5bf81be | ||
|
|
7def00d5a9 | ||
|
|
dd5806662a | ||
|
|
996732d5a6 | ||
|
|
fdc7166c3c | ||
|
|
f9aa7d3b9a | ||
|
|
8eb4f95766 | ||
|
|
46225f3bb1 | ||
|
|
d9a7364dae | ||
|
|
7ce960ae51 | ||
|
|
130928590b | ||
|
|
8315c0e337 | ||
|
|
854066e849 | ||
|
|
b43413916d | ||
|
|
5859050d29 | ||
|
|
af02fb5183 | ||
|
|
871ce1c8f5 | ||
|
|
1bd9b0fbe2 | ||
|
|
a04e73ddbc | ||
|
|
1b8450e7a0 | ||
|
|
35093e8f0d | ||
|
|
6ab92af181 | ||
|
|
e134eca694 | ||
|
|
18fef18ab1 | ||
|
|
7b7a275902 | ||
|
|
bb293b297c | ||
|
|
a1cf7f67a1 | ||
|
|
638eb1f000 | ||
|
|
84b280b881 | ||
|
|
def4466671 | ||
|
|
160b9548ee | ||
|
|
fd6f05c9ea | ||
|
|
5a3cfbbdf5 | ||
|
|
51f256e897 | ||
|
|
857ca941d2 | ||
|
|
b731bd77ab | ||
|
|
5b731f761f | ||
|
|
9f21e45156 | ||
|
|
0d8be55c51 | ||
|
|
2330837747 | ||
|
|
b2e730fb5e | ||
|
|
29746d492e | ||
|
|
64c6cbee48 | ||
|
|
3f1cab3e7e | ||
|
|
411c6b5e9f | ||
|
|
518f99b480 | ||
|
|
79e8e063af | ||
|
|
01ecf2a75f | ||
|
|
7eec1f2efc | ||
|
|
8846a8860f | ||
|
|
f883d4d4fd | ||
|
|
f984c5fb83 | ||
|
|
72161b82ef | ||
|
|
0302d2a328 | ||
|
|
e51272e277 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,4 +1,5 @@
|
||||
.* export-ignore
|
||||
/CODE_OF_CONDUCT.md export-ignore
|
||||
/CONTRIBUTING.md export-ignore
|
||||
/Dockerfile export-ignore
|
||||
/ISSUE_TEMPLATE.md export-ignore
|
||||
@@ -7,4 +8,5 @@
|
||||
/README.md export-ignore
|
||||
/custom-checks export-ignore
|
||||
/img export-ignore
|
||||
/run-tests export-ignore
|
||||
/test export-ignore
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
language: python
|
||||
script: |
|
||||
./run-tests
|
||||
|
||||
@@ -74,10 +74,10 @@ If you want to credit multiple authors, you can comma separate them.
|
||||
### 3.i. Adding a New Linter
|
||||
|
||||
If you add a new linter, look for existing handlers first in the
|
||||
[handlers.vim](autoload/ale/handlers.vim) file. One of the handlers there may
|
||||
[handlers](autoload/ale/handlers) directory. One of the handlers there may
|
||||
already be able to handle your lines of output. If you find that your new
|
||||
linter replicates an existing error handler, consider pulling it up into the
|
||||
[handlers.vim](autoload/ale/handlers.vim) file, and use the generic handler in
|
||||
[handlers](autoload/ale/handlers) directory, and use the generic handler in
|
||||
both places.
|
||||
|
||||
When you add a linter, make sure the language for the linter and the linter
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
<!--
|
||||
READ THIS FIRST: If you are experiencing any bug whatsoever dealing with
|
||||
the output of linters, please use `let g:ale_history_log_output = 1` before
|
||||
pasting output. It will capture the output of commands that are run.
|
||||
|
||||
For bugs, paste output from your clipboard after running :ALEInfoToClipboard
|
||||
here. If that doesn't work for some reason, try running :ALEInfo and copying
|
||||
the output from that here instead. If everything is broken, run around in
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016, w0rp <devw0rp@gmail.com>
|
||||
Copyright (c) 2016-2017, w0rp <devw0rp@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<!--
|
||||
When creating new pull requests, please consider the following.
|
||||
READ THIS: Before creating a pull request, please consider the following first.
|
||||
|
||||
* The most important thing you can do is write tests. Code without tests
|
||||
probably doesn't work, and will almost certainly stop working later on. Pull
|
||||
requests without tests probably won't be accepted, although there are some
|
||||
exceptions.
|
||||
* Read the Contributing guide linked above first.
|
||||
* If you are adding a new linter, remember to update the README.md file and
|
||||
doc/ale.txt first.
|
||||
|
||||
177
README.md
177
README.md
@@ -15,17 +15,21 @@ back to a filesystem.
|
||||
|
||||
In other words, this plugin allows you to lint while you type.
|
||||
|
||||
ALE also supports fixing problems with files by running commands in the
|
||||
background with a command `ALEFix`.
|
||||
In addition to linting support, ALE offers some support for fixing code with
|
||||
formatting tools, and completion via Language Server Protocol servers, or
|
||||
servers with similar enough protocols, like `tsserver`.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Supported Languages and Tools](#supported-languages)
|
||||
2. [Usage](#usage)
|
||||
1. [Linting](#usage-linting)
|
||||
2. [Fixing](#usage-fixing)
|
||||
3. [Completion](#usage-completion)
|
||||
3. [Installation](#installation)
|
||||
1. [Installation with Pathogen](#installation-with-pathogen)
|
||||
2. [Installation with Vundle](#installation-with-vundle)
|
||||
3. [Manual Installation](#manual-installation)
|
||||
1. [Installation with Vim package management](#standard-installation)
|
||||
2. [Installation with Pathogen](#installation-with-pathogen)
|
||||
3. [Installation with Vundle](#installation-with-vundle)
|
||||
4. [Contributing](#contributing)
|
||||
5. [FAQ](#faq)
|
||||
1. [How do I disable particular linters?](#faq-disable-linters)
|
||||
@@ -61,8 +65,8 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| Awk | [gawk](https://www.gnu.org/software/gawk/)|
|
||||
| Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) |
|
||||
| Bourne Shell | [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/) |
|
||||
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
|
||||
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [gcc](https://gcc.gnu.org/)|
|
||||
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/), [clang-format](https://clang.llvm.org/docs/ClangFormat.html)|
|
||||
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [gcc](https://gcc.gnu.org/), [clang-format](https://clang.llvm.org/docs/ClangFormat.html)|
|
||||
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
|
||||
| Chef | [foodcritic](http://www.foodcritic.io/) |
|
||||
| CMake | [cmakelint](https://github.com/richq/cmake-lint) |
|
||||
@@ -71,20 +75,23 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) |
|
||||
| Cython (pyrex filetype) | [cython](http://cython.org/) |
|
||||
| D | [dmd](https://dlang.org/dmd-linux.html) |
|
||||
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) |
|
||||
| Dockerfile | [hadolint](https://github.com/lukasmartinelli/hadolint) |
|
||||
| Elixir | [credo](https://github.com/rrrene/credo), [dogma](https://github.com/lpil/dogma) |
|
||||
| Elm | [elm-make](https://github.com/elm-lang/elm-make) |
|
||||
| Erb | [erb](https://github.com/jeremyevans/erubi) |
|
||||
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
|
||||
| Erb | [erb](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis) |
|
||||
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html), [SyntaxErl](https://github.com/ten0s/syntaxerl) |
|
||||
| Fortran | [gcc](https://gcc.gnu.org/) |
|
||||
| FusionScript | [fusion-lint](https://github.com/RyanSquared/fusionscript) |
|
||||
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [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) |
|
||||
| GraphQL | [gqlint](https://github.com/happylinks/gqlint) |
|
||||
| Haml | [haml-lint](https://github.com/brigade/haml-lint)
|
||||
| Handlebars | [ember-template-lint](https://github.com/rwjblue/ember-template-lint) |
|
||||
| Haskell | [ghc](https://www.haskell.org/ghc/), [ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) |
|
||||
| Haskell | [ghc](https://www.haskell.org/ghc/), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/), [ghc-mod](https://github.com/DanielG/ghc-mod), [stack-ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) |
|
||||
| HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) |
|
||||
| Idris | [idris](http://www.idris-lang.org/) |
|
||||
| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) |
|
||||
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/), [prettier](https://github.com/prettier/prettier) (and `prettier-eslint`), [xo](https://github.com/sindresorhus/xo)
|
||||
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/), [prettier](https://github.com/prettier/prettier) (and `prettier-eslint`, `prettier-standard`), [xo](https://github.com/sindresorhus/xo)
|
||||
| JSON | [jsonlint](http://zaa.ch/jsonlint/) |
|
||||
| Kotlin | [kotlinc](https://kotlinlang.org), [ktlint](https://ktlint.github.io) see `:help ale-integration-kotlin` for configuration instructions
|
||||
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/) |
|
||||
@@ -98,23 +105,26 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| Objective-C++ | [clang](http://clang.llvm.org/) |
|
||||
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions
|
||||
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
|
||||
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) |
|
||||
| PHP | [hack](http://hacklang.org/), [langserver](https://github.com/felixfbecker/php-language-server), [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) |
|
||||
| Pod | [proselint](http://proselint.com/)|
|
||||
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
|
||||
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
|
||||
| Python | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/), [yapf](https://github.com/google/yapf) |
|
||||
| Python | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pylint](https://www.pylint.org/), [yapf](https://github.com/google/yapf) |
|
||||
| R | [lintr](https://github.com/jimhester/lintr) |
|
||||
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions
|
||||
| reStructuredText | [proselint](http://proselint.com/)|
|
||||
| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) |
|
||||
| Ruby | [brakeman](http://brakemanscanner.org/), [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) |
|
||||
| Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) |
|
||||
| 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) |
|
||||
| Rust | cargo (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/) |
|
||||
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
|
||||
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
|
||||
| Scala | [scalac](http://scala-lang.org) |
|
||||
| Scala | [scalac](http://scala-lang.org), [scalastyle](http://www.scalastyle.org) |
|
||||
| Slim | [slim-lint](https://github.com/sds/slim-lint)
|
||||
| SML | [smlnj](http://www.smlnj.org/) |
|
||||
| Stylus | [stylelint](https://github.com/stylelint/stylelint) |
|
||||
| SQL | [sqlint](https://github.com/purcell/sqlint) |
|
||||
| Swift | [swiftlint](https://swift.org/) |
|
||||
| Swift | [swiftlint](https://github.com/realm/SwiftLint), [swiftformat](https://github.com/nicklockwood/SwiftFormat) |
|
||||
| Tcl | [nagelfar](http://nagelfar.sourceforge.net)|
|
||||
| Texinfo | [proselint](http://proselint.com/)|
|
||||
| Text^ | [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) |
|
||||
| TypeScript | [eslint](http://eslint.org/), [tslint](https://github.com/palantir/tslint), tsserver, typecheck |
|
||||
@@ -123,7 +133,7 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| Vim help^ | [proselint](http://proselint.com/)|
|
||||
| XHTML | [proselint](http://proselint.com/)|
|
||||
| XML | [xmllint](http://xmlsoft.org/xmllint.html/)|
|
||||
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
|
||||
| YAML | [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) |
|
||||
|
||||
* *^ No linters for text or Vim help filetypes are enabled by default.*
|
||||
|
||||
@@ -131,6 +141,10 @@ name. That seems to be the fairest way to arrange this table.
|
||||
|
||||
## 2. Usage
|
||||
|
||||
<a name="usage-linting"></a>
|
||||
|
||||
### 2.i Linting
|
||||
|
||||
Once this plugin is installed, while editing your files in supported
|
||||
languages and tools which have been correctly installed,
|
||||
this plugin will send the contents of your text buffers to a variety of
|
||||
@@ -143,8 +157,46 @@ documented in [the Vim help file](doc/ale.txt). For more information on the
|
||||
options ALE offers, consult `:help ale-options` for global options and `:help
|
||||
ale-linter-options` for options specified to particular linters.
|
||||
|
||||
<a name="usage-fixing"></a>
|
||||
|
||||
### 2.ii Fixing
|
||||
|
||||
ALE can fix files with the `ALEFix` command. Functions need to be configured
|
||||
for different filetypes with the `g:ale_fixers` variable. See `:help ale-fix`.
|
||||
for different filetypes with the `g:ale_fixers` variable. For example, the
|
||||
following code can be used to fix JavaScript code with ESLint:
|
||||
|
||||
```vim
|
||||
" Put this in vimrc or a plugin file of your own.
|
||||
" After this is configured, :ALEFix will try and fix your JS code with ESLint.
|
||||
let g:ale_fixers = {
|
||||
\ 'javascript': ['eslint'],
|
||||
\}
|
||||
|
||||
" Set this setting in vimrc if you want to fix files automatically on save.
|
||||
" This is off by default.
|
||||
let g:ale_fix_on_save = 1
|
||||
```
|
||||
|
||||
The `:ALEFixSuggest` command will suggest some supported tools for fixing code,
|
||||
but fixers can be also implemented with functions, including lambda functions
|
||||
too. See `:help ale-fix` for detailed information.
|
||||
|
||||
<a name="usage-completion"></a>
|
||||
|
||||
### 2.iii Completion
|
||||
|
||||
ALE offers some support for completion via hijacking of omnicompletion while you
|
||||
type. All of ALE's completion information must come from Language Server
|
||||
Protocol linters, or similar protocols. At the moment, completion is only
|
||||
supported for TypeScript code with `tsserver`, when `tsserver` is enabled. You
|
||||
can enable completion like so:
|
||||
|
||||
```vim
|
||||
" Enable completion where available.
|
||||
let g:ale_completion_enabled = 1
|
||||
```
|
||||
|
||||
See `:help ale-completion` for more information.
|
||||
|
||||
<a name="installation"></a>
|
||||
|
||||
@@ -152,13 +204,59 @@ for different filetypes with the `g:ale_fixers` variable. See `:help ale-fix`.
|
||||
|
||||
To install this plugin, you should use one of the following methods.
|
||||
For Windows users, replace usage of the Unix `~/.vim` directory with
|
||||
`%USERPROFILE%\_vim`, or another directory if you have configured
|
||||
`%USERPROFILE%\vimfiles`, or another directory if you have configured
|
||||
Vim differently. On Windows, your `~/.vimrc` file will be similarly
|
||||
stored in `%USERPROFILE%\_vimrc`.
|
||||
|
||||
<a name="standard-installation"></a>
|
||||
|
||||
### 3.i. Installation with Vim package management
|
||||
|
||||
In Vim 8 and NeoVim, you can install plugins easily without needing to use
|
||||
any other tools. Simply clone the plugin into your `pack` directory.
|
||||
|
||||
#### Vim 8 on Unix
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.vim/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/.vim/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### NeoVim on Unix
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### Vim 8 on Windows
|
||||
|
||||
```bash
|
||||
# Run these commands in the "Git for Windows" Bash terminal
|
||||
mkdir -p ~/vimfiles/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/vimfiles/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### Generating Vim help files
|
||||
|
||||
You can add the following line to your vimrc files to generate documentation
|
||||
tags automatically, if you don't have something similar already, so you can use
|
||||
the `:help` command to consult ALE's online documentation:
|
||||
|
||||
```vim
|
||||
" Put these lines at the very end of your vimrc file.
|
||||
|
||||
" Load all plugins now.
|
||||
" Plugins need to be added to runtimepath before helptags can be generated.
|
||||
packloadall
|
||||
" Load all of the helptags now, after plugins have been loaded.
|
||||
" All messages and errors will be ignored.
|
||||
silent! helptags ALL
|
||||
```
|
||||
|
||||
<a name="installation-with-pathogen"></a>
|
||||
|
||||
### 3.i. Installation with Pathogen
|
||||
### 3.ii. Installation with Pathogen
|
||||
|
||||
To install this module with [Pathogen](https://github.com/tpope/vim-pathogen),
|
||||
you should clone this repository to your bundle directory, and ensure
|
||||
@@ -172,7 +270,7 @@ git clone https://github.com/w0rp/ale.git
|
||||
|
||||
<a name="installation-with-vundle"></a>
|
||||
|
||||
### 3.ii. Installation with Vundle
|
||||
### 3.iii. Installation with Vundle
|
||||
|
||||
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
|
||||
by using the path on GitHub for this repository.
|
||||
@@ -183,41 +281,6 @@ Plugin 'w0rp/ale'
|
||||
|
||||
See the Vundle documentation for more information.
|
||||
|
||||
<a name="manual-installation"></a>
|
||||
|
||||
### 3.iii. Manual Installation
|
||||
|
||||
For installation without a package manager, you can clone this git repository
|
||||
into a bundle directory as with pathogen, and add the repository to your
|
||||
runtime path yourself. First clone the repository.
|
||||
|
||||
```bash
|
||||
cd ~/.vim/bundle
|
||||
git clone https://github.com/w0rp/ale.git
|
||||
```
|
||||
|
||||
Then, modify your `~/.vimrc` file to add this plugin to your runtime path.
|
||||
|
||||
```vim
|
||||
set nocompatible
|
||||
filetype off
|
||||
|
||||
let &runtimepath.=',~/.vim/bundle/ale'
|
||||
|
||||
filetype plugin on
|
||||
```
|
||||
|
||||
You can add the following line to generate documentation tags automatically,
|
||||
if you don't have something similar already, so you can use the `:help` command
|
||||
to consult ALE's online documentation:
|
||||
|
||||
```vim
|
||||
silent! helptags ALL
|
||||
```
|
||||
|
||||
Because the author of this plugin is a weird nerd, this is his preferred
|
||||
installation method.
|
||||
|
||||
<a name="contributing"></a>
|
||||
|
||||
## 4. Contributing
|
||||
|
||||
@@ -15,26 +15,26 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" test.yml:35: [EANSIBLE0002] Trailing whitespace
|
||||
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$'
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:code = l:match[3]
|
||||
let l:code = l:match[4]
|
||||
|
||||
if (l:code ==# 'EANSIBLE002')
|
||||
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
if l:code is# 'EANSIBLE002'
|
||||
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:item = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:code . ': ' . l:match[4],
|
||||
\ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
|
||||
\}
|
||||
|
||||
call add(l:output, l:item)
|
||||
if ale#path#IsBufferPath(a:buffer, l:match[1])
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:code . ': ' . l:match[5],
|
||||
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: clang linter for c files
|
||||
|
||||
" Set this option to change the Clang options for warnings for C.
|
||||
if !exists('g:ale_c_clang_options')
|
||||
" let g:ale_c_clang_options = '-Wall'
|
||||
" let g:ale_c_clang_options = '-std=c99 -Wall'
|
||||
" c11 compatible
|
||||
let g:ale_c_clang_options = '-std=c11 -Wall'
|
||||
endif
|
||||
call ale#Set('c_clang_executable', 'clang')
|
||||
call ale#Set('c_clang_options', '-std=c11 -Wall')
|
||||
|
||||
function! ale_linters#c#clang#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'c_clang_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#clang#GetCommand(buffer) abort
|
||||
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang -S -x c -fsyntax-only '
|
||||
return ale#Escape(ale_linters#c#clang#GetExecutable(a:buffer))
|
||||
\ . ' -S -x c -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
|
||||
\ . ale#c#IncludeOptions(l:paths)
|
||||
\ . ale#Var(a:buffer, 'c_clang_options') . ' -'
|
||||
@@ -23,7 +23,7 @@ endfunction
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang',
|
||||
\ 'executable_callback': 'ale_linters#c#clang#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#c#clang#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
" Author: Bart Libert <bart.libert@gmail.com>
|
||||
" Description: cppcheck linter for c files
|
||||
|
||||
" Set this option to change the cppcheck options
|
||||
let g:ale_c_cppcheck_options = get(g:, 'ale_c_cppcheck_options', '--enable=style')
|
||||
call ale#Set('c_cppcheck_executable', 'cppcheck')
|
||||
call ale#Set('c_cppcheck_options', '--enable=style')
|
||||
|
||||
function! ale_linters#c#cppcheck#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'c_cppcheck_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#cppcheck#GetCommand(buffer) abort
|
||||
" Search upwards from the file for compile_commands.json.
|
||||
@@ -19,7 +23,8 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
|
||||
\ : ''
|
||||
|
||||
return l:cd_command
|
||||
\ . 'cppcheck -q --language=c '
|
||||
\ . ale#Escape(ale_linters#c#cppcheck#GetExecutable(a:buffer))
|
||||
\ . ' -q --language=c '
|
||||
\ . l:compile_commands_option
|
||||
\ . ale#Var(a:buffer, 'c_cppcheck_options')
|
||||
\ . ' %t'
|
||||
@@ -28,7 +33,7 @@ endfunction
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'cppcheck',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': 'cppcheck',
|
||||
\ 'executable_callback': 'ale_linters#c#cppcheck#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#c#cppcheck#GetCommand',
|
||||
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
|
||||
\})
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: gcc linter for c files
|
||||
|
||||
" Set this option to change the GCC options for warnings for C.
|
||||
if !exists('g:ale_c_gcc_options')
|
||||
" let g:ale_c_gcc_options = '-Wall'
|
||||
" let g:ale_c_gcc_options = '-std=c99 -Wall'
|
||||
" c11 compatible
|
||||
let g:ale_c_gcc_options = '-std=c11 -Wall'
|
||||
endif
|
||||
call ale#Set('c_gcc_executable', 'gcc')
|
||||
call ale#Set('c_gcc_options', '-std=c11 -Wall')
|
||||
|
||||
function! ale_linters#c#gcc#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'c_gcc_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#gcc#GetCommand(buffer) abort
|
||||
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'gcc -S -x c -fsyntax-only '
|
||||
return ale#Escape(ale_linters#c#gcc#GetExecutable(a:buffer))
|
||||
\ . ' -S -x c -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
|
||||
\ . ale#c#IncludeOptions(l:paths)
|
||||
\ . ale#Var(a:buffer, 'c_gcc_options') . ' -'
|
||||
@@ -23,7 +23,7 @@ endfunction
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'gcc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'gcc',
|
||||
\ 'executable_callback': 'ale_linters#c#gcc#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#c#gcc#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -27,7 +27,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'type': l:match[3] ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
|
||||
\ 'text': l:match[4],
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
" Author: Tomota Nakamura <https://github.com/tomotanakamura>
|
||||
" Description: clang linter for cpp files
|
||||
|
||||
" Set this option to change the Clang options for warnings for CPP.
|
||||
if !exists('g:ale_cpp_clang_options')
|
||||
let g:ale_cpp_clang_options = '-std=c++14 -Wall'
|
||||
endif
|
||||
call ale#Set('cpp_clang_executable', 'clang++')
|
||||
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
|
||||
|
||||
function! ale_linters#cpp#clang#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_clang_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#clang#GetCommand(buffer) abort
|
||||
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang++ -S -x c++ -fsyntax-only '
|
||||
return ale#Escape(ale_linters#cpp#clang#GetExecutable(a:buffer))
|
||||
\ . ' -S -x c++ -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
|
||||
\ . ale#c#IncludeOptions(l:paths)
|
||||
\ . ale#Var(a:buffer, 'cpp_clang_options') . ' -'
|
||||
@@ -20,7 +23,7 @@ endfunction
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang++',
|
||||
\ 'executable_callback': 'ale_linters#cpp#clang#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#clang#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
" Author: gagbo <gagbobada@gmail.com>
|
||||
" Description: clang-check linter for cpp files
|
||||
|
||||
" Set this option to manually set some options for clang-check.
|
||||
let g:ale_cpp_clangcheck_options = get(g:, 'ale_cpp_clangcheck_options', '')
|
||||
call ale#Set('cpp_clangcheck_executable', 'clang-check')
|
||||
call ale#Set('cpp_clangcheck_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
" Set this option to manually point to the build directory for clang-tidy.
|
||||
" This will disable all the other clangtidy_options, since compilation
|
||||
" flags are contained in the json
|
||||
let g:ale_c_build_dir = get(g:, 'ale_c_build_dir', '')
|
||||
function! ale_linters#cpp#clangcheck#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_clangcheck_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
|
||||
let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options')
|
||||
let l:extra_options = !empty(l:user_options)
|
||||
\ ? l:user_options
|
||||
\ : ''
|
||||
|
||||
" Try to find compilation database to link automatically
|
||||
let l:user_build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
if empty(l:user_build_dir)
|
||||
let l:user_build_dir = ale#c#FindCompileCommands(a:buffer)
|
||||
endif
|
||||
let l:build_options = !empty(l:user_build_dir)
|
||||
\ ? ' -p ' . ale#Escape(l:user_build_dir)
|
||||
\ : ''
|
||||
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
|
||||
return 'clang-check -analyze ' . '%s' . l:extra_options . l:build_options
|
||||
if empty(l:build_dir)
|
||||
let l:build_dir = ale#c#FindCompileCommands(a:buffer)
|
||||
endif
|
||||
|
||||
" The extra arguments in the command are used to prevent .plist files from
|
||||
" being generated. These are only added if no build directory can be
|
||||
" detected.
|
||||
return ale#Escape(ale_linters#cpp#clangcheck#GetExecutable(a:buffer))
|
||||
\ . ' -analyze %s'
|
||||
\ . (!empty(l:user_options) ? ' ' . l:user_options : '')
|
||||
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
|
||||
\ . (empty(l:build_dir) ? ' -extra-arg -Xanalyzer -extra-arg -analyzer-output=text' : '')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clangcheck',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang-check',
|
||||
\ 'executable_callback': 'ale_linters#cpp#clangcheck#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#clangcheck#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'lint_file': 1,
|
||||
|
||||
@@ -2,51 +2,56 @@
|
||||
" gagbo <gagbobada@gmail.com>
|
||||
" Description: clang-tidy linter for cpp files
|
||||
|
||||
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
|
||||
" Set this option to check the checks clang-tidy will apply.
|
||||
let g:ale_cpp_clangtidy_checks = get(g:, 'ale_cpp_clangtidy_checks', ['*'])
|
||||
|
||||
call ale#Set('cpp_clangtidy_checks', ['*'])
|
||||
" Set this option to manually set some options for clang-tidy.
|
||||
" This will disable compile_commands.json detection.
|
||||
let g:ale_cpp_clangtidy_options = get(g:, 'ale_cpp_clangtidy_options', '')
|
||||
call ale#Set('cpp_clangtidy_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
" Set this option to manually point to the build directory for clang-tidy.
|
||||
" This will disable all the other clangtidy_options, since compilation
|
||||
" flags are contained in the json
|
||||
let g:ale_c_build_dir = get(g:, 'ale_c_build_dir', '')
|
||||
function! ale_linters#cpp#clangtidy#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_clangtidy_executable')
|
||||
endfunction
|
||||
|
||||
function! s:GetBuildDirectory(buffer) abort
|
||||
" Don't include build directory for header files, as compile_commands.json
|
||||
" files don't consider headers to be translation units, and provide no
|
||||
" commands for compiling header files.
|
||||
if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
|
||||
return ''
|
||||
endif
|
||||
|
||||
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
|
||||
let l:check_list = ale#Var(a:buffer, 'cpp_clangtidy_checks')
|
||||
let l:check_option = !empty(l:check_list)
|
||||
\ ? '-checks=' . ale#Escape(join(l:check_list, ',')) . ' '
|
||||
\ : ''
|
||||
let l:user_options = ale#Var(a:buffer, 'cpp_clangtidy_options')
|
||||
let l:user_build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
|
||||
" c_build_dir has the priority if defined
|
||||
if empty(l:user_build_dir)
|
||||
let l:user_build_dir = ale#c#FindCompileCommands(a:buffer)
|
||||
if !empty(l:build_dir)
|
||||
return l:build_dir
|
||||
endif
|
||||
|
||||
" We check again if user_builddir stayed empty after the
|
||||
" c_build_dir_names check
|
||||
" If we found the compilation database we override the value of
|
||||
" l:extra_options
|
||||
if empty(l:user_build_dir)
|
||||
let l:extra_options = !empty(l:user_options)
|
||||
\ ? ' -- ' . l:user_options
|
||||
\ : ''
|
||||
else
|
||||
let l:extra_options = ' -p ' . ale#Escape(l:user_build_dir)
|
||||
endif
|
||||
return ale#c#FindCompileCommands(a:buffer)
|
||||
endfunction
|
||||
|
||||
return 'clang-tidy ' . l:check_option . '%s' . l:extra_options
|
||||
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
|
||||
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
|
||||
let l:build_dir = s:GetBuildDirectory(a:buffer)
|
||||
|
||||
" Get the extra options if we couldn't find a build directory.
|
||||
let l:options = empty(l:build_dir)
|
||||
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
|
||||
\ : ''
|
||||
|
||||
return ale#Escape(ale_linters#cpp#clangtidy#GetExecutable(a:buffer))
|
||||
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
|
||||
\ . ' %s'
|
||||
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
|
||||
\ . (!empty(l:options) ? ' -- ' . l:options : '')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clangtidy',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'clang-tidy',
|
||||
\ 'executable_callback': 'ale_linters#cpp#clangtidy#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'lint_file': 1,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
" Author: Bart Libert <bart.libert@gmail.com>
|
||||
" Description: cppcheck linter for cpp files
|
||||
|
||||
" Set this option to change the cppcheck options
|
||||
let g:ale_cpp_cppcheck_options = get(g:, 'ale_cpp_cppcheck_options', '--enable=style')
|
||||
call ale#Set('cpp_cppcheck_executable', 'cppcheck')
|
||||
call ale#Set('cpp_cppcheck_options', '--enable=style')
|
||||
|
||||
function! ale_linters#cpp#cppcheck#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_cppcheck_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
|
||||
" Search upwards from the file for compile_commands.json.
|
||||
@@ -19,7 +23,8 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
|
||||
\ : ''
|
||||
|
||||
return l:cd_command
|
||||
\ . 'cppcheck -q --language=c++ '
|
||||
\ . ale#Escape(ale_linters#cpp#cppcheck#GetExecutable(a:buffer))
|
||||
\ . ' -q --language=c++ '
|
||||
\ . l:compile_commands_option
|
||||
\ . ale#Var(a:buffer, 'cpp_cppcheck_options')
|
||||
\ . ' %t'
|
||||
@@ -28,7 +33,7 @@ endfunction
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'cppcheck',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': 'cppcheck',
|
||||
\ 'executable_callback': 'ale_linters#cpp#cppcheck#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#cppcheck#GetCommand',
|
||||
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
|
||||
\})
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
" Author: Dawid Kurek https://github.com/dawikur
|
||||
" Description: cpplint for cpp files
|
||||
|
||||
if !exists('g:ale_cpp_cpplint_options')
|
||||
let g:ale_cpp_cpplint_options = ''
|
||||
endif
|
||||
call ale#Set('cpp_cpplint_executable', 'cpplint')
|
||||
call ale#Set('cpp_cpplint_options', '')
|
||||
|
||||
function! ale_linters#cpp#cpplint#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_cpplint_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#cpplint#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'cpp_cpplint_options')
|
||||
|
||||
return ale#Escape(ale_linters#cpp#cpplint#GetExecutable(a:buffer))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'cpplint',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'cpplint',
|
||||
\ 'command': 'cpplint %s',
|
||||
\ 'executable_callback': 'ale_linters#cpp#cpplint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#cpplint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
" Author: geam <mdelage@student.42.fr>
|
||||
" Description: gcc linter for cpp files
|
||||
"
|
||||
call ale#Set('cpp_gcc_executable', 'gcc')
|
||||
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
|
||||
|
||||
" Set this option to change the GCC options for warnings for C.
|
||||
if !exists('g:ale_cpp_gcc_options')
|
||||
let s:version = ale#handlers#gcc#ParseGCCVersion(systemlist('gcc --version'))
|
||||
|
||||
if !empty(s:version) && ale#semver#GreaterOrEqual(s:version, [4, 9, 0])
|
||||
" Use c++14 support in 4.9 and above.
|
||||
let g:ale_cpp_gcc_options = '-std=c++14 -Wall'
|
||||
else
|
||||
" Use c++1y in older versions.
|
||||
let g:ale_cpp_gcc_options = '-std=c++1y -Wall'
|
||||
endif
|
||||
|
||||
unlet! s:version
|
||||
endif
|
||||
function! ale_linters#cpp#gcc#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'cpp_gcc_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#gcc#GetCommand(buffer) abort
|
||||
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'gcc -S -x c++ -fsyntax-only '
|
||||
return ale#Escape(ale_linters#cpp#gcc#GetExecutable(a:buffer))
|
||||
\ . ' -S -x c++ -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
|
||||
\ . ale#c#IncludeOptions(l:paths)
|
||||
\ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -'
|
||||
@@ -30,7 +23,7 @@ endfunction
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'g++',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'g++',
|
||||
\ 'executable_callback': 'ale_linters#cpp#gcc#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#cpp#gcc#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -4,31 +4,21 @@
|
||||
function! ale_linters#crystal#crystal#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
let l:lines = join(a:lines, '')
|
||||
|
||||
if !empty(l:lines)
|
||||
let l:errors = json_decode(l:lines)
|
||||
|
||||
for l:error in l:errors
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:error.line + 0,
|
||||
\ 'col': l:error.column + 0,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
endif
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.line + 0,
|
||||
\ 'col': l:error.column + 0,
|
||||
\ 'text': l:error.message,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#crystal#crystal#GetCommand(buffer) abort
|
||||
let l:crystal_cmd = 'crystal build -f json --no-codegen --no-color -o '
|
||||
let l:crystal_cmd .= ale#Escape(g:ale#util#nul_file)
|
||||
let l:crystal_cmd .= ' %s'
|
||||
|
||||
return l:crystal_cmd
|
||||
return 'crystal build -f json --no-codegen --no-color -o '
|
||||
\ . ale#Escape(g:ale#util#nul_file)
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('crystal', {
|
||||
|
||||
@@ -60,7 +60,7 @@ function! ale_linters#d#dmd#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1],
|
||||
\ 'col': l:match[2],
|
||||
\ 'type': l:match[3] ==# 'Warning' ? 'W' : 'E',
|
||||
\ 'type': l:match[3] is# 'Warning' ? 'W' : 'E',
|
||||
\ 'text': l:match[4],
|
||||
\})
|
||||
endfor
|
||||
|
||||
40
ale_linters/dart/dartanalyzer.vim
Normal file
40
ale_linters/dart/dartanalyzer.vim
Normal file
@@ -0,0 +1,40 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Check Dart files with dartanalyzer
|
||||
|
||||
call ale#Set('dart_dartanalyzer_executable', 'dartanalyzer')
|
||||
|
||||
function! ale_linters#dart#dartanalyzer#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'dart_dartanalyzer_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dart#dartanalyzer#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#dart#dartanalyzer#GetExecutable(a:buffer)
|
||||
let l:path = ale#path#FindNearestFile(a:buffer, '.packages')
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
\ . (!empty(l:path) ? ' --packages ' . ale#Escape(l:path) : '')
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dart#dartanalyzer#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v^ ([a-z]+) . (.+) at (.+):(\d+):(\d+) . (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
|
||||
\ 'text': l:match[6] . ': ' . l:match[2],
|
||||
\ 'lnum': str2nr(l:match[4]),
|
||||
\ 'col': str2nr(l:match[5]),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('dart', {
|
||||
\ 'name': 'dartanalyzer',
|
||||
\ 'executable_callback': 'ale_linters#dart#dartanalyzer#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#dart#dartanalyzer#GetCommand',
|
||||
\ 'callback': 'ale_linters#dart#dartanalyzer#Handle',
|
||||
\})
|
||||
@@ -1,5 +1,9 @@
|
||||
" Author: hauleth - https://github.com/hauleth
|
||||
|
||||
" always, yes, never
|
||||
call ale#Set('dockerfile_hadolint_use_docker', 'never')
|
||||
call ale#Set('dockerfile_hadolint_docker_image', 'lukasmartinelli/hadolint')
|
||||
|
||||
function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
@@ -10,7 +14,7 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:lnum = 0
|
||||
|
||||
if l:match[1] !=# ''
|
||||
if l:match[1] isnot# ''
|
||||
let l:lnum = l:match[1] + 0
|
||||
endif
|
||||
|
||||
@@ -29,9 +33,45 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
" This is a little different than the typical 'executable' callback. We want
|
||||
" to afford the user the chance to say always use docker, never use docker,
|
||||
" and use docker if the hadolint executable is not present on the system.
|
||||
"
|
||||
" In the case of neither docker nor hadolint executables being present, it
|
||||
" really doesn't matter which we return -- either will have the effect of
|
||||
" 'nope, can't use this linter!'.
|
||||
|
||||
function! ale_linters#dockerfile#hadolint#GetExecutable(buffer) abort
|
||||
let l:use_docker = ale#Var(a:buffer, 'dockerfile_hadolint_use_docker')
|
||||
|
||||
" check for mandatory directives
|
||||
if l:use_docker is# 'never'
|
||||
return 'hadolint'
|
||||
elseif l:use_docker is# 'always'
|
||||
return 'docker'
|
||||
endif
|
||||
|
||||
" if we reach here, we want to use 'hadolint' if present...
|
||||
if executable('hadolint')
|
||||
return 'hadolint'
|
||||
endif
|
||||
|
||||
"... and 'docker' as a fallback.
|
||||
return 'docker'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort
|
||||
let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer)
|
||||
if l:command is# 'docker'
|
||||
return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image')
|
||||
endif
|
||||
return 'hadolint -'
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('dockerfile', {
|
||||
\ 'name': 'hadolint',
|
||||
\ 'executable': 'hadolint',
|
||||
\ 'command': 'hadolint -',
|
||||
\ 'executable_callback': 'ale_linters#dockerfile#hadolint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#dockerfile#hadolint#GetCommand',
|
||||
\ 'callback': 'ale_linters#dockerfile#hadolint#Handle',
|
||||
\})
|
||||
|
||||
@@ -11,9 +11,9 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
|
||||
let l:type = l:match[3]
|
||||
let l:text = l:match[4]
|
||||
|
||||
if l:type ==# 'C'
|
||||
if l:type is# 'C'
|
||||
let l:type = 'E'
|
||||
elseif l:type ==# 'R'
|
||||
elseif l:type is# 'R'
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
|
||||
let l:type = l:match[3]
|
||||
let l:text = l:match[4]
|
||||
|
||||
if l:type ==# 'C'
|
||||
if l:type is# 'C'
|
||||
let l:type = 'E'
|
||||
elseif l:type ==# 'R'
|
||||
elseif l:type is# 'R'
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
|
||||
@@ -7,29 +7,31 @@ function! ale_linters#elm#make#Handle(buffer, lines) abort
|
||||
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
|
||||
let l:unparsed_lines = []
|
||||
for l:line in a:lines
|
||||
if l:line[0] ==# '['
|
||||
if l:line[0] is# '['
|
||||
let l:errors = json_decode(l:line)
|
||||
|
||||
for l:error in l:errors
|
||||
" Check if file is from the temp directory.
|
||||
" Filters out any errors not related to the buffer.
|
||||
if l:is_windows
|
||||
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==? l:temp_dir
|
||||
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is? l:temp_dir
|
||||
else
|
||||
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==# l:temp_dir
|
||||
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is# l:temp_dir
|
||||
endif
|
||||
|
||||
if l:file_is_buffer
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.region.start.line,
|
||||
\ 'col': l:error.region.start.column,
|
||||
\ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
|
||||
\ 'end_lnum': l:error.region.end.line,
|
||||
\ 'end_col': l:error.region.end.column,
|
||||
\ 'type': (l:error.type is? 'error') ? 'E' : 'W',
|
||||
\ 'text': l:error.overview,
|
||||
\ 'detail': l:error.overview . "\n\n" . l:error.details
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
elseif l:line !=# 'Successfully generated /dev/null'
|
||||
elseif l:line isnot# 'Successfully generated /dev/null'
|
||||
call add(l:unparsed_lines, l:line)
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -27,7 +27,7 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
let l:pattern_no_module_definition = '\v(no module definition)$'
|
||||
let l:pattern_unused = '\v(.* is unused)$'
|
||||
|
||||
let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') ==# 'hrl'
|
||||
let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') is# 'hrl'
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
53
ale_linters/erlang/syntaxerl.vim
Normal file
53
ale_linters/erlang/syntaxerl.vim
Normal file
@@ -0,0 +1,53 @@
|
||||
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com>
|
||||
" Description: SyntaxErl linter for Erlang files
|
||||
|
||||
call ale#Set('erlang_syntaxerl_executable', 'syntaxerl')
|
||||
|
||||
|
||||
function! ale_linters#erlang#syntaxerl#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'erlang_syntaxerl_executable')
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale_linters#erlang#syntaxerl#FeatureCheck(buffer) abort
|
||||
return s:GetEscapedExecutable(a:buffer) . ' -h'
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output) abort
|
||||
let l:use_b_option = match(a:output, '\C\V-b, --base\>') > -1
|
||||
|
||||
return s:GetEscapedExecutable(a:buffer) . (l:use_b_option ? ' -b %s %t' : ' %t')
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v\C:(\d+):( warning:)? (.+)'
|
||||
let l:loclist = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:loclist, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': empty(l:match[2]) ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:loclist
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:GetEscapedExecutable(buffer) abort
|
||||
return ale#Escape(ale_linters#erlang#syntaxerl#GetExecutable(a:buffer))
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('erlang', {
|
||||
\ 'name': 'syntaxerl',
|
||||
\ 'executable_callback': 'ale_linters#erlang#syntaxerl#GetExecutable',
|
||||
\ 'command_chain': [
|
||||
\ {'callback': 'ale_linters#erlang#syntaxerl#FeatureCheck'},
|
||||
\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'},
|
||||
\ ],
|
||||
\ 'callback': 'ale_linters#erlang#syntaxerl#Handle',
|
||||
\})
|
||||
11
ale_linters/eruby/erubis.vim
Normal file
11
ale_linters/eruby/erubis.vim
Normal file
@@ -0,0 +1,11 @@
|
||||
" Author: Jake Zimmerman <jake@zimmerman.io>
|
||||
" Description: eruby checker using `erubis`, instead of `erb`
|
||||
|
||||
call ale#linter#Define('eruby', {
|
||||
\ 'name': 'erubis',
|
||||
\ 'executable': 'erubis',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': 'erubis -x %t | ruby -c',
|
||||
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
|
||||
\})
|
||||
|
||||
@@ -44,7 +44,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
|
||||
|
||||
" Now we have the text, we can set it and add the error.
|
||||
let l:last_loclist_obj.text = l:match[2]
|
||||
let l:last_loclist_obj.type = l:match[1] ==# 'Warning' ? 'W' : 'E'
|
||||
let l:last_loclist_obj.type = l:match[1] is# 'Warning' ? 'W' : 'E'
|
||||
call add(l:output, l:last_loclist_obj)
|
||||
else
|
||||
let l:last_loclist_obj = {
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
" Author: Ben Reedy <https://github.com/breed808>
|
||||
" Description: Adds support for the gometalinter suite for Go files
|
||||
|
||||
if !exists('g:ale_go_gometalinter_options')
|
||||
let g:ale_go_gometalinter_options = ''
|
||||
endif
|
||||
call ale#Set('go_gometalinter_options', '')
|
||||
call ale#Set('go_gometalinter_executable', 'gometalinter')
|
||||
|
||||
function! ale_linters#go#gometalinter#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'go_gometalinter_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gometalinter#GetCommand(buffer) abort
|
||||
let l:filename = expand('#' . a:buffer . ':p')
|
||||
let l:executable = ale_linters#go#gometalinter#GetExecutable(a:buffer)
|
||||
let l:filename = expand('#' . a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'go_gometalinter_options')
|
||||
|
||||
return 'gometalinter --include=''^' . l:filename . '.*$'' '
|
||||
\ . ale#Var(a:buffer, 'go_gometalinter_options')
|
||||
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
return ale#Escape(l:executable)
|
||||
\ . ' --include=' . ale#Escape('^' . ale#util#EscapePCRE(l:filename))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' ' . ale#Escape(fnamemodify(l:filename, ':h'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gometalinter#GetMatches(lines) abort
|
||||
@@ -26,7 +32,7 @@ function! ale_linters#go#gometalinter#Handler(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': tolower(l:match[4]) ==# 'warning' ? 'W' : 'E',
|
||||
\ 'type': tolower(l:match[4]) is# 'warning' ? 'W' : 'E',
|
||||
\ 'text': l:match[5],
|
||||
\})
|
||||
endfor
|
||||
@@ -36,7 +42,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'gometalinter',
|
||||
\ 'executable': 'gometalinter',
|
||||
\ 'executable_callback': 'ale_linters#go#gometalinter#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
|
||||
\ 'callback': 'ale_linters#go#gometalinter#Handler',
|
||||
\ 'lint_file': 1,
|
||||
|
||||
@@ -6,4 +6,5 @@ call ale#linter#Define('go', {
|
||||
\ 'executable': 'gosimple',
|
||||
\ 'command': 'gosimple %t',
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
|
||||
\ 'output_stream': 'both'
|
||||
\})
|
||||
|
||||
@@ -6,4 +6,5 @@ call ale#linter#Define('go', {
|
||||
\ 'executable': 'staticcheck',
|
||||
\ 'command': 'staticcheck %t',
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
|
||||
\ 'output_stream': 'both'
|
||||
\})
|
||||
|
||||
9
ale_linters/graphql/gqlint.vim
Normal file
9
ale_linters/graphql/gqlint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Michiel Westerbeek <happylinks@gmail.com>
|
||||
" Description: Linter for GraphQL Schemas
|
||||
|
||||
call ale#linter#Define('graphql', {
|
||||
\ 'name': 'gqlint',
|
||||
\ 'executable': 'gqlint',
|
||||
\ 'command': 'gqlint --reporter=simple %t',
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
|
||||
\})
|
||||
@@ -16,16 +16,10 @@ function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
|
||||
if len(a:lines) == 0
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:output = []
|
||||
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
|
||||
|
||||
let l:input_json = json_decode(join(a:lines, ''))
|
||||
let l:file_errors = values(l:input_json)[0]
|
||||
|
||||
for l:error in l:file_errors
|
||||
for l:error in get(values(l:json), 0, [])
|
||||
if has_key(l:error, 'fatal')
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'ghc-mod',
|
||||
\ 'executable': 'ghc-mod',
|
||||
\ 'command': 'ghc-mod check %t',
|
||||
\ 'command': 'ghc-mod --map-file %s=%t check %s',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'stack-ghc-mod',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command': 'stack exec ghc-mod check %t',
|
||||
\ 'command': 'stack exec ghc-mod -- --map-file %s=%t check %s',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
|
||||
@@ -8,11 +8,3 @@ call ale#linter#Define('haskell', {
|
||||
\ 'command': 'ghc -fno-code -v0 %t',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'stack-ghc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command': 'stack ghc -- -fno-code -v0 %t',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
" Author: rob-b
|
||||
" Author: rob-b, Takano Akio <tak@anoak.io>
|
||||
" Description: hdevtools for Haskell files
|
||||
|
||||
call ale#Set('haskell_hdevtools_executable', 'hdevtools')
|
||||
call ale#Set('haskell_hdevtools_options', '-g -Wall')
|
||||
|
||||
function! ale_linters#haskell#hdevtools#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'haskell_hdevtools_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#haskell#hdevtools#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#haskell#hdevtools#GetExecutable(a:buffer))
|
||||
\ . ' check ' . ale#Var(a:buffer, 'haskell_hdevtools_options')
|
||||
\ . ' -p %s %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'hdevtools',
|
||||
\ 'executable': 'hdevtools',
|
||||
\ 'command': 'hdevtools check -g -Wall -p %s %t',
|
||||
\ 'executable_callback': 'ale_linters#haskell#hdevtools#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#haskell#hdevtools#GetCommand',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
|
||||
@@ -2,17 +2,24 @@
|
||||
" Description: hlint for Haskell files
|
||||
|
||||
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
|
||||
let l:errors = json_decode(join(a:lines, ''))
|
||||
|
||||
let l:output = []
|
||||
|
||||
for l:error in l:errors
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
if l:error.severity is# 'Error'
|
||||
let l:type = 'E'
|
||||
elseif l:error.severity is# 'Suggestion'
|
||||
let l:type = 'I'
|
||||
else
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:error.startLine + 0,
|
||||
\ 'col': l:error.startColumn + 0,
|
||||
\ 'lnum': str2nr(l:error.startLine),
|
||||
\ 'col': str2nr(l:error.startColumn),
|
||||
\ 'end_lnum': str2nr(l:error.endLine),
|
||||
\ 'end_col': str2nr(l:error.endColumn),
|
||||
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
|
||||
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
22
ale_linters/haskell/stack_build.vim
Normal file
22
ale_linters/haskell/stack_build.vim
Normal file
@@ -0,0 +1,22 @@
|
||||
" Author: Jake Zimmerman <jake@zimmerman.io>
|
||||
" Description: Like stack-ghc, but for entire projects
|
||||
"
|
||||
" Note: Ideally, this would *only* typecheck. Right now, it also does codegen.
|
||||
" See <https://github.com/commercialhaskell/stack/issues/977>.
|
||||
|
||||
call ale#Set('haskell_stack_build_options', '--fast')
|
||||
|
||||
function ale_linters#haskell#stack_build#GetCommand(buffer) abort
|
||||
let l:flags = ale#Var(a:buffer, 'haskell_stack_build_options')
|
||||
|
||||
return 'stack build ' . l:flags
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'stack-build',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand',
|
||||
\ 'lint_file': 1,
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
10
ale_linters/haskell/stack_ghc.vim
Normal file
10
ale_linters/haskell/stack_ghc.vim
Normal file
@@ -0,0 +1,10 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: ghc for Haskell files, using Stack
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'stack-ghc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command': 'stack ghc -- -fno-code -v0 %t',
|
||||
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
|
||||
\})
|
||||
@@ -46,7 +46,7 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:line = l:match[1] + 0
|
||||
let l:col = l:match[2] + 0
|
||||
let l:type = l:match[3] ==# 'Error' ? 'E' : 'W'
|
||||
let l:type = l:match[3] is# 'Error' ? 'E' : 'W'
|
||||
let l:text = l:match[4]
|
||||
|
||||
call add(l:output, {
|
||||
|
||||
87
ale_linters/idris/idris.vim
Normal file
87
ale_linters/idris/idris.vim
Normal file
@@ -0,0 +1,87 @@
|
||||
" Author: Scott Bonds <scott@ggr.com>
|
||||
" Description: default Idris compiler
|
||||
|
||||
call ale#Set('idris_idris_executable', 'idris')
|
||||
call ale#Set('idris_idris_options', '--total --warnpartial --warnreach --warnipkg')
|
||||
|
||||
function! ale_linters#idris#idris#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'idris_idris_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#idris#idris#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'idris_idris_options')
|
||||
|
||||
return ale#Escape(ale_linters#idris#idris#GetExecutable(a:buffer))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --check %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#idris#idris#Handle(buffer, lines) abort
|
||||
" This was copied almost verbatim from ale#handlers#haskell#HandleGHCFormat
|
||||
|
||||
" Look for lines like the following:
|
||||
" foo.idr:2:6:When checking right hand side of main with expected type
|
||||
" bar.idr:11:11-13:
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)(-\d+)?:(.*)?$'
|
||||
let l:output = []
|
||||
|
||||
let l:corrected_lines = []
|
||||
|
||||
for l:line in a:lines
|
||||
if len(matchlist(l:line, l:pattern)) > 0
|
||||
call add(l:corrected_lines, l:line)
|
||||
elseif len(l:corrected_lines) > 0
|
||||
if l:line is# ''
|
||||
let l:corrected_lines[-1] .= ' ' " turn a blank line into a space
|
||||
else
|
||||
let l:corrected_lines[-1] .= l:line
|
||||
endif
|
||||
let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g')
|
||||
endif
|
||||
endfor
|
||||
|
||||
for l:line in l:corrected_lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
if !ale#path#IsBufferPath(a:buffer, l:match[1])
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:errors = matchlist(l:match[5], '\v([wW]arning|[eE]rror) - ?(.*)')
|
||||
|
||||
if len(l:errors) > 0
|
||||
let l:ghc_type = l:errors[1]
|
||||
let l:text = l:errors[2]
|
||||
else
|
||||
let l:ghc_type = ''
|
||||
let l:text = l:match[5][:0] is# ' ' ? l:match[5][1:] : l:match[5]
|
||||
endif
|
||||
|
||||
if l:ghc_type is? 'Warning'
|
||||
let l:type = 'W'
|
||||
else
|
||||
let l:type = 'E'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('idris', {
|
||||
\ 'name': 'idris',
|
||||
\ 'executable_callback': 'ale_linters#idris#idris#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#idris#idris#GetCommand',
|
||||
\ 'callback': 'ale_linters#idris#idris#Handle',
|
||||
\})
|
||||
|
||||
@@ -68,14 +68,14 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort
|
||||
let l:output[-1].col = len(l:match[1])
|
||||
elseif empty(l:match[3])
|
||||
" Add symbols to 'cannot find symbol' errors.
|
||||
if l:output[-1].text ==# 'error: cannot find symbol'
|
||||
if l:output[-1].text is# 'error: cannot find symbol'
|
||||
let l:output[-1].text .= ': ' . l:match[2]
|
||||
endif
|
||||
else
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'text': l:match[2] . ':' . l:match[3],
|
||||
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[2] is# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -10,7 +10,12 @@ function! ale_linters#javascript#flow#GetExecutable(buffer) abort
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#flow#GetCommand(buffer) abort
|
||||
function! ale_linters#javascript#flow#VersionCheck(buffer) abort
|
||||
return ale#Escape(ale_linters#javascript#flow#GetExecutable(a:buffer))
|
||||
\ . ' --version'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#flow#GetCommand(buffer, version_lines) abort
|
||||
let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig')
|
||||
|
||||
if empty(l:flow_config)
|
||||
@@ -18,14 +23,43 @@ function! ale_linters#javascript#flow#GetCommand(buffer) abort
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:use_respect_pragma = 1
|
||||
|
||||
" If we can parse the version number, then only use --respect-pragma
|
||||
" if the version is >= 0.36.0, which added the argument.
|
||||
for l:match in ale#util#GetMatches(a:version_lines, '\v\d+\.\d+\.\d+$')
|
||||
let l:use_respect_pragma = ale#semver#GreaterOrEqual(
|
||||
\ ale#semver#Parse(l:match[0]),
|
||||
\ [0, 36, 0]
|
||||
\)
|
||||
endfor
|
||||
|
||||
return ale#Escape(ale_linters#javascript#flow#GetExecutable(a:buffer))
|
||||
\ . ' check-contents --respect-pragma --json --from ale %s'
|
||||
\ . ' check-contents'
|
||||
\ . (l:use_respect_pragma ? ' --respect-pragma': '')
|
||||
\ . ' --json --from ale %s'
|
||||
endfunction
|
||||
|
||||
" Filter lines of flow output until we find the first line where the JSON
|
||||
" output starts.
|
||||
function! s:GetJSONLines(lines) abort
|
||||
let l:start_index = 0
|
||||
|
||||
for l:line in a:lines
|
||||
if l:line[:0] is# '{'
|
||||
break
|
||||
endif
|
||||
|
||||
let l:start_index += 1
|
||||
endfor
|
||||
|
||||
return a:lines[l:start_index :]
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#flow#Handle(buffer, lines) abort
|
||||
let l:str = join(a:lines, '')
|
||||
let l:str = join(s:GetJSONLines(a:lines), '')
|
||||
|
||||
if l:str ==# ''
|
||||
if empty(l:str)
|
||||
return []
|
||||
endif
|
||||
|
||||
@@ -43,13 +77,13 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
|
||||
" In certain cases, `l:message.loc.source` points to a different path
|
||||
" than the buffer one, thus we skip this loc information too.
|
||||
if has_key(l:message, 'loc')
|
||||
\&& l:line ==# 0
|
||||
\&& l:line is# 0
|
||||
\&& ale#path#IsBufferPath(a:buffer, l:message.loc.source)
|
||||
let l:line = l:message.loc.start.line + 0
|
||||
let l:col = l:message.loc.start.column + 0
|
||||
endif
|
||||
|
||||
if l:text ==# ''
|
||||
if l:text is# ''
|
||||
let l:text = l:message.descr . ':'
|
||||
else
|
||||
let l:text = l:text . ' ' . l:message.descr
|
||||
@@ -64,7 +98,7 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:error.level ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:error.level is# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -74,6 +108,10 @@ endfunction
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'flow',
|
||||
\ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#flow#GetCommand',
|
||||
\ 'command_chain': [
|
||||
\ {'callback': 'ale_linters#javascript#flow#VersionCheck'},
|
||||
\ {'callback': 'ale_linters#javascript#flow#GetCommand'},
|
||||
\ ],
|
||||
\ 'callback': 'ale_linters#javascript#flow#Handle',
|
||||
\ 'add_newline': !has('win32'),
|
||||
\})
|
||||
|
||||
@@ -1,9 +1,63 @@
|
||||
" Author: Chris Kyrouac - https://github.com/fijshion
|
||||
" Description: jscs for JavaScript files
|
||||
|
||||
call ale#Set('javascript_jscs_executable', 'jscs')
|
||||
call ale#Set('javascript_jscs_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#jscs#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_jscs', [
|
||||
\ 'node_modules/.bin/jscs',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#jscs#GetCommand(buffer) abort
|
||||
" Search for a local JShint config locaation, and default to a global one.
|
||||
let l:jscs_config = ale#path#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ '.jscsrc',
|
||||
\ get(g:, 'ale_jscs_config_loc', '')
|
||||
\)
|
||||
|
||||
let l:command = ale#Escape(ale_linters#javascript#jscs#GetExecutable(a:buffer))
|
||||
let l:command .= ' --reporter inline --no-colors'
|
||||
|
||||
if !empty(l:jscs_config)
|
||||
let l:command .= ' --config ' . ale#Escape(l:jscs_config)
|
||||
endif
|
||||
|
||||
let l:command .= ' -'
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#jscs#Handle(buffer, lines) abort
|
||||
" Matches patterns looking like the following
|
||||
"
|
||||
" foobar.js: line 2, col 1, Expected indentation of 1 characters
|
||||
"
|
||||
let l:pattern = '^.*:\s\+line \(\d\+\),\s\+col\s\+\(\d\+\),\s\+\(.*\)$'
|
||||
let l:output = []
|
||||
let l:m = ale#util#GetMatches(a:lines, [l:pattern])
|
||||
|
||||
for l:match in l:m
|
||||
let l:text = l:match[3]
|
||||
|
||||
let l:obj = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3]
|
||||
\}
|
||||
|
||||
call add(l:output, l:obj)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'jscs',
|
||||
\ 'executable': 'jscs',
|
||||
\ 'command': 'jscs -r unix -n -',
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsError',
|
||||
\ 'executable_callback': 'ale_linters#javascript#jscs#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#jscs#GetCommand',
|
||||
\ 'callback': 'ale_linters#javascript#jscs#Handle',
|
||||
\})
|
||||
|
||||
|
||||
@@ -7,13 +7,17 @@ call ale#Set('javascript_standard_options', '')
|
||||
|
||||
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
|
||||
\ 'node_modules/standard/bin/cmd.js',
|
||||
\ 'node_modules/.bin/standard',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#standard#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#javascript#standard#GetExecutable(a:buffer))
|
||||
\ . ' ' . ale#Var(a:buffer, 'javascript_standard_options')
|
||||
let l:executable = ale_linters#javascript#standard#GetExecutable(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'javascript_standard_options')
|
||||
|
||||
return ale#node#Executable(a:buffer, l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -12,17 +12,21 @@ let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_fi
|
||||
let s:classpath_sep = has('unix') ? ':' : ';'
|
||||
|
||||
function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort
|
||||
" exec maven only if classpath is not set
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
|
||||
" exec maven/gradle only if classpath is not set
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# ''
|
||||
return ''
|
||||
else
|
||||
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
|
||||
|
||||
if !empty(l:pom_path) && executable('mvn')
|
||||
return ale#path#CdString(fnamemodify(l:pom_path, ':h'))
|
||||
\ . 'mvn dependency:build-classpath'
|
||||
endif
|
||||
|
||||
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
|
||||
if !empty(l:classpath_command)
|
||||
return l:classpath_command
|
||||
endif
|
||||
|
||||
return ''
|
||||
endif
|
||||
endfunction
|
||||
@@ -66,19 +70,27 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
|
||||
endif
|
||||
|
||||
" We only get here if not using module or the module file not readable
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# ''
|
||||
let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath')
|
||||
else
|
||||
" get classpath from maven
|
||||
" get classpath from maven/gradle
|
||||
let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths)
|
||||
endif
|
||||
|
||||
let l:fname = ''
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') !=# ''
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') isnot# ''
|
||||
let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' '
|
||||
else
|
||||
" Find the src directory for files in this project.
|
||||
let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
|
||||
|
||||
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
|
||||
if !empty(l:project_root)
|
||||
let l:src_dir = l:project_root
|
||||
else
|
||||
let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
|
||||
\ . ' ' . ale#path#FindNearestDirectory(a:buffer, 'src/main/kotlin')
|
||||
endif
|
||||
|
||||
let l:fname .= expand(l:src_dir, 1) . ' '
|
||||
endif
|
||||
let l:fname .= ale#Escape(expand('#' . a:buffer . ':p'))
|
||||
@@ -109,10 +121,10 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
|
||||
let l:curbuf_abspath = expand('#' . a:buffer . ':p')
|
||||
|
||||
" Skip if file is not loaded
|
||||
if l:buf_abspath !=# l:curbuf_abspath
|
||||
if l:buf_abspath isnot# l:curbuf_abspath
|
||||
continue
|
||||
endif
|
||||
let l:type_marker_str = l:type ==# 'warning' ? 'W' : 'E'
|
||||
let l:type_marker_str = l:type is# 'warning' ? 'W' : 'E'
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:line,
|
||||
@@ -133,7 +145,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
|
||||
let l:type = l:match[1]
|
||||
let l:text = l:match[2]
|
||||
|
||||
let l:type_marker_str = l:type ==# 'warning' || l:type ==# 'info' ? 'W' : 'E'
|
||||
let l:type_marker_str = l:type is# 'warning' || l:type is# 'info' ? 'W' : 'E'
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': 1,
|
||||
@@ -155,3 +167,4 @@ call ale#linter#Define('kotlin', {
|
||||
\ 'callback': 'ale_linters#kotlin#kotlinc#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
|
||||
"
|
||||
" artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106
|
||||
" artal.lua:182:7: (W213) unused loop variable 'i'
|
||||
let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\d\+) \(.\+\)$'
|
||||
let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\(\d\+\)) \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'text': l:match[3] . l:match[4] . ': ' . l:match[5],
|
||||
\ 'type': l:match[3],
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -30,7 +30,7 @@ function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
|
||||
|
||||
" Suppress erroneous waring about filename
|
||||
" TODO: Enable this error when copying filename is supported
|
||||
if l:code ==# 'FNDEF'
|
||||
if l:code is# 'FNDEF'
|
||||
continue
|
||||
endif
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
|
||||
" module names.
|
||||
|
||||
let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t')
|
||||
if l:buffer_filename !=# '' && l:temp_buffer_filename !=# l:buffer_filename
|
||||
if l:buffer_filename isnot# '' && l:temp_buffer_filename isnot# l:buffer_filename
|
||||
continue
|
||||
endif
|
||||
|
||||
@@ -26,7 +26,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
|
||||
|
||||
if len(l:textmatch) > 0
|
||||
let l:errortype = l:textmatch[1]
|
||||
if l:errortype ==# 'Error'
|
||||
if l:errortype is# 'Error'
|
||||
let l:type = 'E'
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -34,7 +34,7 @@ function! ale_linters#perl#perl#Handle(buffer, lines) abort
|
||||
|
||||
if ale#path#IsBufferPath(a:buffer, l:match[2])
|
||||
\ && (
|
||||
\ l:text !=# 'BEGIN failed--compilation aborted'
|
||||
\ l:text isnot# 'BEGIN failed--compilation aborted'
|
||||
\ || empty(l:output)
|
||||
\ || match(l:output[-1].text, s:begin_failed_skip_pattern) < 0
|
||||
\ )
|
||||
|
||||
@@ -1,17 +1,54 @@
|
||||
" Author: Vincent Lequertier <https://github.com/SkySymbol>
|
||||
" Author: Vincent Lequertier <https://github.com/SkySymbol>, Chris Weyl <cweyl@alumni.drew.edu>
|
||||
" Description: This file adds support for checking perl with perl critic
|
||||
|
||||
if !exists('g:ale_perl_perlcritic_showrules')
|
||||
let g:ale_perl_perlcritic_showrules = 0
|
||||
endif
|
||||
let g:ale_perl_perlcritic_executable =
|
||||
\ get(g:, 'ale_perl_perlcritic_executable', 'perlcritic')
|
||||
|
||||
let g:ale_perl_perlcritic_profile =
|
||||
\ get(g:, 'ale_perl_perlcritic_profile', '.perlcriticrc')
|
||||
|
||||
let g:ale_perl_perlcritic_options =
|
||||
\ get(g:, 'ale_perl_perlcritic_options', '')
|
||||
|
||||
let g:ale_perl_perlcritic_showrules =
|
||||
\ get(g:, 'ale_perl_perlcritic_showrules', 0)
|
||||
|
||||
function! ale_linters#perl#perlcritic#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'perl_perlcritic_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#perl#perlcritic#GetProfile(buffer) abort
|
||||
|
||||
" first see if we've been overridden
|
||||
let l:profile = ale#Var(a:buffer, 'perl_perlcritic_profile')
|
||||
if l:profile is? ''
|
||||
return ''
|
||||
endif
|
||||
|
||||
" otherwise, iterate upwards to find it
|
||||
return ale#path#FindNearestFile(a:buffer, l:profile)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#perl#perlcritic#GetCommand(buffer) abort
|
||||
let l:critic_verbosity = '%l:%c %m\n'
|
||||
if g:ale_perl_perlcritic_showrules
|
||||
if ale#Var(a:buffer, 'perl_perlcritic_showrules')
|
||||
let l:critic_verbosity = '%l:%c %m [%p]\n'
|
||||
endif
|
||||
|
||||
return "perlcritic --verbose '". l:critic_verbosity . "' --nocolor"
|
||||
let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'perl_perlcritic_options')
|
||||
|
||||
let l:command = ale#Escape(ale_linters#perl#perlcritic#GetExecutable(a:buffer))
|
||||
\ . " --verbose '". l:critic_verbosity . "' --nocolor"
|
||||
|
||||
if l:profile isnot? ''
|
||||
let l:command .= ' --profile ' . ale#Escape(l:profile)
|
||||
endif
|
||||
if l:options isnot? ''
|
||||
let l:command .= ' ' . l:options
|
||||
endif
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -32,8 +69,8 @@ endfunction
|
||||
|
||||
call ale#linter#Define('perl', {
|
||||
\ 'name': 'perlcritic',
|
||||
\ 'executable': 'perlcritic',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable_callback': 'ale_linters#perl#perlcritic#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand',
|
||||
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
|
||||
\})
|
||||
|
||||
34
ale_linters/php/langserver.vim
Normal file
34
ale_linters/php/langserver.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" Author: Eric Stern <eric@ericstern.com>
|
||||
" Description: PHP Language server integration for ALE
|
||||
|
||||
call ale#Set('php_langserver_executable', 'php-language-server.php')
|
||||
call ale#Set('php_langserver_use_global', 0)
|
||||
|
||||
function! ale_linters#php#langserver#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'php_langserver', [
|
||||
\ 'vendor/bin/php-language-server.php',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#langserver#GetCommand(buffer) abort
|
||||
return 'php ' . ale#Escape(ale_linters#php#langserver#GetExecutable(a:buffer))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#langserver#GetLanguage(buffer) abort
|
||||
return 'php'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'langserver',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#php#langserver#GetCommand',
|
||||
\ 'language_callback': 'ale_linters#php#langserver#GetLanguage',
|
||||
\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
|
||||
\})
|
||||
@@ -40,7 +40,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:type is# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
46
ale_linters/php/phpstan.vim
Normal file
46
ale_linters/php/phpstan.vim
Normal file
@@ -0,0 +1,46 @@
|
||||
" Author: medains <https://github.com/medains>, ardis <https://github.com/ardisdreelath>
|
||||
" Description: phpstan for PHP files
|
||||
|
||||
" Set to change the ruleset
|
||||
let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan')
|
||||
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4')
|
||||
|
||||
function! ale_linters#php#phpstan#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'php_phpstan_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#phpstan#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
\ . ' analyze -l'
|
||||
\ . ale#Var(a:buffer, 'php_phpstan_level')
|
||||
\ . ' --errorFormat raw'
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#phpstan#Handle(buffer, lines) abort
|
||||
" Matches against lines like the following:
|
||||
"
|
||||
" filename.php:15:message
|
||||
" C:\folder\filename.php:15:message
|
||||
let l:pattern = '^\([a-zA-Z]:\)\?[^:]\+:\(\d\+\):\(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'phpstan',
|
||||
\ 'executable_callback': 'ale_linters#php#phpstan#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#php#phpstan#GetCommand',
|
||||
\ 'callback': 'ale_linters#php#phpstan#Handle',
|
||||
\})
|
||||
@@ -1,10 +1,48 @@
|
||||
" Author: w0rp - <devw0rp@gmail.com>
|
||||
" Description: pug-lint for checking Pug/Jade files.
|
||||
|
||||
call ale#Set('pug_puglint_options', '')
|
||||
call ale#Set('pug_puglint_executable', 'pug-lint')
|
||||
call ale#Set('pug_puglint_use_global', 0)
|
||||
|
||||
function! ale_linters#pug#puglint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'pug_puglint', [
|
||||
\ 'node_modules/.bin/pug-lint',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! s:FindConfig(buffer) abort
|
||||
for l:filename in [
|
||||
\ '.pug-lintrc',
|
||||
\ '.pug-lintrc.js',
|
||||
\ '.pug-lintrc.json',
|
||||
\ 'package.json',
|
||||
\]
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
|
||||
|
||||
if !empty(l:config)
|
||||
return l:config
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#pug#puglint#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#pug#puglint#GetExecutable(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'pug_puglint_options')
|
||||
let l:config = s:FindConfig(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
|
||||
\ . ' -r inline %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('pug', {
|
||||
\ 'name': 'puglint',
|
||||
\ 'executable': 'pug-lint',
|
||||
\ 'executable_callback': 'ale_linters#pug#puglint#GetExecutable',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': 'pug-lint -r inline %t',
|
||||
\ 'command_callback': 'ale_linters#pug#puglint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsError',
|
||||
\})
|
||||
|
||||
@@ -19,16 +19,8 @@ function! s:UsingModule(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#flake8#GetExecutable(buffer) abort
|
||||
if !s:UsingModule(a:buffer) && !ale#Var(a:buffer, 'python_flake8_use_global')
|
||||
let l:virtualenv = ale#python#FindVirtualenv(a:buffer)
|
||||
|
||||
if !empty(l:virtualenv)
|
||||
let l:ve_flake8 = l:virtualenv . '/bin/flake8'
|
||||
|
||||
if executable(l:ve_flake8)
|
||||
return l:ve_flake8
|
||||
endif
|
||||
endif
|
||||
if !s:UsingModule(a:buffer)
|
||||
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
|
||||
endif
|
||||
|
||||
return ale#Var(a:buffer, 'python_flake8_executable')
|
||||
@@ -91,6 +83,7 @@ function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
|
||||
|
||||
return ale#Escape(ale_linters#python#flake8#GetExecutable(a:buffer))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --format=default'
|
||||
\ . l:display_name_args . ' -'
|
||||
endfunction
|
||||
|
||||
@@ -123,7 +116,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:code = l:match[3]
|
||||
|
||||
if (l:code ==# 'W291' || l:code ==# 'W293')
|
||||
if (l:code is# 'W291' || l:code is# 'W293')
|
||||
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
@@ -136,12 +129,12 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
|
||||
\ 'type': 'W',
|
||||
\}
|
||||
|
||||
if l:code[:0] ==# 'F' || l:code ==# 'E999'
|
||||
if l:code[:0] is# 'F' || l:code is# 'E999'
|
||||
let l:item.type = 'E'
|
||||
elseif l:code[:0] ==# 'E'
|
||||
elseif l:code[:0] is# 'E'
|
||||
let l:item.type = 'E'
|
||||
let l:item.sub_type = 'style'
|
||||
elseif l:code[:0] ==# 'W'
|
||||
elseif l:code[:0] is# 'W'
|
||||
let l:item.sub_type = 'style'
|
||||
endif
|
||||
|
||||
|
||||
@@ -7,17 +7,25 @@ let g:ale_python_mypy_options = get(g:, 'ale_python_mypy_options', '')
|
||||
let g:ale_python_mypy_use_global = get(g:, 'ale_python_mypy_use_global', 0)
|
||||
|
||||
function! ale_linters#python#mypy#GetExecutable(buffer) abort
|
||||
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['/bin/mypy'])
|
||||
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy'])
|
||||
endfunction
|
||||
|
||||
" The directory to change to before running mypy
|
||||
function! s:GetDir(buffer) abort
|
||||
let l:project_root = ale#python#FindProjectRoot(a:buffer)
|
||||
|
||||
return !empty(l:project_root)
|
||||
\ ? l:project_root
|
||||
\ : expand('#' . a:buffer . ':p:h')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#mypy#GetCommand(buffer) abort
|
||||
let l:project_root = ale#python#FindProjectRoot(a:buffer)
|
||||
let l:cd_command = !empty(l:project_root)
|
||||
\ ? ale#path#CdString(l:project_root)
|
||||
\ : ''
|
||||
let l:dir = s:GetDir(a:buffer)
|
||||
let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer)
|
||||
|
||||
return l:cd_command
|
||||
" We have to always switch to an explicit directory for a command so
|
||||
" we can know with certainty the base path for the 'filename' keys below.
|
||||
return ale#path#CdString(l:dir)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ . ' --show-column-numbers '
|
||||
\ . ale#Var(a:buffer, 'python_mypy_options')
|
||||
@@ -25,6 +33,7 @@ function! ale_linters#python#mypy#GetCommand(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
let l:dir = s:GetDir(a:buffer)
|
||||
" Look for lines like the following:
|
||||
"
|
||||
" file.py:4: error: No library stub file for module 'django.db'
|
||||
@@ -34,17 +43,13 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
" file.py:4: note: (Stub files are from https://github.com/python/typeshed)
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$'
|
||||
let l:output = []
|
||||
let l:buffer_filename = expand('#' . a:buffer . ':p')
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
if l:buffer_filename[-len(l:match[1]):] !=# l:match[1]
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[4] =~# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
|
||||
\ 'text': l:match[5],
|
||||
\})
|
||||
endfor
|
||||
|
||||
42
ale_linters/python/pycodestyle.vim
Normal file
42
ale_linters/python/pycodestyle.vim
Normal file
@@ -0,0 +1,42 @@
|
||||
" Author: Michael Thiesen <micthiesen@gmail.com>
|
||||
" Description: pycodestyle linting for python files
|
||||
|
||||
call ale#Set('python_pycodestyle_executable', 'pycodestyle')
|
||||
call ale#Set('python_pycodestyle_options', '')
|
||||
call ale#Set('python_pycodestyle_use_global', 0)
|
||||
|
||||
function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
|
||||
return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle'])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pycodestyle#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#python#pycodestyle#GetExecutable(a:buffer))
|
||||
\ . ' '
|
||||
\ . ale#Var(a:buffer, 'python_pycodestyle_options')
|
||||
\ . ' -'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pycodestyle#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v^(\S*):(\d*):(\d*): ((([EW])\d+) .*)$'
|
||||
let l:output = []
|
||||
|
||||
" lines are formatted as follows:
|
||||
" file.py:21:26: W291 trailing whitespace
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[6],
|
||||
\ 'text': l:match[4],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'pycodestyle',
|
||||
\ 'executable_callback': 'ale_linters#python#pycodestyle#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#python#pycodestyle#GetCommand',
|
||||
\ 'callback': 'ale_linters#python#pycodestyle#Handle',
|
||||
\})
|
||||
@@ -10,19 +10,7 @@ let g:ale_python_pylint_options =
|
||||
let g:ale_python_pylint_use_global = get(g:, 'ale_python_pylint_use_global', 0)
|
||||
|
||||
function! ale_linters#python#pylint#GetExecutable(buffer) abort
|
||||
if !ale#Var(a:buffer, 'python_pylint_use_global')
|
||||
let l:virtualenv = ale#python#FindVirtualenv(a:buffer)
|
||||
|
||||
if !empty(l:virtualenv)
|
||||
let l:ve_pylint = l:virtualenv . '/bin/pylint'
|
||||
|
||||
if executable(l:ve_pylint)
|
||||
return l:ve_pylint
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
return ale#Var(a:buffer, 'python_pylint_executable')
|
||||
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pylint#GetCommand(buffer) abort
|
||||
@@ -43,13 +31,13 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
|
||||
"let l:failed = append(0, l:match)
|
||||
let l:code = l:match[3]
|
||||
|
||||
if (l:code ==# 'C0303')
|
||||
if (l:code is# 'C0303')
|
||||
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
|
||||
if l:code ==# 'I0011'
|
||||
if l:code is# 'I0011'
|
||||
" Skip 'Locally disabling' message
|
||||
continue
|
||||
endif
|
||||
@@ -58,7 +46,7 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 1,
|
||||
\ 'text': l:code . ': ' . l:match[5] . ' (' . l:match[4] . ')',
|
||||
\ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
|
||||
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
15
ale_linters/r/lintr.vim
Normal file
15
ale_linters/r/lintr.vim
Normal file
@@ -0,0 +1,15 @@
|
||||
" Author: Michel Lang <michellang@gmail.com>, w0rp <devw0rp@gmail.com>
|
||||
" Description: This file adds support for checking R code with lintr.
|
||||
|
||||
function! ale_linters#r#lintr#GetCommand(buffer) abort
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . 'Rscript -e ' . ale#Escape('lintr::lint(commandArgs(TRUE))') . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('r', {
|
||||
\ 'name': 'lintr',
|
||||
\ 'executable': 'Rscript',
|
||||
\ 'command_callback': 'ale_linters#r#lintr#GetCommand',
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'output_stream': 'both',
|
||||
\})
|
||||
@@ -5,13 +5,12 @@ let g:ale_ruby_brakeman_options =
|
||||
\ get(g:, 'ale_ruby_brakeman_options', '')
|
||||
|
||||
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
|
||||
let l:result = json_decode(join(a:lines, ''))
|
||||
|
||||
let l:output = []
|
||||
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
|
||||
|
||||
for l:warning in l:result.warnings
|
||||
for l:warning in get(l:json, 'warnings', [])
|
||||
" Brakeman always outputs paths relative to the Rails app root
|
||||
let l:rails_root = s:FindRailsRoot(a:buffer)
|
||||
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
|
||||
let l:warning_file = l:rails_root . '/' . l:warning.file
|
||||
|
||||
if !ale#path#IsBufferPath(a:buffer, l:warning_file)
|
||||
@@ -32,9 +31,9 @@ function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
|
||||
let l:rails_root = s:FindRailsRoot(a:buffer)
|
||||
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
|
||||
|
||||
if l:rails_root ==? ''
|
||||
if l:rails_root is? ''
|
||||
return ''
|
||||
endif
|
||||
|
||||
@@ -43,26 +42,6 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
|
||||
\ . ' -p ' . ale#Escape(l:rails_root)
|
||||
endfunction
|
||||
|
||||
function! s:FindRailsRoot(buffer) abort
|
||||
" Find the nearest dir contining "app", "db", and "config", and assume it is
|
||||
" the root of a Rails app.
|
||||
for l:name in ['app', 'config', 'db']
|
||||
let l:dir = fnamemodify(
|
||||
\ ale#path#FindNearestDirectory(a:buffer, l:name),
|
||||
\ ':h:h'
|
||||
\)
|
||||
|
||||
if l:dir !=# '.'
|
||||
\&& isdirectory(l:dir . '/app')
|
||||
\&& isdirectory(l:dir . '/config')
|
||||
\&& isdirectory(l:dir . '/db')
|
||||
return l:dir
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'brakeman',
|
||||
\ 'executable': 'brakeman',
|
||||
|
||||
53
ale_linters/ruby/rails_best_practices.vim
Normal file
53
ale_linters/ruby/rails_best_practices.vim
Normal file
@@ -0,0 +1,53 @@
|
||||
" Author: Eddie Lebow https://github.com/elebow
|
||||
" Description: rails_best_practices, a code metric tool for rails projects
|
||||
|
||||
let g:ale_ruby_rails_best_practices_options =
|
||||
\ get(g:, 'ale_ruby_rails_best_practices_options', '')
|
||||
|
||||
function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
for l:warning in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
if !ale#path#IsBufferPath(a:buffer, l:warning.filename)
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:warning.line_number + 0,
|
||||
\ 'type': 'W',
|
||||
\ 'text': l:warning.message,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
|
||||
let l:executable = ale#handlers#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: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
|
||||
\ . ' --silent -f json --output-file ' . l:output_file
|
||||
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
|
||||
\ . ale#Escape(l:rails_root)
|
||||
\ . l:cat_file
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'rails_best_practices',
|
||||
\ 'executable_callback': 'ale#handlers#rails_best_practices#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
|
||||
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
@@ -1,22 +1,13 @@
|
||||
" Author: Eddie Lebow https://github.com/elebow
|
||||
" Description: Reek, a code smell detector for Ruby files
|
||||
|
||||
let g:ale_ruby_reek_show_context =
|
||||
\ get(g:, 'ale_ruby_reek_show_context', 0)
|
||||
|
||||
let g:ale_ruby_reek_show_wiki_link =
|
||||
\ get(g:, 'ale_ruby_reek_show_wiki_link', 0)
|
||||
call ale#Set('ruby_reek_show_context', 0)
|
||||
call ale#Set('ruby_reek_show_wiki_link', 0)
|
||||
|
||||
function! ale_linters#ruby#reek#Handle(buffer, lines) abort
|
||||
if len(a:lines) == 0
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:errors = json_decode(a:lines[0])
|
||||
|
||||
let l:output = []
|
||||
|
||||
for l:error in l:errors
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
for l:location in l:error.lines
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:location,
|
||||
|
||||
@@ -1,58 +1,60 @@
|
||||
" Author: ynonp - https://github.com/ynonp
|
||||
" Description: rubocop for Ruby files
|
||||
|
||||
" Set this option to change Rubocop options.
|
||||
if !exists('g:ale_ruby_rubocop_options')
|
||||
" let g:ale_ruby_rubocop_options = '--lint'
|
||||
let g:ale_ruby_rubocop_options = ''
|
||||
endif
|
||||
|
||||
if !exists('g:ale_ruby_rubocop_executable')
|
||||
let g:ale_ruby_rubocop_executable = 'rubocop'
|
||||
endif
|
||||
|
||||
function! ale_linters#ruby#rubocop#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'ruby_rubocop_executable')
|
||||
endfunction
|
||||
" Author: ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow
|
||||
" Description: RuboCop, a code style analyzer for Ruby files
|
||||
|
||||
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
|
||||
let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
|
||||
let l:exec_args = l:executable =~? 'bundle$'
|
||||
\ ? ' exec rubocop'
|
||||
\ : ''
|
||||
|
||||
return ale#Escape(l:executable) . l:exec_args
|
||||
\ . ' --format emacs --force-exclusion '
|
||||
\ . ' --format json --force-exclusion '
|
||||
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
|
||||
\ . ' --stdin ' . bufname(a:buffer)
|
||||
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" <path>:83:29: C: Prefer single-quoted strings when you don't
|
||||
" need string interpolation or special symbols.
|
||||
let l:pattern = '\v:(\d+):(\d+): (.): (.+)'
|
||||
try
|
||||
let l:errors = json_decode(a:lines[0])
|
||||
catch
|
||||
return []
|
||||
endtry
|
||||
|
||||
if !has_key(l:errors, 'summary')
|
||||
\|| l:errors['summary']['offense_count'] == 0
|
||||
\|| empty(l:errors['files'])
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:text = l:match[4]
|
||||
let l:type = l:match[3]
|
||||
|
||||
for l:error in l:errors['files'][0]['offenses']
|
||||
let l:start_col = l:error['location']['column'] + 0
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': index(['F', 'E'], l:type) != -1 ? 'E' : 'W',
|
||||
\ 'lnum': l:error['location']['line'] + 0,
|
||||
\ 'col': l:start_col,
|
||||
\ 'end_col': l:start_col + l:error['location']['length'] - 1,
|
||||
\ 'text': printf('%s [%s]', l:error['message'], l:error['cop_name']),
|
||||
\ 'type': ale_linters#ruby#rubocop#GetType(l:error['severity']),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#rubocop#GetType(severity) abort
|
||||
if a:severity is? 'convention'
|
||||
\|| a:severity is? 'warning'
|
||||
\|| a:severity is? 'refactor'
|
||||
return 'W'
|
||||
endif
|
||||
|
||||
return 'E'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'rubocop',
|
||||
\ 'executable_callback': 'ale_linters#ruby#rubocop#GetExecutable',
|
||||
\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
|
||||
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
|
||||
\})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
let g:ale_rust_cargo_use_check = get(g:, 'ale_rust_cargo_use_check', 0)
|
||||
|
||||
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
|
||||
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') !=# ''
|
||||
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
|
||||
return 'cargo'
|
||||
else
|
||||
" if there is no Cargo.toml file, we don't use cargo even if it exists,
|
||||
|
||||
33
ale_linters/rust/rls.vim
Normal file
33
ale_linters/rust/rls.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: A language server for Rust
|
||||
|
||||
call ale#Set('rust_rls_executable', 'rls')
|
||||
|
||||
function! ale_linters#rust#rls#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'rust_rls_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#rust#rls#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#rust#rls#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable) . ' +nightly'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#rust#rls#GetLanguage(buffer) abort
|
||||
return 'rust'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#rust#rls#GetProjectRoot(buffer) abort
|
||||
let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
|
||||
|
||||
return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('rust', {
|
||||
\ 'name': 'rls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable_callback': 'ale_linters#rust#rls#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
|
||||
\ 'language_callback': 'ale_linters#rust#rls#GetLanguage',
|
||||
\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
|
||||
\})
|
||||
@@ -7,7 +7,7 @@ function! ale_linters#rust#rustc#RustcCommand(buffer_number) abort
|
||||
" <project root>/target/release/deps/
|
||||
let l:cargo_file = ale#path#FindNearestFile(a:buffer_number, 'Cargo.toml')
|
||||
|
||||
if l:cargo_file !=# ''
|
||||
if l:cargo_file isnot# ''
|
||||
let l:project_root = fnamemodify(l:cargo_file, ':h')
|
||||
let l:dependencies = '-L ' . l:project_root . '/target/debug/deps -L ' .
|
||||
\ l:project_root . '/target/release/deps'
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
" Author: Zoltan Kalmar - https://github.com/kalmiz
|
||||
" Author: Zoltan Kalmar - https://github.com/kalmiz,
|
||||
" w0rp <devw0rp@gmail.com>
|
||||
" Description: Basic scala support using scalac
|
||||
|
||||
function! ale_linters#scala#scalac#GetExecutable(buffer) abort
|
||||
if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
|
||||
" Don't check sbt files with scalac.
|
||||
return ''
|
||||
endif
|
||||
|
||||
return 'scalac'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scala#scalac#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#scala#scalac#GetExecutable(a:buffer)
|
||||
|
||||
if empty(l:executable)
|
||||
return ''
|
||||
endif
|
||||
|
||||
return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scala#scalac#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
@@ -18,7 +38,7 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) abort
|
||||
endif
|
||||
|
||||
let l:text = l:match[3]
|
||||
let l:type = l:match[2] ==# 'error' ? 'E' : 'W'
|
||||
let l:type = l:match[2] is# 'error' ? 'E' : 'W'
|
||||
let l:col = 0
|
||||
|
||||
if l:ln + 1 < len(a:lines)
|
||||
@@ -38,8 +58,8 @@ endfunction
|
||||
|
||||
call ale#linter#Define('scala', {
|
||||
\ 'name': 'scalac',
|
||||
\ 'executable': 'scalac',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': 'scalac -Ystop-after:parser %t',
|
||||
\ 'executable_callback': 'ale_linters#scala#scalac#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#scala#scalac#GetCommand',
|
||||
\ 'callback': 'ale_linters#scala#scalac#Handle',
|
||||
\ 'output_stream': 'stderr',
|
||||
\})
|
||||
|
||||
83
ale_linters/scala/scalastyle.vim
Normal file
83
ale_linters/scala/scalastyle.vim
Normal file
@@ -0,0 +1,83 @@
|
||||
" Author: Kevin Kays - https://github.com/okkays
|
||||
" Description: Support for the scalastyle checker.
|
||||
|
||||
let g:ale_scala_scalastyle_options =
|
||||
\ get(g:, 'ale_scala_scalastyle_options', '')
|
||||
|
||||
let g:ale_scalastyle_config_loc =
|
||||
\ get(g:, 'ale_scalastyle_config_loc', '')
|
||||
|
||||
function! ale_linters#scala#scalastyle#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" warning file=/home/blurble/Doop.scala message=Missing or badly formed ScalaDoc: Extra @param foobles line=190
|
||||
|
||||
let l:patterns = [
|
||||
\ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\)$',
|
||||
\ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\) column=\(\d\+\)$',
|
||||
\]
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:patterns)
|
||||
let l:args = {
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'type': l:match[1] =~? 'error' ? 'E' : 'W',
|
||||
\ 'text': l:match[2]
|
||||
\}
|
||||
|
||||
if !empty(l:match[4])
|
||||
let l:args['col'] = l:match[4] + 1
|
||||
endif
|
||||
|
||||
call add(l:output, l:args)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scala#scalastyle#GetCommand(buffer) abort
|
||||
" Search for scalastyle config in parent directories.
|
||||
let l:scalastyle_config = ''
|
||||
let l:potential_configs = [
|
||||
\ 'scalastyle_config.xml',
|
||||
\ 'scalastyle-config.xml'
|
||||
\]
|
||||
for l:config in l:potential_configs
|
||||
let l:scalastyle_config = ale#path#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ l:config,
|
||||
\ ''
|
||||
\)
|
||||
if !empty(l:scalastyle_config)
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" If all else fails, try the global config.
|
||||
if empty(l:scalastyle_config)
|
||||
let l:scalastyle_config = get(g:, 'ale_scalastyle_config_loc', '')
|
||||
endif
|
||||
|
||||
" Build the command using the config file and additional options.
|
||||
let l:command = 'scalastyle'
|
||||
|
||||
if !empty(l:scalastyle_config)
|
||||
let l:command .= ' --config ' . ale#Escape(l:scalastyle_config)
|
||||
endif
|
||||
|
||||
if !empty(g:ale_scala_scalastyle_options)
|
||||
let l:command .= ' ' . g:ale_scala_scalastyle_options
|
||||
endif
|
||||
|
||||
let l:command .= ' %t'
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('scala', {
|
||||
\ 'name': 'scalastyle',
|
||||
\ 'executable': 'scalastyle',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'command_callback': 'ale_linters#scala#scalastyle#GetCommand',
|
||||
\ 'callback': 'ale_linters#scala#scalastyle#Handle',
|
||||
\})
|
||||
@@ -19,7 +19,7 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:match[3] ==# 'E' ? 'E' : 'W',
|
||||
\ 'type': l:match[3] is# 'E' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -11,24 +11,16 @@ endif
|
||||
if !exists('g:ale_sh_shell_default_shell')
|
||||
let g:ale_sh_shell_default_shell = fnamemodify($SHELL, ':t')
|
||||
|
||||
if g:ale_sh_shell_default_shell ==# '' || g:ale_sh_shell_default_shell ==# 'fish'
|
||||
if g:ale_sh_shell_default_shell is# '' || g:ale_sh_shell_default_shell is# 'fish'
|
||||
let g:ale_sh_shell_default_shell = 'bash'
|
||||
endif
|
||||
endif
|
||||
|
||||
function! ale_linters#sh#shell#GetExecutable(buffer) abort
|
||||
let l:banglines = getbufline(a:buffer, 1)
|
||||
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
|
||||
|
||||
" Take the shell executable from the hashbang, if we can.
|
||||
if len(l:banglines) == 1 && l:banglines[0] =~# '^#!'
|
||||
" Remove options like -e, etc.
|
||||
let l:line = substitute(l:banglines[0], '--\?[a-zA-Z0-9]\+', '', 'g')
|
||||
|
||||
for l:possible_shell in ['bash', 'tcsh', 'csh', 'zsh', 'sh']
|
||||
if l:line =~# l:possible_shell . '\s*$'
|
||||
return l:possible_shell
|
||||
endif
|
||||
endfor
|
||||
if !empty(l:shell_type)
|
||||
return l:shell_type
|
||||
endif
|
||||
|
||||
return ale#Var(a:buffer, 'sh_shell_default_shell')
|
||||
|
||||
@@ -19,25 +19,35 @@ function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'sh_shellcheck_executable')
|
||||
endfunction
|
||||
|
||||
function! s:GetDialectArgument() abort
|
||||
if exists('b:is_bash') && b:is_bash
|
||||
return '-s bash'
|
||||
elseif exists('b:is_sh') && b:is_sh
|
||||
return '-s sh'
|
||||
elseif exists('b:is_kornshell') && b:is_kornshell
|
||||
return '-s ksh'
|
||||
function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort
|
||||
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
|
||||
|
||||
if !empty(l:shell_type)
|
||||
return l:shell_type
|
||||
endif
|
||||
|
||||
" If there's no hashbang, try using Vim's buffer variables.
|
||||
if get(b:, 'is_bash')
|
||||
return 'bash'
|
||||
elseif get(b:, 'is_sh')
|
||||
return 'sh'
|
||||
elseif get(b:, 'is_kornshell')
|
||||
return 'ksh'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shellcheck#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
|
||||
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
|
||||
let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer)
|
||||
|
||||
return ale_linters#sh#shellcheck#GetExecutable(a:buffer)
|
||||
\ . ' ' . ale#Var(a:buffer, 'sh_shellcheck_options')
|
||||
\ . ' ' . (!empty(l:exclude_option) ? '-e ' . l:exclude_option : '')
|
||||
\ . ' ' . s:GetDialectArgument() . ' -f gcc -'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
|
||||
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
|
||||
\ . ' -f gcc -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sh', {
|
||||
|
||||
@@ -29,7 +29,7 @@ function! ale_linters#sml#smlnj#Handle(buffer, lines) abort
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'text': l:match[2] . ': ' . l:match[3],
|
||||
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[2] is# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
continue
|
||||
endif
|
||||
|
||||
24
ale_linters/stylus/stylelint.vim
Normal file
24
ale_linters/stylus/stylelint.vim
Normal file
@@ -0,0 +1,24 @@
|
||||
" Author: diartyz <diartyz@gmail.com>, w0rp <devw0rp@gmail.com>
|
||||
|
||||
call ale#Set('stylus_stylelint_executable', 'stylelint')
|
||||
call ale#Set('stylus_stylelint_options', '')
|
||||
call ale#Set('stylus_stylelint_use_global', 0)
|
||||
|
||||
function! ale_linters#stylus#stylelint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'stylus_stylelint', [
|
||||
\ 'node_modules/.bin/stylelint',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#stylus#stylelint#GetCommand(buffer) abort
|
||||
return ale_linters#stylus#stylelint#GetExecutable(a:buffer)
|
||||
\ . ' ' . ale#Var(a:buffer, 'stylus_stylelint_options')
|
||||
\ . ' --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('stylus', {
|
||||
\ 'name': 'stylelint',
|
||||
\ 'executable_callback': 'ale_linters#stylus#stylelint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#stylus#stylelint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
|
||||
\})
|
||||
46
ale_linters/tcl/nagelfar.vim
Normal file
46
ale_linters/tcl/nagelfar.vim
Normal file
@@ -0,0 +1,46 @@
|
||||
" Author: Nick James <github@nsjuk.xyz>
|
||||
" Description: nagelfar linter for tcl files
|
||||
|
||||
call ale#Set('tcl_nagelfar_executable', 'nagelfar.tcl')
|
||||
call ale#Set('tcl_nagelfar_options', '')
|
||||
|
||||
function! ale_linters#tcl#nagelfar#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'tcl_nagelfar_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tcl#nagelfar#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'tcl_nagelfar_options')
|
||||
|
||||
return ale#Escape(ale_linters#tcl#nagelfar#GetExecutable(a:buffer))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" Line 5: W Found constant "bepa" which is also a variable.
|
||||
" Line 13: E Wrong number of arguments (3) to "set"
|
||||
" Line 93: N Close brace not aligned with line 90 (4 0)
|
||||
|
||||
let l:pattern = '^Line\s\+\([0-9]\+\): \([NEW]\) \(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'type': l:match[2] is# 'N' ? 'W' : l:match[2],
|
||||
\ 'text': l:match[3],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('tcl', {
|
||||
\ 'name': 'nagelfar',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable_callback': 'ale_linters#tcl#nagelfar#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#tcl#nagelfar#GetCommand',
|
||||
\ 'callback': 'ale_linters#tcl#nagelfar#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
@@ -12,25 +12,27 @@ function! ale_linters#typescript#tslint#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
|
||||
let l:dir = expand('#' . a:buffer . ':p:h')
|
||||
let l:output = []
|
||||
|
||||
for l:error in json_decode(join(a:lines, ''))
|
||||
if ale#path#IsBufferPath(a:buffer, l:error.name)
|
||||
call add(l:output, {
|
||||
\ 'type': (get(l:error, 'ruleSeverity', '') ==# 'WARNING' ? 'W' : 'E'),
|
||||
\ 'text': l:error.failure,
|
||||
\ 'lnum': l:error.startPosition.line + 1,
|
||||
\ 'col': l:error.startPosition.character + 1,
|
||||
\ 'end_lnum': l:error.endPosition.line + 1,
|
||||
\ 'end_col': l:error.endPosition.character + 1,
|
||||
\})
|
||||
endif
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:error.name),
|
||||
\ 'type': (get(l:error, 'ruleSeverity', '') is# 'WARNING' ? 'W' : 'E'),
|
||||
\ 'text': has_key(l:error, 'ruleName')
|
||||
\ ? l:error.ruleName . ': ' . l:error.failure
|
||||
\ : l:error.failure,
|
||||
\ 'lnum': l:error.startPosition.line + 1,
|
||||
\ 'col': l:error.startPosition.character + 1,
|
||||
\ 'end_lnum': l:error.endPosition.line + 1,
|
||||
\ 'end_col': l:error.endPosition.character + 1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort
|
||||
function! ale_linters#typescript#tslint#GetCommand(buffer) abort
|
||||
let l:tslint_config_path = ale#path#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'tslint.json',
|
||||
@@ -41,7 +43,8 @@ function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort
|
||||
\ ? ' -c ' . ale#Escape(l:tslint_config_path)
|
||||
\ : ''
|
||||
|
||||
return ale_linters#typescript#tslint#GetExecutable(a:buffer)
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale_linters#typescript#tslint#GetExecutable(a:buffer)
|
||||
\ . ' --format json'
|
||||
\ . l:tslint_config_option
|
||||
\ . ' %t'
|
||||
@@ -50,6 +53,6 @@ endfunction
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'tslint',
|
||||
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
|
||||
\ 'command_callback': 'ale_linters#typescript#tslint#GetCommand',
|
||||
\ 'callback': 'ale_linters#typescript#tslint#Handle',
|
||||
\})
|
||||
|
||||
@@ -5,19 +5,26 @@ call ale#Set('typescript_tsserver_executable', 'tsserver')
|
||||
call ale#Set('typescript_tsserver_config_path', '')
|
||||
call ale#Set('typescript_tsserver_use_global', 0)
|
||||
|
||||
" These functions need to be defined just to comply with the API for LSP.
|
||||
function! ale_linters#typescript#tsserver#GetProjectRoot(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tsserver#GetLanguage(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [
|
||||
\ 'node_modules/.bin/tsserver',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tsserver#Handle(buffer, lines) abort
|
||||
return a:lines
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'tsserver',
|
||||
\ 'lsp': 'tsserver',
|
||||
\ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable',
|
||||
\ 'callback': 'ale_linters#typescript#tsserver#Handle',
|
||||
\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable',
|
||||
\ 'project_root_callback': 'ale_linters#typescript#tsserver#GetProjectRoot',
|
||||
\ 'language_callback': 'ale_linters#typescript#tsserver#GetLanguage',
|
||||
\})
|
||||
|
||||
@@ -14,7 +14,7 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:line = l:match[1] + 0
|
||||
let l:type = l:match[2] =~# 'error' ? 'E' : 'W'
|
||||
let l:text = l:match[2] ==# 'syntax error' ? 'syntax error' : l:match[4]
|
||||
let l:text = l:match[2] is# 'syntax error' ? 'syntax error' : l:match[4]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:line,
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: verilator for verilog files
|
||||
|
||||
" Set this option to change Verilator lint options
|
||||
if !exists('g:ale_verilog_verilator_options')
|
||||
let g:ale_verilog_verilator_options = ''
|
||||
endif
|
||||
|
||||
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
|
||||
let l:filename = tempname() . '_verilator_linted.v'
|
||||
|
||||
" Create a special filename, so we can detect it in the handler.
|
||||
call ale#engine#ManageFile(a:buffer, l:filename)
|
||||
call writefile(getbufline(a:buffer, 1, '$'), l:filename)
|
||||
let l:lines = getbufline(a:buffer, 1, '$')
|
||||
call ale#util#Writefile(a:buffer, l:lines, l:filename)
|
||||
|
||||
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' . ale#Escape(l:filename)
|
||||
return 'verilator --lint-only -Wall -Wno-DECLFILENAME '
|
||||
\ . ale#Var(a:buffer, 'verilog_verilator_options') .' '
|
||||
\ . ale#Escape(l:filename)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
@@ -25,7 +33,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:line = l:match[3] + 0
|
||||
let l:type = l:match[1] ==# 'Error' ? 'E' : 'W'
|
||||
let l:type = l:match[1] is# 'Error' ? 'E' : 'W'
|
||||
let l:text = l:match[4]
|
||||
let l:file = l:match[2]
|
||||
|
||||
|
||||
@@ -36,6 +36,32 @@ function! ale_linters#vim#vint#GetCommand(buffer, version_output) abort
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
let s:word_regex_list = [
|
||||
\ '\v^Undefined variable: ([^ ]+)',
|
||||
\ '\v^Make the scope explicit like ...([^ ]+). ',
|
||||
\ '\v^.*start with a capital or contain a colon: ([^ ]+)',
|
||||
\ '\v.*instead of .(\=[=~]).',
|
||||
\]
|
||||
|
||||
function! ale_linters#vim#vint#Handle(buffer, lines) abort
|
||||
let l:loclist = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
|
||||
|
||||
for l:item in l:loclist
|
||||
let l:match = []
|
||||
|
||||
for l:regex in s:word_regex_list
|
||||
let l:match = matchlist(l:item.text, l:regex)
|
||||
|
||||
if !empty(l:match)
|
||||
let l:item.end_col = l:item.col + len(l:match[1]) - 1
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return l:loclist
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('vim', {
|
||||
\ 'name': 'vint',
|
||||
\ 'executable': 'vint',
|
||||
@@ -43,5 +69,5 @@ call ale#linter#Define('vim', {
|
||||
\ {'callback': 'ale_linters#vim#vint#VersionCommand', 'output_stream': 'stderr'},
|
||||
\ {'callback': 'ale_linters#vim#vint#GetCommand', 'output_stream': 'stdout'},
|
||||
\ ],
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'callback': 'ale_linters#vim#vint#Handle',
|
||||
\})
|
||||
|
||||
41
ale_linters/yaml/swaglint.vim
Normal file
41
ale_linters/yaml/swaglint.vim
Normal file
@@ -0,0 +1,41 @@
|
||||
" Author: Matthew Turland <https://github.com/elazar>
|
||||
" Description: This file adds support for linting Swagger / OpenAPI documents using swaglint
|
||||
|
||||
call ale#Set('yaml_swaglint_executable', 'swaglint')
|
||||
call ale#Set('yaml_swaglint_use_global', 0)
|
||||
|
||||
function! ale_linters#yaml#swaglint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'yaml_swaglint', [
|
||||
\ 'node_modules/.bin/swaglint',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#yaml#swaglint#GetCommand(buffer) abort
|
||||
return ale_linters#yaml#swaglint#GetExecutable(a:buffer)
|
||||
\ . ' -r compact --stdin'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#yaml#swaglint#Handle(buffer, lines) abort
|
||||
let l:pattern = ': \([^\s]\+\) @ \(\d\+\):\(\d\+\) - \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:obj = {
|
||||
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\}
|
||||
|
||||
call add(l:output, l:obj)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('yaml', {
|
||||
\ 'name': 'swaglint',
|
||||
\ 'executable_callback': 'ale_linters#yaml#swaglint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#yaml#swaglint#GetCommand',
|
||||
\ 'callback': 'ale_linters#yaml#swaglint#Handle',
|
||||
\})
|
||||
@@ -33,7 +33,7 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:type is# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
133
autoload/ale.vim
133
autoload/ale.vim
@@ -5,6 +5,31 @@
|
||||
let s:lint_timer = -1
|
||||
let s:queued_buffer_number = -1
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
let s:error_delay_ms = 1000 * 60 * 2
|
||||
|
||||
let s:timestamp_map = {}
|
||||
|
||||
" Given a key for a script variable for tracking the time to wait until
|
||||
" a given function should be called, a funcref for a function to call, and
|
||||
" a List of arguments, call the function and return whatever value it returns.
|
||||
"
|
||||
" If the function throws an exception, then the function will not be called
|
||||
" for a while, and 0 will be returned instead.
|
||||
function! ale#CallWithCooldown(timestamp_key, func, arglist) abort
|
||||
let l:now = ale#util#ClockMilliseconds()
|
||||
|
||||
if l:now < get(s:timestamp_map, a:timestamp_key, -1)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let s:timestamp_map[a:timestamp_key] = l:now + s:error_delay_ms
|
||||
|
||||
let l:return_value = call(a:func, a:arglist)
|
||||
|
||||
let s:timestamp_map[a:timestamp_key] = -1
|
||||
|
||||
return l:return_value
|
||||
endfunction
|
||||
|
||||
" Return 1 if a file is too large for ALE to handle.
|
||||
function! ale#FileTooLarge() abort
|
||||
@@ -15,36 +40,50 @@ endfunction
|
||||
|
||||
" A function for checking various conditions whereby ALE just shouldn't
|
||||
" attempt to do anything, say if particular buffer types are open in Vim.
|
||||
function! ale#ShouldDoNothing() abort
|
||||
function! ale#ShouldDoNothing(buffer) abort
|
||||
" Do nothing for blacklisted files
|
||||
" OR if ALE is running in the sandbox
|
||||
return index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
\ || (exists('*getcmdwintype') && !empty(getcmdwintype()))
|
||||
\ || ale#util#InSandbox()
|
||||
\ || !ale#Var(bufnr(''), 'enabled')
|
||||
\ || !ale#Var(a:buffer, 'enabled')
|
||||
\ || ale#FileTooLarge()
|
||||
\ || getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky'
|
||||
endfunction
|
||||
|
||||
" (delay, [linting_flag])
|
||||
" (delay, [linting_flag, buffer_number])
|
||||
function! ale#Queue(delay, ...) abort
|
||||
if len(a:0) > 1
|
||||
if a:0 > 2
|
||||
throw 'too many arguments!'
|
||||
endif
|
||||
|
||||
" Default linting_flag to ''
|
||||
let l:linting_flag = get(a:000, 0, '')
|
||||
let l:buffer = get(a:000, 1, bufnr(''))
|
||||
|
||||
if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
|
||||
return ale#CallWithCooldown(
|
||||
\ 'dont_queue_until',
|
||||
\ function('s:ALEQueueImpl'),
|
||||
\ [a:delay, l:linting_flag, l:buffer],
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
|
||||
if a:linting_flag isnot# '' && a:linting_flag isnot# 'lint_file'
|
||||
throw "linting_flag must be either '' or 'lint_file'"
|
||||
endif
|
||||
|
||||
if ale#ShouldDoNothing()
|
||||
if type(a:buffer) != type(0)
|
||||
throw 'buffer_number must be a Number'
|
||||
endif
|
||||
|
||||
if ale#ShouldDoNothing(a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
" Remember that we want to check files for this buffer.
|
||||
" We will remember this until we finally run the linters, via any event.
|
||||
if l:linting_flag ==# 'lint_file'
|
||||
if a:linting_flag is# 'lint_file'
|
||||
let s:should_lint_file_for_buffer[bufnr('%')] = 1
|
||||
endif
|
||||
|
||||
@@ -53,63 +92,63 @@ function! ale#Queue(delay, ...) abort
|
||||
let s:lint_timer = -1
|
||||
endif
|
||||
|
||||
let l:linters = ale#linter#Get(&filetype)
|
||||
if len(l:linters) == 0
|
||||
" There are no linters to lint with, so stop here.
|
||||
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
|
||||
" Don't set up buffer data and so on if there are no linters to run.
|
||||
if empty(l:linters)
|
||||
" If we have some previous buffer data, then stop any jobs currently
|
||||
" running and clear everything.
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RunLinters(a:buffer, [], 1)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
if a:delay > 0
|
||||
let s:queued_buffer_number = bufnr('%')
|
||||
let s:queued_buffer_number = a:buffer
|
||||
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
|
||||
else
|
||||
call ale#Lint()
|
||||
call ale#Lint(-1, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#Lint(...) abort
|
||||
if ale#ShouldDoNothing()
|
||||
if a:0 > 1
|
||||
" Use the buffer number given as the optional second argument.
|
||||
let l:buffer = a:2
|
||||
elseif a:0 > 0 && a:1 == s:lint_timer
|
||||
" Use the buffer number for the buffer linting was queued for.
|
||||
let l:buffer = s:queued_buffer_number
|
||||
else
|
||||
" Use the current buffer number.
|
||||
let l:buffer = bufnr('')
|
||||
endif
|
||||
|
||||
return ale#CallWithCooldown(
|
||||
\ 'dont_lint_until',
|
||||
\ function('s:ALELintImpl'),
|
||||
\ [l:buffer],
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:ALELintImpl(buffer) abort
|
||||
if ale#ShouldDoNothing(a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
" Get the buffer number linting was queued for.
|
||||
" or else take the current one.
|
||||
let l:buffer = len(a:0) > 1 && a:1 == s:lint_timer
|
||||
\ ? s:queued_buffer_number
|
||||
\ : bufnr('%')
|
||||
|
||||
" Use the filetype from the buffer
|
||||
let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
|
||||
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
let l:should_lint_file = 0
|
||||
|
||||
" Check if we previously requested checking the file.
|
||||
if has_key(s:should_lint_file_for_buffer, l:buffer)
|
||||
unlet s:should_lint_file_for_buffer[l:buffer]
|
||||
if has_key(s:should_lint_file_for_buffer, a:buffer)
|
||||
unlet s:should_lint_file_for_buffer[a:buffer]
|
||||
" Lint files if they exist.
|
||||
let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
|
||||
let l:should_lint_file = filereadable(expand('#' . a:buffer . ':p'))
|
||||
endif
|
||||
|
||||
" Initialise the buffer information if needed.
|
||||
call ale#engine#InitBufferInfo(l:buffer)
|
||||
|
||||
" Clear the new loclist again, so we will work with all new items.
|
||||
let g:ale_buffer_info[l:buffer].new_loclist = []
|
||||
|
||||
if l:should_lint_file
|
||||
" Clear loclist items for files if we are checking files again.
|
||||
let g:ale_buffer_info[l:buffer].lint_file_loclist = []
|
||||
else
|
||||
" Otherwise, don't run any `lint_file` linters
|
||||
" We will continue running any linters which are currently checking
|
||||
" the file, and the items will be mixed together with any new items.
|
||||
call filter(l:linters, '!v:val.lint_file')
|
||||
endif
|
||||
|
||||
call ale#engine#StopCurrentJobs(l:buffer, l:should_lint_file)
|
||||
|
||||
for l:linter in l:linters
|
||||
call ale#engine#Invoke(l:buffer, l:linter)
|
||||
endfor
|
||||
call ale#engine#RunLinters(a:buffer, l:linters, l:should_lint_file)
|
||||
endfunction
|
||||
|
||||
" Reset flags indicating that files should be checked for all buffers.
|
||||
@@ -117,6 +156,10 @@ function! ale#ResetLintFileMarkers() abort
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
endfunction
|
||||
|
||||
function! ale#ResetErrorDelays() abort
|
||||
let s:timestamp_map = {}
|
||||
endfunction
|
||||
|
||||
let g:ale_has_override = get(g:, 'ale_has_override', {})
|
||||
|
||||
" Call has(), but check a global Dictionary so we can force flags on or off
|
||||
@@ -159,7 +202,7 @@ endfunction
|
||||
" Escape a string suitably for each platform.
|
||||
" shellescape does not work on Windows.
|
||||
function! ale#Escape(str) abort
|
||||
if fnamemodify(&shell, ':t') ==? 'cmd.exe'
|
||||
if fnamemodify(&shell, ':t') is? 'cmd.exe'
|
||||
" If the string contains spaces, it will be surrounded by quotes.
|
||||
" Otherwise, special characters will be escaped with carets (^).
|
||||
return substitute(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
function! ale#balloon#MessageForPos(bufnr, lnum, col) abort
|
||||
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
|
||||
let l:index = ale#util#BinarySearch(l:loclist, a:lnum, a:col)
|
||||
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col)
|
||||
|
||||
return l:index >= 0 ? l:loclist[l:index].text : ''
|
||||
endfunction
|
||||
|
||||
@@ -9,7 +9,7 @@ function! ale#c#FindProjectRoot(buffer) abort
|
||||
let l:path = fnamemodify(l:full_path, ':h')
|
||||
|
||||
" Correct .git path detection.
|
||||
if fnamemodify(l:path, ':t') ==# '.git'
|
||||
if fnamemodify(l:path, ':t') is# '.git'
|
||||
let l:path = fnamemodify(l:path, ':h')
|
||||
endif
|
||||
|
||||
@@ -47,7 +47,7 @@ function! ale#c#FindLocalHeaderPaths(buffer) abort
|
||||
|
||||
" If we find an 'include' directory in the project root, then use that.
|
||||
if isdirectory(l:project_root . '/include')
|
||||
return [simplify(l:project_root . '/include')]
|
||||
return [ale#path#Simplify(l:project_root . '/include')]
|
||||
endif
|
||||
|
||||
return []
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Utility functions related to cleaning state.
|
||||
|
||||
function! ale#cleanup#Buffer(buffer) abort
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" When buffers are removed, clear all of the jobs.
|
||||
call ale#engine#StopCurrentJobs(a:buffer, 1)
|
||||
|
||||
" Clear delayed highlights for a buffer being removed.
|
||||
if g:ale_set_highlights
|
||||
call ale#highlight#UnqueueHighlights(a:buffer)
|
||||
call ale#highlight#RemoveHighlights([])
|
||||
endif
|
||||
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
339
autoload/ale/completion.vim
Normal file
339
autoload/ale/completion.vim
Normal file
@@ -0,0 +1,339 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Completion support for LSP linters
|
||||
|
||||
let s:timer_id = -1
|
||||
|
||||
function! s:GetRegex(map, filetype) abort
|
||||
for l:part in reverse(split(a:filetype, '\.'))
|
||||
let l:regex = get(a:map, l:part, [])
|
||||
|
||||
if !empty(l:regex)
|
||||
return l:regex
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Regular expressions for checking the characters in the line before where
|
||||
" the insert cursor is. If one of these matches, we'll check for completions.
|
||||
let s:should_complete_map = {
|
||||
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
|
||||
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
|
||||
\}
|
||||
|
||||
" Check if we should look for completions for a language.
|
||||
function! ale#completion#GetPrefix(filetype, line, column) abort
|
||||
let l:regex = s:GetRegex(s:should_complete_map, a:filetype)
|
||||
" The column we're using completions for is where we are inserting text,
|
||||
" like so:
|
||||
" abc
|
||||
" ^
|
||||
" So we need check the text in the column before that position.
|
||||
return matchstr(getline(a:line)[: a:column - 2], l:regex)
|
||||
endfunction
|
||||
|
||||
" Regular expressions for finding the start column to replace with completion.
|
||||
let s:omni_start_map = {
|
||||
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
|
||||
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
|
||||
\}
|
||||
|
||||
function! ale#completion#Filter(suggestions, prefix) abort
|
||||
" For completing...
|
||||
" foo.
|
||||
" ^
|
||||
" We need to include all of the given suggestions.
|
||||
if a:prefix is# '.'
|
||||
return a:suggestions
|
||||
endif
|
||||
|
||||
let l:filtered_suggestions = []
|
||||
|
||||
" Filter suggestions down to those starting with the prefix we used for
|
||||
" finding suggestions in the first place.
|
||||
"
|
||||
" Some completion tools will include suggestions which don't even start
|
||||
" with the characters we have already typed.
|
||||
for l:item in a:suggestions
|
||||
" A List of String values or a List of completion item Dictionaries
|
||||
" is accepted here.
|
||||
let l:word = type(l:item) == type('') ? l:item : l:item.word
|
||||
|
||||
" Add suggestions if the suggestion starts with a case-insensitive
|
||||
" match for the prefix.
|
||||
if l:word[: len(a:prefix) - 1] is? a:prefix
|
||||
call add(l:filtered_suggestions, l:item)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:filtered_suggestions
|
||||
endfunction
|
||||
|
||||
function! s:ReplaceCompleteopt() abort
|
||||
if !exists('b:ale_old_completopt')
|
||||
let b:ale_old_completopt = &l:completeopt
|
||||
endif
|
||||
|
||||
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
|
||||
endfunction
|
||||
|
||||
function! ale#completion#OmniFunc(findstart, base) abort
|
||||
if a:findstart
|
||||
let l:line = b:ale_completion_info.line
|
||||
let l:column = b:ale_completion_info.column
|
||||
let l:regex = s:GetRegex(s:omni_start_map, &filetype)
|
||||
let l:up_to_column = getline(l:line)[: l:column - 2]
|
||||
let l:match = matchstr(l:up_to_column, l:regex)
|
||||
|
||||
return l:column - len(l:match) - 1
|
||||
else
|
||||
" Parse a new response if there is one.
|
||||
if exists('b:ale_completion_response')
|
||||
\&& exists('b:ale_completion_parser')
|
||||
let l:response = b:ale_completion_response
|
||||
let l:parser = b:ale_completion_parser
|
||||
|
||||
unlet b:ale_completion_response
|
||||
unlet b:ale_completion_parser
|
||||
|
||||
let b:ale_completion_result = function(l:parser)(l:response)
|
||||
endif
|
||||
|
||||
call s:ReplaceCompleteopt()
|
||||
|
||||
return get(b:, 'ale_completion_result', [])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Show(response, completion_parser) abort
|
||||
" Remember the old omnifunc value, if there is one.
|
||||
" If we don't store an old one, we'll just never reset the option.
|
||||
" This will stop some random exceptions from appearing.
|
||||
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
|
||||
let b:ale_old_omnifunc = &l:omnifunc
|
||||
endif
|
||||
|
||||
" Set the list in the buffer, temporarily replace omnifunc with our
|
||||
" function, and then start omni-completion.
|
||||
let b:ale_completion_response = a:response
|
||||
let b:ale_completion_parser = a:completion_parser
|
||||
let &l:omnifunc = 'ale#completion#OmniFunc'
|
||||
call s:ReplaceCompleteopt()
|
||||
call ale#util#FeedKeys("\<C-x>\<C-o>", 'n')
|
||||
endfunction
|
||||
|
||||
function! s:CompletionStillValid(request_id) abort
|
||||
let [l:line, l:column] = getcurpos()[1:2]
|
||||
|
||||
return has_key(b:, 'ale_completion_info')
|
||||
\&& b:ale_completion_info.request_id == a:request_id
|
||||
\&& b:ale_completion_info.line == l:line
|
||||
\&& b:ale_completion_info.column == l:column
|
||||
endfunction
|
||||
|
||||
function! ale#completion#ParseTSServerCompletions(response) abort
|
||||
let l:names = []
|
||||
|
||||
for l:suggestion in a:response.body
|
||||
call add(l:names, l:suggestion.name)
|
||||
endfor
|
||||
|
||||
return l:names
|
||||
endfunction
|
||||
|
||||
function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
let l:results = []
|
||||
|
||||
for l:suggestion in a:response.body
|
||||
let l:displayParts = []
|
||||
|
||||
for l:part in l:suggestion.displayParts
|
||||
call add(l:displayParts, l:part.text)
|
||||
endfor
|
||||
|
||||
" Each one of these parts has 'kind' properties
|
||||
let l:documentationParts = []
|
||||
|
||||
for l:part in get(l:suggestion, 'documentation', [])
|
||||
call add(l:documentationParts, l:part.text)
|
||||
endfor
|
||||
|
||||
if l:suggestion.kind is# 'clasName'
|
||||
let l:kind = 'f'
|
||||
elseif l:suggestion.kind is# 'parameterName'
|
||||
let l:kind = 'f'
|
||||
else
|
||||
let l:kind = 'v'
|
||||
endif
|
||||
|
||||
" See :help complete-items
|
||||
call add(l:results, {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'kind': l:kind,
|
||||
\ 'icase': 1,
|
||||
\ 'menu': join(l:displayParts, ''),
|
||||
\ 'info': join(l:documentationParts, ''),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:results
|
||||
endfunction
|
||||
|
||||
function! ale#completion#HandleTSServerLSPResponse(conn_id, response) abort
|
||||
if !s:CompletionStillValid(get(a:response, 'request_seq'))
|
||||
return
|
||||
endif
|
||||
|
||||
if !has_key(a:response, 'body')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:command = get(a:response, 'command', '')
|
||||
|
||||
if l:command is# 'completions'
|
||||
let l:names = ale#completion#Filter(
|
||||
\ ale#completion#ParseTSServerCompletions(a:response),
|
||||
\ b:ale_completion_info.prefix,
|
||||
\)[: g:ale_completion_max_suggestions - 1]
|
||||
|
||||
if !empty(l:names)
|
||||
let b:ale_completion_info.request_id = ale#lsp#Send(
|
||||
\ b:ale_completion_info.conn_id,
|
||||
\ ale#lsp#tsserver_message#CompletionEntryDetails(
|
||||
\ bufnr(''),
|
||||
\ b:ale_completion_info.line,
|
||||
\ b:ale_completion_info.column,
|
||||
\ l:names,
|
||||
\ ),
|
||||
\)
|
||||
endif
|
||||
elseif l:command is# 'completionEntryDetails'
|
||||
call ale#completion#Show(
|
||||
\ a:response,
|
||||
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GetLSPCompletions(linter) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:lsp_details = ale#linter#StartLSP(
|
||||
\ l:buffer,
|
||||
\ a:linter,
|
||||
\ function('ale#completion#HandleTSServerLSPResponse'),
|
||||
\)
|
||||
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:command = l:lsp_details.command
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
let l:message = ale#lsp#tsserver_message#Completions(
|
||||
\ l:buffer,
|
||||
\ b:ale_completion_info.line,
|
||||
\ b:ale_completion_info.column,
|
||||
\ b:ale_completion_info.prefix,
|
||||
\)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
|
||||
|
||||
if l:request_id
|
||||
let b:ale_completion_info.conn_id = l:id
|
||||
let b:ale_completion_info.request_id = l:request_id
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetCompletions() abort
|
||||
let [l:line, l:column] = getcurpos()[1:2]
|
||||
|
||||
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
|
||||
|
||||
if empty(l:prefix)
|
||||
return
|
||||
endif
|
||||
|
||||
let b:ale_completion_info = {
|
||||
\ 'line': l:line,
|
||||
\ 'column': l:column,
|
||||
\ 'prefix': l:prefix,
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\}
|
||||
|
||||
for l:linter in ale#linter#Get(&filetype)
|
||||
if l:linter.lsp is# 'tsserver'
|
||||
call s:GetLSPCompletions(l:linter)
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:TimerHandler(...) abort
|
||||
let s:timer_id = -1
|
||||
|
||||
let [l:line, l:column] = getcurpos()[1:2]
|
||||
|
||||
" When running the timer callback, we have to be sure that the cursor
|
||||
" hasn't moved from where it was when we requested completions by typing.
|
||||
if s:timer_pos == [l:line, l:column]
|
||||
call ale#completion#GetCompletions()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Queue() abort
|
||||
let s:timer_pos = getcurpos()[1:2]
|
||||
|
||||
" If we changed the text again while we're still waiting for a response,
|
||||
" then invalidate the requests before the timer ticks again.
|
||||
if exists('b:ale_completion_info')
|
||||
let b:ale_completion_info.request_id = 0
|
||||
endif
|
||||
|
||||
if s:timer_id != -1
|
||||
call timer_stop(s:timer_id)
|
||||
endif
|
||||
|
||||
let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler'))
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Done() abort
|
||||
silent! pclose
|
||||
|
||||
" Reset settings when completion is done.
|
||||
if exists('b:ale_old_omnifunc')
|
||||
let &l:omnifunc = b:ale_old_omnifunc
|
||||
unlet b:ale_old_omnifunc
|
||||
endif
|
||||
|
||||
if exists('b:ale_old_completopt')
|
||||
let &l:completeopt = b:ale_old_completopt
|
||||
unlet b:ale_old_completopt
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:Setup(enabled) abort
|
||||
augroup ALECompletionGroup
|
||||
autocmd!
|
||||
|
||||
if a:enabled
|
||||
autocmd TextChangedI * call ale#completion#Queue()
|
||||
autocmd CompleteDone * call ale#completion#Done()
|
||||
endif
|
||||
augroup END
|
||||
|
||||
if !a:enabled
|
||||
augroup! ALECompletionGroup
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Enable() abort
|
||||
let g:ale_completion_enabled = 1
|
||||
call s:Setup(1)
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Disable() abort
|
||||
let g:ale_completion_enabled = 0
|
||||
call s:Setup(0)
|
||||
endfunction
|
||||
@@ -1,10 +1,22 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Echoes lint message for the current line, if any
|
||||
|
||||
let s:cursor_timer = -1
|
||||
let s:last_pos = [0, 0, 0]
|
||||
let s:error_delay_ms = 1000 * 60 * 2
|
||||
|
||||
if !exists('s:dont_queue_until')
|
||||
let s:dont_queue_until = -1
|
||||
endif
|
||||
|
||||
if !exists('s:dont_echo_until')
|
||||
let s:dont_echo_until = -1
|
||||
endif
|
||||
|
||||
" Return a formatted message according to g:ale_echo_msg_format variable
|
||||
function! s:GetMessage(linter, type, text) abort
|
||||
let l:msg = g:ale_echo_msg_format
|
||||
let l:type = a:type ==# 'E'
|
||||
let l:type = a:type is# 'E'
|
||||
\ ? g:ale_echo_msg_error_str
|
||||
\ : g:ale_echo_msg_warning_str
|
||||
|
||||
@@ -22,12 +34,12 @@ function! s:EchoWithShortMess(setting, message) abort
|
||||
|
||||
try
|
||||
" Turn shortmess on or off.
|
||||
if a:setting ==# 'on'
|
||||
if a:setting is# 'on'
|
||||
setlocal shortmess+=T
|
||||
" echomsg is neede for the message to get truncated and appear in
|
||||
" echomsg is needed for the message to get truncated and appear in
|
||||
" the message history.
|
||||
exec "norm! :echomsg a:message\n"
|
||||
elseif a:setting ==# 'off'
|
||||
elseif a:setting is# 'off'
|
||||
setlocal shortmess-=T
|
||||
" Regular echo is needed for printing newline characters.
|
||||
echo a:message
|
||||
@@ -50,10 +62,12 @@ function! ale#cursor#TruncatedEcho(message) abort
|
||||
endfunction
|
||||
|
||||
function! s:FindItemAtCursor() abort
|
||||
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
|
||||
let l:buf = bufnr('')
|
||||
let l:info = get(g:ale_buffer_info, l:buf, {})
|
||||
let l:loclist = get(l:info, 'loclist', [])
|
||||
let l:pos = getcurpos()
|
||||
let l:index = ale#util#BinarySearch(l:info.loclist, l:pos[1], l:pos[2])
|
||||
let l:loc = l:index >= 0 ? l:info.loclist[l:index] : {}
|
||||
let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2])
|
||||
let l:loc = l:index >= 0 ? l:loclist[l:index] : {}
|
||||
|
||||
return [l:info, l:loc]
|
||||
endfunction
|
||||
@@ -66,12 +80,16 @@ function! s:StopCursorTimer() abort
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#EchoCursorWarning(...) abort
|
||||
if ale#ShouldDoNothing()
|
||||
return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), [])
|
||||
endfunction
|
||||
|
||||
function! s:EchoImpl() abort
|
||||
if ale#ShouldDoNothing(bufnr(''))
|
||||
return
|
||||
endif
|
||||
|
||||
" Only echo the warnings in normal mode, otherwise we will get problems.
|
||||
if mode() !=# 'n'
|
||||
if mode() isnot# 'n'
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -89,11 +107,16 @@ function! ale#cursor#EchoCursorWarning(...) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:cursor_timer = -1
|
||||
let s:last_pos = [0, 0, 0]
|
||||
|
||||
function! ale#cursor#EchoCursorWarningWithDelay() abort
|
||||
if ale#ShouldDoNothing()
|
||||
return ale#CallWithCooldown(
|
||||
\ 'dont_echo_with_delay_until',
|
||||
\ function('s:EchoWithDelayImpl'),
|
||||
\ [],
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:EchoWithDelayImpl() abort
|
||||
if ale#ShouldDoNothing(bufnr(''))
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -112,12 +135,12 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#ShowCursorDetail() abort
|
||||
if ale#ShouldDoNothing()
|
||||
if ale#ShouldDoNothing(bufnr(''))
|
||||
return
|
||||
endif
|
||||
|
||||
" Only echo the warnings in normal mode, otherwise we will get problems.
|
||||
if mode() !=# 'n'
|
||||
if mode() isnot# 'n'
|
||||
return
|
||||
endif
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ let s:global_variable_list = [
|
||||
\ 'ale_echo_msg_format',
|
||||
\ 'ale_echo_msg_warning_str',
|
||||
\ 'ale_enabled',
|
||||
\ 'ale_fix_on_save',
|
||||
\ 'ale_fixers',
|
||||
\ 'ale_keep_list_window_open',
|
||||
\ 'ale_lint_delay',
|
||||
\ 'ale_lint_on_enter',
|
||||
@@ -68,39 +70,53 @@ function! s:EchoGlobalVariables() abort
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Echo a command that was run.
|
||||
function! s:EchoCommand(item) abort
|
||||
let l:status_message = a:item.status
|
||||
|
||||
" Include the exit code in output if we have it.
|
||||
if a:item.status is# 'finished'
|
||||
let l:status_message .= ' - exit code ' . a:item.exit_code
|
||||
endif
|
||||
|
||||
echom '(' . l:status_message . ') ' . string(a:item.command)
|
||||
|
||||
if g:ale_history_log_output && has_key(a:item, 'output')
|
||||
if empty(a:item.output)
|
||||
echom ''
|
||||
echom '<<<NO OUTPUT RETURNED>>>'
|
||||
echom ''
|
||||
else
|
||||
echom ''
|
||||
echom '<<<OUTPUT STARTS>>>'
|
||||
|
||||
for l:line in a:item.output
|
||||
echom l:line
|
||||
endfor
|
||||
|
||||
echom '<<<OUTPUT ENDS>>>'
|
||||
echom ''
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Echo the results of an executable check.
|
||||
function! s:EchoExecutable(item) abort
|
||||
echom printf(
|
||||
\ '(executable check - %s) %s',
|
||||
\ a:item.status ? 'success' : 'failure',
|
||||
\ a:item.command,
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:EchoCommandHistory() abort
|
||||
let l:buffer = bufnr('%')
|
||||
|
||||
if !has_key(g:ale_buffer_info, l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
for l:item in g:ale_buffer_info[l:buffer].history
|
||||
let l:status_message = l:item.status
|
||||
|
||||
" Include the exit code in output if we have it.
|
||||
if l:item.status ==# 'finished'
|
||||
let l:status_message .= ' - exit code ' . l:item.exit_code
|
||||
endif
|
||||
|
||||
echom '(' . l:status_message . ') ' . string(l:item.command)
|
||||
|
||||
if g:ale_history_log_output && has_key(l:item, 'output')
|
||||
if empty(l:item.output)
|
||||
echom ''
|
||||
echom '<<<NO OUTPUT RETURNED>>>'
|
||||
echom ''
|
||||
else
|
||||
echom ''
|
||||
echom '<<<OUTPUT STARTS>>>'
|
||||
|
||||
for l:line in l:item.output
|
||||
echom l:line
|
||||
endfor
|
||||
|
||||
echom '<<<OUTPUT ENDS>>>'
|
||||
echom ''
|
||||
endif
|
||||
for l:item in ale#history#Get(l:buffer)
|
||||
if l:item.job_id is# 'executable'
|
||||
call s:EchoExecutable(l:item)
|
||||
else
|
||||
call s:EchoCommand(l:item)
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
@@ -11,40 +11,67 @@ if !has_key(s:, 'job_info_map')
|
||||
let s:job_info_map = {}
|
||||
endif
|
||||
|
||||
let s:executable_cache_map = {}
|
||||
" Associates LSP connection IDs with linter names.
|
||||
if !has_key(s:, 'lsp_linter_map')
|
||||
let s:lsp_linter_map = {}
|
||||
endif
|
||||
|
||||
if !has_key(s:, 'executable_cache_map')
|
||||
let s:executable_cache_map = {}
|
||||
endif
|
||||
|
||||
function! ale#engine#ResetExecutableCache() abort
|
||||
let s:executable_cache_map = {}
|
||||
endfunction
|
||||
|
||||
" Check if files are executable, and if they are, remember that they are
|
||||
" for subsequent calls. We'll keep checking until programs can be executed.
|
||||
function! s:IsExecutable(executable) abort
|
||||
function! ale#engine#IsExecutable(buffer, executable) abort
|
||||
if has_key(s:executable_cache_map, a:executable)
|
||||
return 1
|
||||
endif
|
||||
|
||||
let l:result = 0
|
||||
|
||||
if executable(a:executable)
|
||||
let s:executable_cache_map[a:executable] = 1
|
||||
|
||||
return 1
|
||||
let l:result = 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
if g:ale_history_enabled
|
||||
call ale#history#Add(a:buffer, l:result, 'executable', a:executable)
|
||||
endif
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
function! ale#engine#InitBufferInfo(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
" job_list will hold the list of jobs
|
||||
" job_list will hold the list of job IDs
|
||||
" active_linter_list will hold the list of active linter names
|
||||
" loclist holds the loclist items after all jobs have completed.
|
||||
" temporary_file_list holds temporary files to be cleaned up
|
||||
" temporary_directory_list holds temporary directories to be cleaned up
|
||||
" history holds a list of previously run commands for this buffer
|
||||
let g:ale_buffer_info[a:buffer] = {
|
||||
\ 'job_list': [],
|
||||
\ 'active_linter_list': [],
|
||||
\ 'loclist': [],
|
||||
\ 'temporary_file_list': [],
|
||||
\ 'temporary_directory_list': [],
|
||||
\ 'history': [],
|
||||
\ 'open_lsp_documents': [],
|
||||
\}
|
||||
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" Return 1 if ALE is busy checking a given buffer
|
||||
function! ale#engine#IsCheckingBuffer(buffer) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
|
||||
return !empty(get(l:info, 'active_linter_list', []))
|
||||
endfunction
|
||||
|
||||
" Register a temporary file to be managed with the ALE engine for
|
||||
@@ -70,9 +97,7 @@ function! ale#engine#CreateDirectory(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return
|
||||
endif
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
|
||||
" We can't delete anything in a sandbox, so wait until we escape from
|
||||
" it to delete temporary files and directories.
|
||||
@@ -81,21 +106,25 @@ function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||
endif
|
||||
|
||||
" Delete files with a call akin to a plan `rm` command.
|
||||
for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
|
||||
call delete(l:filename)
|
||||
endfor
|
||||
if has_key(l:info, 'temporary_file_list')
|
||||
for l:filename in l:info.temporary_file_list
|
||||
call delete(l:filename)
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_file_list = []
|
||||
let l:info.temporary_file_list = []
|
||||
endif
|
||||
|
||||
" Delete directories like `rm -rf`.
|
||||
" Directories are handled differently from files, so paths that are
|
||||
" intended to be single files can be set up for automatic deletion without
|
||||
" accidentally deleting entire directories.
|
||||
for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
|
||||
call delete(l:directory, 'rf')
|
||||
endfor
|
||||
if has_key(l:info, 'temporary_directory_list')
|
||||
for l:directory in l:info.temporary_directory_list
|
||||
call delete(l:directory, 'rf')
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_directory_list = []
|
||||
let l:info.temporary_directory_list = []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutput(job_id, line) abort
|
||||
@@ -105,12 +134,22 @@ function! s:GatherOutput(job_id, line) abort
|
||||
endfunction
|
||||
|
||||
function! s:HandleLoclist(linter_name, buffer, loclist) abort
|
||||
let l:buffer_info = get(g:ale_buffer_info, a:buffer, {})
|
||||
|
||||
if empty(l:buffer_info)
|
||||
return
|
||||
endif
|
||||
|
||||
" Remove this linter from the list of active linters.
|
||||
" This may have already been done when the job exits.
|
||||
call filter(l:buffer_info.active_linter_list, 'v:val isnot# a:linter_name')
|
||||
|
||||
" Make some adjustments to the loclists to fix common problems, and also
|
||||
" to set default values for loclist items.
|
||||
let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist)
|
||||
|
||||
" Remove previous items for this linter.
|
||||
call filter(g:ale_buffer_info[a:buffer].loclist, 'v:val.linter_name !=# a:linter_name')
|
||||
call filter(g:ale_buffer_info[a:buffer].loclist, 'v:val.linter_name isnot# a:linter_name')
|
||||
" Add the new items.
|
||||
call extend(g:ale_buffer_info[a:buffer].loclist, l:linter_loclist)
|
||||
|
||||
@@ -119,34 +158,11 @@ function! s:HandleLoclist(linter_name, buffer, loclist) abort
|
||||
" for efficient lookup of the messages in the cursor handler.
|
||||
call sort(g:ale_buffer_info[a:buffer].loclist, 'ale#util#LocItemCompare')
|
||||
|
||||
let l:linting_is_done = empty(g:ale_buffer_info[a:buffer].job_list)
|
||||
\ && !get(g:ale_buffer_info[a:buffer], 'waiting_for_tsserver', 0)
|
||||
|
||||
if l:linting_is_done
|
||||
" Automatically remove all managed temporary files and directories
|
||||
" now that all jobs have completed.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" Figure out which linters are still enabled, and remove
|
||||
" problems for linters which are no longer enabled.
|
||||
let l:name_map = {}
|
||||
|
||||
for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype'))
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
call filter(
|
||||
\ g:ale_buffer_info[a:buffer].loclist,
|
||||
\ 'get(l:name_map, v:val.linter_name)',
|
||||
\)
|
||||
if ale#ShouldDoNothing(a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
call ale#engine#SetResults(a:buffer, g:ale_buffer_info[a:buffer].loclist)
|
||||
|
||||
if l:linting_is_done
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HandleExit(job_id, exit_code) abort
|
||||
@@ -167,7 +183,8 @@ function! s:HandleExit(job_id, exit_code) abort
|
||||
" Remove this job from the list.
|
||||
call ale#job#Stop(a:job_id)
|
||||
call remove(s:job_info_map, a:job_id)
|
||||
call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val !=# a:job_id')
|
||||
call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val isnot# a:job_id')
|
||||
call filter(g:ale_buffer_info[l:buffer].active_linter_list, 'v:val isnot# l:linter.name')
|
||||
|
||||
" Stop here if we land in the handle for a job completing if we're in
|
||||
" a sandbox.
|
||||
@@ -194,51 +211,81 @@ function! s:HandleExit(job_id, exit_code) abort
|
||||
call s:HandleLoclist(l:linter.name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPResponse(response) abort
|
||||
let l:is_diag_response = get(a:response, 'type', '') ==# 'event'
|
||||
\ && get(a:response, 'event', '') ==# 'semanticDiag'
|
||||
function! s:HandleLSPDiagnostics(conn_id, response) abort
|
||||
let l:linter_name = s:lsp_linter_map[a:conn_id]
|
||||
let l:filename = ale#path#FromURI(a:response.params.uri)
|
||||
let l:buffer = bufnr(l:filename)
|
||||
|
||||
if !l:is_diag_response
|
||||
if l:buffer <= 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = bufnr(a:response.body.file)
|
||||
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
|
||||
|
||||
call s:HandleLoclist(l:linter_name, l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleTSServerDiagnostics(response, error_type) abort
|
||||
let l:buffer = bufnr(a:response.body.file)
|
||||
let l:info = get(g:ale_buffer_info, l:buffer, {})
|
||||
|
||||
if empty(l:info)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:info.waiting_for_tsserver = 0
|
||||
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
|
||||
|
||||
let l:loclist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
|
||||
" 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'
|
||||
let l:info.syntax_loclist = l:thislist
|
||||
else
|
||||
let l:info.semantic_loclist = l:thislist
|
||||
endif
|
||||
|
||||
let l:loclist = get(l:info, 'semantic_loclist', [])
|
||||
\ + get(l:info, 'syntax_loclist', [])
|
||||
|
||||
call s:HandleLoclist('tsserver', l:buffer, l:loclist)
|
||||
endfunction
|
||||
|
||||
function! s:HandleLSPErrorMessage(error_message) abort
|
||||
echoerr 'Error from LSP:'
|
||||
|
||||
for l:line in split(a:error_message, "\n")
|
||||
echoerr l:line
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#engine#HandleLSPResponse(conn_id, response) abort
|
||||
let l:method = get(a:response, 'method', '')
|
||||
|
||||
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
|
||||
" Uncomment this line to print LSP error messages.
|
||||
" call s:HandleLSPErrorMessage(a:response.error.message)
|
||||
elseif l:method is# 'textDocument/publishDiagnostics'
|
||||
call s:HandleLSPDiagnostics(a:conn_id, a:response)
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'semanticDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'semantic')
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'syntaxDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'syntax')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#SetResults(buffer, loclist) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
let l:job_list = get(l:info, 'job_list', [])
|
||||
let l:waiting_for_tsserver = get(l:info, 'waiting_for_tsserver', 0)
|
||||
let l:linting_is_done = empty(l:job_list) && !l:waiting_for_tsserver
|
||||
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
|
||||
|
||||
" Set signs first. This could potentially fix some line numbers.
|
||||
" The List could be sorted again here by SetSigns.
|
||||
if g:ale_set_signs
|
||||
call ale#sign#SetSigns(a:buffer, a:loclist)
|
||||
|
||||
if l:linting_is_done
|
||||
call ale#sign#RemoveDummySignIfNeeded(a:buffer)
|
||||
endif
|
||||
endif
|
||||
|
||||
if g:ale_set_quickfix || g:ale_set_loclist
|
||||
call ale#list#SetLists(a:buffer, a:loclist)
|
||||
|
||||
if l:linting_is_done
|
||||
call ale#list#CloseWindowIfNeeded(a:buffer)
|
||||
endif
|
||||
endif
|
||||
|
||||
if exists('*ale#statusline#Update')
|
||||
@@ -255,22 +302,34 @@ function! ale#engine#SetResults(buffer, loclist) abort
|
||||
" This will only do something meaningful if we're in normal mode.
|
||||
call ale#cursor#EchoCursorWarning()
|
||||
endif
|
||||
|
||||
if l:linting_is_done
|
||||
" Reset the save event marker, used for opening windows, etc.
|
||||
call setbufvar(a:buffer, 'ale_save_event_fired', 0)
|
||||
|
||||
" Automatically remove all managed temporary files and directories
|
||||
" now that all jobs have completed.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:RemapItemTypes(type_map, loclist) abort
|
||||
for l:item in a:loclist
|
||||
let l:key = l:item.type
|
||||
\ . (get(l:item, 'sub_type', '') ==# 'style' ? 'S' : '')
|
||||
\ . (get(l:item, 'sub_type', '') is# 'style' ? 'S' : '')
|
||||
let l:new_key = get(a:type_map, l:key, '')
|
||||
|
||||
if l:new_key ==# 'E'
|
||||
\|| l:new_key ==# 'ES'
|
||||
\|| l:new_key ==# 'W'
|
||||
\|| l:new_key ==# 'WS'
|
||||
\|| l:new_key ==# 'I'
|
||||
if l:new_key is# 'E'
|
||||
\|| l:new_key is# 'ES'
|
||||
\|| l:new_key is# 'W'
|
||||
\|| l:new_key is# 'WS'
|
||||
\|| l:new_key is# 'I'
|
||||
let l:item.type = l:new_key[0]
|
||||
|
||||
if l:new_key ==# 'ES' || l:new_key ==# 'WS'
|
||||
if l:new_key is# 'ES' || l:new_key is# 'WS'
|
||||
let l:item.sub_type = 'style'
|
||||
elseif has_key(l:item, 'sub_type')
|
||||
call remove(l:item, 'sub_type')
|
||||
@@ -279,7 +338,11 @@ function! s:RemapItemTypes(type_map, loclist) abort
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Save the temporary directory so we can figure out if files are in it.
|
||||
let s:temp_dir = fnamemodify(tempname(), ':h')
|
||||
|
||||
function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
|
||||
let l:bufnr_map = {}
|
||||
let l:new_loclist = []
|
||||
|
||||
" Some errors have line numbers beyond the end of the file,
|
||||
@@ -301,16 +364,42 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
|
||||
" The linter_name will be set on the errors so it can be used in
|
||||
" output, filtering, etc..
|
||||
let l:item = {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'text': l:old_item.text,
|
||||
\ 'lnum': str2nr(l:old_item.lnum),
|
||||
\ 'col': str2nr(get(l:old_item, 'col', 0)),
|
||||
\ 'bufnr': get(l:old_item, 'bufnr', a:buffer),
|
||||
\ 'vcol': get(l:old_item, 'vcol', 0),
|
||||
\ 'type': get(l:old_item, 'type', 'E'),
|
||||
\ 'nr': get(l:old_item, 'nr', -1),
|
||||
\ 'linter_name': a:linter_name,
|
||||
\}
|
||||
|
||||
if has_key(l:old_item, 'filename')
|
||||
\&& l:old_item.filename[:len(s:temp_dir) - 1] isnot# s:temp_dir
|
||||
" Use the filename given.
|
||||
" Temporary files are assumed to be for this buffer,
|
||||
" and the filename is not included then, because it looks bad
|
||||
" in the loclist window.
|
||||
let l:filename = l:old_item.filename
|
||||
let l:item.filename = l:filename
|
||||
|
||||
if has_key(l:old_item, 'bufnr')
|
||||
" If a buffer number is also given, include that too.
|
||||
" If Vim detects that he buffer number is valid, it will
|
||||
" be used instead of the filename.
|
||||
let l:item.bufnr = l:old_item.bufnr
|
||||
elseif has_key(l:bufnr_map, l:filename)
|
||||
" Get the buffer number from the map, which can be faster.
|
||||
let l:item.bufnr = l:bufnr_map[l:filename]
|
||||
else
|
||||
" Look up the buffer number.
|
||||
let l:item.bufnr = bufnr(l:filename)
|
||||
let l:bufnr_map[l:filename] = l:item.bufnr
|
||||
endif
|
||||
elseif has_key(l:old_item, 'bufnr')
|
||||
let l:item.bufnr = l:old_item.bufnr
|
||||
endif
|
||||
|
||||
if has_key(l:old_item, 'detail')
|
||||
let l:item.detail = l:old_item.detail
|
||||
endif
|
||||
@@ -331,8 +420,9 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
|
||||
if l:item.lnum < 1
|
||||
" When errors appear before line 1, put them at line 1.
|
||||
let l:item.lnum = 1
|
||||
elseif l:item.lnum > l:last_line_number
|
||||
elseif l:item.bufnr == a:buffer && l:item.lnum > l:last_line_number
|
||||
" When errors go beyond the end of the file, put them at the end.
|
||||
" This is only done for the current buffer.
|
||||
let l:item.lnum = l:last_line_number
|
||||
endif
|
||||
|
||||
@@ -367,11 +457,15 @@ function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort
|
||||
" Automatically delete the directory later.
|
||||
call ale#engine#ManageDirectory(a:buffer, l:temporary_directory)
|
||||
" Write the buffer out to a file.
|
||||
call writefile(getbufline(a:buffer, 1, '$'), a:temporary_file)
|
||||
let l:lines = getbufline(a:buffer, 1, '$')
|
||||
call ale#util#Writefile(a:buffer, l:lines, a:temporary_file)
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
" Run a job.
|
||||
"
|
||||
" Returns 1 when the job was started successfully.
|
||||
function! s:RunJob(options) abort
|
||||
let l:command = a:options.command
|
||||
let l:buffer = a:options.buffer
|
||||
@@ -379,6 +473,11 @@ function! s:RunJob(options) abort
|
||||
let l:output_stream = a:options.output_stream
|
||||
let l:next_chain_index = a:options.next_chain_index
|
||||
let l:read_buffer = a:options.read_buffer
|
||||
let l:info = g:ale_buffer_info[l:buffer]
|
||||
|
||||
if empty(l:command)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer)
|
||||
|
||||
@@ -388,15 +487,25 @@ function! s:RunJob(options) abort
|
||||
let l:read_buffer = 0
|
||||
endif
|
||||
|
||||
" Add a newline to commands which need it.
|
||||
" This is only used for Flow for now, and is not documented.
|
||||
if l:linter.add_newline
|
||||
if has('win32')
|
||||
let l:command = l:command . '; echo.'
|
||||
else
|
||||
let l:command = l:command . '; echo'
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:command = ale#job#PrepareCommand(l:command)
|
||||
let l:job_options = {
|
||||
\ 'mode': 'nl',
|
||||
\ 'exit_cb': function('s:HandleExit'),
|
||||
\}
|
||||
|
||||
if l:output_stream ==# 'stderr'
|
||||
if l:output_stream is# 'stderr'
|
||||
let l:job_options.err_cb = function('s:GatherOutput')
|
||||
elseif l:output_stream ==# 'both'
|
||||
elseif l:output_stream is# 'both'
|
||||
let l:job_options.out_cb = function('s:GatherOutput')
|
||||
let l:job_options.err_cb = function('s:GatherOutput')
|
||||
else
|
||||
@@ -420,7 +529,11 @@ function! s:RunJob(options) abort
|
||||
" Only proceed if the job is being run.
|
||||
if l:job_id
|
||||
" Add the job to the list of jobs, so we can track them.
|
||||
call add(g:ale_buffer_info[l:buffer].job_list, l:job_id)
|
||||
call add(l:info.job_list, l:job_id)
|
||||
|
||||
if index(l:info.active_linter_list, l:linter.name) < 0
|
||||
call add(l:info.active_linter_list, l:linter.name)
|
||||
endif
|
||||
|
||||
let l:status = 'started'
|
||||
" Store the ID for the job in the map to read back again.
|
||||
@@ -434,8 +547,6 @@ function! s:RunJob(options) abort
|
||||
|
||||
if g:ale_history_enabled
|
||||
call ale#history#Add(l:buffer, l:status, l:job_id, l:command)
|
||||
else
|
||||
let g:ale_buffer_info[l:buffer].history = []
|
||||
endif
|
||||
|
||||
if get(g:, 'ale_run_synchronously') == 1
|
||||
@@ -448,6 +559,8 @@ function! s:RunJob(options) abort
|
||||
|
||||
call l:job_options.exit_cb(l:job_id, v:shell_error)
|
||||
endif
|
||||
|
||||
return l:job_id != 0
|
||||
endfunction
|
||||
|
||||
" Determine which commands to run for a link in a command chain, or
|
||||
@@ -503,16 +616,8 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
|
||||
let l:input = []
|
||||
let l:chain_index += 1
|
||||
endwhile
|
||||
elseif has_key(a:linter, 'command_callback')
|
||||
" If there is a callback for generating a command, call that instead.
|
||||
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
|
||||
else
|
||||
let l:command = a:linter.command
|
||||
endif
|
||||
|
||||
if empty(l:command)
|
||||
" Don't run any jobs if the command is an empty string.
|
||||
return {}
|
||||
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
|
||||
endif
|
||||
|
||||
return {
|
||||
@@ -528,18 +633,13 @@ endfunction
|
||||
function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
|
||||
|
||||
if !empty(l:options)
|
||||
call s:RunJob(l:options)
|
||||
elseif empty(g:ale_buffer_info[a:buffer].job_list)
|
||||
" If we cancelled running a command, and we have no jobs in progress,
|
||||
" then delete the managed temporary files now.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
endif
|
||||
return s:RunJob(l:options)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
let l:new_job_list = []
|
||||
let l:new_active_linter_list = []
|
||||
|
||||
for l:job_id in get(l:info, 'job_list', [])
|
||||
let l:job_info = get(s:job_info_map, l:job_id, {})
|
||||
@@ -550,75 +650,164 @@ function! ale#engine#StopCurrentJobs(buffer, include_lint_file_jobs) abort
|
||||
call remove(s:job_info_map, l:job_id)
|
||||
else
|
||||
call add(l:new_job_list, l:job_id)
|
||||
" Linters with jobs still running are still active.
|
||||
call add(l:new_active_linter_list, l:job_info.linter.name)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Remove duplicates from the active linter list.
|
||||
call uniq(sort(l:new_active_linter_list))
|
||||
|
||||
" Update the List, so it includes only the jobs we still need.
|
||||
let l:info.job_list = l:new_job_list
|
||||
" Ignore current LSP commands.
|
||||
" We should consider cancelling them in future.
|
||||
let l:info.lsp_command_list = []
|
||||
" Update the active linter list, clearing out anything not running.
|
||||
let l:info.active_linter_list = l:new_active_linter_list
|
||||
endfunction
|
||||
|
||||
function! s:CheckWithTSServer(buffer, linter, executable) abort
|
||||
function! s:CheckWithLSP(buffer, linter) abort
|
||||
let l:info = g:ale_buffer_info[a:buffer]
|
||||
let l:open_documents = l:info.open_lsp_documents
|
||||
let l:is_open = index(l:open_documents, a:linter.name) >= 0
|
||||
let l:lsp_details = ale#linter#StartLSP(
|
||||
\ a:buffer,
|
||||
\ a:linter,
|
||||
\ function('ale#engine#HandleLSPResponse'),
|
||||
\)
|
||||
|
||||
let l:command = ale#job#PrepareCommand(a:executable)
|
||||
let l:job_id = ale#lsp#StartProgram(a:executable, l:command, function('s:HandleLSPResponse'))
|
||||
if empty(l:lsp_details)
|
||||
return 0
|
||||
endif
|
||||
|
||||
if !l:job_id
|
||||
if g:ale_history_enabled
|
||||
call ale#history#Add(a:buffer, 'failed', l:job_id, l:command)
|
||||
let l:id = l:lsp_details.connection_id
|
||||
let l:root = l:lsp_details.project_root
|
||||
|
||||
" Remember the linter this connection is for.
|
||||
let s:lsp_linter_map[l:id] = a:linter.name
|
||||
|
||||
let l:change_message = a:linter.lsp is# 'tsserver'
|
||||
\ ? ale#lsp#tsserver_message#Geterr(a:buffer)
|
||||
\ : ale#lsp#message#DidChange(a:buffer)
|
||||
let l:request_id = ale#lsp#Send(l:id, l:change_message, l:root)
|
||||
|
||||
if l:request_id != 0
|
||||
if index(l:info.active_linter_list, a:linter.name) < 0
|
||||
call add(l:info.active_linter_list, a:linter.name)
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:request_id != 0
|
||||
endfunction
|
||||
|
||||
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
|
||||
" Figure out which linters are still enabled, and remove
|
||||
" problems for linters which are no longer enabled.
|
||||
let l:name_map = {}
|
||||
|
||||
for l:linter in a:linters
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
call filter(
|
||||
\ get(g:ale_buffer_info[a:buffer], 'loclist', []),
|
||||
\ 'get(l:name_map, get(v:val, ''linter_name''))',
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
|
||||
let l:filename = expand('#' . a:buffer . ':p')
|
||||
let l:loclist = []
|
||||
let l:name_map = {}
|
||||
|
||||
" Build a map of the active linters.
|
||||
for l:linter in a:linters
|
||||
let l:name_map[l:linter.name] = 1
|
||||
endfor
|
||||
|
||||
" Find the items from other buffers, for the linters that are enabled.
|
||||
for l:info in values(g:ale_buffer_info)
|
||||
for l:item in l:info.loclist
|
||||
if has_key(l:item, 'filename')
|
||||
\&& l:item.filename is# l:filename
|
||||
\&& has_key(l:name_map, l:item.linter_name)
|
||||
" Copy the items and set the buffer numbers to this one.
|
||||
let l:new_item = copy(l:item)
|
||||
let l:new_item.bufnr = a:buffer
|
||||
call add(l:loclist, l:new_item)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if !empty(l:loclist)
|
||||
call sort(l:loclist, function('ale#util#LocItemCompareWithText'))
|
||||
call uniq(l:loclist, function('ale#util#LocItemCompareWithText'))
|
||||
|
||||
" Set the loclist variable, used by some parts of ALE.
|
||||
let g:ale_buffer_info[a:buffer].loclist = l:loclist
|
||||
call ale#engine#SetResults(a:buffer, l:loclist)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Run a linter for a buffer.
|
||||
"
|
||||
" Returns 1 if the linter was successfully run.
|
||||
function! s:RunLinter(buffer, linter) abort
|
||||
if !empty(a:linter.lsp)
|
||||
return s:CheckWithLSP(a:buffer, a:linter)
|
||||
else
|
||||
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
||||
|
||||
if ale#engine#IsExecutable(a:buffer, l:executable)
|
||||
return s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endif
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
" Initialise the buffer information if needed.
|
||||
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
|
||||
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
|
||||
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
|
||||
|
||||
" We can only clear the results if we aren't checking the buffer.
|
||||
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
|
||||
|
||||
for l:linter in a:linters
|
||||
" Only run lint_file linters if we should.
|
||||
if !l:linter.lint_file || a:should_lint_file
|
||||
if s:RunLinter(a:buffer, l:linter)
|
||||
" If a single linter ran, we shouldn't clear everything.
|
||||
let l:can_clear_results = 0
|
||||
endif
|
||||
else
|
||||
" If we skipped running a lint_file linter still in the list,
|
||||
" we shouldn't clear everything.
|
||||
let l:can_clear_results = 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Clear the results if we can. This needs to be done when linters are
|
||||
" disabled, or ALE itself is disabled.
|
||||
if l:can_clear_results
|
||||
call ale#engine#SetResults(a:buffer, [])
|
||||
elseif l:new_buffer
|
||||
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Clean up a buffer.
|
||||
"
|
||||
" This function will stop all current jobs for the buffer,
|
||||
" clear the state of everything, and remove the Dictionary for managing
|
||||
" the buffer.
|
||||
function! ale#engine#Cleanup(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
if !l:is_open
|
||||
if g:ale_history_enabled
|
||||
call ale#history#Add(a:buffer, 'started', l:job_id, l:command)
|
||||
endif
|
||||
call ale#engine#RunLinters(a:buffer, [], 1)
|
||||
|
||||
call add(l:open_documents, a:linter.name)
|
||||
call ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ ale#lsp#tsserver_message#Open(a:buffer),
|
||||
\)
|
||||
endif
|
||||
|
||||
call ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ ale#lsp#tsserver_message#Change(a:buffer),
|
||||
\)
|
||||
|
||||
let l:request_id = ale#lsp#SendMessageToProgram(
|
||||
\ a:executable,
|
||||
\ ale#lsp#tsserver_message#Geterr(a:buffer),
|
||||
\)
|
||||
|
||||
if l:request_id != 0
|
||||
let l:info.waiting_for_tsserver = 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Invoke(buffer, linter) abort
|
||||
if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
|
||||
let l:executable = has_key(a:linter, 'executable_callback')
|
||||
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
|
||||
\ : a:linter.executable
|
||||
|
||||
" Run this program if it can be executed.
|
||||
if s:IsExecutable(l:executable)
|
||||
if a:linter.lsp ==# 'tsserver'
|
||||
call s:CheckWithTSServer(a:buffer, a:linter, l:executable)
|
||||
else
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, return the warnings and errors for a given buffer.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
|
||||
function! ale#events#SaveEvent() abort
|
||||
let l:should_lint = g:ale_enabled && g:ale_lint_on_save
|
||||
function! ale#events#SaveEvent(buffer) abort
|
||||
call setbufvar(a:buffer, 'ale_save_event_fired', 1)
|
||||
let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save
|
||||
|
||||
if g:ale_fix_on_save
|
||||
let l:will_fix = ale#fix#Fix('save_file')
|
||||
@@ -9,25 +10,38 @@ function! ale#events#SaveEvent() abort
|
||||
endif
|
||||
|
||||
if l:should_lint
|
||||
call ale#Queue(0, 'lint_file')
|
||||
call ale#Queue(0, 'lint_file', a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:LintOnEnter() abort
|
||||
if g:ale_enabled && g:ale_lint_on_enter && has_key(b:, 'ale_file_changed')
|
||||
function! s:LintOnEnter(buffer) abort
|
||||
if ale#Var(a:buffer, 'enabled')
|
||||
\&& g:ale_lint_on_enter
|
||||
\&& has_key(b:, 'ale_file_changed')
|
||||
call remove(b:, 'ale_file_changed')
|
||||
call ale#Queue(0, 'lint_file')
|
||||
call ale#Queue(0, 'lint_file', a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#events#EnterEvent() abort
|
||||
call s:LintOnEnter()
|
||||
function! ale#events#EnterEvent(buffer) abort
|
||||
let l:filetype = getbufvar(a:buffer, '&filetype')
|
||||
call setbufvar(a:buffer, 'ale_original_filetype', l:filetype)
|
||||
|
||||
call s:LintOnEnter(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! ale#events#FileTypeEvent(buffer, new_filetype) abort
|
||||
let l:filetype = getbufvar(a:buffer, 'ale_original_filetype', '')
|
||||
|
||||
if a:new_filetype isnot# l:filetype
|
||||
call ale#Queue(300, 'lint_file', a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#events#FileChangedEvent(buffer) abort
|
||||
call setbufvar(a:buffer, 'ale_file_changed', 1)
|
||||
|
||||
if bufnr('') == a:buffer
|
||||
call s:LintOnEnter()
|
||||
call s:LintOnEnter(a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -43,7 +43,6 @@ function! ale#fix#ApplyQueuedFixes() abort
|
||||
if empty(&buftype)
|
||||
noautocmd :w!
|
||||
else
|
||||
call writefile(l:data.output, 'fix_test_file')
|
||||
set nomodified
|
||||
endif
|
||||
endif
|
||||
@@ -77,8 +76,6 @@ function! ale#fix#ApplyFixes(buffer, output) abort
|
||||
echoerr 'The file was changed before fixing finished'
|
||||
return
|
||||
endif
|
||||
|
||||
let l:data.done = 1
|
||||
endif
|
||||
|
||||
if !bufexists(a:buffer)
|
||||
@@ -86,6 +83,8 @@ function! ale#fix#ApplyFixes(buffer, output) abort
|
||||
call remove(g:ale_fix_buffer_data, a:buffer)
|
||||
endif
|
||||
|
||||
let l:data.done = 1
|
||||
|
||||
" We can only change the lines of a buffer which is currently open,
|
||||
" so try and apply the fixes to the current buffer.
|
||||
call ale#fix#ApplyQueuedFixes()
|
||||
@@ -102,9 +101,15 @@ function! s:HandleExit(job_id, exit_code) abort
|
||||
let l:job_info.output = readfile(l:job_info.file_to_read)
|
||||
endif
|
||||
|
||||
" Use the output of the job for changing the file if it isn't empty,
|
||||
" otherwise skip this job and use the input from before.
|
||||
let l:input = !empty(l:job_info.output)
|
||||
\ ? l:job_info.output
|
||||
\ : l:job_info.input
|
||||
|
||||
call s:RunFixer({
|
||||
\ 'buffer': l:job_info.buffer,
|
||||
\ 'input': l:job_info.output,
|
||||
\ 'input': l:input,
|
||||
\ 'callback_list': l:job_info.callback_list,
|
||||
\ 'callback_index': l:job_info.callback_index + 1,
|
||||
\})
|
||||
@@ -149,7 +154,7 @@ function! s:CreateTemporaryFileForJob(buffer, temporary_file, input) abort
|
||||
" Automatically delete the directory later.
|
||||
call ale#fix#ManageDirectory(a:buffer, l:temporary_directory)
|
||||
" Write the buffer out to a file.
|
||||
call writefile(a:input, a:temporary_file)
|
||||
call ale#util#Writefile(a:buffer, a:input, a:temporary_file)
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
@@ -172,6 +177,7 @@ function! s:RunJob(options) abort
|
||||
|
||||
let l:job_info = {
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'output': [],
|
||||
\ 'callback_list': a:options.callback_list,
|
||||
\ 'callback_index': a:options.callback_index,
|
||||
@@ -180,9 +186,9 @@ function! s:RunJob(options) abort
|
||||
if l:read_temporary_file
|
||||
" TODO: Check that a temporary file is set here.
|
||||
let l:job_info.file_to_read = l:temporary_file
|
||||
elseif l:output_stream ==# 'stderr'
|
||||
elseif l:output_stream is# 'stderr'
|
||||
let l:job_options.err_cb = function('s:GatherOutput')
|
||||
elseif l:output_stream ==# 'both'
|
||||
elseif l:output_stream is# 'both'
|
||||
let l:job_options.out_cb = function('s:GatherOutput')
|
||||
let l:job_options.err_cb = function('s:GatherOutput')
|
||||
else
|
||||
@@ -314,7 +320,7 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
|
||||
\ 'lines_before': getbufline(a:buffer, 1, '$'),
|
||||
\ 'filename': expand('#' . a:buffer . ':p'),
|
||||
\ 'done': 0,
|
||||
\ 'should_save': a:fixing_flag ==# 'save_file',
|
||||
\ 'should_save': a:fixing_flag is# 'save_file',
|
||||
\ 'temporary_directory_list': [],
|
||||
\}
|
||||
endfunction
|
||||
@@ -329,14 +335,14 @@ function! ale#fix#Fix(...) abort
|
||||
|
||||
let l:fixing_flag = get(a:000, 0, '')
|
||||
|
||||
if l:fixing_flag !=# '' && l:fixing_flag !=# 'save_file'
|
||||
if l:fixing_flag isnot# '' && l:fixing_flag isnot# 'save_file'
|
||||
throw "fixing_flag must be either '' or 'save_file'"
|
||||
endif
|
||||
|
||||
let l:callback_list = s:GetCallbacks()
|
||||
|
||||
if empty(l:callback_list)
|
||||
if l:fixing_flag ==# ''
|
||||
if l:fixing_flag is# ''
|
||||
echoerr 'No fixers have been defined. Try :ALEFixSuggest'
|
||||
endif
|
||||
|
||||
|
||||
@@ -7,11 +7,21 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
\ 'description': 'Add blank lines before control statements.',
|
||||
\ },
|
||||
\ 'align_help_tags': {
|
||||
\ 'function': 'ale#fixers#help#AlignTags',
|
||||
\ 'suggested_filetypes': ['help'],
|
||||
\ 'description': 'Align help tags to the right margin',
|
||||
\ },
|
||||
\ 'autopep8': {
|
||||
\ 'function': 'ale#fixers#autopep8#Fix',
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
\ 'description': 'Fix PEP8 issues with autopep8.',
|
||||
\ },
|
||||
\ 'prettier_standard': {
|
||||
\ 'function': 'ale#fixers#prettier_standard#Fix',
|
||||
\ 'suggested_filetypes': ['javascript'],
|
||||
\ 'description': 'Apply prettier-standard to a file.',
|
||||
\ },
|
||||
\ 'eslint': {
|
||||
\ 'function': 'ale#fixers#eslint#Fix',
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript'],
|
||||
@@ -32,6 +42,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['javascript'],
|
||||
\ 'description': 'Apply prettier-eslint to a file.',
|
||||
\ },
|
||||
\ 'puppetlint': {
|
||||
\ 'function': 'ale#fixers#puppetlint#Fix',
|
||||
\ 'suggested_filetypes': ['puppet'],
|
||||
\ 'description': 'Run puppet-lint -f on a file.',
|
||||
\ },
|
||||
\ 'remove_trailing_lines': {
|
||||
\ 'function': 'ale#fixers#generic#RemoveTrailingBlankLines',
|
||||
\ 'suggested_filetypes': [],
|
||||
@@ -47,6 +62,31 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['ruby'],
|
||||
\ 'description': 'Fix ruby files with rubocop --auto-correct.',
|
||||
\ },
|
||||
\ 'standard': {
|
||||
\ 'function': 'ale#fixers#standard#Fix',
|
||||
\ 'suggested_filetypes': ['javascript'],
|
||||
\ 'description': 'Fix JavaScript files using standard --fix',
|
||||
\ },
|
||||
\ 'stylelint': {
|
||||
\ 'function': 'ale#fixers#stylelint#Fix',
|
||||
\ 'suggested_filetypes': ['css', 'sass', 'scss', 'stylus'],
|
||||
\ 'description': 'Fix stylesheet files using stylelint --fix.',
|
||||
\ },
|
||||
\ 'swiftformat': {
|
||||
\ 'function': 'ale#fixers#swiftformat#Fix',
|
||||
\ 'suggested_filetypes': ['swift'],
|
||||
\ 'description': 'Apply SwiftFormat to a file.',
|
||||
\ },
|
||||
\ 'phpcbf': {
|
||||
\ 'function': 'ale#fixers#phpcbf#Fix',
|
||||
\ 'suggested_filetypes': ['php'],
|
||||
\ 'description': 'Fix PHP files with phpcbf.',
|
||||
\ },
|
||||
\ 'clang-format': {
|
||||
\ 'function': 'ale#fixers#clangformat#Fix',
|
||||
\ 'suggested_filetypes': ['c', 'cpp'],
|
||||
\ 'description': 'Fix C/C++ files with clang-format.',
|
||||
\ },
|
||||
\}
|
||||
|
||||
" Reset the function registry to the default entries.
|
||||
@@ -111,44 +151,56 @@ endfunction
|
||||
" Suggest functions to use from the registry.
|
||||
function! ale#fix#registry#Suggest(filetype) abort
|
||||
let l:type_list = split(a:filetype, '\.')
|
||||
let l:first_for_filetype = 1
|
||||
let l:first_generic = 1
|
||||
let l:filetype_fixer_list = []
|
||||
|
||||
for l:key in sort(keys(s:entries))
|
||||
let l:suggested_filetypes = s:entries[l:key].suggested_filetypes
|
||||
|
||||
if s:ShouldSuggestForType(l:suggested_filetypes, l:type_list)
|
||||
if l:first_for_filetype
|
||||
let l:first_for_filetype = 0
|
||||
echom 'Try the following fixers appropriate for the filetype:'
|
||||
echom ''
|
||||
endif
|
||||
|
||||
echom printf('%s - %s', string(l:key), s:entries[l:key].description)
|
||||
call add(
|
||||
\ l:filetype_fixer_list,
|
||||
\ printf('%s - %s', string(l:key), s:entries[l:key].description),
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
|
||||
let l:generic_fixer_list = []
|
||||
|
||||
for l:key in sort(keys(s:entries))
|
||||
if empty(s:entries[l:key].suggested_filetypes)
|
||||
if l:first_generic
|
||||
if !l:first_for_filetype
|
||||
echom ''
|
||||
endif
|
||||
|
||||
let l:first_generic = 0
|
||||
echom 'Try the following generic fixers:'
|
||||
echom ''
|
||||
endif
|
||||
|
||||
echom printf('%s - %s', string(l:key), s:entries[l:key].description)
|
||||
call add(
|
||||
\ l:generic_fixer_list,
|
||||
\ printf('%s - %s', string(l:key), s:entries[l:key].description),
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
|
||||
if l:first_for_filetype && l:first_generic
|
||||
echom 'There is nothing in the registry to suggest.'
|
||||
let l:filetype_fixer_header = !empty(l:filetype_fixer_list)
|
||||
\ ? ['Try the following fixers appropriate for the filetype:', '']
|
||||
\ : []
|
||||
let l:generic_fixer_header = !empty(l:generic_fixer_list)
|
||||
\ ? ['Try the following generic fixers:', '']
|
||||
\ : []
|
||||
|
||||
let l:has_both_lists = !empty(l:filetype_fixer_list) && !empty(l:generic_fixer_list)
|
||||
|
||||
let l:lines =
|
||||
\ l:filetype_fixer_header
|
||||
\ + l:filetype_fixer_list
|
||||
\ + (l:has_both_lists ? [''] : [])
|
||||
\ + l:generic_fixer_header
|
||||
\ + l:generic_fixer_list
|
||||
|
||||
if empty(l:lines)
|
||||
let l:lines = ['There is nothing in the registry to suggest.']
|
||||
else
|
||||
echom ''
|
||||
echom 'See :help ale-fix-configuration'
|
||||
let l:lines += ['', 'See :help ale-fix-configuration']
|
||||
endif
|
||||
|
||||
let l:lines += ['', 'Press q to close this window']
|
||||
|
||||
new +set\ filetype=ale-fix-suggest
|
||||
call setline(1, l:lines)
|
||||
setlocal nomodified
|
||||
setlocal nomodifiable
|
||||
endfunction
|
||||
|
||||
@@ -9,7 +9,7 @@ function! ale#fixers#autopep8#Fix(buffer) abort
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'python_autopep8',
|
||||
\ ['/bin/autopep8'],
|
||||
\ ['autopep8'],
|
||||
\)
|
||||
|
||||
if !executable(l:executable)
|
||||
|
||||
22
autoload/ale/fixers/clangformat.vim
Normal file
22
autoload/ale/fixers/clangformat.vim
Normal file
@@ -0,0 +1,22 @@
|
||||
scriptencoding utf-8
|
||||
" Author: Peter Renström <renstrom.peter@gmail.com>
|
||||
" Description: Fixing C/C++ files with clang-format.
|
||||
|
||||
call ale#Set('c_clangformat_executable', 'clang-format')
|
||||
call ale#Set('c_clangformat_use_global', 0)
|
||||
call ale#Set('c_clangformat_options', '')
|
||||
|
||||
function! ale#fixers#clangformat#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'c_clangformat', [
|
||||
\ 'clang-format',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#clangformat#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'c_clangformat_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
|
||||
\ . ' ' . l:options,
|
||||
\}
|
||||
endfunction
|
||||
@@ -2,22 +2,23 @@
|
||||
" Description: Fixing files with eslint.
|
||||
|
||||
function! s:FindConfig(buffer) abort
|
||||
for l:filename in [
|
||||
\ '.eslintrc.js',
|
||||
\ '.eslintrc.yaml',
|
||||
\ '.eslintrc.yml',
|
||||
\ '.eslintrc.json',
|
||||
\ '.eslintrc',
|
||||
\ 'package.json',
|
||||
\]
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
|
||||
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
|
||||
for l:basename in [
|
||||
\ '.eslintrc.js',
|
||||
\ '.eslintrc.yaml',
|
||||
\ '.eslintrc.yml',
|
||||
\ '.eslintrc.json',
|
||||
\ '.eslintrc',
|
||||
\]
|
||||
let l:config = ale#path#Simplify(l:path . '/' . l:basename)
|
||||
|
||||
if !empty(l:config)
|
||||
return l:config
|
||||
endif
|
||||
if filereadable(l:config)
|
||||
return l:config
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return ''
|
||||
return ale#path#FindNearestFile(a:buffer, 'package.json')
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#eslint#Fix(buffer) abort
|
||||
@@ -29,8 +30,8 @@ function! ale#fixers#eslint#Fix(buffer) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . ' --config ' . ale#Escape(l:config)
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ' -c ' . ale#Escape(l:config)
|
||||
\ . ' --fix %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
|
||||
@@ -23,3 +23,38 @@ function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, line
|
||||
|
||||
return l:new_lines
|
||||
endfunction
|
||||
|
||||
" This function breaks up long lines so that autopep8 or other tools can
|
||||
" fix the badly-indented code which is produced as a result.
|
||||
function! ale#fixers#generic_python#BreakUpLongLines(buffer, lines) abort
|
||||
" Default to a maximum line length of 79
|
||||
let l:max_line_length = 79
|
||||
let l:conf = ale#path#FindNearestFile(a:buffer, 'setup.cfg')
|
||||
|
||||
" Read the maximum line length from setup.cfg
|
||||
if !empty(l:conf)
|
||||
for l:match in ale#util#GetMatches(
|
||||
\ readfile(l:conf),
|
||||
\ '\v^ *max-line-length *\= *(\d+)',
|
||||
\)
|
||||
let l:max_line_length = str2nr(l:match[1])
|
||||
endfor
|
||||
endif
|
||||
|
||||
let l:new_list = []
|
||||
|
||||
for l:line in a:lines
|
||||
if len(l:line) > l:max_line_length && l:line !~# '# *noqa'
|
||||
let l:line = substitute(l:line, '\v([(,])([^)])', '\1\n\2', 'g')
|
||||
let l:line = substitute(l:line, '\v([^(])([)])', '\1,\n\2', 'g')
|
||||
|
||||
for l:split_line in split(l:line, "\n")
|
||||
call add(l:new_list, l:split_line)
|
||||
endfor
|
||||
else
|
||||
call add(l:new_list, l:line)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:new_list
|
||||
endfunction
|
||||
|
||||
24
autoload/ale/fixers/help.vim
Normal file
24
autoload/ale/fixers/help.vim
Normal file
@@ -0,0 +1,24 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Generic fixer functions for Vim help documents.
|
||||
|
||||
function! ale#fixers#help#AlignTags(buffer, lines) abort
|
||||
let l:new_lines = []
|
||||
|
||||
for l:line in a:lines
|
||||
if len(l:line) != 79
|
||||
let l:match = matchlist(l:line, '\v +(\*[^*]+\*)$')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:start = l:line[:-len(l:match[0]) - 1]
|
||||
let l:tag = l:match[1]
|
||||
let l:spaces = repeat(' ', 79 - len(l:start) - len(l:tag))
|
||||
|
||||
let l:line = l:start . l:spaces . l:tag
|
||||
endif
|
||||
endif
|
||||
|
||||
call add(l:new_lines, l:line)
|
||||
endfor
|
||||
|
||||
return l:new_lines
|
||||
endfunction
|
||||
@@ -8,7 +8,7 @@ function! ale#fixers#isort#Fix(buffer) abort
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'python_isort',
|
||||
\ ['/bin/isort'],
|
||||
\ ['isort'],
|
||||
\)
|
||||
|
||||
if !executable(l:executable)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user