Compare commits

..

13 Commits

Author SHA1 Message Date
w0rp
cedc3e1a1f Fix #560 #763 - Silence errors for setting signs, and do nothing for dirvish 2017-07-16 01:17:48 +01:00
w0rp
30aef6b19a Fix #749 - Use /bin/sh when the shell is fish 2017-07-10 21:36:42 +01:00
w0rp
bd0f31147e Fix #730 - Lint files on save even when nothing was fixed 2017-07-10 13:41:38 +01:00
daa84
74f2afbe2e Fix windows path check on rust linter (#736)
* Fix rust linter on windows

* Add windows path test

* Use ale#path#IsBufferPath to compare paths

* Fix errors
2017-07-07 17:04:16 +01:00
w0rp
d438f8f268 Fix #735 - Support old versions of Flow by only adding --respect-pragma for supported versions 2017-07-07 11:00:38 +01:00
w0rp
2f2af4315b #710 - Fix a parsing bug caused by the last fix 2017-07-07 11:00:26 +01:00
w0rp
a040878ebc #710 - Show warnings as warnings for ghc 2017-07-07 00:28:52 +01:00
w0rp
a72c1edfcc #732 - Use the configuration files when fixing files with rubocop 2017-07-06 23:08:38 +01:00
w0rp
acda19776a Initialize rubocop variables in one place 2017-07-06 23:08:24 +01:00
w0rp
e9a1cd600a Store the output of commands by default so I don't have to ask people to turn it on any more. 2017-07-04 00:16:53 +01:00
w0rp
0819c4cd56 Fix #216 - Filter out errors for other files for ansible-lint 2017-07-03 23:18:49 +01:00
w0rp
448600fe4f Merge pull request #716 from sobrinho/master
Fix brakeman handler when there is no output
2017-07-01 15:43:41 +01:00
w0rp
bb1f413bf3 Fix #706 - Skip fixers with jobs that return empty output, in case they have failed 2017-06-29 12:03:05 +01:00
372 changed files with 2190 additions and 10125 deletions

View File

@@ -2,6 +2,9 @@
sudo: required sudo: required
services: services:
- docker - docker
branches:
only:
- master
language: python language: python
script: | script: |
./run-tests ./run-tests

View File

@@ -74,10 +74,10 @@ If you want to credit multiple authors, you can comma separate them.
### 3.i. Adding a New Linter ### 3.i. Adding a New Linter
If you add a new linter, look for existing handlers first in the If you add a new linter, look for existing handlers first in the
[handlers](autoload/ale/handlers) directory. One of the handlers there may [handlers.vim](autoload/ale/handlers.vim) file. One of the handlers there may
already be able to handle your lines of output. If you find that your new already be able to handle your lines of output. If you find that your new
linter replicates an existing error handler, consider pulling it up into the linter replicates an existing error handler, consider pulling it up into the
[handlers](autoload/ale/handlers) directory, and use the generic handler in [handlers.vim](autoload/ale/handlers.vim) file, and use the generic handler in
both places. both places.
When you add a linter, make sure the language for the linter and the linter When you add a linter, make sure the language for the linter and the linter

View File

@@ -1,4 +1,8 @@
<!-- <!--
READ THIS FIRST: If you are experiencing any bug whatsoever dealing with
the output of linters, please use `let g:ale_history_log_output = 1` before
pasting output. It will capture the output of commands that are run.
For bugs, paste output from your clipboard after running :ALEInfoToClipboard For bugs, paste output from your clipboard after running :ALEInfoToClipboard
here. If that doesn't work for some reason, try running :ALEInfo and copying 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 the output from that here instead. If everything is broken, run around in

View File

@@ -1,4 +1,4 @@
Copyright (c) 2016-2017, w0rp <devw0rp@gmail.com> Copyright (c) 2016, w0rp <devw0rp@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -1,10 +1,6 @@
<!-- <!--
READ THIS: Before creating a pull request, please consider the following first. When creating new pull requests, please consider the following.
* The most important thing you can do is write tests. Code without tests
probably doesn't work, and will almost certainly stop working later on. Pull
requests without tests probably won't be accepted, although there are some
exceptions.
* Read the Contributing guide linked above first. * Read the Contributing guide linked above first.
* If you are adding a new linter, remember to update the README.md file and * If you are adding a new linter, remember to update the README.md file and
doc/ale.txt first. doc/ale.txt first.

177
README.md
View File

@@ -15,21 +15,17 @@ back to a filesystem.
In other words, this plugin allows you to lint while you type. In other words, this plugin allows you to lint while you type.
In addition to linting support, ALE offers some support for fixing code with ALE also supports fixing problems with files by running commands in the
formatting tools, and completion via Language Server Protocol servers, or background with a command `ALEFix`.
servers with similar enough protocols, like `tsserver`.
## Table of Contents ## Table of Contents
1. [Supported Languages and Tools](#supported-languages) 1. [Supported Languages and Tools](#supported-languages)
2. [Usage](#usage) 2. [Usage](#usage)
1. [Linting](#usage-linting)
2. [Fixing](#usage-fixing)
3. [Completion](#usage-completion)
3. [Installation](#installation) 3. [Installation](#installation)
1. [Installation with Vim package management](#standard-installation) 1. [Installation with Pathogen](#installation-with-pathogen)
2. [Installation with Pathogen](#installation-with-pathogen) 2. [Installation with Vundle](#installation-with-vundle)
3. [Installation with Vundle](#installation-with-vundle) 3. [Manual Installation](#manual-installation)
4. [Contributing](#contributing) 4. [Contributing](#contributing)
5. [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)
@@ -65,8 +61,8 @@ name. That seems to be the fairest way to arrange this table.
| Awk | [gawk](https://www.gnu.org/software/gawk/)| | Awk | [gawk](https://www.gnu.org/software/gawk/)|
| Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) | | 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/), [clang-format](https://clang.llvm.org/docs/ClangFormat.html)| | C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [gcc](https://gcc.gnu.org/), [clang-format](https://clang.llvm.org/docs/ClangFormat.html)| | C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [gcc](https://gcc.gnu.org/)|
| 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) | | CMake | [cmakelint](https://github.com/richq/cmake-lint) |
@@ -75,23 +71,20 @@ name. That seems to be the fairest way to arrange this table.
| 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/) |
| D | [dmd](https://dlang.org/dmd-linux.html) | | D | [dmd](https://dlang.org/dmd-linux.html) |
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) |
| Dockerfile | [hadolint](https://github.com/lukasmartinelli/hadolint) | | Dockerfile | [hadolint](https://github.com/lukasmartinelli/hadolint) |
| Elixir | [credo](https://github.com/rrrene/credo), [dogma](https://github.com/lpil/dogma) | | Elixir | [credo](https://github.com/rrrene/credo), [dogma](https://github.com/lpil/dogma) |
| Elm | [elm-make](https://github.com/elm-lang/elm-make) | | Elm | [elm-make](https://github.com/elm-lang/elm-make) |
| Erb | [erb](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis) | | Erb | [erb](https://github.com/jeremyevans/erubi) |
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html), [SyntaxErl](https://github.com/ten0s/syntaxerl) | | Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
| Fortran | [gcc](https://gcc.gnu.org/) | | Fortran | [gcc](https://gcc.gnu.org/) |
| FusionScript | [fusion-lint](https://github.com/RyanSquared/fusionscript) | | FusionScript | [fusion-lint](https://github.com/RyanSquared/fusionscript) |
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [gometalinter](https://github.com/alecthomas/gometalinter), [go build](https://golang.org/cmd/go/), [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple), [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) | | Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [gometalinter](https://github.com/alecthomas/gometalinter), [go build](https://golang.org/cmd/go/), [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple), [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) |
| GraphQL | [gqlint](https://github.com/happylinks/gqlint) |
| Haml | [haml-lint](https://github.com/brigade/haml-lint) | Haml | [haml-lint](https://github.com/brigade/haml-lint)
| Handlebars | [ember-template-lint](https://github.com/rwjblue/ember-template-lint) | | Handlebars | [ember-template-lint](https://github.com/rwjblue/ember-template-lint) |
| Haskell | [ghc](https://www.haskell.org/ghc/), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/), [ghc-mod](https://github.com/DanielG/ghc-mod), [stack-ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) | | Haskell | [ghc](https://www.haskell.org/ghc/), [ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) |
| HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) | | HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) |
| Idris | [idris](http://www.idris-lang.org/) |
| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) | | Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/), [prettier](https://github.com/prettier/prettier) (and `prettier-eslint`, `prettier-standard`), [xo](https://github.com/sindresorhus/xo) | JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/), [prettier](https://github.com/prettier/prettier) (and `prettier-eslint`), [xo](https://github.com/sindresorhus/xo)
| JSON | [jsonlint](http://zaa.ch/jsonlint/) | | JSON | [jsonlint](http://zaa.ch/jsonlint/) |
| Kotlin | [kotlinc](https://kotlinlang.org), [ktlint](https://ktlint.github.io) see `:help ale-integration-kotlin` for configuration instructions | Kotlin | [kotlinc](https://kotlinlang.org), [ktlint](https://ktlint.github.io) see `:help ale-integration-kotlin` for configuration instructions
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/) | | LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/) |
@@ -105,26 +98,23 @@ name. That seems to be the fairest way to arrange this table.
| Objective-C++ | [clang](http://clang.llvm.org/) | | Objective-C++ | [clang](http://clang.llvm.org/) |
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions | 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/), [langserver](https://github.com/felixfbecker/php-language-server), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer) | | PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) |
| Pod | [proselint](http://proselint.com/)| | 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 | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pylint](https://www.pylint.org/), [yapf](https://github.com/google/yapf) | | Python | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/), [yapf](https://github.com/google/yapf) |
| R | [lintr](https://github.com/jimhester/lintr) |
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions | ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions
| reStructuredText | [proselint](http://proselint.com/)| | reStructuredText | [proselint](http://proselint.com/)|
| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) | | RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) |
| Ruby | [brakeman](http://brakemanscanner.org/), [rails_best_practices](https://github.com/flyerhzm/rails_best_practices), [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) | | Ruby | [brakeman](http://brakemanscanner.org/), [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) |
| Rust | cargo (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/) | | 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), [scalastyle](http://www.scalastyle.org) | | Scala | [scalac](http://scala-lang.org) |
| Slim | [slim-lint](https://github.com/sds/slim-lint) | Slim | [slim-lint](https://github.com/sds/slim-lint)
| SML | [smlnj](http://www.smlnj.org/) | | SML | [smlnj](http://www.smlnj.org/) |
| Stylus | [stylelint](https://github.com/stylelint/stylelint) |
| SQL | [sqlint](https://github.com/purcell/sqlint) | | SQL | [sqlint](https://github.com/purcell/sqlint) |
| Swift | [swiftlint](https://github.com/realm/SwiftLint), [swiftformat](https://github.com/nicklockwood/SwiftFormat) | | Swift | [swiftlint](https://swift.org/) |
| Tcl | [nagelfar](http://nagelfar.sourceforge.net)|
| Texinfo | [proselint](http://proselint.com/)| | Texinfo | [proselint](http://proselint.com/)|
| Text^ | [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) | | Text^ | [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) |
| TypeScript | [eslint](http://eslint.org/), [tslint](https://github.com/palantir/tslint), tsserver, typecheck | | TypeScript | [eslint](http://eslint.org/), [tslint](https://github.com/palantir/tslint), tsserver, typecheck |
@@ -133,7 +123,7 @@ name. That seems to be the fairest way to arrange this table.
| Vim help^ | [proselint](http://proselint.com/)| | Vim help^ | [proselint](http://proselint.com/)|
| XHTML | [proselint](http://proselint.com/)| | XHTML | [proselint](http://proselint.com/)|
| XML | [xmllint](http://xmlsoft.org/xmllint.html/)| | XML | [xmllint](http://xmlsoft.org/xmllint.html/)|
| YAML | [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) | | YAML | [yamllint](https://yamllint.readthedocs.io/) |
* *^ No linters for text or Vim help filetypes are enabled by default.* * *^ No linters for text or Vim help filetypes are enabled by default.*
@@ -141,10 +131,6 @@ name. That seems to be the fairest way to arrange this table.
## 2. Usage ## 2. Usage
<a name="usage-linting"></a>
### 2.i Linting
Once this plugin is installed, while editing your files in supported Once this plugin is installed, while editing your files in supported
languages and tools which have been correctly installed, languages and tools which have been correctly installed,
this plugin will send the contents of your text buffers to a variety of this plugin will send the contents of your text buffers to a variety of
@@ -157,46 +143,8 @@ documented in [the Vim help file](doc/ale.txt). For more information on the
options ALE offers, consult `:help ale-options` for global options and `:help options ALE offers, consult `:help ale-options` for global options and `:help
ale-linter-options` for options specified to particular linters. ale-linter-options` for options specified to particular linters.
<a name="usage-fixing"></a>
### 2.ii Fixing
ALE can fix files with the `ALEFix` command. Functions need to be configured ALE can fix files with the `ALEFix` command. Functions need to be configured
for different filetypes with the `g:ale_fixers` variable. For example, the for different filetypes with the `g:ale_fixers` variable. See `:help ale-fix`.
following code can be used to fix JavaScript code with ESLint:
```vim
" Put this in vimrc or a plugin file of your own.
" After this is configured, :ALEFix will try and fix your JS code with ESLint.
let g:ale_fixers = {
\ 'javascript': ['eslint'],
\}
" Set this setting in vimrc if you want to fix files automatically on save.
" This is off by default.
let g:ale_fix_on_save = 1
```
The `:ALEFixSuggest` command will suggest some supported tools for fixing code,
but fixers can be also implemented with functions, including lambda functions
too. See `:help ale-fix` for detailed information.
<a name="usage-completion"></a>
### 2.iii Completion
ALE offers some support for completion via hijacking of omnicompletion while you
type. All of ALE's completion information must come from Language Server
Protocol linters, or similar protocols. At the moment, completion is only
supported for TypeScript code with `tsserver`, when `tsserver` is enabled. You
can enable completion like so:
```vim
" Enable completion where available.
let g:ale_completion_enabled = 1
```
See `:help ale-completion` for more information.
<a name="installation"></a> <a name="installation"></a>
@@ -204,59 +152,13 @@ See `:help ale-completion` for more information.
To install this plugin, you should use one of the following methods. To install this plugin, you should use one of the following methods.
For Windows users, replace usage of the Unix `~/.vim` directory with For Windows users, replace usage of the Unix `~/.vim` directory with
`%USERPROFILE%\vimfiles`, or another directory if you have configured `%USERPROFILE%\_vim`, or another directory if you have configured
Vim differently. On Windows, your `~/.vimrc` file will be similarly Vim differently. On Windows, your `~/.vimrc` file will be similarly
stored in `%USERPROFILE%\_vimrc`. stored in `%USERPROFILE%\_vimrc`.
<a name="standard-installation"></a>
### 3.i. Installation with Vim package management
In Vim 8 and NeoVim, you can install plugins easily without needing to use
any other tools. Simply clone the plugin into your `pack` directory.
#### Vim 8 on Unix
```bash
mkdir -p ~/.vim/pack/git-plugins/start
git clone https://github.com/w0rp/ale.git ~/.vim/pack/git-plugins/start/ale
```
#### NeoVim on Unix
```bash
mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start
git clone https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
```
#### Vim 8 on Windows
```bash
# Run these commands in the "Git for Windows" Bash terminal
mkdir -p ~/vimfiles/pack/git-plugins/start
git clone https://github.com/w0rp/ale.git ~/vimfiles/pack/git-plugins/start/ale
```
#### Generating Vim help files
You can add the following line to your vimrc files to generate documentation
tags automatically, if you don't have something similar already, so you can use
the `:help` command to consult ALE's online documentation:
```vim
" Put these lines at the very end of your vimrc file.
" Load all plugins now.
" Plugins need to be added to runtimepath before helptags can be generated.
packloadall
" Load all of the helptags now, after plugins have been loaded.
" All messages and errors will be ignored.
silent! helptags ALL
```
<a name="installation-with-pathogen"></a> <a name="installation-with-pathogen"></a>
### 3.ii. Installation with Pathogen ### 3.i. Installation with Pathogen
To install this module with [Pathogen](https://github.com/tpope/vim-pathogen), To install this module with [Pathogen](https://github.com/tpope/vim-pathogen),
you should clone this repository to your bundle directory, and ensure you should clone this repository to your bundle directory, and ensure
@@ -270,7 +172,7 @@ git clone https://github.com/w0rp/ale.git
<a name="installation-with-vundle"></a> <a name="installation-with-vundle"></a>
### 3.iii. Installation with Vundle ### 3.ii. Installation with Vundle
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim) You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
by using the path on GitHub for this repository. by using the path on GitHub for this repository.
@@ -281,6 +183,41 @@ Plugin 'w0rp/ale'
See the Vundle documentation for more information. See the Vundle documentation for more information.
<a name="manual-installation"></a>
### 3.iii. Manual Installation
For installation without a package manager, you can clone this git repository
into a bundle directory as with pathogen, and add the repository to your
runtime path yourself. First clone the repository.
```bash
cd ~/.vim/bundle
git clone https://github.com/w0rp/ale.git
```
Then, modify your `~/.vimrc` file to add this plugin to your runtime path.
```vim
set nocompatible
filetype off
let &runtimepath.=',~/.vim/bundle/ale'
filetype plugin on
```
You can add the following line to generate documentation tags automatically,
if you don't have something similar already, so you can use the `:help` command
to consult ALE's online documentation:
```vim
silent! helptags ALL
```
Because the author of this plugin is a weird nerd, this is his preferred
installation method.
<a name="contributing"></a> <a name="contributing"></a>
## 4. Contributing ## 4. Contributing

View File

@@ -21,7 +21,7 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[4] let l:code = l:match[4]
if l:code is# 'EANSIBLE002' if (l:code ==# 'EANSIBLE002')
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
" Skip warnings for trailing whitespace if the option is off. " Skip warnings for trailing whitespace if the option is off.
continue continue
@@ -32,7 +32,7 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'text': l:code . ': ' . l:match[5], \ 'text': l:code . ': ' . l:match[5],
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W', \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
\}) \})
endif endif
endfor endfor

View File

@@ -1,20 +1,20 @@
" Author: Masahiro H https://github.com/mshr-h " Author: Masahiro H https://github.com/mshr-h
" Description: clang linter for c files " Description: clang linter for c files
call ale#Set('c_clang_executable', 'clang') " Set this option to change the Clang options for warnings for C.
call ale#Set('c_clang_options', '-std=c11 -Wall') if !exists('g:ale_c_clang_options')
" let g:ale_c_clang_options = '-Wall'
function! ale_linters#c#clang#GetExecutable(buffer) abort " let g:ale_c_clang_options = '-std=c99 -Wall'
return ale#Var(a:buffer, 'c_clang_executable') " c11 compatible
endfunction let g:ale_c_clang_options = '-std=c11 -Wall'
endif
function! ale_linters#c#clang#GetCommand(buffer) abort function! ale_linters#c#clang#GetCommand(buffer) abort
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer) let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return ale#Escape(ale_linters#c#clang#GetExecutable(a:buffer)) return 'clang -S -x c -fsyntax-only '
\ . ' -S -x c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' ' \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . ale#c#IncludeOptions(l:paths) \ . ale#c#IncludeOptions(l:paths)
\ . ale#Var(a:buffer, 'c_clang_options') . ' -' \ . ale#Var(a:buffer, 'c_clang_options') . ' -'
@@ -23,7 +23,7 @@ endfunction
call ale#linter#Define('c', { call ale#linter#Define('c', {
\ 'name': 'clang', \ 'name': 'clang',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#c#clang#GetExecutable', \ 'executable': 'clang',
\ 'command_callback': 'ale_linters#c#clang#GetCommand', \ 'command_callback': 'ale_linters#c#clang#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\}) \})

View File

@@ -1,12 +1,8 @@
" Author: Bart Libert <bart.libert@gmail.com> " Author: Bart Libert <bart.libert@gmail.com>
" Description: cppcheck linter for c files " Description: cppcheck linter for c files
call ale#Set('c_cppcheck_executable', 'cppcheck') " Set this option to change the cppcheck options
call ale#Set('c_cppcheck_options', '--enable=style') let g:ale_c_cppcheck_options = get(g:, 'ale_c_cppcheck_options', '--enable=style')
function! ale_linters#c#cppcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'c_cppcheck_executable')
endfunction
function! ale_linters#c#cppcheck#GetCommand(buffer) abort function! ale_linters#c#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json. " Search upwards from the file for compile_commands.json.
@@ -23,8 +19,7 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . ale#Escape(ale_linters#c#cppcheck#GetExecutable(a:buffer)) \ . 'cppcheck -q --language=c '
\ . ' -q --language=c '
\ . l:compile_commands_option \ . l:compile_commands_option
\ . ale#Var(a:buffer, 'c_cppcheck_options') \ . ale#Var(a:buffer, 'c_cppcheck_options')
\ . ' %t' \ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('c', { call ale#linter#Define('c', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable_callback': 'ale_linters#c#cppcheck#GetExecutable', \ 'executable': 'cppcheck',
\ 'command_callback': 'ale_linters#c#cppcheck#GetCommand', \ 'command_callback': 'ale_linters#c#cppcheck#GetCommand',
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\}) \})

View File

@@ -1,20 +1,20 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: gcc linter for c files " Description: gcc linter for c files
call ale#Set('c_gcc_executable', 'gcc') " Set this option to change the GCC options for warnings for C.
call ale#Set('c_gcc_options', '-std=c11 -Wall') if !exists('g:ale_c_gcc_options')
" let g:ale_c_gcc_options = '-Wall'
function! ale_linters#c#gcc#GetExecutable(buffer) abort " let g:ale_c_gcc_options = '-std=c99 -Wall'
return ale#Var(a:buffer, 'c_gcc_executable') " c11 compatible
endfunction let g:ale_c_gcc_options = '-std=c11 -Wall'
endif
function! ale_linters#c#gcc#GetCommand(buffer) abort function! ale_linters#c#gcc#GetCommand(buffer) abort
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer) let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return ale#Escape(ale_linters#c#gcc#GetExecutable(a:buffer)) return 'gcc -S -x c -fsyntax-only '
\ . ' -S -x c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' ' \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . ale#c#IncludeOptions(l:paths) \ . ale#c#IncludeOptions(l:paths)
\ . ale#Var(a:buffer, 'c_gcc_options') . ' -' \ . ale#Var(a:buffer, 'c_gcc_options') . ' -'
@@ -23,7 +23,7 @@ endfunction
call ale#linter#Define('c', { call ale#linter#Define('c', {
\ 'name': 'gcc', \ 'name': 'gcc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#c#gcc#GetExecutable', \ 'executable': 'gcc',
\ 'command_callback': 'ale_linters#c#gcc#GetCommand', \ 'command_callback': 'ale_linters#c#gcc#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\}) \})

View File

@@ -27,7 +27,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': str2nr(l:match[1]), \ 'lnum': str2nr(l:match[1]),
\ 'type': l:match[3] is# 'error' ? 'E' : 'W', \ 'type': l:match[3] ==# 'error' ? 'E' : 'W',
\ 'text': l:match[4], \ 'text': l:match[4],
\}) \})
endfor endfor

View File

@@ -1,20 +1,17 @@
" Author: Tomota Nakamura <https://github.com/tomotanakamura> " Author: Tomota Nakamura <https://github.com/tomotanakamura>
" Description: clang linter for cpp files " Description: clang linter for cpp files
call ale#Set('cpp_clang_executable', 'clang++') " Set this option to change the Clang options for warnings for CPP.
call ale#Set('cpp_clang_options', '-std=c++14 -Wall') if !exists('g:ale_cpp_clang_options')
let g:ale_cpp_clang_options = '-std=c++14 -Wall'
function! ale_linters#cpp#clang#GetExecutable(buffer) abort endif
return ale#Var(a:buffer, 'cpp_clang_executable')
endfunction
function! ale_linters#cpp#clang#GetCommand(buffer) abort function! ale_linters#cpp#clang#GetCommand(buffer) abort
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer) let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return ale#Escape(ale_linters#cpp#clang#GetExecutable(a:buffer)) return 'clang++ -S -x c++ -fsyntax-only '
\ . ' -S -x c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' ' \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . ale#c#IncludeOptions(l:paths) \ . ale#c#IncludeOptions(l:paths)
\ . ale#Var(a:buffer, 'cpp_clang_options') . ' -' \ . ale#Var(a:buffer, 'cpp_clang_options') . ' -'
@@ -23,7 +20,7 @@ endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'clang', \ 'name': 'clang',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#cpp#clang#GetExecutable', \ 'executable': 'clang++',
\ 'command_callback': 'ale_linters#cpp#clang#GetCommand', \ 'command_callback': 'ale_linters#cpp#clang#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\}) \})

View File

@@ -1,38 +1,36 @@
" Author: gagbo <gagbobada@gmail.com> " Author: gagbo <gagbobada@gmail.com>
" Description: clang-check linter for cpp files " Description: clang-check linter for cpp files
call ale#Set('cpp_clangcheck_executable', 'clang-check') " Set this option to manually set some options for clang-check.
call ale#Set('cpp_clangcheck_options', '') let g:ale_cpp_clangcheck_options = get(g:, 'ale_cpp_clangcheck_options', '')
call ale#Set('c_build_dir', '')
function! ale_linters#cpp#clangcheck#GetExecutable(buffer) abort " Set this option to manually point to the build directory for clang-tidy.
return ale#Var(a:buffer, 'cpp_clangcheck_executable') " This will disable all the other clangtidy_options, since compilation
endfunction " flags are contained in the json
let g:ale_c_build_dir = get(g:, 'ale_c_build_dir', '')
function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options') let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options')
let l:extra_options = !empty(l:user_options)
\ ? l:user_options
\ : ''
" Try to find compilation database to link automatically " Try to find compilation database to link automatically
let l:build_dir = ale#Var(a:buffer, 'c_build_dir') let l:user_build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:user_build_dir)
if empty(l:build_dir) let l:user_build_dir = ale#c#FindCompileCommands(a:buffer)
let l:build_dir = ale#c#FindCompileCommands(a:buffer)
endif endif
let l:build_options = !empty(l:user_build_dir)
\ ? ' -p ' . ale#Escape(l:user_build_dir)
\ : ''
" The extra arguments in the command are used to prevent .plist files from return 'clang-check -analyze ' . '%s' . l:extra_options . l:build_options
" being generated. These are only added if no build directory can be
" detected.
return ale#Escape(ale_linters#cpp#clangcheck#GetExecutable(a:buffer))
\ . ' -analyze %s'
\ . (!empty(l:user_options) ? ' ' . l:user_options : '')
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (empty(l:build_dir) ? ' -extra-arg -Xanalyzer -extra-arg -analyzer-output=text' : '')
endfunction endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'clangcheck', \ 'name': 'clangcheck',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#cpp#clangcheck#GetExecutable', \ 'executable': 'clang-check',
\ 'command_callback': 'ale_linters#cpp#clangcheck#GetCommand', \ 'command_callback': 'ale_linters#cpp#clangcheck#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1, \ 'lint_file': 1,

View File

@@ -2,56 +2,51 @@
" gagbo <gagbobada@gmail.com> " gagbo <gagbobada@gmail.com>
" Description: clang-tidy linter for cpp files " Description: clang-tidy linter for cpp files
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply. " Set this option to check the checks clang-tidy will apply.
call ale#Set('cpp_clangtidy_checks', ['*']) let g:ale_cpp_clangtidy_checks = get(g:, 'ale_cpp_clangtidy_checks', ['*'])
" Set this option to manually set some options for clang-tidy. " Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection. " This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '') let g:ale_cpp_clangtidy_options = get(g:, 'ale_cpp_clangtidy_options', '')
call ale#Set('c_build_dir', '')
function! ale_linters#cpp#clangtidy#GetExecutable(buffer) abort " Set this option to manually point to the build directory for clang-tidy.
return ale#Var(a:buffer, 'cpp_clangtidy_executable') " This will disable all the other clangtidy_options, since compilation
endfunction " flags are contained in the json
let g:ale_c_build_dir = get(g:, 'ale_c_build_dir', '')
function! s:GetBuildDirectory(buffer) abort
" Don't include build directory for header files, as compile_commands.json
" files don't consider headers to be translation units, and provide no
" commands for compiling header files.
if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
return ''
endif
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
" c_build_dir has the priority if defined
if !empty(l:build_dir)
return l:build_dir
endif
return ale#c#FindCompileCommands(a:buffer)
endfunction
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',') let l:check_list = ale#Var(a:buffer, 'cpp_clangtidy_checks')
let l:build_dir = s:GetBuildDirectory(a:buffer) let l:check_option = !empty(l:check_list)
\ ? '-checks=' . ale#Escape(join(l:check_list, ',')) . ' '
" Get the extra options if we couldn't find a build directory.
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
\ : '' \ : ''
let l:user_options = ale#Var(a:buffer, 'cpp_clangtidy_options')
let l:user_build_dir = ale#Var(a:buffer, 'c_build_dir')
return ale#Escape(ale_linters#cpp#clangtidy#GetExecutable(a:buffer)) " c_build_dir has the priority if defined
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') if empty(l:user_build_dir)
\ . ' %s' let l:user_build_dir = ale#c#FindCompileCommands(a:buffer)
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') endif
\ . (!empty(l:options) ? ' -- ' . l:options : '')
" We check again if user_builddir stayed empty after the
" c_build_dir_names check
" If we found the compilation database we override the value of
" l:extra_options
if empty(l:user_build_dir)
let l:extra_options = !empty(l:user_options)
\ ? ' -- ' . l:user_options
\ : ''
else
let l:extra_options = ' -p ' . ale#Escape(l:user_build_dir)
endif
return 'clang-tidy ' . l:check_option . '%s' . l:extra_options
endfunction endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'clangtidy', \ 'name': 'clangtidy',
\ 'output_stream': 'stdout', \ 'output_stream': 'stdout',
\ 'executable_callback': 'ale_linters#cpp#clangtidy#GetExecutable', \ 'executable': 'clang-tidy',
\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand', \ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1, \ 'lint_file': 1,

View File

@@ -1,12 +1,8 @@
" Author: Bart Libert <bart.libert@gmail.com> " Author: Bart Libert <bart.libert@gmail.com>
" Description: cppcheck linter for cpp files " Description: cppcheck linter for cpp files
call ale#Set('cpp_cppcheck_executable', 'cppcheck') " Set this option to change the cppcheck options
call ale#Set('cpp_cppcheck_options', '--enable=style') let g:ale_cpp_cppcheck_options = get(g:, 'ale_cpp_cppcheck_options', '--enable=style')
function! ale_linters#cpp#cppcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'cpp_cppcheck_executable')
endfunction
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json. " Search upwards from the file for compile_commands.json.
@@ -23,8 +19,7 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . ale#Escape(ale_linters#cpp#cppcheck#GetExecutable(a:buffer)) \ . 'cppcheck -q --language=c++ '
\ . ' -q --language=c++ '
\ . l:compile_commands_option \ . l:compile_commands_option
\ . ale#Var(a:buffer, 'cpp_cppcheck_options') \ . ale#Var(a:buffer, 'cpp_cppcheck_options')
\ . ' %t' \ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable_callback': 'ale_linters#cpp#cppcheck#GetExecutable', \ 'executable': 'cppcheck',
\ 'command_callback': 'ale_linters#cpp#cppcheck#GetCommand', \ 'command_callback': 'ale_linters#cpp#cppcheck#GetCommand',
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\}) \})

View File

@@ -1,26 +1,15 @@
" Author: Dawid Kurek https://github.com/dawikur " Author: Dawid Kurek https://github.com/dawikur
" Description: cpplint for cpp files " Description: cpplint for cpp files
call ale#Set('cpp_cpplint_executable', 'cpplint') if !exists('g:ale_cpp_cpplint_options')
call ale#Set('cpp_cpplint_options', '') let g:ale_cpp_cpplint_options = ''
endif
function! ale_linters#cpp#cpplint#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'cpp_cpplint_executable')
endfunction
function! ale_linters#cpp#cpplint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'cpp_cpplint_options')
return ale#Escape(ale_linters#cpp#cpplint#GetExecutable(a:buffer))
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %s'
endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'cpplint', \ 'name': 'cpplint',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#cpp#cpplint#GetExecutable', \ 'executable': 'cpplint',
\ 'command_callback': 'ale_linters#cpp#cpplint#GetCommand', \ 'command': 'cpplint %s',
\ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat', \ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat',
\ 'lint_file': 1, \ 'lint_file': 1,
\}) \})

View File

@@ -1,20 +1,27 @@
" Author: geam <mdelage@student.42.fr> " Author: geam <mdelage@student.42.fr>
" Description: gcc linter for cpp files " Description: gcc linter for cpp files
"
call ale#Set('cpp_gcc_executable', 'gcc')
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
function! ale_linters#cpp#gcc#GetExecutable(buffer) abort " Set this option to change the GCC options for warnings for C.
return ale#Var(a:buffer, 'cpp_gcc_executable') if !exists('g:ale_cpp_gcc_options')
endfunction let s:version = ale#handlers#gcc#ParseGCCVersion(systemlist('gcc --version'))
if !empty(s:version) && ale#semver#GreaterOrEqual(s:version, [4, 9, 0])
" Use c++14 support in 4.9 and above.
let g:ale_cpp_gcc_options = '-std=c++14 -Wall'
else
" Use c++1y in older versions.
let g:ale_cpp_gcc_options = '-std=c++1y -Wall'
endif
unlet! s:version
endif
function! ale_linters#cpp#gcc#GetCommand(buffer) abort function! ale_linters#cpp#gcc#GetCommand(buffer) abort
let l:paths = ale#c#FindLocalHeaderPaths(a:buffer) let l:paths = ale#c#FindLocalHeaderPaths(a:buffer)
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return ale#Escape(ale_linters#cpp#gcc#GetExecutable(a:buffer)) return 'gcc -S -x c++ -fsyntax-only '
\ . ' -S -x c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' ' \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . ale#c#IncludeOptions(l:paths) \ . ale#c#IncludeOptions(l:paths)
\ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -' \ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -'
@@ -23,7 +30,7 @@ endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'g++', \ 'name': 'g++',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#cpp#gcc#GetExecutable', \ 'executable': 'g++',
\ 'command_callback': 'ale_linters#cpp#gcc#GetCommand', \ 'command_callback': 'ale_linters#cpp#gcc#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\}) \})

View File

@@ -4,21 +4,31 @@
function! ale_linters#crystal#crystal#Handle(buffer, lines) abort function! ale_linters#crystal#crystal#Handle(buffer, lines) abort
let l:output = [] let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, []) let l:lines = join(a:lines, '')
if !empty(l:lines)
let l:errors = json_decode(l:lines)
for l:error in l:errors
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:error.line + 0, \ 'lnum': l:error.line + 0,
\ 'col': l:error.column + 0, \ 'col': l:error.column + 0,
\ 'text': l:error.message, \ 'text': l:error.message,
\ 'type': 'E',
\}) \})
endfor endfor
endif
return l:output return l:output
endfunction endfunction
function! ale_linters#crystal#crystal#GetCommand(buffer) abort function! ale_linters#crystal#crystal#GetCommand(buffer) abort
return 'crystal build -f json --no-codegen --no-color -o ' let l:crystal_cmd = 'crystal build -f json --no-codegen --no-color -o '
\ . ale#Escape(g:ale#util#nul_file) let l:crystal_cmd .= ale#Escape(g:ale#util#nul_file)
\ . ' %s' let l:crystal_cmd .= ' %s'
return l:crystal_cmd
endfunction endfunction
call ale#linter#Define('crystal', { call ale#linter#Define('crystal', {

View File

@@ -60,7 +60,7 @@ function! ale_linters#d#dmd#Handle(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[1], \ 'lnum': l:match[1],
\ 'col': l:match[2], \ 'col': l:match[2],
\ 'type': l:match[3] is# 'Warning' ? 'W' : 'E', \ 'type': l:match[3] ==# 'Warning' ? 'W' : 'E',
\ 'text': l:match[4], \ 'text': l:match[4],
\}) \})
endfor endfor

View File

@@ -1,40 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Check Dart files with dartanalyzer
call ale#Set('dart_dartanalyzer_executable', 'dartanalyzer')
function! ale_linters#dart#dartanalyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'dart_dartanalyzer_executable')
endfunction
function! ale_linters#dart#dartanalyzer#GetCommand(buffer) abort
let l:executable = ale_linters#dart#dartanalyzer#GetExecutable(a:buffer)
let l:path = ale#path#FindNearestFile(a:buffer, '.packages')
return ale#Escape(l:executable)
\ . (!empty(l:path) ? ' --packages ' . ale#Escape(l:path) : '')
\ . ' %t'
endfunction
function! ale_linters#dart#dartanalyzer#Handle(buffer, lines) abort
let l:pattern = '\v^ ([a-z]+) . (.+) at (.+):(\d+):(\d+) . (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'text': l:match[6] . ': ' . l:match[2],
\ 'lnum': str2nr(l:match[4]),
\ 'col': str2nr(l:match[5]),
\})
endfor
return l:output
endfunction
call ale#linter#Define('dart', {
\ 'name': 'dartanalyzer',
\ 'executable_callback': 'ale_linters#dart#dartanalyzer#GetExecutable',
\ 'command_callback': 'ale_linters#dart#dartanalyzer#GetCommand',
\ 'callback': 'ale_linters#dart#dartanalyzer#Handle',
\})

View File

@@ -1,9 +1,5 @@
" Author: hauleth - https://github.com/hauleth " Author: hauleth - https://github.com/hauleth
" always, yes, never
call ale#Set('dockerfile_hadolint_use_docker', 'never')
call ale#Set('dockerfile_hadolint_docker_image', 'lukasmartinelli/hadolint')
function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
@@ -14,7 +10,7 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:lnum = 0 let l:lnum = 0
if l:match[1] isnot# '' if l:match[1] !=# ''
let l:lnum = l:match[1] + 0 let l:lnum = l:match[1] + 0
endif endif
@@ -33,45 +29,9 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
" This is a little different than the typical 'executable' callback. We want
" to afford the user the chance to say always use docker, never use docker,
" and use docker if the hadolint executable is not present on the system.
"
" In the case of neither docker nor hadolint executables being present, it
" really doesn't matter which we return -- either will have the effect of
" 'nope, can't use this linter!'.
function! ale_linters#dockerfile#hadolint#GetExecutable(buffer) abort
let l:use_docker = ale#Var(a:buffer, 'dockerfile_hadolint_use_docker')
" check for mandatory directives
if l:use_docker is# 'never'
return 'hadolint'
elseif l:use_docker is# 'always'
return 'docker'
endif
" if we reach here, we want to use 'hadolint' if present...
if executable('hadolint')
return 'hadolint'
endif
"... and 'docker' as a fallback.
return 'docker'
endfunction
function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort
let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer)
if l:command is# 'docker'
return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image')
endif
return 'hadolint -'
endfunction
call ale#linter#Define('dockerfile', { call ale#linter#Define('dockerfile', {
\ 'name': 'hadolint', \ 'name': 'hadolint',
\ 'executable_callback': 'ale_linters#dockerfile#hadolint#GetExecutable', \ 'executable': 'hadolint',
\ 'command_callback': 'ale_linters#dockerfile#hadolint#GetCommand', \ 'command': 'hadolint -',
\ 'callback': 'ale_linters#dockerfile#hadolint#Handle', \ 'callback': 'ale_linters#dockerfile#hadolint#Handle',
\}) \})

View File

@@ -11,9 +11,9 @@ function! ale_linters#elixir#credo#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]
if l:type is# 'C' if l:type ==# 'C'
let l:type = 'E' let l:type = 'E'
elseif l:type is# 'R' elseif l:type ==# 'R'
let l:type = 'W' let l:type = 'W'
endif endif

View File

@@ -11,9 +11,9 @@ function! ale_linters#elixir#dogma#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]
if l:type is# 'C' if l:type ==# 'C'
let l:type = 'E' let l:type = 'E'
elseif l:type is# 'R' elseif l:type ==# 'R'
let l:type = 'W' let l:type = 'W'
endif endif

View File

@@ -7,31 +7,29 @@ function! ale_linters#elm#make#Handle(buffer, lines) abort
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
let l:unparsed_lines = [] let l:unparsed_lines = []
for l:line in a:lines for l:line in a:lines
if l:line[0] is# '[' if l:line[0] ==# '['
let l:errors = json_decode(l:line) let l:errors = json_decode(l:line)
for l:error in l:errors for l:error in l:errors
" Check if file is from the temp directory. " Check if file is from the temp directory.
" Filters out any errors not related to the buffer. " Filters out any errors not related to the buffer.
if l:is_windows if l:is_windows
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is? l:temp_dir let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==? l:temp_dir
else else
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is# l:temp_dir let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==# l:temp_dir
endif endif
if l:file_is_buffer if l:file_is_buffer
call add(l:output, { call add(l:output, {
\ 'lnum': l:error.region.start.line, \ 'lnum': l:error.region.start.line,
\ 'col': l:error.region.start.column, \ 'col': l:error.region.start.column,
\ 'end_lnum': l:error.region.end.line, \ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
\ 'end_col': l:error.region.end.column,
\ 'type': (l:error.type is? 'error') ? 'E' : 'W',
\ 'text': l:error.overview, \ 'text': l:error.overview,
\ 'detail': l:error.overview . "\n\n" . l:error.details \ 'detail': l:error.overview . "\n\n" . l:error.details
\}) \})
endif endif
endfor endfor
elseif l:line isnot# 'Successfully generated /dev/null' elseif l:line !=# 'Successfully generated /dev/null'
call add(l:unparsed_lines, l:line) call add(l:unparsed_lines, l:line)
endif endif
endfor endfor

View File

@@ -27,7 +27,7 @@ function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
let l:pattern_no_module_definition = '\v(no module definition)$' let l:pattern_no_module_definition = '\v(no module definition)$'
let l:pattern_unused = '\v(.* is unused)$' let l:pattern_unused = '\v(.* is unused)$'
let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') is# 'hrl' let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') ==# 'hrl'
for l:line in a:lines for l:line in a:lines
let l:match = matchlist(l:line, l:pattern) let l:match = matchlist(l:line, l:pattern)

View File

@@ -1,53 +0,0 @@
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com>
" Description: SyntaxErl linter for Erlang files
call ale#Set('erlang_syntaxerl_executable', 'syntaxerl')
function! ale_linters#erlang#syntaxerl#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'erlang_syntaxerl_executable')
endfunction
function! ale_linters#erlang#syntaxerl#FeatureCheck(buffer) abort
return s:GetEscapedExecutable(a:buffer) . ' -h'
endfunction
function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output) abort
let l:use_b_option = match(a:output, '\C\V-b, --base\>') > -1
return s:GetEscapedExecutable(a:buffer) . (l:use_b_option ? ' -b %s %t' : ' %t')
endfunction
function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
let l:pattern = '\v\C:(\d+):( warning:)? (.+)'
let l:loclist = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:loclist, {
\ 'lnum': l:match[1] + 0,
\ 'text': l:match[3],
\ 'type': empty(l:match[2]) ? 'E' : 'W',
\})
endfor
return l:loclist
endfunction
function! s:GetEscapedExecutable(buffer) abort
return ale#Escape(ale_linters#erlang#syntaxerl#GetExecutable(a:buffer))
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'syntaxerl',
\ 'executable_callback': 'ale_linters#erlang#syntaxerl#GetExecutable',
\ 'command_chain': [
\ {'callback': 'ale_linters#erlang#syntaxerl#FeatureCheck'},
\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'},
\ ],
\ 'callback': 'ale_linters#erlang#syntaxerl#Handle',
\})

View File

@@ -1,11 +0,0 @@
" Author: Jake Zimmerman <jake@zimmerman.io>
" Description: eruby checker using `erubis`, instead of `erb`
call ale#linter#Define('eruby', {
\ 'name': 'erubis',
\ 'executable': 'erubis',
\ 'output_stream': 'stderr',
\ 'command': 'erubis -x %t | ruby -c',
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
\})

View File

@@ -44,7 +44,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
" Now we have the text, we can set it and add the error. " Now we have the text, we can set it and add the error.
let l:last_loclist_obj.text = l:match[2] let l:last_loclist_obj.text = l:match[2]
let l:last_loclist_obj.type = l:match[1] is# 'Warning' ? 'W' : 'E' let l:last_loclist_obj.type = l:match[1] ==# 'Warning' ? 'W' : 'E'
call add(l:output, l:last_loclist_obj) call add(l:output, l:last_loclist_obj)
else else
let l:last_loclist_obj = { let l:last_loclist_obj = {

View File

@@ -1,22 +1,16 @@
" Author: Ben Reedy <https://github.com/breed808> " Author: Ben Reedy <https://github.com/breed808>
" Description: Adds support for the gometalinter suite for Go files " Description: Adds support for the gometalinter suite for Go files
call ale#Set('go_gometalinter_options', '') if !exists('g:ale_go_gometalinter_options')
call ale#Set('go_gometalinter_executable', 'gometalinter') let g:ale_go_gometalinter_options = ''
endif
function! ale_linters#go#gometalinter#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'go_gometalinter_executable')
endfunction
function! ale_linters#go#gometalinter#GetCommand(buffer) abort function! ale_linters#go#gometalinter#GetCommand(buffer) abort
let l:executable = ale_linters#go#gometalinter#GetExecutable(a:buffer) let l:filename = expand('#' . a:buffer . ':p')
let l:filename = expand('#' . a:buffer)
let l:options = ale#Var(a:buffer, 'go_gometalinter_options')
return ale#Escape(l:executable) return 'gometalinter --include=''^' . l:filename . '.*$'' '
\ . ' --include=' . ale#Escape('^' . ale#util#EscapePCRE(l:filename)) \ . ale#Var(a:buffer, 'go_gometalinter_options')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Escape(fnamemodify(l:filename, ':h'))
endfunction endfunction
function! ale_linters#go#gometalinter#GetMatches(lines) abort function! ale_linters#go#gometalinter#GetMatches(lines) abort
@@ -32,7 +26,7 @@ function! ale_linters#go#gometalinter#Handler(buffer, lines) abort
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'type': tolower(l:match[4]) is# 'warning' ? 'W' : 'E', \ 'type': tolower(l:match[4]) ==# 'warning' ? 'W' : 'E',
\ 'text': l:match[5], \ 'text': l:match[5],
\}) \})
endfor endfor
@@ -42,7 +36,7 @@ endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gometalinter', \ 'name': 'gometalinter',
\ 'executable_callback': 'ale_linters#go#gometalinter#GetExecutable', \ 'executable': 'gometalinter',
\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand', \ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
\ 'callback': 'ale_linters#go#gometalinter#Handler', \ 'callback': 'ale_linters#go#gometalinter#Handler',
\ 'lint_file': 1, \ 'lint_file': 1,

View File

@@ -1,9 +0,0 @@
" Author: Michiel Westerbeek <happylinks@gmail.com>
" Description: Linter for GraphQL Schemas
call ale#linter#Define('graphql', {
\ 'name': 'gqlint',
\ 'executable': 'gqlint',
\ 'command': 'gqlint --reporter=simple %t',
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})

View File

@@ -16,10 +16,16 @@ function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer) abort
endfunction endfunction
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = [] if len(a:lines) == 0
let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) return []
endif
for l:error in get(values(l:json), 0, []) let l:output = []
let l:input_json = json_decode(join(a:lines, ''))
let l:file_errors = values(l:input_json)[0]
for l:error in l:file_errors
if has_key(l:error, 'fatal') if has_key(l:error, 'fatal')
call add(l:output, { call add(l:output, {
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,

View File

@@ -4,13 +4,13 @@
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'ghc-mod', \ 'name': 'ghc-mod',
\ 'executable': 'ghc-mod', \ 'executable': 'ghc-mod',
\ 'command': 'ghc-mod --map-file %s=%t check %s', \ 'command': 'ghc-mod check %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'stack-ghc-mod', \ 'name': 'stack-ghc-mod',
\ 'executable': 'stack', \ 'executable': 'stack',
\ 'command': 'stack exec ghc-mod -- --map-file %s=%t check %s', \ 'command': 'stack exec ghc-mod check %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})

View File

@@ -8,3 +8,11 @@ call ale#linter#Define('haskell', {
\ 'command': 'ghc -fno-code -v0 %t', \ 'command': 'ghc -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})
call ale#linter#Define('haskell', {
\ 'name': 'stack-ghc',
\ 'output_stream': 'stderr',
\ 'executable': 'stack',
\ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})

View File

@@ -1,22 +1,9 @@
" Author: rob-b, Takano Akio <tak@anoak.io> " Author: rob-b
" Description: hdevtools for Haskell files " Description: hdevtools for Haskell files
call ale#Set('haskell_hdevtools_executable', 'hdevtools')
call ale#Set('haskell_hdevtools_options', '-g -Wall')
function! ale_linters#haskell#hdevtools#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'haskell_hdevtools_executable')
endfunction
function! ale_linters#haskell#hdevtools#GetCommand(buffer) abort
return ale#Escape(ale_linters#haskell#hdevtools#GetExecutable(a:buffer))
\ . ' check ' . ale#Var(a:buffer, 'haskell_hdevtools_options')
\ . ' -p %s %t'
endfunction
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'hdevtools', \ 'name': 'hdevtools',
\ 'executable_callback': 'ale_linters#haskell#hdevtools#GetExecutable', \ 'executable': 'hdevtools',
\ 'command_callback': 'ale_linters#haskell#hdevtools#GetCommand', \ 'command': 'hdevtools check -g -Wall -p %s %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})

View File

@@ -2,24 +2,17 @@
" Description: hlint for Haskell files " Description: hlint for Haskell files
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:errors = json_decode(join(a:lines, ''))
let l:output = [] let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, []) for l:error in l:errors
if l:error.severity is# 'Error'
let l:type = 'E'
elseif l:error.severity is# 'Suggestion'
let l:type = 'I'
else
let l:type = 'W'
endif
call add(l:output, { call add(l:output, {
\ 'lnum': str2nr(l:error.startLine), \ 'bufnr': a:buffer,
\ 'col': str2nr(l:error.startColumn), \ 'lnum': l:error.startLine + 0,
\ 'end_lnum': str2nr(l:error.endLine), \ 'col': l:error.startColumn + 0,
\ 'end_col': str2nr(l:error.endColumn),
\ '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:type, \ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@@ -1,22 +0,0 @@
" Author: Jake Zimmerman <jake@zimmerman.io>
" Description: Like stack-ghc, but for entire projects
"
" Note: Ideally, this would *only* typecheck. Right now, it also does codegen.
" See <https://github.com/commercialhaskell/stack/issues/977>.
call ale#Set('haskell_stack_build_options', '--fast')
function ale_linters#haskell#stack_build#GetCommand(buffer) abort
let l:flags = ale#Var(a:buffer, 'haskell_stack_build_options')
return 'stack build ' . l:flags
endfunction
call ale#linter#Define('haskell', {
\ 'name': 'stack-build',
\ 'output_stream': 'stderr',
\ 'executable': 'stack',
\ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand',
\ 'lint_file': 1,
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})

View File

@@ -1,10 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: ghc for Haskell files, using Stack
call ale#linter#Define('haskell', {
\ 'name': 'stack-ghc',
\ 'output_stream': 'stderr',
\ 'executable': 'stack',
\ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})

View File

@@ -46,7 +46,7 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:line = l:match[1] + 0 let l:line = l:match[1] + 0
let l:col = l:match[2] + 0 let l:col = l:match[2] + 0
let l:type = l:match[3] is# 'Error' ? 'E' : 'W' let l:type = l:match[3] ==# 'Error' ? 'E' : 'W'
let l:text = l:match[4] let l:text = l:match[4]
call add(l:output, { call add(l:output, {

View File

@@ -1,87 +0,0 @@
" Author: Scott Bonds <scott@ggr.com>
" Description: default Idris compiler
call ale#Set('idris_idris_executable', 'idris')
call ale#Set('idris_idris_options', '--total --warnpartial --warnreach --warnipkg')
function! ale_linters#idris#idris#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'idris_idris_executable')
endfunction
function! ale_linters#idris#idris#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'idris_idris_options')
return ale#Escape(ale_linters#idris#idris#GetExecutable(a:buffer))
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --check %s'
endfunction
function! ale_linters#idris#idris#Handle(buffer, lines) abort
" This was copied almost verbatim from ale#handlers#haskell#HandleGHCFormat
" Look for lines like the following:
" foo.idr:2:6:When checking right hand side of main with expected type
" bar.idr:11:11-13:
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)(-\d+)?:(.*)?$'
let l:output = []
let l:corrected_lines = []
for l:line in a:lines
if len(matchlist(l:line, l:pattern)) > 0
call add(l:corrected_lines, l:line)
elseif len(l:corrected_lines) > 0
if l:line is# ''
let l:corrected_lines[-1] .= ' ' " turn a blank line into a space
else
let l:corrected_lines[-1] .= l:line
endif
let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g')
endif
endfor
for l:line in l:corrected_lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
if !ale#path#IsBufferPath(a:buffer, l:match[1])
continue
endif
let l:errors = matchlist(l:match[5], '\v([wW]arning|[eE]rror) - ?(.*)')
if len(l:errors) > 0
let l:ghc_type = l:errors[1]
let l:text = l:errors[2]
else
let l:ghc_type = ''
let l:text = l:match[5][:0] is# ' ' ? l:match[5][1:] : l:match[5]
endif
if l:ghc_type is? 'Warning'
let l:type = 'W'
else
let l:type = 'E'
endif
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'text': l:text,
\ 'type': l:type,
\})
endfor
return l:output
endfunction
call ale#linter#Define('idris', {
\ 'name': 'idris',
\ 'executable_callback': 'ale_linters#idris#idris#GetExecutable',
\ 'command_callback': 'ale_linters#idris#idris#GetCommand',
\ 'callback': 'ale_linters#idris#idris#Handle',
\})

View File

@@ -68,14 +68,14 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort
let l:output[-1].col = len(l:match[1]) let l:output[-1].col = len(l:match[1])
elseif empty(l:match[3]) elseif empty(l:match[3])
" Add symbols to 'cannot find symbol' errors. " Add symbols to 'cannot find symbol' errors.
if l:output[-1].text is# 'error: cannot find symbol' if l:output[-1].text ==# 'error: cannot find symbol'
let l:output[-1].text .= ': ' . l:match[2] let l:output[-1].text .= ': ' . l:match[2]
endif endif
else else
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'text': l:match[2] . ':' . l:match[3], \ 'text': l:match[2] . ':' . l:match[3],
\ 'type': l:match[2] is# 'error' ? 'E' : 'W', \ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\}) \})
endif endif
endfor endfor

View File

@@ -40,26 +40,10 @@ function! ale_linters#javascript#flow#GetCommand(buffer, version_lines) abort
\ . ' --json --from ale %s' \ . ' --json --from ale %s'
endfunction endfunction
" Filter lines of flow output until we find the first line where the JSON
" output starts.
function! s:GetJSONLines(lines) abort
let l:start_index = 0
for l:line in a:lines
if l:line[:0] is# '{'
break
endif
let l:start_index += 1
endfor
return a:lines[l:start_index :]
endfunction
function! ale_linters#javascript#flow#Handle(buffer, lines) abort function! ale_linters#javascript#flow#Handle(buffer, lines) abort
let l:str = join(s:GetJSONLines(a:lines), '') let l:str = join(a:lines, '')
if empty(l:str) if l:str ==# ''
return [] return []
endif endif
@@ -77,13 +61,13 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
" In certain cases, `l:message.loc.source` points to a different path " In certain cases, `l:message.loc.source` points to a different path
" than the buffer one, thus we skip this loc information too. " than the buffer one, thus we skip this loc information too.
if has_key(l:message, 'loc') if has_key(l:message, 'loc')
\&& l:line is# 0 \&& l:line ==# 0
\&& ale#path#IsBufferPath(a:buffer, l:message.loc.source) \&& ale#path#IsBufferPath(a:buffer, l:message.loc.source)
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 endif
if l:text is# '' if l:text ==# ''
let l:text = l:message.descr . ':' let l:text = l:message.descr . ':'
else else
let l:text = l:text . ' ' . l:message.descr let l:text = l:text . ' ' . l:message.descr
@@ -98,7 +82,7 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'col': l:col, \ 'col': l:col,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:error.level is# 'error' ? 'E' : 'W', \ 'type': l:error.level ==# 'error' ? 'E' : 'W',
\}) \})
endfor endfor
@@ -113,5 +97,5 @@ call ale#linter#Define('javascript', {
\ {'callback': 'ale_linters#javascript#flow#GetCommand'}, \ {'callback': 'ale_linters#javascript#flow#GetCommand'},
\ ], \ ],
\ 'callback': 'ale_linters#javascript#flow#Handle', \ 'callback': 'ale_linters#javascript#flow#Handle',
\ 'add_newline': !has('win32'), \ 'add_newline': 1,
\}) \})

View File

@@ -1,63 +1,9 @@
" Author: Chris Kyrouac - https://github.com/fijshion " Author: Chris Kyrouac - https://github.com/fijshion
" Description: jscs for JavaScript files " Description: jscs for JavaScript files
call ale#Set('javascript_jscs_executable', 'jscs')
call ale#Set('javascript_jscs_use_global', 0)
function! ale_linters#javascript#jscs#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_jscs', [
\ 'node_modules/.bin/jscs',
\])
endfunction
function! ale_linters#javascript#jscs#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jscs_config = ale#path#ResolveLocalPath(
\ a:buffer,
\ '.jscsrc',
\ get(g:, 'ale_jscs_config_loc', '')
\)
let l:command = ale#Escape(ale_linters#javascript#jscs#GetExecutable(a:buffer))
let l:command .= ' --reporter inline --no-colors'
if !empty(l:jscs_config)
let l:command .= ' --config ' . ale#Escape(l:jscs_config)
endif
let l:command .= ' -'
return l:command
endfunction
function! ale_linters#javascript#jscs#Handle(buffer, lines) abort
" Matches patterns looking like the following
"
" foobar.js: line 2, col 1, Expected indentation of 1 characters
"
let l:pattern = '^.*:\s\+line \(\d\+\),\s\+col\s\+\(\d\+\),\s\+\(.*\)$'
let l:output = []
let l:m = ale#util#GetMatches(a:lines, [l:pattern])
for l:match in l:m
let l:text = l:match[3]
let l:obj = {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3]
\}
call add(l:output, l:obj)
endfor
return l:output
endfunction
call ale#linter#Define('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'jscs', \ 'name': 'jscs',
\ 'executable_callback': 'ale_linters#javascript#jscs#GetExecutable', \ 'executable': 'jscs',
\ 'command_callback': 'ale_linters#javascript#jscs#GetCommand', \ 'command': 'jscs -r unix -n -',
\ 'callback': 'ale_linters#javascript#jscs#Handle', \ 'callback': 'ale#handlers#unix#HandleAsError',
\}) \})

View File

@@ -7,25 +7,13 @@ call ale#Set('javascript_standard_options', '')
function! ale_linters#javascript#standard#GetExecutable(buffer) abort function! ale_linters#javascript#standard#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [ return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
\ 'node_modules/standard/bin/cmd.js',
\ 'node_modules/.bin/standard', \ 'node_modules/.bin/standard',
\]) \])
endfunction endfunction
function! ale_linters#javascript#standard#GetCommand(buffer) abort function! ale_linters#javascript#standard#GetCommand(buffer) abort
let l:executable = ale_linters#javascript#standard#GetExecutable(a:buffer) return ale#Escape(ale_linters#javascript#standard#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'javascript_standard_options')
if ale#Has('win32') && l:executable =~? '\.js$'
" .js files have to be executed with Node on Windows.
let l:head = 'node ' . ale#Escape(l:executable)
else
let l:head = ale#Escape(l:executable)
endif
let l:options = ale#Var(a:buffer, 'javascript_standard_options')
return l:head
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin %s' \ . ' --stdin %s'
endfunction endfunction

View File

@@ -12,21 +12,17 @@ let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_fi
let s:classpath_sep = has('unix') ? ':' : ';' let s:classpath_sep = has('unix') ? ':' : ';'
function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort
" exec maven/gradle only if classpath is not set " exec maven only if classpath is not set
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# '' if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
return '' return ''
else else
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
if !empty(l:pom_path) && executable('mvn') if !empty(l:pom_path) && executable('mvn')
return ale#path#CdString(fnamemodify(l:pom_path, ':h')) return ale#path#CdString(fnamemodify(l:pom_path, ':h'))
\ . 'mvn dependency:build-classpath' \ . 'mvn dependency:build-classpath'
endif endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
if !empty(l:classpath_command)
return l:classpath_command
endif
return '' return ''
endif endif
endfunction endfunction
@@ -70,27 +66,19 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
endif endif
" We only get here if not using module or the module file not readable " We only get here if not using module or the module file not readable
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# '' if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath') let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath')
else else
" get classpath from maven/gradle " get classpath from maven
let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths) let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths)
endif endif
let l:fname = '' let l:fname = ''
if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') isnot# '' if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') !=# ''
let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' ' let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' '
else else
" Find the src directory for files in this project. " Find the src directory for files in this project.
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
if !empty(l:project_root)
let l:src_dir = l:project_root
else
let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java') let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
\ . ' ' . ale#path#FindNearestDirectory(a:buffer, 'src/main/kotlin')
endif
let l:fname .= expand(l:src_dir, 1) . ' ' let l:fname .= expand(l:src_dir, 1) . ' '
endif endif
let l:fname .= ale#Escape(expand('#' . a:buffer . ':p')) let l:fname .= ale#Escape(expand('#' . a:buffer . ':p'))
@@ -121,10 +109,10 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
let l:curbuf_abspath = expand('#' . a:buffer . ':p') let l:curbuf_abspath = expand('#' . a:buffer . ':p')
" Skip if file is not loaded " Skip if file is not loaded
if l:buf_abspath isnot# l:curbuf_abspath if l:buf_abspath !=# l:curbuf_abspath
continue continue
endif endif
let l:type_marker_str = l:type is# 'warning' ? 'W' : 'E' let l:type_marker_str = l:type ==# 'warning' ? 'W' : 'E'
call add(l:output, { call add(l:output, {
\ 'lnum': l:line, \ 'lnum': l:line,
@@ -145,7 +133,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
let l:type = l:match[1] let l:type = l:match[1]
let l:text = l:match[2] let l:text = l:match[2]
let l:type_marker_str = l:type is# 'warning' || l:type is# 'info' ? 'W' : 'E' let l:type_marker_str = l:type ==# 'warning' || l:type ==# 'info' ? 'W' : 'E'
call add(l:output, { call add(l:output, {
\ 'lnum': 1, \ 'lnum': 1,
@@ -167,4 +155,3 @@ call ale#linter#Define('kotlin', {
\ 'callback': 'ale_linters#kotlin#kotlinc#Handle', \ 'callback': 'ale_linters#kotlin#kotlinc#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,
\}) \})

View File

@@ -22,14 +22,14 @@ function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
" "
" artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106 " artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106
" artal.lua:182:7: (W213) unused loop variable 'i' " artal.lua:182:7: (W213) unused loop variable 'i'
let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\(\d\+\)) \(.\+\)$' let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\d\+) \(.\+\)$'
let l:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[3] . l:match[4] . ': ' . l:match[5], \ 'text': l:match[4],
\ 'type': l:match[3], \ 'type': l:match[3],
\}) \})
endfor endfor

View File

@@ -30,7 +30,7 @@ function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Suppress erroneous waring about filename " Suppress erroneous waring about filename
" TODO: Enable this error when copying filename is supported " TODO: Enable this error when copying filename is supported
if l:code is# 'FNDEF' if l:code ==# 'FNDEF'
continue continue
endif endif

View File

@@ -12,7 +12,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
" module names. " module names.
let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t') let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t')
if l:buffer_filename isnot# '' && l:temp_buffer_filename isnot# l:buffer_filename if l:buffer_filename !=# '' && l:temp_buffer_filename !=# l:buffer_filename
continue continue
endif endif
@@ -26,7 +26,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
if len(l:textmatch) > 0 if len(l:textmatch) > 0
let l:errortype = l:textmatch[1] let l:errortype = l:textmatch[1]
if l:errortype is# 'Error' if l:errortype ==# 'Error'
let l:type = 'E' let l:type = 'E'
endif endif
endif endif

View File

@@ -34,7 +34,7 @@ function! ale_linters#perl#perl#Handle(buffer, lines) abort
if ale#path#IsBufferPath(a:buffer, l:match[2]) if ale#path#IsBufferPath(a:buffer, l:match[2])
\ && ( \ && (
\ l:text isnot# 'BEGIN failed--compilation aborted' \ l:text !=# 'BEGIN failed--compilation aborted'
\ || empty(l:output) \ || empty(l:output)
\ || match(l:output[-1].text, s:begin_failed_skip_pattern) < 0 \ || match(l:output[-1].text, s:begin_failed_skip_pattern) < 0
\ ) \ )

View File

@@ -1,54 +1,17 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>, Chris Weyl <cweyl@alumni.drew.edu> " Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl with perl critic " Description: This file adds support for checking perl with perl critic
let g:ale_perl_perlcritic_executable = if !exists('g:ale_perl_perlcritic_showrules')
\ get(g:, 'ale_perl_perlcritic_executable', 'perlcritic') let g:ale_perl_perlcritic_showrules = 0
let g:ale_perl_perlcritic_profile =
\ get(g:, 'ale_perl_perlcritic_profile', '.perlcriticrc')
let g:ale_perl_perlcritic_options =
\ get(g:, 'ale_perl_perlcritic_options', '')
let g:ale_perl_perlcritic_showrules =
\ get(g:, 'ale_perl_perlcritic_showrules', 0)
function! ale_linters#perl#perlcritic#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'perl_perlcritic_executable')
endfunction
function! ale_linters#perl#perlcritic#GetProfile(buffer) abort
" first see if we've been overridden
let l:profile = ale#Var(a:buffer, 'perl_perlcritic_profile')
if l:profile is? ''
return ''
endif endif
" otherwise, iterate upwards to find it
return ale#path#FindNearestFile(a:buffer, l:profile)
endfunction
function! ale_linters#perl#perlcritic#GetCommand(buffer) abort function! ale_linters#perl#perlcritic#GetCommand(buffer) abort
let l:critic_verbosity = '%l:%c %m\n' let l:critic_verbosity = '%l:%c %m\n'
if ale#Var(a:buffer, 'perl_perlcritic_showrules') if g:ale_perl_perlcritic_showrules
let l:critic_verbosity = '%l:%c %m [%p]\n' let l:critic_verbosity = '%l:%c %m [%p]\n'
endif endif
let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer) return "perlcritic --verbose '". l:critic_verbosity . "' --nocolor"
let l:options = ale#Var(a:buffer, 'perl_perlcritic_options')
let l:command = ale#Escape(ale_linters#perl#perlcritic#GetExecutable(a:buffer))
\ . " --verbose '". l:critic_verbosity . "' --nocolor"
if l:profile isnot? ''
let l:command .= ' --profile ' . ale#Escape(l:profile)
endif
if l:options isnot? ''
let l:command .= ' ' . l:options
endif
return l:command
endfunction endfunction
@@ -69,8 +32,8 @@ endfunction
call ale#linter#Define('perl', { call ale#linter#Define('perl', {
\ 'name': 'perlcritic', \ 'name': 'perlcritic',
\ 'executable': 'perlcritic',
\ 'output_stream': 'stdout', \ 'output_stream': 'stdout',
\ 'executable_callback': 'ale_linters#perl#perlcritic#GetExecutable',
\ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand', \ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand',
\ 'callback': 'ale_linters#perl#perlcritic#Handle', \ 'callback': 'ale_linters#perl#perlcritic#Handle',
\}) \})

View File

@@ -1,34 +0,0 @@
" Author: Eric Stern <eric@ericstern.com>
" Description: PHP Language server integration for ALE
call ale#Set('php_langserver_executable', 'php-language-server.php')
call ale#Set('php_langserver_use_global', 0)
function! ale_linters#php#langserver#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'php_langserver', [
\ 'vendor/bin/php-language-server.php',
\])
endfunction
function! ale_linters#php#langserver#GetCommand(buffer) abort
return 'php ' . ale#Escape(ale_linters#php#langserver#GetExecutable(a:buffer))
endfunction
function! ale_linters#php#langserver#GetLanguage(buffer) abort
return 'php'
endfunction
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
call ale#linter#Define('php', {
\ 'name': 'langserver',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
\ 'command_callback': 'ale_linters#php#langserver#GetCommand',
\ 'language_callback': 'ale_linters#php#langserver#GetLanguage',
\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
\})

View File

@@ -40,7 +40,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W', \ 'type': l:type ==# 'error' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@@ -1,46 +0,0 @@
" Author: medains <https://github.com/medains>, ardis <https://github.com/ardisdreelath>
" Description: phpstan for PHP files
" Set to change the ruleset
let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan')
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4')
function! ale_linters#php#phpstan#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'php_phpstan_executable')
endfunction
function! ale_linters#php#phpstan#GetCommand(buffer) abort
let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
return ale#Escape(l:executable)
\ . ' analyze -l'
\ . ale#Var(a:buffer, 'php_phpstan_level')
\ . ' --errorFormat raw'
\ . ' %s'
endfunction
function! ale_linters#php#phpstan#Handle(buffer, lines) abort
" Matches against lines like the following:
"
" filename.php:15:message
" C:\folder\filename.php:15:message
let l:pattern = '^\([a-zA-Z]:\)\?[^:]\+:\(\d\+\):\(.*\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'text': l:match[3],
\ 'type': 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('php', {
\ 'name': 'phpstan',
\ 'executable_callback': 'ale_linters#php#phpstan#GetExecutable',
\ 'command_callback': 'ale_linters#php#phpstan#GetCommand',
\ 'callback': 'ale_linters#php#phpstan#Handle',
\})

View File

@@ -1,48 +1,10 @@
" Author: w0rp - <devw0rp@gmail.com> " Author: w0rp - <devw0rp@gmail.com>
" Description: pug-lint for checking Pug/Jade files. " Description: pug-lint for checking Pug/Jade files.
call ale#Set('pug_puglint_options', '')
call ale#Set('pug_puglint_executable', 'pug-lint')
call ale#Set('pug_puglint_use_global', 0)
function! ale_linters#pug#puglint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'pug_puglint', [
\ 'node_modules/.bin/pug-lint',
\])
endfunction
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.pug-lintrc',
\ '.pug-lintrc.js',
\ '.pug-lintrc.json',
\ 'package.json',
\]
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
if !empty(l:config)
return l:config
endif
endfor
return ''
endfunction
function! ale_linters#pug#puglint#GetCommand(buffer) abort
let l:executable = ale_linters#pug#puglint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'pug_puglint_options')
let l:config = s:FindConfig(a:buffer)
return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' -r inline %t'
endfunction
call ale#linter#Define('pug', { call ale#linter#Define('pug', {
\ 'name': 'puglint', \ 'name': 'puglint',
\ 'executable_callback': 'ale_linters#pug#puglint#GetExecutable', \ 'executable': 'pug-lint',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command_callback': 'ale_linters#pug#puglint#GetCommand', \ 'command': 'pug-lint -r inline %t',
\ 'callback': 'ale#handlers#unix#HandleAsError', \ 'callback': 'ale#handlers#unix#HandleAsError',
\}) \})

View File

@@ -19,8 +19,16 @@ function! s:UsingModule(buffer) abort
endfunction endfunction
function! ale_linters#python#flake8#GetExecutable(buffer) abort function! ale_linters#python#flake8#GetExecutable(buffer) abort
if !s:UsingModule(a:buffer) if !s:UsingModule(a:buffer) && !ale#Var(a:buffer, 'python_flake8_use_global')
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8']) let l:virtualenv = ale#python#FindVirtualenv(a:buffer)
if !empty(l:virtualenv)
let l:ve_flake8 = l:virtualenv . '/bin/flake8'
if executable(l:ve_flake8)
return l:ve_flake8
endif
endif
endif endif
return ale#Var(a:buffer, 'python_flake8_executable') return ale#Var(a:buffer, 'python_flake8_executable')
@@ -83,7 +91,6 @@ function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
return ale#Escape(ale_linters#python#flake8#GetExecutable(a:buffer)) return ale#Escape(ale_linters#python#flake8#GetExecutable(a:buffer))
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --format=default'
\ . l:display_name_args . ' -' \ . l:display_name_args . ' -'
endfunction endfunction
@@ -116,7 +123,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[3] let l:code = l:match[3]
if (l:code is# 'W291' || l:code is# 'W293') if (l:code ==# 'W291' || l:code ==# 'W293')
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
" Skip warnings for trailing whitespace if the option is off. " Skip warnings for trailing whitespace if the option is off.
continue continue
@@ -129,12 +136,12 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
\ 'type': 'W', \ 'type': 'W',
\} \}
if l:code[:0] is# 'F' || l:code is# 'E999' if l:code[:0] ==# 'F' || l:code ==# 'E999'
let l:item.type = 'E' let l:item.type = 'E'
elseif l:code[:0] is# 'E' elseif l:code[:0] ==# 'E'
let l:item.type = 'E' let l:item.type = 'E'
let l:item.sub_type = 'style' let l:item.sub_type = 'style'
elseif l:code[:0] is# 'W' elseif l:code[:0] ==# 'W'
let l:item.sub_type = 'style' let l:item.sub_type = 'style'
endif endif

View File

@@ -7,25 +7,17 @@ let g:ale_python_mypy_options = get(g:, 'ale_python_mypy_options', '')
let g:ale_python_mypy_use_global = get(g:, 'ale_python_mypy_use_global', 0) let g:ale_python_mypy_use_global = get(g:, 'ale_python_mypy_use_global', 0)
function! ale_linters#python#mypy#GetExecutable(buffer) abort function! ale_linters#python#mypy#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy']) return ale#python#FindExecutable(a:buffer, 'python_mypy', ['/bin/mypy'])
endfunction
" The directory to change to before running mypy
function! s:GetDir(buffer) abort
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root)
\ ? l:project_root
\ : expand('#' . a:buffer . ':p:h')
endfunction endfunction
function! ale_linters#python#mypy#GetCommand(buffer) abort function! ale_linters#python#mypy#GetCommand(buffer) abort
let l:dir = s:GetDir(a:buffer) let l:project_root = ale#python#FindProjectRoot(a:buffer)
let l:cd_command = !empty(l:project_root)
\ ? ale#path#CdString(l:project_root)
\ : ''
let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer) let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer)
" We have to always switch to an explicit directory for a command so return l:cd_command
" we can know with certainty the base path for the 'filename' keys below.
return ale#path#CdString(l:dir)
\ . ale#Escape(l:executable) \ . ale#Escape(l:executable)
\ . ' --show-column-numbers ' \ . ' --show-column-numbers '
\ . ale#Var(a:buffer, 'python_mypy_options') \ . ale#Var(a:buffer, 'python_mypy_options')
@@ -33,7 +25,6 @@ function! ale_linters#python#mypy#GetCommand(buffer) abort
endfunction endfunction
function! ale_linters#python#mypy#Handle(buffer, lines) abort function! ale_linters#python#mypy#Handle(buffer, lines) abort
let l:dir = s:GetDir(a:buffer)
" Look for lines like the following: " Look for lines like the following:
" "
" file.py:4: error: No library stub file for module 'django.db' " file.py:4: error: No library stub file for module 'django.db'
@@ -43,13 +34,17 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
" file.py:4: note: (Stub files are from https://github.com/python/typeshed) " file.py:4: note: (Stub files are from https://github.com/python/typeshed)
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$' let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$'
let l:output = [] let l:output = []
let l:buffer_filename = expand('#' . a:buffer . ':p')
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
if l:buffer_filename[-len(l:match[1]):] !=# l:match[1]
continue
endif
call add(l:output, { call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0, \ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'type': l:match[4] =~# 'error' ? 'E' : 'W',
\ 'text': l:match[5], \ 'text': l:match[5],
\}) \})
endfor endfor

View File

@@ -1,42 +0,0 @@
" Author: Michael Thiesen <micthiesen@gmail.com>
" Description: pycodestyle linting for python files
call ale#Set('python_pycodestyle_executable', 'pycodestyle')
call ale#Set('python_pycodestyle_options', '')
call ale#Set('python_pycodestyle_use_global', 0)
function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle'])
endfunction
function! ale_linters#python#pycodestyle#GetCommand(buffer) abort
return ale#Escape(ale_linters#python#pycodestyle#GetExecutable(a:buffer))
\ . ' '
\ . ale#Var(a:buffer, 'python_pycodestyle_options')
\ . ' -'
endfunction
function! ale_linters#python#pycodestyle#Handle(buffer, lines) abort
let l:pattern = '\v^(\S*):(\d*):(\d*): ((([EW])\d+) .*)$'
let l:output = []
" lines are formatted as follows:
" file.py:21:26: W291 trailing whitespace
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[6],
\ 'text': l:match[4],
\})
endfor
return l:output
endfunction
call ale#linter#Define('python', {
\ 'name': 'pycodestyle',
\ 'executable_callback': 'ale_linters#python#pycodestyle#GetExecutable',
\ 'command_callback': 'ale_linters#python#pycodestyle#GetCommand',
\ 'callback': 'ale_linters#python#pycodestyle#Handle',
\})

View File

@@ -10,7 +10,19 @@ let g:ale_python_pylint_options =
let g:ale_python_pylint_use_global = get(g:, 'ale_python_pylint_use_global', 0) let g:ale_python_pylint_use_global = get(g:, 'ale_python_pylint_use_global', 0)
function! ale_linters#python#pylint#GetExecutable(buffer) abort function! ale_linters#python#pylint#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint']) if !ale#Var(a:buffer, 'python_pylint_use_global')
let l:virtualenv = ale#python#FindVirtualenv(a:buffer)
if !empty(l:virtualenv)
let l:ve_pylint = l:virtualenv . '/bin/pylint'
if executable(l:ve_pylint)
return l:ve_pylint
endif
endif
endif
return ale#Var(a:buffer, 'python_pylint_executable')
endfunction endfunction
function! ale_linters#python#pylint#GetCommand(buffer) abort function! ale_linters#python#pylint#GetCommand(buffer) abort
@@ -31,13 +43,13 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
"let l:failed = append(0, l:match) "let l:failed = append(0, l:match)
let l:code = l:match[3] let l:code = l:match[3]
if (l:code is# 'C0303') if (l:code ==# 'C0303')
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
" Skip warnings for trailing whitespace if the option is off. " Skip warnings for trailing whitespace if the option is off.
continue continue
endif endif
if l:code is# 'I0011' if l:code ==# 'I0011'
" Skip 'Locally disabling' message " Skip 'Locally disabling' message
continue continue
endif endif
@@ -46,7 +58,7 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 1, \ 'col': l:match[2] + 1,
\ 'text': l:code . ': ' . l:match[5] . ' (' . l:match[4] . ')', \ 'text': l:code . ': ' . l:match[5] . ' (' . l:match[4] . ')',
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W', \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@@ -1,15 +0,0 @@
" Author: Michel Lang <michellang@gmail.com>, w0rp <devw0rp@gmail.com>
" Description: This file adds support for checking R code with lintr.
function! ale_linters#r#lintr#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . 'Rscript -e ' . ale#Escape('lintr::lint(commandArgs(TRUE))') . ' %t'
endfunction
call ale#linter#Define('r', {
\ 'name': 'lintr',
\ 'executable': 'Rscript',
\ 'command_callback': 'ale_linters#r#lintr#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'output_stream': 'both',
\})

View File

@@ -5,12 +5,17 @@ let g:ale_ruby_brakeman_options =
\ get(g:, 'ale_ruby_brakeman_options', '') \ get(g:, 'ale_ruby_brakeman_options', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
let l:output = [] if len(a:lines) == 0
let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) return []
endif
for l:warning in get(l:json, 'warnings', []) let l:result = json_decode(join(a:lines, ''))
let l:output = []
for l:warning in l:result.warnings
" Brakeman always outputs paths relative to the Rails app root " Brakeman always outputs paths relative to the Rails app root
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) let l:rails_root = s:FindRailsRoot(a:buffer)
let l:warning_file = l:rails_root . '/' . l:warning.file let l:warning_file = l:rails_root . '/' . l:warning.file
if !ale#path#IsBufferPath(a:buffer, l:warning_file) if !ale#path#IsBufferPath(a:buffer, l:warning_file)
@@ -31,9 +36,9 @@ function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
endfunction endfunction
function! ale_linters#ruby#brakeman#GetCommand(buffer) abort function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) let l:rails_root = s:FindRailsRoot(a:buffer)
if l:rails_root is? '' if l:rails_root ==? ''
return '' return ''
endif endif
@@ -42,6 +47,26 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
\ . ' -p ' . ale#Escape(l:rails_root) \ . ' -p ' . ale#Escape(l:rails_root)
endfunction endfunction
function! s:FindRailsRoot(buffer) abort
" Find the nearest dir contining "app", "db", and "config", and assume it is
" the root of a Rails app.
for l:name in ['app', 'config', 'db']
let l:dir = fnamemodify(
\ ale#path#FindNearestDirectory(a:buffer, l:name),
\ ':h:h'
\)
if l:dir !=# '.'
\&& isdirectory(l:dir . '/app')
\&& isdirectory(l:dir . '/config')
\&& isdirectory(l:dir . '/db')
return l:dir
endif
endfor
return ''
endfunction
call ale#linter#Define('ruby', { call ale#linter#Define('ruby', {
\ 'name': 'brakeman', \ 'name': 'brakeman',
\ 'executable': 'brakeman', \ 'executable': 'brakeman',

View File

@@ -1,53 +0,0 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: rails_best_practices, a code metric tool for rails projects
let g:ale_ruby_rails_best_practices_options =
\ get(g:, 'ale_ruby_rails_best_practices_options', '')
function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
let l:output = []
for l:warning in ale#util#FuzzyJSONDecode(a:lines, [])
if !ale#path#IsBufferPath(a:buffer, l:warning.filename)
continue
endif
call add(l:output, {
\ 'lnum': l:warning.line_number + 0,
\ 'type': 'W',
\ 'text': l:warning.message,
\})
endfor
return l:output
endfunction
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
let l:executable = ale#handlers#rails_best_practices#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'bundle$'
\ ? ' exec rails_best_practices'
\ : ''
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
if l:rails_root is? ''
return ''
endif
let l:output_file = ale#Has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = ale#Has('win32') ? '; type %t' : ''
return ale#Escape(l:executable) . l:exec_args
\ . ' --silent -f json --output-file ' . l:output_file
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
\ . ale#Escape(l:rails_root)
\ . l:cat_file
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
\ 'executable_callback': 'ale#handlers#rails_best_practices#GetExecutable',
\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
\ 'lint_file': 1,
\})

View File

@@ -1,13 +1,22 @@
" Author: Eddie Lebow https://github.com/elebow " Author: Eddie Lebow https://github.com/elebow
" Description: Reek, a code smell detector for Ruby files " Description: Reek, a code smell detector for Ruby files
call ale#Set('ruby_reek_show_context', 0) let g:ale_ruby_reek_show_context =
call ale#Set('ruby_reek_show_wiki_link', 0) \ get(g:, 'ale_ruby_reek_show_context', 0)
let g:ale_ruby_reek_show_wiki_link =
\ get(g:, 'ale_ruby_reek_show_wiki_link', 0)
function! ale_linters#ruby#reek#Handle(buffer, lines) abort function! ale_linters#ruby#reek#Handle(buffer, lines) abort
if len(a:lines) == 0
return []
endif
let l:errors = json_decode(a:lines[0])
let l:output = [] let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, []) for l:error in l:errors
for l:location in l:error.lines for l:location in l:error.lines
call add(l:output, { call add(l:output, {
\ 'lnum': l:location, \ 'lnum': l:location,

View File

@@ -1,5 +1,5 @@
" Author: ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow " Author: ynonp - https://github.com/ynonp
" Description: RuboCop, a code style analyzer for Ruby files " Description: rubocop for Ruby files
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer) let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
@@ -8,50 +8,34 @@ function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
\ : '' \ : ''
return ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args
\ . ' --format json --force-exclusion ' \ . ' --format emacs --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options') \ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin ' . bufname(a:buffer)
endfunction endfunction
function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
try " Matches patterns line the following:
let l:errors = json_decode(a:lines[0]) "
catch " <path>:83:29: C: Prefer single-quoted strings when you don't
return [] " need string interpolation or special symbols.
endtry let l:pattern = '\v:(\d+):(\d+): (.): (.+)'
if !has_key(l:errors, 'summary')
\|| l:errors['summary']['offense_count'] == 0
\|| empty(l:errors['files'])
return []
endif
let l:output = [] let l:output = []
for l:error in l:errors['files'][0]['offenses'] for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:start_col = l:error['location']['column'] + 0 let l:text = l:match[4]
let l:type = l:match[3]
call add(l:output, { call add(l:output, {
\ 'lnum': l:error['location']['line'] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:start_col, \ 'col': l:match[2] + 0,
\ 'end_col': l:start_col + l:error['location']['length'] - 1, \ 'text': l:text,
\ 'text': printf('%s [%s]', l:error['message'], l:error['cop_name']), \ 'type': index(['F', 'E'], l:type) != -1 ? 'E' : 'W',
\ 'type': ale_linters#ruby#rubocop#GetType(l:error['severity']),
\}) \})
endfor endfor
return l:output return l:output
endfunction endfunction
function! ale_linters#ruby#rubocop#GetType(severity) abort
if a:severity is? 'convention'
\|| a:severity is? 'warning'
\|| a:severity is? 'refactor'
return 'W'
endif
return 'E'
endfunction
call ale#linter#Define('ruby', { call ale#linter#Define('ruby', {
\ 'name': 'rubocop', \ 'name': 'rubocop',
\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable', \ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',

View File

@@ -4,7 +4,7 @@
let g:ale_rust_cargo_use_check = get(g:, 'ale_rust_cargo_use_check', 0) let g:ale_rust_cargo_use_check = get(g:, 'ale_rust_cargo_use_check', 0)
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# '' if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') !=# ''
return 'cargo' return 'cargo'
else else
" if there is no Cargo.toml file, we don't use cargo even if it exists, " if there is no Cargo.toml file, we don't use cargo even if it exists,

View File

@@ -1,33 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A language server for Rust
call ale#Set('rust_rls_executable', 'rls')
function! ale_linters#rust#rls#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'rust_rls_executable')
endfunction
function! ale_linters#rust#rls#GetCommand(buffer) abort
let l:executable = ale_linters#rust#rls#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' +nightly'
endfunction
function! ale_linters#rust#rls#GetLanguage(buffer) abort
return 'rust'
endfunction
function! ale_linters#rust#rls#GetProjectRoot(buffer) abort
let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : ''
endfunction
call ale#linter#Define('rust', {
\ 'name': 'rls',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#rust#rls#GetExecutable',
\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
\ 'language_callback': 'ale_linters#rust#rls#GetLanguage',
\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
\})

View File

@@ -7,7 +7,7 @@ function! ale_linters#rust#rustc#RustcCommand(buffer_number) abort
" <project root>/target/release/deps/ " <project root>/target/release/deps/
let l:cargo_file = ale#path#FindNearestFile(a:buffer_number, 'Cargo.toml') let l:cargo_file = ale#path#FindNearestFile(a:buffer_number, 'Cargo.toml')
if l:cargo_file isnot# '' if l:cargo_file !=# ''
let l:project_root = fnamemodify(l:cargo_file, ':h') let l:project_root = fnamemodify(l:cargo_file, ':h')
let l:dependencies = '-L ' . l:project_root . '/target/debug/deps -L ' . let l:dependencies = '-L ' . l:project_root . '/target/debug/deps -L ' .
\ l:project_root . '/target/release/deps' \ l:project_root . '/target/release/deps'

View File

@@ -1,26 +1,6 @@
" Author: Zoltan Kalmar - https://github.com/kalmiz, " Author: Zoltan Kalmar - https://github.com/kalmiz
" w0rp <devw0rp@gmail.com>
" Description: Basic scala support using scalac " Description: Basic scala support using scalac
function! ale_linters#scala#scalac#GetExecutable(buffer) abort
if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
" Don't check sbt files with scalac.
return ''
endif
return 'scalac'
endfunction
function! ale_linters#scala#scalac#GetCommand(buffer) abort
let l:executable = ale_linters#scala#scalac#GetExecutable(a:buffer)
if empty(l:executable)
return ''
endif
return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
endfunction
function! ale_linters#scala#scalac#Handle(buffer, lines) abort function! ale_linters#scala#scalac#Handle(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
@@ -38,7 +18,7 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) abort
endif endif
let l:text = l:match[3] let l:text = l:match[3]
let l:type = l:match[2] is# '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)
@@ -58,8 +38,8 @@ endfunction
call ale#linter#Define('scala', { call ale#linter#Define('scala', {
\ 'name': 'scalac', \ 'name': 'scalac',
\ 'executable_callback': 'ale_linters#scala#scalac#GetExecutable', \ 'executable': 'scalac',
\ 'command_callback': 'ale_linters#scala#scalac#GetCommand',
\ 'callback': 'ale_linters#scala#scalac#Handle',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command': 'scalac -Ystop-after:parser %t',
\ 'callback': 'ale_linters#scala#scalac#Handle',
\}) \})

View File

@@ -1,83 +0,0 @@
" Author: Kevin Kays - https://github.com/okkays
" Description: Support for the scalastyle checker.
let g:ale_scala_scalastyle_options =
\ get(g:, 'ale_scala_scalastyle_options', '')
let g:ale_scalastyle_config_loc =
\ get(g:, 'ale_scalastyle_config_loc', '')
function! ale_linters#scala#scalastyle#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" warning file=/home/blurble/Doop.scala message=Missing or badly formed ScalaDoc: Extra @param foobles line=190
let l:patterns = [
\ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\)$',
\ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\) column=\(\d\+\)$',
\]
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:patterns)
let l:args = {
\ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] =~? 'error' ? 'E' : 'W',
\ 'text': l:match[2]
\}
if !empty(l:match[4])
let l:args['col'] = l:match[4] + 1
endif
call add(l:output, l:args)
endfor
return l:output
endfunction
function! ale_linters#scala#scalastyle#GetCommand(buffer) abort
" Search for scalastyle config in parent directories.
let l:scalastyle_config = ''
let l:potential_configs = [
\ 'scalastyle_config.xml',
\ 'scalastyle-config.xml'
\]
for l:config in l:potential_configs
let l:scalastyle_config = ale#path#ResolveLocalPath(
\ a:buffer,
\ l:config,
\ ''
\)
if !empty(l:scalastyle_config)
break
endif
endfor
" If all else fails, try the global config.
if empty(l:scalastyle_config)
let l:scalastyle_config = get(g:, 'ale_scalastyle_config_loc', '')
endif
" Build the command using the config file and additional options.
let l:command = 'scalastyle'
if !empty(l:scalastyle_config)
let l:command .= ' --config ' . ale#Escape(l:scalastyle_config)
endif
if !empty(g:ale_scala_scalastyle_options)
let l:command .= ' ' . g:ale_scala_scalastyle_options
endif
let l:command .= ' %t'
return l:command
endfunction
call ale#linter#Define('scala', {
\ 'name': 'scalastyle',
\ 'executable': 'scalastyle',
\ 'output_stream': 'stdout',
\ 'command_callback': 'ale_linters#scala#scalastyle#GetCommand',
\ 'callback': 'ale_linters#scala#scalastyle#Handle',
\})

View File

@@ -19,7 +19,7 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:match[4], \ 'text': l:match[4],
\ 'type': l:match[3] is# 'E' ? 'E' : 'W', \ 'type': l:match[3] ==# 'E' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@@ -11,7 +11,7 @@ endif
if !exists('g:ale_sh_shell_default_shell') if !exists('g:ale_sh_shell_default_shell')
let g:ale_sh_shell_default_shell = fnamemodify($SHELL, ':t') let g:ale_sh_shell_default_shell = fnamemodify($SHELL, ':t')
if g:ale_sh_shell_default_shell is# '' || g:ale_sh_shell_default_shell is# 'fish' if g:ale_sh_shell_default_shell ==# '' || g:ale_sh_shell_default_shell ==# 'fish'
let g:ale_sh_shell_default_shell = 'bash' let g:ale_sh_shell_default_shell = 'bash'
endif endif
endif endif

View File

@@ -29,7 +29,7 @@ function! ale_linters#sml#smlnj#Handle(buffer, lines) abort
\ 'bufnr': a:buffer, \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'text': l:match[2] . ': ' . l:match[3], \ 'text': l:match[2] . ': ' . l:match[3],
\ 'type': l:match[2] is# 'error' ? 'E' : 'W', \ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\}) \})
continue continue
endif endif

View File

@@ -1,24 +0,0 @@
" Author: diartyz <diartyz@gmail.com>, w0rp <devw0rp@gmail.com>
call ale#Set('stylus_stylelint_executable', 'stylelint')
call ale#Set('stylus_stylelint_options', '')
call ale#Set('stylus_stylelint_use_global', 0)
function! ale_linters#stylus#stylelint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'stylus_stylelint', [
\ 'node_modules/.bin/stylelint',
\])
endfunction
function! ale_linters#stylus#stylelint#GetCommand(buffer) abort
return ale_linters#stylus#stylelint#GetExecutable(a:buffer)
\ . ' ' . ale#Var(a:buffer, 'stylus_stylelint_options')
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('stylus', {
\ 'name': 'stylelint',
\ 'executable_callback': 'ale_linters#stylus#stylelint#GetExecutable',
\ 'command_callback': 'ale_linters#stylus#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})

View File

@@ -1,46 +0,0 @@
" Author: Nick James <github@nsjuk.xyz>
" Description: nagelfar linter for tcl files
call ale#Set('tcl_nagelfar_executable', 'nagelfar.tcl')
call ale#Set('tcl_nagelfar_options', '')
function! ale_linters#tcl#nagelfar#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'tcl_nagelfar_executable')
endfunction
function! ale_linters#tcl#nagelfar#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'tcl_nagelfar_options')
return ale#Escape(ale_linters#tcl#nagelfar#GetExecutable(a:buffer))
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %s'
endfunction
function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
" Matches patterns like the following:
" Line 5: W Found constant "bepa" which is also a variable.
" Line 13: E Wrong number of arguments (3) to "set"
" Line 93: N Close brace not aligned with line 90 (4 0)
let l:pattern = '^Line\s\+\([0-9]\+\): \([NEW]\) \(.*\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'type': l:match[2] is# 'N' ? 'W' : l:match[2],
\ 'text': l:match[3],
\})
endfor
return l:output
endfunction
call ale#linter#Define('tcl', {
\ 'name': 'nagelfar',
\ 'output_stream': 'stdout',
\ 'executable_callback': 'ale_linters#tcl#nagelfar#GetExecutable',
\ 'command_callback': 'ale_linters#tcl#nagelfar#GetCommand',
\ 'callback': 'ale_linters#tcl#nagelfar#Handle',
\ 'lint_file': 1,
\})

View File

@@ -12,27 +12,25 @@ function! ale_linters#typescript#tslint#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
let l:dir = expand('#' . a:buffer . ':p:h')
let l:output = [] let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, []) for l:error in json_decode(join(a:lines, ''))
if ale#path#IsBufferPath(a:buffer, l:error.name)
call add(l:output, { call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:error.name), \ 'type': (get(l:error, 'ruleSeverity', '') ==# 'WARNING' ? 'W' : 'E'),
\ 'type': (get(l:error, 'ruleSeverity', '') is# 'WARNING' ? 'W' : 'E'), \ 'text': l:error.failure,
\ 'text': has_key(l:error, 'ruleName')
\ ? l:error.ruleName . ': ' . l:error.failure
\ : l:error.failure,
\ 'lnum': l:error.startPosition.line + 1, \ 'lnum': l:error.startPosition.line + 1,
\ 'col': l:error.startPosition.character + 1, \ 'col': l:error.startPosition.character + 1,
\ 'end_lnum': l:error.endPosition.line + 1, \ 'end_lnum': l:error.endPosition.line + 1,
\ 'end_col': l:error.endPosition.character + 1, \ 'end_col': l:error.endPosition.character + 1,
\}) \})
endif
endfor endfor
return l:output return l:output
endfunction endfunction
function! ale_linters#typescript#tslint#GetCommand(buffer) abort function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort
let l:tslint_config_path = ale#path#ResolveLocalPath( let l:tslint_config_path = ale#path#ResolveLocalPath(
\ a:buffer, \ a:buffer,
\ 'tslint.json', \ 'tslint.json',
@@ -43,8 +41,7 @@ function! ale_linters#typescript#tslint#GetCommand(buffer) abort
\ ? ' -c ' . ale#Escape(l:tslint_config_path) \ ? ' -c ' . ale#Escape(l:tslint_config_path)
\ : '' \ : ''
return ale#path#BufferCdString(a:buffer) return ale_linters#typescript#tslint#GetExecutable(a:buffer)
\ . ale_linters#typescript#tslint#GetExecutable(a:buffer)
\ . ' --format json' \ . ' --format json'
\ . l:tslint_config_option \ . l:tslint_config_option
\ . ' %t' \ . ' %t'
@@ -53,6 +50,6 @@ endfunction
call ale#linter#Define('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'tslint', \ 'name': 'tslint',
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable', \ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable',
\ 'command_callback': 'ale_linters#typescript#tslint#GetCommand', \ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
\ 'callback': 'ale_linters#typescript#tslint#Handle', \ 'callback': 'ale_linters#typescript#tslint#Handle',
\}) \})

View File

@@ -5,26 +5,19 @@ call ale#Set('typescript_tsserver_executable', 'tsserver')
call ale#Set('typescript_tsserver_config_path', '') call ale#Set('typescript_tsserver_config_path', '')
call ale#Set('typescript_tsserver_use_global', 0) call ale#Set('typescript_tsserver_use_global', 0)
" These functions need to be defined just to comply with the API for LSP.
function! ale_linters#typescript#tsserver#GetProjectRoot(buffer) abort
return ''
endfunction
function! ale_linters#typescript#tsserver#GetLanguage(buffer) abort
return ''
endfunction
function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [ return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [
\ 'node_modules/.bin/tsserver', \ 'node_modules/.bin/tsserver',
\]) \])
endfunction endfunction
function! ale_linters#typescript#tsserver#Handle(buffer, lines) abort
return a:lines
endfunction
call ale#linter#Define('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'tsserver', \ 'name': 'tsserver',
\ 'lsp': 'tsserver', \ 'lsp': 'tsserver',
\ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable', \ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable',
\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable', \ 'callback': 'ale_linters#typescript#tsserver#Handle',
\ 'project_root_callback': 'ale_linters#typescript#tsserver#GetProjectRoot',
\ 'language_callback': 'ale_linters#typescript#tsserver#GetLanguage',
\}) \})

View File

@@ -14,7 +14,7 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:line = l:match[1] + 0 let l:line = l:match[1] + 0
let l:type = l:match[2] =~# 'error' ? 'E' : 'W' let l:type = l:match[2] =~# 'error' ? 'E' : 'W'
let l:text = l:match[2] is# 'syntax error' ? 'syntax error' : l:match[4] let l:text = l:match[2] ==# 'syntax error' ? 'syntax error' : l:match[4]
call add(l:output, { call add(l:output, {
\ 'lnum': l:line, \ 'lnum': l:line,

View File

@@ -1,22 +1,14 @@
" 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
" Set this option to change Verilator lint options
if !exists('g:ale_verilog_verilator_options')
let g:ale_verilog_verilator_options = ''
endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = tempname() . '_verilator_linted.v' let l:filename = tempname() . '_verilator_linted.v'
" Create a special filename, so we can detect it in the handler. " Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename) call ale#engine#ManageFile(a:buffer, l:filename)
let l:lines = getbufline(a:buffer, 1, '$') call writefile(getbufline(a:buffer, 1, '$'), l:filename)
call ale#util#Writefile(a:buffer, l:lines, l:filename)
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' . ale#Escape(l:filename)
\ . ale#Var(a:buffer, 'verilog_verilator_options') .' '
\ . ale#Escape(l:filename)
endfunction endfunction
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
@@ -33,7 +25,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:line = l:match[3] + 0 let l:line = l:match[3] + 0
let l:type = l:match[1] is# 'Error' ? 'E' : 'W' let l:type = l:match[1] ==# 'Error' ? 'E' : 'W'
let l:text = l:match[4] let l:text = l:match[4]
let l:file = l:match[2] let l:file = l:match[2]

View File

@@ -36,32 +36,6 @@ function! ale_linters#vim#vint#GetCommand(buffer, version_output) abort
\ . ' %t' \ . ' %t'
endfunction endfunction
let s:word_regex_list = [
\ '\v^Undefined variable: ([^ ]+)',
\ '\v^Make the scope explicit like ...([^ ]+). ',
\ '\v^.*start with a capital or contain a colon: ([^ ]+)',
\ '\v.*instead of .(\=[=~]).',
\]
function! ale_linters#vim#vint#Handle(buffer, lines) abort
let l:loclist = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
for l:item in l:loclist
let l:match = []
for l:regex in s:word_regex_list
let l:match = matchlist(l:item.text, l:regex)
if !empty(l:match)
let l:item.end_col = l:item.col + len(l:match[1]) - 1
break
endif
endfor
endfor
return l:loclist
endfunction
call ale#linter#Define('vim', { call ale#linter#Define('vim', {
\ 'name': 'vint', \ 'name': 'vint',
\ 'executable': 'vint', \ 'executable': 'vint',
@@ -69,5 +43,5 @@ call ale#linter#Define('vim', {
\ {'callback': 'ale_linters#vim#vint#VersionCommand', 'output_stream': 'stderr'}, \ {'callback': 'ale_linters#vim#vint#VersionCommand', 'output_stream': 'stderr'},
\ {'callback': 'ale_linters#vim#vint#GetCommand', 'output_stream': 'stdout'}, \ {'callback': 'ale_linters#vim#vint#GetCommand', 'output_stream': 'stdout'},
\ ], \ ],
\ 'callback': 'ale_linters#vim#vint#Handle', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\}) \})

View File

@@ -1,41 +0,0 @@
" Author: Matthew Turland <https://github.com/elazar>
" Description: This file adds support for linting Swagger / OpenAPI documents using swaglint
call ale#Set('yaml_swaglint_executable', 'swaglint')
call ale#Set('yaml_swaglint_use_global', 0)
function! ale_linters#yaml#swaglint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'yaml_swaglint', [
\ 'node_modules/.bin/swaglint',
\])
endfunction
function! ale_linters#yaml#swaglint#GetCommand(buffer) abort
return ale_linters#yaml#swaglint#GetExecutable(a:buffer)
\ . ' -r compact --stdin'
endfunction
function! ale_linters#yaml#swaglint#Handle(buffer, lines) abort
let l:pattern = ': \([^\s]\+\) @ \(\d\+\):\(\d\+\) - \(.\+\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:obj = {
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[4],
\}
call add(l:output, l:obj)
endfor
return l:output
endfunction
call ale#linter#Define('yaml', {
\ 'name': 'swaglint',
\ 'executable_callback': 'ale_linters#yaml#swaglint#GetExecutable',
\ 'command_callback': 'ale_linters#yaml#swaglint#GetCommand',
\ 'callback': 'ale_linters#yaml#swaglint#Handle',
\})

View File

@@ -33,7 +33,7 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'col': l:col, \ 'col': l:col,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W', \ 'type': l:type ==# 'error' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@@ -5,31 +5,6 @@
let s:lint_timer = -1 let s:lint_timer = -1
let s:queued_buffer_number = -1 let s:queued_buffer_number = -1
let s:should_lint_file_for_buffer = {} let s:should_lint_file_for_buffer = {}
let s:error_delay_ms = 1000 * 60 * 2
let s:timestamp_map = {}
" Given a key for a script variable for tracking the time to wait until
" a given function should be called, a funcref for a function to call, and
" a List of arguments, call the function and return whatever value it returns.
"
" If the function throws an exception, then the function will not be called
" for a while, and 0 will be returned instead.
function! ale#CallWithCooldown(timestamp_key, func, arglist) abort
let l:now = ale#util#ClockMilliseconds()
if l:now < get(s:timestamp_map, a:timestamp_key, -1)
return 0
endif
let s:timestamp_map[a:timestamp_key] = l:now + s:error_delay_ms
let l:return_value = call(a:func, a:arglist)
let s:timestamp_map[a:timestamp_key] = -1
return l:return_value
endfunction
" Return 1 if a file is too large for ALE to handle. " Return 1 if a file is too large for ALE to handle.
function! ale#FileTooLarge() abort function! ale#FileTooLarge() abort
@@ -40,49 +15,36 @@ endfunction
" A function for checking various conditions whereby ALE just shouldn't " A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim. " attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing(buffer) abort function! ale#ShouldDoNothing() abort
" Do nothing for blacklisted files " Do nothing for blacklisted files
" OR if ALE is running in the sandbox " OR if ALE is running in the sandbox
return index(g:ale_filetype_blacklist, &filetype) >= 0 return index(g:ale_filetype_blacklist, &filetype) >= 0
\ || (exists('*getcmdwintype') && !empty(getcmdwintype())) \ || (exists('*getcmdwintype') && !empty(getcmdwintype()))
\ || ale#util#InSandbox() \ || ale#util#InSandbox()
\ || !ale#Var(a:buffer, 'enabled') \ || !ale#Var(bufnr(''), 'enabled')
\ || ale#FileTooLarge() \ || ale#FileTooLarge()
endfunction endfunction
" (delay, [linting_flag, buffer_number]) " (delay, [linting_flag])
function! ale#Queue(delay, ...) abort function! ale#Queue(delay, ...) abort
if a:0 > 2 if len(a:0) > 1
throw 'too many arguments!' throw 'too many arguments!'
endif endif
" Default linting_flag to '' " Default linting_flag to ''
let l:linting_flag = get(a:000, 0, '') let l:linting_flag = get(a:000, 0, '')
let l:buffer = get(a:000, 1, bufnr(''))
return ale#CallWithCooldown( if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
\ 'dont_queue_until',
\ function('s:ALEQueueImpl'),
\ [a:delay, l:linting_flag, l:buffer],
\)
endfunction
function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
if a:linting_flag isnot# '' && a:linting_flag isnot# 'lint_file'
throw "linting_flag must be either '' or 'lint_file'" throw "linting_flag must be either '' or 'lint_file'"
endif endif
if type(a:buffer) != type(0) if ale#ShouldDoNothing()
throw 'buffer_number must be a Number'
endif
if ale#ShouldDoNothing(a:buffer)
return return
endif endif
" Remember that we want to check files for this buffer. " Remember that we want to check files for this buffer.
" We will remember this until we finally run the linters, via any event. " We will remember this until we finally run the linters, via any event.
if a:linting_flag is# 'lint_file' if l:linting_flag ==# 'lint_file'
let s:should_lint_file_for_buffer[bufnr('%')] = 1 let s:should_lint_file_for_buffer[bufnr('%')] = 1
endif endif
@@ -91,63 +53,63 @@ function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
let s:lint_timer = -1 let s:lint_timer = -1
endif endif
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype')) let l:linters = ale#linter#Get(&filetype)
if len(l:linters) == 0
" Don't set up buffer data and so on if there are no linters to run. " There are no linters to lint with, so stop here.
if empty(l:linters)
" If we have some previous buffer data, then stop any jobs currently
" running and clear everything.
if has_key(g:ale_buffer_info, a:buffer)
call ale#engine#RunLinters(a:buffer, [], 1)
endif
return return
endif endif
if a:delay > 0 if a:delay > 0
let s:queued_buffer_number = a:buffer let s:queued_buffer_number = bufnr('%')
let s:lint_timer = timer_start(a:delay, function('ale#Lint')) let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
else else
call ale#Lint(-1, a:buffer) call ale#Lint()
endif endif
endfunction endfunction
function! ale#Lint(...) abort function! ale#Lint(...) abort
if a:0 > 1 if ale#ShouldDoNothing()
" Use the buffer number given as the optional second argument.
let l:buffer = a:2
elseif a:0 > 0 && a:1 == s:lint_timer
" Use the buffer number for the buffer linting was queued for.
let l:buffer = s:queued_buffer_number
else
" Use the current buffer number.
let l:buffer = bufnr('')
endif
return ale#CallWithCooldown(
\ 'dont_lint_until',
\ function('s:ALELintImpl'),
\ [l:buffer],
\)
endfunction
function! s:ALELintImpl(buffer) abort
if ale#ShouldDoNothing(a:buffer)
return return
endif endif
" Get the buffer number linting was queued for.
" or else take the current one.
let l:buffer = len(a:0) > 1 && a:1 == s:lint_timer
\ ? s:queued_buffer_number
\ : bufnr('%')
" Use the filetype from the buffer " Use the filetype from the buffer
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype')) let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
let l:should_lint_file = 0 let l:should_lint_file = 0
" Check if we previously requested checking the file. " Check if we previously requested checking the file.
if has_key(s:should_lint_file_for_buffer, a:buffer) if has_key(s:should_lint_file_for_buffer, l:buffer)
unlet s:should_lint_file_for_buffer[a:buffer] unlet s:should_lint_file_for_buffer[l:buffer]
" Lint files if they exist. " Lint files if they exist.
let l:should_lint_file = filereadable(expand('#' . a:buffer . ':p')) let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
endif endif
call ale#engine#RunLinters(a:buffer, l:linters, l:should_lint_file) " Initialise the buffer information if needed.
call ale#engine#InitBufferInfo(l:buffer)
" Clear the new loclist again, so we will work with all new items.
let g:ale_buffer_info[l:buffer].new_loclist = []
if l:should_lint_file
" Clear loclist items for files if we are checking files again.
let g:ale_buffer_info[l:buffer].lint_file_loclist = []
else
" Otherwise, don't run any `lint_file` linters
" We will continue running any linters which are currently checking
" the file, and the items will be mixed together with any new items.
call filter(l:linters, '!v:val.lint_file')
endif
call ale#engine#StopCurrentJobs(l:buffer, l:should_lint_file)
for l:linter in l:linters
call ale#engine#Invoke(l:buffer, l:linter)
endfor
endfunction endfunction
" Reset flags indicating that files should be checked for all buffers. " Reset flags indicating that files should be checked for all buffers.
@@ -155,10 +117,6 @@ function! ale#ResetLintFileMarkers() abort
let s:should_lint_file_for_buffer = {} let s:should_lint_file_for_buffer = {}
endfunction endfunction
function! ale#ResetErrorDelays() abort
let s:timestamp_map = {}
endfunction
let g:ale_has_override = get(g:, 'ale_has_override', {}) let g:ale_has_override = get(g:, 'ale_has_override', {})
" Call has(), but check a global Dictionary so we can force flags on or off " Call has(), but check a global Dictionary so we can force flags on or off
@@ -201,7 +159,7 @@ endfunction
" Escape a string suitably for each platform. " Escape a string suitably for each platform.
" shellescape does not work on Windows. " shellescape does not work on Windows.
function! ale#Escape(str) abort function! ale#Escape(str) abort
if fnamemodify(&shell, ':t') is? 'cmd.exe' if fnamemodify(&shell, ':t') ==? 'cmd.exe'
" If the string contains spaces, it will be surrounded by quotes. " If the string contains spaces, it will be surrounded by quotes.
" Otherwise, special characters will be escaped with carets (^). " Otherwise, special characters will be escaped with carets (^).
return substitute( return substitute(

View File

@@ -3,7 +3,7 @@
function! ale#balloon#MessageForPos(bufnr, lnum, col) abort function! ale#balloon#MessageForPos(bufnr, lnum, col) abort
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col) let l:index = ale#util#BinarySearch(l:loclist, a:lnum, a:col)
return l:index >= 0 ? l:loclist[l:index].text : '' return l:index >= 0 ? l:loclist[l:index].text : ''
endfunction endfunction

View File

@@ -9,7 +9,7 @@ function! ale#c#FindProjectRoot(buffer) abort
let l:path = fnamemodify(l:full_path, ':h') let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection. " Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git' if fnamemodify(l:path, ':t') ==# '.git'
let l:path = fnamemodify(l:path, ':h') let l:path = fnamemodify(l:path, ':h')
endif endif
@@ -47,7 +47,7 @@ function! ale#c#FindLocalHeaderPaths(buffer) abort
" If we find an 'include' directory in the project root, then use that. " If we find an 'include' directory in the project root, then use that.
if isdirectory(l:project_root . '/include') if isdirectory(l:project_root . '/include')
return [ale#path#Simplify(l:project_root . '/include')] return [simplify(l:project_root . '/include')]
endif endif
return [] return []

19
autoload/ale/cleanup.vim Normal file
View File

@@ -0,0 +1,19 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Utility functions related to cleaning state.
function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_info, a:buffer)
call ale#engine#RemoveManagedFiles(a:buffer)
" When buffers are removed, clear all of the jobs.
call ale#engine#StopCurrentJobs(a:buffer, 1)
" Clear delayed highlights for a buffer being removed.
if g:ale_set_highlights
call ale#highlight#UnqueueHighlights(a:buffer)
call ale#highlight#RemoveHighlights([])
endif
call remove(g:ale_buffer_info, a:buffer)
endif
endfunction

View File

@@ -1,339 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Completion support for LSP linters
let s:timer_id = -1
function! s:GetRegex(map, filetype) abort
for l:part in reverse(split(a:filetype, '\.'))
let l:regex = get(a:map, l:part, [])
if !empty(l:regex)
return l:regex
endif
endfor
return ''
endfunction
" Regular expressions for checking the characters in the line before where
" the insert cursor is. If one of these matches, we'll check for completions.
let s:should_complete_map = {
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
\}
" Check if we should look for completions for a language.
function! ale#completion#GetPrefix(filetype, line, column) abort
let l:regex = s:GetRegex(s:should_complete_map, a:filetype)
" The column we're using completions for is where we are inserting text,
" like so:
" abc
" ^
" So we need check the text in the column before that position.
return matchstr(getline(a:line)[: a:column - 2], l:regex)
endfunction
" Regular expressions for finding the start column to replace with completion.
let s:omni_start_map = {
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
\}
function! ale#completion#Filter(suggestions, prefix) abort
" For completing...
" foo.
" ^
" We need to include all of the given suggestions.
if a:prefix is# '.'
return a:suggestions
endif
let l:filtered_suggestions = []
" Filter suggestions down to those starting with the prefix we used for
" finding suggestions in the first place.
"
" Some completion tools will include suggestions which don't even start
" with the characters we have already typed.
for l:item in a:suggestions
" A List of String values or a List of completion item Dictionaries
" is accepted here.
let l:word = type(l:item) == type('') ? l:item : l:item.word
" Add suggestions if the suggestion starts with a case-insensitive
" match for the prefix.
if l:word[: len(a:prefix) - 1] is? a:prefix
call add(l:filtered_suggestions, l:item)
endif
endfor
return l:filtered_suggestions
endfunction
function! s:ReplaceCompleteopt() abort
if !exists('b:ale_old_completopt')
let b:ale_old_completopt = &l:completeopt
endif
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:line = b:ale_completion_info.line
let l:column = b:ale_completion_info.column
let l:regex = s:GetRegex(s:omni_start_map, &filetype)
let l:up_to_column = getline(l:line)[: l:column - 2]
let l:match = matchstr(l:up_to_column, l:regex)
return l:column - len(l:match) - 1
else
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
call s:ReplaceCompleteopt()
return get(b:, 'ale_completion_result', [])
endif
endfunction
function! ale#completion#Show(response, completion_parser) abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
" Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion.
let b:ale_completion_response = a:response
let b:ale_completion_parser = a:completion_parser
let &l:omnifunc = 'ale#completion#OmniFunc'
call s:ReplaceCompleteopt()
call ale#util#FeedKeys("\<C-x>\<C-o>", 'n')
endfunction
function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getcurpos()[1:2]
return has_key(b:, 'ale_completion_info')
\&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line
\&& b:ale_completion_info.column == l:column
endfunction
function! ale#completion#ParseTSServerCompletions(response) abort
let l:names = []
for l:suggestion in a:response.body
call add(l:names, l:suggestion.name)
endfor
return l:names
endfunction
function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:results = []
for l:suggestion in a:response.body
let l:displayParts = []
for l:part in l:suggestion.displayParts
call add(l:displayParts, l:part.text)
endfor
" Each one of these parts has 'kind' properties
let l:documentationParts = []
for l:part in get(l:suggestion, 'documentation', [])
call add(l:documentationParts, l:part.text)
endfor
if l:suggestion.kind is# 'clasName'
let l:kind = 'f'
elseif l:suggestion.kind is# 'parameterName'
let l:kind = 'f'
else
let l:kind = 'v'
endif
" See :help complete-items
call add(l:results, {
\ 'word': l:suggestion.name,
\ 'kind': l:kind,
\ 'icase': 1,
\ 'menu': join(l:displayParts, ''),
\ 'info': join(l:documentationParts, ''),
\})
endfor
return l:results
endfunction
function! ale#completion#HandleTSServerLSPResponse(conn_id, response) abort
if !s:CompletionStillValid(get(a:response, 'request_seq'))
return
endif
if !has_key(a:response, 'body')
return
endif
let l:command = get(a:response, 'command', '')
if l:command is# 'completions'
let l:names = ale#completion#Filter(
\ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix,
\)[: g:ale_completion_max_suggestions - 1]
if !empty(l:names)
let b:ale_completion_info.request_id = ale#lsp#Send(
\ b:ale_completion_info.conn_id,
\ ale#lsp#tsserver_message#CompletionEntryDetails(
\ bufnr(''),
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ l:names,
\ ),
\)
endif
elseif l:command is# 'completionEntryDetails'
call ale#completion#Show(
\ a:response,
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
\)
endif
endfunction
function! s:GetLSPCompletions(linter) abort
let l:buffer = bufnr('')
let l:lsp_details = ale#linter#StartLSP(
\ l:buffer,
\ a:linter,
\ function('ale#completion#HandleTSServerLSPResponse'),
\)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:command = l:lsp_details.command
let l:root = l:lsp_details.project_root
let l:message = ale#lsp#tsserver_message#Completions(
\ l:buffer,
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ b:ale_completion_info.prefix,
\)
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
if l:request_id
let b:ale_completion_info.conn_id = l:id
let b:ale_completion_info.request_id = l:request_id
endif
endfunction
function! ale#completion#GetCompletions() abort
let [l:line, l:column] = getcurpos()[1:2]
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if empty(l:prefix)
return
endif
let b:ale_completion_info = {
\ 'line': l:line,
\ 'column': l:column,
\ 'prefix': l:prefix,
\ 'conn_id': 0,
\ 'request_id': 0,
\}
for l:linter in ale#linter#Get(&filetype)
if l:linter.lsp is# 'tsserver'
call s:GetLSPCompletions(l:linter)
endif
endfor
endfunction
function! s:TimerHandler(...) abort
let s:timer_id = -1
let [l:line, l:column] = getcurpos()[1:2]
" When running the timer callback, we have to be sure that the cursor
" hasn't moved from where it was when we requested completions by typing.
if s:timer_pos == [l:line, l:column]
call ale#completion#GetCompletions()
endif
endfunction
function! ale#completion#Queue() abort
let s:timer_pos = getcurpos()[1:2]
" If we changed the text again while we're still waiting for a response,
" then invalidate the requests before the timer ticks again.
if exists('b:ale_completion_info')
let b:ale_completion_info.request_id = 0
endif
if s:timer_id != -1
call timer_stop(s:timer_id)
endif
let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler'))
endfunction
function! ale#completion#Done() abort
silent! pclose
" Reset settings when completion is done.
if exists('b:ale_old_omnifunc')
let &l:omnifunc = b:ale_old_omnifunc
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
endif
endfunction
function! s:Setup(enabled) abort
augroup ALECompletionGroup
autocmd!
if a:enabled
autocmd TextChangedI * call ale#completion#Queue()
autocmd CompleteDone * call ale#completion#Done()
endif
augroup END
if !a:enabled
augroup! ALECompletionGroup
endif
endfunction
function! ale#completion#Enable() abort
let g:ale_completion_enabled = 1
call s:Setup(1)
endfunction
function! ale#completion#Disable() abort
let g:ale_completion_enabled = 0
call s:Setup(0)
endfunction

View File

@@ -1,22 +1,10 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Echoes lint message for the current line, if any " Description: Echoes lint message for the current line, if any
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
let s:error_delay_ms = 1000 * 60 * 2
if !exists('s:dont_queue_until')
let s:dont_queue_until = -1
endif
if !exists('s:dont_echo_until')
let s:dont_echo_until = -1
endif
" Return a formatted message according to g:ale_echo_msg_format variable " Return a formatted message according to g:ale_echo_msg_format variable
function! s:GetMessage(linter, type, text) abort function! s:GetMessage(linter, type, text) abort
let l:msg = g:ale_echo_msg_format let l:msg = g:ale_echo_msg_format
let l:type = a:type is# 'E' let l:type = a:type ==# 'E'
\ ? g:ale_echo_msg_error_str \ ? g:ale_echo_msg_error_str
\ : g:ale_echo_msg_warning_str \ : g:ale_echo_msg_warning_str
@@ -34,12 +22,12 @@ function! s:EchoWithShortMess(setting, message) abort
try try
" Turn shortmess on or off. " Turn shortmess on or off.
if a:setting is# 'on' if a:setting ==# 'on'
setlocal shortmess+=T setlocal shortmess+=T
" echomsg is needed for the message to get truncated and appear in " echomsg is neede for the message to get truncated and appear in
" the message history. " the message history.
exec "norm! :echomsg a:message\n" exec "norm! :echomsg a:message\n"
elseif a:setting is# 'off' elseif a:setting ==# 'off'
setlocal shortmess-=T setlocal shortmess-=T
" Regular echo is needed for printing newline characters. " Regular echo is needed for printing newline characters.
echo a:message echo a:message
@@ -62,12 +50,10 @@ function! ale#cursor#TruncatedEcho(message) abort
endfunction endfunction
function! s:FindItemAtCursor() abort function! s:FindItemAtCursor() abort
let l:buf = bufnr('') let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
let l:info = get(g:ale_buffer_info, l:buf, {})
let l:loclist = get(l:info, 'loclist', [])
let l:pos = getcurpos() let l:pos = getcurpos()
let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2]) let l:index = ale#util#BinarySearch(l:info.loclist, l:pos[1], l:pos[2])
let l:loc = l:index >= 0 ? l:loclist[l:index] : {} let l:loc = l:index >= 0 ? l:info.loclist[l:index] : {}
return [l:info, l:loc] return [l:info, l:loc]
endfunction endfunction
@@ -80,16 +66,12 @@ function! s:StopCursorTimer() abort
endfunction endfunction
function! ale#cursor#EchoCursorWarning(...) abort function! ale#cursor#EchoCursorWarning(...) abort
return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), []) if ale#ShouldDoNothing()
endfunction
function! s:EchoImpl() abort
if ale#ShouldDoNothing(bufnr(''))
return return
endif endif
" Only echo the warnings in normal mode, otherwise we will get problems. " Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n' if mode() !=# 'n'
return return
endif endif
@@ -107,16 +89,11 @@ function! s:EchoImpl() abort
endif endif
endfunction endfunction
function! ale#cursor#EchoCursorWarningWithDelay() abort let s:cursor_timer = -1
return ale#CallWithCooldown( let s:last_pos = [0, 0, 0]
\ 'dont_echo_with_delay_until',
\ function('s:EchoWithDelayImpl'),
\ [],
\)
endfunction
function! s:EchoWithDelayImpl() abort function! ale#cursor#EchoCursorWarningWithDelay() abort
if ale#ShouldDoNothing(bufnr('')) if ale#ShouldDoNothing()
return return
endif endif
@@ -135,12 +112,12 @@ function! s:EchoWithDelayImpl() abort
endfunction endfunction
function! ale#cursor#ShowCursorDetail() abort function! ale#cursor#ShowCursorDetail() abort
if ale#ShouldDoNothing(bufnr('')) if ale#ShouldDoNothing()
return return
endif endif
" Only echo the warnings in normal mode, otherwise we will get problems. " Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n' if mode() !=# 'n'
return return
endif endif

View File

@@ -7,8 +7,6 @@ let s:global_variable_list = [
\ 'ale_echo_msg_format', \ 'ale_echo_msg_format',
\ 'ale_echo_msg_warning_str', \ 'ale_echo_msg_warning_str',
\ 'ale_enabled', \ 'ale_enabled',
\ 'ale_fix_on_save',
\ 'ale_fixers',
\ 'ale_keep_list_window_open', \ 'ale_keep_list_window_open',
\ 'ale_lint_delay', \ 'ale_lint_delay',
\ 'ale_lint_on_enter', \ 'ale_lint_on_enter',
@@ -70,19 +68,25 @@ function! s:EchoGlobalVariables() abort
endfor endfor
endfunction endfunction
" Echo a command that was run. function! s:EchoCommandHistory() abort
function! s:EchoCommand(item) abort let l:buffer = bufnr('%')
let l:status_message = a:item.status
" Include the exit code in output if we have it. if !has_key(g:ale_buffer_info, l:buffer)
if a:item.status is# 'finished' return
let l:status_message .= ' - exit code ' . a:item.exit_code
endif endif
echom '(' . l:status_message . ') ' . string(a:item.command) for l:item in g:ale_buffer_info[l:buffer].history
let l:status_message = l:item.status
if g:ale_history_log_output && has_key(a:item, 'output') " Include the exit code in output if we have it.
if empty(a:item.output) 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 ''
echom '<<<NO OUTPUT RETURNED>>>' echom '<<<NO OUTPUT RETURNED>>>'
echom '' echom ''
@@ -90,7 +94,7 @@ function! s:EchoCommand(item) abort
echom '' echom ''
echom '<<<OUTPUT STARTS>>>' echom '<<<OUTPUT STARTS>>>'
for l:line in a:item.output for l:line in l:item.output
echom l:line echom l:line
endfor endfor
@@ -98,26 +102,6 @@ function! s:EchoCommand(item) abort
echom '' echom ''
endif endif
endif endif
endfunction
" Echo the results of an executable check.
function! s:EchoExecutable(item) abort
echom printf(
\ '(executable check - %s) %s',
\ a:item.status ? 'success' : 'failure',
\ a:item.command,
\)
endfunction
function! s:EchoCommandHistory() abort
let l:buffer = bufnr('%')
for l:item in ale#history#Get(l:buffer)
if l:item.job_id is# 'executable'
call s:EchoExecutable(l:item)
else
call s:EchoCommand(l:item)
endif
endfor endfor
endfunction endfunction

View File

@@ -11,67 +11,40 @@ if !has_key(s:, 'job_info_map')
let s:job_info_map = {} let s:job_info_map = {}
endif endif
" Associates LSP connection IDs with linter names.
if !has_key(s:, 'lsp_linter_map')
let s:lsp_linter_map = {}
endif
if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {} let s:executable_cache_map = {}
endif
function! ale#engine#ResetExecutableCache() abort
let s:executable_cache_map = {}
endfunction
" Check if files are executable, and if they are, remember that they are " Check if files are executable, and if they are, remember that they are
" for subsequent calls. We'll keep checking until programs can be executed. " for subsequent calls. We'll keep checking until programs can be executed.
function! ale#engine#IsExecutable(buffer, executable) abort function! s:IsExecutable(executable) abort
if has_key(s:executable_cache_map, a:executable) if has_key(s:executable_cache_map, a:executable)
return 1 return 1
endif endif
let l:result = 0
if executable(a:executable) if executable(a:executable)
let s:executable_cache_map[a:executable] = 1 let s:executable_cache_map[a:executable] = 1
let l:result = 1
endif
if g:ale_history_enabled
call ale#history#Add(a:buffer, l:result, 'executable', a:executable)
endif
return l:result
endfunction
function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" job_list will hold the list of job IDs
" active_linter_list will hold the list of active linter names
" loclist holds the loclist items after all jobs have completed.
" temporary_file_list holds temporary files to be cleaned up
" temporary_directory_list holds temporary directories to be cleaned up
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'active_linter_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
\}
return 1 return 1
endif endif
return 0 return 0
endfunction endfunction
" Return 1 if ALE is busy checking a given buffer function! ale#engine#InitBufferInfo(buffer) abort
function! ale#engine#IsCheckingBuffer(buffer) abort if !has_key(g:ale_buffer_info, a:buffer)
let l:info = get(g:ale_buffer_info, a:buffer, {}) " job_list will hold the list of jobs
" loclist holds the loclist items after all jobs have completed.
return !empty(get(l:info, 'active_linter_list', [])) " temporary_file_list holds temporary files to be cleaned up
" temporary_directory_list holds temporary directories to be cleaned up
" history holds a list of previously run commands for this buffer
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
\ 'history': [],
\ 'open_lsp_documents': [],
\}
endif
endfunction endfunction
" Register a temporary file to be managed with the ALE engine for " Register a temporary file to be managed with the ALE engine for
@@ -97,7 +70,9 @@ function! ale#engine#CreateDirectory(buffer) abort
endfunction endfunction
function! ale#engine#RemoveManagedFiles(buffer) abort function! ale#engine#RemoveManagedFiles(buffer) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) 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 " We can't delete anything in a sandbox, so wait until we escape from
" it to delete temporary files and directories. " it to delete temporary files and directories.
@@ -106,25 +81,21 @@ function! ale#engine#RemoveManagedFiles(buffer) abort
endif endif
" Delete files with a call akin to a plan `rm` command. " Delete files with a call akin to a plan `rm` command.
if has_key(l:info, 'temporary_file_list') for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
for l:filename in l:info.temporary_file_list
call delete(l:filename) call delete(l:filename)
endfor endfor
let l:info.temporary_file_list = [] let g:ale_buffer_info[a:buffer].temporary_file_list = []
endif
" Delete directories like `rm -rf`. " Delete directories like `rm -rf`.
" Directories are handled differently from files, so paths that are " Directories are handled differently from files, so paths that are
" intended to be single files can be set up for automatic deletion without " intended to be single files can be set up for automatic deletion without
" accidentally deleting entire directories. " accidentally deleting entire directories.
if has_key(l:info, 'temporary_directory_list') for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
for l:directory in l:info.temporary_directory_list
call delete(l:directory, 'rf') call delete(l:directory, 'rf')
endfor endfor
let l:info.temporary_directory_list = [] let g:ale_buffer_info[a:buffer].temporary_directory_list = []
endif
endfunction endfunction
function! s:GatherOutput(job_id, line) abort function! s:GatherOutput(job_id, line) abort
@@ -134,22 +105,12 @@ function! s:GatherOutput(job_id, line) abort
endfunction endfunction
function! s:HandleLoclist(linter_name, buffer, loclist) abort function! s:HandleLoclist(linter_name, buffer, loclist) abort
let l:buffer_info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:buffer_info)
return
endif
" Remove this linter from the list of active linters.
" This may have already been done when the job exits.
call filter(l:buffer_info.active_linter_list, 'v:val isnot# a:linter_name')
" Make some adjustments to the loclists to fix common problems, and also " Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items. " to set default values for loclist items.
let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist) let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist)
" Remove previous items for this linter. " Remove previous items for this linter.
call filter(g:ale_buffer_info[a:buffer].loclist, 'v:val.linter_name isnot# a:linter_name') call filter(g:ale_buffer_info[a:buffer].loclist, 'v:val.linter_name !=# a:linter_name')
" Add the new items. " Add the new items.
call extend(g:ale_buffer_info[a:buffer].loclist, l:linter_loclist) call extend(g:ale_buffer_info[a:buffer].loclist, l:linter_loclist)
@@ -158,11 +119,34 @@ function! s:HandleLoclist(linter_name, buffer, loclist) abort
" for efficient lookup of the messages in the cursor handler. " for efficient lookup of the messages in the cursor handler.
call sort(g:ale_buffer_info[a:buffer].loclist, 'ale#util#LocItemCompare') call sort(g:ale_buffer_info[a:buffer].loclist, 'ale#util#LocItemCompare')
if ale#ShouldDoNothing(a:buffer) let l:linting_is_done = empty(g:ale_buffer_info[a:buffer].job_list)
return \ && !get(g:ale_buffer_info[a:buffer], 'waiting_for_tsserver', 0)
if l:linting_is_done
" Automatically remove all managed temporary files and directories
" now that all jobs have completed.
call ale#engine#RemoveManagedFiles(a:buffer)
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
let l:name_map = {}
for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype'))
let l:name_map[l:linter.name] = 1
endfor
call filter(
\ g:ale_buffer_info[a:buffer].loclist,
\ 'get(l:name_map, v:val.linter_name)',
\)
endif endif
call ale#engine#SetResults(a:buffer, g:ale_buffer_info[a:buffer].loclist) call ale#engine#SetResults(a:buffer, g:ale_buffer_info[a:buffer].loclist)
if l:linting_is_done
" Call user autocommands. This allows users to hook into ALE's lint cycle.
silent doautocmd User ALELint
endif
endfunction endfunction
function! s:HandleExit(job_id, exit_code) abort function! s:HandleExit(job_id, exit_code) abort
@@ -183,8 +167,7 @@ function! s:HandleExit(job_id, exit_code) abort
" Remove this job from the list. " Remove this job from the list.
call ale#job#Stop(a:job_id) call ale#job#Stop(a:job_id)
call remove(s:job_info_map, a:job_id) call remove(s:job_info_map, a:job_id)
call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val isnot# a:job_id') call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val !=# a:job_id')
call filter(g:ale_buffer_info[l:buffer].active_linter_list, 'v:val isnot# l:linter.name')
" Stop here if we land in the handle for a job completing if we're in " Stop here if we land in the handle for a job completing if we're in
" a sandbox. " a sandbox.
@@ -211,77 +194,43 @@ function! s:HandleExit(job_id, exit_code) abort
call s:HandleLoclist(l:linter.name, l:buffer, l:loclist) call s:HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPResponse(response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id] let l:is_diag_response = get(a:response, 'type', '') ==# 'event'
let l:filename = ale#path#FromURI(a:response.params.uri) \ && get(a:response, 'event', '') ==# 'semanticDiag'
let l:buffer = bufnr(l:filename)
if l:buffer <= 0 if !l:is_diag_response
return return
endif endif
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call s:HandleLoclist(l:linter_name, l:buffer, l:loclist)
endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:buffer = bufnr(a:response.body.file) let l:buffer = bufnr(a:response.body.file)
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
return return
endif endif
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response) let l:info.waiting_for_tsserver = 0
" tsserver sends syntax and semantic errors in separate messages, so we let l:loclist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
" have to collect the messages separately for each buffer and join them
" back together again.
if a:error_type is# 'syntax'
let l:info.syntax_loclist = l:thislist
else
let l:info.semantic_loclist = l:thislist
endif
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
call s:HandleLoclist('tsserver', l:buffer, l:loclist) call s:HandleLoclist('tsserver', l:buffer, l:loclist)
endfunction endfunction
function! s:HandleLSPErrorMessage(error_message) abort
echoerr 'Error from LSP:'
for l:line in split(a:error_message, "\n")
echoerr l:line
endfor
endfunction
function! ale#engine#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
" Uncomment this line to print LSP error messages.
" call s:HandleLSPErrorMessage(a:response.error.message)
elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response)
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'semanticDiag'
call s:HandleTSServerDiagnostics(a:response, 'semantic')
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'syntaxDiag'
call s:HandleTSServerDiagnostics(a:response, 'syntax')
endif
endfunction
function! ale#engine#SetResults(buffer, loclist) abort function! ale#engine#SetResults(buffer, loclist) abort
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer) let l:info = get(g:ale_buffer_info, a:buffer, {})
let l:job_list = get(l:info, 'job_list', [])
let l:waiting_for_tsserver = get(l:info, 'waiting_for_tsserver', 0)
let l:linting_is_done = empty(l:job_list) && !l:waiting_for_tsserver
" Set signs first. This could potentially fix some line numbers. " Set signs first. This could potentially fix some line numbers.
" The List could be sorted again here by SetSigns. " The List could be sorted again here by SetSigns.
if g:ale_set_signs if g:ale_set_signs
call ale#sign#SetSigns(a:buffer, a:loclist) call ale#sign#SetSigns(a:buffer, a:loclist)
if l:linting_is_done
call ale#sign#RemoveDummySignIfNeeded(a:buffer)
endif
endif endif
if g:ale_set_quickfix || g:ale_set_loclist if g:ale_set_quickfix || g:ale_set_loclist
@@ -306,34 +255,22 @@ function! ale#engine#SetResults(buffer, loclist) abort
" This will only do something meaningful if we're in normal mode. " This will only do something meaningful if we're in normal mode.
call ale#cursor#EchoCursorWarning() call ale#cursor#EchoCursorWarning()
endif endif
if l:linting_is_done
" Reset the save event marker, used for opening windows, etc.
call setbufvar(a:buffer, 'ale_save_event_fired', 0)
" Automatically remove all managed temporary files and directories
" now that all jobs have completed.
call ale#engine#RemoveManagedFiles(a:buffer)
" Call user autocommands. This allows users to hook into ALE's lint cycle.
silent doautocmd User ALELint
endif
endfunction endfunction
function! s:RemapItemTypes(type_map, loclist) abort function! s:RemapItemTypes(type_map, loclist) abort
for l:item in a:loclist for l:item in a:loclist
let l:key = l:item.type let l:key = l:item.type
\ . (get(l:item, 'sub_type', '') is# 'style' ? 'S' : '') \ . (get(l:item, 'sub_type', '') ==# 'style' ? 'S' : '')
let l:new_key = get(a:type_map, l:key, '') let l:new_key = get(a:type_map, l:key, '')
if l:new_key is# 'E' if l:new_key ==# 'E'
\|| l:new_key is# 'ES' \|| l:new_key ==# 'ES'
\|| l:new_key is# 'W' \|| l:new_key ==# 'W'
\|| l:new_key is# 'WS' \|| l:new_key ==# 'WS'
\|| l:new_key is# 'I' \|| l:new_key ==# 'I'
let l:item.type = l:new_key[0] let l:item.type = l:new_key[0]
if l:new_key is# 'ES' || l:new_key is# 'WS' if l:new_key ==# 'ES' || l:new_key ==# 'WS'
let l:item.sub_type = 'style' let l:item.sub_type = 'style'
elseif has_key(l:item, 'sub_type') elseif has_key(l:item, 'sub_type')
call remove(l:item, 'sub_type') call remove(l:item, 'sub_type')
@@ -342,11 +279,7 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfor endfor
endfunction endfunction
" Save the temporary directory so we can figure out if files are in it.
let s:temp_dir = fnamemodify(tempname(), ':h')
function! ale#engine#FixLocList(buffer, linter_name, loclist) abort function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
let l:bufnr_map = {}
let l:new_loclist = [] 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,
@@ -368,42 +301,16 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
" The linter_name will be set on the errors so it can be used in " The linter_name will be set on the errors so it can be used in
" output, filtering, etc.. " output, filtering, etc..
let l:item = { let l:item = {
\ 'bufnr': a:buffer,
\ 'text': l:old_item.text, \ 'text': l:old_item.text,
\ 'lnum': str2nr(l:old_item.lnum), \ 'lnum': str2nr(l:old_item.lnum),
\ 'col': str2nr(get(l:old_item, 'col', 0)), \ 'col': str2nr(get(l:old_item, 'col', 0)),
\ 'bufnr': get(l:old_item, 'bufnr', a:buffer),
\ 'vcol': get(l:old_item, 'vcol', 0), \ 'vcol': get(l:old_item, 'vcol', 0),
\ 'type': get(l:old_item, 'type', 'E'), \ 'type': get(l:old_item, 'type', 'E'),
\ 'nr': get(l:old_item, 'nr', -1), \ 'nr': get(l:old_item, 'nr', -1),
\ 'linter_name': a:linter_name, \ 'linter_name': a:linter_name,
\} \}
if has_key(l:old_item, 'filename')
\&& l:old_item.filename[:len(s:temp_dir) - 1] isnot# s:temp_dir
" Use the filename given.
" Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad
" in the loclist window.
let l:filename = l:old_item.filename
let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr')
" If a buffer number is also given, include that too.
" If Vim detects that he buffer number is valid, it will
" be used instead of the filename.
let l:item.bufnr = l:old_item.bufnr
elseif has_key(l:bufnr_map, l:filename)
" Get the buffer number from the map, which can be faster.
let l:item.bufnr = l:bufnr_map[l:filename]
else
" Look up the buffer number.
let l:item.bufnr = bufnr(l:filename)
let l:bufnr_map[l:filename] = l:item.bufnr
endif
elseif has_key(l:old_item, 'bufnr')
let l:item.bufnr = l:old_item.bufnr
endif
if has_key(l:old_item, 'detail') if has_key(l:old_item, 'detail')
let l:item.detail = l:old_item.detail let l:item.detail = l:old_item.detail
endif endif
@@ -424,9 +331,8 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
if l:item.lnum < 1 if l:item.lnum < 1
" When errors appear before line 1, put them at line 1. " When errors appear before line 1, put them at line 1.
let l:item.lnum = 1 let l:item.lnum = 1
elseif l:item.bufnr == a:buffer && 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. " When errors go beyond the end of the file, put them at the end.
" This is only done for the current buffer.
let l:item.lnum = l:last_line_number let l:item.lnum = l:last_line_number
endif endif
@@ -461,15 +367,11 @@ function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort
" Automatically delete the directory later. " Automatically delete the directory later.
call ale#engine#ManageDirectory(a:buffer, l:temporary_directory) call ale#engine#ManageDirectory(a:buffer, l:temporary_directory)
" Write the buffer out to a file. " Write the buffer out to a file.
let l:lines = getbufline(a:buffer, 1, '$') call writefile(getbufline(a:buffer, 1, '$'), a:temporary_file)
call ale#util#Writefile(a:buffer, l:lines, a:temporary_file)
return 1 return 1
endfunction endfunction
" Run a job.
"
" Returns 1 when the job was started successfully.
function! s:RunJob(options) abort function! s:RunJob(options) abort
let l:command = a:options.command let l:command = a:options.command
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
@@ -477,11 +379,6 @@ function! s:RunJob(options) abort
let l:output_stream = a:options.output_stream let l:output_stream = a:options.output_stream
let l:next_chain_index = a:options.next_chain_index let l:next_chain_index = a:options.next_chain_index
let l:read_buffer = a:options.read_buffer let l:read_buffer = a:options.read_buffer
let l:info = g:ale_buffer_info[l:buffer]
if empty(l:command)
return 0
endif
let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer) let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer)
@@ -507,9 +404,9 @@ function! s:RunJob(options) abort
\ 'exit_cb': function('s:HandleExit'), \ 'exit_cb': function('s:HandleExit'),
\} \}
if l:output_stream is# 'stderr' if l:output_stream ==# 'stderr'
let l:job_options.err_cb = function('s:GatherOutput') let l:job_options.err_cb = function('s:GatherOutput')
elseif l:output_stream is# 'both' elseif l:output_stream ==# 'both'
let l:job_options.out_cb = function('s:GatherOutput') let l:job_options.out_cb = function('s:GatherOutput')
let l:job_options.err_cb = function('s:GatherOutput') let l:job_options.err_cb = function('s:GatherOutput')
else else
@@ -533,11 +430,7 @@ function! s:RunJob(options) abort
" Only proceed if the job is being run. " Only proceed if the job is being run.
if l:job_id if l:job_id
" 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(l:info.job_list, l:job_id) call add(g:ale_buffer_info[l:buffer].job_list, l:job_id)
if index(l:info.active_linter_list, l:linter.name) < 0
call add(l:info.active_linter_list, l:linter.name)
endif
let l:status = 'started' let l:status = 'started'
" 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.
@@ -551,6 +444,8 @@ function! s:RunJob(options) abort
if g:ale_history_enabled if g:ale_history_enabled
call ale#history#Add(l:buffer, l:status, l:job_id, l:command) call ale#history#Add(l:buffer, l:status, l:job_id, l:command)
else
let g:ale_buffer_info[l:buffer].history = []
endif endif
if get(g:, 'ale_run_synchronously') == 1 if get(g:, 'ale_run_synchronously') == 1
@@ -563,8 +458,6 @@ function! s:RunJob(options) abort
call l:job_options.exit_cb(l:job_id, v:shell_error) call l:job_options.exit_cb(l:job_id, v:shell_error)
endif endif
return l:job_id != 0
endfunction endfunction
" Determine which commands to run for a link in a command chain, or " Determine which commands to run for a link in a command chain, or
@@ -620,8 +513,16 @@ 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
elseif has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead.
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
else else
let l:command = ale#linter#GetCommand(a:buffer, a:linter) let l:command = a:linter.command
endif
if empty(l:command)
" Don't run any jobs if the command is an empty string.
return {}
endif endif
return { return {
@@ -637,13 +538,18 @@ endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort function! s:InvokeChain(buffer, linter, chain_index, input) abort
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input) let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
return s:RunJob(l:options) 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! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort function! ale#engine#StopCurrentJobs(buffer, include_lint_file_jobs) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
let l:new_job_list = [] let l:new_job_list = []
let l:new_active_linter_list = []
for l:job_id in get(l:info, 'job_list', []) for l:job_id in get(l:info, 'job_list', [])
let l:job_info = get(s:job_info_map, l:job_id, {}) let l:job_info = get(s:job_info_map, l:job_id, {})
@@ -654,164 +560,75 @@ function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
call remove(s:job_info_map, l:job_id) call remove(s:job_info_map, l:job_id)
else else
call add(l:new_job_list, l:job_id) call add(l:new_job_list, l:job_id)
" Linters with jobs still running are still active.
call add(l:new_active_linter_list, l:job_info.linter.name)
endif endif
endif endif
endfor endfor
" Remove duplicates from the active linter list.
call uniq(sort(l:new_active_linter_list))
" Update the List, so it includes only the jobs we still need. " Update the List, so it includes only the jobs we still need.
let l:info.job_list = l:new_job_list let l:info.job_list = l:new_job_list
" Update the active linter list, clearing out anything not running. " Ignore current LSP commands.
let l:info.active_linter_list = l:new_active_linter_list " We should consider cancelling them in future.
let l:info.lsp_command_list = []
endfunction endfunction
function! s:CheckWithLSP(buffer, linter) abort function! s:CheckWithTSServer(buffer, linter, executable) abort
let l:info = g:ale_buffer_info[a:buffer] let l:info = g:ale_buffer_info[a:buffer]
let l:lsp_details = ale#linter#StartLSP( let l:open_documents = l:info.open_lsp_documents
\ a:buffer, let l:is_open = index(l:open_documents, a:linter.name) >= 0
\ a:linter,
\ function('ale#engine#HandleLSPResponse'),
\)
if empty(l:lsp_details) let l:command = ale#job#PrepareCommand(a:executable)
return 0 let l:job_id = ale#lsp#StartProgram(a:executable, l:command, function('s:HandleLSPResponse'))
if !l:job_id
if g:ale_history_enabled
call ale#history#Add(a:buffer, 'failed', l:job_id, l:command)
endif endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
" Remember the linter this connection is for.
let s:lsp_linter_map[l:id] = a:linter.name
let l:change_message = a:linter.lsp is# 'tsserver'
\ ? ale#lsp#tsserver_message#Geterr(a:buffer)
\ : ale#lsp#message#DidChange(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:change_message, l:root)
if l:request_id != 0
if index(l:info.active_linter_list, a:linter.name) < 0
call add(l:info.active_linter_list, a:linter.name)
endif
endif
return l:request_id != 0
endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
let l:name_map = {}
for l:linter in a:linters
let l:name_map[l:linter.name] = 1
endfor
call filter(
\ get(g:ale_buffer_info[a:buffer], 'loclist', []),
\ 'get(l:name_map, get(v:val, ''linter_name''))',
\)
endfunction
function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
let l:filename = expand('#' . a:buffer . ':p')
let l:loclist = []
let l:name_map = {}
" Build a map of the active linters.
for l:linter in a:linters
let l:name_map[l:linter.name] = 1
endfor
" Find the items from other buffers, for the linters that are enabled.
for l:info in values(g:ale_buffer_info)
for l:item in l:info.loclist
if has_key(l:item, 'filename')
\&& l:item.filename is# l:filename
\&& has_key(l:name_map, l:item.linter_name)
" Copy the items and set the buffer numbers to this one.
let l:new_item = copy(l:item)
let l:new_item.bufnr = a:buffer
call add(l:loclist, l:new_item)
endif
endfor
endfor
if !empty(l:loclist)
call sort(l:loclist, function('ale#util#LocItemCompareWithText'))
call uniq(l:loclist, function('ale#util#LocItemCompareWithText'))
" Set the loclist variable, used by some parts of ALE.
let g:ale_buffer_info[a:buffer].loclist = l:loclist
call ale#engine#SetResults(a:buffer, l:loclist)
endif
endfunction
" Run a linter for a buffer.
"
" Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter) abort
if !empty(a:linter.lsp)
return s:CheckWithLSP(a:buffer, a:linter)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if ale#engine#IsExecutable(a:buffer, l:executable)
return s:InvokeChain(a:buffer, a:linter, 0, [])
endif
endif
return 0
endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
for l:linter in a:linters
" Only run lint_file linters if we should.
if !l:linter.lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter)
" If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0
endif
else
" If we skipped running a lint_file linter still in the list,
" we shouldn't clear everything.
let l:can_clear_results = 0
endif
endfor
" Clear the results if we can. This needs to be done when linters are
" disabled, or ALE itself is disabled.
if l:can_clear_results
call ale#engine#SetResults(a:buffer, [])
elseif l:new_buffer
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
endif
endfunction
" Clean up a buffer.
"
" This function will stop all current jobs for the buffer,
" clear the state of everything, and remove the Dictionary for managing
" the buffer.
function! ale#engine#Cleanup(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
return return
endif endif
call ale#engine#RunLinters(a:buffer, [], 1) if !l:is_open
if g:ale_history_enabled
call ale#history#Add(a:buffer, 'started', l:job_id, l:command)
endif
call remove(g:ale_buffer_info, a:buffer) call add(l:open_documents, a:linter.name)
call ale#lsp#SendMessageToProgram(
\ a:executable,
\ ale#lsp#tsserver_message#Open(a:buffer),
\)
endif
call ale#lsp#SendMessageToProgram(
\ a:executable,
\ ale#lsp#tsserver_message#Change(a:buffer),
\)
let l:request_id = ale#lsp#SendMessageToProgram(
\ a:executable,
\ ale#lsp#tsserver_message#Geterr(a:buffer),
\)
if l:request_id != 0
let l:info.waiting_for_tsserver = 1
endif
endfunction
function! ale#engine#Invoke(buffer, linter) abort
if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver'
let l:executable = has_key(a:linter, 'executable_callback')
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
\ : a:linter.executable
" Run this program if it can be executed.
if s:IsExecutable(l:executable)
if a:linter.lsp ==# 'tsserver'
call s:CheckWithTSServer(a:buffer, a:linter, l:executable)
else
call s:InvokeChain(a:buffer, a:linter, 0, [])
endif
endif
endif
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.

View File

@@ -1,8 +1,7 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
function! ale#events#SaveEvent(buffer) abort function! ale#events#SaveEvent() abort
call setbufvar(a:buffer, 'ale_save_event_fired', 1) let l:should_lint = g:ale_enabled && g:ale_lint_on_save
let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save
if g:ale_fix_on_save if g:ale_fix_on_save
let l:will_fix = ale#fix#Fix('save_file') let l:will_fix = ale#fix#Fix('save_file')
@@ -10,38 +9,25 @@ function! ale#events#SaveEvent(buffer) abort
endif endif
if l:should_lint if l:should_lint
call ale#Queue(0, 'lint_file', a:buffer) call ale#Queue(0, 'lint_file')
endif endif
endfunction endfunction
function! s:LintOnEnter(buffer) abort function! s:LintOnEnter() abort
if ale#Var(a:buffer, 'enabled') if g:ale_enabled && g:ale_lint_on_enter && has_key(b:, 'ale_file_changed')
\&& g:ale_lint_on_enter
\&& has_key(b:, 'ale_file_changed')
call remove(b:, 'ale_file_changed') call remove(b:, 'ale_file_changed')
call ale#Queue(0, 'lint_file', a:buffer) call ale#Queue(0, 'lint_file')
endif endif
endfunction endfunction
function! ale#events#EnterEvent(buffer) abort function! ale#events#EnterEvent() abort
let l:filetype = getbufvar(a:buffer, '&filetype') call s:LintOnEnter()
call setbufvar(a:buffer, 'ale_original_filetype', l:filetype)
call s:LintOnEnter(a:buffer)
endfunction
function! ale#events#FileTypeEvent(buffer, new_filetype) abort
let l:filetype = getbufvar(a:buffer, 'ale_original_filetype', '')
if a:new_filetype isnot# l:filetype
call ale#Queue(300, 'lint_file', a:buffer)
endif
endfunction endfunction
function! ale#events#FileChangedEvent(buffer) abort function! ale#events#FileChangedEvent(buffer) abort
call setbufvar(a:buffer, 'ale_file_changed', 1) call setbufvar(a:buffer, 'ale_file_changed', 1)
if bufnr('') == a:buffer if bufnr('') == a:buffer
call s:LintOnEnter(a:buffer) call s:LintOnEnter()
endif endif
endfunction endfunction

View File

@@ -43,6 +43,7 @@ function! ale#fix#ApplyQueuedFixes() abort
if empty(&buftype) if empty(&buftype)
noautocmd :w! noautocmd :w!
else else
call writefile(l:data.output, 'fix_test_file')
set nomodified set nomodified
endif endif
endif endif
@@ -154,7 +155,7 @@ function! s:CreateTemporaryFileForJob(buffer, temporary_file, input) abort
" Automatically delete the directory later. " Automatically delete the directory later.
call ale#fix#ManageDirectory(a:buffer, l:temporary_directory) call ale#fix#ManageDirectory(a:buffer, l:temporary_directory)
" Write the buffer out to a file. " Write the buffer out to a file.
call ale#util#Writefile(a:buffer, a:input, a:temporary_file) call writefile(a:input, a:temporary_file)
return 1 return 1
endfunction endfunction
@@ -186,9 +187,9 @@ function! s:RunJob(options) abort
if l:read_temporary_file if l:read_temporary_file
" TODO: Check that a temporary file is set here. " TODO: Check that a temporary file is set here.
let l:job_info.file_to_read = l:temporary_file let l:job_info.file_to_read = l:temporary_file
elseif l:output_stream is# 'stderr' elseif l:output_stream ==# 'stderr'
let l:job_options.err_cb = function('s:GatherOutput') let l:job_options.err_cb = function('s:GatherOutput')
elseif l:output_stream is# 'both' elseif l:output_stream ==# 'both'
let l:job_options.out_cb = function('s:GatherOutput') let l:job_options.out_cb = function('s:GatherOutput')
let l:job_options.err_cb = function('s:GatherOutput') let l:job_options.err_cb = function('s:GatherOutput')
else else
@@ -320,7 +321,7 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
\ 'lines_before': getbufline(a:buffer, 1, '$'), \ 'lines_before': getbufline(a:buffer, 1, '$'),
\ 'filename': expand('#' . a:buffer . ':p'), \ 'filename': expand('#' . a:buffer . ':p'),
\ 'done': 0, \ 'done': 0,
\ 'should_save': a:fixing_flag is# 'save_file', \ 'should_save': a:fixing_flag ==# 'save_file',
\ 'temporary_directory_list': [], \ 'temporary_directory_list': [],
\} \}
endfunction endfunction
@@ -335,14 +336,14 @@ function! ale#fix#Fix(...) abort
let l:fixing_flag = get(a:000, 0, '') let l:fixing_flag = get(a:000, 0, '')
if l:fixing_flag isnot# '' && l:fixing_flag isnot# 'save_file' if l:fixing_flag !=# '' && l:fixing_flag !=# 'save_file'
throw "fixing_flag must be either '' or 'save_file'" throw "fixing_flag must be either '' or 'save_file'"
endif endif
let l:callback_list = s:GetCallbacks() let l:callback_list = s:GetCallbacks()
if empty(l:callback_list) if empty(l:callback_list)
if l:fixing_flag is# '' if l:fixing_flag ==# ''
echoerr 'No fixers have been defined. Try :ALEFixSuggest' echoerr 'No fixers have been defined. Try :ALEFixSuggest'
endif endif

View File

@@ -7,21 +7,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],
\ 'description': 'Add blank lines before control statements.', \ 'description': 'Add blank lines before control statements.',
\ }, \ },
\ 'align_help_tags': {
\ 'function': 'ale#fixers#help#AlignTags',
\ 'suggested_filetypes': ['help'],
\ 'description': 'Align help tags to the right margin',
\ },
\ 'autopep8': { \ 'autopep8': {
\ 'function': 'ale#fixers#autopep8#Fix', \ 'function': 'ale#fixers#autopep8#Fix',
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with autopep8.', \ 'description': 'Fix PEP8 issues with autopep8.',
\ }, \ },
\ 'prettier_standard': {
\ 'function': 'ale#fixers#prettier_standard#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Apply prettier-standard to a file.',
\ },
\ 'eslint': { \ 'eslint': {
\ 'function': 'ale#fixers#eslint#Fix', \ 'function': 'ale#fixers#eslint#Fix',
\ 'suggested_filetypes': ['javascript', 'typescript'], \ 'suggested_filetypes': ['javascript', 'typescript'],
@@ -42,11 +32,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['javascript'], \ 'suggested_filetypes': ['javascript'],
\ 'description': 'Apply prettier-eslint to a file.', \ 'description': 'Apply prettier-eslint to a file.',
\ }, \ },
\ 'puppetlint': {
\ 'function': 'ale#fixers#puppetlint#Fix',
\ 'suggested_filetypes': ['puppet'],
\ 'description': 'Run puppet-lint -f on a file.',
\ },
\ 'remove_trailing_lines': { \ 'remove_trailing_lines': {
\ 'function': 'ale#fixers#generic#RemoveTrailingBlankLines', \ 'function': 'ale#fixers#generic#RemoveTrailingBlankLines',
\ 'suggested_filetypes': [], \ 'suggested_filetypes': [],
@@ -62,31 +47,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['ruby'], \ 'suggested_filetypes': ['ruby'],
\ 'description': 'Fix ruby files with rubocop --auto-correct.', \ 'description': 'Fix ruby files with rubocop --auto-correct.',
\ }, \ },
\ 'standard': {
\ 'function': 'ale#fixers#standard#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Fix JavaScript files using standard --fix',
\ },
\ 'stylelint': {
\ 'function': 'ale#fixers#stylelint#Fix',
\ 'suggested_filetypes': ['css', 'sass', 'scss', 'stylus'],
\ 'description': 'Fix stylesheet files using stylelint --fix.',
\ },
\ 'swiftformat': {
\ 'function': 'ale#fixers#swiftformat#Fix',
\ 'suggested_filetypes': ['swift'],
\ 'description': 'Apply SwiftFormat to a file.',
\ },
\ 'phpcbf': {
\ 'function': 'ale#fixers#phpcbf#Fix',
\ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with phpcbf.',
\ },
\ 'clang-format': {
\ 'function': 'ale#fixers#clangformat#Fix',
\ 'suggested_filetypes': ['c', 'cpp'],
\ 'description': 'Fix C/C++ files with clang-format.',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.
@@ -151,56 +111,44 @@ endfunction
" Suggest functions to use from the registry. " Suggest functions to use from the registry.
function! ale#fix#registry#Suggest(filetype) abort function! ale#fix#registry#Suggest(filetype) abort
let l:type_list = split(a:filetype, '\.') let l:type_list = split(a:filetype, '\.')
let l:filetype_fixer_list = [] let l:first_for_filetype = 1
let l:first_generic = 1
for l:key in sort(keys(s:entries)) for l:key in sort(keys(s:entries))
let l:suggested_filetypes = s:entries[l:key].suggested_filetypes let l:suggested_filetypes = s:entries[l:key].suggested_filetypes
if s:ShouldSuggestForType(l:suggested_filetypes, l:type_list) if s:ShouldSuggestForType(l:suggested_filetypes, l:type_list)
call add( if l:first_for_filetype
\ l:filetype_fixer_list, let l:first_for_filetype = 0
\ printf('%s - %s', string(l:key), s:entries[l:key].description), echom 'Try the following fixers appropriate for the filetype:'
\) echom ''
endif
echom printf('%s - %s', string(l:key), s:entries[l:key].description)
endif endif
endfor endfor
let l:generic_fixer_list = []
for l:key in sort(keys(s:entries)) for l:key in sort(keys(s:entries))
if empty(s:entries[l:key].suggested_filetypes) if empty(s:entries[l:key].suggested_filetypes)
call add( if l:first_generic
\ l:generic_fixer_list, if !l:first_for_filetype
\ printf('%s - %s', string(l:key), s:entries[l:key].description), echom ''
\) endif
let l:first_generic = 0
echom 'Try the following generic fixers:'
echom ''
endif
echom printf('%s - %s', string(l:key), s:entries[l:key].description)
endif endif
endfor endfor
let l:filetype_fixer_header = !empty(l:filetype_fixer_list) if l:first_for_filetype && l:first_generic
\ ? ['Try the following fixers appropriate for the filetype:', ''] echom 'There is nothing in the registry to suggest.'
\ : []
let l:generic_fixer_header = !empty(l:generic_fixer_list)
\ ? ['Try the following generic fixers:', '']
\ : []
let l:has_both_lists = !empty(l:filetype_fixer_list) && !empty(l:generic_fixer_list)
let l:lines =
\ l:filetype_fixer_header
\ + l:filetype_fixer_list
\ + (l:has_both_lists ? [''] : [])
\ + l:generic_fixer_header
\ + l:generic_fixer_list
if empty(l:lines)
let l:lines = ['There is nothing in the registry to suggest.']
else else
let l:lines += ['', 'See :help ale-fix-configuration'] echom ''
echom 'See :help ale-fix-configuration'
endif endif
let l:lines += ['', 'Press q to close this window']
new +set\ filetype=ale-fix-suggest
call setline(1, l:lines)
setlocal nomodified
setlocal nomodifiable
endfunction endfunction

View File

@@ -9,7 +9,7 @@ function! ale#fixers#autopep8#Fix(buffer) abort
let l:executable = ale#python#FindExecutable( let l:executable = ale#python#FindExecutable(
\ a:buffer, \ a:buffer,
\ 'python_autopep8', \ 'python_autopep8',
\ ['autopep8'], \ ['/bin/autopep8'],
\) \)
if !executable(l:executable) if !executable(l:executable)

View File

@@ -1,21 +0,0 @@
" Author: Peter Renström <renstrom.peter@gmail.com>
" Description: Fixing C/C++ files with clang-format.
call ale#Set('c_clangformat_executable', 'clang-format')
call ale#Set('c_clangformat_use_global', 0)
call ale#Set('c_clangformat_options', '')
function! ale#fixers#clangformat#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'c_clangformat', [
\ 'clang-format',
\])
endfunction
function! ale#fixers#clangformat#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'c_clangformat_options')
return {
\ 'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
\ . ' ' . l:options,
\}
endfunction

View File

@@ -28,16 +28,8 @@ function! ale#fixers#eslint#Fix(buffer) abort
return 0 return 0
endif endif
if ale#Has('win32') && l:executable =~? 'eslint\.js$'
" For Windows, if we detect an eslint.js script, we need to execute
" it with node, or the file can be opened with a text editor.
let l:head = 'node ' . ale#Escape(l:executable)
else
let l:head = ale#Escape(l:executable)
endif
return { return {
\ 'command': l:head \ 'command': ale#Escape(l:executable)
\ . ' --config ' . ale#Escape(l:config) \ . ' --config ' . ale#Escape(l:config)
\ . ' --fix %t', \ . ' --fix %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,

View File

@@ -23,38 +23,3 @@ function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, line
return l:new_lines return l:new_lines
endfunction endfunction
" This function breaks up long lines so that autopep8 or other tools can
" fix the badly-indented code which is produced as a result.
function! ale#fixers#generic_python#BreakUpLongLines(buffer, lines) abort
" Default to a maximum line length of 79
let l:max_line_length = 79
let l:conf = ale#path#FindNearestFile(a:buffer, 'setup.cfg')
" Read the maximum line length from setup.cfg
if !empty(l:conf)
for l:match in ale#util#GetMatches(
\ readfile(l:conf),
\ '\v^ *max-line-length *\= *(\d+)',
\)
let l:max_line_length = str2nr(l:match[1])
endfor
endif
let l:new_list = []
for l:line in a:lines
if len(l:line) > l:max_line_length && l:line !~# '# *noqa'
let l:line = substitute(l:line, '\v([(,])([^)])', '\1\n\2', 'g')
let l:line = substitute(l:line, '\v([^(])([)])', '\1,\n\2', 'g')
for l:split_line in split(l:line, "\n")
call add(l:new_list, l:split_line)
endfor
else
call add(l:new_list, l:line)
endif
endfor
return l:new_list
endfunction

View File

@@ -1,24 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Generic fixer functions for Vim help documents.
function! ale#fixers#help#AlignTags(buffer, lines) abort
let l:new_lines = []
for l:line in a:lines
if len(l:line) != 79
let l:match = matchlist(l:line, '\v +(\*[^*]+\*)$')
if !empty(l:match)
let l:start = l:line[:-len(l:match[0]) - 1]
let l:tag = l:match[1]
let l:spaces = repeat(' ', 79 - len(l:start) - len(l:tag))
let l:line = l:start . l:spaces . l:tag
endif
endif
call add(l:new_lines, l:line)
endfor
return l:new_lines
endfunction

View File

@@ -8,7 +8,7 @@ function! ale#fixers#isort#Fix(buffer) abort
let l:executable = ale#python#FindExecutable( let l:executable = ale#python#FindExecutable(
\ a:buffer, \ a:buffer,
\ 'python_isort', \ 'python_isort',
\ ['isort'], \ ['/bin/isort'],
\) \)
if !executable(l:executable) if !executable(l:executable)

View File

@@ -1,24 +0,0 @@
" Author: notomo <notomo.motono@gmail.com>
" Description: Fixing files with phpcbf.
call ale#Set('php_phpcbf_standard', '')
call ale#Set('php_phpcbf_executable', 'phpcbf')
call ale#Set('php_phpcbf_use_global', 0)
function! ale#fixers#phpcbf#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'php_phpcbf', [
\ 'vendor/bin/phpcbf',
\ 'phpcbf'
\])
endfunction
function! ale#fixers#phpcbf#Fix(buffer) abort
let l:executable = ale#fixers#phpcbf#GetExecutable(a:buffer)
let l:standard = ale#Var(a:buffer, 'php_phpcbf_standard')
let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard
\ : ''
return {
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option
\}
endfunction

View File

@@ -1,24 +0,0 @@
" Author: sheerun (Adam Stankiewicz) <sheerun@sher.pl>
" Description: Integration of Prettier Standard with ALE.
call ale#Set('javascript_prettier_standard_executable', 'prettier-standard')
call ale#Set('javascript_prettier_standard_use_global', 0)
call ale#Set('javascript_prettier_standard_options', '')
function! ale#fixers#prettier_standard#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_prettier_standard', [
\ 'node_modules/prettier-standard/lib/index.js',
\ 'node_modules/.bin/prettier-standard',
\])
endfunction
function! ale#fixers#prettier_standard#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'javascript_prettier_standard_options')
return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
\ . ' %t'
\ . ' ' . l:options,
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -1,21 +0,0 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
" Description: puppet-lint fixer
if !exists('g:ale_puppet_puppetlint_executable')
let g:ale_puppet_puppetlint_executable = 'puppet-lint'
endif
if !exists('g:ale_puppet_puppetlint_options')
let g:ale_puppet_puppetlint_options = ''
endif
function! ale#fixers#puppetlint#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'puppet_puppetlint_executable')
return {
\ 'command': ale#Escape(l:executable)
\ . ' ' . ale#Var(a:buffer, 'puppet_puppetlint_options')
\ . ' --fix'
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -4,11 +4,9 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort
\ ? ' exec rubocop' \ ? ' exec rubocop'
\ : '' \ : ''
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options')
return ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --auto-correct %t' \ . ' --auto-correct %t'
endfunction endfunction

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