mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 20:54:26 +08:00
Compare commits
172 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5582711680 | ||
|
|
822b19ac83 | ||
|
|
b3f6f56745 | ||
|
|
a5ac3e4e4b | ||
|
|
3ca4c7de96 | ||
|
|
9f3cdf8270 | ||
|
|
59b5644fb3 | ||
|
|
18bae7da2e | ||
|
|
c59204b94f | ||
|
|
3e13e10e03 | ||
|
|
2d1d6fb850 | ||
|
|
6550cdfbd0 | ||
|
|
551d53aa67 | ||
|
|
5122dc498d | ||
|
|
51729346bf | ||
|
|
297bc8553c | ||
|
|
e7d32fe376 | ||
|
|
790c614b7a | ||
|
|
d19a35485f | ||
|
|
5836d9a9a7 | ||
|
|
6f0fc965ab | ||
|
|
fae26369d4 | ||
|
|
3f3d8b0014 | ||
|
|
e969d97843 | ||
|
|
711ab99362 | ||
|
|
382e569f66 | ||
|
|
f25a543260 | ||
|
|
a4ae5ca997 | ||
|
|
f3eab445ee | ||
|
|
4bf6784d7d | ||
|
|
ca78e4c150 | ||
|
|
892fff03cc | ||
|
|
d58a18b8ed | ||
|
|
c2ceb9e085 | ||
|
|
7d6b313065 | ||
|
|
bd07d04670 | ||
|
|
3b981e22cc | ||
|
|
587360e760 | ||
|
|
3cababc83b | ||
|
|
fc072a0772 | ||
|
|
ad49846a48 | ||
|
|
1c3f0b1e19 | ||
|
|
21caf54543 | ||
|
|
b487c62130 | ||
|
|
b3ab89ac15 | ||
|
|
663d8f832f | ||
|
|
75a2dc5ff5 | ||
|
|
70fb1606ad | ||
|
|
f659d97504 | ||
|
|
be57b545b7 | ||
|
|
76df2d393b | ||
|
|
c1947d13cf | ||
|
|
fb8df75ac3 | ||
|
|
9e9e15bc87 | ||
|
|
2750c605c1 | ||
|
|
da8a0f25cc | ||
|
|
1f211dbe3e | ||
|
|
7030758da6 | ||
|
|
edc5dee226 | ||
|
|
ae88263f0f | ||
|
|
f5ddc51d85 | ||
|
|
969274ccc2 | ||
|
|
0e50a7d278 | ||
|
|
fab9e8f5ea | ||
|
|
79f18e7d87 | ||
|
|
70711022db | ||
|
|
18508f7453 | ||
|
|
6befe9e37c | ||
|
|
f578c4a792 | ||
|
|
4fa52fd98a | ||
|
|
ceeff6c723 | ||
|
|
31d328b272 | ||
|
|
7a92c3a046 | ||
|
|
b2fe1b2567 | ||
|
|
f1e80b800c | ||
|
|
9c93e79a66 | ||
|
|
b5e603bbc5 | ||
|
|
f48f306ab9 | ||
|
|
c2c6c9f491 | ||
|
|
fef3276f34 | ||
|
|
6a02c5812c | ||
|
|
c310080359 | ||
|
|
1a9c8b8d06 | ||
|
|
884109c6f4 | ||
|
|
3c4af280f0 | ||
|
|
3786322cf0 | ||
|
|
8eca101fd1 | ||
|
|
677e55df0f | ||
|
|
cca0222cf1 | ||
|
|
a18e172a96 | ||
|
|
06fe8a043f | ||
|
|
b21ca4ed4e | ||
|
|
bdbf36991d | ||
|
|
5041246c0e | ||
|
|
eac0a41ae1 | ||
|
|
843370b96f | ||
|
|
ca17b5aebd | ||
|
|
3a2286a1b8 | ||
|
|
434ff01f59 | ||
|
|
8c3c84c45e | ||
|
|
406d784f7a | ||
|
|
a7272466f7 | ||
|
|
c4afd72792 | ||
|
|
8c758e339c | ||
|
|
9e7034c6e2 | ||
|
|
b2241e991b | ||
|
|
732e8a813f | ||
|
|
ba1eb90212 | ||
|
|
903a6dc885 | ||
|
|
c49819e892 | ||
|
|
cb60a2c06e | ||
|
|
2e7050dbe2 | ||
|
|
721a850e21 | ||
|
|
7ef1d485fe | ||
|
|
14679f0bd4 | ||
|
|
0131526261 | ||
|
|
ed370667c8 | ||
|
|
c460602cbb | ||
|
|
4afa415bd9 | ||
|
|
78135103fb | ||
|
|
68b6be57f1 | ||
|
|
afd0730248 | ||
|
|
810e420510 | ||
|
|
f39e88cfa8 | ||
|
|
c0814934af | ||
|
|
0589022c76 | ||
|
|
f6bc73b749 | ||
|
|
a5ec5366c4 | ||
|
|
f9815fcdef | ||
|
|
a2f59049dc | ||
|
|
5cdd1498b4 | ||
|
|
3aa1d57b57 | ||
|
|
a995daa827 | ||
|
|
83b46f66f8 | ||
|
|
f0bd08ec11 | ||
|
|
4e082b9217 | ||
|
|
820896315d | ||
|
|
ed269b8831 | ||
|
|
355608b031 | ||
|
|
4a71638061 | ||
|
|
341ea5f367 | ||
|
|
112f71fb17 | ||
|
|
8c4846b68a | ||
|
|
3551bde012 | ||
|
|
2078255ec3 | ||
|
|
ecbb276805 | ||
|
|
c33602534e | ||
|
|
beeef28b1a | ||
|
|
03ab963d1a | ||
|
|
88192e8662 | ||
|
|
8ad85858b8 | ||
|
|
2ba2aff65e | ||
|
|
4737e09bcf | ||
|
|
14c38cdb63 | ||
|
|
81779e60bb | ||
|
|
49f7ce4f6d | ||
|
|
926cd1a953 | ||
|
|
c528ab1eaa | ||
|
|
5bda827143 | ||
|
|
d3e7d3d5e7 | ||
|
|
5de445c041 | ||
|
|
9f8c76b5b9 | ||
|
|
38d9802d12 | ||
|
|
b0190fd080 | ||
|
|
d8efd4fa73 | ||
|
|
6dfed8576e | ||
|
|
943fe9b4b0 | ||
|
|
f67cf17070 | ||
|
|
119695bd08 | ||
|
|
69ce8502a4 | ||
|
|
1da187a6e5 | ||
|
|
ff096124c6 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -5,3 +5,4 @@
|
||||
/README.md export-ignore
|
||||
/img export-ignore
|
||||
/test export-ignore
|
||||
/custom-checks export-ignore
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
3. [Creating Pull Requests](#pull-requests)
|
||||
1. [Adding a New Linter](#adding-a-new-linter)
|
||||
2. [Adding New Options](#adding-new-options)
|
||||
4. [Writing Documentation](#writing-documentation)
|
||||
1. [Documenting New Linters](#documenting-new-linters)
|
||||
2. [Editing the Online Documentation](#editing-online-documentation)
|
||||
3. [Documenting Linter Options](#documenting-new-options)
|
||||
5. [In Case of Busses](#in-case-of-busses)
|
||||
|
||||
<a name="guidelines"></a>
|
||||
|
||||
@@ -12,6 +17,12 @@
|
||||
|
||||
Have fun, and work on whatever floats your boat. Take It Easy :tm:.
|
||||
|
||||
Don't forget to **write documentation** for whatever it is you are doing.
|
||||
See the ["Writing Documentation"](#writing-documentation) section.
|
||||
|
||||
Remember to write Vader tests for most of the code you write. You can look at
|
||||
existing Vader tests in the `test` directory for examples.
|
||||
|
||||
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
|
||||
@@ -90,3 +101,73 @@ global variable names.
|
||||
|
||||
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...`.
|
||||
|
||||
<a name="writing-documentation"></a>
|
||||
|
||||
# 4. Writing Documentation
|
||||
|
||||
If you are adding new linters, changing the API, adding new options, etc., you
|
||||
_must_ write some documentation describing it in the `doc/ale.txt` file. New
|
||||
linters _must_ be added to the `README.md` file too, so other users can get a
|
||||
quick overview of the supported tools.
|
||||
|
||||
<a name="documenting-new-linters"></a>
|
||||
|
||||
# 4.i Documenting New Linters
|
||||
|
||||
If you add a new linter to the project, edit the table in the `README.md` file,
|
||||
and edit the list of linters at the top of the `doc/ale.txt` file. The linters
|
||||
should be sorted vertically in lexicographic (alphabetical) order by the
|
||||
programming language name or filetype, and the tools for each language should
|
||||
be sorted in lexicographic order horizontally. Sorting in this manner is a fair
|
||||
manner of presenting all of the information in an easy to scan way, without
|
||||
giving some unfair preference to any particular tool or language.
|
||||
|
||||
<a name="editing-online-documentation"></a>
|
||||
|
||||
# 4.ii Editing the Online Documentation
|
||||
|
||||
The "online documentation" file used for this project lives in `doc/ale.txt`.
|
||||
This is the file used for generating `:help` text inside Vim itself. There are
|
||||
some guidlines to follow for this file.
|
||||
|
||||
1. Keep all text within a column size of 79 characters, inclusive.
|
||||
2. Open a section with 79 `=` or `-` characters, for headings and subheadings.
|
||||
3. Sections should have a _single_ blank line before or after.
|
||||
4. Between descriptions of variables/functions/commands, use _two_ blank lines.
|
||||
5. Up-indent the description of a variable/function/command by two spaces.
|
||||
6. Place tags at the ends of lines, with the final characters on column 79.
|
||||
All of the tags should line up perfectly on the same column as you scan
|
||||
down through the document.
|
||||
7. Keep the table of contents balanced so the longest tag link ends on column
|
||||
79, and so all links line up perfectly on their first character, on the
|
||||
left.
|
||||
|
||||
<a name="documenting-linter-options"></a>
|
||||
|
||||
# 4.iii Documenting Linter Options
|
||||
|
||||
For documenting new linter options, please add a new sub-section under the
|
||||
"Linter Specific Options" section describing all of the global options added
|
||||
for each linter, and what the default values of the options are. All global
|
||||
options for linters should be set to some default value. This will allow users
|
||||
to look up the default value easily by typing `:echo g:ale_...`.
|
||||
|
||||
<a name="in-case-of-busses"></a>
|
||||
|
||||
# 5. In Case of Busses
|
||||
|
||||
Should the principal author of the ALE project and all collaborators with the
|
||||
required access needed to properly administrate the project on GitHub or any
|
||||
other website either perish or disappear, whether by tragic traffic accident
|
||||
or government adduction, etc., action should be taken to ensure that the
|
||||
project continues. If no one is left to administer the project where it is
|
||||
hosted, please fork the project and nominate someone capable to administer it.
|
||||
Preferably, in such an event, a single fork of the project will replace the
|
||||
original, and life will go on, except the life of whoever vanished, because
|
||||
then they will probably be dead.
|
||||
|
||||
Should w0rp suddenly disappear, then he was probably killed in a traffic
|
||||
accident, or the government finally decided to kill him and make it look like
|
||||
suicide. In the latter event, please subvert said government and restore
|
||||
order to the universe, and ensure peace for mankind.
|
||||
|
||||
10
ISSUE_TEMPLATE.md
Normal file
10
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,10 @@
|
||||
For bugs, paste output from your clipboard after running :ALEInfoToClipboard
|
||||
here. If that doesn't work for some reason, try running :ALEInfo and copying
|
||||
the output from that here instead. If everything is broken, run around in
|
||||
circles and scream.
|
||||
|
||||
If you are experiencing a bug where ALE is not correctly parsing the output of
|
||||
commands, set g:ale_history_log_output to 1, and run ALE again, and then
|
||||
:ALEInfo should include the full output of each command which ran.
|
||||
|
||||
Whatever the case, describe the your issue here.
|
||||
11
Makefile
11
Makefile
@@ -2,11 +2,20 @@ SHELL := /usr/bin/env bash
|
||||
IMAGE ?= w0rp/ale
|
||||
CURRENT_IMAGE_ID = 107e4efc4267
|
||||
DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)"
|
||||
tests = test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*/*.vader
|
||||
|
||||
test-setup:
|
||||
docker images -q w0rp/ale | grep ^$(CURRENT_IMAGE_ID) > /dev/null || \
|
||||
docker pull $(IMAGE)
|
||||
|
||||
vader: test-setup
|
||||
@:; \
|
||||
vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \
|
||||
if [ -z "$$vims" ]; then echo "No Vims found!"; exit 1; fi; \
|
||||
for vim in $$vims; do \
|
||||
docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! $(tests)'; \
|
||||
done
|
||||
|
||||
test: test-setup
|
||||
@:; \
|
||||
vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \
|
||||
@@ -18,7 +27,7 @@ test: test-setup
|
||||
echo "Running tests for $$vim"; \
|
||||
echo '========================================'; \
|
||||
echo; \
|
||||
docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! test/*' || EXIT=$$?; \
|
||||
docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! $(tests)' || EXIT=$$?; \
|
||||
done; \
|
||||
echo; \
|
||||
echo '========================================'; \
|
||||
|
||||
132
README.md
132
README.md
@@ -23,7 +23,8 @@ In other words, this plugin allows you to lint while you type.
|
||||
1. [Installation with Pathogen](#installation-with-pathogen)
|
||||
2. [Installation with Vundle](#installation-with-vundle)
|
||||
3. [Manual Installation](#manual-installation)
|
||||
4. [FAQ](#faq)
|
||||
4. [Contributing](#contributing)
|
||||
5. [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)
|
||||
@@ -33,6 +34,8 @@ In other words, this plugin allows you to lint while you type.
|
||||
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)
|
||||
10. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
|
||||
11. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
|
||||
|
||||
<a name="supported-languages"></a>
|
||||
|
||||
@@ -50,12 +53,14 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| Language | Tools |
|
||||
| -------- | ----- |
|
||||
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) |
|
||||
| AsciiDoc | [proselint](http://proselint.com/)|
|
||||
| Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) |
|
||||
| Bourne Shell | [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/) |
|
||||
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
|
||||
| C++ (filetype cpp) | [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
|
||||
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
|
||||
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
|
||||
| Chef | [foodcritic](http://www.foodcritic.io/) |
|
||||
| CMake | [cmakelint](https://github.com/richq/cmake-lint) |
|
||||
| CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
|
||||
| CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) |
|
||||
| Cython (pyrex filetype) | [cython](http://cython.org/) |
|
||||
@@ -66,40 +71,46 @@ name. That seems to be the fairest way to arrange this table.
|
||||
| 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 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/), [flow](https://flowtype.org/) |
|
||||
| Haml | [haml-lint](https://github.com/brigade/haml-lint)
|
||||
| Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) |
|
||||
| HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) |
|
||||
| Java | [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) |
|
||||
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/)
|
||||
| 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) |
|
||||
| Nim | [nim](https://nim-lang.org/docs/nimc.html) |
|
||||
| nix | [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate) |
|
||||
| nroff | [proselint](http://proselint.com/)|
|
||||
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions
|
||||
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
|
||||
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
|
||||
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) |
|
||||
| Pod | [proselint](http://proselint.com/)|
|
||||
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
|
||||
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
|
||||
| Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) |
|
||||
| reStructuredText | [proselint](http://proselint.com/)|
|
||||
| Ruby | [rubocop](https://github.com/bbatsov/rubocop) |
|
||||
| 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) |
|
||||
| Slim | [slim-lint](https://github.com/sds/slim-lint)
|
||||
| SML | [smlnj](http://www.smlnj.org/) |
|
||||
| Swift | [swiftlint](https://swift.org/) |
|
||||
| Tex | [proselint](http://proselint.com/) |
|
||||
| Text^^ | [proselint](http://proselint.com/) |
|
||||
| Texinfo | [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) |
|
||||
| Vim help^ | [proselint](http://proselint.com/)|
|
||||
| XHTML | [proselint](http://proselint.com/)|
|
||||
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
|
||||
|
||||
* *^^ 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 it.
|
||||
* *^ No linters for text or Vim help filetypes are enabled by default.*
|
||||
|
||||
<a name="usage"></a>
|
||||
|
||||
@@ -189,13 +200,27 @@ silent! helptags ALL
|
||||
Because the author of this plugin is a weird nerd, this is his preferred
|
||||
installation method.
|
||||
|
||||
<a name="contributing"></a>
|
||||
|
||||
## 4. Contributing
|
||||
|
||||
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 it.
|
||||
|
||||
If you are interested in the general direction of the project, check out the
|
||||
[wiki home page](https://github.com/w0rp/ale/wiki). The wiki includes a
|
||||
Roadmap for the future, and more.
|
||||
|
||||
<a name="faq"></a>
|
||||
|
||||
## 4. FAQ
|
||||
## 5. FAQ
|
||||
|
||||
<a name="faq-disable-linters"></a>
|
||||
|
||||
### 4.i. How do I disable particular linters?
|
||||
### 5.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
|
||||
@@ -219,7 +244,7 @@ in each directory corresponds to the name of a particular linter.
|
||||
|
||||
<a name="faq-keep-signs"></a>
|
||||
|
||||
### 4.ii. How can I keep the sign gutter open?
|
||||
### 5.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
|
||||
@@ -230,7 +255,7 @@ let g:ale_sign_column_always = 1
|
||||
|
||||
<a name="faq-change-signs"></a>
|
||||
|
||||
### 4.iii. How can I change the signs ALE uses?
|
||||
### 5.iii. How can I change the signs ALE uses?
|
||||
|
||||
Use these options to specify what text should be used for signs:
|
||||
|
||||
@@ -250,7 +275,7 @@ highlight clear ALEWarningSign
|
||||
|
||||
<a name="faq-statusline"></a>
|
||||
|
||||
### 4.iv. How can I show errors or warnings in my statusline?
|
||||
### 5.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
|
||||
@@ -277,7 +302,7 @@ let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
|
||||
|
||||
<a name="faq-echo-format"></a>
|
||||
|
||||
### 4.v. How can I change the format for echo messages?
|
||||
### 5.v. How can I change the format for echo messages?
|
||||
|
||||
There are 3 global options that allow customizing the echoed message.
|
||||
|
||||
@@ -302,7 +327,7 @@ Will give you:
|
||||
|
||||
<a name="faq-autocmd"></a>
|
||||
|
||||
### 4.vi. How can I execute some code when ALE stops linting?
|
||||
### 5.vi. How can I execute some code when ALE stops linting?
|
||||
|
||||
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
|
||||
event whenever has a linter has been successfully executed and processed. This
|
||||
@@ -317,7 +342,7 @@ augroup END
|
||||
|
||||
<a name="faq-navigation"></a>
|
||||
|
||||
### 4.vii. How can I navigate between errors quickly?
|
||||
### 5.vii. How can I navigate between errors quickly?
|
||||
|
||||
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
|
||||
@@ -333,7 +358,7 @@ For more information, consult the online documentation with
|
||||
|
||||
<a name="faq-lint-on-save"></a>
|
||||
|
||||
### 4.viii. How can I run linters only when I save files?
|
||||
### 5.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
|
||||
@@ -351,7 +376,7 @@ 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?
|
||||
### 5.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
|
||||
@@ -375,3 +400,62 @@ let g:ale_open_list = 1
|
||||
" some other plugin which sets quickfix errors, etc.
|
||||
let g:ale_keep_list_window_open = 1
|
||||
```
|
||||
|
||||
<a name="faq-jsx-stylelint-eslint"></a>
|
||||
|
||||
### 5.x. How can I check JSX files with both stylelint and eslint?
|
||||
|
||||
If you configure ALE options correctly in your vimrc file, and install
|
||||
the right tools, you can check JSX files with stylelint and eslint.
|
||||
|
||||
First, install eslint and install stylelint with
|
||||
[https://github.com/styled-components/stylelint-processor-styled-components](stylelint-processor-styled-components).
|
||||
|
||||
Supposing you have installed both tools correctly, configure your .jsx files so
|
||||
`jsx` is included in the filetype. You can use an `autocmd` for this.
|
||||
|
||||
```vim
|
||||
augroup FiletypeGroup
|
||||
autocmd!
|
||||
au BufNewFile,BufRead *.jsx set filetype=javascript.jsx
|
||||
augroup END
|
||||
```
|
||||
|
||||
Supposing the filetype has been set correctly, you can set the following
|
||||
options in your vimrc file:
|
||||
|
||||
```vim
|
||||
let g:ale_linters = {'jsx': ['stylelint', 'eslint']}
|
||||
let g:ale_linter_aliases = {'jsx': 'css'}
|
||||
```
|
||||
|
||||
ALE will alias the `jsx` filetype so it uses the `css` filetype linters, and
|
||||
use the original Array of selected linters for `jsx` from the `g:ale_linters`
|
||||
object. All available linters will be used for the filetype `javascript`, and
|
||||
no linter will be run twice for the same file.
|
||||
|
||||
<a name="faq-my-battery-is-sad"></a>
|
||||
|
||||
### 5.xi. Will this plugin eat all of my laptop battery power?
|
||||
|
||||
ALE takes advantage of the power of various tools to check your code. This of
|
||||
course means that CPU time will be used to continuously check your code. If you
|
||||
are concerned about the CPU time ALE will spend, which will of course imply
|
||||
some cost to battery life, you can adjust your settings to make your CPU do
|
||||
less work.
|
||||
|
||||
First, consider increasing the delay before which ALE will run any linters
|
||||
while you type. ALE uses a timeout which is cancelled and reset every time you
|
||||
type, and this delay can be increased so linters are run less often. See
|
||||
`:help g:ale_lint_delay` for more information.
|
||||
|
||||
If you don't wish to run linters while you type, you can disable that
|
||||
behaviour. Set `g:ale_lint_on_text_changed` to `0`, and consider setting
|
||||
`g:ale_lint_on_save` to `1` to enable linting when you save files. You won't
|
||||
get as frequent error checking, but ALE shouldn't block your ability to edit a
|
||||
document after you save a file, so the asynchronous nature of the plugin will
|
||||
still be an advantage.
|
||||
|
||||
If you are still concerned, you can turn the automatic linting off altogether,
|
||||
including the option `g:ale_lint_on_enter`, and you can run ALE manually with
|
||||
`:call ale#Lint()`.
|
||||
|
||||
28
after/plugin/ale.vim
Normal file
28
after/plugin/ale.vim
Normal file
@@ -0,0 +1,28 @@
|
||||
if exists('g:loaded_ale_after')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_after = 1
|
||||
|
||||
if !g:ale_emit_conflict_warnings
|
||||
finish
|
||||
endif
|
||||
|
||||
function! s:GetConflictingPluginWarning(plugin_name) abort
|
||||
return 'ALE conflicts with ' . a:plugin_name
|
||||
\ . '. Uninstall it, or disable this warning with '
|
||||
\ . '`let g:ale_emit_conflict_warnings = 0` in your vimrc file, '
|
||||
\ . '*before* plugins are loaded.'
|
||||
endfunction
|
||||
|
||||
if exists('g:loaded_syntastic_plugin')
|
||||
throw s:GetConflictingPluginWarning('Syntastic')
|
||||
endif
|
||||
|
||||
if exists('g:loaded_neomake')
|
||||
throw s:GetConflictingPluginWarning('Neomake')
|
||||
endif
|
||||
|
||||
if exists('g:loaded_validator_plugin')
|
||||
throw s:GetConflictingPluginWarning('Validator')
|
||||
endif
|
||||
@@ -4,6 +4,6 @@
|
||||
call ale#linter#Define('ansible', {
|
||||
\ 'name': 'ansible',
|
||||
\ 'executable': 'ansible',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .yml ansible-lint -p',
|
||||
\ 'command': 'ansible-lint -p %t',
|
||||
\ 'callback': 'ale#handlers#HandlePEP8Format',
|
||||
\})
|
||||
|
||||
9
ale_linters/asciidoc/proselint.vim
Normal file
9
ale_linters/asciidoc/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for AsciiDoc files
|
||||
|
||||
call ale#linter#Define('asciidoc', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -9,12 +9,18 @@ if !exists('g:ale_c_clang_options')
|
||||
let g:ale_c_clang_options = '-std=c11 -Wall'
|
||||
endif
|
||||
|
||||
function! ale_linters#c#clang#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang -S -x c -fsyntax-only '
|
||||
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ' ' . g:ale_c_clang_options . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang',
|
||||
\ 'command': 'clang -S -x c -fsyntax-only '
|
||||
\ . g:ale_c_clang_options
|
||||
\ . ' -',
|
||||
\ 'command_callback': 'ale_linters#c#clang#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
" 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
|
||||
let g:ale_c_cppcheck_options = get(g:, 'ale_c_cppcheck_options', '--enable=style')
|
||||
|
||||
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,
|
||||
\ 'command': 'cppcheck -q --language=c '
|
||||
\ . g:ale_c_cppcheck_options
|
||||
\ . ' %t',
|
||||
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
|
||||
\})
|
||||
|
||||
@@ -10,9 +10,11 @@ if !exists('g:ale_c_gcc_options')
|
||||
endif
|
||||
|
||||
function! ale_linters#c#gcc#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'gcc -S -x c -fsyntax-only '
|
||||
\ . g:ale_c_gcc_options . ' -'
|
||||
|
||||
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ' ' . g:ale_c_gcc_options . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
|
||||
@@ -21,11 +21,9 @@ function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -35,7 +33,7 @@ endfunction
|
||||
call ale#linter#Define('chef', {
|
||||
\ 'name': 'foodcritic',
|
||||
\ 'executable': 'foodcritic',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .rb foodcritic',
|
||||
\ 'command': 'foodcritic %t',
|
||||
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
|
||||
\})
|
||||
|
||||
|
||||
24
ale_linters/cmake/cmakelint.vim
Normal file
24
ale_linters/cmake/cmakelint.vim
Normal file
@@ -0,0 +1,24 @@
|
||||
" Author: Kenneth Benzie <k.benzie83@gmail.com>
|
||||
" Description: cmakelint for cmake files
|
||||
|
||||
let g:ale_cmake_cmakelint_executable =
|
||||
\ get(g:, 'ale_cmake_cmakelint_executable', 'cmakelint')
|
||||
|
||||
let g:ale_cmake_cmakelint_options =
|
||||
\ get(g:, 'ale_cmake_cmakelint_options', '')
|
||||
|
||||
function! ale_linters#cmake#cmakelint#Executable(buffer) abort
|
||||
return g:ale_cmake_cmakelint_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cmake#cmakelint#Command(buffer) abort
|
||||
return ale_linters#cmake#cmakelint#Executable(a:buffer)
|
||||
\ . ' ' . g:ale_cmake_cmakelint_options . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cmake', {
|
||||
\ 'name': 'cmakelint',
|
||||
\ 'executable_callback': 'ale_linters#cmake#cmakelint#Executable',
|
||||
\ 'command_callback': 'ale_linters#cmake#cmakelint#Command',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -1,10 +1,23 @@
|
||||
" Author: KabbAmine - https://github.com/KabbAmine
|
||||
" Description: Coffee for checking coffee files
|
||||
|
||||
function! ale_linters#coffee#coffee#GetExecutable(buffer) abort
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/coffee',
|
||||
\ 'coffee'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#coffee#coffee#GetCommand(buffer) abort
|
||||
return ale_linters#coffee#coffee#GetExecutable(a:buffer)
|
||||
\ . ' -cp -s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('coffee', {
|
||||
\ 'name': 'coffee',
|
||||
\ 'executable': 'coffee',
|
||||
\ 'command': 'coffee -cp -s',
|
||||
\ 'executable_callback': 'ale_linters#coffee#coffee#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#coffee#coffee#GetCommand',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
" Author: Prashanth Chandra https://github.com/prashcr
|
||||
" Description: coffeelint linter for coffeescript files
|
||||
|
||||
function! ale_linters#coffee#coffeelint#GetExecutable(buffer) abort
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/coffeelint',
|
||||
\ 'coffeelint'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#coffee#coffeelint#GetCommand(buffer) abort
|
||||
return ale_linters#coffee#coffeelint#GetExecutable(a:buffer)
|
||||
\ . ' --stdin --reporter csv'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
@@ -8,7 +21,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
|
||||
" stdin,14,,error,Throwing strings is forbidden
|
||||
"
|
||||
" Note that we currently ignore lineNumberEnd for multiline errors
|
||||
let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\+\),\(.\+\)'
|
||||
let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\{-1,}\),\(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -27,11 +40,9 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -40,7 +51,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('coffee', {
|
||||
\ 'name': 'coffeelint',
|
||||
\ 'executable': 'coffeelint',
|
||||
\ 'command': 'coffeelint --stdin --reporter csv',
|
||||
\ 'executable_callback': 'ale_linters#coffee#coffeelint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#coffee#coffeelint#GetCommand',
|
||||
\ 'callback': 'ale_linters#coffee#coffeelint#Handle',
|
||||
\})
|
||||
|
||||
23
ale_linters/cpp/clang.vim
Normal file
23
ale_linters/cpp/clang.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
" Author: Tomota Nakamura <https://github.com/tomotanakamura>
|
||||
" Description: clang linter for cpp files
|
||||
|
||||
" Set this option to change the Clang options for warnings for CPP.
|
||||
if !exists('g:ale_cpp_clang_options')
|
||||
let g:ale_cpp_clang_options = '-std=c++14 -Wall'
|
||||
endif
|
||||
|
||||
function! ale_linters#cpp#clang#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang++ -S -x c++ -fsyntax-only '
|
||||
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ' ' . g:ale_cpp_clang_options . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'clang++',
|
||||
\ 'command_callback': 'ale_linters#cpp#clang#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
18
ale_linters/cpp/clangtidy.vim
Normal file
18
ale_linters/cpp/clangtidy.vim
Normal file
@@ -0,0 +1,18 @@
|
||||
" Author: vdeurzen <tim@kompiler.org>, w0rp <devw0rp@gmail.com>
|
||||
" Description: clang-tidy linter for cpp files
|
||||
|
||||
" Set this option to change the clang-tidy options for warnings for C.
|
||||
let g:ale_cpp_clangtidy_options =
|
||||
\ get(g:, 'ale_cpp_clangtidy_options', '-std=c++14 -Wall')
|
||||
|
||||
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
|
||||
return 'clang-tidy %t -- ' . g:ale_cpp_clangtidy_options
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clangtidy',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'clang-tidy',
|
||||
\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
@@ -2,15 +2,14 @@
|
||||
" 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
|
||||
let g:ale_cpp_cppcheck_options = get(g:, 'ale_cpp_cppcheck_options', '--enable=style')
|
||||
|
||||
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,
|
||||
\ 'command': 'cppcheck -q --language=c++ '
|
||||
\ . g:ale_cpp_cppcheck_options
|
||||
\ . ' %t',
|
||||
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
|
||||
\})
|
||||
|
||||
@@ -16,9 +16,11 @@ if !exists('g:ale_cpp_gcc_options')
|
||||
endif
|
||||
|
||||
function! ale_linters#cpp#gcc#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'gcc -S -x c++ -fsyntax-only '
|
||||
\ . g:ale_cpp_gcc_options . ' -'
|
||||
|
||||
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ' ' . g:ale_cpp_gcc_options . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
if !exists('g:ale_cs_mcs_options')
|
||||
let g:ale_cs_mcs_options = ''
|
||||
endif
|
||||
let g:ale_cs_mcs_options = get(g:, 'ale_cs_mcs_options', '')
|
||||
|
||||
function! ale_linters#cs#mcs#GetCommand(buffer) abort
|
||||
return 'mcs -unsafe --parse ' . g:ale_cs_mcs_options . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cs#mcs#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
@@ -19,11 +21,9 @@ function! ale_linters#cs#mcs#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
@@ -31,10 +31,9 @@ function! ale_linters#cs#mcs#Handle(buffer, lines) abort
|
||||
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',
|
||||
\ })
|
||||
|
||||
\ 'name': 'mcs',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'mcs',
|
||||
\ 'command_callback': 'ale_linters#cs#mcs#GetCommand',
|
||||
\ 'callback': 'ale_linters#cs#mcs#Handle',
|
||||
\})
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
call ale#linter#Define('css', {
|
||||
\ 'name': 'csslint',
|
||||
\ 'executable': 'csslint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .css csslint --format=compact',
|
||||
\ 'command': 'csslint --format=compact %t',
|
||||
\ 'callback': 'ale#handlers#HandleCSSLintFormat',
|
||||
\})
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
let g:ale_css_stylelint_executable =
|
||||
\ get(g:, 'ale_css_stylelint_executable', 'stylelint')
|
||||
|
||||
let g:ale_css_stylelint_options =
|
||||
\ get(g:, 'ale_css_stylelint_options', '')
|
||||
|
||||
let g:ale_css_stylelint_use_global =
|
||||
\ get(g:, 'ale_css_stylelint_use_global', 0)
|
||||
|
||||
@@ -20,6 +23,7 @@ endfunction
|
||||
|
||||
function! ale_linters#css#stylelint#GetCommand(buffer) abort
|
||||
return ale_linters#css#stylelint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_css_stylelint_options
|
||||
\ . ' --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -46,9 +46,7 @@ function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort
|
||||
endif
|
||||
endfor
|
||||
|
||||
return g:ale#util#stdin_wrapper . ' .d dmd '
|
||||
\ . join(l:import_list)
|
||||
\ . ' -o- -vcolumns -c'
|
||||
return 'dmd '. join(l:import_list) . ' -o- -vcolumns -c %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#d#dmd#Handle(buffer, lines) abort
|
||||
@@ -74,11 +72,9 @@ function! ale_linters#d#dmd#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': bufnr('%'),
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type ==# 'Warning' ? 'W' : 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:lnum,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:text,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
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.
|
||||
let l:pattern = '\v^stdin:(\d+):?(\d+)?: (.): (.+)$'
|
||||
" lib/filename.ex:19:7: F: Pipe chain should start with a raw value.
|
||||
let l:pattern = '\v:(\d+):?(\d+)?: (.): (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -27,11 +27,9 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:text,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -41,5 +39,5 @@ endfunction
|
||||
call ale#linter#Define('elixir', {
|
||||
\ 'name': 'credo',
|
||||
\ 'executable': 'mix',
|
||||
\ 'command': 'mix credo suggest --format=flycheck --read-from-stdin',
|
||||
\ 'command': 'mix credo suggest --format=flycheck --read-from-stdin %s',
|
||||
\ 'callback': 'ale_linters#elixir#credo#Handle' })
|
||||
|
||||
@@ -22,11 +22,10 @@ function! ale_linters#elm#make#Handle(buffer, lines) abort
|
||||
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,
|
||||
\ 'detail': l:error.overview . "\n\n" . l:error.details
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
@@ -52,9 +51,8 @@ function! ale_linters#elm#make#GetCommand(buffer) abort
|
||||
" 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
|
||||
return l:dir_set_cmd . ' ' . l:elm_cmd . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('elm', {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
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
|
||||
let l:output_file = tempname()
|
||||
call ale#engine#ManageFile(a:buffer, l:output_file)
|
||||
return 'erlc -o ' . fnameescape(l:output_file) . ' ' . g:ale_erlang_erlc_options . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
@@ -43,11 +45,9 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': 'E',
|
||||
\ 'text': l:match_parse_transform[0],
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
|
||||
continue
|
||||
@@ -77,11 +77,9 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 0,
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:text,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
|
||||
"
|
||||
" :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 = {}
|
||||
@@ -41,9 +41,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
|
||||
let l:last_loclist_obj = {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'nr': -1,
|
||||
\}
|
||||
|
||||
" Start looking for the message and error type.
|
||||
|
||||
@@ -101,6 +101,12 @@ function! ale_linters#go#gobuild#CopyFiles(buffer, golist_output) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gobuild#GetCommand(buffer, copy_output) abort
|
||||
" If for some reason we don't get any output from the last command, stop
|
||||
" here.
|
||||
if empty(a:copy_output)
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:tempdir = a:copy_output[0]
|
||||
let l:importpath = s:PackageImportPath(a:buffer)
|
||||
|
||||
@@ -190,11 +196,9 @@ function! ale_linters#go#gobuild#Handler(buffer, lines) abort
|
||||
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
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ call ale#linter#Define('go', {
|
||||
\ 'name': 'gofmt',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'gofmt',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .go gofmt -e',
|
||||
\ 'command': 'gofmt -e %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'golint',
|
||||
\ 'executable': 'golint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .go golint',
|
||||
\ 'command': 'golint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
|
||||
@@ -5,6 +5,6 @@ call ale#linter#Define('go', {
|
||||
\ 'name': 'go vet',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'go',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .go go vet',
|
||||
\ 'command': 'go vet %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
33
ale_linters/haml/hamllint.vim
Normal file
33
ale_linters/haml/hamllint.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: Patrick Lewis - https://github.com/patricklewis
|
||||
" Description: haml-lint for Haml files
|
||||
|
||||
function! ale_linters#haml#hamllint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" <path>:51 [W] RuboCop: Use the new Ruby 1.9 hash syntax.
|
||||
let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$'
|
||||
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,
|
||||
\ 'type': l:match[2],
|
||||
\ 'text': l:match[3]
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('haml', {
|
||||
\ 'name': 'hamllint',
|
||||
\ 'executable': 'haml-lint',
|
||||
\ 'command': 'haml-lint %t',
|
||||
\ 'callback': 'ale_linters#haml#hamllint#Handle'
|
||||
\})
|
||||
@@ -1,73 +1,18 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: ghc for Haskell files
|
||||
|
||||
if exists('g:loaded_ale_linters_haskell_ghc')
|
||||
finish
|
||||
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_linters#haskell#ghc#Handle',
|
||||
\ 'command': 'ghc -fno-code -v0 %t',
|
||||
\ 'callback': 'ale#handlers#HandleGhcFormat',
|
||||
\})
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'stack-ghc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'stack',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .hs stack ghc -- -fno-code -v0',
|
||||
\ 'callback': 'ale_linters#haskell#ghc#Handle',
|
||||
\ 'command': 'stack ghc -- -fno-code -v0 %t',
|
||||
\ 'callback': 'ale#handlers#HandleGhcFormat',
|
||||
\})
|
||||
|
||||
9
ale_linters/haskell/hdevtools.vim
Normal file
9
ale_linters/haskell/hdevtools.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: rob-b
|
||||
" Description: hdevtools for Haskell files
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'hdevtools',
|
||||
\ 'executable': 'hdevtools',
|
||||
\ 'command': 'hdevtools check -g -Wall -p %s %t',
|
||||
\ 'callback': 'ale#handlers#HandleGhcFormat',
|
||||
\})
|
||||
@@ -11,7 +11,6 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:error.startLine + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:error.startColumn + 0,
|
||||
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
|
||||
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',
|
||||
|
||||
9
ale_linters/help/proselint.vim
Normal file
9
ale_linters/help/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for Vim help files
|
||||
|
||||
call ale#linter#Define('help', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -23,9 +23,9 @@ function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#html#htmlhint#GetCommand(buffer) abort
|
||||
return g:ale#util#stdin_wrapper . ' .html '
|
||||
\ . ale_linters#html#htmlhint#GetExecutable(a:buffer)
|
||||
return ale_linters#html#htmlhint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_html_htmlhint_options
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('html', {
|
||||
|
||||
9
ale_linters/html/proselint.vim
Normal file
9
ale_linters/html/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for HTML files
|
||||
|
||||
call ale#linter#Define('html', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -53,11 +53,9 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
52
ale_linters/java/javac.vim
Normal file
52
ale_linters/java/javac.vim
Normal file
@@ -0,0 +1,52 @@
|
||||
" Author: farenjihn <farenjihn@gmail.com>, w0rp <devw0rp@gmail.com>
|
||||
" Description: Lints java files using javac
|
||||
|
||||
let g:ale_java_javac_options = get(g:, 'ale_java_javac_options', '')
|
||||
let g:ale_java_javac_classpath = get(g:, 'ale_java_javac_classpath', '')
|
||||
|
||||
function! ale_linters#java#javac#GetCommand(buffer) abort
|
||||
let l:cp_option = !empty(g:ale_java_javac_classpath)
|
||||
\ ? '-cp ' . g:ale_java_javac_classpath
|
||||
\ : ''
|
||||
|
||||
return 'javac -Xlint '
|
||||
\ . l:cp_option
|
||||
\ . ' ' . g:ale_java_javac_options
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#javac#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
|
||||
" Main.java:16: error: ';' expected
|
||||
|
||||
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,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:match[2] . ':' . l:match[3],
|
||||
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('java', {
|
||||
\ 'name': 'javac',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'javac',
|
||||
\ 'command_callback': 'ale_linters#java#javac#GetCommand',
|
||||
\ 'callback': 'ale_linters#java#javac#Handle',
|
||||
\})
|
||||
@@ -29,6 +29,21 @@ function! ale_linters#javascript#eslint#GetCommand(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
|
||||
let l:config_error_pattern = '\v^ESLint couldn''t find a configuration file'
|
||||
\ . '|^Cannot read config file'
|
||||
|
||||
" Look for a message in the first few lines which indicates that
|
||||
" a configuration file couldn't be found.
|
||||
for l:line in a:lines[:10]
|
||||
if len(matchlist(l:line, l:config_error_pattern)) > 0
|
||||
return [{
|
||||
\ 'lnum': 1,
|
||||
\ 'text': 'eslint configuration error (type :ALEDetail for more information)',
|
||||
\ 'detail': join(a:lines, "\n"),
|
||||
\}]
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
|
||||
@@ -65,11 +80,9 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
|
||||
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 ==# 'Warning' ? 'W' : 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -8,68 +8,73 @@ 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
|
||||
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
|
||||
\)
|
||||
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'
|
||||
let l:flow_config = ale#util#FindNearestFile(a:buffer, '.flowconfig')
|
||||
|
||||
if empty(l:flow_config)
|
||||
" Don't run Flow if we can't find a .flowconfig file.
|
||||
return ''
|
||||
endif
|
||||
|
||||
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)
|
||||
let l:str = join(a:lines, '')
|
||||
|
||||
if has_key(l:flow_output, 'errors')
|
||||
if l:str ==# ''
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:flow_output = json_decode(l:str)
|
||||
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
|
||||
for l:error in get(l:flow_output, 'errors', [])
|
||||
" Each error is broken up into parts
|
||||
let l:text = ''
|
||||
let l:line = 0
|
||||
let l:col = 0
|
||||
|
||||
if has_key(l:error, 'operation')
|
||||
let l:text = l:text . ' See also: ' . l:error.operation.descr
|
||||
endif
|
||||
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
|
||||
|
||||
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',
|
||||
\})
|
||||
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,
|
||||
\ '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', {
|
||||
|
||||
69
ale_linters/javascript/standard.vim
Normal file
69
ale_linters/javascript/standard.vim
Normal file
@@ -0,0 +1,69 @@
|
||||
" Author: Ahmed El Gabri <@ahmedelgabri>
|
||||
" Description: standardjs for JavaScript files
|
||||
|
||||
let g:ale_javascript_standard_executable =
|
||||
\ get(g:, 'ale_javascript_standard_executable', 'standard')
|
||||
|
||||
let g:ale_javascript_standard_options =
|
||||
\ get(g:, 'ale_javascript_standard_options', '')
|
||||
|
||||
let g:ale_javascript_standard_use_global =
|
||||
\ get(g:, 'ale_javascript_standard_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
|
||||
if g:ale_javascript_standard_use_global
|
||||
return g:ale_javascript_standard_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/standard',
|
||||
\ g:ale_javascript_standard_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#standard#GetCommand(buffer) abort
|
||||
return ale_linters#javascript#standard#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_javascript_standard_options
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#standard#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" /path/to/some-filename.js:47:14: Strings must use singlequote.
|
||||
" /path/to/some-filename.js:56:41: Expected indentation of 2 spaces but found 4.
|
||||
" /path/to/some-filename.js:13:3: Parsing error: Unexpected token
|
||||
let l: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
|
||||
|
||||
let l:type = 'Error'
|
||||
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:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'standard',
|
||||
\ 'executable_callback': 'ale_linters#javascript#standard#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#standard#GetCommand',
|
||||
\ 'callback': 'ale_linters#javascript#standard#Handle',
|
||||
\})
|
||||
|
||||
41
ale_linters/javascript/xo.vim
Normal file
41
ale_linters/javascript/xo.vim
Normal file
@@ -0,0 +1,41 @@
|
||||
" Author: Daniel Lupu <lupu.daniel.f@gmail.com>
|
||||
" Description: xo for JavaScript files
|
||||
|
||||
let g:ale_javascript_xo_executable =
|
||||
\ get(g:, 'ale_javascript_xo_executable', 'xo')
|
||||
|
||||
let g:ale_javascript_xo_options =
|
||||
\ get(g:, 'ale_javascript_xo_options', '')
|
||||
|
||||
let g:ale_javascript_xo_use_global =
|
||||
\ get(g:, 'ale_javascript_xo_use_global', 0)
|
||||
|
||||
function! ale_linters#javascript#xo#GetExecutable(buffer) abort
|
||||
if g:ale_javascript_xo_use_global
|
||||
return g:ale_javascript_xo_executable
|
||||
endif
|
||||
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/xo',
|
||||
\ g:ale_javascript_xo_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#xo#GetCommand(buffer) abort
|
||||
return ale_linters#javascript#xo#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_javascript_xo_options
|
||||
\ . ' --reporter unix --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#javascript#xo#Handle(buffer, lines) abort
|
||||
" xo uses eslint and the output format is the same
|
||||
return ale_linters#javascript#eslint#Handle(a:buffer, a:lines)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'xo',
|
||||
\ 'executable_callback': 'ale_linters#javascript#xo#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#javascript#xo#GetCommand',
|
||||
\ 'callback': 'ale_linters#javascript#xo#Handle',
|
||||
\})
|
||||
@@ -18,11 +18,9 @@ function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
|
||||
@@ -23,11 +23,9 @@ function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
|
||||
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],
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -16,11 +16,9 @@ function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
" Author: poohzrn https://github.com/poohzrn
|
||||
" Description: proselint for markdown files
|
||||
" Description: proselint for Markdown files
|
||||
|
||||
call ale#linter#Define('markdown', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .md proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
let g:ale_matlab_mlint_executable =
|
||||
\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
|
||||
|
||||
function! ale_linters#matlab#mlint#GetExecutable(buffer) abort
|
||||
return g:ale_matlab_mlint_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#matlab#mlint#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#matlab#mlint#GetExecutable(a:buffer)
|
||||
|
||||
return l:executable . ' -id %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
@@ -34,11 +44,9 @@ function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:lnum,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -47,9 +55,8 @@ endfunction
|
||||
|
||||
call ale#linter#Define('matlab', {
|
||||
\ 'name': 'mlint',
|
||||
\ 'executable': 'mlint',
|
||||
\ 'command': g:ale#util#stdin_wrapper .
|
||||
\ ' .m ' . g:ale_matlab_mlint_executable . ' -id',
|
||||
\ 'executable_callback': 'ale_linters#matlab#mlint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#matlab#mlint#GetCommand',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'callback': 'ale_linters#matlab#mlint#Handle',
|
||||
\})
|
||||
|
||||
65
ale_linters/nim/nimcheck.vim
Normal file
65
ale_linters/nim/nimcheck.vim
Normal file
@@ -0,0 +1,65 @@
|
||||
" Author: Baabelfish
|
||||
" Description: Typechecking for nim files
|
||||
|
||||
|
||||
function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
|
||||
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p:t')
|
||||
let l:pattern = '^\(.\+\.nim\)(\(\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
|
||||
|
||||
" Only show errors of the current buffer
|
||||
" NOTE: Checking filename only is OK because nim enforces unique
|
||||
" module names.
|
||||
|
||||
let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t')
|
||||
if l:buffer_filename !=# '' && l:temp_buffer_filename !=# l:buffer_filename
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:line = l:match[2] + 0
|
||||
let l:column = l:match[3] + 0
|
||||
let l:text = l:match[4]
|
||||
let l:type = 'W'
|
||||
|
||||
" Extract error type from message of type 'Error: Some error message'
|
||||
let l:textmatch = matchlist(l:match[4], '^\(.\{-}\): .\+$')
|
||||
|
||||
if len(l:textmatch) > 0
|
||||
let l:errortype = l:textmatch[1]
|
||||
if l:errortype ==# 'Error'
|
||||
let l:type = 'E'
|
||||
endif
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale_linters#nim#nimcheck#GetCommand(buffer)
|
||||
return 'nim check --path:' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h')) . ' --verbosity:0 --colors:off --listFullPaths %t'
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('nim', {
|
||||
\ 'name': 'nimcheck',
|
||||
\ 'executable': 'nim',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'command_callback': 'ale_linters#nim#nimcheck#GetCommand',
|
||||
\ 'callback': 'ale_linters#nim#nimcheck#Handle'
|
||||
\})
|
||||
34
ale_linters/nix/nix.vim
Normal file
34
ale_linters/nix/nix.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" Author: Alistair Bill <@alibabzo>
|
||||
" Description: nix-instantiate linter for nix files
|
||||
|
||||
function! ale_linters#nix#nix#Handle(buffer, lines) abort
|
||||
|
||||
let l:pattern = '^\(.\+\): \(.\+\), 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
|
||||
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'col': l:match[4] + 0,
|
||||
\ 'text': l:match[1] . ': ' . l:match[2],
|
||||
\ 'type': l:match[1] =~# '^error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('nix', {
|
||||
\ 'name': 'nix',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'nix-instantiate',
|
||||
\ 'command': 'nix-instantiate --parse -',
|
||||
\ 'callback': 'ale_linters#nix#nix#Handle',
|
||||
\})
|
||||
9
ale_linters/nroff/proselint.vim
Normal file
9
ale_linters/nroff/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for nroff files
|
||||
|
||||
call ale#linter#Define('nroff', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -1,6 +1,22 @@
|
||||
" Author: Vincent Lequertier <https://github.com/SkySymbol>
|
||||
" Description: This file adds support for checking perl syntax
|
||||
|
||||
let g:ale_perl_perl_executable =
|
||||
\ get(g:, 'ale_perl_perl_executable', 'perl')
|
||||
|
||||
let g:ale_perl_perl_options =
|
||||
\ get(g:, 'ale_perl_perl_options', '-X -c -Mwarnings -Ilib')
|
||||
|
||||
function! ale_linters#perl#perl#GetExecutable(buffer) abort
|
||||
return g:ale_perl_perl_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#perl#perl#GetCommand(buffer) abort
|
||||
return ale_linters#perl#perl#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_perl_perl_options
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#perl#perl#Handle(buffer, lines) abort
|
||||
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
|
||||
let l:output = []
|
||||
@@ -21,11 +37,9 @@ function! ale_linters#perl#perl#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -34,8 +48,8 @@ endfunction
|
||||
|
||||
call ale#linter#Define('perl', {
|
||||
\ 'name': 'perl',
|
||||
\ 'executable': 'perl',
|
||||
\ 'executable_callback': 'ale_linters#perl#perl#GetExecutable',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'command': 'perl -X -c -Mwarnings -Ilib',
|
||||
\ 'command_callback': 'ale_linters#perl#perl#GetCommand',
|
||||
\ 'callback': 'ale_linters#perl#perl#Handle',
|
||||
\})
|
||||
|
||||
@@ -21,11 +21,9 @@ function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ function! ale_linters#php#hack#Handle(buffer, lines) abort
|
||||
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',
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
function! ale_linters#php#php#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" Parse error: parse error in - on line 7
|
||||
let l:pattern = 'Parse error:\s\+\(.\+\) on line \(\d\+\)'
|
||||
" PHP Parse error: syntax error, unexpected ';', expecting ']' in - on line 15
|
||||
let l:pattern = '\vParse error:\s+(.+unexpected ''(.+)%(expecting.+)@<!''.*|.+) in - on line (\d+)'
|
||||
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -18,12 +19,10 @@ function! ale_linters#php#php#Handle(buffer, lines) abort
|
||||
" 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': 1,
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'col': empty(l:match[2]) ? 0 : stridx(getline(l:match[3]), l:match[2]) + 1,
|
||||
\ 'text': l:match[1],
|
||||
\ 'type': 'E',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -33,11 +33,9 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
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 ==# 'error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
39
ale_linters/php/phpmd.vim
Normal file
39
ale_linters/php/phpmd.vim
Normal file
@@ -0,0 +1,39 @@
|
||||
" Author: medains <https://github.com/medains>
|
||||
" Description: phpmd for PHP files
|
||||
|
||||
" Set to change the ruleset
|
||||
let g:ale_php_phpmd_ruleset = get(g:, 'ale_php_phpmd_ruleset', 'cleancode,codesize,controversial,design,naming,unusedcode')
|
||||
|
||||
function! ale_linters#php#phpmd#Handle(buffer, lines) abort
|
||||
" Matches against lines like the following:
|
||||
"
|
||||
" /path/to/some-filename.php:18 message
|
||||
let l:pattern = '^.*:\(\d\+\)\t\(.\+\)$'
|
||||
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[1] + 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:match[2],
|
||||
\ 'type': 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'phpmd',
|
||||
\ 'executable': 'phpmd',
|
||||
\ 'command': 'phpmd %s text ' . g:ale_php_phpmd_ruleset . ' --ignore-violations-on-exit %t',
|
||||
\ 'callback': 'ale_linters#php#phpmd#Handle',
|
||||
\})
|
||||
9
ale_linters/pod/proselint.vim
Normal file
9
ale_linters/pod/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for Pod files
|
||||
|
||||
call ale#linter#Define('pod', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -5,6 +5,6 @@ call ale#linter#Define('pug', {
|
||||
\ 'name': 'puglint',
|
||||
\ 'executable': 'pug-lint',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .pug pug-lint -r inline',
|
||||
\ 'command': 'pug-lint -r inline %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
@@ -18,11 +18,9 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
@@ -33,6 +31,6 @@ call ale#linter#Define('puppet', {
|
||||
\ 'name': 'puppet',
|
||||
\ 'executable': 'puppet',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet parser validate --color=false',
|
||||
\ 'command': 'puppet parser validate --color=false %t',
|
||||
\ 'callback': 'ale_linters#puppet#puppet#Handle',
|
||||
\})
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
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}"',
|
||||
\ 'command': 'puppet-lint --no-autoloader_layout-check'
|
||||
\ . ' --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"'
|
||||
\ . ' %t',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
@@ -5,8 +5,6 @@ call ale#linter#Define('pyrex', {
|
||||
\ 'name': 'cython',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'cython',
|
||||
\ 'command': g:ale#util#stdin_wrapper
|
||||
\ . ' .pyx cython --warning-extra -o '
|
||||
\ . g:ale#util#nul_file,
|
||||
\ 'command': 'cython --warning-extra -o ' . g:ale#util#nul_file . ' %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
|
||||
\})
|
||||
|
||||
@@ -10,10 +10,9 @@ function! g:ale_linters#python#mypy#GetCommand(buffer) abort
|
||||
\ ? 'MYPYPATH=' . l:automatic_stubs_dir . ' '
|
||||
\ : ''
|
||||
|
||||
return l:automatic_stubs_command
|
||||
\ . g:ale#util#stdin_wrapper
|
||||
\ . ' .py mypy --show-column-numbers '
|
||||
return 'mypy --show-column-numbers '
|
||||
\ . g:ale_python_mypy_options
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
|
||||
@@ -45,11 +44,9 @@ function! g:ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pylint#GetCommand(buffer) abort
|
||||
return g:ale#util#stdin_wrapper . ' .py '
|
||||
\ . ale_linters#python#pylint#GetExecutable(a:buffer)
|
||||
return 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'
|
||||
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n'
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
|
||||
9
ale_linters/rst/proselint.vim
Normal file
9
ale_linters/rst/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for reStructuredText files
|
||||
|
||||
call ale#linter#Define('rst', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -23,11 +23,9 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
call ale#linter#Define('sass', {
|
||||
\ 'name': 'sasslint',
|
||||
\ 'executable': 'sass-lint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .sass sass-lint -v -q -f compact',
|
||||
\ 'command': 'sass-lint -v -q -f compact %t',
|
||||
\ 'callback': 'ale#handlers#HandleCSSLintFormat',
|
||||
\})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
" vim: set et:
|
||||
" Author: Zoltan Kalmar - https://github.com/kalmiz
|
||||
" Description: Basic scala support using scalac
|
||||
|
||||
@@ -21,8 +20,10 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) abort
|
||||
let l:text = l:match[3]
|
||||
let l:type = l:match[2] ==# 'error' ? 'E' : 'W'
|
||||
let l:col = 0
|
||||
|
||||
if l:ln + 1 < len(a:lines)
|
||||
let l:col = stridx(a:lines[l:ln + 1], '^')
|
||||
|
||||
if l:col == -1
|
||||
let l:col = 0
|
||||
endif
|
||||
@@ -32,11 +33,9 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col + 1,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -47,6 +46,6 @@ call ale#linter#Define('scala', {
|
||||
\ 'name': 'scalac',
|
||||
\ 'executable': 'scalac',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .scala scalac -Ystop-after:parser',
|
||||
\ 'command': 'scalac -Ystop-after:parser %t',
|
||||
\ 'callback': 'ale_linters#scala#scalac#Handle',
|
||||
\})
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
call ale#linter#Define('scss', {
|
||||
\ 'name': 'sasslint',
|
||||
\ 'executable': 'sass-lint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .scss sass-lint -v -q -f compact',
|
||||
\ 'command': 'sass-lint -v -q -f compact %t',
|
||||
\ 'callback': 'ale#handlers#HandleCSSLintFormat',
|
||||
\})
|
||||
|
||||
@@ -24,11 +24,9 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
|
||||
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] ==# 'E' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -57,11 +57,9 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
33
ale_linters/slim/slimlint.vim
Normal file
33
ale_linters/slim/slimlint.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: Markus Doits - https://github.com/doits
|
||||
" Description: slim-lint for Slim files, based on hamllint.vim
|
||||
|
||||
function! ale_linters#slim#slimlint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" <path>:5 [W] LineLength: Line is too long. [150/120]
|
||||
let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$'
|
||||
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,
|
||||
\ 'type': l:match[2],
|
||||
\ 'text': l:match[3]
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('slim', {
|
||||
\ 'name': 'slimlint',
|
||||
\ 'executable': 'slim-lint',
|
||||
\ 'command': 'slim-lint %t',
|
||||
\ 'callback': 'ale_linters#slim#slimlint#Handle'
|
||||
\})
|
||||
40
ale_linters/sml/smlnj.vim
Normal file
40
ale_linters/sml/smlnj.vim
Normal file
@@ -0,0 +1,40 @@
|
||||
" Author: Paulo Alem <paulo.alem@gmail.com>
|
||||
" Description: Rudimentary SML checking with smlnj compiler
|
||||
|
||||
if exists('g:loaded_ale_sml_smlnj_checker')
|
||||
finish
|
||||
endif
|
||||
|
||||
let g:loaded_ale_sml_smlnj_checker = 1
|
||||
|
||||
function! ale_linters#sml#smlnj#Handle(buffer, lines) abort
|
||||
" Try to match basic sml errors
|
||||
|
||||
let l:out = []
|
||||
let l:pattern = '^.*\:\([0-9\.]\+\)\ \(\w\+\)\:\ \(.*\)'
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:out, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:match[2] . ': ' . l:match[3],
|
||||
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:out
|
||||
endfunction
|
||||
|
||||
call g:ale#linter#Define('sml', {
|
||||
\ 'name': 'smlnj',
|
||||
\ 'executable': 'sml',
|
||||
\ 'command': 'sml',
|
||||
\ 'callback': 'ale_linters#sml#smlnj#Handle',
|
||||
\})
|
||||
@@ -44,11 +44,9 @@ function! ale_linters#tex#chktex#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
let g:ale_tex_lacheck_executable =
|
||||
\ get(g:, 'ale_tex_lacheck_executable', 'lacheck')
|
||||
|
||||
function! ale_linters#tex#lacheck#GetExecutable(buffer) abort
|
||||
return g:ale_tex_lacheck_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tex#lacheck#GetCommand(buffer) abort
|
||||
return g:ale_tex_lacheck_executable . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
|
||||
" Mattes lines like:
|
||||
"
|
||||
@@ -30,11 +38,9 @@ function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
@@ -43,8 +49,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'lacheck',
|
||||
\ 'executable': 'lacheck',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .tex '
|
||||
\ . g:ale_tex_lacheck_executable,
|
||||
\ 'executable_callback': 'ale_linters#tex#lacheck#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#tex#lacheck#GetCommand',
|
||||
\ 'callback': 'ale_linters#tex#lacheck#Handle'
|
||||
\})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
" Author: poohzrn https://github.com/poohzrn
|
||||
" Description: proselint for tex files
|
||||
" Description: proselint for TeX files
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .tex proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
|
||||
9
ale_linters/texinfo/proselint.vim
Normal file
9
ale_linters/texinfo/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for Texinfo files
|
||||
|
||||
call ale#linter#Define('texinfo', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -4,6 +4,6 @@
|
||||
call ale#linter#Define('text', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .txt proselint',
|
||||
\})
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
" Author: Prashanth Chandra https://github.com/prashcr
|
||||
" Description: tslint for TypeScript files
|
||||
|
||||
let g:ale_typescript_tslint_executable =
|
||||
\ get(g:, 'ale_typescript_tslint_executable', 'tslint')
|
||||
|
||||
let g:ale_typescript_tslint_config_path =
|
||||
\ get(g:, 'ale_typescript_tslint_config_path', '')
|
||||
|
||||
function! ale_linters#typescript#tslint#GetExecutable(buffer) abort
|
||||
return ale#util#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ 'node_modules/.bin/tslint',
|
||||
\ g:ale_typescript_tslint_executable
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
@@ -27,29 +41,34 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
|
||||
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
|
||||
|
||||
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
|
||||
function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort
|
||||
let g:ale_typescript_tslint_config_path =
|
||||
\ empty(g:ale_typescript_tslint_config_path) ?
|
||||
\ ale#util#FindNearestFile(a:buffer, 'tslint.json')
|
||||
\ : g:ale_typescript_tslint_config_path
|
||||
|
||||
let l:ext = '.' . fnamemodify(bufname(a:buffer_n), ':e')
|
||||
let l:tslint_options =
|
||||
\ empty(g:ale_typescript_tslint_config_path) ?
|
||||
\ ''
|
||||
\ : '-c ' . fnameescape(g:ale_typescript_tslint_config_path)
|
||||
|
||||
return g:ale#util#stdin_wrapper . ' ' . l:ext . ' tslint ' . l:tslint_options
|
||||
return ale_linters#typescript#tslint#GetExecutable(a:buffer)
|
||||
\ . ' ' . l:tslint_options
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'tslint',
|
||||
\ 'executable': 'tslint',
|
||||
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
|
||||
\ 'callback': 'ale_linters#typescript#tslint#Handle',
|
||||
\})
|
||||
|
||||
@@ -7,7 +7,7 @@ function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
|
||||
" 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:pattern = '.\+\.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
@@ -26,11 +26,9 @@ function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -25,11 +25,9 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -40,6 +38,6 @@ call ale#linter#Define('verilog', {
|
||||
\ 'name': 'iverilog',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'iverilog',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .v iverilog -t null -Wall',
|
||||
\ 'command': 'iverilog -t null -Wall %t',
|
||||
\ 'callback': 'ale_linters#verilog#iverilog#Handle',
|
||||
\})
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: verilator for verilog files
|
||||
|
||||
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
|
||||
let l:filename = tempname() . '_verilator_linted.v'
|
||||
|
||||
" Create a special filename, so we can detect it in the handler.
|
||||
call ale#engine#ManageFile(a:buffer, l:filename)
|
||||
call writefile(getbufline(a:buffer, 1, '$'), l:filename)
|
||||
|
||||
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' . fnameescape(l:filename)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
@@ -25,16 +35,14 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
let l:text = l:match[4]
|
||||
let l:file = l:match[2]
|
||||
|
||||
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,
|
||||
\})
|
||||
if l:file =~# '_verilator_linted.v'
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': 1,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -45,6 +53,7 @@ call ale#linter#Define('verilog', {
|
||||
\ 'name': 'verilator',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'verilator',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' _verilator_linted.v verilator --lint-only -Wall -Wno-DECLFILENAME',
|
||||
\ 'command_callback': 'ale_linters#verilog#verilator#GetCommand',
|
||||
\ 'callback': 'ale_linters#verilog#verilator#Handle',
|
||||
\ 'read_buffer': 0,
|
||||
\})
|
||||
|
||||
@@ -6,17 +6,19 @@ 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:vint_version = ale#semver#Parse(system('vint --version'))
|
||||
let s:has_no_color_support = ale#semver#GreaterOrEqual(s:vint_version, [3, 0, 7])
|
||||
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', {
|
||||
\ 'name': 'vint',
|
||||
\ 'executable': 'vint',
|
||||
\ 'command': g:ale#util#stdin_wrapper
|
||||
\ . ' .vim vint '
|
||||
\ . s:warning_flag
|
||||
\ . ' --no-color '
|
||||
\ 'command': 'vint '
|
||||
\ . s:warning_flag . ' '
|
||||
\ . (s:has_no_color_support ? '--no-color ' : '')
|
||||
\ . s:enable_neovim
|
||||
\ . s:format,
|
||||
\ . s:format
|
||||
\ . ' %t',
|
||||
\ 'callback': 'ale#handlers#HandleGCCFormat',
|
||||
\})
|
||||
|
||||
9
ale_linters/xhtml/proselint.vim
Normal file
9
ale_linters/xhtml/proselint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: Daniel M. Capella https://github.com/polyzen
|
||||
" Description: proselint for XHTML files
|
||||
|
||||
call ale#linter#Define('xhtml', {
|
||||
\ 'name': 'proselint',
|
||||
\ 'executable': 'proselint',
|
||||
\ 'command': 'proselint %t',
|
||||
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
|
||||
\})
|
||||
@@ -1,5 +1,21 @@
|
||||
" Author: KabbAmine <amine.kabb@gmail.com>
|
||||
|
||||
let g:ale_yaml_yamllint_executable =
|
||||
\ get(g:, 'ale_yaml_yamllint_executable', 'yamllint')
|
||||
|
||||
let g:ale_yaml_yamllint_options =
|
||||
\ get(g:, 'ale_yaml_yamllint_options', '')
|
||||
|
||||
function! ale_linters#yaml#yamllint#GetExecutable(buffer) abort
|
||||
return g:ale_yaml_yamllint_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#yaml#yamllint#GetCommand(buffer) abort
|
||||
return ale_linters#yaml#yamllint#GetExecutable(a:buffer)
|
||||
\ . ' ' . g:ale_yaml_yamllint_options
|
||||
\ . ' -f parsable %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
" something.yaml:1:1: [warning] missing document start "---" (document-start)
|
||||
@@ -23,11 +39,9 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'lnum': l:line,
|
||||
\ 'vcol': 0,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type ==# 'error' ? 'E' : 'W',
|
||||
\ 'nr': -1,
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -36,7 +50,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('yaml', {
|
||||
\ 'name': 'yamllint',
|
||||
\ 'executable': 'yamllint',
|
||||
\ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable',
|
||||
\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand',
|
||||
\ 'callback': 'ale_linters#yaml#yamllint#Handle',
|
||||
\})
|
||||
|
||||
@@ -3,13 +3,40 @@
|
||||
" Manages execution of linters when requested by autocommands
|
||||
|
||||
let s:lint_timer = -1
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
|
||||
function! ale#Queue(delay) abort
|
||||
" Do nothing for blacklisted files.
|
||||
if index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
" A function for checking various conditions whereby ALE just shouldn't
|
||||
" attempt to do anything, say if particular buffer types are open in Vim.
|
||||
function! ale#ShouldDoNothing() abort
|
||||
" Do nothing for blacklisted files
|
||||
" OR if ALE is running in the sandbox
|
||||
return index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
\ || ale#util#InSandbox()
|
||||
endfunction
|
||||
|
||||
" (delay, [linting_flag])
|
||||
function! ale#Queue(delay, ...) abort
|
||||
if len(a:0) > 1
|
||||
throw 'too many arguments!'
|
||||
endif
|
||||
|
||||
" Default linting_flag to ''
|
||||
let l:linting_flag = get(a:000, 0, '')
|
||||
|
||||
if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
|
||||
throw "linting_flag must be either '' or 'lint_file'"
|
||||
endif
|
||||
|
||||
if ale#ShouldDoNothing()
|
||||
return
|
||||
endif
|
||||
|
||||
" Remember that we want to check files for this buffer.
|
||||
" We will remember this until we finally run the linters, via any event.
|
||||
if l:linting_flag ==# 'lint_file'
|
||||
let s:should_lint_file_for_buffer[bufnr('%')] = 1
|
||||
endif
|
||||
|
||||
if s:lint_timer != -1
|
||||
call timer_stop(s:lint_timer)
|
||||
let s:lint_timer = -1
|
||||
@@ -29,13 +56,19 @@ function! ale#Queue(delay) abort
|
||||
endfunction
|
||||
|
||||
function! ale#Lint(...) abort
|
||||
" Do nothing for blacklisted files.
|
||||
if index(g:ale_filetype_blacklist, &filetype) >= 0
|
||||
if ale#ShouldDoNothing()
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = bufnr('%')
|
||||
let l:linters = ale#linter#Get(&filetype)
|
||||
let l:should_lint_file = 0
|
||||
|
||||
" Check if we previously requested checking the file.
|
||||
if has_key(s:should_lint_file_for_buffer, l:buffer)
|
||||
unlet s:should_lint_file_for_buffer[l:buffer]
|
||||
let l:should_lint_file = 1
|
||||
endif
|
||||
|
||||
" Initialise the buffer information if needed.
|
||||
call ale#engine#InitBufferInfo(l:buffer)
|
||||
@@ -43,19 +76,22 @@ function! ale#Lint(...) abort
|
||||
" Clear the new loclist again, so we will work with all new items.
|
||||
let g:ale_buffer_info[l:buffer].new_loclist = []
|
||||
|
||||
if l:should_lint_file
|
||||
" Clear loclist items for files if we are checking files again.
|
||||
let g:ale_buffer_info[l:buffer].lint_file_loclist = []
|
||||
else
|
||||
" Otherwise, don't run any `lint_file` linters
|
||||
" We will continue running any linters which are currently checking
|
||||
" the file, and the items will be mixed together with any new items.
|
||||
call filter(l:linters, '!v:val.lint_file')
|
||||
endif
|
||||
|
||||
for l:linter in l:linters
|
||||
" Check if a given linter has a program which can be executed.
|
||||
if has_key(l:linter, 'executable_callback')
|
||||
let l:executable = ale#util#GetFunction(l:linter.executable_callback)(l:buffer)
|
||||
else
|
||||
let l:executable = l:linter.executable
|
||||
endif
|
||||
|
||||
if !executable(l:executable)
|
||||
" The linter's program cannot be executed, so skip it.
|
||||
continue
|
||||
endif
|
||||
|
||||
call ale#engine#Invoke(l:buffer, l:linter)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Reset flags indicating that files should be checked for all buffers.
|
||||
function! ale#ResetLintFileMarkers() abort
|
||||
let s:should_lint_file_for_buffer = {}
|
||||
endfunction
|
||||
|
||||
@@ -3,11 +3,18 @@
|
||||
|
||||
function! ale#cleanup#Buffer(buffer) abort
|
||||
if has_key(g:ale_buffer_info, a:buffer)
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
|
||||
" When buffers are removed, clear all of the jobs.
|
||||
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
|
||||
call ale#engine#ClearJob(l:job)
|
||||
endfor
|
||||
|
||||
" Clear delayed highlights for a buffer being removed.
|
||||
if g:ale_set_highlights
|
||||
call ale#highlight#UnqueueHighlights(a:buffer)
|
||||
endif
|
||||
|
||||
call remove(g:ale_buffer_info, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -18,6 +18,29 @@ function! s:GetMessage(linter, type, text) abort
|
||||
return printf(l:msg, l:text)
|
||||
endfunction
|
||||
|
||||
function! s:EchoWithShortMess(setting, message) abort
|
||||
" We need to remember the setting for shormess and reset it again.
|
||||
let l:shortmess_options = getbufvar('%', '&shortmess')
|
||||
|
||||
try
|
||||
" Turn shortmess on or off.
|
||||
if a:setting ==# 'on'
|
||||
setlocal shortmess+=T
|
||||
" echomsg is neede for the message to get truncated and appear in
|
||||
" the message history.
|
||||
exec "norm! :echomsg a:message\n"
|
||||
elseif a:setting ==# 'off'
|
||||
setlocal shortmess-=T
|
||||
" Regular echo is needed for printing newline characters.
|
||||
echo a:message
|
||||
else
|
||||
throw 'Invalid setting: ' . string(a:setting)
|
||||
endif
|
||||
finally
|
||||
call setbufvar('%', '&shortmess', l:shortmess_options)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#TruncatedEcho(message) abort
|
||||
let l:message = a:message
|
||||
" Change tabs to spaces.
|
||||
@@ -25,17 +48,23 @@ function! ale#cursor#TruncatedEcho(message) abort
|
||||
" Remove any newlines in the message.
|
||||
let l:message = substitute(l:message, "\n", '', 'g')
|
||||
|
||||
" We need to turn T for truncated messages on for shortmess,
|
||||
" and then then we need to reset the option back to what it was.
|
||||
let l:shortmess_options = getbufvar('%', '&shortmess')
|
||||
call s:EchoWithShortMess('on', l:message)
|
||||
endfunction
|
||||
|
||||
try
|
||||
" Echo the message truncated to fit without creating a prompt.
|
||||
setlocal shortmess+=T
|
||||
exec "norm! :echomsg message\n"
|
||||
finally
|
||||
call setbufvar('%', '&shortmess', l:shortmess_options)
|
||||
endtry
|
||||
function! s:FindItemAtCursor() abort
|
||||
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
|
||||
let l:pos = getcurpos()
|
||||
let l:index = ale#util#BinarySearch(l:info.loclist, l:pos[1], l:pos[2])
|
||||
let l:loc = l:index >= 0 ? l:info.loclist[l:index] : {}
|
||||
|
||||
return [l:info, l:loc]
|
||||
endfunction
|
||||
|
||||
function! s:StopCursorTimer() abort
|
||||
if s:cursor_timer != -1
|
||||
call timer_stop(s:cursor_timer)
|
||||
let s:cursor_timer = -1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#EchoCursorWarning(...) abort
|
||||
@@ -44,28 +73,17 @@ function! ale#cursor#EchoCursorWarning(...) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = bufnr('%')
|
||||
let [l:info, l:loc] = s:FindItemAtCursor()
|
||||
|
||||
if !has_key(g:ale_buffer_info, l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:pos = getcurpos()
|
||||
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]
|
||||
if !empty(l:loc)
|
||||
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
|
||||
let l:info.echoed = 1
|
||||
elseif get(l:info, 'echoed')
|
||||
" We'll only clear the echoed message when moving off errors once,
|
||||
" so we don't continually clear the echo line.
|
||||
if get(g:ale_buffer_info[l:buffer], 'echoed')
|
||||
echo
|
||||
let g:ale_buffer_info[l:buffer].echoed = 0
|
||||
endif
|
||||
echo
|
||||
let l:info.echoed = 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -73,15 +91,11 @@ 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
|
||||
if ale#ShouldDoNothing()
|
||||
return
|
||||
endif
|
||||
|
||||
if s:cursor_timer != -1
|
||||
call timer_stop(s:cursor_timer)
|
||||
let s:cursor_timer = -1
|
||||
endif
|
||||
call s:StopCursorTimer()
|
||||
|
||||
let l:pos = getcurpos()[0:2]
|
||||
|
||||
@@ -94,3 +108,23 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
|
||||
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#cursor#ShowCursorDetail() abort
|
||||
" Only echo the warnings in normal mode, otherwise we will get problems.
|
||||
if mode() !=# 'n'
|
||||
return
|
||||
endif
|
||||
|
||||
call s:StopCursorTimer()
|
||||
|
||||
let [l:info, l:loc] = s:FindItemAtCursor()
|
||||
|
||||
if !empty(l:loc)
|
||||
let l:message = get(l:loc, 'detail', l:loc.text)
|
||||
|
||||
call s:EchoWithShortMess('off', l:message)
|
||||
|
||||
" Set the echo marker, so we can clear it by moving the cursor.
|
||||
let l:info.echoed = 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
142
autoload/ale/debugging.vim
Normal file
142
autoload/ale/debugging.vim
Normal file
@@ -0,0 +1,142 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file implements debugging information for ALE
|
||||
|
||||
let s:global_variable_list = [
|
||||
\ 'ale_echo_cursor',
|
||||
\ 'ale_echo_msg_error_str',
|
||||
\ 'ale_echo_msg_format',
|
||||
\ 'ale_echo_msg_warning_str',
|
||||
\ 'ale_enabled',
|
||||
\ 'ale_keep_list_window_open',
|
||||
\ 'ale_lint_delay',
|
||||
\ 'ale_lint_on_enter',
|
||||
\ 'ale_lint_on_save',
|
||||
\ 'ale_lint_on_text_changed',
|
||||
\ 'ale_linter_aliases',
|
||||
\ 'ale_linters',
|
||||
\ 'ale_open_list',
|
||||
\ 'ale_set_highlights',
|
||||
\ 'ale_set_loclist',
|
||||
\ 'ale_set_quickfix',
|
||||
\ 'ale_set_signs',
|
||||
\ 'ale_sign_column_always',
|
||||
\ 'ale_sign_error',
|
||||
\ 'ale_sign_offset',
|
||||
\ 'ale_sign_warning',
|
||||
\ 'ale_statusline_format',
|
||||
\ 'ale_warn_about_trailing_whitespace',
|
||||
\]
|
||||
|
||||
function! s:GetLinterVariables(filetype, linter_names) abort
|
||||
let l:variable_list = []
|
||||
let l:filetype_parts = split(a:filetype, '\.')
|
||||
|
||||
for l:key in keys(g:)
|
||||
" Extract variable names like: 'ale_python_flake8_executable'
|
||||
let l:match = matchlist(l:key, '\v^ale_([^_]+)_([^_]+)_.+$')
|
||||
|
||||
" Include matching variables.
|
||||
if !empty(l:match)
|
||||
\&& index(l:filetype_parts, l:match[1]) >= 0
|
||||
\&& index(a:linter_names, l:match[2]) >= 0
|
||||
call add(l:variable_list, l:key)
|
||||
endif
|
||||
endfor
|
||||
|
||||
call sort(l:variable_list)
|
||||
|
||||
return l:variable_list
|
||||
endfunction
|
||||
|
||||
function! s:EchoLinterVariables(variable_list) abort
|
||||
for l:key in a:variable_list
|
||||
echom 'let g:' . l:key . ' = ' . string(g:[l:key])
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:EchoGlobalVariables() abort
|
||||
for l:key in s:global_variable_list
|
||||
echom 'let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:EchoCommandHistory() abort
|
||||
let l:buffer = bufnr('%')
|
||||
|
||||
if !has_key(g:ale_buffer_info, l:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
for l:item in g:ale_buffer_info[l:buffer].history
|
||||
let l:status_message = l:item.status
|
||||
|
||||
" Include the exit code in output if we have it.
|
||||
if l:item.status ==# 'finished'
|
||||
let l:status_message .= ' - exit code ' . l:item.exit_code
|
||||
endif
|
||||
|
||||
echom '(' . l:status_message . ') ' . string(l:item.command)
|
||||
|
||||
if g:ale_history_log_output && has_key(l:item, 'output')
|
||||
if empty(l:item.output)
|
||||
echom ''
|
||||
echom '<<<NO OUTPUT RETURNED>>>'
|
||||
echom ''
|
||||
else
|
||||
echom ''
|
||||
echom '<<<OUTPUT STARTS>>>'
|
||||
|
||||
for l:line in l:item.output
|
||||
echom l:line
|
||||
endfor
|
||||
|
||||
echom '<<<OUTPUT ENDS>>>'
|
||||
echom ''
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#debugging#Info() abort
|
||||
let l:filetype = &filetype
|
||||
|
||||
" We get the list of enabled linters for free by the above function.
|
||||
let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype))
|
||||
|
||||
" But have to build the list of available linters ourselves.
|
||||
let l:all_linters = []
|
||||
let l:linter_variable_list = []
|
||||
|
||||
for l:part in split(l:filetype, '\.')
|
||||
let l:aliased_filetype = ale#linter#ResolveFiletype(l:part)
|
||||
call extend(l:all_linters, ale#linter#GetAll(l:aliased_filetype))
|
||||
endfor
|
||||
|
||||
let l:all_names = map(l:all_linters, 'v:val[''name'']')
|
||||
let l:enabled_names = map(l:enabled_linters, 'v:val[''name'']')
|
||||
|
||||
" Load linter variables to display
|
||||
" This must be done after linters are loaded.
|
||||
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
|
||||
|
||||
echom ' Current Filetype: ' . l:filetype
|
||||
echom 'Available Linters: ' . string(l:all_names)
|
||||
echom ' Enabled Linters: ' . string(l:enabled_names)
|
||||
echom ' Linter Variables:'
|
||||
echom ''
|
||||
call s:EchoLinterVariables(l:variable_list)
|
||||
echom ' Global Variables:'
|
||||
echom ''
|
||||
call s:EchoGlobalVariables()
|
||||
echom ' Command History:'
|
||||
echom ''
|
||||
call s:EchoCommandHistory()
|
||||
endfunction
|
||||
|
||||
function! ale#debugging#InfoToClipboard() abort
|
||||
redir @+>
|
||||
silent call ale#debugging#Info()
|
||||
redir END
|
||||
|
||||
echom 'ALEInfo copied to your clipboard'
|
||||
endfunction
|
||||
@@ -9,33 +9,53 @@
|
||||
" output: The array of lines for the output of the job.
|
||||
let s:job_info_map = {}
|
||||
|
||||
function! ale#engine#ParseVim8ProcessID(job_string) abort
|
||||
return matchstr(a:job_string, '\d\+') + 0
|
||||
endfunction
|
||||
|
||||
function! s:GetJobID(job) abort
|
||||
if has('nvim')
|
||||
"In NeoVim, job values are just IDs.
|
||||
return a:job
|
||||
endif
|
||||
|
||||
" In Vim 8, the job is a special variable, and we open a channel for each
|
||||
" job. We'll use the ID of the channel instead as the job ID.
|
||||
return ch_info(job_getchannel(a:job)).id
|
||||
" For Vim 8, the job is a different variable type, and we can parse the
|
||||
" process ID from the string.
|
||||
return ale#engine#ParseVim8ProcessID(string(a:job))
|
||||
endfunction
|
||||
|
||||
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.
|
||||
" lint_file_loclist holds items from the last run including linters
|
||||
" which use the lint_file option.
|
||||
" new_loclist holds loclist items while jobs are being run.
|
||||
" temporary_file_list holds temporary files to be cleaned up
|
||||
" temporary_directory_list holds temporary directories to be cleaned up
|
||||
" history holds a list of previously run commands for this buffer
|
||||
let g:ale_buffer_info[a:buffer] = {
|
||||
\ 'job_list': [],
|
||||
\ 'loclist': [],
|
||||
\ 'lint_file_loclist': [],
|
||||
\ 'new_loclist': [],
|
||||
\ 'temporary_file_list': [],
|
||||
\ 'temporary_directory_list': [],
|
||||
\ 'history': [],
|
||||
\}
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" A map from timer IDs to Vim 8 jobs, for tracking jobs that need to be killed
|
||||
" with SIGKILL if they don't terminate right away.
|
||||
let s:job_kill_timers = {}
|
||||
|
||||
function! s:KillHandler(timer) abort
|
||||
call job_stop(remove(s:job_kill_timers, a:timer), 'kill')
|
||||
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
|
||||
|
||||
if has('nvim')
|
||||
call jobstop(a:job)
|
||||
@@ -46,10 +66,19 @@ function! ale#engine#ClearJob(job) abort
|
||||
call ch_close_in(job_getchannel(a:job))
|
||||
endif
|
||||
|
||||
" Ask nicely for the job to stop.
|
||||
call job_stop(a:job)
|
||||
|
||||
" If a job doesn't stop immediately, queue a timer which will
|
||||
" send SIGKILL to the job, if it's alive by the time the timer ticks.
|
||||
if job_status(a:job) ==# 'run'
|
||||
let s:job_kill_timers[timer_start(100, function('s:KillHandler'))] = a:job
|
||||
endif
|
||||
endif
|
||||
|
||||
call remove(s:job_info_map, l:job_id)
|
||||
if has_key(s:job_info_map, l:job_id)
|
||||
call remove(s:job_info_map, l:job_id)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:StopPreviousJobs(buffer, linter) abort
|
||||
@@ -112,6 +141,46 @@ function! ale#engine#JoinNeovimOutput(output, data) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Register a temporary file to be managed with the ALE engine for
|
||||
" a current job run.
|
||||
function! ale#engine#ManageFile(buffer, filename) abort
|
||||
call add(g:ale_buffer_info[a:buffer].temporary_file_list, a:filename)
|
||||
endfunction
|
||||
|
||||
" Same as the above, but manage an entire directory.
|
||||
function! ale#engine#ManageDirectory(buffer, directory) abort
|
||||
call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RemoveManagedFiles(buffer) abort
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
" We can't delete anything in a sandbox, so wait until we escape from
|
||||
" it to delete temporary files and directories.
|
||||
if ale#util#InSandbox()
|
||||
return
|
||||
endif
|
||||
|
||||
" Delete files with a call akin to a plan `rm` command.
|
||||
for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
|
||||
call delete(l:filename)
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_file_list = []
|
||||
|
||||
" Delete directories like `rm -rf`.
|
||||
" Directories are handled differently from files, so paths that are
|
||||
" intended to be single files can be set up for automatic deletion without
|
||||
" accidentally deleting entire directories.
|
||||
for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
|
||||
call delete(l:directory, 'rf')
|
||||
endfor
|
||||
|
||||
let g:ale_buffer_info[a:buffer].temporary_directory_list = []
|
||||
endfunction
|
||||
|
||||
function! s:HandleExit(job) abort
|
||||
if a:job ==# 'no process'
|
||||
" Stop right away when the job is not valid in Vim 8.
|
||||
@@ -134,59 +203,110 @@ function! s:HandleExit(job) abort
|
||||
" which just closed.
|
||||
call s:StopPreviousJobs(l:buffer, l:linter)
|
||||
|
||||
" Stop here if we land in the handle for a job completing if we're in
|
||||
" a sandbox.
|
||||
if ale#util#InSandbox()
|
||||
return
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
" Log the output of the command for ALEInfo if we should.
|
||||
if g:ale_history_enabled && g:ale_history_log_output
|
||||
call ale#history#RememberOutput(l:buffer, l:job_id, l:output[:])
|
||||
endif
|
||||
|
||||
let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
|
||||
|
||||
" Make some adjustments to the loclists to fix common problems.
|
||||
call s:FixLocList(l:buffer, l:linter_loclist)
|
||||
|
||||
for l:item in l:linter_loclist
|
||||
let l:item.linter_name = l:linter.name
|
||||
endfor
|
||||
" Make some adjustments to the loclists to fix common problems, and also
|
||||
" to set default values for loclist items.
|
||||
let l:linter_loclist = ale#engine#FixLocList(l:buffer, l:linter, l:linter_loclist)
|
||||
|
||||
" Add the loclist items from the linter.
|
||||
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
|
||||
" loclist items for files which are checked go into a different list,
|
||||
" and are kept between runs.
|
||||
if l:linter.lint_file
|
||||
call extend(g:ale_buffer_info[l:buffer].lint_file_loclist, l:linter_loclist)
|
||||
else
|
||||
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
|
||||
endif
|
||||
|
||||
if !empty(g:ale_buffer_info[l:buffer].job_list)
|
||||
" Wait for all jobs to complete before doing anything else.
|
||||
return
|
||||
endif
|
||||
|
||||
" Automatically remove all managed temporary files and directories
|
||||
" now that all jobs have completed.
|
||||
call ale#engine#RemoveManagedFiles(l:buffer)
|
||||
|
||||
" Combine the lint_file List and the List for everything else.
|
||||
let l:combined_list = g:ale_buffer_info[l:buffer].lint_file_loclist
|
||||
\ + g:ale_buffer_info[l:buffer].new_loclist
|
||||
|
||||
" 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_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
|
||||
call sort(l:combined_list, 'ale#util#LocItemCompare')
|
||||
|
||||
" 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].loclist = l:combined_list
|
||||
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)
|
||||
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
endfunction
|
||||
|
||||
function! ale#engine#SetResults(buffer, loclist) abort
|
||||
" Set signs first. This could potentially fix some line numbers.
|
||||
" The List could be sorted again here by SetSigns.
|
||||
if g:ale_set_signs
|
||||
call ale#sign#SetSigns(a:buffer, a:loclist)
|
||||
endif
|
||||
|
||||
if g:ale_set_signs
|
||||
call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
if g:ale_set_quickfix || g:ale_set_loclist
|
||||
call ale#list#SetLists(a:buffer, a:loclist)
|
||||
endif
|
||||
|
||||
if exists('*ale#statusline#Update')
|
||||
" Don't load/run if not already loaded.
|
||||
call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||
call ale#statusline#Update(a:buffer, a:loclist)
|
||||
endif
|
||||
|
||||
" Call user autocommands. This allows users to hook into ALE's lint cycle.
|
||||
silent doautocmd User ALELint
|
||||
if g:ale_set_highlights
|
||||
call ale#highlight#SetHighlights(a:buffer, a:loclist)
|
||||
endif
|
||||
|
||||
" Mark line 200, column 17 with a squiggly line or something
|
||||
" matchadd('ALEError', '\%200l\%17v')
|
||||
if g:ale_echo_cursor
|
||||
" Try and echo the warning now.
|
||||
" This will only do something meaningful if we're in normal mode.
|
||||
call ale#cursor#EchoCursorWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HandleExitNeoVim(job, data, event) abort
|
||||
function! s:SetExitCode(job, exit_code) abort
|
||||
let l:job_id = s:GetJobID(a:job)
|
||||
|
||||
if !has_key(s:job_info_map, l:job_id)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = s:job_info_map[l:job_id].buffer
|
||||
|
||||
call ale#history#SetExitCode(l:buffer, l:job_id, a:exit_code)
|
||||
endfunction
|
||||
|
||||
function! s:HandleExitNeoVim(job, exit_code, event) abort
|
||||
if g:ale_history_enabled
|
||||
call s:SetExitCode(a:job, a:exit_code)
|
||||
endif
|
||||
|
||||
call s:HandleExit(a:job)
|
||||
endfunction
|
||||
|
||||
@@ -194,34 +314,154 @@ function! s:HandleExitVim(channel) abort
|
||||
call s:HandleExit(ch_getjob(a:channel))
|
||||
endfunction
|
||||
|
||||
function! s:FixLocList(buffer, loclist) abort
|
||||
" Vim returns the exit status with one callback,
|
||||
" and the channel will close later in another callback.
|
||||
function! s:HandleExitStatusVim(job, exit_code) abort
|
||||
call s:SetExitCode(a:job, a:exit_code)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#FixLocList(buffer, linter, loclist) abort
|
||||
let l:new_loclist = []
|
||||
|
||||
" Some errors have line numbers beyond the end of the file,
|
||||
" so we need to adjust them so they set the error at the last line
|
||||
" of the file instead.
|
||||
let l:last_line_number = ale#util#GetLineCount(a:buffer)
|
||||
|
||||
for l:item in a:loclist
|
||||
for l:old_item in a:loclist
|
||||
" Copy the loclist item with some default values and corrections.
|
||||
"
|
||||
" line and column numbers will be converted to numbers.
|
||||
" The buffer will default to the buffer being checked.
|
||||
" The vcol setting will default to 0, a byte index.
|
||||
" The error type will default to 'E' for errors.
|
||||
" The error number will default to -1.
|
||||
"
|
||||
" The line number and text are the only required keys.
|
||||
"
|
||||
" The linter_name will be set on the errors so it can be used in
|
||||
" output, filtering, etc..
|
||||
let l:item = {
|
||||
\ 'text': l:old_item.text,
|
||||
\ 'lnum': str2nr(l:old_item.lnum),
|
||||
\ 'col': str2nr(get(l:old_item, 'col', 0)),
|
||||
\ 'bufnr': get(l:old_item, 'bufnr', a:buffer),
|
||||
\ 'vcol': get(l:old_item, 'vcol', 0),
|
||||
\ 'type': get(l:old_item, 'type', 'E'),
|
||||
\ 'nr': get(l:old_item, 'nr', -1),
|
||||
\ 'linter_name': a:linter.name,
|
||||
\}
|
||||
|
||||
if has_key(l:old_item, 'detail')
|
||||
let l:item.detail = l:old_item.detail
|
||||
endif
|
||||
|
||||
if l:item.lnum == 0
|
||||
" When errors appear at line 0, put them at line 1 instead.
|
||||
let l:item.lnum = 1
|
||||
elseif l:item.lnum > l:last_line_number
|
||||
" When errors go beyond the end of the file, put them at the end.
|
||||
let l:item.lnum = l:last_line_number
|
||||
endif
|
||||
|
||||
call add(l:new_loclist, l:item)
|
||||
endfor
|
||||
|
||||
return l:new_loclist
|
||||
endfunction
|
||||
|
||||
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
|
||||
" Given part of a command, replace any % with %%, so that no characters in
|
||||
" the string will be replaced with filenames, etc.
|
||||
function! ale#engine#EscapeCommandPart(command_part) abort
|
||||
return substitute(a:command_part, '%', '%%', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:TemporaryFilename(buffer) abort
|
||||
let l:filename = fnamemodify(bufname(a:buffer), ':t')
|
||||
|
||||
if empty(l:filename)
|
||||
" If the buffer's filename is empty, create a dummy filename.
|
||||
let l:ft = getbufvar(a:buffer, '&filetype')
|
||||
let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft)
|
||||
endif
|
||||
|
||||
" Create a temporary filename, <temp_dir>/<original_basename>
|
||||
" The file itself will not be created by this function.
|
||||
return tempname() . (has('win32') ? '\' : '/') . l:filename
|
||||
endfunction
|
||||
|
||||
" Given a command string, replace every...
|
||||
" %s -> with the current filename
|
||||
" %t -> with the name of an unused file in a temporary directory
|
||||
" %% -> with a literal %
|
||||
function! ale#engine#FormatCommand(buffer, command) abort
|
||||
let l:temporary_file = ''
|
||||
let l:command = a:command
|
||||
|
||||
" First replace all uses of %%, used for literal percent characters,
|
||||
" with an ugly string.
|
||||
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
|
||||
|
||||
" Replace all %s occurences in the string with the name of the current
|
||||
" file.
|
||||
if l:command =~# '%s'
|
||||
" 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(l:buffer), ':p')))
|
||||
let l:filename = fnamemodify(bufname(a:buffer), ':p')
|
||||
let l:command = substitute(l:command, '%s', '\=fnameescape(l:filename)', 'g')
|
||||
endif
|
||||
|
||||
if l:command =~# '%t'
|
||||
" Create a temporary filename, <temp_dir>/<original_basename>
|
||||
" The file itself will not be created by this function.
|
||||
let l:temporary_file = s:TemporaryFilename(a:buffer)
|
||||
let l:command = substitute(l:command, '%t', '\=fnameescape(l:temporary_file)', 'g')
|
||||
endif
|
||||
|
||||
" Finish formatting so %% becomes %.
|
||||
let l:command = substitute(l:command, '<<PERCENTS>>', '%', 'g')
|
||||
|
||||
return [l:temporary_file, l:command]
|
||||
endfunction
|
||||
|
||||
function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort
|
||||
if empty(a:temporary_file)
|
||||
" There is no file, so we didn't create anything.
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:temporary_directory = fnamemodify(a:temporary_file, ':h')
|
||||
" Create the temporary directory for the file, unreadable by 'other'
|
||||
" users.
|
||||
call mkdir(l:temporary_directory, '', 0750)
|
||||
" Automatically delete the directory later.
|
||||
call ale#engine#ManageDirectory(a:buffer, l:temporary_directory)
|
||||
" Write the buffer out to a file.
|
||||
call writefile(getbufline(a:buffer, 1, '$'), a:temporary_file)
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:RunJob(options) abort
|
||||
let l:command = a:options.command
|
||||
let l:buffer = a:options.buffer
|
||||
let l:linter = a:options.linter
|
||||
let l:output_stream = a:options.output_stream
|
||||
let l:next_chain_index = a:options.next_chain_index
|
||||
let l:read_buffer = a:options.read_buffer
|
||||
|
||||
let [l:temporary_file, l:command] = ale#engine#FormatCommand(l:buffer, l:command)
|
||||
|
||||
if l:read_buffer && empty(l:temporary_file)
|
||||
" If we are to send the Vim buffer to a command, we'll do it
|
||||
" in the shell. We'll write out the file to a temporary file,
|
||||
" and then read it back in, in the shell.
|
||||
let l:temporary_file = s:TemporaryFilename(l:buffer)
|
||||
let l:command = l:command . ' < ' . fnameescape(l:temporary_file)
|
||||
endif
|
||||
|
||||
if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file)
|
||||
" If a temporary filename has been formatted in to the command, then
|
||||
" we do not need to send the Vim buffer to the command.
|
||||
let l:read_buffer = 0
|
||||
endif
|
||||
|
||||
if has('nvim')
|
||||
@@ -251,6 +491,12 @@ function! s:RunJob(command, generic_job_options) abort
|
||||
\ 'close_cb': function('s:HandleExitVim'),
|
||||
\}
|
||||
|
||||
if g:ale_history_enabled
|
||||
" We only need to capture the exit status if we are going to
|
||||
" save it in the history. Otherwise, we don't care.
|
||||
let l:job_options.exit_cb = function('s:HandleExitStatusVim')
|
||||
endif
|
||||
|
||||
if l:output_stream ==# 'stderr'
|
||||
" Read from stderr instead of stdout.
|
||||
let l:job_options.err_cb = function('s:GatherOutputVim')
|
||||
@@ -262,63 +508,50 @@ function! s:RunJob(command, generic_job_options) abort
|
||||
let l:job_options.out_cb = function('s:GatherOutputVim')
|
||||
endif
|
||||
|
||||
if has('win32')
|
||||
" job_start commands on Windows have to be run with cmd /c,
|
||||
" othwerwise %PATHTEXT% will not be used to programs ending int
|
||||
" .cmd, .bat, .exe, etc.
|
||||
let l:command = 'cmd /c ' . l:command
|
||||
else
|
||||
" Execute the command with the shell, to fix escaping issues.
|
||||
let l:command = split(&shell) + split(&shellcmdflag) + [l:command]
|
||||
|
||||
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
|
||||
" The command will be executed in a subshell. This fixes a number of
|
||||
" issues, including reading the PATH variables correctly, %PATHEXT%
|
||||
" expansion on Windows, etc.
|
||||
"
|
||||
" NeoVim handles this issue automatically if the command is a String.
|
||||
let l:command = has('win32')
|
||||
\ ? 'cmd /c ' . l:command
|
||||
\ : split(&shell) + split(&shellcmdflag) + [l:command]
|
||||
|
||||
" Vim 8 will read the stdin from the file's buffer.
|
||||
let l:job = job_start(l:command, l:job_options)
|
||||
endif
|
||||
|
||||
let l:status = 'failed'
|
||||
let l:job_id = 0
|
||||
|
||||
" Only proceed if the job is being run.
|
||||
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run')
|
||||
" 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)
|
||||
|
||||
let l:status = 'started'
|
||||
let l:job_id = s:GetJobID(l:job)
|
||||
" Store the ID for the job in the map to read back again.
|
||||
let s:job_info_map[s:GetJobID(l:job)] = {
|
||||
let s:job_info_map[l:job_id] = {
|
||||
\ 'linter': l:linter,
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'output': [],
|
||||
\ 'next_chain_index': l:next_chain_index,
|
||||
\}
|
||||
endif
|
||||
|
||||
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(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)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
if g:ale_history_enabled
|
||||
call ale#history#Add(l:buffer, l:status, l:job_id, l:command)
|
||||
else
|
||||
let g:ale_buffer_info[l:buffer].history = []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
" Determine which commands to run for a link in a command chain, or
|
||||
" just a regular command.
|
||||
function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
|
||||
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
|
||||
let l:read_buffer = a:linter.read_buffer
|
||||
let l:chain_index = a:chain_index
|
||||
let l:input = a:input
|
||||
|
||||
@@ -328,11 +561,6 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
" 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)(
|
||||
@@ -348,6 +576,21 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
|
||||
if !empty(l:command)
|
||||
" We hit a command to run, so we'll execute that
|
||||
|
||||
" The chain item can override the output_stream option.
|
||||
if has_key(l:chain_item, 'output_stream')
|
||||
let l:output_stream = l:chain_item.output_stream
|
||||
endif
|
||||
|
||||
" The chain item can override the read_buffer option.
|
||||
if has_key(l:chain_item, 'read_buffer')
|
||||
let l:read_buffer = l:chain_item.read_buffer
|
||||
elseif l:chain_index != len(a:linter.command_chain) - 1
|
||||
" Don't read the buffer for commands besides the last one
|
||||
" in the chain by default.
|
||||
let l:read_buffer = 0
|
||||
endif
|
||||
|
||||
break
|
||||
endif
|
||||
|
||||
@@ -357,11 +600,6 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
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)
|
||||
@@ -369,21 +607,45 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
let l:command = a:linter.command
|
||||
endif
|
||||
|
||||
let l:is_last_job = l:chain_index >= len(get(a:linter, 'command_chain', [])) - 1
|
||||
if empty(l:command)
|
||||
" Don't run any jobs if the command is an empty string.
|
||||
return {}
|
||||
endif
|
||||
|
||||
call s:RunJob(l:command, {
|
||||
return {
|
||||
\ 'command': 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,
|
||||
\})
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
function! s:InvokeChain(buffer, linter, chain_index, input) abort
|
||||
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
|
||||
|
||||
if !empty(l:options)
|
||||
call s:RunJob(l:options)
|
||||
elseif empty(g:ale_buffer_info[a:buffer].job_list)
|
||||
" If we cancelled running a command, and we have no jobs in progress,
|
||||
" then delete the managed temporary files now.
|
||||
call ale#engine#RemoveManagedFiles(a:buffer)
|
||||
endif
|
||||
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, [])
|
||||
|
||||
let l:executable = has_key(a:linter, 'executable_callback')
|
||||
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
|
||||
\ : a:linter.executable
|
||||
|
||||
" Run this program if it can be executed.
|
||||
if executable(l:executable)
|
||||
call s:InvokeChain(a:buffer, a:linter, 0, [])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, return the warnings and errors for a given buffer.
|
||||
@@ -402,7 +664,7 @@ endfunction
|
||||
" The time taken will be a very rough approximation, and more time may be
|
||||
" permitted than is specified.
|
||||
function! ale#engine#WaitForJobs(deadline) abort
|
||||
let l:start_time = system('date +%s%3N') + 0
|
||||
let l:start_time = ale#util#ClockMilliseconds()
|
||||
|
||||
if l:start_time == 0
|
||||
throw 'Failed to read milliseconds from the clock!'
|
||||
@@ -422,7 +684,7 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
|
||||
for l:job in l:job_list
|
||||
if job_status(l:job) ==# 'run'
|
||||
let l:now = system('date +%s%3N') + 0
|
||||
let l:now = ale#util#ClockMilliseconds()
|
||||
|
||||
if l:now - l:start_time > a:deadline
|
||||
" Stop waiting after a timeout, so we don't wait forever.
|
||||
@@ -447,15 +709,19 @@ function! ale#engine#WaitForJobs(deadline) abort
|
||||
" for command_chain linters.
|
||||
let l:has_new_jobs = 0
|
||||
|
||||
" Check again to see if any jobs are running.
|
||||
for l:info in values(g:ale_buffer_info)
|
||||
if !empty(l:info.job_list)
|
||||
let l:has_new_jobs = 1
|
||||
endif
|
||||
for l:job in l:info.job_list
|
||||
if job_status(l:job) ==# 'run'
|
||||
let l:has_new_jobs = 1
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
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:now = ale#util#ClockMilliseconds()
|
||||
let l:new_deadline = a:deadline - (l:now - l:start_time)
|
||||
|
||||
if l:new_deadline <= 0
|
||||
|
||||
60
autoload/ale/filetypes.vim
Normal file
60
autoload/ale/filetypes.vim
Normal file
@@ -0,0 +1,60 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file handles guessing file extensions for filetypes, etc.
|
||||
|
||||
function! ale#filetypes#LoadExtensionMap() abort
|
||||
" Output includes:
|
||||
" '*.erl setf erlang'
|
||||
redir => l:output
|
||||
silent exec 'autocmd'
|
||||
redir end
|
||||
|
||||
let l:map = {}
|
||||
|
||||
for l:line in split(l:output, "\n")
|
||||
" Parse filetypes, like so:
|
||||
"
|
||||
" *.erl setf erlang
|
||||
" *.md set filetype=markdown
|
||||
" *.snippet setlocal filetype=snippets
|
||||
let l:match = matchlist(l:line, '\v^ *\*(\.[^ ]+).*set(f *| *filetype=|local *filetype=)([^ ]+)')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:map[substitute(l:match[3], '^=', '', '')] = l:match[1]
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:map
|
||||
endfunction
|
||||
|
||||
let s:cached_map = {}
|
||||
|
||||
function! s:GetCachedExtensionMap() abort
|
||||
if empty(s:cached_map)
|
||||
let s:cached_map = ale#filetypes#LoadExtensionMap()
|
||||
endif
|
||||
|
||||
return s:cached_map
|
||||
endfunction
|
||||
|
||||
function! ale#filetypes#GuessExtension(filetype) abort
|
||||
let l:map = s:GetCachedExtensionMap()
|
||||
let l:ext = get(l:map, a:filetype, '')
|
||||
|
||||
" If we have an exact match, like something for javascript.jsx, use that.
|
||||
if !empty(l:ext)
|
||||
return l:ext
|
||||
endif
|
||||
|
||||
" If we don't have an exact match, use the first filetype in the compound
|
||||
" filetype.
|
||||
for l:part in split(a:filetype, '\.')
|
||||
let l:ext = get(l:map, l:part, '')
|
||||
|
||||
if !empty(l:ext)
|
||||
return l:ext
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Return an empty string if we don't find anything.
|
||||
return ''
|
||||
endfunction
|
||||
@@ -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
|
||||
@@ -220,3 +220,58 @@ function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#HandleGhcFormat(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
"Appoint/Lib.hs:8:1: warning:
|
||||
"Appoint/Lib.hs:8:1:
|
||||
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\):\(.*\)\?$'
|
||||
let l:output = []
|
||||
|
||||
let l:corrected_lines = []
|
||||
for l:line in a:lines
|
||||
if len(matchlist(l:line, l:pattern)) > 0
|
||||
call add(l:corrected_lines, l:line)
|
||||
elseif 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
|
||||
|
||||
let l:errors = matchlist(l:match[3], '\(warning:\|error:\)\(.*\)')
|
||||
|
||||
if len(l:errors) > 0
|
||||
let l:type = l:errors[1]
|
||||
let l:text = l:errors[2]
|
||||
else
|
||||
let l:type = ''
|
||||
let l:text = l:match[3]
|
||||
endif
|
||||
|
||||
let l:type = l:type ==# '' ? 'E' : toupper(l:type[0])
|
||||
|
||||
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
|
||||
|
||||
102
autoload/ale/highlight.vim
Normal file
102
autoload/ale/highlight.vim
Normal file
@@ -0,0 +1,102 @@
|
||||
scriptencoding utf8
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This module implements error/warning highlighting.
|
||||
|
||||
if !hlexists('ALEError')
|
||||
highlight link ALEError SpellBad
|
||||
endif
|
||||
|
||||
if !hlexists('ALEWarning')
|
||||
highlight link ALEWarning SpellCap
|
||||
endif
|
||||
|
||||
" This map holds highlights to be set when buffers are opened.
|
||||
" We can only set highlights for whatever the current buffer is, so we will
|
||||
" wait until the buffer is entered again to show the highlights, unless
|
||||
" the buffer is in focus when linting completes.
|
||||
let s:buffer_highlights = {}
|
||||
|
||||
function! ale#highlight#UnqueueHighlights(buffer) abort
|
||||
if has_key(s:buffer_highlights, a:buffer)
|
||||
call remove(s:buffer_highlights, a:buffer)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GetALEMatches() abort
|
||||
let l:list = []
|
||||
|
||||
for l:match in getmatches()
|
||||
if l:match['group'] ==# 'ALEError' || l:match['group'] ==# 'ALEWarning'
|
||||
call add(l:list, l:match)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:list
|
||||
endfunction
|
||||
|
||||
function! s:GetCurrentMatchIDs(loclist) abort
|
||||
let l:current_id_map = {}
|
||||
|
||||
for l:item in a:loclist
|
||||
if has_key(l:item, 'match_id')
|
||||
let l:current_id_map[l:item.match_id] = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:current_id_map
|
||||
endfunction
|
||||
|
||||
function! ale#highlight#UpdateHighlights() abort
|
||||
let l:buffer = bufnr('%')
|
||||
let l:has_new_items = has_key(s:buffer_highlights, l:buffer)
|
||||
let l:loclist = l:has_new_items ? remove(s:buffer_highlights, l:buffer) : []
|
||||
let l:current_id_map = s:GetCurrentMatchIDs(l:loclist)
|
||||
|
||||
if l:has_new_items || !g:ale_enabled
|
||||
for l:match in s:GetALEMatches()
|
||||
if !has_key(l:current_id_map, l:match.id)
|
||||
call matchdelete(l:match.id)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
" Remove anything with a current match_id
|
||||
call filter(l:loclist, '!has_key(v:val, ''match_id'')')
|
||||
|
||||
if l:has_new_items
|
||||
for l:item in l:loclist
|
||||
let l:col = l:item.col
|
||||
let l:group = l:item.type ==# 'E' ? 'ALEError' : 'ALEWarning'
|
||||
let l:line = l:item.lnum
|
||||
let l:size = 1
|
||||
|
||||
" Rememeber the match ID for the item.
|
||||
" This ID will be used to preserve loclist items which are set
|
||||
" many times.
|
||||
let l:item.match_id = matchaddpos(l:group, [[l:line, l:col, l:size]])
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
augroup ALEHighlightBufferGroup
|
||||
autocmd!
|
||||
autocmd BufEnter * call ale#highlight#UpdateHighlights()
|
||||
augroup END
|
||||
|
||||
function! ale#highlight#SetHighlights(buffer, loclist) abort
|
||||
" Only set set items for the buffer if ALE is enabled.
|
||||
if g:ale_enabled
|
||||
" Set a list of items to be set as highlights for a buffer when
|
||||
" we next open it.
|
||||
"
|
||||
" We'll filter the loclist down to items we can set now.
|
||||
let s:buffer_highlights[a:buffer] = filter(
|
||||
\ copy(a:loclist),
|
||||
\ 'v:val.bufnr == a:buffer && v:val.col > 0'
|
||||
\)
|
||||
|
||||
" Update highlights for the current buffer, which may or may not
|
||||
" be the buffer we just set highlights for.
|
||||
call ale#highlight#UpdateHighlights()
|
||||
endif
|
||||
endfunction
|
||||
58
autoload/ale/history.vim
Normal file
58
autoload/ale/history.vim
Normal file
@@ -0,0 +1,58 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Tools for managing command history
|
||||
"
|
||||
function! ale#history#Add(buffer, status, job_id, command) abort
|
||||
if g:ale_max_buffer_history_size <= 0
|
||||
" Don't save anything if the history isn't a positive number.
|
||||
let g:ale_buffer_info[a:buffer].history = []
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:history = g:ale_buffer_info[a:buffer].history
|
||||
|
||||
" Remove the first item if we hit the max history size.
|
||||
if len(l:history) >= g:ale_max_buffer_history_size
|
||||
let l:history = l:history[1:]
|
||||
endif
|
||||
|
||||
call add(l:history, {
|
||||
\ 'status': a:status,
|
||||
\ 'job_id': a:job_id,
|
||||
\ 'command': a:command,
|
||||
\})
|
||||
|
||||
let g:ale_buffer_info[a:buffer].history = l:history
|
||||
endfunction
|
||||
|
||||
function! s:FindHistoryItem(buffer, job_id) abort
|
||||
" Search backwards to find a matching job ID. IDs might be recycled,
|
||||
" so finding the last one should be good enough.
|
||||
for l:obj in reverse(g:ale_buffer_info[a:buffer].history[:])
|
||||
if l:obj.job_id == a:job_id
|
||||
return l:obj
|
||||
endif
|
||||
endfor
|
||||
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
" Set an exit code for a command which finished.
|
||||
function! ale#history#SetExitCode(buffer, job_id, exit_code) abort
|
||||
let l:obj = s:FindHistoryItem(a:buffer, a:job_id)
|
||||
|
||||
if !empty(l:obj)
|
||||
" If we find a match, then set the code and status.
|
||||
let l:obj.exit_code = a:exit_code
|
||||
let l:obj.status = 'finished'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Set the output for a command which finished.
|
||||
function! ale#history#RememberOutput(buffer, job_id, output) abort
|
||||
let l:obj = s:FindHistoryItem(a:buffer, a:job_id)
|
||||
|
||||
if !empty(l:obj)
|
||||
let l:obj.output = a:output
|
||||
endif
|
||||
endfunction
|
||||
@@ -18,10 +18,14 @@ let s:default_ale_linter_aliases = {
|
||||
" The user defined linter selections will be merged with this Dictionary.
|
||||
"
|
||||
" No linters are used for plaintext files by default.
|
||||
"
|
||||
" Only cargo is enabled for Rust by default.
|
||||
let s:default_ale_linters = {
|
||||
\ 'zsh': ['shell'],
|
||||
\ 'csh': ['shell'],
|
||||
\ 'help': [],
|
||||
\ 'rust': ['cargo'],
|
||||
\ 'text': [],
|
||||
\ 'zsh': ['shell'],
|
||||
\}
|
||||
|
||||
" Testing/debugging helper to unload all linters.
|
||||
@@ -33,6 +37,10 @@ function! s:IsCallback(value) abort
|
||||
return type(a:value) == type('') || type(a:value) == type(function('type'))
|
||||
endfunction
|
||||
|
||||
function! s:IsBoolean(value) abort
|
||||
return type(a:value) == type(0) && (a:value == 0 || a:value == 1)
|
||||
endfunction
|
||||
|
||||
function! ale#linter#PreProcess(linter) abort
|
||||
if type(a:linter) != type({})
|
||||
throw 'The linter object must be a Dictionary'
|
||||
@@ -95,6 +103,10 @@ function! ale#linter#PreProcess(linter) abort
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(l:link, 'read_buffer') && !s:IsBoolean(l:link.read_buffer)
|
||||
throw l:err_prefix . 'value for `read_buffer` must be `0` or `1`'
|
||||
endif
|
||||
|
||||
let l:link_index += 1
|
||||
endfor
|
||||
elseif has_key(a:linter, 'command_callback')
|
||||
@@ -114,6 +126,15 @@ function! ale#linter#PreProcess(linter) abort
|
||||
\ . 'must be defined'
|
||||
endif
|
||||
|
||||
if (
|
||||
\ has_key(a:linter, 'command')
|
||||
\ + has_key(a:linter, 'command_chain')
|
||||
\ + has_key(a:linter, 'command_callback')
|
||||
\) > 1
|
||||
throw 'Only one of `command`, `command_callback`, or `command_chain` '
|
||||
\ . 'should be set'
|
||||
endif
|
||||
|
||||
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
|
||||
|
||||
if type(l:obj.output_stream) != type('')
|
||||
@@ -121,6 +142,25 @@ function! ale#linter#PreProcess(linter) abort
|
||||
throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
|
||||
endif
|
||||
|
||||
" An option indicating that this linter should only be run against the
|
||||
" file on disk.
|
||||
let l:obj.lint_file = get(a:linter, 'lint_file', 0)
|
||||
|
||||
if !s:IsBoolean(l:obj.lint_file)
|
||||
throw '`lint_file` must be `0` or `1`'
|
||||
endif
|
||||
|
||||
" An option indicating that the buffer should be read.
|
||||
let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file)
|
||||
|
||||
if !s:IsBoolean(l:obj.read_buffer)
|
||||
throw '`read_buffer` must be `0` or `1`'
|
||||
endif
|
||||
|
||||
if l:obj.lint_file && l:obj.read_buffer
|
||||
throw 'Only one of `lint_file` or `read_buffer` can be `1`'
|
||||
endif
|
||||
|
||||
return l:obj
|
||||
endfunction
|
||||
|
||||
@@ -156,7 +196,7 @@ function! ale#linter#GetAll(filetype) abort
|
||||
return s:linters[a:filetype]
|
||||
endfunction
|
||||
|
||||
function! s:ResolveFiletype(original_filetype) abort
|
||||
function! ale#linter#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(
|
||||
@@ -177,7 +217,7 @@ function! ale#linter#Get(original_filetypes) abort
|
||||
|
||||
" Handle dot-seperated filetypes.
|
||||
for l:original_filetype in split(a:original_filetypes, '\.')
|
||||
let l:filetype = s:ResolveFiletype(l:original_filetype)
|
||||
let l:filetype = ale#linter#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,
|
||||
@@ -211,25 +251,3 @@ function! ale#linter#Get(original_filetypes) abort
|
||||
|
||||
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
|
||||
|
||||
@@ -11,11 +11,20 @@ function! ale#list#IsQuickfixOpen() abort
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#list#SetLists(loclist) abort
|
||||
function! ale#list#SetLists(buffer, loclist) abort
|
||||
if g:ale_set_quickfix
|
||||
call setqflist(a:loclist)
|
||||
elseif g:ale_set_loclist
|
||||
call setloclist(0, a:loclist)
|
||||
" If windows support is off, bufwinid() may not exist.
|
||||
if exists('*bufwinid')
|
||||
" Set the results on the window for the buffer.
|
||||
call setloclist(bufwinid(str2nr(a:buffer)), a:loclist)
|
||||
else
|
||||
" Set the results in the current window.
|
||||
" This may not be the same window we ran the linters for, but
|
||||
" it's better than nothing.
|
||||
call setloclist(0, a:loclist)
|
||||
endif
|
||||
endif
|
||||
|
||||
" If we don't auto-open lists, bail out here.
|
||||
@@ -27,10 +36,12 @@ function! ale#list#SetLists(loclist) abort
|
||||
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
|
||||
if !ale#list#IsQuickfixOpen()
|
||||
if g:ale_set_quickfix
|
||||
copen
|
||||
elseif g:ale_set_loclist
|
||||
lopen
|
||||
endif
|
||||
endif
|
||||
|
||||
" If focus changed, restore it (jump to the last window).
|
||||
|
||||
@@ -1,37 +1,6 @@
|
||||
" 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
|
||||
" based on ALE's internal loclist.
|
||||
|
||||
" Search for the nearest line either before or after the current position
|
||||
" in the loclist. The argument 'wrap' can be passed to enable wrapping
|
||||
@@ -41,18 +10,15 @@ endfunction
|
||||
" 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]}
|
||||
let l:pos = getcurpos()
|
||||
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
|
||||
" This list will have already been sorted.
|
||||
let l:loclist = l:info.loclist
|
||||
let l:search_item = {'lnum': l:pos[1], 'col': l:pos[2]}
|
||||
|
||||
" When searching backwards, so we can find the next smallest match.
|
||||
if a:direction ==# 'before'
|
||||
call reverse(l:loclist)
|
||||
let l:loclist = reverse(copy(l:loclist))
|
||||
endif
|
||||
|
||||
" Look for items before or after the current position.
|
||||
@@ -81,8 +47,8 @@ function! ale#loclist_jumping#FindNearest(direction, wrap) abort
|
||||
|
||||
" 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)
|
||||
if a:wrap && !empty(l:loclist)
|
||||
let l:item = l:loclist[0]
|
||||
|
||||
return [l:item.lnum, l:item.col]
|
||||
endif
|
||||
|
||||
@@ -12,14 +12,6 @@ if !hlexists('ALEWarningSign')
|
||||
highlight link ALEWarningSign todo
|
||||
endif
|
||||
|
||||
if !hlexists('ALEError')
|
||||
highlight link ALEError SpellBad
|
||||
endif
|
||||
|
||||
if !hlexists('ALEWarning')
|
||||
highlight link ALEWarning SpellCap
|
||||
endif
|
||||
|
||||
" Signs show up on the left for error markers.
|
||||
execute 'sign define ALEErrorSign text=' . g:ale_sign_error
|
||||
\ . ' texthl=ALEErrorSign'
|
||||
@@ -36,26 +28,30 @@ function! ale#sign#ReadSigns(buffer) abort
|
||||
return split(l:output, "\n")
|
||||
endfunction
|
||||
|
||||
" Given a list of lines for sign output, return a list of sign IDs
|
||||
" Given a list of lines for sign output, return a List of pairs [line, id]
|
||||
function! ale#sign#ParseSigns(line_list) abort
|
||||
" Matches output like :
|
||||
" line=4 id=1 name=ALEErrorSign
|
||||
" строка=1 id=1000001 имя=ALEErrorSign
|
||||
" 行=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 = []
|
||||
" riga=1 id=1000001, nome=ALEWarningSign
|
||||
let l:pattern = '^.*=\(\d\+\).*=\(\d\+\).*=ALE\(Error\|Warning\|Dummy\)Sign'
|
||||
let l:result = []
|
||||
|
||||
for l:line in a:line_list
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) > 0
|
||||
call add(l:id_list, l:match[1] + 0)
|
||||
call add(l:result, [
|
||||
\ str2nr(l:match[1]),
|
||||
\ str2nr(l:match[2]),
|
||||
\ 'ALE' . l:match[3] . 'Sign',
|
||||
\])
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:id_list
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
function! ale#sign#FindCurrentSigns(buffer) abort
|
||||
@@ -64,90 +60,144 @@ function! ale#sign#FindCurrentSigns(buffer) abort
|
||||
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.
|
||||
function! ale#sign#CombineSigns(loclist) abort
|
||||
let l:signlist = []
|
||||
" Given a loclist, group the List into with one List per line.
|
||||
function! s:GroupLoclistItems(loclist) abort
|
||||
let l:grouped_items = []
|
||||
let l:last_lnum = -1
|
||||
|
||||
for l:obj in a:loclist
|
||||
let l:should_append = 1
|
||||
|
||||
if l:obj.lnum < 1
|
||||
" Skip warnings and errors at line 0, etc.
|
||||
continue
|
||||
" Create a new sub-List when we hit a new line.
|
||||
if l:obj.lnum != l:last_lnum
|
||||
call add(l:grouped_items, [])
|
||||
endif
|
||||
|
||||
if len(l:signlist) > 0 && l:signlist[-1].lnum == l:obj.lnum
|
||||
" We can't add the same line twice, because signs must be
|
||||
" unique per line.
|
||||
let l:should_append = 0
|
||||
|
||||
if l:signlist[-1].type ==# 'W' && l:obj.type ==# 'E'
|
||||
" If we had a warning previously, but now have an error,
|
||||
" we replace the object to set an error instead.
|
||||
let l:signlist[-1] = l:obj
|
||||
endif
|
||||
endif
|
||||
|
||||
if l:should_append
|
||||
call add(l:signlist, l:obj)
|
||||
endif
|
||||
call add(l:grouped_items[-1], l:obj)
|
||||
let l:last_lnum = l:obj.lnum
|
||||
endfor
|
||||
|
||||
return l:signlist
|
||||
return l:grouped_items
|
||||
endfunction
|
||||
|
||||
" This function will set the signs which show up on the left.
|
||||
function! ale#sign#SetSigns(buffer, loclist) abort
|
||||
let l:signlist = ale#sign#CombineSigns(a:loclist)
|
||||
function! s:IsDummySignSet(current_id_list) abort
|
||||
for [l:line, l:id, l:name] in a:current_id_list
|
||||
if l:id == g:ale_sign_offset
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Find the current markers
|
||||
let l:current_id_list = ale#sign#FindCurrentSigns(a:buffer)
|
||||
let l:dummy_sign_set = 0
|
||||
|
||||
" Check if we set the dummy sign already.
|
||||
for l:current_id in l:current_id_list
|
||||
if l:current_id == g:ale_sign_offset
|
||||
let l:dummy_sign_set = 1
|
||||
if l:line > 1
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! s:SetDummySignIfNeeded(buffer, current_sign_list, new_signs) abort
|
||||
let l:is_dummy_sign_set = s:IsDummySignSet(a:current_sign_list)
|
||||
|
||||
" 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)
|
||||
if !l:is_dummy_sign_set && (a:new_signs || 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
|
||||
let l:is_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
|
||||
return l:is_dummy_sign_set
|
||||
endfunction
|
||||
|
||||
function! s:PlaceNewSigns(buffer, grouped_items) abort
|
||||
" Add the new signs,
|
||||
for l:index in range(0, len(a:grouped_items) - 1)
|
||||
let l:sign_id = l:index + g:ale_sign_offset + 1
|
||||
let l:sublist = a:grouped_items[l:index]
|
||||
let l:type = !empty(filter(copy(l:sublist), 'v:val.type ==# ''E'''))
|
||||
\ ? 'ALEErrorSign'
|
||||
\ : 'ALEWarningSign'
|
||||
|
||||
" Save the sign IDs we are setting back on our loclist objects.
|
||||
" These IDs will be used to preserve items which are set many times.
|
||||
for l:obj in l:sublist
|
||||
let l:obj.sign_id = l:sign_id
|
||||
endfor
|
||||
|
||||
execute 'sign place ' . l:sign_id
|
||||
\ . ' line=' . l:sublist[0].lnum
|
||||
\ . ' name=' . l:type
|
||||
\ . ' buffer=' . a:buffer
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Get items grouped by any current sign IDs they might have.
|
||||
function! s:GetItemsWithSignIDs(loclist) abort
|
||||
let l:items_by_sign_id = {}
|
||||
|
||||
for l:item in a:loclist
|
||||
if has_key(l:item, 'sign_id')
|
||||
if !has_key(l:items_by_sign_id, l:item.sign_id)
|
||||
let l:items_by_sign_id[l:item.sign_id] = []
|
||||
endif
|
||||
|
||||
call add(l:items_by_sign_id[l:item.sign_id], l:item)
|
||||
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'
|
||||
return l:items_by_sign_id
|
||||
endfunction
|
||||
|
||||
let l:sign_line = 'sign place ' . (l:index + g:ale_sign_offset + 1)
|
||||
\. ' line=' . l:sign['lnum']
|
||||
\. ' name=' . l:type
|
||||
\. ' buffer=' . a:buffer
|
||||
" Given some current signs and a loclist, look for items with sign IDs,
|
||||
" and change the line numbers for loclist items to match the signs.
|
||||
function! s:UpdateLineNumbers(current_sign_list, loclist) abort
|
||||
let l:items_by_sign_id = s:GetItemsWithSignIDs(a:loclist)
|
||||
|
||||
exec l:sign_line
|
||||
" Do nothing if there's nothing to work with.
|
||||
if empty(l:items_by_sign_id)
|
||||
return
|
||||
endif
|
||||
|
||||
for [l:line, l:sign_id, l:name] in a:current_sign_list
|
||||
for l:obj in get(l:items_by_sign_id, l:sign_id, [])
|
||||
let l:obj.lnum = l:line
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" Sort items again.
|
||||
call sort(a:loclist, 'ale#util#LocItemCompare')
|
||||
endfunction
|
||||
|
||||
" This function will set the signs which show up on the left.
|
||||
function! ale#sign#SetSigns(buffer, loclist) abort
|
||||
" Find the current markers
|
||||
let l:current_sign_list = ale#sign#FindCurrentSigns(a:buffer)
|
||||
|
||||
call s:UpdateLineNumbers(l:current_sign_list, a:loclist)
|
||||
|
||||
let l:grouped_items = s:GroupLoclistItems(a:loclist)
|
||||
|
||||
" Set the dummy sign if we need to.
|
||||
" This keeps the sign gutter open while we remove things, etc.
|
||||
let l:is_dummy_sign_set = s:SetDummySignIfNeeded(
|
||||
\ a:buffer,
|
||||
\ l:current_sign_list,
|
||||
\ !empty(l:grouped_items),
|
||||
\)
|
||||
|
||||
" 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:line, l:sign_id, l:name] in l:current_sign_list
|
||||
if l:sign_id != g:ale_sign_offset
|
||||
exec 'sign unplace ' . l:sign_id . ' buffer=' . a:buffer
|
||||
endif
|
||||
endfor
|
||||
|
||||
call s:PlaceNewSigns(a:buffer, l:grouped_items)
|
||||
|
||||
" 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
|
||||
if l:is_dummy_sign_set && !g:ale_sign_column_always
|
||||
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
|
||||
endif
|
||||
endfunction
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user