Compare commits

..

4 Commits

Author SHA1 Message Date
w0rp
97b410bbba Merge pull request #342 from Exteris/bugfix/gfortran-6.3.1
Update line marker pattern for new gfortran
2017-02-21 20:38:57 +00:00
Chris Paul
78b05d30a5 escape dot in maker regex (#357)
* escape dot in maker regex

* Create test_typecheck_handler

* Rename test_typecheck_handler to test_typecheck_handler.vader
2017-02-21 20:33:16 +00:00
w0rp
6f6c156995 Fix Pug linting 2017-02-11 20:47:11 +00:00
w0rp
62a45f8ae4 Don't export the custom-checks script in archives 2017-02-09 19:34:31 +00:00
165 changed files with 1099 additions and 5352 deletions

3
.gitattributes vendored
View File

@@ -1,9 +1,8 @@
.* export-ignore .* export-ignore
/CONTRIBUTING.md export-ignore /CONTRIBUTING.md export-ignore
/Dockerfile export-ignore /Dockerfile export-ignore
/ISSUE_TEMPLATE.md export-ignore
/Makefile export-ignore /Makefile export-ignore
/README.md export-ignore /README.md export-ignore
/custom-checks export-ignore
/img export-ignore /img export-ignore
/test export-ignore /test export-ignore
/custom-checks export-ignore

View File

@@ -5,11 +5,6 @@
3. [Creating Pull Requests](#pull-requests) 3. [Creating Pull Requests](#pull-requests)
1. [Adding a New Linter](#adding-a-new-linter) 1. [Adding a New Linter](#adding-a-new-linter)
2. [Adding New Options](#adding-new-options) 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> <a name="guidelines"></a>
@@ -17,12 +12,6 @@
Have fun, and work on whatever floats your boat. Take It Easy :tm:. 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 When writing code, follow the [Google Vimscript Style
Guide](https://google.github.io/styleguide/vimscriptguide.xml), and run `vint 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 -s` on your files to check for most of what the guide mentions and more. If you
@@ -101,73 +90,3 @@ global variable names.
Any options for linters should be set to some default value so it is always 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...`. 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.

View File

@@ -1,10 +0,0 @@
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.

View File

@@ -2,20 +2,11 @@ SHELL := /usr/bin/env bash
IMAGE ?= w0rp/ale IMAGE ?= w0rp/ale
CURRENT_IMAGE_ID = 107e4efc4267 CURRENT_IMAGE_ID = 107e4efc4267
DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)" DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)"
tests = test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*/*.vader
test-setup: test-setup:
docker images -q w0rp/ale | grep ^$(CURRENT_IMAGE_ID) > /dev/null || \ docker images -q w0rp/ale | grep ^$(CURRENT_IMAGE_ID) > /dev/null || \
docker pull $(IMAGE) 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 test: test-setup
@:; \ @:; \
vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \ vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \
@@ -27,7 +18,7 @@ test: test-setup
echo "Running tests for $$vim"; \ echo "Running tests for $$vim"; \
echo '========================================'; \ echo '========================================'; \
echo; \ echo; \
docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! $(tests)' || EXIT=$$?; \ docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! test/*' || EXIT=$$?; \
done; \ done; \
echo; \ echo; \
echo '========================================'; \ echo '========================================'; \

132
README.md
View File

@@ -23,8 +23,7 @@ In other words, this plugin allows you to lint while you type.
1. [Installation with Pathogen](#installation-with-pathogen) 1. [Installation with Pathogen](#installation-with-pathogen)
2. [Installation with Vundle](#installation-with-vundle) 2. [Installation with Vundle](#installation-with-vundle)
3. [Manual Installation](#manual-installation) 3. [Manual Installation](#manual-installation)
4. [Contributing](#contributing) 4. [FAQ](#faq)
5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters) 1. [How do I disable particular linters?](#faq-disable-linters)
2. [How can I keep the sign gutter open?](#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) 3. [How can I change the signs ALE uses?](#faq-change-signs)
@@ -34,8 +33,6 @@ In other words, this plugin allows you to lint while you type.
7. [How can I navigate between errors quickly?](#faq-navigation) 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) 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) 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> <a name="supported-languages"></a>
@@ -53,14 +50,12 @@ name. That seems to be the fairest way to arrange this table.
| Language | Tools | | Language | Tools |
| -------- | ----- | | -------- | ----- |
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) | | 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/) | | 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/) | | 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 | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.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++ (filetype cpp) | [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) | | C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
| Chef | [foodcritic](http://www.foodcritic.io/) | | 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) | | CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
| CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) | | CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) |
| Cython (pyrex filetype) | [cython](http://cython.org/) | | Cython (pyrex filetype) | [cython](http://cython.org/) |
@@ -71,46 +66,40 @@ name. That seems to be the fairest way to arrange this table.
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html) | | Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
| Fortran | [gcc](https://gcc.gnu.org/) | | 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/) | | 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/) |
| Haml | [haml-lint](https://github.com/brigade/haml-lint) | Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint) |
| 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/), [tidy](http://www.html-tidy.org/) |
| HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) | | JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.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/) | | JSON | [jsonlint](http://zaa.ch/jsonlint/) |
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck) | | LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck) |
| Lua | [luacheck](https://github.com/mpeterv/luacheck) | | Lua | [luacheck](https://github.com/mpeterv/luacheck) |
| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/)| | Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/)|
| MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) | | 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 | 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) | | Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) | | PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
| Pod | [proselint](http://proselint.com/)|
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) | | Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) | | 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/) | | 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) | | Ruby | [rubocop](https://github.com/bbatsov/rubocop) |
| Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) | | 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) | | 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) | | SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
| Scala | [scalac](http://scala-lang.org) | | Scala | [scalac](http://scala-lang.org) |
| Slim | [slim-lint](https://github.com/sds/slim-lint)
| SML | [smlnj](http://www.smlnj.org/) |
| Swift | [swiftlint](https://swift.org/) | | Swift | [swiftlint](https://swift.org/) |
| Tex | [proselint](http://proselint.com/) | | Tex | [proselint](http://proselint.com/) |
| Texinfo | [proselint](http://proselint.com/)| | Text^^ | [proselint](http://proselint.com/) |
| Text^ | [proselint](http://proselint.com/) |
| TypeScript | [tslint](https://github.com/palantir/tslint), typecheck | | TypeScript | [tslint](https://github.com/palantir/tslint), typecheck |
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) | | Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
| Vim | [vint](https://github.com/Kuniwak/vint) | | Vim | [vint](https://github.com/Kuniwak/vint) |
| Vim help^ | [proselint](http://proselint.com/)|
| XHTML | [proselint](http://proselint.com/)|
| YAML | [yamllint](https://yamllint.readthedocs.io/) | | YAML | [yamllint](https://yamllint.readthedocs.io/) |
* *^ No linters for text or Vim help filetypes are enabled by default.* * *^^ 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.
<a name="usage"></a> <a name="usage"></a>
@@ -200,27 +189,13 @@ silent! helptags ALL
Because the author of this plugin is a weird nerd, this is his preferred Because the author of this plugin is a weird nerd, this is his preferred
installation method. 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> <a name="faq"></a>
## 5. FAQ ## 4. FAQ
<a name="faq-disable-linters"></a> <a name="faq-disable-linters"></a>
### 5.i. How do I disable particular linters? ### 4.i. How do I disable particular linters?
By default, all available tools for all supported languages will be run. 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 If you want to only select a subset of the tools, simply create a
@@ -244,7 +219,7 @@ in each directory corresponds to the name of a particular linter.
<a name="faq-keep-signs"></a> <a name="faq-keep-signs"></a>
### 5.ii. How can I keep the sign gutter open? ### 4.ii. How can I keep the sign gutter open?
You can keep the sign gutter open at all times by setting the You can keep the sign gutter open at all times by setting the
`g:ale_sign_column_always` to 1 `g:ale_sign_column_always` to 1
@@ -255,7 +230,7 @@ let g:ale_sign_column_always = 1
<a name="faq-change-signs"></a> <a name="faq-change-signs"></a>
### 5.iii. How can I change the signs ALE uses? ### 4.iii. How can I change the signs ALE uses?
Use these options to specify what text should be used for signs: Use these options to specify what text should be used for signs:
@@ -275,7 +250,7 @@ highlight clear ALEWarningSign
<a name="faq-statusline"></a> <a name="faq-statusline"></a>
### 5.iv. How can I show errors or warnings in my statusline? ### 4.iv. How can I show errors or warnings in my statusline?
You can use `ALEGetStatusLine()` to integrate ALE into vim statusline. You can use `ALEGetStatusLine()` to integrate ALE into vim statusline.
To enable it, you should have in your `statusline` settings To enable it, you should have in your `statusline` settings
@@ -302,7 +277,7 @@ let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
<a name="faq-echo-format"></a> <a name="faq-echo-format"></a>
### 5.v. How can I change the format for echo messages? ### 4.v. How can I change the format for echo messages?
There are 3 global options that allow customizing the echoed message. There are 3 global options that allow customizing the echoed message.
@@ -327,7 +302,7 @@ Will give you:
<a name="faq-autocmd"></a> <a name="faq-autocmd"></a>
### 5.vi. How can I execute some code when ALE stops linting? ### 4.vi. How can I execute some code when ALE stops linting?
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html) ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
event whenever has a linter has been successfully executed and processed. This event whenever has a linter has been successfully executed and processed. This
@@ -342,7 +317,7 @@ augroup END
<a name="faq-navigation"></a> <a name="faq-navigation"></a>
### 5.vii. How can I navigate between errors quickly? ### 4.vii. How can I navigate between errors quickly?
ALE offers some commands with `<Plug>` keybinds for moving between warnings and 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 errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
@@ -358,7 +333,7 @@ For more information, consult the online documentation with
<a name="faq-lint-on-save"></a> <a name="faq-lint-on-save"></a>
### 5.viii. How can I run linters only when I save files? ### 4.viii. How can I run linters only when I save files?
ALE offers an option `g:ale_lint_on_save` for enabling running the linters 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 when files are saved. If you wish to run linters when files are saved, not
@@ -376,7 +351,7 @@ let g:ale_lint_on_enter = 0
<a name="faq-quickfix"></a> <a name="faq-quickfix"></a>
### 5.ix. How can I use the quickfix list instead of the loclist? ### 4.ix. How can I use the quickfix list instead of the loclist?
The quickfix list can be enabled by turning the `g:ale_set_quickfix` 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 option on. If you wish to also disable the loclist, you can disable
@@ -400,62 +375,3 @@ let g:ale_open_list = 1
" some other plugin which sets quickfix errors, etc. " some other plugin which sets quickfix errors, etc.
let g:ale_keep_list_window_open = 1 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()`.

View File

@@ -1,37 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Follow-up checks for the plugin: warn about conflicting plugins.
" A flag for ensuring that this is not run more than one time.
if exists('g:loaded_ale_after')
finish
endif
" Set the flag so this file is not run more than one time.
let g:loaded_ale_after = 1
" Check if the flag is available and set to 0 to disable checking for and
" emitting conflicting plugin warnings.
if exists('g:ale_emit_conflict_warnings') && !g:ale_emit_conflict_warnings
finish
endif
" Conflicting Plugins Checks
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

View File

@@ -4,6 +4,6 @@
call ale#linter#Define('ansible', { call ale#linter#Define('ansible', {
\ 'name': 'ansible', \ 'name': 'ansible',
\ 'executable': 'ansible', \ 'executable': 'ansible',
\ 'command': 'ansible-lint -p %t', \ 'command': g:ale#util#stdin_wrapper . ' .yml ansible-lint -p',
\ 'callback': 'ale#handlers#HandlePEP8Format', \ 'callback': 'ale#handlers#HandlePEP8Format',
\}) \})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -9,18 +9,12 @@ if !exists('g:ale_c_clang_options')
let g:ale_c_clang_options = '-std=c11 -Wall' let g:ale_c_clang_options = '-std=c11 -Wall'
endif 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', { call ale#linter#Define('c', {
\ 'name': 'clang', \ 'name': 'clang',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'clang', \ 'executable': 'clang',
\ 'command_callback': 'ale_linters#c#clang#GetCommand', \ 'command': 'clang -S -x c -fsyntax-only '
\ . g:ale_c_clang_options
\ . ' -',
\ 'callback': 'ale#handlers#HandleGCCFormat', \ 'callback': 'ale#handlers#HandleGCCFormat',
\}) \})

View File

@@ -2,14 +2,15 @@
" Description: cppcheck linter for c files " Description: cppcheck linter for c files
" Set this option to change the cppcheck options " Set this option to change the cppcheck options
let g:ale_c_cppcheck_options = get(g:, 'ale_c_cppcheck_options', '--enable=style') if !exists('g:ale_c_cppcheck_options')
let g:ale_c_cppcheck_options = '--enable=style'
endif
call ale#linter#Define('c', { call ale#linter#Define('c', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable': 'cppcheck', \ 'executable': 'cppcheck',
\ 'command': 'cppcheck -q --language=c ' \ 'command': g:ale#util#stdin_wrapper . ' .c cppcheck -q --language=c '
\ . g:ale_c_cppcheck_options \ . g:ale_c_cppcheck_options,
\ . ' %t',
\ 'callback': 'ale#handlers#HandleCppCheckFormat', \ 'callback': 'ale#handlers#HandleCppCheckFormat',
\}) \})

View File

@@ -10,11 +10,9 @@ if !exists('g:ale_c_gcc_options')
endif endif
function! ale_linters#c#gcc#GetCommand(buffer) abort 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 ' return 'gcc -S -x c -fsyntax-only '
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h')) \ . g:ale_c_gcc_options . ' -'
\ . ' ' . g:ale_c_gcc_options . ' -'
endfunction endfunction
call ale#linter#Define('c', { call ale#linter#Define('c', {

View File

@@ -17,12 +17,15 @@ function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
let l:text = l:match[1] let l:text = l:match[1]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0, \ 'lnum': l:match[3] + 0,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': 'W', \ 'type': 'W',
\ 'nr': -1,
\}) \})
endfor endfor
@@ -32,7 +35,7 @@ endfunction
call ale#linter#Define('chef', { call ale#linter#Define('chef', {
\ 'name': 'foodcritic', \ 'name': 'foodcritic',
\ 'executable': 'foodcritic', \ 'executable': 'foodcritic',
\ 'command': 'foodcritic %t', \ 'command': g:ale#util#stdin_wrapper . ' .rb foodcritic',
\ 'callback': 'ale_linters#chef#foodcritic#Handle', \ 'callback': 'ale_linters#chef#foodcritic#Handle',
\}) \})

View File

@@ -1,24 +0,0 @@
" 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',
\})

View File

@@ -1,23 +1,10 @@
" Author: KabbAmine - https://github.com/KabbAmine " Author: KabbAmine - https://github.com/KabbAmine
" Description: Coffee for checking coffee files " 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', { call ale#linter#Define('coffee', {
\ 'name': 'coffee', \ 'name': 'coffee',
\ 'executable_callback': 'ale_linters#coffee#coffee#GetExecutable', \ 'executable': 'coffee',
\ 'command_callback': 'ale_linters#coffee#coffee#GetCommand', \ 'command': 'coffee -cp -s',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#HandleGCCFormat', \ 'callback': 'ale#handlers#HandleGCCFormat',
\}) \})

View File

@@ -1,19 +1,6 @@
" Author: Prashanth Chandra https://github.com/prashcr " Author: Prashanth Chandra https://github.com/prashcr
" Description: coffeelint linter for coffeescript files " 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 function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
" Matches patterns like the following: " Matches patterns like the following:
" "
@@ -21,7 +8,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
" stdin,14,,error,Throwing strings is forbidden " stdin,14,,error,Throwing strings is forbidden
" "
" Note that we currently ignore lineNumberEnd for multiline errors " Note that we currently ignore lineNumberEnd for multiline errors
let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\{-1,}\),\(.\+\)' let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\+\),\(.\+\)'
let l:output = [] let l:output = []
for l:line in a:lines for l:line in a:lines
@@ -32,14 +19,19 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
endif endif
let l:line = l:match[1] + 0 let l:line = l:match[1] + 0
let l:column = 1
let l:type = l:match[3] ==# 'error' ? 'E' : 'W' let l:type = l:match[3] ==# 'error' ? 'E' : 'W'
let l:text = l:match[4] let l:text = l:match[4]
" vcol is needed to indicate that the column is a character
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor
@@ -48,7 +40,7 @@ endfunction
call ale#linter#Define('coffee', { call ale#linter#Define('coffee', {
\ 'name': 'coffeelint', \ 'name': 'coffeelint',
\ 'executable_callback': 'ale_linters#coffee#coffeelint#GetExecutable', \ 'executable': 'coffeelint',
\ 'command_callback': 'ale_linters#coffee#coffeelint#GetCommand', \ 'command': 'coffeelint --stdin --reporter csv',
\ 'callback': 'ale_linters#coffee#coffeelint#Handle', \ 'callback': 'ale_linters#coffee#coffeelint#Handle',
\}) \})

View File

@@ -1,23 +0,0 @@
" 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',
\})

View File

@@ -1,18 +0,0 @@
" 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',
\})

View File

@@ -2,14 +2,15 @@
" Description: cppcheck linter for cpp files " Description: cppcheck linter for cpp files
" Set this option to change the cppcheck options " Set this option to change the cppcheck options
let g:ale_cpp_cppcheck_options = get(g:, 'ale_cpp_cppcheck_options', '--enable=style') if !exists('g:ale_cpp_cppcheck_options')
let g:ale_cpp_cppcheck_options = '--enable=style'
endif
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable': 'cppcheck', \ 'executable': 'cppcheck',
\ 'command': 'cppcheck -q --language=c++ ' \ 'command': g:ale#util#stdin_wrapper . ' .cpp cppcheck -q --language=c++ '
\ . g:ale_cpp_cppcheck_options \ . g:ale_cpp_cppcheck_options,
\ . ' %t',
\ 'callback': 'ale#handlers#HandleCppCheckFormat', \ 'callback': 'ale#handlers#HandleCppCheckFormat',
\}) \})

View File

@@ -16,11 +16,9 @@ if !exists('g:ale_cpp_gcc_options')
endif endif
function! ale_linters#cpp#gcc#GetCommand(buffer) abort 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 ' return 'gcc -S -x c++ -fsyntax-only '
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h')) \ . g:ale_cpp_gcc_options . ' -'
\ . ' ' . g:ale_cpp_gcc_options . ' -'
endfunction endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {

View File

@@ -1,8 +1,6 @@
let g:ale_cs_mcs_options = get(g:, 'ale_cs_mcs_options', '') if !exists('g:ale_cs_mcs_options')
let g:ale_cs_mcs_options = ''
function! ale_linters#cs#mcs#GetCommand(buffer) abort endif
return 'mcs -unsafe --parse ' . g:ale_cs_mcs_options . ' %t'
endfunction
function! ale_linters#cs#mcs#Handle(buffer, lines) abort function! ale_linters#cs#mcs#Handle(buffer, lines) abort
" Look for lines like the following. " Look for lines like the following.
@@ -21,9 +19,11 @@ function! ale_linters#cs#mcs#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[3] . ': ' . l:match[4], \ 'text': l:match[3] . ': ' . l:match[4],
\ 'type': l:match[3] =~# '^error' ? 'E' : 'W', \ 'type': l:match[3] =~# '^error' ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor
@@ -31,9 +31,10 @@ function! ale_linters#cs#mcs#Handle(buffer, lines) abort
endfunction endfunction
call ale#linter#Define('cs',{ call ale#linter#Define('cs',{
\ 'name': 'mcs', \ 'name': 'mcs',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'mcs', \ 'executable': 'mcs',
\ 'command_callback': 'ale_linters#cs#mcs#GetCommand', \ 'command': g:ale#util#stdin_wrapper . ' .cs mcs -unsafe --parse' . g:ale_cs_mcs_options,
\ 'callback': 'ale_linters#cs#mcs#Handle', \ 'callback': 'ale_linters#cs#mcs#Handle',
\}) \ })

View File

@@ -4,6 +4,6 @@
call ale#linter#Define('css', { call ale#linter#Define('css', {
\ 'name': 'csslint', \ 'name': 'csslint',
\ 'executable': 'csslint', \ 'executable': 'csslint',
\ 'command': 'csslint --format=compact %t', \ 'command': g:ale#util#stdin_wrapper . ' .css csslint --format=compact',
\ 'callback': 'ale#handlers#HandleCSSLintFormat', \ 'callback': 'ale#handlers#HandleCSSLintFormat',
\}) \})

View File

@@ -3,9 +3,6 @@
let g:ale_css_stylelint_executable = let g:ale_css_stylelint_executable =
\ get(g:, 'ale_css_stylelint_executable', 'stylelint') \ 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 = let g:ale_css_stylelint_use_global =
\ get(g:, 'ale_css_stylelint_use_global', 0) \ get(g:, 'ale_css_stylelint_use_global', 0)
@@ -23,7 +20,6 @@ endfunction
function! ale_linters#css#stylelint#GetCommand(buffer) abort function! ale_linters#css#stylelint#GetCommand(buffer) abort
return ale_linters#css#stylelint#GetExecutable(a:buffer) return ale_linters#css#stylelint#GetExecutable(a:buffer)
\ . ' ' . g:ale_css_stylelint_options
\ . ' --stdin-filename %s' \ . ' --stdin-filename %s'
endfunction endfunction

View File

@@ -46,7 +46,9 @@ function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort
endif endif
endfor endfor
return 'dmd '. join(l:import_list) . ' -o- -vcolumns -c %t' return g:ale#util#stdin_wrapper . ' .d dmd '
\ . join(l:import_list)
\ . ' -o- -vcolumns -c'
endfunction endfunction
function! ale_linters#d#dmd#Handle(buffer, lines) abort function! ale_linters#d#dmd#Handle(buffer, lines) abort
@@ -68,12 +70,15 @@ function! ale_linters#d#dmd#Handle(buffer, lines) abort
let l:type = l:match[3] let l:type = l:match[3]
let l:text = l:match[4] let l:text = l:match[4]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': bufnr('%'), \ 'bufnr': bufnr('%'),
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column, \ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type ==# 'Warning' ? 'W' : 'E', \ 'type': l:type ==# 'Warning' ? 'W' : 'E',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -23,9 +23,11 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
let l:type = 'W' let l:type = 'W'
let l:text = l:match[3] let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:lnum, \ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'type': l:type, \ 'type': l:type,
\ 'text': l:text, \ 'text': l:text,

View File

@@ -3,8 +3,8 @@
function! ale_linters#elixir#credo#Handle(buffer, lines) abort function! ale_linters#elixir#credo#Handle(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
" lib/filename.ex:19:7: F: Pipe chain should start with a raw value. " stdin:19: F: Pipe chain should start with a raw value.
let l:pattern = '\v:(\d+):?(\d+)?: (.): (.+)$' let l:pattern = '\v^stdin:(\d+):?(\d+)?: (.): (.+)$'
let l:output = [] let l:output = []
for l:line in a:lines for l:line in a:lines
@@ -23,12 +23,15 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
let l:type = 'W' let l:type = 'W'
endif endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'type': l:type, \ 'type': l:type,
\ 'text': l:text, \ 'text': l:text,
\ 'nr': -1,
\}) \})
endfor endfor
@@ -38,5 +41,5 @@ endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'credo', \ 'name': 'credo',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': 'mix credo suggest --format=flycheck --read-from-stdin %s', \ 'command': 'mix credo suggest --format=flycheck --read-from-stdin',
\ 'callback': 'ale_linters#elixir#credo#Handle' }) \ 'callback': 'ale_linters#elixir#credo#Handle' })

View File

@@ -22,10 +22,11 @@ function! ale_linters#elm#make#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:error.region.start.line, \ 'lnum': l:error.region.start.line,
\ 'vcol': 0,
\ 'col': l:error.region.start.column, \ 'col': l:error.region.start.column,
\ 'type': (l:error.type ==? 'error') ? 'E' : 'W', \ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
\ 'text': l:error.overview, \ 'text': l:error.overview,
\ 'detail': l:error.overview . "\n\n" . l:error.details \ 'nr': -1,
\}) \})
endif endif
endfor endfor
@@ -51,8 +52,9 @@ function! ale_linters#elm#make#GetCommand(buffer) abort
" which is why this is hard coded here. " which is why this is hard coded here.
" Source: https://github.com/elm-lang/elm-make/blob/master/src/Flags.hs " 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: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:elm_cmd . ' %t' return l:dir_set_cmd . ' ' . l:stdin_wrapper . ' ' . l:elm_cmd
endfunction endfunction
call ale#linter#Define('elm', { call ale#linter#Define('elm', {

View File

@@ -3,9 +3,7 @@
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '') let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
function! ale_linters#erlang#erlc#GetCommand(buffer) abort function! ale_linters#erlang#erlc#GetCommand(buffer) abort
let l:output_file = tempname() return g:ale#util#stdin_wrapper . ' .erl erlc ' . g:ale_erlang_erlc_options
call ale#engine#ManageFile(a:buffer, l:output_file)
return 'erlc -o ' . fnameescape(l:output_file) . ' ' . g:ale_erlang_erlc_options . ' %t'
endfunction endfunction
function! ale_linters#erlang#erlc#Handle(buffer, lines) abort function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
@@ -45,9 +43,11 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': 0, \ 'lnum': 0,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'type': 'E', \ 'type': 'E',
\ 'text': l:match_parse_transform[0], \ 'text': l:match_parse_transform[0],
\ 'nr': -1,
\}) \})
continue continue
@@ -73,12 +73,15 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
let l:type = 'E' let l:type = 'E'
endif endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'type': l:type, \ 'type': l:type,
\ 'text': l:text, \ 'text': l:text,
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -41,7 +41,9 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
let l:last_loclist_obj = { let l:last_loclist_obj = {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'nr': -1,
\} \}
" Start looking for the message and error type. " Start looking for the message and error type.

View File

@@ -101,12 +101,6 @@ function! ale_linters#go#gobuild#CopyFiles(buffer, golist_output) abort
endfunction endfunction
function! ale_linters#go#gobuild#GetCommand(buffer, copy_output) abort 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:tempdir = a:copy_output[0]
let l:importpath = s:PackageImportPath(a:buffer) let l:importpath = s:PackageImportPath(a:buffer)
@@ -196,9 +190,11 @@ function! ale_linters#go#gobuild#Handler(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': l:buffer, \ 'bufnr': l:buffer,
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'text': l:match[4], \ 'text': l:match[4],
\ 'type': 'E', \ 'type': 'E',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -5,6 +5,6 @@ call ale#linter#Define('go', {
\ 'name': 'gofmt', \ 'name': 'gofmt',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gofmt', \ 'executable': 'gofmt',
\ 'command': 'gofmt -e %t', \ 'command': g:ale#util#stdin_wrapper . ' .go gofmt -e',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError', \ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\}) \})

View File

@@ -4,6 +4,6 @@
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'golint', \ 'name': 'golint',
\ 'executable': 'golint', \ 'executable': 'golint',
\ 'command': 'golint %t', \ 'command': g:ale#util#stdin_wrapper . ' .go golint',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning', \ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\}) \})

View File

@@ -5,6 +5,6 @@ call ale#linter#Define('go', {
\ 'name': 'go vet', \ 'name': 'go vet',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'go', \ 'executable': 'go',
\ 'command': 'go vet %t', \ 'command': g:ale#util#stdin_wrapper . ' .go go vet',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError', \ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\}) \})

View File

@@ -1,33 +0,0 @@
" 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'
\})

View File

@@ -1,18 +1,73 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: ghc for Haskell files " 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', { call ale#linter#Define('haskell', {
\ 'name': 'ghc', \ 'name': 'ghc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'ghc', \ 'executable': 'ghc',
\ 'command': 'ghc -fno-code -v0 %t', \ 'command': g:ale#util#stdin_wrapper . ' .hs ghc -fno-code -v0',
\ 'callback': 'ale#handlers#HandleGhcFormat', \ 'callback': 'ale_linters#haskell#ghc#Handle',
\}) \})
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'stack-ghc', \ 'name': 'stack-ghc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'stack', \ 'executable': 'stack',
\ 'command': 'stack ghc -- -fno-code -v0 %t', \ 'command': g:ale#util#stdin_wrapper . ' .hs stack ghc -- -fno-code -v0',
\ 'callback': 'ale#handlers#HandleGhcFormat', \ 'callback': 'ale_linters#haskell#ghc#Handle',
\}) \})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -7,9 +7,11 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:output = [] let l:output = []
for l:error in l:errors for l:error in l:errors
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:error.startLine + 0, \ 'lnum': l:error.startLine + 0,
\ 'vcol': 0,
\ 'col': l:error.startColumn + 0, \ 'col': l:error.startColumn + 0,
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to, \ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W', \ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -23,9 +23,9 @@ function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#html#htmlhint#GetCommand(buffer) abort function! ale_linters#html#htmlhint#GetCommand(buffer) abort
return ale_linters#html#htmlhint#GetExecutable(a:buffer) return g:ale#util#stdin_wrapper . ' .html '
\ . ale_linters#html#htmlhint#GetExecutable(a:buffer)
\ . ' ' . g:ale_html_htmlhint_options \ . ' ' . g:ale_html_htmlhint_options
\ . ' %t'
endfunction endfunction
call ale#linter#Define('html', { call ale#linter#Define('html', {

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -49,12 +49,15 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
let l:type = l:match[3] ==# 'Error' ? 'E' : 'W' let l:type = l:match[3] ==# 'Error' ? 'E' : 'W'
let l:text = l:match[4] let l:text = l:match[4]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col, \ 'col': l:col,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -1,51 +0,0 @@
" 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,
\ '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',
\})

View File

@@ -29,21 +29,6 @@ function! ale_linters#javascript#eslint#GetCommand(buffer) abort
endfunction endfunction
function! ale_linters#javascript#eslint#Handle(buffer, lines) abort 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: " Matches patterns line the following:
" "
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle] " /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
@@ -76,12 +61,15 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
let l:text .= ' [' . l:match[4] . ']' let l:text .= ' [' . l:match[4] . ']'
endif endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type ==# 'Warning' ? 'W' : 'E', \ 'type': l:type ==# 'Warning' ? 'W' : 'E',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -8,73 +8,68 @@ let g:ale_javascript_flow_use_global =
\ get(g:, 'ale_javascript_flow_use_global', 0) \ get(g:, 'ale_javascript_flow_use_global', 0)
function! ale_linters#javascript#flow#GetExecutable(buffer) abort function! ale_linters#javascript#flow#GetExecutable(buffer) abort
if g:ale_javascript_flow_use_global if g:ale_javascript_flow_use_global
return g:ale_javascript_flow_executable return g:ale_javascript_flow_executable
endif endif
return ale#util#ResolveLocalPath( return ale#util#ResolveLocalPath(
\ a:buffer, \ a:buffer,
\ 'node_modules/.bin/flow', \ 'node_modules/.bin/flow',
\ g:ale_javascript_flow_executable \ g:ale_javascript_flow_executable
\) \)
endfunction endfunction
function! ale_linters#javascript#flow#GetCommand(buffer) abort function! ale_linters#javascript#flow#GetCommand(buffer) abort
let l:flow_config = ale#util#FindNearestFile(a:buffer, '.flowconfig') return ale_linters#javascript#flow#GetExecutable(a:buffer)
\ . ' check-contents --respect-pragma --json --from ale %s'
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 endfunction
function! ale_linters#javascript#flow#Handle(buffer, lines) abort function! ale_linters#javascript#flow#Handle(buffer, lines) abort
let l:str = join(a:lines, '') let l:str = join(a:lines, '')
if l:str ==# ''
return []
endif
let l:flow_output = json_decode(l:str)
if l:str ==# '' if has_key(l:flow_output, 'errors')
return []
endif
let l:flow_output = json_decode(l:str)
let l:output = [] let l:output = []
for l:error in get(l:flow_output, 'errors', []) for l:error in l:flow_output.errors
" Each error is broken up into parts " Each error is broken up into parts
let l:text = '' let l:text = ''
let l:line = 0 let l:line = 0
let l:col = 0 let l:col = 0
for l:message in l:error.message
for l:message in l:error.message " Comments have no line of column information
" Comments have no line of column information if has_key(l:message, 'loc') && l:line ==# 0
if has_key(l:message, 'loc') && l:line ==# 0 let l:line = l:message.loc.start.line + 0
let l:line = l:message.loc.start.line + 0 let l:col = l:message.loc.start.column + 0
let l:col = l:message.loc.start.column + 0
endif
if l:text ==# ''
let l:text = l:message.descr . ':'
else
let l:text = l:text . ' ' . l:message.descr
endif
endfor
if has_key(l:error, 'operation')
let l:text = l:text . ' See also: ' . l:error.operation.descr
endif endif
if l:text ==# ''
let l:text = l:message.descr . ':'
else
let l:text = l:text . ' ' . l:message.descr
endif
endfor
call add(l:output, { if has_key(l:error, 'operation')
\ 'bufnr': a:buffer, let l:text = l:text . ' See also: ' . l:error.operation.descr
\ 'lnum': l:line, endif
\ 'col': l:col,
\ 'text': l:text, call add(l:output, {
\ 'type': l:error.level ==# 'error' ? 'E' : 'W', \ 'bufnr': a:buffer,
\}) \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:error.level ==# 'error' ? 'E' : 'W',
\})
endfor endfor
return l:output return l:output
else
return []
endif
endfunction endfunction
call ale#linter#Define('javascript', { call ale#linter#Define('javascript', {

View File

@@ -1,68 +0,0 @@
" 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]
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',
\})

View File

@@ -1,41 +0,0 @@
" 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',
\})

View File

@@ -14,12 +14,15 @@ function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is needed to indicate that the column is a character
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[3], \ 'text': l:match[3],
\ 'type': 'E', \ 'type': 'E',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -19,12 +19,15 @@ function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[4], \ 'text': l:match[4],
\ 'type': l:match[3], \ 'type': l:match[3],
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -16,9 +16,11 @@ function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'text': l:match[2], \ 'text': l:match[2],
\ 'type': 'W', \ 'type': 'W',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -1,9 +1,9 @@
" Author: poohzrn https://github.com/poohzrn " Author: poohzrn https://github.com/poohzrn
" Description: proselint for Markdown files " Description: proselint for markdown files
call ale#linter#Define('markdown', { call ale#linter#Define('markdown', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': 'proselint',
\ 'command': 'proselint %t', \ 'command': g:ale#util#stdin_wrapper . ' .md proselint',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning', \ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\}) \})

View File

@@ -4,16 +4,6 @@
let g:ale_matlab_mlint_executable = let g:ale_matlab_mlint_executable =
\ get(g:, 'ale_matlab_mlint_executable', 'mlint') \ 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 function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Matches patterns like the following: " Matches patterns like the following:
" "
@@ -40,12 +30,15 @@ function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:lnum, \ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': l:col, \ 'col': l:col,
\ 'text': l:text, \ 'text': l:text,
\ 'type': 'W', \ 'type': 'W',
\ 'nr': -1,
\}) \})
endfor endfor
@@ -54,8 +47,9 @@ endfunction
call ale#linter#Define('matlab', { call ale#linter#Define('matlab', {
\ 'name': 'mlint', \ 'name': 'mlint',
\ 'executable_callback': 'ale_linters#matlab#mlint#GetExecutable', \ 'executable': 'mlint',
\ 'command_callback': 'ale_linters#matlab#mlint#GetCommand', \ 'command': g:ale#util#stdin_wrapper .
\ ' .m ' . g:ale_matlab_mlint_executable . ' -id',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#matlab#mlint#Handle', \ 'callback': 'ale_linters#matlab#mlint#Handle',
\}) \})

View File

@@ -1,65 +0,0 @@
" 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'
\})

View File

@@ -1,34 +0,0 @@
" 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',
\})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -1,22 +1,6 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol> " Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl syntax " 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 function! ale_linters#perl#perl#Handle(buffer, lines) abort
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)' let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = [] let l:output = []
@@ -29,14 +13,19 @@ function! ale_linters#perl#perl#Handle(buffer, lines) abort
endif endif
let l:line = l:match[3] let l:line = l:match[3]
let l:column = 1
let l:text = l:match[1] let l:text = l:match[1]
let l:type = 'E' let l:type = 'E'
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor
@@ -45,8 +34,8 @@ endfunction
call ale#linter#Define('perl', { call ale#linter#Define('perl', {
\ 'name': 'perl', \ 'name': 'perl',
\ 'executable_callback': 'ale_linters#perl#perl#GetExecutable', \ 'executable': 'perl',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'command_callback': 'ale_linters#perl#perl#GetCommand', \ 'command': 'perl -X -c -Mwarnings -Ilib',
\ 'callback': 'ale_linters#perl#perl#Handle', \ 'callback': 'ale_linters#perl#perl#Handle',
\}) \})

View File

@@ -13,14 +13,19 @@ function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort
endif endif
let l:line = l:match[3] let l:line = l:match[3]
let l:column = 1
let l:text = l:match[1] let l:text = l:match[1]
let l:type = 'E' let l:type = 'E'
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -19,6 +19,7 @@ function! ale_linters#php#hack#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'text': l:match[5], \ 'text': l:match[5],
\ 'type': 'E', \ 'type': 'E',

View File

@@ -1,12 +1,11 @@
" Author: Spencer Wood <https://github.com/scwood>, Adriaan Zonnenberg <amz@adriaan.xyz> " Author: Spencer Wood <https://github.com/scwood>
" Description: This file adds support for checking PHP with php-cli " Description: This file adds support for checking PHP with php-cli
function! ale_linters#php#php#Handle(buffer, lines) abort function! ale_linters#php#php#Handle(buffer, lines) abort
" Matches patterns like the following: " Matches patterns like the following:
" "
" PHP Parse error: syntax error, unexpected ';', expecting ']' in - on line 15 " Parse error: parse error in - on line 7
let l:pattern = '\vPHP %(Fatal|Parse) error:\s+(.+unexpected ''(.+)%(expecting.+)@<!''.*|.+) in - on line (\d+)' let l:pattern = 'Parse error:\s\+\(.\+\) on line \(\d\+\)'
let l:output = [] let l:output = []
for l:line in a:lines for l:line in a:lines
@@ -16,12 +15,15 @@ function! ale_linters#php#php#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0, \ 'lnum': l:match[2] + 0,
\ 'col': empty(l:match[2]) ? 0 : stridx(getline(l:match[3]), l:match[2]) + 1, \ 'vcol': 0,
\ 'col': 1,
\ 'text': l:match[1], \ 'text': l:match[1],
\ 'type': 'E', \ 'type': 'E',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -29,12 +29,15 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
let l:text = l:match[4] let l:text = l:match[4]
let l:type = l:match[3] let l:type = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type ==# 'error' ? 'E' : 'W', \ 'type': l:type ==# 'error' ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -1,38 +0,0 @@
" 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
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',
\})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -5,6 +5,6 @@ call ale#linter#Define('pug', {
\ 'name': 'puglint', \ 'name': 'puglint',
\ 'executable': 'pug-lint', \ 'executable': 'pug-lint',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command': 'pug-lint -r inline %t', \ 'command': g:ale#util#stdin_wrapper . ' .pug pug-lint -r inline',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError', \ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\}) \})

View File

@@ -14,12 +14,15 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is needed to indicate that the column is a character
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'text': l:match[1], \ 'text': l:match[1],
\ 'type': 'E', \ 'type': 'E',
\ 'nr': -1,
\}) \})
endfor endfor
@@ -30,6 +33,6 @@ call ale#linter#Define('puppet', {
\ 'name': 'puppet', \ 'name': 'puppet',
\ 'executable': 'puppet', \ 'executable': 'puppet',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command': 'puppet parser validate --color=false %t', \ 'command': g:ale#util#stdin_wrapper . ' .pp puppet parser validate --color=false',
\ 'callback': 'ale_linters#puppet#puppet#Handle', \ 'callback': 'ale_linters#puppet#puppet#Handle',
\}) \})

View File

@@ -3,8 +3,6 @@
call ale#linter#Define('puppet', { call ale#linter#Define('puppet', {
\ 'name': 'puppetlint', \ 'name': 'puppetlint',
\ 'executable': 'puppet-lint', \ 'executable': 'puppet-lint',
\ 'command': 'puppet-lint --no-autoloader_layout-check' \ 'command': g:ale#util#stdin_wrapper . ' .pp puppet-lint --no-autoloader_layout-check --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"',
\ . ' --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"'
\ . ' %t',
\ 'callback': 'ale#handlers#HandleGCCFormat', \ 'callback': 'ale#handlers#HandleGCCFormat',
\}) \})

View File

@@ -5,6 +5,8 @@ call ale#linter#Define('pyrex', {
\ 'name': 'cython', \ 'name': 'cython',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'cython', \ 'executable': 'cython',
\ 'command': 'cython --warning-extra -o ' . g:ale#util#nul_file . ' %t', \ 'command': g:ale#util#stdin_wrapper
\ . ' .pyx cython --warning-extra -o '
\ . g:ale#util#nul_file,
\ 'callback': 'ale#handlers#HandleUnixFormatAsError', \ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\}) \})

View File

@@ -10,9 +10,10 @@ function! g:ale_linters#python#mypy#GetCommand(buffer) abort
\ ? 'MYPYPATH=' . l:automatic_stubs_dir . ' ' \ ? 'MYPYPATH=' . l:automatic_stubs_dir . ' '
\ : '' \ : ''
return 'mypy --show-column-numbers ' return l:automatic_stubs_command
\ . g:ale#util#stdin_wrapper
\ . ' .py mypy --show-column-numbers '
\ . g:ale_python_mypy_options \ . g:ale_python_mypy_options
\ . ' %t'
endfunction endfunction
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+' let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
@@ -44,9 +45,11 @@ function! g:ale_linters#python#mypy#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[4], \ 'text': l:match[4],
\ 'type': l:match[3] =~# 'error' ? 'E' : 'W', \ 'type': l:match[3] =~# 'error' ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -12,10 +12,10 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#python#pylint#GetCommand(buffer) abort function! ale_linters#python#pylint#GetCommand(buffer) abort
return ale_linters#python#pylint#GetExecutable(a:buffer) return g:ale#util#stdin_wrapper . ' .py '
\ . ale_linters#python#pylint#GetExecutable(a:buffer)
\ . ' ' . g:ale_python_pylint_options \ . ' ' . g:ale_python_pylint_options
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} {msg}" --reports n'
\ . ' %t'
endfunction endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -19,12 +19,15 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
let l:text = l:match[4] let l:text = l:match[4]
let l:type = l:match[3] let l:type = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W', \ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -3,6 +3,6 @@
call ale#linter#Define('sass', { call ale#linter#Define('sass', {
\ 'name': 'sasslint', \ 'name': 'sasslint',
\ 'executable': 'sass-lint', \ 'executable': 'sass-lint',
\ 'command': 'sass-lint -v -q -f compact %t', \ 'command': g:ale#util#stdin_wrapper . ' .sass sass-lint -v -q -f compact',
\ 'callback': 'ale#handlers#HandleCSSLintFormat', \ 'callback': 'ale#handlers#HandleCSSLintFormat',
\}) \})

View File

@@ -1,3 +1,4 @@
" vim: set et:
" Author: Zoltan Kalmar - https://github.com/kalmiz " Author: Zoltan Kalmar - https://github.com/kalmiz
" Description: Basic scala support using scalac " Description: Basic scala support using scalac
@@ -20,17 +21,22 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) abort
let l:text = l:match[3] let l:text = l:match[3]
let l:type = l:match[2] ==# 'error' ? 'E' : 'W' let l:type = l:match[2] ==# 'error' ? 'E' : 'W'
let l:col = 0 let l:col = 0
if l:ln + 1 < len(a:lines) if l:ln + 1 < len(a:lines)
let l:col = stridx(a:lines[l:ln + 1], '^') let l:col = stridx(a:lines[l:ln + 1], '^')
if l:col == -1
let l:col = 0
endif
endif endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:col + 1, \ 'col': l:col + 1,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor
@@ -41,6 +47,6 @@ call ale#linter#Define('scala', {
\ 'name': 'scalac', \ 'name': 'scalac',
\ 'executable': 'scalac', \ 'executable': 'scalac',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command': 'scalac -Ystop-after:parser %t', \ 'command': g:ale#util#stdin_wrapper . ' .scala scalac -Ystop-after:parser',
\ 'callback': 'ale_linters#scala#scalac#Handle', \ 'callback': 'ale_linters#scala#scalac#Handle',
\}) \})

View File

@@ -3,6 +3,6 @@
call ale#linter#Define('scss', { call ale#linter#Define('scss', {
\ 'name': 'sasslint', \ 'name': 'sasslint',
\ 'executable': 'sass-lint', \ 'executable': 'sass-lint',
\ 'command': 'sass-lint -v -q -f compact %t', \ 'command': g:ale#util#stdin_wrapper . ' .scss sass-lint -v -q -f compact',
\ 'callback': 'ale#handlers#HandleCSSLintFormat', \ 'callback': 'ale#handlers#HandleCSSLintFormat',
\}) \})

View File

@@ -20,12 +20,15 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
continue continue
endif endif
" vcol is needed to indicate that the column is a character
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[4], \ 'text': l:match[4],
\ 'type': l:match[3] ==# 'E' ? 'E' : 'W', \ 'type': l:match[3] ==# 'E' ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -30,7 +30,7 @@ function! ale_linters#sh#shell#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#sh#shell#GetCommand(buffer) abort function! ale_linters#sh#shell#GetCommand(buffer) abort
return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n %t' return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n'
endfunction endfunction
function! ale_linters#sh#shell#Handle(buffer, lines) abort function! ale_linters#sh#shell#Handle(buffer, lines) abort
@@ -38,7 +38,7 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
" "
" bash: line 13: syntax error near unexpected token `d' " bash: line 13: syntax error near unexpected token `d'
" sh: 11: Syntax error: "(" unexpected " sh: 11: Syntax error: "(" unexpected
let l:pattern = '\v(line |: ?)(\d+): (.+)$' let l:pattern = '^[^:]\+: \%(\w\+ \|\)\(\d\+\): \(.\+\)'
let l:output = [] let l:output = []
for l:line in a:lines for l:line in a:lines
@@ -48,15 +48,20 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
continue continue
endif endif
let l:line = l:match[2] + 0 let l:line = l:match[1] + 0
let l:text = l:match[3] let l:column = 1
let l:text = l:match[2]
let l:type = 'E' let l:type = 'E'
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -1,33 +0,0 @@
" 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'
\})

View File

@@ -1,39 +0,0 @@
" 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,
\ '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',
\})

View File

@@ -44,9 +44,11 @@ function! ale_linters#tex#chktex#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[4] . ' (' . (l:match[3]+0) . ')', \ 'text': l:match[4] . ' (' . (l:match[3]+0) . ')',
\ 'type': 'W', \ 'type': 'W',
\ 'nr': -1
\}) \})
endfor endfor

View File

@@ -4,14 +4,6 @@
let g:ale_tex_lacheck_executable = let g:ale_tex_lacheck_executable =
\ get(g:, 'ale_tex_lacheck_executable', 'lacheck') \ 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 function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
" Mattes lines like: " Mattes lines like:
" "
@@ -38,9 +30,11 @@ function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': 0, \ 'col': 0,
\ 'text': l:match[2], \ 'text': l:match[2],
\ 'type': 'W', \ 'type': 'W',
\ 'nr': -1
\}) \})
endfor endfor
@@ -49,7 +43,8 @@ endfunction
call ale#linter#Define('tex', { call ale#linter#Define('tex', {
\ 'name': 'lacheck', \ 'name': 'lacheck',
\ 'executable_callback': 'ale_linters#tex#lacheck#GetExecutable', \ 'executable': 'lacheck',
\ 'command_callback': 'ale_linters#tex#lacheck#GetCommand', \ 'command': g:ale#util#stdin_wrapper . ' .tex '
\ . g:ale_tex_lacheck_executable,
\ 'callback': 'ale_linters#tex#lacheck#Handle' \ 'callback': 'ale_linters#tex#lacheck#Handle'
\}) \})

View File

@@ -1,9 +1,9 @@
" Author: poohzrn https://github.com/poohzrn " Author: poohzrn https://github.com/poohzrn
" Description: proselint for TeX files " Description: proselint for tex files
call ale#linter#Define('tex', { call ale#linter#Define('tex', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': 'proselint',
\ 'command': 'proselint %t', \ 'command': g:ale#util#stdin_wrapper . ' .tex proselint',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning', \ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\}) \})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -4,6 +4,6 @@
call ale#linter#Define('text', { call ale#linter#Define('text', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning', \ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\ 'command': g:ale#util#stdin_wrapper . ' .txt proselint',
\}) \})

View File

@@ -1,20 +1,6 @@
" Author: Prashanth Chandra https://github.com/prashcr " Author: Prashanth Chandra https://github.com/prashcr
" Description: tslint for TypeScript files " 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 function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
" Matches patterns like the following: " Matches patterns like the following:
" "
@@ -37,37 +23,33 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
let l:type = 'E' let l:type = 'E'
let l:text = l:match[3] let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column, \ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor
return l:output return l:output
endfunction endfunction
function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort function! ale_linters#typescript#tslint#BuildLintCommand(buffer_n) abort
let g:ale_typescript_tslint_config_path = let l:tsconfig_path = ale#util#FindNearestFile(a:buffer_n, 'tslint.json')
\ empty(g:ale_typescript_tslint_config_path) ? let l:tslint_options = empty(l:tsconfig_path) ? '' : '-c ' . l:tsconfig_path
\ ale#util#FindNearestFile(a:buffer, 'tslint.json')
\ : g:ale_typescript_tslint_config_path
let l:tslint_options = let l:ext = '.' . fnamemodify(bufname(a:buffer_n), ':e')
\ empty(g:ale_typescript_tslint_config_path) ?
\ ''
\ : '-c ' . fnameescape(g:ale_typescript_tslint_config_path)
return ale_linters#typescript#tslint#GetExecutable(a:buffer) return g:ale#util#stdin_wrapper . ' ' . l:ext . ' tslint ' . l:tslint_options
\ . ' ' . l:tslint_options
\ . ' %t'
endfunction endfunction
call ale#linter#Define('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'tslint', \ 'name': 'tslint',
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable', \ 'executable': 'tslint',
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand', \ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
\ 'callback': 'ale_linters#typescript#tslint#Handle', \ 'callback': 'ale_linters#typescript#tslint#Handle',
\}) \})

View File

@@ -22,12 +22,15 @@ function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
let l:type = 'E' let l:type = 'E'
let l:text = l:match[3] let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column, \ 'col': l:column,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor

View File

@@ -25,8 +25,11 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 1,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type, \ 'type': l:type,
\ 'nr': -1,
\}) \})
endfor endfor
@@ -37,6 +40,6 @@ call ale#linter#Define('verilog', {
\ 'name': 'iverilog', \ 'name': 'iverilog',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'iverilog', \ 'executable': 'iverilog',
\ 'command': 'iverilog -t null -Wall %t', \ 'command': g:ale#util#stdin_wrapper . ' .v iverilog -t null -Wall',
\ 'callback': 'ale_linters#verilog#iverilog#Handle', \ 'callback': 'ale_linters#verilog#iverilog#Handle',
\}) \})

View File

@@ -1,16 +1,6 @@
" Author: Masahiro H https://github.com/mshr-h " Author: Masahiro H https://github.com/mshr-h
" Description: verilator for verilog files " 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 function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
" Look for lines like the following. " Look for lines like the following.
" "
@@ -35,13 +25,16 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
let l:text = l:match[4] let l:text = l:match[4]
let l:file = l:match[2] let l:file = l:match[2]
if l:file =~# '_verilator_linted.v' if(l:file =~# '_verilator_linted.v')
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'text': l:text, \ 'vcol': 0,
\ 'type': l:type, \ 'col': 1,
\}) \ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endif endif
endfor endfor
@@ -52,7 +45,6 @@ call ale#linter#Define('verilog', {
\ 'name': 'verilator', \ 'name': 'verilator',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'verilator', \ 'executable': 'verilator',
\ 'command_callback': 'ale_linters#verilog#verilator#GetCommand', \ 'command': g:ale#util#stdin_wrapper . ' _verilator_linted.v verilator --lint-only -Wall -Wno-DECLFILENAME',
\ 'callback': 'ale_linters#verilog#verilator#Handle', \ 'callback': 'ale_linters#verilog#verilator#Handle',
\ 'read_buffer': 0,
\}) \})

View File

@@ -6,19 +6,17 @@ let g:ale_vim_vint_show_style_issues =
\ get(g:, 'ale_vim_vint_show_style_issues', 1) \ get(g:, 'ale_vim_vint_show_style_issues', 1)
let s:warning_flag = g:ale_vim_vint_show_style_issues ? '-s' : '-w' 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, [0, 3, 7])
let s:enable_neovim = has('nvim') ? ' --enable-neovim ' : '' let s:enable_neovim = has('nvim') ? ' --enable-neovim ' : ''
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"' let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
call ale#linter#Define('vim', { call ale#linter#Define('vim', {
\ 'name': 'vint', \ 'name': 'vint',
\ 'executable': 'vint', \ 'executable': 'vint',
\ 'command': 'vint ' \ 'command': g:ale#util#stdin_wrapper
\ . s:warning_flag . ' ' \ . ' .vim vint '
\ . (s:has_no_color_support ? '--no-color ' : '') \ . s:warning_flag
\ . ' --no-color '
\ . s:enable_neovim \ . s:enable_neovim
\ . s:format \ . s:format,
\ . ' %t',
\ 'callback': 'ale#handlers#HandleGCCFormat', \ 'callback': 'ale#handlers#HandleGCCFormat',
\}) \})

View File

@@ -1,9 +0,0 @@
" 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',
\})

View File

@@ -1,21 +1,5 @@
" Author: KabbAmine <amine.kabb@gmail.com> " 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 function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" something.yaml:1:1: [warning] missing document start "---" (document-start) " something.yaml:1:1: [warning] missing document start "---" (document-start)
@@ -35,12 +19,15 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
let l:type = l:match[3] let l:type = l:match[3]
let l:text = l:match[4] let l:text = l:match[4]
" vcol is Needed to indicate that the column is a character.
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col, \ 'col': l:col,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type ==# 'error' ? 'E' : 'W', \ 'type': l:type ==# 'error' ? 'E' : 'W',
\ 'nr': -1,
\}) \})
endfor endfor
@@ -49,7 +36,7 @@ endfunction
call ale#linter#Define('yaml', { call ale#linter#Define('yaml', {
\ 'name': 'yamllint', \ 'name': 'yamllint',
\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable', \ 'executable': 'yamllint',
\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand', \ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable',
\ 'callback': 'ale_linters#yaml#yamllint#Handle', \ 'callback': 'ale_linters#yaml#yamllint#Handle',
\}) \})

View File

@@ -3,41 +3,13 @@
" Manages execution of linters when requested by autocommands " Manages execution of linters when requested by autocommands
let s:lint_timer = -1 let s:lint_timer = -1
let s:should_lint_file_for_buffer = {}
" A function for checking various conditions whereby ALE just shouldn't function! ale#Queue(delay) abort
" attempt to do anything, say if particular buffer types are open in Vim. " Do nothing for blacklisted files.
function! ale#ShouldDoNothing() abort if index(g:ale_filetype_blacklist, &filetype) >= 0
" Do nothing for blacklisted files
" OR if ALE is running in the sandbox
return index(g:ale_filetype_blacklist, &filetype) >= 0
\ || (exists('*getcmdwintype') && !empty(getcmdwintype()))
\ || ale#util#InSandbox()
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 return
endif 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 if s:lint_timer != -1
call timer_stop(s:lint_timer) call timer_stop(s:lint_timer)
let s:lint_timer = -1 let s:lint_timer = -1
@@ -57,19 +29,13 @@ function! ale#Queue(delay, ...) abort
endfunction endfunction
function! ale#Lint(...) abort function! ale#Lint(...) abort
if ale#ShouldDoNothing() " Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
return return
endif endif
let l:buffer = bufnr('%') let l:buffer = bufnr('%')
let l:linters = ale#linter#Get(&filetype) 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. " Initialise the buffer information if needed.
call ale#engine#InitBufferInfo(l:buffer) call ale#engine#InitBufferInfo(l:buffer)
@@ -77,22 +43,19 @@ function! ale#Lint(...) abort
" Clear the new loclist again, so we will work with all new items. " Clear the new loclist again, so we will work with all new items.
let g:ale_buffer_info[l:buffer].new_loclist = [] 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 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) call ale#engine#Invoke(l:buffer, l:linter)
endfor endfor
endfunction endfunction
" Reset flags indicating that files should be checked for all buffers.
function! ale#ResetLintFileMarkers() abort
let s:should_lint_file_for_buffer = {}
endfunction

View File

@@ -3,19 +3,11 @@
function! ale#cleanup#Buffer(buffer) abort function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_info, a:buffer) if has_key(g:ale_buffer_info, a:buffer)
call ale#engine#RemoveManagedFiles(a:buffer)
" When buffers are removed, clear all of the jobs. " When buffers are removed, clear all of the jobs.
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', []) for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
call ale#engine#ClearJob(l:job) call ale#engine#ClearJob(l:job)
endfor endfor
" Clear delayed highlights for a buffer being removed.
if g:ale_set_highlights
call ale#highlight#UnqueueHighlights(a:buffer)
call ale#highlight#RemoveHighlights([])
endif
call remove(g:ale_buffer_info, a:buffer) call remove(g:ale_buffer_info, a:buffer)
endif endif
endfunction endfunction

View File

@@ -18,29 +18,6 @@ function! s:GetMessage(linter, type, text) abort
return printf(l:msg, l:text) return printf(l:msg, l:text)
endfunction 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 function! ale#cursor#TruncatedEcho(message) abort
let l:message = a:message let l:message = a:message
" Change tabs to spaces. " Change tabs to spaces.
@@ -48,23 +25,17 @@ function! ale#cursor#TruncatedEcho(message) abort
" Remove any newlines in the message. " Remove any newlines in the message.
let l:message = substitute(l:message, "\n", '', 'g') let l:message = substitute(l:message, "\n", '', 'g')
call s:EchoWithShortMess('on', l:message) " We need to turn T for truncated messages on for shortmess,
endfunction " and then then we need to reset the option back to what it was.
let l:shortmess_options = getbufvar('%', '&shortmess')
function! s:FindItemAtCursor() abort try
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []}) " Echo the message truncated to fit without creating a prompt.
let l:pos = getcurpos() setlocal shortmess+=T
let l:index = ale#util#BinarySearch(l:info.loclist, l:pos[1], l:pos[2]) exec "norm! :echomsg message\n"
let l:loc = l:index >= 0 ? l:info.loclist[l:index] : {} finally
call setbufvar('%', '&shortmess', l:shortmess_options)
return [l:info, l:loc] endtry
endfunction
function! s:StopCursorTimer() abort
if s:cursor_timer != -1
call timer_stop(s:cursor_timer)
let s:cursor_timer = -1
endif
endfunction endfunction
function! ale#cursor#EchoCursorWarning(...) abort function! ale#cursor#EchoCursorWarning(...) abort
@@ -73,17 +44,28 @@ function! ale#cursor#EchoCursorWarning(...) abort
return return
endif endif
let [l:info, l:loc] = s:FindItemAtCursor() let l:buffer = bufnr('%')
if !empty(l:loc) 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]
let l:msg = s:GetMessage(l:loc.linter_name, l:loc.type, l:loc.text) let l:msg = s:GetMessage(l:loc.linter_name, l:loc.type, l:loc.text)
call ale#cursor#TruncatedEcho(l:msg) call ale#cursor#TruncatedEcho(l:msg)
let l:info.echoed = 1 let g:ale_buffer_info[l:buffer].echoed = 1
elseif get(l:info, 'echoed') else
" We'll only clear the echoed message when moving off errors once, " We'll only clear the echoed message when moving off errors once,
" so we don't continually clear the echo line. " so we don't continually clear the echo line.
echo if get(g:ale_buffer_info[l:buffer], 'echoed')
let l:info.echoed = 0 echo
let g:ale_buffer_info[l:buffer].echoed = 0
endif
endif endif
endfunction endfunction
@@ -91,11 +73,15 @@ let s:cursor_timer = -1
let s:last_pos = [0, 0, 0] let s:last_pos = [0, 0, 0]
function! ale#cursor#EchoCursorWarningWithDelay() abort function! ale#cursor#EchoCursorWarningWithDelay() abort
if ale#ShouldDoNothing() " Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
return return
endif endif
call s:StopCursorTimer() if s:cursor_timer != -1
call timer_stop(s:cursor_timer)
let s:cursor_timer = -1
endif
let l:pos = getcurpos()[0:2] let l:pos = getcurpos()[0:2]
@@ -108,23 +94,3 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning')) let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
endif endif
endfunction 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

View File

@@ -1,142 +0,0 @@
" 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

View File

@@ -9,53 +9,33 @@
" output: The array of lines for the output of the job. " output: The array of lines for the output of the job.
let s:job_info_map = {} 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 function! s:GetJobID(job) abort
if has('nvim') if has('nvim')
"In NeoVim, job values are just IDs. "In NeoVim, job values are just IDs.
return a:job return a:job
endif endif
" For Vim 8, the job is a different variable type, and we can parse the " In Vim 8, the job is a special variable, and we open a channel for each
" process ID from the string. " job. We'll use the ID of the channel instead as the job ID.
return ale#engine#ParseVim8ProcessID(string(a:job)) return ch_info(job_getchannel(a:job)).id
endfunction endfunction
function! ale#engine#InitBufferInfo(buffer) abort function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer) if !has_key(g:ale_buffer_info, a:buffer)
" job_list will hold the list of jobs " job_list will hold the list of jobs
" loclist holds the loclist items after all jobs have completed. " 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. " 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] = { let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [], \ 'job_list': [],
\ 'loclist': [], \ 'loclist': [],
\ 'lint_file_loclist': [],
\ 'new_loclist': [], \ 'new_loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
\ 'history': [],
\} \}
endif endif
endfunction 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 function! ale#engine#ClearJob(job) abort
let l:job_id = s:GetJobID(a:job) let l:job_id = s:GetJobID(a:job)
let l:linter = s:job_info_map[l:job_id].linter
if has('nvim') if has('nvim')
call jobstop(a:job) call jobstop(a:job)
@@ -66,19 +46,10 @@ function! ale#engine#ClearJob(job) abort
call ch_close_in(job_getchannel(a:job)) call ch_close_in(job_getchannel(a:job))
endif endif
" Ask nicely for the job to stop.
call job_stop(a:job) 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 endif
if has_key(s:job_info_map, l:job_id) call remove(s:job_info_map, l:job_id)
call remove(s:job_info_map, l:job_id)
endif
endfunction endfunction
function! s:StopPreviousJobs(buffer, linter) abort function! s:StopPreviousJobs(buffer, linter) abort
@@ -141,46 +112,6 @@ function! ale#engine#JoinNeovimOutput(output, data) abort
endif endif
endfunction 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 function! s:HandleExit(job) abort
if a:job ==# 'no process' if a:job ==# 'no process'
" Stop right away when the job is not valid in Vim 8. " Stop right away when the job is not valid in Vim 8.
@@ -203,110 +134,59 @@ function! s:HandleExit(job) abort
" which just closed. " which just closed.
call s:StopPreviousJobs(l:buffer, l:linter) 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', [])) if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output) call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
return return
endif 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) let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
" Make some adjustments to the loclists to fix common problems, and also " Make some adjustments to the loclists to fix common problems.
" to set default values for loclist items. call s:FixLocList(l:buffer, l:linter_loclist)
let l:linter_loclist = ale#engine#FixLocList(l:buffer, l:linter, l:linter_loclist)
for l:item in l:linter_loclist
let l:item.linter_name = l:linter.name
endfor
" Add the loclist items from the linter. " Add the loclist items from the linter.
" loclist items for files which are checked go into a different list, call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
" 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) if !empty(g:ale_buffer_info[l:buffer].job_list)
" Wait for all jobs to complete before doing anything else. " Wait for all jobs to complete before doing anything else.
return return
endif 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. " Sort the loclist again.
" We need a sorted list so we can run a binary search against it " We need a sorted list so we can run a binary search against it
" for efficient lookup of the messages in the cursor handler. " for efficient lookup of the messages in the cursor handler.
call sort(l:combined_list, 'ale#util#LocItemCompare') call sort(g:ale_buffer_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
" Now swap the old and new loclists, after we have collected everything " Now swap the old and new loclists, after we have collected everything
" and sorted the list again. " and sorted the list again.
let g:ale_buffer_info[l:buffer].loclist = l:combined_list let g:ale_buffer_info[l:buffer].loclist = g:ale_buffer_info[l:buffer].new_loclist
let g:ale_buffer_info[l:buffer].new_loclist = [] let g:ale_buffer_info[l:buffer].new_loclist = []
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist) if g:ale_set_quickfix || g:ale_set_loclist
call ale#list#SetLists(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 endif
if g:ale_set_quickfix || g:ale_set_loclist if g:ale_set_signs
call ale#list#SetLists(a:buffer, a:loclist) call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif endif
if exists('*ale#statusline#Update') if exists('*ale#statusline#Update')
" Don't load/run if not already loaded. " Don't load/run if not already loaded.
call ale#statusline#Update(a:buffer, a:loclist) call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif endif
if g:ale_set_highlights " Call user autocommands. This allows users to hook into ALE's lint cycle.
call ale#highlight#SetHighlights(a:buffer, a:loclist) silent doautocmd User ALELint
endif
if g:ale_echo_cursor " Mark line 200, column 17 with a squiggly line or something
" Try and echo the warning now. " matchadd('ALEError', '\%200l\%17v')
" This will only do something meaningful if we're in normal mode.
call ale#cursor#EchoCursorWarning()
endif
endfunction endfunction
function! s:SetExitCode(job, exit_code) abort function! s:HandleExitNeoVim(job, data, event) 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) call s:HandleExit(a:job)
endfunction endfunction
@@ -314,154 +194,34 @@ function! s:HandleExitVim(channel) abort
call s:HandleExit(ch_getjob(a:channel)) call s:HandleExit(ch_getjob(a:channel))
endfunction endfunction
" Vim returns the exit status with one callback, function! s:FixLocList(buffer, loclist) abort
" 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, " 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 " so we need to adjust them so they set the error at the last line
" of the file instead. " of the file instead.
let l:last_line_number = ale#util#GetLineCount(a:buffer) let l:last_line_number = ale#util#GetLineCount(a:buffer)
for l:old_item in a:loclist for l: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 if l:item.lnum == 0
" When errors appear at line 0, put them at line 1 instead. " When errors appear at line 0, put them at line 1 instead.
let l:item.lnum = 1 let l:item.lnum = 1
elseif l:item.lnum > l:last_line_number 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 let l:item.lnum = l:last_line_number
endif endif
call add(l:new_loclist, l:item)
endfor endfor
return l:new_loclist
endfunction endfunction
" Given part of a command, replace any % with %%, so that no characters in function! s:RunJob(command, generic_job_options) abort
" the string will be replaced with filenames, etc. let l:buffer = a:generic_job_options.buffer
function! ale#engine#EscapeCommandPart(command_part) abort let l:linter = a:generic_job_options.linter
return substitute(a:command_part, '%', '%%', 'g') let l:output_stream = a:generic_job_options.output_stream
endfunction let l:next_chain_index = a:generic_job_options.next_chain_index
let l:read_buffer = a:generic_job_options.read_buffer
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 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 l:command =~# '%s'
let l:filename = fnamemodify(bufname(a:buffer), ':p') " If there is a '%s' in the command string, replace it with the name
let l:command = substitute(l:command, '%s', '\=fnameescape(l:filename)', 'g') " of the file.
endif let l:command = printf(l:command, shellescape(fnamemodify(bufname(l:buffer), ':p')))
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 endif
if has('nvim') if has('nvim')
@@ -491,12 +251,6 @@ function! s:RunJob(options) abort
\ 'close_cb': function('s:HandleExitVim'), \ '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' if l:output_stream ==# 'stderr'
" Read from stderr instead of stdout. " Read from stderr instead of stdout.
let l:job_options.err_cb = function('s:GatherOutputVim') let l:job_options.err_cb = function('s:GatherOutputVim')
@@ -508,50 +262,63 @@ function! s:RunJob(options) abort
let l:job_options.out_cb = function('s:GatherOutputVim') let l:job_options.out_cb = function('s:GatherOutputVim')
endif endif
" The command will be executed in a subshell. This fixes a number of if has('win32')
" issues, including reading the PATH variables correctly, %PATHEXT% " job_start commands on Windows have to be run with cmd /c,
" expansion on Windows, etc. " othwerwise %PATHTEXT% will not be used to programs ending int
" " .cmd, .bat, .exe, etc.
" NeoVim handles this issue automatically if the command is a String. let l:command = 'cmd /c ' . l:command
let l:command = has('win32') else
\ ? 'cmd /c ' . l:command " Execute the command with the shell, to fix escaping issues.
\ : split(&shell) + split(&shellcmdflag) + [l:command] 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
" Vim 8 will read the stdin from the file's buffer. " Vim 8 will read the stdin from the file's buffer.
let l:job = job_start(l:command, l:job_options) let l:job = job_start(l:command, l:job_options)
endif endif
let l:status = 'failed'
let l:job_id = 0
" Only proceed if the job is being run. " Only proceed if the job is being run.
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# '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. " 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) 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. " Store the ID for the job in the map to read back again.
let s:job_info_map[l:job_id] = { let s:job_info_map[s:GetJobID(l:job)] = {
\ 'linter': l:linter, \ 'linter': l:linter,
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'output': [], \ 'output': [],
\ 'next_chain_index': l:next_chain_index, \ 'next_chain_index': l:next_chain_index,
\} \}
endif
if g:ale_history_enabled if l:read_buffer
call ale#history#Add(l:buffer, l:status, l:job_id, l:command) if has('nvim')
else " In NeoVim, we have to send the buffer lines ourselves.
let g:ale_buffer_info[l:buffer].history = [] 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
endif endif
endfunction endfunction
" Determine which commands to run for a link in a command chain, or function! s:InvokeChain(buffer, linter, chain_index, input) abort
" 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: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:chain_index = a:chain_index
let l:input = a:input let l:input = a:input
@@ -561,6 +328,11 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
" so that many programs can be run in a sequence. " so that many programs can be run in a sequence.
let l:chain_item = a:linter.command_chain[l:chain_index] 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 if l:chain_index == 0
" The first callback in the chain takes only a buffer number. " The first callback in the chain takes only a buffer number.
let l:command = ale#util#GetFunction(l:chain_item.callback)( let l:command = ale#util#GetFunction(l:chain_item.callback)(
@@ -576,21 +348,6 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
if !empty(l:command) if !empty(l:command)
" We hit a command to run, so we'll execute that " 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 break
endif endif
@@ -600,6 +357,11 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
let l:input = [] let l:input = []
let l:chain_index += 1 let l:chain_index += 1
endwhile 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') elseif has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead. " If there is a callback for generating a command, call that instead.
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer) let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
@@ -607,45 +369,21 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
let l:command = a:linter.command let l:command = a:linter.command
endif endif
if empty(l:command) let l:is_last_job = l:chain_index >= len(get(a:linter, 'command_chain', [])) - 1
" Don't run any jobs if the command is an empty string.
return {}
endif
return { call s:RunJob(l:command, {
\ 'command': l:command,
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'linter': a:linter, \ 'linter': a:linter,
\ 'output_stream': l:output_stream, \ 'output_stream': l:output_stream,
\ 'next_chain_index': l:chain_index + 1, \ 'next_chain_index': l:chain_index + 1,
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:is_last_job,
\} \})
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 endfunction
function! ale#engine#Invoke(buffer, linter) abort function! ale#engine#Invoke(buffer, linter) abort
" Stop previous jobs for the same linter. " Stop previous jobs for the same linter.
call s:StopPreviousJobs(a:buffer, a: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 endfunction
" Given a buffer number, return the warnings and errors for a given buffer. " Given a buffer number, return the warnings and errors for a given buffer.
@@ -664,7 +402,7 @@ endfunction
" The time taken will be a very rough approximation, and more time may be " The time taken will be a very rough approximation, and more time may be
" permitted than is specified. " permitted than is specified.
function! ale#engine#WaitForJobs(deadline) abort function! ale#engine#WaitForJobs(deadline) abort
let l:start_time = ale#util#ClockMilliseconds() let l:start_time = system('date +%s%3N') + 0
if l:start_time == 0 if l:start_time == 0
throw 'Failed to read milliseconds from the clock!' throw 'Failed to read milliseconds from the clock!'
@@ -684,7 +422,7 @@ function! ale#engine#WaitForJobs(deadline) abort
for l:job in l:job_list for l:job in l:job_list
if job_status(l:job) ==# 'run' if job_status(l:job) ==# 'run'
let l:now = ale#util#ClockMilliseconds() let l:now = system('date +%s%3N') + 0
if l:now - l:start_time > a:deadline if l:now - l:start_time > a:deadline
" Stop waiting after a timeout, so we don't wait forever. " Stop waiting after a timeout, so we don't wait forever.
@@ -709,19 +447,15 @@ function! ale#engine#WaitForJobs(deadline) abort
" for command_chain linters. " for command_chain linters.
let l:has_new_jobs = 0 let l:has_new_jobs = 0
" Check again to see if any jobs are running.
for l:info in values(g:ale_buffer_info) for l:info in values(g:ale_buffer_info)
for l:job in l:info.job_list if !empty(l:info.job_list)
if job_status(l:job) ==# 'run' let l:has_new_jobs = 1
let l:has_new_jobs = 1 endif
break
endif
endfor
endfor endfor
if l:has_new_jobs if l:has_new_jobs
" We have to wait more. Offset the timeout by the time taken so far. " We have to wait more. Offset the timeout by the time taken so far.
let l:now = ale#util#ClockMilliseconds() let l:now = system('date +%s%3N') + 0
let l:new_deadline = a:deadline - (l:now - l:start_time) let l:new_deadline = a:deadline - (l:now - l:start_time)
if l:new_deadline <= 0 if l:new_deadline <= 0

View File

@@ -1,60 +0,0 @@
" 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

View File

@@ -220,58 +220,3 @@ function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
return l:output return l:output
endfunction 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

View File

@@ -1,109 +0,0 @@
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
" Given a loclist for current items to highlight, remove all highlights
" except these which have matching loclist item entries.
function! ale#highlight#RemoveHighlights(loclist) abort
let l:current_id_map = s:GetCurrentMatchIDs(a:loclist)
for l:match in s:GetALEMatches()
if !has_key(l:current_id_map, l:match.id)
call matchdelete(l:match.id)
endif
endfor
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) : []
if l:has_new_items || !g:ale_enabled
call ale#highlight#RemoveHighlights(l:loclist)
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

View File

@@ -1,58 +0,0 @@
" 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

View File

@@ -18,14 +18,10 @@ let s:default_ale_linter_aliases = {
" The user defined linter selections will be merged with this Dictionary. " The user defined linter selections will be merged with this Dictionary.
" "
" No linters are used for plaintext files by default. " No linters are used for plaintext files by default.
"
" Only cargo is enabled for Rust by default.
let s:default_ale_linters = { let s:default_ale_linters = {
\ 'csh': ['shell'],
\ 'help': [],
\ 'rust': ['cargo'],
\ 'text': [],
\ 'zsh': ['shell'], \ 'zsh': ['shell'],
\ 'csh': ['shell'],
\ 'text': [],
\} \}
" Testing/debugging helper to unload all linters. " Testing/debugging helper to unload all linters.
@@ -37,10 +33,6 @@ function! s:IsCallback(value) abort
return type(a:value) == type('') || type(a:value) == type(function('type')) return type(a:value) == type('') || type(a:value) == type(function('type'))
endfunction 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 function! ale#linter#PreProcess(linter) abort
if type(a:linter) != type({}) if type(a:linter) != type({})
throw 'The linter object must be a Dictionary' throw 'The linter object must be a Dictionary'
@@ -103,10 +95,6 @@ function! ale#linter#PreProcess(linter) abort
endif endif
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 let l:link_index += 1
endfor endfor
elseif has_key(a:linter, 'command_callback') elseif has_key(a:linter, 'command_callback')
@@ -126,15 +114,6 @@ function! ale#linter#PreProcess(linter) abort
\ . 'must be defined' \ . 'must be defined'
endif 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') let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
if type(l:obj.output_stream) != type('') if type(l:obj.output_stream) != type('')
@@ -142,25 +121,6 @@ function! ale#linter#PreProcess(linter) abort
throw "`output_stream` must be 'stdout', 'stderr', or 'both'" throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
endif 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 return l:obj
endfunction endfunction
@@ -196,7 +156,7 @@ function! ale#linter#GetAll(filetype) abort
return s:linters[a:filetype] return s:linters[a:filetype]
endfunction endfunction
function! ale#linter#ResolveFiletype(original_filetype) abort function! s:ResolveFiletype(original_filetype) abort
" Try and get an aliased file type either from the user's Dictionary, or " Try and get an aliased file type either from the user's Dictionary, or
" our default Dictionary, otherwise use the filetype as-is. " our default Dictionary, otherwise use the filetype as-is.
let l:filetype = get( let l:filetype = get(
@@ -217,7 +177,7 @@ function! ale#linter#Get(original_filetypes) abort
" Handle dot-seperated filetypes. " Handle dot-seperated filetypes.
for l:original_filetype in split(a:original_filetypes, '\.') for l:original_filetype in split(a:original_filetypes, '\.')
let l:filetype = ale#linter#ResolveFiletype(l:original_filetype) let l:filetype = s:ResolveFiletype(l:original_filetype)
" Try and get a list of linters to run, using the original file type, " 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, " not the aliased filetype. We have some linters to limit by default,
@@ -251,3 +211,25 @@ function! ale#linter#Get(original_filetypes) abort
return l:combined_linters return l:combined_linters
endfunction 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

View File

@@ -11,20 +11,11 @@ function! ale#list#IsQuickfixOpen() abort
return 0 return 0
endfunction endfunction
function! ale#list#SetLists(buffer, loclist) abort function! ale#list#SetLists(loclist) abort
if g:ale_set_quickfix if g:ale_set_quickfix
call setqflist(a:loclist) call setqflist(a:loclist)
elseif g:ale_set_loclist elseif g:ale_set_loclist
" If windows support is off, bufwinid() may not exist. call setloclist(0, a:loclist)
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 endif
" If we don't auto-open lists, bail out here. " If we don't auto-open lists, bail out here.
@@ -36,12 +27,10 @@ function! ale#list#SetLists(buffer, loclist) abort
if len(a:loclist) > 0 || g:ale_keep_list_window_open if len(a:loclist) > 0 || g:ale_keep_list_window_open
let l:winnr = winnr() let l:winnr = winnr()
if !ale#list#IsQuickfixOpen() if g:ale_set_quickfix
if g:ale_set_quickfix copen
copen elseif g:ale_set_loclist
elseif g:ale_set_loclist lopen
lopen
endif
endif endif
" If focus changed, restore it (jump to the last window). " If focus changed, restore it (jump to the last window).

View File

@@ -1,6 +1,37 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: This file implements functions for jumping around in a file " Description: This file implements functions for jumping around in a file
" based on ALE's internal loclist. " based on errors and warnings in the loclist or quickfix list.
function! s:GetCurrentList() abort
if g:ale_set_loclist
return getloclist(winnr())
elseif g:ale_set_quickfix
let l:buffer = bufnr('%')
return filter(getqflist(), 'get(v:val, ''bufnr'', -1) == ' . l:buffer)
endif
return []
endfunction
function! s:GetSortedLoclist() abort
let l:loclist = []
for l:item in s:GetCurrentList()
if l:item.lnum < 1
" Remove items we can't even jump to.
continue
endif
call add(l:loclist, l:item)
endfor
" We must sort the list again, as the loclist could contain items set
" by other plugins.
call sort(l:loclist, 'ale#util#LocItemCompare')
return l:loclist
endfunction
" Search for the nearest line either before or after the current position " Search for the nearest line either before or after the current position
" in the loclist. The argument 'wrap' can be passed to enable wrapping " in the loclist. The argument 'wrap' can be passed to enable wrapping
@@ -10,15 +41,18 @@
" List will be returned, otherwise a pair of [line_number, column_number] will " List will be returned, otherwise a pair of [line_number, column_number] will
" be returned. " be returned.
function! ale#loclist_jumping#FindNearest(direction, wrap) abort function! ale#loclist_jumping#FindNearest(direction, wrap) abort
let l:pos = getcurpos() let l:loclist = s:GetSortedLoclist()
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
" This list will have already been sorted. if empty(l:loclist)
let l:loclist = l:info.loclist " We couldn't find anything, so stop here.
let l:search_item = {'lnum': l:pos[1], 'col': l:pos[2]} return []
endif
let l:search_item = {'lnum': getcurpos()[1], 'col': getcurpos()[2]}
" When searching backwards, so we can find the next smallest match. " When searching backwards, so we can find the next smallest match.
if a:direction ==# 'before' if a:direction ==# 'before'
let l:loclist = reverse(copy(l:loclist)) call reverse(l:loclist)
endif endif
" Look for items before or after the current position. " Look for items before or after the current position.
@@ -47,8 +81,8 @@ function! ale#loclist_jumping#FindNearest(direction, wrap) abort
" If we found nothing, and the wrap option is set to 1, then we should " If we found nothing, and the wrap option is set to 1, then we should
" wrap around the list of warnings/errors " wrap around the list of warnings/errors
if a:wrap && !empty(l:loclist) if a:wrap
let l:item = l:loclist[0] let l:item = get(l:loclist, 0)
return [l:item.lnum, l:item.col] return [l:item.lnum, l:item.col]
endif endif

View File

@@ -12,6 +12,14 @@ if !hlexists('ALEWarningSign')
highlight link ALEWarningSign todo highlight link ALEWarningSign todo
endif 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. " Signs show up on the left for error markers.
execute 'sign define ALEErrorSign text=' . g:ale_sign_error execute 'sign define ALEErrorSign text=' . g:ale_sign_error
\ . ' texthl=ALEErrorSign' \ . ' texthl=ALEErrorSign'
@@ -28,30 +36,26 @@ function! ale#sign#ReadSigns(buffer) abort
return split(l:output, "\n") return split(l:output, "\n")
endfunction endfunction
" Given a list of lines for sign output, return a List of pairs [line, id] " Given a list of lines for sign output, return a list of sign IDs
function! ale#sign#ParseSigns(line_list) abort function! ale#sign#ParseSigns(line_list) abort
" Matches output like : " Matches output like :
" line=4 id=1 name=ALEErrorSign " line=4 id=1 name=ALEErrorSign
" строка=1 id=1000001 имя=ALEErrorSign " строка=1 id=1000001 имя=ALEErrorSign
" 行=1 識別子=1000001 名前=ALEWarningSign " 行=1 識別子=1000001 名前=ALEWarningSign
" línea=12 id=1000001 nombre=ALEWarningSign " línea=12 id=1000001 nombre=ALEWarningSign
" riga=1 id=1000001, nome=ALEWarningSign let l:pattern = '^.*=\d*\s\+.*=\(\d\+\)\s\+.*=ALE\(Warning\|Error\|Dummy\)Sign'
let l:pattern = '^.*=\(\d\+\).*=\(\d\+\).*=ALE\(Error\|Warning\|Dummy\)Sign'
let l:result = [] let l:id_list = []
for l:line in a:line_list for l:line in a:line_list
let l:match = matchlist(l:line, l:pattern) let l:match = matchlist(l:line, l:pattern)
if len(l:match) > 0 if len(l:match) > 0
call add(l:result, [ call add(l:id_list, l:match[1] + 0)
\ str2nr(l:match[1]),
\ str2nr(l:match[2]),
\ 'ALE' . l:match[3] . 'Sign',
\])
endif endif
endfor endfor
return l:result return l:id_list
endfunction endfunction
function! ale#sign#FindCurrentSigns(buffer) abort function! ale#sign#FindCurrentSigns(buffer) abort
@@ -60,144 +64,90 @@ function! ale#sign#FindCurrentSigns(buffer) abort
return ale#sign#ParseSigns(l:line_list) return ale#sign#ParseSigns(l:line_list)
endfunction endfunction
" Given a loclist, group the List into with one List per line. " Given a loclist, combine the loclist into a list of signs such that only
function! s:GroupLoclistItems(loclist) abort " one sign appears per line. Error lines will take precedence.
let l:grouped_items = [] " The loclist will have been previously sorted.
let l:last_lnum = -1 function! ale#sign#CombineSigns(loclist) abort
let l:signlist = []
for l:obj in a:loclist for l:obj in a:loclist
" Create a new sub-List when we hit a new line. let l:should_append = 1
if l:obj.lnum != l:last_lnum
call add(l:grouped_items, []) if l:obj.lnum < 1
" Skip warnings and errors at line 0, etc.
continue
endif endif
call add(l:grouped_items[-1], l:obj) if len(l:signlist) > 0 && l:signlist[-1].lnum == l:obj.lnum
let l:last_lnum = l:obj.lnum " We can't add the same line twice, because signs must be
endfor " unique per line.
let l:should_append = 0
return l:grouped_items if l:signlist[-1].type ==# 'W' && l:obj.type ==# 'E'
endfunction " If we had a warning previously, but now have an error,
" we replace the object to set an error instead.
function! s:IsDummySignSet(current_id_list) abort let l:signlist[-1] = l:obj
for [l:line, l:id, l:name] in a:current_id_list
if l:id == g:ale_sign_offset
return 1
endif
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: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:is_dummy_sign_set = 1
endif
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 endif
endif
call add(l:items_by_sign_id[l:item.sign_id], l:item) if l:should_append
call add(l:signlist, l:obj)
endif endif
endfor endfor
return l:items_by_sign_id return l:signlist
endfunction
" 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)
" 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 endfunction
" This function will set the signs which show up on the left. " This function will set the signs which show up on the left.
function! ale#sign#SetSigns(buffer, loclist) abort function! ale#sign#SetSigns(buffer, loclist) abort
let l:signlist = ale#sign#CombineSigns(a:loclist)
" Find the current markers " Find the current markers
let l:current_sign_list = ale#sign#FindCurrentSigns(a:buffer) let l:current_id_list = ale#sign#FindCurrentSigns(a:buffer)
let l:dummy_sign_set = 0
call s:UpdateLineNumbers(l:current_sign_list, a:loclist) " Check if we set the dummy sign already.
for l:current_id in l:current_id_list
let l:grouped_items = s:GroupLoclistItems(a:loclist) if l:current_id == g:ale_sign_offset
let l:dummy_sign_set = 1
" 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 endif
endfor endfor
call s:PlaceNewSigns(a:buffer, l:grouped_items) " If we haven't already set a dummy sign, and we have some previous signs
" or always want a dummy sign, then set one, to keep the sign column open.
if !l:dummy_sign_set && (len(l:signlist) > 0 || g:ale_sign_column_always)
execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign buffer='
\ . a:buffer
let l:dummy_sign_set = 1
endif
" Now remove the previous signs. The dummy will hold the column open
" while we add the new signs, if we had signs before.
for l:current_id in l:current_id_list
if l:current_id != g:ale_sign_offset
exec 'sign unplace ' . l:current_id . ' buffer=' . a:buffer
endif
endfor
" Add the new signs,
for l:index in range(0, len(l:signlist) - 1)
let l:sign = l:signlist[l:index]
let l:type = l:sign['type'] ==# 'W' ? 'ALEWarningSign' : 'ALEErrorSign'
let l:sign_line = 'sign place ' . (l:index + g:ale_sign_offset + 1)
\. ' line=' . l:sign['lnum']
\. ' name=' . l:type
\. ' buffer=' . a:buffer
exec l:sign_line
endfor
" Remove the dummy sign now we've updated the signs, unless we want " 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 " to keep it, which will keep the sign column open even when there are
" no warnings or errors. " no warnings or errors.
if l:is_dummy_sign_set && !g:ale_sign_column_always if l:dummy_sign_set && !g:ale_sign_column_always
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
endif endif
endfunction endfunction

Some files were not shown because too many files have changed in this diff Show More