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
379 changed files with 2241 additions and 10383 deletions

View File

@@ -2,6 +2,9 @@
sudo: required
services:
- docker
branches:
only:
- master
language: python
script: |
./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
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
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.
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
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,9 +11,9 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
let l:type = l:match[3]
let l:text = l:match[4]
if l:type is# 'C'
if l:type ==# 'C'
let l:type = 'E'
elseif l:type is# 'R'
elseif l:type ==# 'R'
let l:type = 'W'
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:unparsed_lines = []
for l:line in a:lines
if l:line[0] is# '['
if l:line[0] ==# '['
let l:errors = json_decode(l:line)
for l:error in l:errors
" Check if file is from the temp directory.
" Filters out any errors not related to the buffer.
if l:is_windows
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is? l:temp_dir
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==? l:temp_dir
else
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] is# l:temp_dir
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==# l:temp_dir
endif
if l:file_is_buffer
call add(l:output, {
\ 'lnum': l:error.region.start.line,
\ 'col': l:error.region.start.column,
\ 'end_lnum': l:error.region.end.line,
\ 'end_col': l:error.region.end.column,
\ 'type': (l:error.type is? 'error') ? 'E' : 'W',
\ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
\ 'text': l:error.overview,
\ 'detail': l:error.overview . "\n\n" . l:error.details
\})
endif
endfor
elseif l:line isnot# 'Successfully generated /dev/null'
elseif l:line !=# 'Successfully generated /dev/null'
call add(l:unparsed_lines, l:line)
endif
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_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
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.
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)
else
let l:last_loclist_obj = {

View File

@@ -1,22 +1,16 @@
" Author: Ben Reedy <https://github.com/breed808>
" Description: Adds support for the gometalinter suite for Go files
call ale#Set('go_gometalinter_options', '')
call ale#Set('go_gometalinter_executable', 'gometalinter')
function! ale_linters#go#gometalinter#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'go_gometalinter_executable')
endfunction
if !exists('g:ale_go_gometalinter_options')
let g:ale_go_gometalinter_options = ''
endif
function! ale_linters#go#gometalinter#GetCommand(buffer) abort
let l:executable = ale_linters#go#gometalinter#GetExecutable(a:buffer)
let l:filename = expand('#' . a:buffer)
let l:options = ale#Var(a:buffer, 'go_gometalinter_options')
let l:filename = expand('#' . a:buffer . ':p')
return ale#Escape(l:executable)
\ . ' --include=' . ale#Escape('^' . ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' ' . ale#Escape(fnamemodify(l:filename, ':h'))
return 'gometalinter --include=''^' . l:filename . '.*$'' '
\ . ale#Var(a:buffer, 'go_gometalinter_options')
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
endfunction
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, {
\ 'lnum': l:match[2] + 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],
\})
endfor
@@ -42,7 +36,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gometalinter',
\ 'executable_callback': 'ale_linters#go#gometalinter#GetExecutable',
\ 'executable': 'gometalinter',
\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
\ 'callback': 'ale_linters#go#gometalinter#Handler',
\ '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
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
if len(a:lines) == 0
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')
call add(l:output, {
\ 'bufnr': a:buffer,

View File

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

View File

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

View File

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

View File

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

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)
let l:line = l:match[1] + 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]
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])
elseif empty(l:match[3])
" 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]
endif
else
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'text': l:match[2] . ':' . l:match[3],
\ 'type': l:match[2] is# 'error' ? 'E' : 'W',
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\})
endif
endfor

View File

@@ -40,26 +40,10 @@ function! ale_linters#javascript#flow#GetCommand(buffer, version_lines) abort
\ . ' --json --from ale %s'
endfunction
" Filter lines of flow output until we find the first line where the JSON
" output starts.
function! s:GetJSONLines(lines) abort
let l:start_index = 0
for l:line in a:lines
if l:line[:0] is# '{'
break
endif
let l:start_index += 1
endfor
return a:lines[l:start_index :]
endfunction
function! ale_linters#javascript#flow#Handle(buffer, lines) abort
let l:str = join(s:GetJSONLines(a:lines), '')
let l:str = join(a:lines, '')
if empty(l:str)
if l:str ==# ''
return []
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
" than the buffer one, thus we skip this loc information too.
if has_key(l:message, 'loc')
\&& l:line is# 0
\&& l:line ==# 0
\&& ale#path#IsBufferPath(a:buffer, l:message.loc.source)
let l:line = l:message.loc.start.line + 0
let l:col = l:message.loc.start.column + 0
endif
if l:text is# ''
if l:text ==# ''
let l:text = l:message.descr . ':'
else
let l:text = l:text . ' ' . l:message.descr
@@ -98,7 +82,7 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
\ 'lnum': l:line,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:error.level is# 'error' ? 'E' : 'W',
\ 'type': l:error.level ==# 'error' ? 'E' : 'W',
\})
endfor
@@ -113,5 +97,5 @@ call ale#linter#Define('javascript', {
\ {'callback': 'ale_linters#javascript#flow#GetCommand'},
\ ],
\ '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
" Description: jscs for JavaScript files
call ale#Set('javascript_jscs_executable', 'jscs')
call ale#Set('javascript_jscs_use_global', 0)
function! ale_linters#javascript#jscs#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_jscs', [
\ 'node_modules/.bin/jscs',
\])
endfunction
function! ale_linters#javascript#jscs#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jscs_config = ale#path#ResolveLocalPath(
\ a:buffer,
\ '.jscsrc',
\ get(g:, 'ale_jscs_config_loc', '')
\)
let l:command = ale#Escape(ale_linters#javascript#jscs#GetExecutable(a:buffer))
let l:command .= ' --reporter inline --no-colors'
if !empty(l:jscs_config)
let l:command .= ' --config ' . ale#Escape(l:jscs_config)
endif
let l:command .= ' -'
return l:command
endfunction
function! ale_linters#javascript#jscs#Handle(buffer, lines) abort
" Matches patterns looking like the following
"
" foobar.js: line 2, col 1, Expected indentation of 1 characters
"
let l:pattern = '^.*:\s\+line \(\d\+\),\s\+col\s\+\(\d\+\),\s\+\(.*\)$'
let l:output = []
let l:m = ale#util#GetMatches(a:lines, [l:pattern])
for l:match in l:m
let l:text = l:match[3]
let l:obj = {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3]
\}
call add(l:output, l:obj)
endfor
return l:output
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jscs',
\ 'executable_callback': 'ale_linters#javascript#jscs#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#jscs#GetCommand',
\ 'callback': 'ale_linters#javascript#jscs#Handle',
\ 'executable': 'jscs',
\ 'command': 'jscs -r unix -n -',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})

View File

@@ -7,17 +7,13 @@ call ale#Set('javascript_standard_options', '')
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
\ 'node_modules/standard/bin/cmd.js',
\ 'node_modules/.bin/standard',
\])
endfunction
function! ale_linters#javascript#standard#GetCommand(buffer) abort
let l:executable = ale_linters#javascript#standard#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_standard_options')
return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
return ale#Escape(ale_linters#javascript#standard#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'javascript_standard_options')
\ . ' --stdin %s'
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') ? ':' : ';'
function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort
" exec maven/gradle only if classpath is not set
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# ''
" exec maven only if classpath is not set
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
return ''
else
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
if !empty(l:pom_path) && executable('mvn')
return ale#path#CdString(fnamemodify(l:pom_path, ':h'))
\ . 'mvn dependency:build-classpath'
endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
if !empty(l:classpath_command)
return l:classpath_command
endif
return ''
endif
endfunction
@@ -70,27 +66,19 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
endif
" We only get here if not using module or the module file not readable
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# ''
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# ''
let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath')
else
" get classpath from maven/gradle
" get classpath from maven
let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths)
endif
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) . ' '
else
" 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')
\ . ' ' . ale#path#FindNearestDirectory(a:buffer, 'src/main/kotlin')
endif
let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
let l:fname .= expand(l:src_dir, 1) . ' '
endif
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')
" Skip if file is not loaded
if l:buf_abspath isnot# l:curbuf_abspath
if l:buf_abspath !=# l:curbuf_abspath
continue
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, {
\ 'lnum': l:line,
@@ -145,7 +133,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
let l:type = l:match[1]
let l:text = l:match[2]
let l:type_marker_str = l:type 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, {
\ 'lnum': 1,
@@ -167,4 +155,3 @@ call ale#linter#Define('kotlin', {
\ 'callback': 'ale_linters#kotlin#kotlinc#Handle',
\ '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:182:7: (W213) unused loop variable 'i'
let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\(\d\+\)) \(.\+\)$'
let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\d\+) \(.\+\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3] . l:match[4] . ': ' . l:match[5],
\ 'text': l:match[4],
\ 'type': l:match[3],
\})
endfor

View File

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

View File

@@ -12,7 +12,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
" module names.
let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t')
if l:buffer_filename isnot# '' && l:temp_buffer_filename isnot# l:buffer_filename
if l:buffer_filename !=# '' && l:temp_buffer_filename !=# l:buffer_filename
continue
endif
@@ -26,7 +26,7 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
if len(l:textmatch) > 0
let l:errortype = l:textmatch[1]
if l:errortype is# 'Error'
if l:errortype ==# 'Error'
let l:type = 'E'
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])
\ && (
\ l:text isnot# 'BEGIN failed--compilation aborted'
\ l:text !=# 'BEGIN failed--compilation aborted'
\ || empty(l:output)
\ || 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
let g:ale_perl_perlcritic_executable =
\ get(g:, 'ale_perl_perlcritic_executable', 'perlcritic')
let g:ale_perl_perlcritic_profile =
\ get(g:, 'ale_perl_perlcritic_profile', '.perlcriticrc')
let g:ale_perl_perlcritic_options =
\ get(g:, 'ale_perl_perlcritic_options', '')
let g:ale_perl_perlcritic_showrules =
\ get(g:, 'ale_perl_perlcritic_showrules', 0)
function! ale_linters#perl#perlcritic#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'perl_perlcritic_executable')
endfunction
function! ale_linters#perl#perlcritic#GetProfile(buffer) abort
" first see if we've been overridden
let l:profile = ale#Var(a:buffer, 'perl_perlcritic_profile')
if l:profile is? ''
return ''
endif
" otherwise, iterate upwards to find it
return ale#path#FindNearestFile(a:buffer, l:profile)
endfunction
if !exists('g:ale_perl_perlcritic_showrules')
let g:ale_perl_perlcritic_showrules = 0
endif
function! ale_linters#perl#perlcritic#GetCommand(buffer) abort
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'
endif
let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer)
let l:options = ale#Var(a:buffer, 'perl_perlcritic_options')
let l:command = ale#Escape(ale_linters#perl#perlcritic#GetExecutable(a:buffer))
\ . " --verbose '". l:critic_verbosity . "' --nocolor"
if l:profile isnot? ''
let l:command .= ' --profile ' . ale#Escape(l:profile)
endif
if l:options isnot? ''
let l:command .= ' ' . l:options
endif
return l:command
return "perlcritic --verbose '". l:critic_verbosity . "' --nocolor"
endfunction
@@ -69,8 +32,8 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perlcritic',
\ 'executable': 'perlcritic',
\ 'output_stream': 'stdout',
\ 'executable_callback': 'ale_linters#perl#perlcritic#GetExecutable',
\ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand',
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
\})

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,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W',
\ 'type': l:type ==# 'error' ? 'E' : 'W',
\})
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>
" Description: pug-lint for checking Pug/Jade files.
call ale#Set('pug_puglint_options', '')
call ale#Set('pug_puglint_executable', 'pug-lint')
call ale#Set('pug_puglint_use_global', 0)
function! ale_linters#pug#puglint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'pug_puglint', [
\ 'node_modules/.bin/pug-lint',
\])
endfunction
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.pug-lintrc',
\ '.pug-lintrc.js',
\ '.pug-lintrc.json',
\ 'package.json',
\]
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
if !empty(l:config)
return l:config
endif
endfor
return ''
endfunction
function! ale_linters#pug#puglint#GetCommand(buffer) abort
let l:executable = ale_linters#pug#puglint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'pug_puglint_options')
let l:config = s:FindConfig(a:buffer)
return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' -r inline %t'
endfunction
call ale#linter#Define('pug', {
\ 'name': 'puglint',
\ 'executable_callback': 'ale_linters#pug#puglint#GetExecutable',
\ 'executable': 'pug-lint',
\ 'output_stream': 'stderr',
\ 'command_callback': 'ale_linters#pug#puglint#GetCommand',
\ 'command': 'pug-lint -r inline %t',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})

View File

@@ -19,8 +19,16 @@ function! s:UsingModule(buffer) abort
endfunction
function! ale_linters#python#flake8#GetExecutable(buffer) abort
if !s:UsingModule(a:buffer)
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
if !s:UsingModule(a:buffer) && !ale#Var(a:buffer, 'python_flake8_use_global')
let l:virtualenv = ale#python#FindVirtualenv(a:buffer)
if !empty(l:virtualenv)
let l:ve_flake8 = l:virtualenv . '/bin/flake8'
if executable(l:ve_flake8)
return l:ve_flake8
endif
endif
endif
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))
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --format=default'
\ . l:display_name_args . ' -'
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)
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')
" Skip warnings for trailing whitespace if the option is off.
continue
@@ -129,12 +136,12 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
\ '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'
elseif l:code[:0] is# 'E'
elseif l:code[:0] ==# 'E'
let l:item.type = 'E'
let l:item.sub_type = 'style'
elseif l:code[:0] is# 'W'
elseif l:code[:0] ==# 'W'
let l:item.sub_type = 'style'
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)
function! ale_linters#python#mypy#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy'])
endfunction
" The directory to change to before running mypy
function! s:GetDir(buffer) abort
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root)
\ ? l:project_root
\ : expand('#' . a:buffer . ':p:h')
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['/bin/mypy'])
endfunction
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)
" We have to always switch to an explicit directory for a command so
" we can know with certainty the base path for the 'filename' keys below.
return ale#path#CdString(l:dir)
return l:cd_command
\ . ale#Escape(l:executable)
\ . ' --show-column-numbers '
\ . ale#Var(a:buffer, 'python_mypy_options')
@@ -33,7 +25,6 @@ function! ale_linters#python#mypy#GetCommand(buffer) abort
endfunction
function! ale_linters#python#mypy#Handle(buffer, lines) abort
let l:dir = s:GetDir(a:buffer)
" Look for lines like the following:
"
" file.py:4: error: No library stub file for module 'django.db'
@@ -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)
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$'
let l:output = []
let l:buffer_filename = expand('#' . a:buffer . ':p')
for l:match in ale#util#GetMatches(a:lines, l:pattern)
if l:buffer_filename[-len(l:match[1]):] !=# l:match[1]
continue
endif
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'type': l:match[4] =~# 'error' ? 'E' : 'W',
\ 'text': l:match[5],
\})
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)
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
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:code = l:match[3]
if (l:code is# 'C0303')
if (l:code ==# 'C0303')
\ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
" Skip warnings for trailing whitespace if the option is off.
continue
endif
if l:code is# 'I0011'
if l:code ==# 'I0011'
" Skip 'Locally disabling' message
continue
endif
@@ -46,7 +58,7 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 1,
\ 'text': l:code . ': ' . l:match[5] . ' (' . l:match[4] . ')',
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
\ 'type': l:code[:0] ==# 'E' ? 'E' : 'W',
\})
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', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
if len(a:lines) == 0
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
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
if !ale#path#IsBufferPath(a:buffer, l:warning_file)
@@ -31,9 +36,9 @@ function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
endfunction
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 ''
endif
@@ -42,6 +47,26 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
\ . ' -p ' . ale#Escape(l:rails_root)
endfunction
function! s:FindRailsRoot(buffer) abort
" Find the nearest dir contining "app", "db", and "config", and assume it is
" the root of a Rails app.
for l:name in ['app', 'config', 'db']
let l:dir = fnamemodify(
\ ale#path#FindNearestDirectory(a:buffer, l:name),
\ ':h:h'
\)
if l:dir !=# '.'
\&& isdirectory(l:dir . '/app')
\&& isdirectory(l:dir . '/config')
\&& isdirectory(l:dir . '/db')
return l:dir
endif
endfor
return ''
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'brakeman',
\ 'executable': 'brakeman',

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
" Description: Reek, a code smell detector for Ruby files
call ale#Set('ruby_reek_show_context', 0)
call ale#Set('ruby_reek_show_wiki_link', 0)
let g:ale_ruby_reek_show_context =
\ get(g:, 'ale_ruby_reek_show_context', 0)
let g:ale_ruby_reek_show_wiki_link =
\ get(g:, 'ale_ruby_reek_show_wiki_link', 0)
function! ale_linters#ruby#reek#Handle(buffer, lines) abort
if len(a:lines) == 0
return []
endif
let l:errors = json_decode(a:lines[0])
let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
for l:error in l:errors
for l:location in l:error.lines
call add(l:output, {
\ 'lnum': l:location,

View File

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

View File

@@ -4,7 +4,7 @@
let g:ale_rust_cargo_use_check = get(g:, 'ale_rust_cargo_use_check', 0)
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') !=# ''
return 'cargo'
else
" 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/
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:dependencies = '-L ' . l:project_root . '/target/debug/deps -L ' .
\ l:project_root . '/target/release/deps'

View File

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

View File

@@ -11,16 +11,24 @@ endif
if !exists('g:ale_sh_shell_default_shell')
let g:ale_sh_shell_default_shell = fnamemodify($SHELL, ':t')
if g:ale_sh_shell_default_shell 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'
endif
endif
function! ale_linters#sh#shell#GetExecutable(buffer) abort
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
let l:banglines = getbufline(a:buffer, 1)
if !empty(l:shell_type)
return l:shell_type
" Take the shell executable from the hashbang, if we can.
if len(l:banglines) == 1 && l:banglines[0] =~# '^#!'
" Remove options like -e, etc.
let l:line = substitute(l:banglines[0], '--\?[a-zA-Z0-9]\+', '', 'g')
for l:possible_shell in ['bash', 'tcsh', 'csh', 'zsh', 'sh']
if l:line =~# l:possible_shell . '\s*$'
return l:possible_shell
endif
endfor
endif
return ale#Var(a:buffer, 'sh_shell_default_shell')

View File

@@ -19,35 +19,25 @@ function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'sh_shellcheck_executable')
endfunction
function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
if !empty(l:shell_type)
return l:shell_type
endif
" If there's no hashbang, try using Vim's buffer variables.
if get(b:, 'is_bash')
return 'bash'
elseif get(b:, 'is_sh')
return 'sh'
elseif get(b:, 'is_kornshell')
return 'ksh'
function! s:GetDialectArgument() abort
if exists('b:is_bash') && b:is_bash
return '-s bash'
elseif exists('b:is_sh') && b:is_sh
return '-s sh'
elseif exists('b:is_kornshell') && b:is_kornshell
return '-s ksh'
endif
return ''
endfunction
function! ale_linters#sh#shellcheck#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer)
return ale_linters#sh#shellcheck#GetExecutable(a:buffer)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
\ . ' -f gcc -'
\ . ' ' . ale#Var(a:buffer, 'sh_shellcheck_options')
\ . ' ' . (!empty(l:exclude_option) ? '-e ' . l:exclude_option : '')
\ . ' ' . s:GetDialectArgument() . ' -f gcc -'
endfunction
call ale#linter#Define('sh', {

View File

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

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_use_global', 0)
" These functions need to be defined just to comply with the API for LSP.
function! ale_linters#typescript#tsserver#GetProjectRoot(buffer) abort
return ''
endfunction
function! ale_linters#typescript#tsserver#GetLanguage(buffer) abort
return ''
endfunction
function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [
\ 'node_modules/.bin/tsserver',
\])
endfunction
function! ale_linters#typescript#tsserver#Handle(buffer, lines) abort
return a:lines
endfunction
call ale#linter#Define('typescript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
\ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable',
\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable',
\ 'project_root_callback': 'ale_linters#typescript#tsserver#GetProjectRoot',
\ 'language_callback': 'ale_linters#typescript#tsserver#GetLanguage',
\ 'callback': 'ale_linters#typescript#tsserver#Handle',
\})

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)
let l:line = l:match[1] + 0
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, {
\ 'lnum': l:line,

View File

@@ -1,22 +1,14 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: verilator for verilog files
" Set this option to change Verilator lint options
if !exists('g:ale_verilog_verilator_options')
let g:ale_verilog_verilator_options = ''
endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = tempname() . '_verilator_linted.v'
" Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename)
let l:lines = getbufline(a:buffer, 1, '$')
call ale#util#Writefile(a:buffer, l:lines, l:filename)
call writefile(getbufline(a:buffer, 1, '$'), l:filename)
return 'verilator --lint-only -Wall -Wno-DECLFILENAME '
\ . ale#Var(a:buffer, 'verilog_verilator_options') .' '
\ . ale#Escape(l:filename)
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' . ale#Escape(l:filename)
endfunction
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)
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:file = l:match[2]

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ function! ale#c#FindProjectRoot(buffer) abort
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
if fnamemodify(l:path, ':t') ==# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
@@ -47,7 +47,7 @@ function! ale#c#FindLocalHeaderPaths(buffer) abort
" If we find an 'include' directory in the project root, then use that.
if isdirectory(l:project_root . '/include')
return [ale#path#Simplify(l:project_root . '/include')]
return [simplify(l:project_root . '/include')]
endif
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>
" Description: Echoes lint message for the current line, if any
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
let s:error_delay_ms = 1000 * 60 * 2
if !exists('s:dont_queue_until')
let s:dont_queue_until = -1
endif
if !exists('s:dont_echo_until')
let s:dont_echo_until = -1
endif
" Return a formatted message according to g:ale_echo_msg_format variable
function! s:GetMessage(linter, type, text) abort
let l:msg = g:ale_echo_msg_format
let l:type = a:type is# 'E'
let l:type = a:type ==# 'E'
\ ? g:ale_echo_msg_error_str
\ : g:ale_echo_msg_warning_str
@@ -34,12 +22,12 @@ function! s:EchoWithShortMess(setting, message) abort
try
" Turn shortmess on or off.
if a:setting is# 'on'
if a:setting ==# 'on'
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.
exec "norm! :echomsg a:message\n"
elseif a:setting is# 'off'
elseif a:setting ==# 'off'
setlocal shortmess-=T
" Regular echo is needed for printing newline characters.
echo a:message
@@ -62,12 +50,10 @@ function! ale#cursor#TruncatedEcho(message) abort
endfunction
function! s:FindItemAtCursor() abort
let l:buf = bufnr('')
let l:info = get(g:ale_buffer_info, l:buf, {})
let l:loclist = get(l:info, 'loclist', [])
let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []})
let l:pos = getcurpos()
let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2])
let l:loc = l:index >= 0 ? l:loclist[l:index] : {}
let l:index = ale#util#BinarySearch(l:info.loclist, l:pos[1], l:pos[2])
let l:loc = l:index >= 0 ? l:info.loclist[l:index] : {}
return [l:info, l:loc]
endfunction
@@ -80,16 +66,12 @@ function! s:StopCursorTimer() abort
endfunction
function! ale#cursor#EchoCursorWarning(...) abort
return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), [])
endfunction
function! s:EchoImpl() abort
if ale#ShouldDoNothing(bufnr(''))
if ale#ShouldDoNothing()
return
endif
" Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n'
if mode() !=# 'n'
return
endif
@@ -107,16 +89,11 @@ function! s:EchoImpl() abort
endif
endfunction
function! ale#cursor#EchoCursorWarningWithDelay() abort
return ale#CallWithCooldown(
\ 'dont_echo_with_delay_until',
\ function('s:EchoWithDelayImpl'),
\ [],
\)
endfunction
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
function! s:EchoWithDelayImpl() abort
if ale#ShouldDoNothing(bufnr(''))
function! ale#cursor#EchoCursorWarningWithDelay() abort
if ale#ShouldDoNothing()
return
endif
@@ -135,12 +112,12 @@ function! s:EchoWithDelayImpl() abort
endfunction
function! ale#cursor#ShowCursorDetail() abort
if ale#ShouldDoNothing(bufnr(''))
if ale#ShouldDoNothing()
return
endif
" Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n'
if mode() !=# 'n'
return
endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ function! ale#fixers#eslint#Fix(buffer) abort
endif
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ 'command': ale#Escape(l:executable)
\ . ' --config ' . ale#Escape(l:config)
\ . ' --fix %t',
\ 'read_temporary_file': 1,

View File

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

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(
\ a:buffer,
\ 'python_isort',
\ ['isort'],
\ ['/bin/isort'],
\)
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

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