mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-07 13:14:29 +08:00
Compare commits
190 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97b410bbba | ||
|
|
78b05d30a5 | ||
|
|
6f6c156995 | ||
|
|
62a45f8ae4 | ||
|
|
73e0f87eba | ||
|
|
bf2075cd0c | ||
|
|
db835fa0a1 | ||
|
|
325fcc25dd | ||
|
|
eb37d9c1fc | ||
|
|
df2c6df819 | ||
|
|
c3ebe7bd9e | ||
|
|
472631573e | ||
|
|
c0ac393297 | ||
|
|
da8408501c | ||
|
|
a3b7056cad | ||
|
|
a9a76241ac | ||
|
|
ccf78c40b1 | ||
|
|
0143eb6a53 | ||
|
|
6f40cdca65 | ||
|
|
9d85590421 | ||
|
|
0a14bbe78d | ||
|
|
744d7d789f | ||
|
|
eb410b4ee6 | ||
|
|
9a5fc6f932 | ||
|
|
d953c68ebb | ||
|
|
829f87bc6a | ||
|
|
f2fc7072b9 | ||
|
|
97131262ab | ||
|
|
32c8d02d62 | ||
|
|
512b6e00d9 | ||
|
|
e8123b3d5e | ||
|
|
a1458e9c07 | ||
|
|
03bab835d9 | ||
|
|
aff56e69a9 | ||
|
|
a82ead0dc1 | ||
|
|
a9c650cd05 | ||
|
|
fd89da113d | ||
|
|
b2696b105a | ||
|
|
d7ed49f849 | ||
|
|
e4a4fcd26b | ||
|
|
cae153b3ac | ||
|
|
23f8e7ddc5 | ||
|
|
a37970facd | ||
|
|
a23173eeb2 | ||
|
|
9820899b9e | ||
|
|
ea438be5c1 | ||
|
|
831f783493 | ||
|
|
2478d7d925 | ||
|
|
1560f4ce03 | ||
|
|
d45505e135 | ||
|
|
62b492c727 | ||
|
|
41686980fd | ||
|
|
35bdd6f478 | ||
|
|
f1ac7c9f73 | ||
|
|
548ff299f4 | ||
|
|
8762a6fa66 | ||
|
|
74e7a283c0 | ||
|
|
dc8166384c | ||
|
|
0a9f9c0811 | ||
|
|
f412b4f96f | ||
|
|
3b486d3475 | ||
|
|
9191750b5b | ||
|
|
9c5f092b4f | ||
|
|
75485d53f6 | ||
|
|
2c176a234e | ||
|
|
5a0c3fd01e | ||
|
|
ed43b17201 | ||
|
|
c17123b631 | ||
|
|
c9b58136bf | ||
|
|
871c09c123 | ||
|
|
c97ad01bcb | ||
|
|
4566bd65c9 | ||
|
|
e0928d0991 | ||
|
|
2b251a2cee | ||
|
|
3e1486fc92 | ||
|
|
14aff89fb2 | ||
|
|
fcfd8d5f56 | ||
|
|
12e99489b2 | ||
|
|
9767fd8732 | ||
|
|
e46ef0ae19 | ||
|
|
55827a9493 | ||
|
|
6c0996eb9c | ||
|
|
cd6d8f2ab6 | ||
|
|
771bfe3b18 | ||
|
|
bda6df61a0 | ||
|
|
8cb9b2ba4e | ||
|
|
7e6d5292f7 | ||
|
|
8df2444ec4 | ||
|
|
4ad5c4757c | ||
|
|
54b55bb39c | ||
|
|
1ae851878a | ||
|
|
0ffef758ae | ||
|
|
3418faf054 | ||
|
|
10777d3421 | ||
|
|
f950c29035 | ||
|
|
88f4598ea2 | ||
|
|
76a03b0709 | ||
|
|
70e379cc46 | ||
|
|
25f6445c50 | ||
|
|
b5013ba54b | ||
|
|
815be12649 | ||
|
|
88c203b686 | ||
|
|
aee339f401 | ||
|
|
d5c626667e | ||
|
|
725957de6e | ||
|
|
1a749a6b43 | ||
|
|
ff8f3673eb | ||
|
|
d77e5a9308 | ||
|
|
35307c0585 | ||
|
|
bbdff82aee | ||
|
|
3a1caca907 | ||
|
|
5636626da1 | ||
|
|
f5a4e11894 | ||
|
|
66b183e1ba | ||
|
|
900b4cdff3 | ||
|
|
e03df80a09 | ||
|
|
da37989960 | ||
|
|
10bacf0996 | ||
|
|
f7e6236fe8 | ||
|
|
d700da8cb8 | ||
|
|
713a6910d4 | ||
|
|
498a9435de | ||
|
|
7669550ae2 | ||
|
|
0a3faa60f7 | ||
|
|
2e5f3899d1 | ||
|
|
ccc08d08f6 | ||
|
|
60b89abd9c | ||
|
|
ec2845eefa | ||
|
|
ca18a80e3e | ||
|
|
8d5353831e | ||
|
|
f9cbc69ce1 | ||
|
|
175db78f35 | ||
|
|
8ba5b3cb76 | ||
|
|
afa37e6855 | ||
|
|
5b8410f868 | ||
|
|
8632e6b4e0 | ||
|
|
f03fb64e51 | ||
|
|
4088347901 | ||
|
|
614a30a508 | ||
|
|
cb410927d1 | ||
|
|
f44756f347 | ||
|
|
e3a8829d67 | ||
|
|
9028d1f132 | ||
|
|
a6ca60203f | ||
|
|
629e6a3675 | ||
|
|
c4ab4855b7 | ||
|
|
8bee64d1b7 | ||
|
|
e9bbbbdf3e | ||
|
|
9a4645fc7f | ||
|
|
5fc2f8f6c0 | ||
|
|
86cc2aab71 | ||
|
|
5b56103c69 | ||
|
|
c8821fc049 | ||
|
|
1bcee7ef33 | ||
|
|
454dbbe33e | ||
|
|
aa4c669ea0 | ||
|
|
60762d5018 | ||
|
|
222d9e6908 | ||
|
|
9a019e2342 | ||
|
|
73c9a1f965 | ||
|
|
0fbf7bcc99 | ||
|
|
2bcb21f350 | ||
|
|
d6a7b0f518 | ||
|
|
b9428b7db0 | ||
|
|
95373ddab5 | ||
|
|
6e66b60b63 | ||
|
|
79552872f3 | ||
|
|
c546f47cc0 | ||
|
|
0dbf08f6d5 | ||
|
|
7481facd73 | ||
|
|
226b4ed586 | ||
|
|
36461b69d7 | ||
|
|
f94865c4ce | ||
|
|
dc99282f79 | ||
|
|
89d8f2a0bc | ||
|
|
99aebcafac | ||
|
|
cd00a18c3a | ||
|
|
e293e0b5ab | ||
|
|
f49f615ef6 | ||
|
|
216eadbcbe | ||
|
|
1e83489691 | ||
|
|
5eee70cf37 | ||
|
|
ce3d79550d | ||
|
|
c697ef05bb | ||
|
|
7a06d276c2 | ||
|
|
a2e4af1626 | ||
|
|
c34664120b | ||
|
|
a34fb0a6a7 | ||
|
|
acb209aa11 | ||
|
|
6df632218e |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -5,3 +5,4 @@
|
||||
/README.md export-ignore
|
||||
/img export-ignore
|
||||
/test export-ignore
|
||||
/custom-checks export-ignore
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
language: python
|
||||
script: |
|
||||
make test
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# Contributing to ALE
|
||||
|
||||
1. [Guidelines](#guidelines)
|
||||
2. [Creating Pull Requests](#pull-requests)
|
||||
3. [Creating Pull Requests](#compiling)
|
||||
2. [Creating Issues](#issues)
|
||||
3. [Creating Pull Requests](#pull-requests)
|
||||
1. [Adding a New Linter](#adding-a-new-linter)
|
||||
2. [Adding New Options](#adding-new-options)
|
||||
|
||||
<a name="guidelines"></a>
|
||||
|
||||
@@ -10,16 +12,44 @@
|
||||
|
||||
Have fun, and work on whatever floats your boat. Take It Easy :tm:.
|
||||
|
||||
When writing code, follow the [Google Vimscript Style
|
||||
Guide](https://google.github.io/styleguide/vimscriptguide.xml), and run `vint
|
||||
-s` on your files to check for most of what the guide mentions and more. If you
|
||||
install this plugin (ALE) and install [Vint](https://github.com/Kuniwak/vint), it
|
||||
will check your code while you type.
|
||||
|
||||
<a name="issues"></a>
|
||||
|
||||
# 2. Creating Issues
|
||||
|
||||
Before creating any issues, please look through the current list of issues and
|
||||
pull requests, and ensure that the issue hasn't already been reported. If an
|
||||
issue has already been reported, but you have some new insight, please add
|
||||
a comment to the existing issue.
|
||||
|
||||
Please read the FAQ in the README before creating any issues. A feature
|
||||
you desire may already exist and be documented, or the FAQ might explain
|
||||
how to solve a problem you have already.
|
||||
|
||||
Please try and describe any issues reported with as much detail as you can
|
||||
provide about your Vim version, the linter you were trying to run, your
|
||||
operating system, or any other information you think might be helpful.
|
||||
|
||||
Please describe your issue in clear, grammatically correct, and easy to
|
||||
understand English. You are more likely to see an issue resolved if others
|
||||
can understand you.
|
||||
|
||||
<a name="pull-requests"></a>
|
||||
|
||||
# 2. Creating Pull Requests
|
||||
# 3. Creating Pull Requests
|
||||
|
||||
For code you write, make sure to credit yourself at the top of files you add, and probably those you modify. You can write
|
||||
some comments at the top of your VIM files.
|
||||
For code you write, make sure to credit yourself at the top of files you add,
|
||||
and probably those you modify. You can write some comments at the top of your
|
||||
VIM files.
|
||||
|
||||
```vim
|
||||
" Author: John Smith <john.smith@gmail.com>
|
||||
" Description: This file adds support for awesomelinter to the best language ever.
|
||||
" Description: This file adds support for awesomelinter for the best language ever.
|
||||
```
|
||||
|
||||
If you want to credit multiple authors, you can comma separate them.
|
||||
@@ -28,34 +58,35 @@ If you want to credit multiple authors, you can comma separate them.
|
||||
" Author: John Smith <john.smith@gmail.com>, Jane Doe <https://jane-doe.info>
|
||||
```
|
||||
|
||||
# 2.1. Adding a New Linter
|
||||
<a name="adding-a-new-linter"></a>
|
||||
|
||||
If you add a new linter, look for existing handlers first in the [handlers.vim](plugin/ale/handlers.vim) file. 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](plugin/ale/handlers.vim) file, and use the generic handler in both places.
|
||||
# 3.i. Adding a New Linter
|
||||
|
||||
When you add a linter, make sure the language for the linter and the linter itself are present in the table in the
|
||||
[README.md](README.md) file and in the Vim [help file](doc/ale.txt). The programs and linters are sorted alphabetically in the
|
||||
table and list.
|
||||
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
|
||||
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
|
||||
both places.
|
||||
|
||||
# 2.2. Adding New Options
|
||||
When you add a linter, make sure the language for the linter and the linter
|
||||
itself are present in the table in the [README.md](README.md) file and in the
|
||||
Vim [help file](doc/ale.txt). The programs and linters should be sorted
|
||||
alphabetically in the table and list.
|
||||
|
||||
If you add new options to the plugin, make sure to document those new options in the [README.md](README.md) file, and also
|
||||
in the [help file](doc/ale.txt). Follow the format of other options in each. Global options should appear in the README
|
||||
file, and in the relevant section in the help file, and options specific to a particular linter should go in the section
|
||||
for that linter.
|
||||
<a name="adding-new-options"></a>
|
||||
|
||||
<a name="compiling"></a>
|
||||
# 3.ii. Adding New Options
|
||||
|
||||
# 3. Compiling the Windows stdin wrapper
|
||||
If you add new options to the plugin, make sure to document those new options
|
||||
in the [README.md](README.md) file, and also in the [help file](doc/ale.txt).
|
||||
Follow the format of other options in each. Global options should appear in the
|
||||
README file, and in the relevant section in the help file. Options specific
|
||||
to a particular linter should appear in the section for that linter.
|
||||
|
||||
To compile the stdin wrapper program for Windows, when updating the D program, you will need to compile the program with
|
||||
[LDC](https://github.com/ldc-developers/ldc) in release mode. Download and install the Community edition of Visual Studio
|
||||
from [the Visual Studio website](https://www.visualstudio.com/downloads/) first before installing LDC. LDC typically comes in
|
||||
a ZIP you can just extract somewhere.
|
||||
Linter options for customizing general argument lists should be named
|
||||
`g:ale_<filetype>_<linter>_options`, so that all linters can have similar
|
||||
global variable names.
|
||||
|
||||
Make sure to compile with the 32-bit architecture flag, otherwise the EXE will not run on 32-bit machines.
|
||||
|
||||
```
|
||||
ldc2 -m32 -Oz -release stdin_wrapper.d -of=stdin-wrapper.exe
|
||||
```
|
||||
Any options for linters should be set to some default value so it is always
|
||||
easy to see what the default is with `:echo g:ale...`.
|
||||
|
||||
11
Makefile
11
Makefile
@@ -1,3 +1,4 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
IMAGE ?= w0rp/ale
|
||||
CURRENT_IMAGE_ID = 107e4efc4267
|
||||
DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)"
|
||||
@@ -25,8 +26,18 @@ test: test-setup
|
||||
echo '========================================'; \
|
||||
echo 'Vint warnings/errors follow:'; \
|
||||
echo; \
|
||||
set -o pipefail; \
|
||||
docker run -a stdout $(DOCKER_FLAGS) vint -s /testplugin | sed s:^/testplugin/:: || EXIT=$$?; \
|
||||
set +o pipefail; \
|
||||
echo; \
|
||||
echo '========================================'; \
|
||||
echo 'Running custom checks'; \
|
||||
echo '========================================'; \
|
||||
echo 'Custom warnings/errors follow:'; \
|
||||
echo; \
|
||||
set -o pipefail; \
|
||||
docker run -a stdout $(DOCKER_FLAGS) /testplugin/custom-checks /testplugin | sed s:^/testplugin/:: || EXIT=$$?; \
|
||||
set +o pipefail; \
|
||||
echo; \
|
||||
exit $$EXIT;
|
||||
|
||||
|
||||
305
README.md
305
README.md
@@ -15,7 +15,28 @@ back to a filesystem.
|
||||
|
||||
In other words, this plugin allows you to lint while you type.
|
||||
|
||||
## Supported Languages and Tools
|
||||
## Table of Contents
|
||||
|
||||
1. [Supported Languages and Tools](#supported-languages)
|
||||
2. [Usage](#usage)
|
||||
3. [Installation](#installation)
|
||||
1. [Installation with Pathogen](#installation-with-pathogen)
|
||||
2. [Installation with Vundle](#installation-with-vundle)
|
||||
3. [Manual Installation](#manual-installation)
|
||||
4. [FAQ](#faq)
|
||||
1. [How do I disable particular linters?](#faq-disable-linters)
|
||||
2. [How can I keep the sign gutter open?](#faq-disable-linters)
|
||||
3. [How can I change the signs ALE uses?](#faq-change-signs)
|
||||
4. [How can I show errors or warnings in my statusline?](#faq-statusline)
|
||||
5. [How can I change the format for echo messages?](#faq-echo-format)
|
||||
6. [How can I execute some code when ALE stops linting?](#faq-autocmd)
|
||||
7. [How can I navigate between errors quickly?](#faq-navigation)
|
||||
8. [How can I run linters only when I save files?](#faq-lint-on-save)
|
||||
9. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
|
||||
|
||||
<a name="supported-languages"></a>
|
||||
|
||||
## 1. Supported Languages and Tools
|
||||
|
||||
This plugin supports the following languages and tools. All available
|
||||
tools will be run in combination, so they can be complementary.
|
||||
@@ -28,44 +49,61 @@ name. That seems to be the fairest way to arrange this table.
|
||||
|
||||
| Language | Tools |
|
||||
| -------- | ----- |
|
||||
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) |
|
||||
| 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 | [gcc](https://gcc.gnu.org/) |
|
||||
| C++ (filetype cpp)| [gcc](https://gcc.gnu.org/) |
|
||||
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
|
||||
| C++ (filetype cpp) | [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
|
||||
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
|
||||
| Chef | [foodcritic](http://www.foodcritic.io/) |
|
||||
| CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
|
||||
| CSS | [csslint](http://csslint.net/) |
|
||||
| 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)^ |
|
||||
| D | [dmd](https://dlang.org/dmd-linux.html) |
|
||||
| Dockerfile | [hadolint](https://github.com/lukasmartinelli/hadolint) |
|
||||
| Elixir | [credo](https://github.com/rrrene/credo) |
|
||||
| Elm | [elm-make](https://github.com/elm-lang/elm-make) |
|
||||
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
|
||||
| Fortran | [gcc](https://gcc.gnu.org/) |
|
||||
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint) |
|
||||
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [go build](https://golang.org/cmd/go/) |
|
||||
| Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint) |
|
||||
| HTML | [HTMLHint](http://htmlhint.com/), [tidy](http://www.html-tidy.org/) |
|
||||
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/) |
|
||||
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/) |
|
||||
| JSON | [jsonlint](http://zaa.ch/jsonlint/) |
|
||||
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck) |
|
||||
| Lua | [luacheck](https://github.com/mpeterv/luacheck) |
|
||||
| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/)|
|
||||
| MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) |
|
||||
| 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 | [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
|
||||
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
|
||||
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
|
||||
| Python | [flake8](http://flake8.pycqa.org/en/latest/) |
|
||||
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
|
||||
| Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) |
|
||||
| Ruby | [rubocop](https://github.com/bbatsov/rubocop) |
|
||||
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint) |
|
||||
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint) |
|
||||
| Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) |
|
||||
| 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) |
|
||||
| TypeScript | [tslint](https://github.com/palantir/tslint) |
|
||||
| Swift | [swiftlint](https://swift.org/) |
|
||||
| Tex | [proselint](http://proselint.com/) |
|
||||
| Text^^ | [proselint](http://proselint.com/) |
|
||||
| TypeScript | [tslint](https://github.com/palantir/tslint), typecheck |
|
||||
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
|
||||
| Vim | [vint](https://github.com/Kuniwak/vint) |
|
||||
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
|
||||
|
||||
*^ Supported only on Unix machines via a wrapper script.*
|
||||
* *^^ No text linters are enabled by default.*
|
||||
|
||||
If you would like to see support for more languages and tools, please
|
||||
[create an issue](https://github.com/w0rp/ale/issues)
|
||||
or [create a pull request](https://github.com/w0rp/ale/pulls).
|
||||
If your tool can read from stdin or you have code to suggest which is good,
|
||||
support can be happily added for more tools.
|
||||
support can be happily added for it.
|
||||
|
||||
## Usage
|
||||
<a name="usage"></a>
|
||||
|
||||
## 2. Usage
|
||||
|
||||
Once this plugin is installed, while editing your files in supported
|
||||
languages and tools which have been correctly installed,
|
||||
@@ -74,32 +112,90 @@ programs for checking the syntax and semantics of your programs. By default,
|
||||
linters will be re-run in the background to check your syntax when you open
|
||||
new buffers or as you make edits to your files.
|
||||
|
||||
### Options
|
||||
The behaviour of linting can be configured with a variety of options,
|
||||
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 full list of options supported for configuring this plugin in your
|
||||
vimrc file for all given linters is as follows:
|
||||
<a name="installation"></a>
|
||||
|
||||
| Option | Description | Default |
|
||||
| ------ | ----------- | ------- |
|
||||
| `g:ale_echo_cursor` | echo errors when the cursor is over them | `1` |
|
||||
| `g:ale_echo_msg_format` | string format to use for the echoed message | `'%s'` |
|
||||
| `g:ale_echo_msg_error_str` | string used for error severity in echoed message | `'Error'` |
|
||||
| `g:ale_echo_msg_warning_str` | string used for warning severity in echoed message | `'Warning'` |
|
||||
| `g:ale_lint_delay` | milliseconds to wait before linting | `200` |
|
||||
| `g:ale_linters` | a dictionary of linters to whitelist | _not set_ |
|
||||
| `g:ale_lint_on_enter` | lint when opening a file | `1` |
|
||||
| `g:ale_lint_on_save` | lint when saving a file | `0` |
|
||||
| `g:ale_lint_on_text_changed` | lint while typing | `1` |
|
||||
| `g:ale_set_loclist` | set the loclist with errors | `1` |
|
||||
| `g:ale_set_signs` | set gutter signs with error markers | `has('signs')` |
|
||||
| `g:ale_sign_column_always` | always show the sign gutter | `0` |
|
||||
| `g:ale_sign_error` | the text to use for errors in the gutter | `'>>'` |
|
||||
| `g:ale_sign_offset` | an offset for sign ids | `1000000` |
|
||||
| `g:ale_sign_warning` | the text to use for warnings in the gutter | `'--'` |
|
||||
| `g:ale_statusline_format` | string format to use in statusline flag | `['%d error(s)', '%d warning(s)', 'OK']` |
|
||||
| `g:ale_warn_about_trailing_whitespace` | enable trailing whitespace warnings for some linters | `1` |
|
||||
## 3. Installation
|
||||
|
||||
### Selecting Particular Linters
|
||||
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
|
||||
Vim differently. On Windows, your `~/.vimrc` file will be similarly
|
||||
stored in `%USERPROFILE%\_vimrc`.
|
||||
|
||||
<a name="installation-with-pathogen"></a>
|
||||
|
||||
### 3.i. 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
|
||||
you have the line `execute pathogen#infect()` in your `~/.vimrc` file.
|
||||
You can run the following commands in your terminal to do so:
|
||||
|
||||
```bash
|
||||
cd ~/.vim/bundle
|
||||
git clone https://github.com/w0rp/ale.git
|
||||
```
|
||||
|
||||
<a name="installation-with-vundle"></a>
|
||||
|
||||
### 3.ii. 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.
|
||||
|
||||
```vim
|
||||
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="faq"></a>
|
||||
|
||||
## 4. FAQ
|
||||
|
||||
<a name="faq-disable-linters"></a>
|
||||
|
||||
### 4.i. How do I disable particular linters?
|
||||
|
||||
By default, all available tools for all supported languages will be run.
|
||||
If you want to only select a subset of the tools, simply create a
|
||||
@@ -121,15 +217,20 @@ This plugin will look for linters in the [`ale_linters`](ale_linters) directory.
|
||||
Each directory within corresponds to a particular filetype in Vim, and each file
|
||||
in each directory corresponds to the name of a particular linter.
|
||||
|
||||
### Always showing gutter
|
||||
<a name="faq-keep-signs"></a>
|
||||
|
||||
You can keep the sign gutter open at all times by setting the `g:ale_sign_column_always` to 1
|
||||
### 4.ii. How can I keep the sign gutter open?
|
||||
|
||||
You can keep the sign gutter open at all times by setting the
|
||||
`g:ale_sign_column_always` to 1
|
||||
|
||||
```vim
|
||||
let g:ale_sign_column_always = 1
|
||||
```
|
||||
|
||||
### Customize signs
|
||||
<a name="faq-change-signs"></a>
|
||||
|
||||
### 4.iii. How can I change the signs ALE uses?
|
||||
|
||||
Use these options to specify what text should be used for signs:
|
||||
|
||||
@@ -138,7 +239,18 @@ let g:ale_sign_error = '>>'
|
||||
let g:ale_sign_warning = '--'
|
||||
```
|
||||
|
||||
### Statusline
|
||||
ALE sets some background colors automatically for warnings and errors
|
||||
in the sign gutter, with the names `ALEErrorSign` and `ALEWarningSign`.
|
||||
These colors can be customised, or even removed completely:
|
||||
|
||||
```vim
|
||||
highlight clear ALEErrorSign
|
||||
highlight clear ALEWarningSign
|
||||
```
|
||||
|
||||
<a name="faq-statusline"></a>
|
||||
|
||||
### 4.iv. How can I show errors or warnings in my statusline?
|
||||
|
||||
You can use `ALEGetStatusLine()` to integrate ALE into vim statusline.
|
||||
To enable it, you should have in your `statusline` settings
|
||||
@@ -163,8 +275,9 @@ let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
|
||||

|
||||

|
||||
|
||||
<a name="faq-echo-format"></a>
|
||||
|
||||
### Customize echoed message
|
||||
### 4.v. How can I change the format for echo messages?
|
||||
|
||||
There are 3 global options that allow customizing the echoed message.
|
||||
|
||||
@@ -187,58 +300,78 @@ Will give you:
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
<a name="faq-autocmd"></a>
|
||||
|
||||
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
|
||||
Vim differently. On Windows, your `~/.vimrc` file will be similarly
|
||||
stored in `%USERPROFILE%\_vimrc`.
|
||||
### 4.vi. How can I execute some code when ALE stops linting?
|
||||
|
||||
### 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
|
||||
you have the line `execute pathogen#infect()` in your `~/.vimrc` file.
|
||||
You can run the following commands in your terminal to do so:
|
||||
|
||||
```bash
|
||||
cd ~/.vim/bundle
|
||||
git clone https://github.com/w0rp/ale.git
|
||||
```
|
||||
|
||||
### 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.
|
||||
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
|
||||
event whenever has a linter has been successfully executed and processed. This
|
||||
autocmd event can be used to call arbitrary functions after ALE stops linting.
|
||||
|
||||
```vim
|
||||
Plugin 'w0rp/ale'
|
||||
augroup YourGroup
|
||||
autocmd!
|
||||
autocmd User ALELint call YourFunction()
|
||||
augroup END
|
||||
```
|
||||
|
||||
See the Vundle documentation for more information.
|
||||
<a name="faq-navigation"></a>
|
||||
|
||||
### Manual Installation
|
||||
### 4.vii. How can I navigate between errors quickly?
|
||||
|
||||
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.
|
||||
ALE offers some commands with `<Plug>` keybinds for moving between warnings and
|
||||
errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
|
||||
for example:
|
||||
|
||||
```vim
|
||||
set nocompatible
|
||||
filetype off
|
||||
|
||||
let &runtimepath.=',~/.vim/bundle/ale'
|
||||
|
||||
filetype plugin on
|
||||
nmap <silent> <C-k> <Plug>(ale_previous_wrap)
|
||||
nmap <silent> <C-j> <Plug>(ale_next_wrap)
|
||||
```
|
||||
|
||||
Because the author of this plugin is a weird nerd, this is his preferred
|
||||
installation method.
|
||||
For more information, consult the online documentation with
|
||||
`:help ale-navigation-commands`.
|
||||
|
||||
<a name="faq-lint-on-save"></a>
|
||||
|
||||
### 4.viii. How can I run linters only when I save files?
|
||||
|
||||
ALE offers an option `g:ale_lint_on_save` for enabling running the linters
|
||||
when files are saved. If you wish to run linters when files are saved, not
|
||||
as you are editing files, then you can turn the option for linting
|
||||
when text is changed off too.
|
||||
|
||||
```vim
|
||||
" Write this in your vimrc file
|
||||
let g:ale_lint_on_save = 1
|
||||
let g:ale_lint_on_text_changed = 0
|
||||
" You can disable this option too
|
||||
" if you don't want linters to run on opening a file
|
||||
let g:ale_lint_on_enter = 0
|
||||
```
|
||||
|
||||
<a name="faq-quickfix"></a>
|
||||
|
||||
### 4.ix. How can I use the quickfix list instead of the loclist?
|
||||
|
||||
The quickfix list can be enabled by turning the `g:ale_set_quickfix`
|
||||
option on. If you wish to also disable the loclist, you can disable
|
||||
the `g:ale_set_loclist` option.
|
||||
|
||||
```vim
|
||||
" Write this in your vimrc file
|
||||
let g:ale_set_loclist = 0
|
||||
let g:ale_set_quickfix = 1
|
||||
```
|
||||
|
||||
If you wish to show Vim windows for the loclist or quickfix items
|
||||
when a file contains warnings or errors, `g:ale_open_list` can be
|
||||
set to `1`. `g:ale_keep_list_window_open` can be set to `1`
|
||||
if you wish to keep the window open even after errors disappear.
|
||||
|
||||
```vim
|
||||
let g:ale_open_list = 1
|
||||
" Set this if you want to.
|
||||
" This can be useful if you are combining ALE with
|
||||
" some other plugin which sets quickfix errors, etc.
|
||||
let g:ale_keep_list_window_open = 1
|
||||
```
|
||||
|
||||
9
ale_linters/ansible/ansible-lint.vim
Normal file
9
ale_linters/ansible/ansible-lint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Bjorn Neergaard <bjorn@neersighted.com>
|
||||
" Description: ansible-lint for ansible-yaml files
|
||||
|
||||
call ale#linter#Define('ansible', {
|
||||
\ 'name': 'ansible',
|
||||
\ 'executable': 'ansible',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .yml ansible-lint -p',
|
||||
\ 'callback': 'ale#handlers#HandlePEP8Format',
|
||||
\})
|
||||
20
ale_linters/c/clang.vim
Normal file
20
ale_linters/c/clang.vim
Normal file
@@ -0,0 +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#linter#Define('c', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang',
|
||||
\ 'command': 'clang -S -x c -fsyntax-only '
|
||||
\ . g:ale_c_clang_options
|
||||
\ . ' -',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
16
ale_linters/c/cppcheck.vim
Normal file
16
ale_linters/c/cppcheck.vim
Normal file
@@ -0,0 +1,16 @@
|
||||
" Author: Bart Libert <bart.libert@gmail.com>
|
||||
" Description: cppcheck linter for c files
|
||||
|
||||
" Set this option to change the cppcheck options
|
||||
if !exists('g:ale_c_cppcheck_options')
|
||||
let g:ale_c_cppcheck_options = '--enable=style'
|
||||
endif
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'cppcheck',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': 'cppcheck',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .c cppcheck -q --language=c '
|
||||
\ . g:ale_c_cppcheck_options,
|
||||
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
|
||||
\})
|
||||
@@ -1,23 +1,24 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: gcc linter for c files
|
||||
|
||||
if exists('g:loaded_ale_linters_c_gcc')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_c_gcc = 1
|
||||
|
||||
" 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 = '-Wall'
|
||||
" let g:ale_c_gcc_options = '-std=c99 -Wall'
|
||||
" c11 compatible
|
||||
let g:ale_c_gcc_options = '-std=c11 -Wall'
|
||||
endif
|
||||
|
||||
function! ale_linters#c#gcc#GetCommand(buffer) abort
|
||||
return 'gcc -S -x c -fsyntax-only '
|
||||
\ . g:ale_c_gcc_options . ' -'
|
||||
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'gcc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'gcc',
|
||||
\ 'command': 'gcc -S -x c -fsyntax-only '
|
||||
\ . g:ale_c_gcc_options
|
||||
\ . ' -',
|
||||
\ 'command_callback': 'ale_linters#c#gcc#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
41
ale_linters/chef/foodcritic.vim
Normal file
41
ale_linters/chef/foodcritic.vim
Normal file
@@ -0,0 +1,41 @@
|
||||
" Author: Edward Larkey <edwlarkey@mac.com>
|
||||
" Description: This file adds the foodcritic linter for Chef files.
|
||||
|
||||
function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" FC002: Avoid string interpolation where not required: httpd.rb:13
|
||||
let l:pattern = '^\(.\+:\s.\+\):\s\(.\+\):\(\d\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:text = l:match[1]
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('chef', {
|
||||
\ 'name': 'foodcritic',
|
||||
\ 'executable': 'foodcritic',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .rb foodcritic',
|
||||
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: KabbAmine - https://github.com/KabbAmine
|
||||
" Description: Coffee for checking coffee files
|
||||
|
||||
if exists('g:loaded_ale_linters_coffee_coffee')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_coffee_coffee = 1
|
||||
|
||||
call ale#linter#Define('coffee', {
|
||||
\ 'name': 'coffee',
|
||||
\ 'executable': 'coffee',
|
||||
@@ -14,4 +8,3 @@ call ale#linter#Define('coffee', {
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: Prashanth Chandra https://github.com/prashcr
|
||||
" Description: coffeelint linter for coffeescript files
|
||||
|
||||
if exists('g:loaded_ale_linters_coffee_coffeelint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_coffee_coffeelint = 1
|
||||
|
||||
function! ale_linters#coffee#coffeelint#Handle(buffer, lines)
|
||||
function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" path,lineNumber,lineNumberEnd,level,message
|
||||
|
||||
16
ale_linters/cpp/cppcheck.vim
Normal file
16
ale_linters/cpp/cppcheck.vim
Normal file
@@ -0,0 +1,16 @@
|
||||
" Author: Bart Libert <bart.libert@gmail.com>
|
||||
" Description: cppcheck linter for cpp files
|
||||
|
||||
" Set this option to change the cppcheck options
|
||||
if !exists('g:ale_cpp_cppcheck_options')
|
||||
let g:ale_cpp_cppcheck_options = '--enable=style'
|
||||
endif
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'cppcheck',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': 'cppcheck',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .cpp cppcheck -q --language=c++ '
|
||||
\ . g:ale_cpp_cppcheck_options,
|
||||
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
|
||||
\})
|
||||
@@ -1,23 +1,30 @@
|
||||
" Author: geam <mdelage@student.42.fr>
|
||||
" Description: gcc linter for cpp files
|
||||
|
||||
if exists('g:loaded_ale_linters_cpp_gcc')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_cpp_gcc = 1
|
||||
|
||||
" Set this option to change the GCC options for warnings for C.
|
||||
if !exists('g:ale_cpp_gcc_options')
|
||||
let g:ale_cpp_gcc_options = '-Wall'
|
||||
" added c++14 standard support
|
||||
" POSIX thread and standard c++ thread and atomic library Linker
|
||||
" let g:ale_cpp_gcc_options = '-std=c++1z' for c++17
|
||||
" for previous version and default, you can just use
|
||||
" let g:ale_cpp_gcc_options = '-Wall'
|
||||
" for more see man pages of gcc
|
||||
" $ man g++
|
||||
" make sure g++ in your $PATH
|
||||
" Add flags according to your requirements
|
||||
let g:ale_cpp_gcc_options = '-std=c++14 -Wall'
|
||||
endif
|
||||
|
||||
function! ale_linters#cpp#gcc#GetCommand(buffer) abort
|
||||
return 'gcc -S -x c++ -fsyntax-only '
|
||||
\ . g:ale_cpp_gcc_options . ' -'
|
||||
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'gcc',
|
||||
\ 'name': 'g++',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'gcc',
|
||||
\ 'command': 'gcc -S -x c++ -fsyntax-only '
|
||||
\ . g:ale_cpp_gcc_options
|
||||
\ . ' -',
|
||||
\ 'executable': 'g++',
|
||||
\ 'command_callback': 'ale_linters#cpp#gcc#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
40
ale_linters/cs/mcs.vim
Normal file
40
ale_linters/cs/mcs.vim
Normal file
@@ -0,0 +1,40 @@
|
||||
if !exists('g:ale_cs_mcs_options')
|
||||
let g:ale_cs_mcs_options = ''
|
||||
endif
|
||||
|
||||
function! ale_linters#cs#mcs#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" Tests.cs(12,29): error CSXXXX: ; expected
|
||||
let l:pattern = '^.\+.cs(\(\d\+\),\(\d\+\)): \(.\+\): \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3] . ': ' . l:match[4],
|
||||
\ 'type': l:match[3] =~# '^error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cs',{
|
||||
\ 'name': 'mcs',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'mcs',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .cs mcs -unsafe --parse' . g:ale_cs_mcs_options,
|
||||
\ 'callback': 'ale_linters#cs#mcs#Handle',
|
||||
\ })
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file adds support for checking CSS code with csslint.
|
||||
|
||||
if exists('g:loaded_ale_linters_css_csslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_css_csslint = 1
|
||||
|
||||
call ale#linter#Define('css', {
|
||||
\ 'name': 'csslint',
|
||||
\ 'executable': 'csslint',
|
||||
|
||||
31
ale_linters/css/stylelint.vim
Normal file
31
ale_linters/css/stylelint.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Author: diartyz <diartyz@gmail.com>
|
||||
|
||||
let g:ale_css_stylelint_executable =
|
||||
\ get(g:, 'ale_css_stylelint_executable', 'stylelint')
|
||||
|
||||
let g:ale_css_stylelint_use_global =
|
||||
\ get(g:, 'ale_css_stylelint_use_global', 0)
|
||||
|
||||
function! ale_linters#css#stylelint#GetExecutable(buffer) abort
|
||||
if g:ale_css_stylelint_use_global
|
||||
return g:ale_css_stylelint_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/stylelint',
|
||||
\ g:ale_css_stylelint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#css#stylelint#GetCommand(buffer) abort
|
||||
return ale_linters#css#stylelint#GetExecutable(a:buffer)
|
||||
\ . ' --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('css', {
|
||||
\ 'name': 'stylelint',
|
||||
\ 'executable_callback': 'ale_linters#css#stylelint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#css#stylelint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
|
||||
\})
|
||||
@@ -1,37 +1,61 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: "dmd for D files"
|
||||
|
||||
if exists('g:loaded_ale_linters_d_dmd')
|
||||
finish
|
||||
endif
|
||||
function! s:FindDUBConfig(buffer) abort
|
||||
" Find a DUB configuration file in ancestor paths.
|
||||
" The most DUB-specific names will be tried first.
|
||||
for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
|
||||
let l:dub_file = ale#util#FindNearestFile(a:buffer, l:possible_filename)
|
||||
|
||||
let g:loaded_ale_linters_d_dmd = 1
|
||||
|
||||
" A function for finding the dmd-wrapper script in the Vim runtime paths
|
||||
function! s:FindWrapperScript()
|
||||
for l:parent in split(&runtimepath, ',')
|
||||
" Expand the path to deal with ~ issues.
|
||||
let l:path = expand(l:parent . '/' . 'dmd-wrapper')
|
||||
|
||||
if filereadable(l:path)
|
||||
return l:path
|
||||
if !empty(l:dub_file)
|
||||
return l:dub_file
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#d#dmd#GetCommand(buffer)
|
||||
let l:wrapper_script = s:FindWrapperScript()
|
||||
function! ale_linters#d#dmd#DUBCommand(buffer) abort
|
||||
" If we can't run dub, then skip this command.
|
||||
if !executable('dub')
|
||||
" Returning an empty string skips to the DMD command.
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:command = l:wrapper_script . ' -o- -vcolumns -c'
|
||||
let l:dub_file = s:FindDUBConfig(a:buffer)
|
||||
|
||||
return l:command
|
||||
if empty(l:dub_file)
|
||||
return ''
|
||||
endif
|
||||
|
||||
" To support older dub versions, we just change the directory to
|
||||
" the directory where we found the dub config, and then run `dub describe`
|
||||
" from that directory.
|
||||
return 'cd ' . fnameescape(fnamemodify(l:dub_file, ':h'))
|
||||
\ . ' && dub describe --import-paths'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#d#dmd#Handle(buffer, lines)
|
||||
function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort
|
||||
let l:import_list = []
|
||||
|
||||
" Build a list of import paths generated from DUB, if available.
|
||||
for l:line in a:dub_output
|
||||
if !empty(l:line)
|
||||
" The arguments must be '-Ifilename', not '-I filename'
|
||||
call add(l:import_list, '-I' . fnameescape(l:line))
|
||||
endif
|
||||
endfor
|
||||
|
||||
return g:ale#util#stdin_wrapper . ' .d dmd '
|
||||
\ . join(l:import_list)
|
||||
\ . ' -o- -vcolumns -c'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#d#dmd#Handle(buffer, lines) abort
|
||||
" Matches patterns lines like the following:
|
||||
"
|
||||
" /tmp/tmp.qclsa7qLP7/file.d(1): Error: function declaration without return type. (Note that constructors are always named 'this')
|
||||
" /tmp/tmp.G1L5xIizvB.d(8,8): Error: module weak_reference is in file 'dstruct/weak_reference.d' which cannot be read
|
||||
let l:pattern = '^[^(]\+(\([0-9]\+\),\([0-9]\+\)): \([^:]\+\): \(.\+\)'
|
||||
let l:pattern = '^[^(]\+(\([0-9]\+\)\,\?\([0-9]*\)): \([^:]\+\): \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -63,8 +87,10 @@ endfunction
|
||||
|
||||
call ale#linter#Define('d', {
|
||||
\ 'name': 'dmd',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'dmd',
|
||||
\ 'command_callback': 'ale_linters#d#dmd#GetCommand',
|
||||
\ 'command_chain': [
|
||||
\ {'callback': 'ale_linters#d#dmd#DUBCommand', 'output_stream': 'stdout'},
|
||||
\ {'callback': 'ale_linters#d#dmd#DMDCommand', 'output_stream': 'stderr'},
|
||||
\ ],
|
||||
\ 'callback': 'ale_linters#d#dmd#Handle',
|
||||
\})
|
||||
|
||||
45
ale_linters/dockerfile/hadolint.vim
Normal file
45
ale_linters/dockerfile/hadolint.vim
Normal file
@@ -0,0 +1,45 @@
|
||||
" Author: hauleth - https://github.com/hauleth
|
||||
|
||||
function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" stdin:19: F: Pipe chain should start with a raw value.
|
||||
let l:pattern = '\v^/dev/stdin:?(\d+)? (\S+) (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:lnum = 0
|
||||
|
||||
if l:match[1] !=# ''
|
||||
let l:lnum = l:match[1] + 0
|
||||
endif
|
||||
|
||||
let l:type = 'W'
|
||||
let l:text = l:match[3]
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:lnum,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:text,
|
||||
\ 'nr': l:match[2],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('dockerfile', {
|
||||
\ 'name': 'hadolint',
|
||||
\ 'executable': 'hadolint',
|
||||
\ 'command': 'hadolint -',
|
||||
\ 'callback': 'ale_linters#dockerfile#hadolint#Handle' })
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: hauleth - https://github.com/haulethe
|
||||
" Author: hauleth - https://github.com/hauleth
|
||||
|
||||
if exists('g:loaded_ale_linters_elixir_credo')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_elixir_credo = 1
|
||||
|
||||
function! ale_linters#elixir#credo#Handle(buffer, lines)
|
||||
function! ale_linters#elixir#credo#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" stdin:19: F: Pipe chain should start with a raw value.
|
||||
|
||||
67
ale_linters/elm/make.vim
Normal file
67
ale_linters/elm/make.vim
Normal file
@@ -0,0 +1,67 @@
|
||||
" Author: buffalocoder - https://github.com/buffalocoder
|
||||
" Description: Elm linting in Ale. Closely follows the Syntastic checker in https://github.com/ElmCast/elm-vim.
|
||||
|
||||
function! ale_linters#elm#make#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
let l:is_windows = has('win32')
|
||||
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
|
||||
for l:line in a:lines
|
||||
if l:line[0] ==# '['
|
||||
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
|
||||
else
|
||||
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==# l:temp_dir
|
||||
endif
|
||||
|
||||
if l:file_is_buffer
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:error.region.start.line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:error.region.start.column,
|
||||
\ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
|
||||
\ 'text': l:error.overview,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
" Return the command to execute the linter in the projects directory.
|
||||
" If it doesn't, then this will fail when imports are needed.
|
||||
function! ale_linters#elm#make#GetCommand(buffer) abort
|
||||
let l:elm_package = ale#util#FindNearestFile(a:buffer, 'elm-package.json')
|
||||
if empty(l:elm_package)
|
||||
let l:dir_set_cmd = ''
|
||||
else
|
||||
let l:root_dir = fnamemodify(l:elm_package, ':p:h')
|
||||
let l:dir_set_cmd = 'cd ' . fnameescape(l:root_dir) . ' && '
|
||||
endif
|
||||
|
||||
" The elm-make compiler, at the time of this writing, uses '/dev/null' as
|
||||
" a sort of flag to tell the compiler not to generate an output file,
|
||||
" which is why this is hard coded here.
|
||||
" Source: https://github.com/elm-lang/elm-make/blob/master/src/Flags.hs
|
||||
let l:elm_cmd = 'elm-make --report=json --output='.shellescape('/dev/null')
|
||||
let l:stdin_wrapper = g:ale#util#stdin_wrapper . ' .elm'
|
||||
|
||||
return l:dir_set_cmd . ' ' . l:stdin_wrapper . ' ' . l:elm_cmd
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('elm', {
|
||||
\ 'name': 'make',
|
||||
\ 'executable': 'elm-make',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'command_callback': 'ale_linters#elm#make#GetCommand',
|
||||
\ 'callback': 'ale_linters#elm#make#Handle'
|
||||
\})
|
||||
|
||||
96
ale_linters/erlang/erlc.vim
Normal file
96
ale_linters/erlang/erlc.vim
Normal file
@@ -0,0 +1,96 @@
|
||||
" Author: Magnus Ottenklinger - https://github.com/evnu
|
||||
|
||||
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
|
||||
|
||||
function! ale_linters#erlang#erlc#GetCommand(buffer) abort
|
||||
return g:ale#util#stdin_wrapper . ' .erl erlc ' . g:ale_erlang_erlc_options
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" error.erl:4: variable 'B' is unbound
|
||||
" error.erl:3: Warning: function main/0 is unused
|
||||
" error.erl:4: Warning: variable 'A' is unused
|
||||
let l:pattern = '\v^([^:]+):(\d+): (Warning: )?(.+)$'
|
||||
|
||||
" parse_transforms are a special case. The error message does not indicate a location:
|
||||
" error.erl: undefined parse transform 'some_parse_transform'
|
||||
let l:pattern_parse_transform = '\v(undefined parse transform .*)$'
|
||||
let l:output = []
|
||||
|
||||
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'
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
" Determine if the output indicates an error. We distinguish between two cases:
|
||||
"
|
||||
" 1) normal errors match l:pattern
|
||||
" 2) parse_transform errors match l:pattern_parse_transform
|
||||
"
|
||||
" If none of the patterns above match, the line can be ignored
|
||||
if len(l:match) == 0 " not a 'normal' warning or error
|
||||
let l:match_parse_transform = matchlist(l:line, l:pattern_parse_transform)
|
||||
|
||||
if len(l:match_parse_transform) == 0 " also not a parse_transform error
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': 'E',
|
||||
\ 'text': l:match_parse_transform[0],
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:line = l:match[2]
|
||||
let l:warning_or_text = l:match[3]
|
||||
let l:text = l:match[4]
|
||||
|
||||
" If this file is a header .hrl, ignore the following expected messages:
|
||||
" - 'no module definition'
|
||||
" - 'X is unused'
|
||||
if l:is_hrl && (
|
||||
\ match(l:text, l:pattern_no_module_definition) != -1
|
||||
\ || match(l:text, l:pattern_unused) != -1
|
||||
\)
|
||||
continue
|
||||
endif
|
||||
|
||||
if !empty(l:warning_or_text)
|
||||
let l:type = 'W'
|
||||
else
|
||||
let l:type = 'E'
|
||||
endif
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:text,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('erlang', {
|
||||
\ 'name': 'erlc',
|
||||
\ 'executable': 'erlc',
|
||||
\ 'command_callback': 'ale_linters#erlang#erlc#GetCommand',
|
||||
\ 'callback': 'ale_linters#erlang#erlc#Handle',
|
||||
\})
|
||||
@@ -1,24 +1,18 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: gcc for Fortran files
|
||||
|
||||
if exists('g:loaded_ale_linters_fortran_gcc')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_fortran_gcc = 1
|
||||
|
||||
" Set this option to change the GCC options for warnings for Fortran.
|
||||
if !exists('g:ale_fortran_gcc_options')
|
||||
let g:ale_fortran_gcc_options = '-Wall'
|
||||
endif
|
||||
|
||||
function! ale_linters#fortran#gcc#Handle(buffer, lines)
|
||||
function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
|
||||
" We have to match a starting line and a later ending line together,
|
||||
" like so.
|
||||
"
|
||||
" :21.34:
|
||||
" Error: Expected comma in I/O list at (1)
|
||||
let l:line_marker_pattern = '^:\(\d\+\)\.\(\d\+\):$'
|
||||
let l:line_marker_pattern = ':\(\d\+\)[.:]\=\(\d\+\)\=:\=$'
|
||||
let l:message_pattern = '^\(Error\|Warning\): \(.\+\)$'
|
||||
let l:looking_for_message = 0
|
||||
let l:last_loclist_obj = {}
|
||||
|
||||
214
ale_linters/go/gobuild.vim
Normal file
214
ale_linters/go/gobuild.vim
Normal file
@@ -0,0 +1,214 @@
|
||||
" Author: Joshua Rubin <joshua@rubixconsulting.com>
|
||||
" Description: go build for Go files
|
||||
|
||||
" inspired by work from dzhou121 <dzhou121@gmail.com>
|
||||
|
||||
function! ale_linters#go#gobuild#GoEnv(buffer) abort
|
||||
if exists('s:go_env')
|
||||
return ''
|
||||
endif
|
||||
|
||||
return 'go env GOPATH GOROOT'
|
||||
endfunction
|
||||
|
||||
let s:SplitChar = has('unix') ? ':' : ':'
|
||||
|
||||
" get a list of all source directories from $GOPATH and $GOROOT
|
||||
function! s:SrcDirs() abort
|
||||
let l:paths = split(s:go_env.GOPATH, s:SplitChar)
|
||||
call add(l:paths, s:go_env.GOROOT)
|
||||
|
||||
return l:paths
|
||||
endfunction
|
||||
|
||||
" figure out from a directory like `/home/user/go/src/some/package` that the
|
||||
" import for that path is simply `some/package`
|
||||
function! s:PackageImportPath(buffer) abort
|
||||
let l:bufname = resolve(bufname(a:buffer))
|
||||
let l:pkgdir = fnamemodify(l:bufname, ':p:h')
|
||||
|
||||
for l:path in s:SrcDirs()
|
||||
let l:path = l:path . '/src/'
|
||||
|
||||
if stridx(l:pkgdir, l:path) == 0
|
||||
return l:pkgdir[strlen(l:path):]
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" get the package info data structure using `go list`
|
||||
function! ale_linters#go#gobuild#GoList(buffer, goenv_output) abort
|
||||
if !empty(a:goenv_output)
|
||||
let s:go_env = {
|
||||
\ 'GOPATH': a:goenv_output[0],
|
||||
\ 'GOROOT': a:goenv_output[1],
|
||||
\}
|
||||
endif
|
||||
|
||||
return 'go list -json ' . shellescape(s:PackageImportPath(a:buffer))
|
||||
endfunction
|
||||
|
||||
let s:filekeys = [
|
||||
\ 'GoFiles',
|
||||
\ 'CgoFiles',
|
||||
\ 'CFiles',
|
||||
\ 'CXXFiles',
|
||||
\ 'MFiles',
|
||||
\ 'HFiles',
|
||||
\ 'FFiles',
|
||||
\ 'SFiles',
|
||||
\ 'SwigFiles',
|
||||
\ 'SwigCXXFiles',
|
||||
\ 'SysoFiles',
|
||||
\ 'TestGoFiles',
|
||||
\ 'XTestGoFiles',
|
||||
\]
|
||||
|
||||
" get the go and test go files from the package
|
||||
" will return empty list if the package has any cgo or other invalid files
|
||||
function! s:PkgFiles(pkginfo) abort
|
||||
let l:files = []
|
||||
|
||||
for l:key in s:filekeys
|
||||
if has_key(a:pkginfo, l:key)
|
||||
call extend(l:files, a:pkginfo[l:key])
|
||||
endif
|
||||
endfor
|
||||
|
||||
" resolve the path of the file relative to the window directory
|
||||
return map(l:files, 'shellescape(fnamemodify(resolve(a:pkginfo.Dir . ''/'' . v:val), '':p''))')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gobuild#CopyFiles(buffer, golist_output) abort
|
||||
let l:tempdir = tempname()
|
||||
let l:temppkgdir = l:tempdir . '/src/' . s:PackageImportPath(a:buffer)
|
||||
call mkdir(l:temppkgdir, 'p', 0700)
|
||||
|
||||
if empty(a:golist_output)
|
||||
return 'echo ' . shellescape(l:tempdir)
|
||||
endif
|
||||
|
||||
" parse the output
|
||||
let l:pkginfo = json_decode(join(a:golist_output, "\n"))
|
||||
|
||||
" get all files for the package
|
||||
let l:files = s:PkgFiles(l:pkginfo)
|
||||
|
||||
" copy the files to a temp directory with $GOPATH structure
|
||||
return 'cp ' . join(l:files, ' ') . ' ' . shellescape(l:temppkgdir) . ' && echo ' . shellescape(l:tempdir)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gobuild#GetCommand(buffer, copy_output) abort
|
||||
let l:tempdir = a:copy_output[0]
|
||||
let l:importpath = s:PackageImportPath(a:buffer)
|
||||
|
||||
" write the a:buffer and any modified buffers from the package to the tempdir
|
||||
for l:bufnum in range(1, bufnr('$'))
|
||||
" ignore unloaded buffers (can't be a:buffer or a modified buffer)
|
||||
if !bufloaded(l:bufnum)
|
||||
continue
|
||||
endif
|
||||
|
||||
" ignore non-Go buffers
|
||||
if getbufvar(l:bufnum, '&ft') !=# 'go'
|
||||
continue
|
||||
endif
|
||||
|
||||
" only consider buffers other than a:buffer if they have the same import
|
||||
" path as a:buffer and are modified
|
||||
if l:bufnum != a:buffer
|
||||
if s:PackageImportPath(l:bufnum) !=# l:importpath
|
||||
continue
|
||||
endif
|
||||
|
||||
if !getbufvar(l:bufnum, '&mod')
|
||||
continue
|
||||
endif
|
||||
endif
|
||||
|
||||
call writefile(getbufline(l:bufnum, 1, '$'), l:tempdir . '/src/' . s:PkgFile(l:bufnum))
|
||||
endfor
|
||||
|
||||
let l:gopaths = [ l:tempdir ]
|
||||
call extend(l:gopaths, split(s:go_env.GOPATH, s:SplitChar))
|
||||
|
||||
return 'GOPATH=' . shellescape(join(l:gopaths, s:SplitChar)) . ' go test -c -o /dev/null ' . shellescape(l:importpath)
|
||||
endfunction
|
||||
|
||||
function! s:PkgFile(buffer) abort
|
||||
let l:bufname = resolve(bufname(a:buffer))
|
||||
let l:importpath = s:PackageImportPath(a:buffer)
|
||||
let l:fname = fnamemodify(l:bufname, ':t')
|
||||
|
||||
return l:importpath . '/' . l:fname
|
||||
endfunction
|
||||
|
||||
function! s:FindBuffer(file) abort
|
||||
for l:buffer in range(1, bufnr('$'))
|
||||
if !buflisted(l:buffer)
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:pkgfile = s:PkgFile(l:buffer)
|
||||
|
||||
if a:file =~ '/' . l:pkgfile . '$'
|
||||
return l:buffer
|
||||
endif
|
||||
endfor
|
||||
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
|
||||
let s:handler_pattern = '^\(' . s:path_pattern . '\):\(\d\+\):\?\(\d\+\)\?: \(.\+\)$'
|
||||
|
||||
let s:multibuffer = 0
|
||||
|
||||
function! ale_linters#go#gobuild#Handler(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, s:handler_pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:buffer = s:FindBuffer(l:match[1])
|
||||
|
||||
if l:buffer == -1
|
||||
continue
|
||||
endif
|
||||
|
||||
if !s:multibuffer && l:buffer != a:buffer
|
||||
" strip lines from other buffers
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': l:buffer,
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'go build',
|
||||
\ 'executable': 'go',
|
||||
\ 'command_chain': [
|
||||
\ {'callback': 'ale_linters#go#gobuild#GoEnv', 'output_stream': 'stdout'},
|
||||
\ {'callback': 'ale_linters#go#gobuild#GoList', 'output_stream': 'stdout'},
|
||||
\ {'callback': 'ale_linters#go#gobuild#CopyFiles', 'output_stream': 'stdout'},
|
||||
\ {'callback': 'ale_linters#go#gobuild#GetCommand', 'output_stream': 'stderr'},
|
||||
\ ],
|
||||
\ 'callback': 'ale_linters#go#gobuild#Handler',
|
||||
\})
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: neersighted <bjorn@neersighted.com>
|
||||
" Description: gofmt for Go files
|
||||
|
||||
if exists('g:loaded_ale_linters_go_gofmt')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_go_gofmt = 1
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'gofmt',
|
||||
\ 'output_stream': 'stderr',
|
||||
@@ -14,4 +8,3 @@ call ale#linter#Define('go', {
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .go gofmt -e',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: neersighted <bjorn@neersighted.com>
|
||||
" Description: golint for Go files
|
||||
|
||||
if exists('g:loaded_ale_linters_go_golint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_go_golint = 1
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'golint',
|
||||
\ 'executable': 'golint',
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: neersighted <bjorn@neersighted.com>
|
||||
" Description: go vet for Go files
|
||||
|
||||
if exists('g:loaded_ale_linters_go_govet')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_go_govet = 1
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'go vet',
|
||||
\ 'output_stream': 'stderr',
|
||||
@@ -14,4 +8,3 @@ call ale#linter#Define('go', {
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .go go vet',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
|
||||
@@ -7,12 +7,61 @@ endif
|
||||
|
||||
let g:loaded_ale_linters_haskell_ghc = 1
|
||||
|
||||
function! ale_linters#haskell#ghc#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" /dev/stdin:28:26: Not in scope: `>>>>>'
|
||||
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
" For some reason the output coming out of the GHC through the wrapper
|
||||
" script breaks the lines up in strange ways. So we have to join some
|
||||
" lines back together again.
|
||||
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)
|
||||
if l:line !~# ': error:$'
|
||||
call add(l:corrected_lines, '')
|
||||
endif
|
||||
elseif l:line ==# ''
|
||||
call add(l:corrected_lines, l:line)
|
||||
else
|
||||
if len(l:corrected_lines) > 0
|
||||
let l:line = substitute(l:line, '\v\s+', ' ', '')
|
||||
let l:corrected_lines[-1] .= l:line
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
for l:line in l:corrected_lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'ghc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'ghc',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .hs ghc -fno-code -v0',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\ 'callback': 'ale_linters#haskell#ghc#Handle',
|
||||
\})
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
@@ -20,5 +69,5 @@ call ale#linter#Define('haskell', {
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .hs stack ghc -- -fno-code -v0',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\ 'callback': 'ale_linters#haskell#ghc#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: jparoz <jesse.paroz@gmail.com>
|
||||
" Description: hlint for Haskell files
|
||||
|
||||
if exists('g:loaded_ale_linters_haskell_hlint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_haskell_hlint = 1
|
||||
|
||||
function! ale_linters#haskell#hlint#Handle(buffer, lines)
|
||||
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
|
||||
let l:errors = json_decode(join(a:lines, ''))
|
||||
|
||||
let l:output = []
|
||||
@@ -19,7 +13,7 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines)
|
||||
\ 'lnum': l:error.startLine + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:error.startColumn + 0,
|
||||
\ 'text': l:error.severity . ': ' . l:error.hint,
|
||||
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
|
||||
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -1,15 +1,36 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>, deathmaz <00maz1987@gmail.com>, diartyz <diartyz@gmail.com>
|
||||
" Description: HTMLHint for checking html files
|
||||
|
||||
if exists('g:loaded_ale_linters_html_htmlhint')
|
||||
finish
|
||||
endif
|
||||
" CLI options
|
||||
let g:ale_html_htmlhint_options = get(g:, 'ale_html_htmlhint_options', '--format=unix')
|
||||
|
||||
let g:loaded_ale_linters_html_htmlhint = 1
|
||||
let g:ale_html_htmlhint_executable =
|
||||
\ get(g:, 'ale_html_htmlhint_executable', 'htmlhint')
|
||||
|
||||
let g:ale_html_htmlhint_use_global =
|
||||
\ get(g:, 'ale_html_htmlhint_use_global', 0)
|
||||
|
||||
function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
|
||||
if g:ale_html_htmlhint_use_global
|
||||
return g:ale_html_htmlhint_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/htmlhint',
|
||||
\ g:ale_html_htmlhint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#html#htmlhint#GetCommand(buffer) abort
|
||||
return g:ale#util#stdin_wrapper . ' .html '
|
||||
\ . ale_linters#html#htmlhint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_html_htmlhint_options
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('html', {
|
||||
\ 'name': 'htmlhint',
|
||||
\ 'executable': 'htmlhint',
|
||||
\ 'command': 'htmlhint --format=unix stdin',
|
||||
\ 'executable_callback': 'ale_linters#html#htmlhint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#html#htmlhint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
" Description: This file adds support for checking HTML code with tidy.
|
||||
|
||||
if exists('g:loaded_ale_linters_html_tidy')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_html_tidy = 1
|
||||
|
||||
" CLI options
|
||||
let g:ale_html_tidy_executable = get(g:, 'ale_html_tidy_executable', 'tidy')
|
||||
let g:ale_html_tidy_args = get(g:, 'ale_html_tidy_args', '-q -e -language en')
|
||||
|
||||
@@ -1,37 +1,64 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: eslint for JavaScript files
|
||||
|
||||
if exists('g:loaded_ale_linters_javascript_eslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_javascript_eslint = 1
|
||||
|
||||
let g:ale_javascript_eslint_executable =
|
||||
\ get(g:, 'ale_javascript_eslint_executable', 'eslint')
|
||||
|
||||
function! ale_linters#javascript#eslint#Handle(buffer, lines)
|
||||
let g:ale_javascript_eslint_options =
|
||||
\ get(g:, 'ale_javascript_eslint_options', '')
|
||||
|
||||
let g:ale_javascript_eslint_use_global =
|
||||
\ get(g:, 'ale_javascript_eslint_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#eslint#GetExecutable(buffer) abort
|
||||
if g:ale_javascript_eslint_use_global
|
||||
return g:ale_javascript_eslint_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/eslint',
|
||||
\ g:ale_javascript_eslint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#eslint#GetCommand(buffer) abort
|
||||
return ale_linters#javascript#eslint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_javascript_eslint_options
|
||||
\ . ' -f unix --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
|
||||
" /path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]
|
||||
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$'
|
||||
" This second pattern matches lines like the following:
|
||||
"
|
||||
" /path/to/some-filename.js:13:3: Parsing error: Unexpected token
|
||||
let l:parsing_pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
" Try the parsing pattern for parsing errors.
|
||||
let l:match = matchlist(l:line, l:parsing_pattern)
|
||||
endif
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:type = 'Error'
|
||||
let l:text = l:match[3]
|
||||
let l:marker = l:match[4]
|
||||
let l:marker_parts = split(l:marker, '/')
|
||||
let l:type = l:marker_parts[0]
|
||||
|
||||
if len(l:marker_parts) == 2
|
||||
let l:text = l:text . ' (' . l:marker_parts[1] . ')'
|
||||
" Take the error type from the output if available.
|
||||
if !empty(l:match[4])
|
||||
let l:type = split(l:match[4], '/')[0]
|
||||
let l:text .= ' [' . l:match[4] . ']'
|
||||
endif
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
@@ -51,7 +78,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'eslint',
|
||||
\ 'executable': g:ale_javascript_eslint_executable,
|
||||
\ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s',
|
||||
\ 'executable_callback': 'ale_linters#javascript#eslint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#eslint#GetCommand',
|
||||
\ 'callback': 'ale_linters#javascript#eslint#Handle',
|
||||
\})
|
||||
|
||||
80
ale_linters/javascript/flow.vim
Normal file
80
ale_linters/javascript/flow.vim
Normal file
@@ -0,0 +1,80 @@
|
||||
" Author: Zach Perrault -- @zperrault
|
||||
" Description: FlowType checking for JavaScript files
|
||||
|
||||
let g:ale_javascript_flow_executable =
|
||||
\ get(g:, 'ale_javascript_flow_executable', 'flow')
|
||||
|
||||
let g:ale_javascript_flow_use_global =
|
||||
\ get(g:, 'ale_javascript_flow_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#flow#GetExecutable(buffer) abort
|
||||
if g:ale_javascript_flow_use_global
|
||||
return g:ale_javascript_flow_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/flow',
|
||||
\ g:ale_javascript_flow_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#flow#GetCommand(buffer) abort
|
||||
return ale_linters#javascript#flow#GetExecutable(a:buffer)
|
||||
\ . ' check-contents --respect-pragma --json --from ale %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#flow#Handle(buffer, lines) abort
|
||||
let l:str = join(a:lines, '')
|
||||
if l:str ==# ''
|
||||
return []
|
||||
endif
|
||||
let l:flow_output = json_decode(l:str)
|
||||
|
||||
if has_key(l:flow_output, 'errors')
|
||||
let l:output = []
|
||||
|
||||
for l:error in l:flow_output.errors
|
||||
" Each error is broken up into parts
|
||||
let l:text = ''
|
||||
let l:line = 0
|
||||
let l:col = 0
|
||||
for l:message in l:error.message
|
||||
" Comments have no line of column information
|
||||
if has_key(l:message, 'loc') && l:line ==# 0
|
||||
let l:line = l:message.loc.start.line + 0
|
||||
let l:col = l:message.loc.start.column + 0
|
||||
endif
|
||||
if l:text ==# ''
|
||||
let l:text = l:message.descr . ':'
|
||||
else
|
||||
let l:text = l:text . ' ' . l:message.descr
|
||||
endif
|
||||
endfor
|
||||
|
||||
if has_key(l:error, 'operation')
|
||||
let l:text = l:text . ' See also: ' . l:error.operation.descr
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:error.level ==# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
else
|
||||
return []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'flow',
|
||||
\ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#flow#GetCommand',
|
||||
\ 'callback': 'ale_linters#javascript#flow#Handle',
|
||||
\})
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: Chris Kyrouac - https://github.com/fijshion
|
||||
" Description: jscs for JavaScript files
|
||||
|
||||
if exists('g:loaded_ale_linters_javascript_jscs')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_javascript_jscs = 1
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'jscs',
|
||||
\ 'executable': 'jscs',
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
" Author: Chris Kyrouac - https://github.com/fijshion
|
||||
" Description: JSHint for Javascript files
|
||||
|
||||
if exists('g:loaded_ale_linters_javascript_jshint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_javascript_jshint = 1
|
||||
|
||||
let g:ale_javascript_jshint_executable =
|
||||
\ get(g:, 'ale_javascript_jshint_executable', 'jshint')
|
||||
|
||||
function! ale_linters#javascript#jshint#GetCommand(buffer)
|
||||
" Set this to the location of the jshint configuration file to
|
||||
" use a fixed location for .jshintrc
|
||||
if exists('g:ale_jshint_config_loc')
|
||||
let l:jshint_config = g:ale_jshint_config_loc
|
||||
else
|
||||
" Look for the JSHint config in parent directories.
|
||||
let l:jshint_config = ale#util#FindNearestFile(a:buffer, '.jshintrc')
|
||||
let g:ale_javascript_jshint_use_global =
|
||||
\ get(g:, 'ale_javascript_jshint_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#jshint#GetExecutable(buffer) abort
|
||||
if g:ale_javascript_jshint_use_global
|
||||
return g:ale_javascript_jshint_executable
|
||||
endif
|
||||
|
||||
let l:command = g:ale_javascript_jshint_executable . ' --reporter unix'
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/jshint',
|
||||
\ g:ale_javascript_jshint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#jshint#GetCommand(buffer) abort
|
||||
" Search for a local JShint config locaation, and default to a global one.
|
||||
let l:jshint_config = ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ '.jshintrc',
|
||||
\ get(g:, 'ale_jshint_config_loc', '')
|
||||
\)
|
||||
|
||||
let l:command = ale_linters#javascript#jshint#GetExecutable(a:buffer)
|
||||
let l:command .= ' --reporter unix'
|
||||
|
||||
if !empty(l:jshint_config)
|
||||
let l:command .= ' --config ' . fnameescape(l:jshint_config)
|
||||
@@ -33,7 +41,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'jshint',
|
||||
\ 'executable': g:ale_javascript_jshint_executable,
|
||||
\ 'executable_callback': 'ale_linters#javascript#jshint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
|
||||
if exists('g:loaded_ale_linters_json_jsonlint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_json_jsonlint = 1
|
||||
|
||||
function! ale_linters#json#jsonlint#Handle(buffer, lines)
|
||||
function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" line 2, col 15, found: 'STRING' - expected: 'EOF', '}', ',', ']'.
|
||||
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
" Author: Sol Bekic https://github.com/s-ol
|
||||
" Description: luacheck linter for lua files
|
||||
|
||||
if exists('g:loaded_ale_linters_lua_luacheck')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_lua_luacheck = 1
|
||||
|
||||
let g:ale_lua_luacheck_executable =
|
||||
\ get(g:, 'ale_lua_luacheck_executable', 'luacheck')
|
||||
|
||||
function! ale_linters#lua#luacheck#Handle(buffer, lines)
|
||||
function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106
|
||||
|
||||
35
ale_linters/markdown/mdl.vim
Normal file
35
ale_linters/markdown/mdl.vim
Normal file
@@ -0,0 +1,35 @@
|
||||
" Author: Steve Dignam <steve@dignam.xyz>
|
||||
" Description: Support for mdl, a markdown linter
|
||||
|
||||
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
|
||||
" matches: '(stdin):173: MD004 Unordered list style'
|
||||
let l:pattern = ':\(\d*\): \(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:match[2],
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('markdown', {
|
||||
\ 'name': 'mdl',
|
||||
\ 'executable': 'mdl',
|
||||
\ 'command': 'mdl',
|
||||
\ 'callback': 'ale_linters#markdown#mdl#Handle'
|
||||
\})
|
||||
9
ale_linters/markdown/proselint.vim
Normal file
9
ale_linters/markdown/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: poohzrn https://github.com/poohzrn
|
||||
" Description: proselint for markdown files
|
||||
|
||||
call ale#linter#Define('markdown', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .md proselint',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
55
ale_linters/matlab/mlint.vim
Normal file
55
ale_linters/matlab/mlint.vim
Normal file
@@ -0,0 +1,55 @@
|
||||
" Author: awlayton <alex@layton.in>
|
||||
" Description: mlint for MATLAB files
|
||||
|
||||
let g:ale_matlab_mlint_executable =
|
||||
\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
|
||||
|
||||
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" L 27 (C 1): FNDEF: Terminate statement with semicolon to suppress output.
|
||||
" L 30 (C 13-15): FNDEF: A quoted string is unterminated.
|
||||
let l:pattern = '^L \(\d\+\) (C \([0-9-]\+\)): \([A-Z]\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:lnum = l:match[1] + 0
|
||||
let l:col = l:match[2] + 0
|
||||
let l:code = l:match[3]
|
||||
let l:text = l:match[4]
|
||||
|
||||
" Suppress erroneous waring about filename
|
||||
" TODO: Enable this error when copying filename is supported
|
||||
if l:code ==# 'FNDEF'
|
||||
continue
|
||||
endif
|
||||
|
||||
" vcol is needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:lnum,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('matlab', {
|
||||
\ 'name': 'mlint',
|
||||
\ 'executable': 'mlint',
|
||||
\ 'command': g:ale#util#stdin_wrapper .
|
||||
\ ' .m ' . g:ale_matlab_mlint_executable . ' -id',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'callback': 'ale_linters#matlab#mlint#Handle',
|
||||
\})
|
||||
19
ale_linters/ocaml/merlin.vim
Normal file
19
ale_linters/ocaml/merlin.vim
Normal file
@@ -0,0 +1,19 @@
|
||||
" Author: Andrey Popp -- @andreypopp
|
||||
" Description: Report errors in OCaml code with Merlin
|
||||
|
||||
if !exists('g:merlin')
|
||||
finish
|
||||
endif
|
||||
|
||||
function! ale_linters#ocaml#merlin#Handle(buffer, lines) abort
|
||||
let l:errors = merlin#ErrorLocList()
|
||||
return l:errors
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ocaml', {
|
||||
\ 'name': 'merlin',
|
||||
\ 'executable': 'ocamlmerlin',
|
||||
\ 'command': 'true',
|
||||
\ 'callback': 'ale_linters#ocaml#merlin#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
" Author: Vincent Lequertier <https://github.com/SkySymbol>
|
||||
" Description: This file adds support for checking perl syntax
|
||||
|
||||
if exists('g:loaded_ale_linters_perl_perlcritic')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_perl_perl = 1
|
||||
function! ale_linters#perl#perl#Handle(buffer, lines)
|
||||
function! ale_linters#perl#perl#Handle(buffer, lines) abort
|
||||
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
|
||||
let l:output = []
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
" Author: Vincent Lequertier <https://github.com/SkySymbol>
|
||||
" Description: This file adds support for checking perl with perl critic
|
||||
|
||||
if exists('g:loaded_ale_linters_perl_perlcritic')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_perl_perlcritic = 1
|
||||
function! ale_linters#perl#perlcritic#Handle(buffer, lines)
|
||||
function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort
|
||||
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
|
||||
let l:output = []
|
||||
|
||||
@@ -40,7 +35,7 @@ endfunction
|
||||
call ale#linter#Define('perl', {
|
||||
\ 'name': 'perlcritic',
|
||||
\ 'executable': 'perlcritic',
|
||||
\ 'output_stream': 'sdtout',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'command': 'perlcritic --verbose 3 --nocolor',
|
||||
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
|
||||
\})
|
||||
|
||||
37
ale_linters/php/hack.vim
Normal file
37
ale_linters/php/hack.vim
Normal file
@@ -0,0 +1,37 @@
|
||||
" Author: Zefei Xuan <https://github.com/zefei>
|
||||
" Description: Hack type checking (http://hacklang.org/)
|
||||
|
||||
function! ale_linters#php#hack#Handle(buffer, lines) abort
|
||||
let l:pattern = '^\(.*\):\(\d\+\):\(\d\+\),\(\d\+\): \(.\+])\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
if a:buffer != bufnr(l:match[1])
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:match[5],
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'hack',
|
||||
\ 'executable': 'hh_client',
|
||||
\ 'command': 'hh_client --retries 0 --retry-if-init false',
|
||||
\ 'callback': 'ale_linters#php#hack#Handle',
|
||||
\})
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: Spencer Wood <https://github.com/scwood>
|
||||
" Description: This file adds support for checking PHP with php-cli
|
||||
|
||||
if exists('g:loaded_ale_linters_php_php')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_php_php = 1
|
||||
|
||||
function! ale_linters#php#php#Handle(buffer, lines)
|
||||
function! ale_linters#php#php#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" Parse error: parse error in - on line 7
|
||||
@@ -40,6 +34,6 @@ call ale#linter#Define('php', {
|
||||
\ 'name': 'php',
|
||||
\ 'executable': 'php',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'command': 'php -l --',
|
||||
\ 'command': 'php -l -d display_errors=1 --',
|
||||
\ 'callback': 'ale_linters#php#php#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: jwilliams108 <https://github.com/jwilliams108>
|
||||
" Description: phpcs for PHP files
|
||||
|
||||
if exists('g:loaded_ale_linters_php_phpcs')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_php_phpcs = 1
|
||||
|
||||
function! ale_linters#php#phpcs#GetCommand(buffer)
|
||||
function! ale_linters#php#phpcs#GetCommand(buffer) abort
|
||||
let l:command = 'phpcs -s --report=emacs --stdin-path=%s'
|
||||
|
||||
" This option can be set to change the standard used by phpcs
|
||||
@@ -18,7 +12,7 @@ function! ale_linters#php#phpcs#GetCommand(buffer)
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#phpcs#Handle(buffer, lines)
|
||||
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
" Matches against lines like the following:
|
||||
"
|
||||
" /path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: w0rp - <devw0rp@gmail.com>
|
||||
" Description: pug-lint for checking Pug/Jade files.
|
||||
|
||||
if exists('g:loaded_ale_linters_pug_puglint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_pug_puglint = 1
|
||||
|
||||
call ale#linter#Define('pug', {
|
||||
\ 'name': 'puglint',
|
||||
\ 'executable': 'pug-lint',
|
||||
|
||||
38
ale_linters/puppet/puppet.vim
Normal file
38
ale_linters/puppet/puppet.vim
Normal file
@@ -0,0 +1,38 @@
|
||||
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
|
||||
|
||||
function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
|
||||
|
||||
let l:pattern = '^Error: .*: \(.\+\) at .\+:\(\d\+\):\(\d\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
" vcol is needed to indicate that the column is a character
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'text': l:match[1],
|
||||
\ 'type': 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('puppet', {
|
||||
\ 'name': 'puppet',
|
||||
\ 'executable': 'puppet',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet parser validate --color=false',
|
||||
\ 'callback': 'ale_linters#puppet#puppet#Handle',
|
||||
\})
|
||||
8
ale_linters/puppet/puppetlint.vim
Normal file
8
ale_linters/puppet/puppetlint.vim
Normal file
@@ -0,0 +1,8 @@
|
||||
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
|
||||
|
||||
call ale#linter#Define('puppet', {
|
||||
\ 'name': 'puppetlint',
|
||||
\ 'executable': 'puppet-lint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet-lint --no-autoloader_layout-check --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
@@ -1,55 +1,76 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: flake8 for python files
|
||||
|
||||
if exists('g:loaded_ale_linters_python_flake8')
|
||||
finish
|
||||
endif
|
||||
let g:ale_python_flake8_executable =
|
||||
\ get(g:, 'ale_python_flake8_executable', 'flake8')
|
||||
|
||||
let g:loaded_ale_linters_python_flake8 = 1
|
||||
let g:ale_python_flake8_args =
|
||||
\ get(g:, 'ale_python_flake8_args', '')
|
||||
|
||||
function! ale_linters#python#flake8#Handle(buffer, lines)
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" stdin:6:6: E111 indentation is not a multiple of four
|
||||
let l:pattern = '^stdin:\(\d\+\):\(\d\+\): \([^ ]\+\) \(.\+\)$'
|
||||
let l:output = []
|
||||
" A map from Python executable paths to semver strings parsed for those
|
||||
" executables, so we don't have to look up the version number constantly.
|
||||
let s:version_cache = {}
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
function! ale_linters#python#flake8#GetExecutable(buffer) abort
|
||||
return g:ale_python_flake8_executable
|
||||
endfunction
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
function! ale_linters#python#flake8#VersionCheck(buffer) abort
|
||||
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
|
||||
|
||||
let l:line = l:match[1] + 0
|
||||
let l:column = l:match[2] + 0
|
||||
let l:code = l:match[3]
|
||||
let l:text = l:code . ': ' . l:match[4]
|
||||
let l:type = l:code[0] ==# 'E' ? 'E' : 'W'
|
||||
" If we have previously stored the version number in a cache, then
|
||||
" don't look it up again.
|
||||
if has_key(s:version_cache, l:executable)
|
||||
" Returning an empty string skips this command.
|
||||
return ''
|
||||
endif
|
||||
|
||||
if (l:code ==# 'W291' || l:code ==# 'W293') && !g:ale_warn_about_trailing_whitespace
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
return ale_linters#python#flake8#GetExecutable(a:buffer) . ' --version'
|
||||
endfunction
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
" Get the flake8 version from the output, or the cache.
|
||||
function! s:GetVersion(buffer, version_output) abort
|
||||
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
|
||||
let l:version = []
|
||||
|
||||
return l:output
|
||||
" Get the version from the cache.
|
||||
if has_key(s:version_cache, l:executable)
|
||||
return s:version_cache[l:executable]
|
||||
endif
|
||||
|
||||
if !empty(a:version_output)
|
||||
" Parse the version string, and store it in the cache.
|
||||
let l:version = ale#semver#Parse(a:version_output[0])
|
||||
let s:version_cache[l:executable] = l:version
|
||||
endif
|
||||
|
||||
return l:version
|
||||
endfunction
|
||||
|
||||
" flake8 versions 3 and up support the --stdin-display-name argument.
|
||||
function! s:SupportsDisplayName(version) abort
|
||||
return !empty(a:version) && ale#semver#GreaterOrEqual(a:version, [3, 0, 0])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
|
||||
let l:version = s:GetVersion(a:buffer, a:version_output)
|
||||
|
||||
" Only include the --stdin-display-name argument if we can parse the
|
||||
" flake8 version, and it is recent enough to support it.
|
||||
let l:display_name_args = s:SupportsDisplayName(l:version)
|
||||
\ ? '--stdin-display-name %s'
|
||||
\ : ''
|
||||
|
||||
return ale_linters#python#flake8#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_python_flake8_args . ' ' . l:display_name_args . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'flake8',
|
||||
\ 'executable': 'flake8',
|
||||
\ 'command': 'flake8 -',
|
||||
\ 'callback': 'ale_linters#python#flake8#Handle',
|
||||
\ 'executable_callback': 'ale_linters#python#flake8#GetExecutable',
|
||||
\ 'command_chain': [
|
||||
\ {'callback': 'ale_linters#python#flake8#VersionCheck'},
|
||||
\ {'callback': 'ale_linters#python#flake8#GetCommand'},
|
||||
\ ],
|
||||
\ 'callback': 'ale#handlers#HandlePEP8Format',
|
||||
\})
|
||||
|
||||
64
ale_linters/python/mypy.vim
Normal file
64
ale_linters/python/mypy.vim
Normal file
@@ -0,0 +1,64 @@
|
||||
" Author: Keith Smiley <k@keith.so>, w0rp <devw0rp@gmail.com>
|
||||
" Description: mypy support for optional python typechecking
|
||||
|
||||
let g:ale_python_mypy_options = get(g:, 'ale_python_mypy_options', '')
|
||||
|
||||
function! g:ale_linters#python#mypy#GetCommand(buffer) abort
|
||||
let l:automatic_stubs_dir = ale#util#FindNearestDirectory(a:buffer, 'stubs')
|
||||
" TODO: Add Windows support
|
||||
let l:automatic_stubs_command = (has('unix') && !empty(l:automatic_stubs_dir))
|
||||
\ ? 'MYPYPATH=' . l:automatic_stubs_dir . ' '
|
||||
\ : ''
|
||||
|
||||
return l:automatic_stubs_command
|
||||
\ . g:ale#util#stdin_wrapper
|
||||
\ . ' .py mypy --show-column-numbers '
|
||||
\ . g:ale_python_mypy_options
|
||||
endfunction
|
||||
|
||||
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
|
||||
|
||||
function! g:ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
" Look for lines like the following:
|
||||
"
|
||||
" file.py:4: error: No library stub file for module 'django.db'
|
||||
"
|
||||
" Lines like these should be ignored below:
|
||||
"
|
||||
" file.py:4: note: (Stub files are from https://github.com/python/typeshed)
|
||||
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \([^:]\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
if l:match[4] =~# 'Stub files are from'
|
||||
" The lines telling us where to get stub files from make it so
|
||||
" we can't read the actual errors, so exclude them.
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:match[3] =~# 'error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call g:ale#linter#Define('python', {
|
||||
\ 'name': 'mypy',
|
||||
\ 'executable': 'mypy',
|
||||
\ 'command_callback': 'ale_linters#python#mypy#GetCommand',
|
||||
\ 'callback': 'ale_linters#python#mypy#Handle',
|
||||
\})
|
||||
26
ale_linters/python/pylint.vim
Normal file
26
ale_linters/python/pylint.vim
Normal file
@@ -0,0 +1,26 @@
|
||||
" Author: keith <k@keith.so>
|
||||
" Description: pylint for python files
|
||||
|
||||
let g:ale_python_pylint_executable =
|
||||
\ get(g:, 'ale_python_pylint_executable', 'pylint')
|
||||
|
||||
let g:ale_python_pylint_options =
|
||||
\ get(g:, 'ale_python_pylint_options', '')
|
||||
|
||||
function! ale_linters#python#pylint#GetExecutable(buffer) abort
|
||||
return g:ale_python_pylint_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pylint#GetCommand(buffer) abort
|
||||
return g:ale#util#stdin_wrapper . ' .py '
|
||||
\ . ale_linters#python#pylint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_python_pylint_options
|
||||
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} {msg}" --reports n'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'pylint',
|
||||
\ 'executable_callback': 'ale_linters#python#pylint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#python#pylint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandlePEP8Format',
|
||||
\})
|
||||
@@ -1,18 +1,12 @@
|
||||
" Author: ynonp - https://github.com/ynonp
|
||||
" Description: rubocop for Ruby files
|
||||
|
||||
if exists('g:loaded_ale_linters_ruby_rubocop')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_ruby_rubocop = 1
|
||||
|
||||
function! ale_linters#ruby#rubocop#Handle(buffer, lines)
|
||||
function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" <path>/_:47:14: 83:29: C: Prefer single-quoted strings when you don't
|
||||
" <path>:83:29: C: Prefer single-quoted strings when you don't
|
||||
" need string interpolation or special symbols.
|
||||
let l:pattern = '\v_:(\d+):(\d+): (.): (.+)'
|
||||
let l:pattern = '\v:(\d+):(\d+): (.): (.+)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -32,7 +26,7 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines)
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type ==# 'C' ? 'E' : 'W',
|
||||
\ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
@@ -40,10 +34,21 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines)
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
|
||||
return 'rubocop --format emacs --force-exclusion ' .
|
||||
\ g:ale_ruby_rubocop_options .
|
||||
\ ' --stdin ' . bufname(a:buffer)
|
||||
endfunction
|
||||
|
||||
" 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
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'rubocop',
|
||||
\ 'executable': 'rubocop',
|
||||
\ 'command': 'rubocop --format emacs --stdin _',
|
||||
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
|
||||
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
|
||||
\})
|
||||
|
||||
|
||||
20
ale_linters/rust/cargo.vim
Normal file
20
ale_linters/rust/cargo.vim
Normal file
@@ -0,0 +1,20 @@
|
||||
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
|
||||
" Description: rustc invoked by cargo for rust files
|
||||
|
||||
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
|
||||
if ale#util#FindNearestFile(a:bufnr, 'Cargo.toml') !=# ''
|
||||
return 'cargo'
|
||||
else
|
||||
" if there is no Cargo.toml file, we don't use cargo even if it exists,
|
||||
" so we return '', because executable('') apparently always fails
|
||||
return ''
|
||||
endif
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('rust', {
|
||||
\ 'name': 'cargo',
|
||||
\ 'executable_callback': 'ale_linters#rust#cargo#GetCargoExecutable',
|
||||
\ 'command': 'cargo build --message-format=json -q',
|
||||
\ 'callback': 'ale#handlers#rust#HandleRustErrors',
|
||||
\ 'output_stream': 'stdout',
|
||||
\})
|
||||
27
ale_linters/rust/rustc.vim
Normal file
27
ale_linters/rust/rustc.vim
Normal file
@@ -0,0 +1,27 @@
|
||||
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
|
||||
" Description: rustc for rust files
|
||||
|
||||
function! ale_linters#rust#rustc#RustcCommand(buffer_number) abort
|
||||
" Try to guess the library search path. If the project is managed by cargo,
|
||||
" it's usually <project root>/target/debug/deps/ or
|
||||
" <project root>/target/release/deps/
|
||||
let l:cargo_file = ale#util#FindNearestFile(a:buffer_number, 'Cargo.toml')
|
||||
|
||||
if l:cargo_file !=# ''
|
||||
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'
|
||||
else
|
||||
let l:dependencies = ''
|
||||
endif
|
||||
|
||||
return 'rustc --error-format=json -Z no-trans ' . l:dependencies . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('rust', {
|
||||
\ 'name': 'rustc',
|
||||
\ 'executable': 'rustc',
|
||||
\ 'command_callback': 'ale_linters#rust#rustc#RustcCommand',
|
||||
\ 'callback': 'ale#handlers#rust#HandleRustErrors',
|
||||
\ 'output_stream': 'stderr',
|
||||
\})
|
||||
@@ -1,11 +1,5 @@
|
||||
" Author: KabbAmine - https://github.com/KabbAmine
|
||||
|
||||
if exists('g:loaded_ale_linters_sass_sasslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_sass_sasslint = 1
|
||||
|
||||
call ale#linter#Define('sass', {
|
||||
\ 'name': 'sasslint',
|
||||
\ 'executable': 'sass-lint',
|
||||
|
||||
31
ale_linters/sass/stylelint.vim
Normal file
31
ale_linters/sass/stylelint.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Author: diartyz <diartyz@gmail.com>
|
||||
|
||||
let g:ale_sass_stylelint_executable =
|
||||
\ get(g:, 'ale_sass_stylelint_executable', 'stylelint')
|
||||
|
||||
let g:ale_sass_stylelint_use_global =
|
||||
\ get(g:, 'ale_sass_stylelint_use_global', 0)
|
||||
|
||||
function! ale_linters#sass#stylelint#GetExecutable(buffer) abort
|
||||
if g:ale_sass_stylelint_use_global
|
||||
return g:ale_sass_stylelint_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/stylelint',
|
||||
\ g:ale_sass_stylelint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sass#stylelint#GetCommand(buffer) abort
|
||||
return ale_linters#sass#stylelint#GetExecutable(a:buffer)
|
||||
\ . ' --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sass', {
|
||||
\ 'name': 'stylelint',
|
||||
\ 'executable_callback': 'ale_linters#sass#stylelint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#sass#stylelint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
|
||||
\})
|
||||
@@ -2,13 +2,7 @@
|
||||
" Author: Zoltan Kalmar - https://github.com/kalmiz
|
||||
" Description: Basic scala support using scalac
|
||||
|
||||
if exists('g:loaded_ale_linters_scala_scalac')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_scala_scalac = 1
|
||||
|
||||
function! ale_linters#scala#scalac#Handle(buffer, lines)
|
||||
function! ale_linters#scala#scalac#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" /var/folders/5q/20rgxx3x1s34g3m14n5bq0x80000gn/T/vv6pSsy/0:26: error: expected class or object definition
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
" Author: KabbAmine - https://github.com/KabbAmine
|
||||
|
||||
if exists('g:loaded_ale_linters_scss_sasslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_scss_sasslint = 1
|
||||
|
||||
call ale#linter#Define('scss', {
|
||||
\ 'name': 'sasslint',
|
||||
\ 'executable': 'sass-lint',
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file add scsslint support for SCSS support
|
||||
|
||||
if exists('g:loaded_ale_linters_scss_scsslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_scss_scsslint = 1
|
||||
|
||||
function! ale_linters#scss#scsslint#Handle(buffer, lines)
|
||||
function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" test.scss:2:1 [W] Indentation: Line should be indented 2 spaces, but was indented 4 spaces
|
||||
|
||||
31
ale_linters/scss/stylelint.vim
Normal file
31
ale_linters/scss/stylelint.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Author: diartyz <diartyz@gmail.com>
|
||||
|
||||
let g:ale_scss_stylelint_executable =
|
||||
\ get(g:, 'ale_scss_stylelint_executable', 'stylelint')
|
||||
|
||||
let g:ale_scss_stylelint_use_global =
|
||||
\ get(g:, 'ale_scss_stylelint_use_global', 0)
|
||||
|
||||
function! ale_linters#scss#stylelint#GetExecutable(buffer) abort
|
||||
if g:ale_scss_stylelint_use_global
|
||||
return g:ale_scss_stylelint_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/stylelint',
|
||||
\ g:ale_scss_stylelint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scss#stylelint#GetCommand(buffer) abort
|
||||
return ale_linters#scss#stylelint#GetExecutable(a:buffer)
|
||||
\ . ' --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('scss', {
|
||||
\ 'name': 'stylelint',
|
||||
\ 'executable_callback': 'ale_linters#scss#stylelint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#scss#stylelint#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
|
||||
\})
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Lints sh files using bash -n
|
||||
|
||||
if exists('g:loaded_ale_linters_sh_shell')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_sh_shell = 1
|
||||
|
||||
" This option can be changed to change the default shell when the shell
|
||||
" cannot be taken from the hashbang line.
|
||||
if !exists('g:ale_linters_sh_shell_default_shell')
|
||||
@@ -17,7 +11,7 @@ if !exists('g:ale_linters_sh_shell_default_shell')
|
||||
endif
|
||||
endif
|
||||
|
||||
function! ale_linters#sh#shell#GetExecutable(buffer)
|
||||
function! ale_linters#sh#shell#GetExecutable(buffer) abort
|
||||
let l:banglines = getbufline(a:buffer, 1)
|
||||
|
||||
" Take the shell executable from the hashbang, if we can.
|
||||
@@ -35,11 +29,11 @@ function! ale_linters#sh#shell#GetExecutable(buffer)
|
||||
return g:ale_linters_sh_shell_default_shell
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shell#GetCommand(buffer)
|
||||
function! ale_linters#sh#shell#GetCommand(buffer) abort
|
||||
return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shell#Handle(buffer, lines)
|
||||
function! ale_linters#sh#shell#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" bash: line 13: syntax error near unexpected token `d'
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
" Description: This file adds support for using the shellcheck linter with
|
||||
" shell scripts.
|
||||
|
||||
if exists('g:loaded_ale_linters_sh_shellcheck')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_sh_shellcheck = 1
|
||||
|
||||
" This global variable can be set with a string of comma-seperated error
|
||||
" codes to exclude from shellcheck. For example:
|
||||
"
|
||||
@@ -22,9 +16,25 @@ else
|
||||
let s:exclude_option = ''
|
||||
endif
|
||||
|
||||
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'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shellcheck#GetCommand(buffer) abort
|
||||
return 'shellcheck ' . s:exclude_option . ' ' . s:GetDialectArgument() . ' -f gcc -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sh', {
|
||||
\ 'name': 'shellcheck',
|
||||
\ 'executable': 'shellcheck',
|
||||
\ 'command': 'shellcheck ' . s:exclude_option . ' -f gcc -',
|
||||
\ 'command_callback': 'ale_linters#sh#shellcheck#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
9
ale_linters/swift/swiftlint.vim
Normal file
9
ale_linters/swift/swiftlint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: David Mohundro <david@mohundro.com>
|
||||
" Description: swiftlint for swift files
|
||||
|
||||
call ale#linter#Define('swift', {
|
||||
\ 'name': 'swiftlint',
|
||||
\ 'executable': 'swiftlint',
|
||||
\ 'command': 'swiftlint lint --use-stdin',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
10
ale_linters/testft/testlinter.vim
Normal file
10
ale_linters/testft/testlinter.vim
Normal file
@@ -0,0 +1,10 @@
|
||||
" Author: neersighted <bjorn@neersighted.com>
|
||||
" Description: dummy linter to use in tests
|
||||
|
||||
call ale#linter#Define('testft', {
|
||||
\ 'name': 'testlinter',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'testlinter',
|
||||
\ 'command': 'testlinter',
|
||||
\ 'callback': 'testCB',
|
||||
\})
|
||||
63
ale_linters/tex/chktex.vim
Normal file
63
ale_linters/tex/chktex.vim
Normal file
@@ -0,0 +1,63 @@
|
||||
" Author: Andrew Balmos - <andrew@balmos.org>
|
||||
" Description: chktex for LaTeX files
|
||||
|
||||
let g:ale_tex_chktex_executable =
|
||||
\ get(g:, 'ale_tex_chktex_executable', 'chktex')
|
||||
|
||||
let g:ale_tex_chktex_options =
|
||||
\ get(g:, 'ale_tex_chktex_options', '-I')
|
||||
|
||||
function! ale_linters#tex#chktex#GetCommand(buffer) abort
|
||||
" Check for optional .chktexrc
|
||||
let l:chktex_config = ale#util#FindNearestFile(
|
||||
\ a:buffer,
|
||||
\ '.chktexrc')
|
||||
|
||||
let l:command = g:ale_tex_chktex_executable
|
||||
" Avoid bug when used without -p (last warning has gibberish for a filename)
|
||||
let l:command .= ' -v0 -p stdin -q'
|
||||
|
||||
if !empty(l:chktex_config)
|
||||
let l:command .= ' -l ' . fnameescape(l:chktex_config)
|
||||
endif
|
||||
|
||||
let l:command .= ' ' . g:ale_tex_chktex_options
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tex#chktex#Handle(buffer, lines) abort
|
||||
" Mattes lines like:
|
||||
"
|
||||
" stdin:499:2:24:Delete this space to maintain correct pagereferences.
|
||||
" stdin:507:81:3:You should enclose the previous parenthesis with `{}'.
|
||||
let l:pattern = '^stdin:\(\d\+\):\(\d\+\):\(\d\+\):\(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4] . ' (' . (l:match[3]+0) . ')',
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'chktex',
|
||||
\ 'executable': 'chktex',
|
||||
\ 'command_callback': 'ale_linters#tex#chktex#GetCommand',
|
||||
\ 'callback': 'ale_linters#tex#chktex#Handle'
|
||||
\})
|
||||
50
ale_linters/tex/lacheck.vim
Normal file
50
ale_linters/tex/lacheck.vim
Normal file
@@ -0,0 +1,50 @@
|
||||
" Author: Andrew Balmos - <andrew@balmos.org>
|
||||
" Description: lacheck for LaTeX files
|
||||
|
||||
let g:ale_tex_lacheck_executable =
|
||||
\ get(g:, 'ale_tex_lacheck_executable', 'lacheck')
|
||||
|
||||
function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
|
||||
" Mattes lines like:
|
||||
"
|
||||
" "book.tex", line 37: possible unwanted space at "{"
|
||||
" "book.tex", line 38: missing `\ ' after "etc."
|
||||
|
||||
let l:pattern = '^".\+", line \(\d\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
" lacheck follows `\input{}` commands. If the cwd is not the same as the
|
||||
" file in the buffer then it will fail to find the inputed items. We do not
|
||||
" want warnings from those items anyway
|
||||
if !empty(matchstr(l:match[2], '^Could not open ".\+"$'))
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:match[2],
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'lacheck',
|
||||
\ 'executable': 'lacheck',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .tex '
|
||||
\ . g:ale_tex_lacheck_executable,
|
||||
\ 'callback': 'ale_linters#tex#lacheck#Handle'
|
||||
\})
|
||||
9
ale_linters/tex/proselint.vim
Normal file
9
ale_linters/tex/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: poohzrn https://github.com/poohzrn
|
||||
" Description: proselint for tex files
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .tex proselint',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
9
ale_linters/text/proselint.vim
Normal file
9
ale_linters/text/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: poohzrn https://github.com/poohzrn
|
||||
" Description: proselint for text files
|
||||
|
||||
call ale#linter#Define('text', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .txt proselint',
|
||||
\})
|
||||
@@ -1,19 +1,14 @@
|
||||
" Author: Prashanth Chandra https://github.com/prashcr
|
||||
" Description: tslint for TypeScript files
|
||||
|
||||
if exists('g:loaded_ale_linters_typescript_tslint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_typescript_tslint = 1
|
||||
|
||||
function! ale_linters#typescript#tslint#Handle(buffer, lines)
|
||||
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" hello.ts[7, 41]: trailing whitespace
|
||||
" hello.ts[5, 1]: Forbidden 'var' keyword, use 'let' or 'const' instead
|
||||
"
|
||||
let l:pattern = '.\+.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
|
||||
let l:ext = '.' . fnamemodify(bufname(a:buffer), ':e')
|
||||
let l:pattern = '.\+' . l:ext . '\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -43,9 +38,18 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines)
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tslint#BuildLintCommand(buffer_n) abort
|
||||
let l:tsconfig_path = ale#util#FindNearestFile(a:buffer_n, 'tslint.json')
|
||||
let l:tslint_options = empty(l:tsconfig_path) ? '' : '-c ' . l:tsconfig_path
|
||||
|
||||
let l:ext = '.' . fnamemodify(bufname(a:buffer_n), ':e')
|
||||
|
||||
return g:ale#util#stdin_wrapper . ' ' . l:ext . ' tslint ' . l:tslint_options
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'tslint',
|
||||
\ 'executable': 'tslint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .ts tslint',
|
||||
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
|
||||
\ 'callback': 'ale_linters#typescript#tslint#Handle',
|
||||
\})
|
||||
|
||||
45
ale_linters/typescript/typecheck.vim
Normal file
45
ale_linters/typescript/typecheck.vim
Normal file
@@ -0,0 +1,45 @@
|
||||
" Author: Prashanth Chandra https://github.com/prashcr, Aleh Kashnikau https://github.com/mkusher
|
||||
" Description: type checker for TypeScript files
|
||||
|
||||
function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" hello.ts[7, 41]: Property 'a' does not exist on type 'A'
|
||||
" hello.ts[16, 7]: Type 'A' is not assignable to type 'B'
|
||||
"
|
||||
let l:pattern = '.\+\.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:line = l:match[1] + 0
|
||||
let l:column = l:match[2] + 0
|
||||
let l:type = 'E'
|
||||
let l:text = l:match[3]
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'typecheck',
|
||||
\ 'executable': 'typecheck',
|
||||
\ 'command': 'typecheck %s',
|
||||
\ 'callback': 'ale_linters#typescript#typecheck#Handle',
|
||||
\})
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: iverilog for verilog files
|
||||
|
||||
if exists('g:loaded_ale_linters_verilog_iverilog')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_verilog_iverilog = 1
|
||||
|
||||
function! ale_linters#verilog#iverilog#Handle(buffer, lines)
|
||||
function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" tb_me_top.v:37: warning: Instantiating module me_top with dangling input port 1 (rst_n) floating.
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: verilator for verilog files
|
||||
|
||||
if exists('g:loaded_ale_linters_verilog_verilator')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_verilog_verilator = 1
|
||||
|
||||
function! ale_linters#verilog#verilator#Handle(buffer, lines)
|
||||
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" %Error: addr_gen.v:3: syntax error, unexpected IDENTIFIER
|
||||
@@ -16,7 +10,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines)
|
||||
" %Warning-UNDRIVEN: test.v:3: Signal is not driven: clk
|
||||
" %Warning-UNUSED: test.v:4: Signal is not used: dout
|
||||
" %Warning-BLKSEQ: test.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).
|
||||
let l:pattern = '^%\(Warning\|Error\)[^:]*:[^:]\+:\(\d\+\): \(.\+\)$'
|
||||
let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -26,19 +20,22 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines)
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:line = l:match[2] + 0
|
||||
let l:line = l:match[3] + 0
|
||||
let l:type = l:match[1] ==# 'Error' ? 'E' : 'W'
|
||||
let l:text = l:match[3]
|
||||
let l:text = l:match[4]
|
||||
let l:file = l:match[2]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
if(l:file =~# '_verilator_linted.v')
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
@@ -48,6 +45,6 @@ call ale#linter#Define('verilog', {
|
||||
\ 'name': 'verilator',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'verilator',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .v verilator --lint-only -Wall -Wno-DECLFILENAME',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' _verilator_linted.v verilator --lint-only -Wall -Wno-DECLFILENAME',
|
||||
\ 'callback': 'ale_linters#verilog#verilator#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>, KabbAmine <amine.kabb@gmail.com>
|
||||
" Description: This file adds support for checking Vim code with Vint.
|
||||
|
||||
if exists('g:loaded_ale_linters_vim_vint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_vim_vint = 1
|
||||
|
||||
" This flag can be used to change enable/disable style issues.
|
||||
let g:ale_vim_vint_show_style_issues =
|
||||
\ get(g:, 'ale_vim_vint_show_style_issues', 1)
|
||||
|
||||
let s:warning_flag = g:ale_vim_vint_show_style_issues ? '-s' : '-w'
|
||||
let s:enable_neovim = has('nvim') ? ' --enable-neovim ' : ''
|
||||
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
|
||||
|
||||
call ale#linter#Define('vim', {
|
||||
@@ -21,6 +16,7 @@ call ale#linter#Define('vim', {
|
||||
\ . ' .vim vint '
|
||||
\ . s:warning_flag
|
||||
\ . ' --no-color '
|
||||
\ . s:enable_neovim
|
||||
\ . s:format,
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
|
||||
if exists('g:loaded_ale_linters_yaml_yamllint')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_linters_yaml_yamllint = 1
|
||||
|
||||
function! ale_linters#yaml#yamllint#Handle(buffer, lines)
|
||||
function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
" something.yaml:1:1: [warning] missing document start "---" (document-start)
|
||||
" something.yml:2:1: [error] syntax error: expected the node content, but found '<stream end>'
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
let s:lint_timer = -1
|
||||
|
||||
function! ale#Queue(delay) abort
|
||||
" Do nothing for blacklisted files.
|
||||
if index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
return
|
||||
endif
|
||||
|
||||
if s:lint_timer != -1
|
||||
call timer_stop(s:lint_timer)
|
||||
let s:lint_timer = -1
|
||||
@@ -24,11 +29,19 @@ function! ale#Queue(delay) abort
|
||||
endfunction
|
||||
|
||||
function! ale#Lint(...) abort
|
||||
" Do nothing for blacklisted files.
|
||||
if index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = bufnr('%')
|
||||
let l:linters = ale#linter#Get(&filetype)
|
||||
|
||||
" Set a variable telling us to clear the loclist later.
|
||||
let g:ale_buffer_should_reset_map[l:buffer] = 1
|
||||
" 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 = []
|
||||
|
||||
for l:linter in l:linters
|
||||
" Check if a given linter has a program which can be executed.
|
||||
|
||||
@@ -2,19 +2,12 @@
|
||||
" Description: Utility functions related to cleaning state.
|
||||
|
||||
function! ale#cleanup#Buffer(buffer) abort
|
||||
if has_key(g:ale_buffer_count_map, a:buffer)
|
||||
call remove(g:ale_buffer_count_map, a:buffer)
|
||||
endif
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
" When buffers are removed, clear all of the jobs.
|
||||
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
|
||||
call ale#engine#ClearJob(l:job)
|
||||
endfor
|
||||
|
||||
if has_key(g:ale_buffer_loclist_map, a:buffer)
|
||||
call remove(g:ale_buffer_loclist_map, a:buffer)
|
||||
endif
|
||||
|
||||
if has_key(g:ale_buffer_should_reset_map, a:buffer)
|
||||
call remove(g:ale_buffer_should_reset_map, a:buffer)
|
||||
endif
|
||||
|
||||
if has_key(g:ale_buffer_sign_dummy_map, a:buffer)
|
||||
call remove(g:ale_buffer_sign_dummy_map, a:buffer)
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -46,30 +46,51 @@ function! ale#cursor#EchoCursorWarning(...) abort
|
||||
|
||||
let l:buffer = bufnr('%')
|
||||
|
||||
if !has_key(g:ale_buffer_loclist_map, l:buffer)
|
||||
if !has_key(g:ale_buffer_info, l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:pos = getcurpos()
|
||||
let l:loclist = g:ale_buffer_loclist_map[l:buffer]
|
||||
let l:loclist = g:ale_buffer_info[l:buffer].loclist
|
||||
let l:index = ale#util#BinarySearch(l:loclist, l:pos[1], l:pos[2])
|
||||
|
||||
if l:index >= 0
|
||||
let l:loc = l:loclist[l:index]
|
||||
let l:msg = s:GetMessage(l:loc.linter_name, l:loc.type, l:loc.text)
|
||||
call ale#cursor#TruncatedEcho(l:msg)
|
||||
let g:ale_buffer_info[l:buffer].echoed = 1
|
||||
else
|
||||
echo
|
||||
" We'll only clear the echoed message when moving off errors once,
|
||||
" so we don't continually clear the echo line.
|
||||
if get(g:ale_buffer_info[l:buffer], 'echoed')
|
||||
echo
|
||||
let g:ale_buffer_info[l:buffer].echoed = 0
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:cursor_timer = -1
|
||||
let s:last_pos = [0, 0, 0]
|
||||
|
||||
function! ale#cursor#EchoCursorWarningWithDelay() abort
|
||||
" Do nothing for blacklisted files.
|
||||
if index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
return
|
||||
endif
|
||||
|
||||
if s:cursor_timer != -1
|
||||
call timer_stop(s:cursor_timer)
|
||||
let s:cursor_timer = -1
|
||||
endif
|
||||
|
||||
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
|
||||
let l:pos = getcurpos()[0:2]
|
||||
|
||||
" Check the current buffer, line, and column number against the last
|
||||
" recorded position. If the position has actually changed, *then*
|
||||
" we should echo something. Otherwise we can end up doing processing
|
||||
" the echo message far too frequently.
|
||||
if l:pos != s:last_pos
|
||||
let s:last_pos = l:pos
|
||||
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -20,7 +20,20 @@ function! s:GetJobID(job) abort
|
||||
return ch_info(job_getchannel(a:job)).id
|
||||
endfunction
|
||||
|
||||
function! s:ClearJob(job) abort
|
||||
function! ale#engine#InitBufferInfo(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
" job_list will hold the list of jobs
|
||||
" loclist holds the loclist items after all jobs have completed.
|
||||
" new_loclist holds loclist items while jobs are being run.
|
||||
let g:ale_buffer_info[a:buffer] = {
|
||||
\ 'job_list': [],
|
||||
\ 'loclist': [],
|
||||
\ 'new_loclist': [],
|
||||
\}
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#ClearJob(job) abort
|
||||
let l:job_id = s:GetJobID(a:job)
|
||||
let l:linter = s:job_info_map[l:job_id].linter
|
||||
|
||||
@@ -37,25 +50,66 @@ function! s:ClearJob(job) abort
|
||||
endif
|
||||
|
||||
call remove(s:job_info_map, l:job_id)
|
||||
call remove(l:linter, 'job')
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutput(job, data) abort
|
||||
function! s:StopPreviousJobs(buffer, linter) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
" Do nothing if we didn't run anything for the buffer.
|
||||
return
|
||||
endif
|
||||
|
||||
let l:new_job_list = []
|
||||
|
||||
for l:job in g:ale_buffer_info[a:buffer].job_list
|
||||
let l:job_id = s:GetJobID(l:job)
|
||||
|
||||
if has_key(s:job_info_map, l:job_id)
|
||||
\&& s:job_info_map[l:job_id].linter.name ==# a:linter.name
|
||||
" Stop jobs which match the buffer and linter.
|
||||
call ale#engine#ClearJob(l:job)
|
||||
else
|
||||
" Keep other jobs in the list.
|
||||
call add(l:new_job_list, l:job)
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Update the list, removing the previously run job.
|
||||
let g:ale_buffer_info[a:buffer].job_list = l:new_job_list
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutputVim(channel, data) abort
|
||||
let l:job_id = s:GetJobID(ch_getjob(a:channel))
|
||||
|
||||
if !has_key(s:job_info_map, l:job_id)
|
||||
return
|
||||
endif
|
||||
|
||||
call add(s:job_info_map[l:job_id].output, a:data)
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutputNeoVim(job, data, event) abort
|
||||
let l:job_id = s:GetJobID(a:job)
|
||||
|
||||
if !has_key(s:job_info_map, l:job_id)
|
||||
return
|
||||
endif
|
||||
|
||||
call extend(s:job_info_map[l:job_id].output, a:data)
|
||||
" Join the lines passed to ale, because Neovim splits them up.
|
||||
" a:data is a list of strings, where every item is a new line, except the
|
||||
" first one, which is the continuation of the last item passed last time.
|
||||
call ale#engine#JoinNeovimOutput(s:job_info_map[l:job_id].output, a:data)
|
||||
endfunction
|
||||
|
||||
function! s:GatherOutputVim(channel, data) abort
|
||||
call s:GatherOutput(ch_getjob(a:channel), [a:data])
|
||||
endfunction
|
||||
function! ale#engine#JoinNeovimOutput(output, data) abort
|
||||
if empty(a:output)
|
||||
call extend(a:output, a:data)
|
||||
else
|
||||
" Extend the previous line, which can be continued.
|
||||
let a:output[-1] .= get(a:data, 0, '')
|
||||
|
||||
function! s:GatherOutputNeoVim(job, data, event) abort
|
||||
call s:GatherOutput(a:job, a:data)
|
||||
" Add the new lines.
|
||||
call extend(a:output, a:data[1:])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HandleExit(job) abort
|
||||
@@ -71,15 +125,17 @@ function! s:HandleExit(job) abort
|
||||
endif
|
||||
|
||||
let l:job_info = s:job_info_map[l:job_id]
|
||||
|
||||
call s:ClearJob(a:job)
|
||||
|
||||
let l:linter = l:job_info.linter
|
||||
let l:output = l:job_info.output
|
||||
let l:buffer = l:job_info.buffer
|
||||
let l:next_chain_index = l:job_info.next_chain_index
|
||||
|
||||
if !has_key(g:ale_buffer_should_reset_map, l:buffer)
|
||||
" A job ended for a buffer which has been closed, so stop here.
|
||||
" Call the same function for stopping jobs again to clean up the job
|
||||
" which just closed.
|
||||
call s:StopPreviousJobs(l:buffer, l:linter)
|
||||
|
||||
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
|
||||
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -92,30 +148,35 @@ function! s:HandleExit(job) abort
|
||||
let l:item.linter_name = l:linter.name
|
||||
endfor
|
||||
|
||||
if g:ale_buffer_should_reset_map[l:buffer]
|
||||
let g:ale_buffer_should_reset_map[l:buffer] = 0
|
||||
let g:ale_buffer_loclist_map[l:buffer] = []
|
||||
endif
|
||||
|
||||
" Add the loclist items from the linter.
|
||||
call extend(g:ale_buffer_loclist_map[l:buffer], l:linter_loclist)
|
||||
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
|
||||
|
||||
if !empty(g:ale_buffer_info[l:buffer].job_list)
|
||||
" Wait for all jobs to complete before doing anything else.
|
||||
return
|
||||
endif
|
||||
|
||||
" Sort the loclist again.
|
||||
" We need a sorted list so we can run a binary search against it
|
||||
" for efficient lookup of the messages in the cursor handler.
|
||||
call sort(g:ale_buffer_loclist_map[l:buffer], 'ale#util#LocItemCompare')
|
||||
call sort(g:ale_buffer_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
|
||||
|
||||
if g:ale_set_loclist
|
||||
call setloclist(0, g:ale_buffer_loclist_map[l:buffer])
|
||||
" Now swap the old and new loclists, after we have collected everything
|
||||
" and sorted the list again.
|
||||
let g:ale_buffer_info[l:buffer].loclist = g:ale_buffer_info[l:buffer].new_loclist
|
||||
let g:ale_buffer_info[l:buffer].new_loclist = []
|
||||
|
||||
if g:ale_set_quickfix || g:ale_set_loclist
|
||||
call ale#list#SetLists(g:ale_buffer_info[l:buffer].loclist)
|
||||
endif
|
||||
|
||||
if g:ale_set_signs
|
||||
call ale#sign#SetSigns(l:buffer, g:ale_buffer_loclist_map[l:buffer])
|
||||
call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
endif
|
||||
|
||||
if exists('*ale#statusline#Update')
|
||||
" Don't load/run if not already loaded.
|
||||
call ale#statusline#Update(l:buffer, g:ale_buffer_loclist_map[l:buffer])
|
||||
call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
endif
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
@@ -149,42 +210,37 @@ function! s:FixLocList(buffer, loclist) abort
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Invoke(buffer, linter) abort
|
||||
if has_key(a:linter, 'job')
|
||||
" Stop previous jobs for the same linter.
|
||||
call s:ClearJob(a:linter.job)
|
||||
endif
|
||||
|
||||
if 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
|
||||
function! s:RunJob(command, generic_job_options) abort
|
||||
let l:buffer = a:generic_job_options.buffer
|
||||
let l:linter = a:generic_job_options.linter
|
||||
let l:output_stream = a:generic_job_options.output_stream
|
||||
let l:next_chain_index = a:generic_job_options.next_chain_index
|
||||
let l:read_buffer = a:generic_job_options.read_buffer
|
||||
let l:command = a:command
|
||||
|
||||
if l:command =~# '%s'
|
||||
" If there is a '%s' in the command string, replace it with the name
|
||||
" of the file.
|
||||
let l:command = printf(l:command, shellescape(fnamemodify(bufname(a:buffer), ':p')))
|
||||
let l:command = printf(l:command, shellescape(fnamemodify(bufname(l:buffer), ':p')))
|
||||
endif
|
||||
|
||||
if has('nvim')
|
||||
if a:linter.output_stream ==# 'stderr'
|
||||
if l:output_stream ==# 'stderr'
|
||||
" Read from stderr instead of stdout.
|
||||
let l:job = jobstart(l:command, {
|
||||
\ 'on_stderr': 's:GatherOutputNeoVim',
|
||||
\ 'on_exit': 's:HandleExitNeoVim',
|
||||
\ 'on_stderr': function('s:GatherOutputNeoVim'),
|
||||
\ 'on_exit': function('s:HandleExitNeoVim'),
|
||||
\})
|
||||
elseif a:linter.output_stream ==# 'both'
|
||||
elseif l:output_stream ==# 'both'
|
||||
let l:job = jobstart(l:command, {
|
||||
\ 'on_stdout': 's:GatherOutputNeoVim',
|
||||
\ 'on_stderr': 's:GatherOutputNeoVim',
|
||||
\ 'on_exit': 's:HandleExitNeoVim',
|
||||
\ 'on_stdout': function('s:GatherOutputNeoVim'),
|
||||
\ 'on_stderr': function('s:GatherOutputNeoVim'),
|
||||
\ 'on_exit': function('s:HandleExitNeoVim'),
|
||||
\})
|
||||
else
|
||||
let l:job = jobstart(l:command, {
|
||||
\ 'on_stdout': 's:GatherOutputNeoVim',
|
||||
\ 'on_exit': 's:HandleExitNeoVim',
|
||||
\ 'on_stdout': function('s:GatherOutputNeoVim'),
|
||||
\ 'on_exit': function('s:HandleExitNeoVim'),
|
||||
\})
|
||||
endif
|
||||
else
|
||||
@@ -195,10 +251,10 @@ function! ale#engine#Invoke(buffer, linter) abort
|
||||
\ 'close_cb': function('s:HandleExitVim'),
|
||||
\}
|
||||
|
||||
if a:linter.output_stream ==# 'stderr'
|
||||
if l:output_stream ==# 'stderr'
|
||||
" Read from stderr instead of stdout.
|
||||
let l:job_options.err_cb = function('s:GatherOutputVim')
|
||||
elseif a:linter.output_stream ==# 'both'
|
||||
elseif l:output_stream ==# 'both'
|
||||
" Read from both streams.
|
||||
let l:job_options.out_cb = function('s:GatherOutputVim')
|
||||
let l:job_options.err_cb = function('s:GatherOutputVim')
|
||||
@@ -215,10 +271,12 @@ function! ale#engine#Invoke(buffer, linter) abort
|
||||
" Execute the command with the shell, to fix escaping issues.
|
||||
let l:command = split(&shell) + split(&shellcmdflag) + [l:command]
|
||||
|
||||
" On Unix machines, we can send the Vim buffer directly.
|
||||
" This is faster than reading the lines ourselves.
|
||||
let l:job_options.in_io = 'buffer'
|
||||
let l:job_options.in_buf = a:buffer
|
||||
if l:read_buffer
|
||||
" On Unix machines, we can send the Vim buffer directly.
|
||||
" This is faster than reading the lines ourselves.
|
||||
let l:job_options.in_io = 'buffer'
|
||||
let l:job_options.in_buf = l:buffer
|
||||
endif
|
||||
endif
|
||||
|
||||
" Vim 8 will read the stdin from the file's buffer.
|
||||
@@ -227,34 +285,116 @@ function! ale#engine#Invoke(buffer, linter) abort
|
||||
|
||||
" Only proceed if the job is being run.
|
||||
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run')
|
||||
let a:linter.job = l:job
|
||||
" 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)
|
||||
|
||||
" Store the ID for the job in the map to read back again.
|
||||
let s:job_info_map[s:GetJobID(l:job)] = {
|
||||
\ 'linter': a:linter,
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': l:linter,
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'output': [],
|
||||
\ 'next_chain_index': l:next_chain_index,
|
||||
\}
|
||||
|
||||
if has('nvim')
|
||||
" In NeoVim, we have to send the buffer lines ourselves.
|
||||
let l:input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
|
||||
if l:read_buffer
|
||||
if has('nvim')
|
||||
" In NeoVim, we have to send the buffer lines ourselves.
|
||||
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
|
||||
|
||||
call jobsend(l:job, l:input)
|
||||
call jobclose(l:job, 'stdin')
|
||||
elseif has('win32')
|
||||
" On some Vim versions, we have to send the buffer data ourselves.
|
||||
let l:input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
|
||||
let l:channel = job_getchannel(l:job)
|
||||
call jobsend(l:job, l:input)
|
||||
call jobclose(l:job, 'stdin')
|
||||
elseif has('win32')
|
||||
" On some Vim versions, we have to send the buffer data ourselves.
|
||||
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
|
||||
let l:channel = job_getchannel(l:job)
|
||||
|
||||
if ch_status(l:channel) ==# 'open'
|
||||
call ch_sendraw(l:channel, l:input)
|
||||
call ch_close_in(l:channel)
|
||||
if ch_status(l:channel) ==# 'open'
|
||||
call ch_sendraw(l:channel, l:input)
|
||||
call ch_close_in(l:channel)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
|
||||
let l:chain_index = a:chain_index
|
||||
let l:input = a:input
|
||||
|
||||
if has_key(a:linter, 'command_chain')
|
||||
while l:chain_index < len(a:linter.command_chain)
|
||||
" Run a chain of commands, one asychronous command after the other,
|
||||
" so that many programs can be run in a sequence.
|
||||
let l:chain_item = a:linter.command_chain[l:chain_index]
|
||||
|
||||
" The chain item can override the output_stream option.
|
||||
if has_key(l:chain_item, 'output_stream')
|
||||
let l:output_stream = l:chain_item.output_stream
|
||||
endif
|
||||
|
||||
if l:chain_index == 0
|
||||
" The first callback in the chain takes only a buffer number.
|
||||
let l:command = ale#util#GetFunction(l:chain_item.callback)(
|
||||
\ a:buffer
|
||||
\)
|
||||
else
|
||||
" The second callback in the chain takes some input too.
|
||||
let l:command = ale#util#GetFunction(l:chain_item.callback)(
|
||||
\ a:buffer,
|
||||
\ l:input
|
||||
\)
|
||||
endif
|
||||
|
||||
if !empty(l:command)
|
||||
" We hit a command to run, so we'll execute that
|
||||
break
|
||||
endif
|
||||
|
||||
" Command chain items can return an empty string to indicate that
|
||||
" a command should be skipped, so we should try the next item
|
||||
" with no input.
|
||||
let l:input = []
|
||||
let l:chain_index += 1
|
||||
endwhile
|
||||
|
||||
if empty(l:command)
|
||||
" Don't run any jobs if the last command is an empty string.
|
||||
return
|
||||
endif
|
||||
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
|
||||
|
||||
let l:is_last_job = l:chain_index >= len(get(a:linter, 'command_chain', [])) - 1
|
||||
|
||||
call s:RunJob(l:command, {
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': a:linter,
|
||||
\ 'output_stream': l:output_stream,
|
||||
\ 'next_chain_index': l:chain_index + 1,
|
||||
\ 'read_buffer': l:is_last_job,
|
||||
\})
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Invoke(buffer, linter) abort
|
||||
" Stop previous jobs for the same linter.
|
||||
call s:StopPreviousJobs(a:buffer, a:linter)
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, return the warnings and errors for a given buffer.
|
||||
function! ale#engine#GetLoclist(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return []
|
||||
endif
|
||||
|
||||
return g:ale_buffer_info[a:buffer].loclist
|
||||
endfunction
|
||||
|
||||
" This function can be called with a timeout to wait for all jobs to finish.
|
||||
" If the jobs to not finish in the given number of milliseconds,
|
||||
" an exception will be thrown.
|
||||
@@ -270,8 +410,9 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
|
||||
let l:job_list = []
|
||||
|
||||
for l:job_id in keys(s:job_info_map)
|
||||
call add(l:job_list, s:job_info_map[l:job_id].linter.job)
|
||||
" Gather all of the jobs from every buffer.
|
||||
for l:info in values(g:ale_buffer_info)
|
||||
call extend(l:job_list, l:info.job_list)
|
||||
endfor
|
||||
|
||||
let l:should_wait_more = 1
|
||||
@@ -301,4 +442,27 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
" prevents the occasional failure where this function exits after jobs
|
||||
" end, but before handlers are run.
|
||||
sleep 10ms
|
||||
|
||||
" We must check the buffer data again to see if new jobs started
|
||||
" for command_chain linters.
|
||||
let l:has_new_jobs = 0
|
||||
|
||||
for l:info in values(g:ale_buffer_info)
|
||||
if !empty(l:info.job_list)
|
||||
let l:has_new_jobs = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
if l:has_new_jobs
|
||||
" We have to wait more. Offset the timeout by the time taken so far.
|
||||
let l:now = system('date +%s%3N') + 0
|
||||
let l:new_deadline = a:deadline - (l:now - l:start_time)
|
||||
|
||||
if l:new_deadline <= 0
|
||||
" Enough time passed already, so stop immediately.
|
||||
throw 'Jobs did not complete on time!'
|
||||
endif
|
||||
|
||||
call ale#engine#WaitForJobs(l:new_deadline)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -4,7 +4,7 @@ scriptencoding utf-8
|
||||
" linter which outputs warnings and errors in a format accepted by one of
|
||||
" these functions can simply use one of these pre-defined error handlers.
|
||||
|
||||
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.-]\+'
|
||||
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
|
||||
|
||||
function! s:HandleUnixFormat(buffer, lines, type) abort
|
||||
" Matches patterns line the following:
|
||||
@@ -12,7 +12,7 @@ function! s:HandleUnixFormat(buffer, lines, type) abort
|
||||
" file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args
|
||||
" file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
|
||||
" file.go:5:2: expected declaration, found 'STRING' "log"
|
||||
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \(.\+\)$'
|
||||
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?:\? \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -45,7 +45,6 @@ function! ale#handlers#HandleUnixFormatAsWarning(buffer, lines) abort
|
||||
return s:HandleUnixFormat(a:buffer, a:lines, 'W')
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale#handlers#HandleGCCFormat(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
@@ -68,7 +67,78 @@ function! ale#handlers#HandleGCCFormat(buffer, lines) abort
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:match[3] ==# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[3] =~# 'error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#HandleCppCheckFormat(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" [test.cpp:5]: (error) Array 'a[10]' accessed at index 10, which is out of bounds
|
||||
let l:pattern = '^\[.\{-}:\(\d\+\)\]: (\(.\{-}\)) \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:match[3] . ' (' . l:match[2] . ')',
|
||||
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#HandlePEP8Format(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" stdin:6:6: E111 indentation is not a multiple of four
|
||||
" test.yml:35: [EANSIBLE0002] Trailing whitespace
|
||||
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \[\?\(\([[:alpha:]]\)[[:alnum:]]\+\)\]\? \(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:code = l:match[3]
|
||||
if (l:code ==# 'W291' || l:code ==# 'W293' || l:code ==# 'EANSIBLE002')
|
||||
\ && !g:ale_warn_about_trailing_whitespace
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
|
||||
if l:code ==# 'I0011'
|
||||
" Skip 'Locally disabling' message
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:code . ': ' . l:match[5],
|
||||
\ 'type': l:match[4] ==# 'E' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
@@ -116,3 +186,37 @@ function! ale#handlers#HandleCSSLintFormat(buffer, lines) abort
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" src/main.css
|
||||
" 108:10 ✖ Unexpected leading zero number-leading-zero
|
||||
" 116:20 ✖ Expected a trailing semicolon declaration-block-trailing-semicolon
|
||||
let l:pattern = '^.* \(\d\+\):\(\d\+\) \s\+\(\S\+\)\s\+ \(\u.\+\) \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:type = l:match[3] ==# '✖' ? 'E' : 'W'
|
||||
let l:text = l:match[4] . '[' . l:match[5] . ']'
|
||||
|
||||
" vcol is Needed to indicate that the column is a character.
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
90
autoload/ale/handlers/rust.vim
Normal file
90
autoload/ale/handlers/rust.vim
Normal file
@@ -0,0 +1,90 @@
|
||||
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>,
|
||||
" w0rp <devw0rp@gmail.com>
|
||||
"
|
||||
" Description: This file implements handlers specific to Rust.
|
||||
|
||||
if !exists('g:ale_rust_ignore_error_codes')
|
||||
let g:ale_rust_ignore_error_codes = []
|
||||
endif
|
||||
|
||||
" returns: a list [lnum, col] with the location of the error or []
|
||||
function! s:FindErrorInExpansion(span, file_name) abort
|
||||
if a:span.file_name ==# a:file_name
|
||||
return [a:span.line_start, a:span.byte_start]
|
||||
endif
|
||||
|
||||
if !empty(a:span.expansion)
|
||||
return s:FindErrorInExpansion(a:span.expansion.span, a:file_name)
|
||||
endif
|
||||
|
||||
return []
|
||||
endfunction
|
||||
|
||||
" A handler function which accepts a file name, to make unit testing easier.
|
||||
function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines) abort
|
||||
let l:filename = fnamemodify(a:full_filename, ':t')
|
||||
let l:output = []
|
||||
|
||||
for l:errorline in a:lines
|
||||
" ignore everything that is not Json
|
||||
if l:errorline !~# '^{'
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:error = json_decode(l:errorline)
|
||||
|
||||
if has_key(l:error, 'message') && type(l:error.message) == type({})
|
||||
let l:error = l:error.message
|
||||
endif
|
||||
|
||||
if !has_key(l:error, 'code')
|
||||
continue
|
||||
endif
|
||||
|
||||
if !empty(l:error.code) && index(g:ale_rust_ignore_error_codes, l:error.code.code) > -1
|
||||
continue
|
||||
endif
|
||||
|
||||
for l:span in l:error.spans
|
||||
let l:span_filename = fnamemodify(l:span.file_name, ':t')
|
||||
|
||||
if (
|
||||
\ l:span.is_primary
|
||||
\ && (l:span_filename ==# l:filename || l:span_filename ==# '<anon>')
|
||||
\)
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:span.line_start,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:span.byte_start,
|
||||
\ 'nr': -1,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': toupper(l:error.level[0]),
|
||||
\})
|
||||
else
|
||||
" when the error is caused in the expansion of a macro, we have
|
||||
" to bury deeper
|
||||
let l:root_cause = s:FindErrorInExpansion(l:span, l:filename)
|
||||
|
||||
if !empty(l:root_cause)
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:root_cause[0],
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:root_cause[1],
|
||||
\ 'nr': -1,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': toupper(l:error.level[0]),
|
||||
\})
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
" A handler for output for Rust linters.
|
||||
function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
|
||||
return ale#handlers#rust#HandleRustErrorsForFile(a:buffer, bufname(a:buffer), a:lines)
|
||||
endfunction
|
||||
@@ -7,52 +7,134 @@ let s:linters = {}
|
||||
" Default filetype aliaes.
|
||||
" The user defined aliases will be merged with this Dictionary.
|
||||
let s:default_ale_linter_aliases = {
|
||||
\ 'javascript.jsx': 'javascript',
|
||||
\ 'zsh': 'sh',
|
||||
\ 'Dockerfile': 'dockerfile',
|
||||
\ 'csh': 'sh',
|
||||
\ 'plaintex': 'tex',
|
||||
\ 'systemverilog': 'verilog',
|
||||
\ 'zsh': 'sh',
|
||||
\}
|
||||
|
||||
" Default linters to run for particular filetypes.
|
||||
" The user defined linter selections will be merged with this Dictionary.
|
||||
"
|
||||
" No linters are used for plaintext files by default.
|
||||
let s:default_ale_linters = {
|
||||
\ 'zsh': ['shell'],
|
||||
\ 'csh': ['shell'],
|
||||
\ 'text': [],
|
||||
\}
|
||||
|
||||
" Testing/debugging helper to unload all linters.
|
||||
function! ale#linter#Reset() abort
|
||||
let s:linters = {}
|
||||
endfunction
|
||||
|
||||
function! s:IsCallback(value) abort
|
||||
return type(a:value) == type('') || type(a:value) == type(function('type'))
|
||||
endfunction
|
||||
|
||||
function! ale#linter#PreProcess(linter) abort
|
||||
if type(a:linter) != type({})
|
||||
throw 'The linter object must be a Dictionary'
|
||||
endif
|
||||
|
||||
let l:obj = {
|
||||
\ 'name': get(a:linter, 'name'),
|
||||
\ 'callback': get(a:linter, 'callback'),
|
||||
\}
|
||||
|
||||
if type(l:obj.name) != type('')
|
||||
throw '`name` must be defined to name the linter'
|
||||
endif
|
||||
|
||||
if !s:IsCallback(l:obj.callback)
|
||||
throw '`callback` must be defined with a callback to accept output'
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'executable_callback')
|
||||
let l:obj.executable_callback = a:linter.executable_callback
|
||||
|
||||
if !s:IsCallback(l:obj.executable_callback)
|
||||
throw '`executable_callback` must be a callback if defined'
|
||||
endif
|
||||
elseif has_key(a:linter, 'executable')
|
||||
let l:obj.executable = a:linter.executable
|
||||
|
||||
if type(l:obj.executable) != type('')
|
||||
throw '`executable` must be a string if defined'
|
||||
endif
|
||||
else
|
||||
throw 'Either `executable` or `executable_callback` must be defined'
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'command_chain')
|
||||
let l:obj.command_chain = a:linter.command_chain
|
||||
|
||||
if type(l:obj.command_chain) != type([])
|
||||
throw '`command_chain` must be a List'
|
||||
endif
|
||||
|
||||
if empty(l:obj.command_chain)
|
||||
throw '`command_chain` must contain at least one item'
|
||||
endif
|
||||
|
||||
let l:link_index = 0
|
||||
|
||||
for l:link in l:obj.command_chain
|
||||
let l:err_prefix = 'The `command_chain` item ' . l:link_index . ' '
|
||||
|
||||
if !s:IsCallback(get(l:link, 'callback'))
|
||||
throw l:err_prefix . 'must define a `callback` function'
|
||||
endif
|
||||
|
||||
if has_key(l:link, 'output_stream')
|
||||
if type(l:link.output_stream) != type('')
|
||||
\|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0
|
||||
throw l:err_prefix . '`output_stream` flag must be '
|
||||
\ . "'stdout', 'stderr', or 'both'"
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:link_index += 1
|
||||
endfor
|
||||
elseif has_key(a:linter, 'command_callback')
|
||||
let l:obj.command_callback = a:linter.command_callback
|
||||
|
||||
if !s:IsCallback(l:obj.command_callback)
|
||||
throw '`command_callback` must be a callback if defined'
|
||||
endif
|
||||
elseif has_key(a:linter, 'command')
|
||||
let l:obj.command = a:linter.command
|
||||
|
||||
if type(l:obj.command) != type('')
|
||||
throw '`command` must be a string if defined'
|
||||
endif
|
||||
else
|
||||
throw 'Either `command`, `executable_callback`, `command_chain` '
|
||||
\ . 'must be defined'
|
||||
endif
|
||||
|
||||
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
|
||||
|
||||
if type(l:obj.output_stream) != type('')
|
||||
\|| index(['stdout', 'stderr', 'both'], l:obj.output_stream) < 0
|
||||
throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
|
||||
endif
|
||||
|
||||
return l:obj
|
||||
endfunction
|
||||
|
||||
function! ale#linter#Define(filetype, linter) abort
|
||||
if !has_key(s:linters, a:filetype)
|
||||
let s:linters[a:filetype] = []
|
||||
endif
|
||||
|
||||
let l:new_linter = {
|
||||
\ 'name': a:linter.name,
|
||||
\ 'callback': a:linter.callback,
|
||||
\}
|
||||
|
||||
if has_key(a:linter, 'executable_callback')
|
||||
let l:new_linter.executable_callback = a:linter.executable_callback
|
||||
else
|
||||
let l:new_linter.executable = a:linter.executable
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'command_callback')
|
||||
let l:new_linter.command_callback = a:linter.command_callback
|
||||
else
|
||||
let l:new_linter.command = a:linter.command
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'output_stream')
|
||||
let l:new_linter.output_stream = a:linter.output_stream
|
||||
else
|
||||
let l:new_linter.output_stream = 'stdout'
|
||||
endif
|
||||
|
||||
" TODO: Assert the value of the output_stream to be something sensible.
|
||||
let l:new_linter = ale#linter#PreProcess(a:linter)
|
||||
|
||||
call add(s:linters[a:filetype], l:new_linter)
|
||||
endfunction
|
||||
|
||||
function! s:LoadLinters(filetype) abort
|
||||
function! ale#linter#GetAll(filetype) abort
|
||||
if a:filetype ==# ''
|
||||
" Empty filetype? Nothing to be done about that.
|
||||
return []
|
||||
@@ -74,7 +156,7 @@ function! s:LoadLinters(filetype) abort
|
||||
return s:linters[a:filetype]
|
||||
endfunction
|
||||
|
||||
function! ale#linter#Get(original_filetype) abort
|
||||
function! s:ResolveFiletype(original_filetype) abort
|
||||
" Try and get an aliased file type either from the user's Dictionary, or
|
||||
" our default Dictionary, otherwise use the filetype as-is.
|
||||
let l:filetype = get(
|
||||
@@ -87,32 +169,67 @@ function! ale#linter#Get(original_filetype) abort
|
||||
\ )
|
||||
\)
|
||||
|
||||
" Try and get a list of linters to run, using the original file type,
|
||||
" not the aliased filetype. We have some linters to limit by default,
|
||||
" and users may define their own list of linters to run.
|
||||
let l:linter_names = get(
|
||||
\ g:ale_linters,
|
||||
\ a:original_filetype,
|
||||
\ get(
|
||||
\ s:default_ale_linters,
|
||||
\ a:original_filetype,
|
||||
\ 'all'
|
||||
\ )
|
||||
\)
|
||||
return l:filetype
|
||||
endfunction
|
||||
|
||||
let l:all_linters = s:LoadLinters(l:filetype)
|
||||
function! ale#linter#Get(original_filetypes) abort
|
||||
let l:combined_linters = []
|
||||
|
||||
if type(l:linter_names) == type('') && l:linter_names ==# 'all'
|
||||
let l:combined_linters = l:all_linters
|
||||
elseif type(l:linter_names) == type([])
|
||||
" Select only the linters we or the user has specified.
|
||||
for l:linter in l:all_linters
|
||||
if index(l:linter_names, l:linter.name) >= 0
|
||||
call add(l:combined_linters, l:linter)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
" Handle dot-seperated filetypes.
|
||||
for l:original_filetype in split(a:original_filetypes, '\.')
|
||||
let l:filetype = s:ResolveFiletype(l:original_filetype)
|
||||
|
||||
" Try and get a list of linters to run, using the original file type,
|
||||
" not the aliased filetype. We have some linters to limit by default,
|
||||
" and users may define their own list of linters to run.
|
||||
let l:linter_names = get(
|
||||
\ g:ale_linters,
|
||||
\ l:original_filetype,
|
||||
\ get(
|
||||
\ s:default_ale_linters,
|
||||
\ l:original_filetype,
|
||||
\ 'all'
|
||||
\ )
|
||||
\)
|
||||
|
||||
let l:all_linters = ale#linter#GetAll(l:filetype)
|
||||
let l:filetype_linters = []
|
||||
|
||||
if type(l:linter_names) == type('') && l:linter_names ==# 'all'
|
||||
let l:filetype_linters = l:all_linters
|
||||
elseif type(l:linter_names) == type([])
|
||||
" Select only the linters we or the user has specified.
|
||||
for l:linter in l:all_linters
|
||||
if index(l:linter_names, l:linter.name) >= 0
|
||||
call add(l:filetype_linters, l:linter)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
call extend(l:combined_linters, l:filetype_linters)
|
||||
endfor
|
||||
|
||||
return l:combined_linters
|
||||
endfunction
|
||||
|
||||
function! ale#linter#Info() abort
|
||||
let l:original_filetypes = &filetype
|
||||
|
||||
" We get the list of enabled linters for free by the above function.
|
||||
let l:enabled_linters = deepcopy(ale#linter#Get(l:original_filetypes))
|
||||
|
||||
" But have to build the list of available linters ourselves.
|
||||
let l:all_linters = []
|
||||
for l:original_filetype in split(l:original_filetypes, '\.')
|
||||
let l:filetype = s:ResolveFiletype(l:original_filetype)
|
||||
let l:filetype_linters = ale#linter#GetAll(l:filetype)
|
||||
call extend(l:all_linters, l:filetype_linters)
|
||||
endfor
|
||||
|
||||
let l:all_names = map(l:all_linters, 'v:val[''name'']')
|
||||
let l:enabled_names = map(l:enabled_linters, 'v:val[''name'']')
|
||||
|
||||
echom ' Current Filetype: ' . l:original_filetypes
|
||||
echom 'Available Linters: ' . string(l:all_names)
|
||||
echom ' Enabled Linters: ' . string(l:enabled_names)
|
||||
endfunction
|
||||
|
||||
49
autoload/ale/list.vim
Normal file
49
autoload/ale/list.vim
Normal file
@@ -0,0 +1,49 @@
|
||||
" Author: Bjorn Neergaard <bjorn@neersighted.com>, modified by Yann fery <yann@fery.me>
|
||||
" Description: Manages the loclist and quickfix lists
|
||||
|
||||
" Return 1 if there is a buffer with buftype == 'quickfix' in bufffer list
|
||||
function! ale#list#IsQuickfixOpen() abort
|
||||
for l:buf in range(1, bufnr('$'))
|
||||
if getbufvar(l:buf, '&buftype') ==# 'quickfix'
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#list#SetLists(loclist) abort
|
||||
if g:ale_set_quickfix
|
||||
call setqflist(a:loclist)
|
||||
elseif g:ale_set_loclist
|
||||
call setloclist(0, a:loclist)
|
||||
endif
|
||||
|
||||
" If we don't auto-open lists, bail out here.
|
||||
if !g:ale_open_list && !g:ale_keep_list_window_open
|
||||
return
|
||||
endif
|
||||
|
||||
" If we have errors in our list, open the list. Only if it isn't already open
|
||||
if len(a:loclist) > 0 || g:ale_keep_list_window_open
|
||||
let l:winnr = winnr()
|
||||
|
||||
if g:ale_set_quickfix
|
||||
copen
|
||||
elseif g:ale_set_loclist
|
||||
lopen
|
||||
endif
|
||||
|
||||
" If focus changed, restore it (jump to the last window).
|
||||
if l:winnr !=# winnr()
|
||||
wincmd p
|
||||
endif
|
||||
|
||||
" Only close if the list is totally empty (relying on Vim's state, not our
|
||||
" own). This keeps us from closing the window when other plugins have
|
||||
" populated it.
|
||||
elseif !g:ale_keep_list_window_open && g:ale_set_quickfix && len(getqflist()) == 0
|
||||
cclose
|
||||
elseif !g:ale_keep_list_window_open && len(getloclist(0)) == 0
|
||||
lclose
|
||||
endif
|
||||
endfunction
|
||||
100
autoload/ale/loclist_jumping.vim
Normal file
100
autoload/ale/loclist_jumping.vim
Normal file
@@ -0,0 +1,100 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file implements functions for jumping around in a file
|
||||
" based on errors and warnings in the loclist or quickfix list.
|
||||
|
||||
function! s:GetCurrentList() abort
|
||||
if g:ale_set_loclist
|
||||
return getloclist(winnr())
|
||||
elseif g:ale_set_quickfix
|
||||
let l:buffer = bufnr('%')
|
||||
|
||||
return filter(getqflist(), 'get(v:val, ''bufnr'', -1) == ' . l:buffer)
|
||||
endif
|
||||
|
||||
return []
|
||||
endfunction
|
||||
|
||||
function! s:GetSortedLoclist() abort
|
||||
let l:loclist = []
|
||||
|
||||
for l:item in s:GetCurrentList()
|
||||
if l:item.lnum < 1
|
||||
" Remove items we can't even jump to.
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:loclist, l:item)
|
||||
endfor
|
||||
|
||||
" We must sort the list again, as the loclist could contain items set
|
||||
" by other plugins.
|
||||
call sort(l:loclist, 'ale#util#LocItemCompare')
|
||||
|
||||
return l:loclist
|
||||
endfunction
|
||||
|
||||
" Search for the nearest line either before or after the current position
|
||||
" in the loclist. The argument 'wrap' can be passed to enable wrapping
|
||||
" around the end of the list.
|
||||
"
|
||||
" If there are no items or we have hit the end with wrapping off, an empty
|
||||
" List will be returned, otherwise a pair of [line_number, column_number] will
|
||||
" be returned.
|
||||
function! ale#loclist_jumping#FindNearest(direction, wrap) abort
|
||||
let l:loclist = s:GetSortedLoclist()
|
||||
|
||||
if empty(l:loclist)
|
||||
" We couldn't find anything, so stop here.
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:search_item = {'lnum': getcurpos()[1], 'col': getcurpos()[2]}
|
||||
|
||||
" When searching backwards, so we can find the next smallest match.
|
||||
if a:direction ==# 'before'
|
||||
call reverse(l:loclist)
|
||||
endif
|
||||
|
||||
" Look for items before or after the current position.
|
||||
for l:item in l:loclist
|
||||
" Compare the cursor with a item where the column number is bounded,
|
||||
" such that it's possible for the cursor to actually be on the given
|
||||
" column number, without modifying the cursor number we return. This
|
||||
" will allow us to move through matches, but still let us move the
|
||||
" cursor to a line without changing the column, in some cases.
|
||||
let l:cmp_value = ale#util#LocItemCompare(
|
||||
\ {
|
||||
\ 'lnum': l:item.lnum,
|
||||
\ 'col': min([max([l:item.col, 1]), len(getline(l:item.lnum))]),
|
||||
\ },
|
||||
\ l:search_item
|
||||
\)
|
||||
|
||||
if a:direction ==# 'before' && l:cmp_value < 0
|
||||
return [l:item.lnum, l:item.col]
|
||||
endif
|
||||
|
||||
if a:direction ==# 'after' && l:cmp_value > 0
|
||||
return [l:item.lnum, l:item.col]
|
||||
endif
|
||||
endfor
|
||||
|
||||
" If we found nothing, and the wrap option is set to 1, then we should
|
||||
" wrap around the list of warnings/errors
|
||||
if a:wrap
|
||||
let l:item = get(l:loclist, 0)
|
||||
|
||||
return [l:item.lnum, l:item.col]
|
||||
endif
|
||||
|
||||
return []
|
||||
endfunction
|
||||
|
||||
" As before, find the nearest match, but position the cursor at it.
|
||||
function! ale#loclist_jumping#Jump(direction, wrap) abort
|
||||
let l:nearest = ale#loclist_jumping#FindNearest(a:direction, a:wrap)
|
||||
|
||||
if !empty(l:nearest)
|
||||
call cursor(l:nearest)
|
||||
endif
|
||||
endfunction
|
||||
29
autoload/ale/semver.vim
Normal file
29
autoload/ale/semver.vim
Normal file
@@ -0,0 +1,29 @@
|
||||
" Given some text, parse a semantic versioning string from the text
|
||||
" into a triple of integeers [major, minor, patch].
|
||||
"
|
||||
" If no match can be performed, then an empty List will be returned instead.
|
||||
function! ale#semver#Parse(text) abort
|
||||
let l:match = matchlist(a:text, '^ *\(\d\+\)\.\(\d\+\)\.\(\d\+\)')
|
||||
|
||||
if empty(l:match)
|
||||
return []
|
||||
endif
|
||||
|
||||
return [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
|
||||
endfunction
|
||||
|
||||
" Given two triples of integers [major, minor, patch], compare the triples
|
||||
" and return 1 if the lhs is greater than or equal to the rhs.
|
||||
function! ale#semver#GreaterOrEqual(lhs, rhs) abort
|
||||
if a:lhs[0] > a:rhs[0]
|
||||
return 1
|
||||
elseif a:lhs[0] == a:rhs[0]
|
||||
if a:lhs[1] > a:rhs[1]
|
||||
return 1
|
||||
elseif a:lhs[1] == a:rhs[1]
|
||||
return a:lhs[2] >= a:rhs[2]
|
||||
endif
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
@@ -27,19 +27,27 @@ execute 'sign define ALEWarningSign text=' . g:ale_sign_warning
|
||||
\ . ' texthl=ALEWarningSign'
|
||||
sign define ALEDummySign
|
||||
|
||||
function! ale#sign#FindCurrentSigns(buffer) abort
|
||||
" Read sign data for a buffer to a list of lines.
|
||||
function! ale#sign#ReadSigns(buffer) abort
|
||||
redir => l:output
|
||||
silent exec 'sign place buffer=' . a:buffer
|
||||
redir end
|
||||
|
||||
return split(l:output, "\n")
|
||||
endfunction
|
||||
|
||||
" Given a list of lines for sign output, return a list of sign IDs
|
||||
function! ale#sign#ParseSigns(line_list) abort
|
||||
" Matches output like :
|
||||
" line=4 id=1 name=ALEErrorSign
|
||||
" строка=1 id=1000001 имя=ALEErrorSign
|
||||
let l:pattern = 'id=\(\d\+\).*=ALE\(Warning\|Error\)Sign'
|
||||
|
||||
redir => l:output
|
||||
silent exec 'sign place buffer=' . a:buffer
|
||||
redir END
|
||||
" 行=1 識別子=1000001 名前=ALEWarningSign
|
||||
" línea=12 id=1000001 nombre=ALEWarningSign
|
||||
let l:pattern = '^.*=\d*\s\+.*=\(\d\+\)\s\+.*=ALE\(Warning\|Error\|Dummy\)Sign'
|
||||
|
||||
let l:id_list = []
|
||||
|
||||
for l:line in split(l:output, "\n")
|
||||
for l:line in a:line_list
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) > 0
|
||||
@@ -50,6 +58,12 @@ function! ale#sign#FindCurrentSigns(buffer) abort
|
||||
return l:id_list
|
||||
endfunction
|
||||
|
||||
function! ale#sign#FindCurrentSigns(buffer) abort
|
||||
let l:line_list = ale#sign#ReadSigns(a:buffer)
|
||||
|
||||
return ale#sign#ParseSigns(l:line_list)
|
||||
endfunction
|
||||
|
||||
" Given a loclist, combine the loclist into a list of signs such that only
|
||||
" one sign appears per line. Error lines will take precedence.
|
||||
" The loclist will have been previously sorted.
|
||||
@@ -88,26 +102,36 @@ endfunction
|
||||
function! ale#sign#SetSigns(buffer, loclist) abort
|
||||
let l:signlist = ale#sign#CombineSigns(a:loclist)
|
||||
|
||||
if len(l:signlist) > 0 || g:ale_sign_column_always
|
||||
if !get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
|
||||
" Insert a dummy sign if one is missing.
|
||||
execute 'sign place ' . g:ale_sign_offset
|
||||
\ . ' line=1 name=ALEDummySign buffer='
|
||||
\ . a:buffer
|
||||
|
||||
let g:ale_buffer_sign_dummy_map[a:buffer] = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
" Find the current signs with the markers we use.
|
||||
" Find the current markers
|
||||
let l:current_id_list = ale#sign#FindCurrentSigns(a:buffer)
|
||||
let l:dummy_sign_set = 0
|
||||
|
||||
" Remove those markers.
|
||||
" Check if we set the dummy sign already.
|
||||
for l:current_id in l:current_id_list
|
||||
exec 'sign unplace ' . l:current_id . ' buffer=' . a:buffer
|
||||
if l:current_id == g:ale_sign_offset
|
||||
let l:dummy_sign_set = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Now set all of the signs.
|
||||
" If we haven't already set a dummy sign, and we have some previous signs
|
||||
" or always want a dummy sign, then set one, to keep the sign column open.
|
||||
if !l:dummy_sign_set && (len(l:signlist) > 0 || g:ale_sign_column_always)
|
||||
execute 'sign place ' . g:ale_sign_offset
|
||||
\ . ' line=1 name=ALEDummySign buffer='
|
||||
\ . a:buffer
|
||||
|
||||
let l:dummy_sign_set = 1
|
||||
endif
|
||||
|
||||
" Now remove the previous signs. The dummy will hold the column open
|
||||
" while we add the new signs, if we had signs before.
|
||||
for l:current_id in l:current_id_list
|
||||
if l:current_id != g:ale_sign_offset
|
||||
exec 'sign unplace ' . l:current_id . ' buffer=' . a:buffer
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Add the new signs,
|
||||
for l:index in range(0, len(l:signlist) - 1)
|
||||
let l:sign = l:signlist[l:index]
|
||||
let l:type = l:sign['type'] ==# 'W' ? 'ALEWarningSign' : 'ALEErrorSign'
|
||||
@@ -120,11 +144,10 @@ function! ale#sign#SetSigns(buffer, loclist) abort
|
||||
exec l:sign_line
|
||||
endfor
|
||||
|
||||
if !g:ale_sign_column_always && len(l:signlist) > 0
|
||||
if get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
|
||||
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
|
||||
|
||||
let g:ale_buffer_sign_dummy_map[a:buffer] = 0
|
||||
endif
|
||||
" Remove the dummy sign now we've updated the signs, unless we want
|
||||
" to keep it, which will keep the sign column open even when there are
|
||||
" no warnings or errors.
|
||||
if l:dummy_sign_set && !g:ale_sign_column_always
|
||||
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -14,34 +14,48 @@ function! ale#statusline#Update(buffer, loclist) abort
|
||||
endif
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_count_map[a:buffer] = [l:errors, l:warnings]
|
||||
let g:ale_buffer_info[a:buffer].count = [l:errors, l:warnings]
|
||||
endfunction
|
||||
|
||||
" Set the error and warning counts, calling for an update only if needed.
|
||||
" If counts cannot be set, return 0.
|
||||
function! s:SetupCount(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
" Linters have not been run for the buffer yet, so stop here.
|
||||
return 0
|
||||
endif
|
||||
|
||||
" Cache is cold, so manually ask for an update.
|
||||
if !has_key(g:ale_buffer_info[a:buffer], 'count')
|
||||
call ale#statusline#Update(a:buffer, g:ale_buffer_info[a:buffer].loclist)
|
||||
endif
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
" Returns a tuple of errors and warnings for use in third-party integrations.
|
||||
function! ale#statusline#Count(buffer) abort
|
||||
" Cache is cold, so manually ask for an update.
|
||||
if !has_key(g:ale_buffer_count_map, a:buffer)
|
||||
call ale#statusline#Update(a:buffer, get(g:ale_buffer_loclist_map, a:buffer, []))
|
||||
if !s:SetupCount(a:buffer)
|
||||
return [0, 0]
|
||||
endif
|
||||
|
||||
return g:ale_buffer_count_map[a:buffer]
|
||||
return g:ale_buffer_info[a:buffer].count
|
||||
endfunction
|
||||
|
||||
" Returns a formatted string that can be integrated in the statusline.
|
||||
function! ale#statusline#Status() abort
|
||||
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
|
||||
let l:buffer = bufnr('%')
|
||||
|
||||
" Cache is cold, so manually ask for an update.
|
||||
if !has_key(g:ale_buffer_count_map, l:buffer)
|
||||
call ale#statusline#Update(l:buffer, get(g:ale_buffer_loclist_map, l:buffer, []))
|
||||
if !s:SetupCount(l:buffer)
|
||||
return l:no_errors
|
||||
endif
|
||||
|
||||
let [l:error_count, l:warning_count] = g:ale_buffer_info[l:buffer].count
|
||||
|
||||
" Build strings based on user formatting preferences.
|
||||
let l:errors = g:ale_buffer_count_map[l:buffer][0] ?
|
||||
\ printf(g:ale_statusline_format[0], g:ale_buffer_count_map[l:buffer][0]) : ''
|
||||
let l:warnings = g:ale_buffer_count_map[l:buffer][1] ?
|
||||
\ printf(g:ale_statusline_format[1], g:ale_buffer_count_map[l:buffer][1]) : ''
|
||||
let l:no_errors = g:ale_statusline_format[2]
|
||||
let l:errors = l:error_count ? printf(l:error_format, l:error_count) : ''
|
||||
let l:warnings = l:warning_count ? printf(l:warning_format, l:warning_count) : ''
|
||||
|
||||
" Different formats based on the combination of errors and warnings.
|
||||
if empty(l:errors) && empty(l:warnings)
|
||||
|
||||
@@ -44,6 +44,35 @@ function! ale#util#FindNearestFile(buffer, filename) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer and a directory name, find the nearest directory by searching upwards
|
||||
" through the paths relative to the given buffer.
|
||||
function! ale#util#FindNearestDirectory(buffer, directory_name) abort
|
||||
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p')
|
||||
|
||||
let l:relative_path = finddir(a:directory_name, l:buffer_filename . ';')
|
||||
|
||||
if !empty(l:relative_path)
|
||||
return fnamemodify(l:relative_path, ':p')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer, a string to search for, an a global fallback for when
|
||||
" the search fails, look for a file in parent paths, and if that fails,
|
||||
" use the global fallback path instead.
|
||||
function! ale#util#ResolveLocalPath(buffer, search_string, global_fallback) abort
|
||||
" Search for a locally installed file first.
|
||||
let l:path = ale#util#FindNearestFile(a:buffer, a:search_string)
|
||||
|
||||
" If the serach fails, try the global executable instead.
|
||||
if empty(l:path)
|
||||
let l:path = a:global_fallback
|
||||
endif
|
||||
|
||||
return l:path
|
||||
endfunction
|
||||
|
||||
function! ale#util#GetFunction(string_or_ref) abort
|
||||
if type(a:string_or_ref) == type('')
|
||||
return function(a:string_or_ref)
|
||||
|
||||
83
custom-checks
Executable file
83
custom-checks
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
# This Bash script implements custom sanity checks for scripts beyond what
|
||||
# Vint covers, which are easy to check with regex.
|
||||
|
||||
# A flag for automatically fixing some errors.
|
||||
FIX_ERRORS=0
|
||||
RETURN_CODE=0
|
||||
|
||||
function print_help() {
|
||||
echo "Usage: ./custom-checks [--fix] [DIRECTORY]" 1>&2
|
||||
echo 1>&2
|
||||
echo " -h, --help Print this help text" 1>&2
|
||||
echo " --fix Automatically fix some errors" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [ $# -ne 0 ]; do
|
||||
case $1 in
|
||||
-h) ;& --help)
|
||||
print_help
|
||||
;;
|
||||
--fix)
|
||||
FIX_ERRORS=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
echo "Invalid argument: $1" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $# -eq 0 ] || [ -z "$1" ]; then
|
||||
print_help
|
||||
fi
|
||||
|
||||
# Called to output an error.
|
||||
# If called at least one, the return code for this script will be 1.
|
||||
output_error() {
|
||||
echo "$FILENAME:$LINE_NUMBER $1"
|
||||
RETURN_CODE=1
|
||||
}
|
||||
|
||||
# This function is called for each line in each file to check syntax.
|
||||
check_line() {
|
||||
line="$1"
|
||||
|
||||
if [[ "$line" =~ ^function ]]; then
|
||||
if ! [[ "$line" =~ abort$ ]]; then
|
||||
if ((FIX_ERRORS)); then
|
||||
# Use sed to add the 'abort' flag
|
||||
sed -i "${LINE_NUMBER}s/$/ abort/" "$FILENAME"
|
||||
else
|
||||
output_error 'Function without abort keyword (See :help except-compat)'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ' '+$ ]]; then
|
||||
output_error 'Trailing whitespace'
|
||||
fi
|
||||
}
|
||||
|
||||
# Loop through all of the vim files and keep track of the file line numbers.
|
||||
for FILENAME in $(find "$1" -name '*.vim'); do
|
||||
LINE_NUMBER=0
|
||||
|
||||
while read; do
|
||||
LINE_NUMBER=$(expr $LINE_NUMBER + 1)
|
||||
|
||||
check_line "$REPLY"
|
||||
done < "$FILENAME"
|
||||
done
|
||||
|
||||
exit $RETURN_CODE
|
||||
40
dmd-wrapper
40
dmd-wrapper
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
# Author: w0rp <devw0rp@gmail.com>
|
||||
# Description: This script wraps DMD so we can get something which is capable of reading
|
||||
# D code from stdin.
|
||||
|
||||
temp_file=`mktemp`
|
||||
mv "$temp_file" "$temp_file".d
|
||||
temp_file="$temp_file".d
|
||||
|
||||
trap "rm $temp_file" EXIT
|
||||
|
||||
while read; do
|
||||
echo "$REPLY" >> "$temp_file"
|
||||
done
|
||||
|
||||
# Read imports from DUB.
|
||||
original_path="$(pwd)"
|
||||
path="$original_path"
|
||||
import_line_options=''
|
||||
|
||||
# We need to look for variable configuration files in parent directories.
|
||||
while [ "$path" != '/' ]; do
|
||||
if [ -f "$path/dub.sdl" ] || [ -f "$path/dub.json" ] || [ -f "$path/package.json" ]; then
|
||||
|
||||
cd "$path"
|
||||
|
||||
while read import_line; do
|
||||
import_line_options="$import_line_options -I$import_line"
|
||||
done <<< "$(dub describe --import-paths)"
|
||||
|
||||
cd "$original_path"
|
||||
|
||||
break
|
||||
fi
|
||||
|
||||
path="$(dirname "$path")"
|
||||
done
|
||||
|
||||
dmd $import_line_options "$@" "$temp_file"
|
||||
908
doc/ale.txt
908
doc/ale.txt
File diff suppressed because it is too large
Load Diff
@@ -7,30 +7,34 @@
|
||||
if exists('g:loaded_ale')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale = 1
|
||||
|
||||
" A flag for detecting if the required features are set.
|
||||
if has('nvim')
|
||||
let s:ale_has_required_features = has('timers')
|
||||
let s:has_features = has('timers')
|
||||
else
|
||||
let s:ale_has_required_features = has('timers') && has('job') && has('channel')
|
||||
" Check if Job and Channel functions are available, instead of the
|
||||
" features. This works better on old MacVim versions.
|
||||
let s:has_features = has('timers') && exists('*job_start') && exists('*ch_close_in')
|
||||
endif
|
||||
|
||||
if !s:ale_has_required_features
|
||||
if !s:has_features
|
||||
echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
|
||||
echoerr 'Please update your editor appropriately.'
|
||||
finish
|
||||
endif
|
||||
|
||||
" Globals
|
||||
|
||||
let g:ale_buffer_count_map = {}
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
let g:ale_buffer_should_reset_map = {}
|
||||
let g:ale_buffer_sign_dummy_map = {}
|
||||
" This global variable is used internally by ALE for tracking information for
|
||||
" each buffer which linters are being run against.
|
||||
let g:ale_buffer_info = {}
|
||||
|
||||
" User Configuration
|
||||
|
||||
" This option prevents ALE autocmd commands from being run for particular
|
||||
" filetypes which can cause issues.
|
||||
let g:ale_filetype_blacklist = ['nerdtree', 'unite']
|
||||
|
||||
" This Dictionary configures which linters are enabled for which languages.
|
||||
let g:ale_linters = get(g:, 'ale_linters', {})
|
||||
|
||||
@@ -57,7 +61,7 @@ let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', 1)
|
||||
if g:ale_lint_on_enter
|
||||
augroup ALERunOnEnterGroup
|
||||
autocmd!
|
||||
autocmd BufEnter,BufRead * call ale#Queue(100)
|
||||
autocmd BufEnter,BufRead * call ale#Queue(300)
|
||||
augroup END
|
||||
endif
|
||||
|
||||
@@ -70,8 +74,16 @@ if g:ale_lint_on_save
|
||||
augroup END
|
||||
endif
|
||||
|
||||
" This flag can be set to 0 to disable setting the loclist.
|
||||
" These flags dictates if ale uses the quickfix or the loclist (loclist is the
|
||||
" default, quickfix overrides loclist).
|
||||
let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1)
|
||||
let g:ale_set_quickfix = get(g:, 'ale_set_quickfix', 0)
|
||||
|
||||
" This flag dictates if ale open the configured loclist
|
||||
let g:ale_open_list = get(g:, 'ale_open_list', 0)
|
||||
|
||||
" This flag dictates if ale keeps open loclist even if there is no error in loclist
|
||||
let g:ale_keep_list_window_open = get(g:, 'ale_keep_list_window_open', 0)
|
||||
|
||||
" This flag can be set to 0 to disable setting signs.
|
||||
" This is enabled by default only if the 'signs' feature exists.
|
||||
@@ -120,6 +132,21 @@ let g:ale_statusline_format = get(g:, 'ale_statusline_format',
|
||||
let g:ale_warn_about_trailing_whitespace =
|
||||
\ get(g:, 'ale_warn_about_trailing_whitespace', 1)
|
||||
|
||||
" Define commands for moving through warnings and errors.
|
||||
command! ALEPrevious :call ale#loclist_jumping#Jump('before', 0)
|
||||
command! ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1)
|
||||
command! ALENext :call ale#loclist_jumping#Jump('after', 0)
|
||||
command! ALENextWrap :call ale#loclist_jumping#Jump('after', 1)
|
||||
|
||||
" Define command to get information about current filetype.
|
||||
command! ALEInfo :call ale#linter#Info()
|
||||
|
||||
" <Plug> mappings for commands
|
||||
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>
|
||||
nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return>
|
||||
nnoremap <silent> <Plug>(ale_next) :ALENext<Return>
|
||||
nnoremap <silent> <Plug>(ale_next_wrap) :ALENextWrap<Return>
|
||||
|
||||
" Housekeeping
|
||||
|
||||
augroup ALECleanupGroup
|
||||
@@ -130,10 +157,10 @@ augroup END
|
||||
|
||||
" Backwards Compatibility
|
||||
|
||||
function! ALELint(delay)
|
||||
function! ALELint(delay) abort
|
||||
call ale#Queue(a:delay)
|
||||
endfunction
|
||||
|
||||
function! ALEGetStatusLine()
|
||||
function! ALEGetStatusLine() abort
|
||||
return ale#statusline#Status()
|
||||
endfunction
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Author: w0rp <devw0rp@gmail.com>
|
||||
# Authors: w0rp <devw0rp@gmail.com>, hauleth <lukasz@niemier.pl>
|
||||
# Description: This script implements a wrapper for any program which does not accept
|
||||
# stdin input on most Unix machines. The input to the script is read to a
|
||||
# temporary file, and the first argument sets a particular file extension
|
||||
# for the temporary file.
|
||||
|
||||
set -eu
|
||||
|
||||
# All of the following arguments are read as command to run.
|
||||
file_extension="$1"
|
||||
shift
|
||||
|
||||
temp_file=$(mktemp --tmpdir "ale-XXXXXXXXX$file_extension")
|
||||
trap 'rm $temp_file' EXIT
|
||||
temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'ale_linter')
|
||||
temp_file="$temp_dir/file$file_extension"
|
||||
trap 'rm -r "$temp_dir"' EXIT
|
||||
|
||||
while read -r; do
|
||||
echo "$REPLY" >> "$temp_file"
|
||||
done
|
||||
cat > "$temp_file"
|
||||
|
||||
"$@" "$temp_file"
|
||||
|
||||
91
test/test_ale_info.vader
Normal file
91
test/test_ale_info.vader
Normal file
@@ -0,0 +1,91 @@
|
||||
Before:
|
||||
let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout'}
|
||||
let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout'}
|
||||
|
||||
call ale#linter#Reset()
|
||||
let g:ale_linters = {}
|
||||
let g:ale_linter_aliases = {}
|
||||
|
||||
After:
|
||||
unlet! g:output
|
||||
|
||||
Given nolintersft (Empty buffer with no linters):
|
||||
Execute (ALEInfo with no linters should return the right output):
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: nolintersft\n
|
||||
\Available Linters: []\n
|
||||
\ Enabled Linters: []", g:output
|
||||
|
||||
Given (Empty buffer with no filetype):
|
||||
Execute (ALEInfo with no filetype should return the right output):
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: \n
|
||||
\Available Linters: []\n
|
||||
\ Enabled Linters: []", g:output
|
||||
|
||||
Given testft (Empty buffer):
|
||||
Execute (ALEInfo with a single linter should return the right output):
|
||||
call ale#linter#Define('testft', g:testlinter1)
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: testft\n
|
||||
\Available Linters: ['testlinter1']\n
|
||||
\ Enabled Linters: ['testlinter1']", g:output
|
||||
|
||||
Given testft (Empty buffer):
|
||||
Execute (ALEInfo with two linters should return the right output):
|
||||
call ale#linter#Define('testft', g:testlinter1)
|
||||
call ale#linter#Define('testft', g:testlinter2)
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: testft\n
|
||||
\Available Linters: ['testlinter1', 'testlinter2']\n
|
||||
\ Enabled Linters: ['testlinter1', 'testlinter2']", g:output
|
||||
|
||||
Given testft (Empty buffer):
|
||||
Execute (ALEInfo should calculate enabled linters correctly):
|
||||
call ale#linter#Define('testft', g:testlinter1)
|
||||
call ale#linter#Define('testft', g:testlinter2)
|
||||
let g:ale_linters = { 'testft': ['testlinter2'] }
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: testft\n
|
||||
\Available Linters: ['testlinter1', 'testlinter2']\n
|
||||
\ Enabled Linters: ['testlinter2']", g:output
|
||||
|
||||
Given testft (Empty buffer):
|
||||
Execute (ALEInfo should only return linters for current filetype):
|
||||
call ale#linter#Define('testft', g:testlinter1)
|
||||
call ale#linter#Define('testft2', g:testlinter2)
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: testft\n
|
||||
\Available Linters: ['testlinter1']\n
|
||||
\ Enabled Linters: ['testlinter1']", g:output
|
||||
|
||||
Given testft.testft2 (Empty buffer with two filetypes):
|
||||
Execute (ALEInfo with compound filetypes should return linters for both of them):
|
||||
call ale#linter#Define('testft', g:testlinter1)
|
||||
call ale#linter#Define('testft2', g:testlinter2)
|
||||
redir => g:output
|
||||
silent ALEInfo
|
||||
redir END
|
||||
AssertEqual "\n
|
||||
\ Current Filetype: testft.testft2\n
|
||||
\Available Linters: ['testlinter1', 'testlinter2']\n
|
||||
\ Enabled Linters: ['testlinter1', 'testlinter2']", g:output
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
Before:
|
||||
let g:ale_linters = {}
|
||||
let g:ale_linter_aliases = {}
|
||||
|
||||
After:
|
||||
let g:ale_linters = {}
|
||||
let g:ale_linter_aliases = {}
|
||||
|
||||
Execute (Defaults should be correct):
|
||||
AssertEqual [{'output_stream': 'stdout', 'name': 'eslint', 'executable': 'eslint', 'command': 'eslint -f unix --stdin --stdin-filename %s', 'callback': 'ale_linters#javascript#eslint#Handle'}, {'output_stream': 'stdout', 'name': 'jscs', 'executable': 'jscs', 'command': 'jscs -r unix -n -', 'callback': 'ale#handlers#HandleUnixFormatAsError'}, {'output_stream': 'stdout', 'name': 'jshint', 'executable': 'jshint', 'command_callback': 'ale_linters#javascript#jshint#GetCommand', 'callback': 'ale#handlers#HandleUnixFormatAsError'}], ale#linter#Get('javascript')
|
||||
|
||||
Execute (You should be able to select only a few linters):
|
||||
let g:ale_linters = {'javascript': ['eslint']}
|
||||
AssertEqual [{'output_stream': 'stdout', 'name': 'eslint', 'executable': 'eslint', 'command': 'eslint -f unix --stdin --stdin-filename %s', 'callback': 'ale_linters#javascript#eslint#Handle'}], ale#linter#Get('javascript')
|
||||
|
||||
Execute (You should be able to alias filetypes and select different linters):
|
||||
let g:ale_linter_aliases = {'foobar': 'javascript'}
|
||||
let g:ale_linters = {'javascript': ['eslint'], 'foobar': ['jshint']}
|
||||
AssertEqual [{'output_stream': 'stdout', 'name': 'jshint', 'executable': 'jshint', 'command_callback': 'ale_linters#javascript#jshint#GetCommand', 'callback': 'ale#handlers#HandleUnixFormatAsError'}], ale#linter#Get('foobar')
|
||||
@@ -1,65 +0,0 @@
|
||||
Before:
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
|
||||
After:
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
|
||||
Execute (Count should be 0 when data is empty):
|
||||
AssertEqual [0, 0], ale#statusline#Count(bufnr('%'))
|
||||
|
||||
Before:
|
||||
let g:ale_buffer_count_map = {'44': [1, 2]}
|
||||
|
||||
After:
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
|
||||
Execute (Count should read data from the cache):
|
||||
AssertEqual [1, 2], ale#statusline#Count(44)
|
||||
|
||||
Execute (Update the cache with new data):
|
||||
call ale#statusline#Update(44, [])
|
||||
|
||||
Then (The cache should reflect the new data):
|
||||
AssertEqual [0, 0], ale#statusline#Count(44)
|
||||
|
||||
Before:
|
||||
let g:ale_buffer_loclist_map = {'1': [{'lnum': 1, 'bufnr': 1, 'vcol': 0, 'linter_name': 'testlinter', 'nr': -1, 'type': 'E', 'col': 1, 'text': 'Test Error'}]}
|
||||
|
||||
After:
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
|
||||
Execute (Count should be match the loclist):
|
||||
AssertEqual [1, 0], ale#statusline#Count(1)
|
||||
|
||||
Execute (Output should be empty for non-existant buffer):
|
||||
AssertEqual [0, 0], ale#statusline#Count(9001)
|
||||
|
||||
Before:
|
||||
let g:ale_statusline_format = ['%sE', '%sW', 'OKIE']
|
||||
|
||||
After:
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
|
||||
Execute (Given some errors):
|
||||
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}])
|
||||
|
||||
Then (Statusline is formatted to the users preference):
|
||||
AssertEqual '2E', ale#statusline#Status()
|
||||
|
||||
Execute (Given some warnings):
|
||||
call ale#statusline#Update(bufnr('%'), [{'type': 'W'}, {'type': 'W'}, {'type': 'W'}])
|
||||
|
||||
Then (Statusline is formatted to the users preference):
|
||||
AssertEqual '3W', ale#statusline#Status()
|
||||
|
||||
Execute (Given some warnings, and errors.):
|
||||
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'W'}, {'type': 'W'}])
|
||||
|
||||
Then (Statusline is formatted to the users preference):
|
||||
AssertEqual '1E 2W', ale#statusline#Status()
|
||||
|
||||
Execute (Given a lack of data):
|
||||
call ale#statusline#Update(bufnr('%'), [])
|
||||
|
||||
Then (Statusline is formatted to the users preference):
|
||||
AssertEqual 'OKIE', ale#statusline#Status()
|
||||
@@ -7,11 +7,14 @@ Before:
|
||||
|
||||
After:
|
||||
augroup! VaderTest
|
||||
let g:ale_buffer_info = {}
|
||||
|
||||
Given vim (Vimscript):
|
||||
Given vim (Some vimscript):
|
||||
set nocompatible
|
||||
Execute (Run ALE):
|
||||
|
||||
Execute (Lint it):
|
||||
call ale#Lint()
|
||||
call ale#engine#WaitForJobs(2000)
|
||||
Then (Autocommand should have run):
|
||||
|
||||
Then (Autocommands should have run):
|
||||
AssertEqual g:success, 1
|
||||
|
||||
@@ -1,32 +1,15 @@
|
||||
Before:
|
||||
let g:buffer = bufnr('%')
|
||||
let g:ale_buffer_count_map = {
|
||||
\ g:buffer: [1, 1],
|
||||
\ 10347: [1, 1],
|
||||
\}
|
||||
let g:ale_buffer_loclist_map = {
|
||||
\ g:buffer : [],
|
||||
\ 10347: [],
|
||||
\}
|
||||
let g:ale_buffer_should_reset_map = {
|
||||
\ g:buffer : 1,
|
||||
\ 10347: 1,
|
||||
\}
|
||||
let g:ale_buffer_sign_dummy_map = {
|
||||
\ g:buffer : 1,
|
||||
\ 10347: 1,
|
||||
|
||||
let g:ale_buffer_info = {
|
||||
\ g:buffer : {},
|
||||
\ 10347: {},
|
||||
\}
|
||||
|
||||
After:
|
||||
unlet! g:buffer
|
||||
let g:ale_buffer_count_map = {}
|
||||
let g:ale_buffer_loclist_map = {}
|
||||
let g:ale_buffer_should_reset_map = {}
|
||||
let g:ale_buffer_sign_dummy_map = {}
|
||||
let g:ale_buffer_info = {}
|
||||
|
||||
Execute('ALE globals should be cleared when the buffer is closed.'):
|
||||
:q!
|
||||
AssertEqual {10347: [1, 1]}, g:ale_buffer_count_map
|
||||
AssertEqual {10347: []}, g:ale_buffer_loclist_map
|
||||
AssertEqual {10347: 1}, g:ale_buffer_should_reset_map
|
||||
AssertEqual {10347: 1}, g:ale_buffer_sign_dummy_map
|
||||
AssertEqual {10347: {}}, g:ale_buffer_info
|
||||
|
||||
61
test/test_command_chain.vader
Normal file
61
test/test_command_chain.vader
Normal file
@@ -0,0 +1,61 @@
|
||||
Before:
|
||||
let g:linter_output = []
|
||||
let g:first_echo_called = 0
|
||||
let g:second_echo_called = 0
|
||||
let g:final_callback_called = 0
|
||||
|
||||
function! CollectResults(buffer, output)
|
||||
let g:final_callback_called = 1
|
||||
let g:linter_output = a:output
|
||||
return []
|
||||
endfunction
|
||||
function! RunFirstEcho(buffer)
|
||||
let g:first_echo_called = 1
|
||||
|
||||
return 'echo foo'
|
||||
endfunction
|
||||
function! RunSecondEcho(buffer, output)
|
||||
let g:second_echo_called = 1
|
||||
|
||||
return 'echo bar'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('foobar', {
|
||||
\ 'name': 'testlinter',
|
||||
\ 'callback': 'CollectResults',
|
||||
\ 'executable': 'echo',
|
||||
\ 'command_chain': [
|
||||
\ {
|
||||
\ 'callback': 'RunFirstEcho',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ },
|
||||
\ {
|
||||
\ 'callback': 'RunSecondEcho',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ },
|
||||
\ ],
|
||||
\})
|
||||
|
||||
After:
|
||||
unlet! g:first_echo_called
|
||||
unlet! g:second_echo_called
|
||||
unlet! g:final_callback_called
|
||||
unlet! g:linter_output
|
||||
let g:ale_buffer_info = {}
|
||||
call ale#linter#Reset()
|
||||
delfunction CollectResults
|
||||
delfunction RunFirstEcho
|
||||
delfunction RunSecondEcho
|
||||
|
||||
Given foobar (Some imaginary filetype):
|
||||
anything
|
||||
|
||||
Execute(Check the results of running the chain):
|
||||
AssertEqual 'foobar', &filetype
|
||||
call ale#Lint()
|
||||
call ale#engine#WaitForJobs(2000)
|
||||
|
||||
Assert g:first_echo_called, 'The first chain item was not called'
|
||||
Assert g:second_echo_called, 'The second chain item was not called'
|
||||
Assert g:final_callback_called, 'The final callback was not called'
|
||||
AssertEqual ['bar'], g:linter_output
|
||||
@@ -26,6 +26,34 @@ Then (The loclist should be correct):
|
||||
\ },
|
||||
\], g:loclist
|
||||
|
||||
Execute (Run HandlePEP8Format):
|
||||
let g:loclist = ale#handlers#HandlePEP8Format(42, [
|
||||
\ "stdin:6:6: E111 indentation is not a multiple of four",
|
||||
\ "test.yml:35: [EANSIBLE0002] Trailing whitespace",
|
||||
\])
|
||||
|
||||
Then (The loclist should be correct):
|
||||
AssertEqual [
|
||||
\ {
|
||||
\ 'bufnr': 42,
|
||||
\ 'vcol': 0,
|
||||
\ 'nr': -1,
|
||||
\ 'lnum': 6,
|
||||
\ 'col': 6,
|
||||
\ 'type': 'E',
|
||||
\ 'text': 'E111: indentation is not a multiple of four',
|
||||
\ },
|
||||
\ {
|
||||
\ 'bufnr': 42,
|
||||
\ 'vcol': 0,
|
||||
\ 'nr': -1,
|
||||
\ 'lnum': 35,
|
||||
\ 'col': 0,
|
||||
\ 'type': 'E',
|
||||
\ 'text': "EANSIBLE0002: Trailing whitespace",
|
||||
\ },
|
||||
\], g:loclist
|
||||
|
||||
Execute (Run HandleGCCFormat):
|
||||
let g:loclist = ale#handlers#HandleGCCFormat(42, [
|
||||
\ '<stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]',
|
||||
@@ -58,6 +86,7 @@ Execute (Run HandleUnixFormatAsError):
|
||||
let g:loclist = ale#handlers#HandleUnixFormatAsError(42, [
|
||||
\ 'file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args',
|
||||
\ 'file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)',
|
||||
\ 'test.pug:1:1 ".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.',
|
||||
\])
|
||||
|
||||
Then (The loclist should be correct):
|
||||
@@ -80,6 +109,15 @@ Then (The loclist should be correct):
|
||||
\ 'type': 'E',
|
||||
\ 'text': 'if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)',
|
||||
\ },
|
||||
\ {
|
||||
\ 'bufnr': 42,
|
||||
\ 'vcol': 0,
|
||||
\ 'nr': -1,
|
||||
\ 'lnum': 1,
|
||||
\ 'col': 1,
|
||||
\ 'type': 'E',
|
||||
\ 'text': '".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.',
|
||||
\ },
|
||||
\], g:loclist
|
||||
|
||||
Execute (Run HandleUnixFormatAsWarning):
|
||||
@@ -138,5 +176,33 @@ Then (The loclist should be correct):
|
||||
\ },
|
||||
\], g:loclist
|
||||
|
||||
Execute (Run HandleCppCheckFormat):
|
||||
let g:loclist = ale#handlers#HandleCppCheckFormat(42, [
|
||||
\ '[/tmp/test.c:5]: (style) Variable a is assigned a value that is never used.',
|
||||
\ '[/tmp/test.c:12]: (error) Array a[10] accessed at index 10, which is out of bounds.'
|
||||
\])
|
||||
|
||||
Then (The loclist should be correct):
|
||||
AssertEqual [
|
||||
\ {
|
||||
\ 'bufnr': 42,
|
||||
\ 'vcol': 0,
|
||||
\ 'nr': -1,
|
||||
\ 'lnum': 5,
|
||||
\ 'col': 0,
|
||||
\ 'type': 'W',
|
||||
\ 'text': 'Variable a is assigned a value that is never used. (style)',
|
||||
\ },
|
||||
\ {
|
||||
\ 'bufnr': 42,
|
||||
\ 'vcol': 0,
|
||||
\ 'nr': -1,
|
||||
\ 'lnum': 12,
|
||||
\ 'col': 0,
|
||||
\ 'type': 'E',
|
||||
\ 'text': 'Array a[10] accessed at index 10, which is out of bounds. (error)',
|
||||
\ },
|
||||
\], g:loclist
|
||||
|
||||
After:
|
||||
unlet g:loclist
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user