Compare commits

...

190 Commits

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

* Create test_typecheck_handler

* Rename test_typecheck_handler to test_typecheck_handler.vader
2017-02-21 20:33:16 +00:00
w0rp
6f6c156995 Fix Pug linting 2017-02-11 20:47:11 +00:00
w0rp
62a45f8ae4 Don't export the custom-checks script in archives 2017-02-09 19:34:31 +00:00
w0rp
73e0f87eba Document the command_chain option 2017-02-09 09:42:17 +00:00
w0rp
bf2075cd0c Revert "Add a Batch stdin wrapper script"
This reverts commit 76a03b0709.
2017-02-09 00:28:32 +00:00
w0rp
db835fa0a1 Make some corrections in the README 2017-02-08 22:25:08 +00:00
w0rp
325fcc25dd #314 Use the quickfix list for jumping between errors if that is set instead of the loclist 2017-02-08 22:14:07 +00:00
w0rp
eb37d9c1fc #39 Don't send the Vim buffer to commands before the last in a chain 2017-02-08 09:37:22 +00:00
w0rp
df2c6df819 Add a test to cover sign placement after linting 2017-02-07 22:55:23 +00:00
w0rp
c3ebe7bd9e Cover the Rust handler with some tests 2017-02-07 21:17:10 +00:00
Joshua Rubin
472631573e try fixing go build (#297)
* try fixing go build

* cache some system calls

* fix /dev/null

* use chained commands, use `go test -c` instead of `go tool compile`

* fix some unescaped shell commands

* fix a bug with explicitly setting GOPATH

* implement changes requested in code review. handle errors from multiple files. fix issue when starting a new package

* run `go env` as a job

* ensure all functions return the proper type

* fix loclist line numbers in some cases

* remove multibuffer support for now
2017-02-07 20:36:04 +00:00
w0rp
c0ac393297 #256 Attempt to fix Rust linter issues again 2017-02-07 15:19:37 +00:00
w0rp
da8408501c #256 Attempt to fix Rust linter issues 2017-02-07 15:15:22 +00:00
w0rp
a3b7056cad #289 Only use the --stdin-display-name flag if the flake8 version supports it 2017-02-06 11:12:27 +00:00
w0rp
a9a76241ac Merge pull request #307 from yous/rubocop-comment
Update comments for RuboCop pattern
2017-02-06 09:59:20 +00:00
w0rp
ccf78c40b1 Merge pull request #305 from notkild/master
Fix rust linting with cargo when multiple targets are present
2017-02-06 09:34:27 +00:00
notkild
0143eb6a53 Fix rust linting with cargo when multiple targets are present 2017-02-06 09:21:06 +01:00
Chayoung You
6f40cdca65 Update comments for RuboCop pattern 2017-02-06 15:13:13 +09:00
w0rp
9d85590421 Take the rubocop filename from the buffer number given to the function 2017-02-05 22:32:38 +00:00
w0rp
0a14bbe78d Merge pull request #299 from derekprior/dp-fix-rubocop-again
Fix Rubocop filename handling
2017-02-05 22:31:43 +00:00
w0rp
744d7d789f Merge pull request #294 from tpict/master
Add vint support for Neovim commands
2017-02-05 15:58:15 +00:00
w0rp
eb410b4ee6 Update the contributing guide to offer some more advice 2017-02-05 15:55:50 +00:00
w0rp
9a5fc6f932 Make a note in the FAQ about how to use quickfix errors 2017-02-05 15:34:35 +00:00
w0rp
d953c68ebb Fix mypy error parsing when column numbers are included. 2017-02-04 19:47:37 +00:00
w0rp
829f87bc6a Fix #124 Finish implementing command chaining, and make it work for DMD 2017-02-04 18:30:30 +00:00
Derek Prior
f2fc7072b9 Fix Rubocop filename handling
In my previous change, I updated the Rubocop linter to pass the filename
to Rubocop. This change was tested on a file I expected Rubocop to
ignore and the experience in vim was as I expected. However, I soon
found that ALE wasn't finding errors in files that should not be
ignored. After investigation, I found a few issues that this commit
fixes:

1. We were not properly passing the current filename. We now use
   `expand` to get the filename.
2. The regular expression used in the callback was expecting the static
   value of `_` for the filename in output. We now use a looser regular
   expression that begins matching on the first `:`.
3. The linter was defined statically. By using the current filename when
   defining the command the linter would always use the filename of the
   first Ruby file the user opened. We now use a `command_callback` to
   inject the proper filename.

I tested these changes on a configuration with included and excluded
files and found it to work as I expected. Apologies for the earlier
incorrect change.
2017-02-03 16:03:52 -05:00
w0rp
97131262ab Add a default alias for the Dockerfile filetype, which is capitalised for some users. 2017-02-02 22:26:46 +00:00
tpict
32c8d02d62 Add --enable-neovim flag to vint when appropriate 2017-02-02 19:48:18 +00:00
w0rp
512b6e00d9 Merge pull request #284 from EinfachToll/fix-gcc-command
Tell gcc to use C, not C++, when linting C source files
2017-02-01 10:46:06 +00:00
EinfachToll
e8123b3d5e Tell gcc to use C, not C++, when linting C source files
A regression bug introduced with PR #232
Ref #278
2017-02-01 11:22:21 +01:00
Łukasz Jan Niemier
a1458e9c07 Dockerfile linting via hadolint (#282)
* Add hadolint linter for Dockerfiles

* Fix path

* Fix typo

* Update docs
2017-01-30 15:27:26 +00:00
w0rp
03bab835d9 Fix #249 Mention how to clear sign background colors in the README 2017-01-30 15:22:14 +00:00
w0rp
aff56e69a9 Merge pull request #281 from derekprior/dp-fix-rubocop
Enable Rubocop to exclude files based on config
2017-01-30 15:04:09 +00:00
Derek Prior
a82ead0dc1 Enable Rubocop to exclude files based on config
When using `--stdin`, Rubocop requires that you also pass the associated
file name. ALE was previously passing `_` as the filename. By passing
the actual relative path to the file and enabling the
`--force-exclusion` option, we can get Rubocop to respect excluded files
in the configuration.

Closes #197
2017-01-27 16:29:58 -05:00
DiscoViking
a9c650cd05 Add ALEInfo command to get list of available/enabled linters (#273)
* Add ALEInfo command to get list of available/enabled linters for current filetype

* Add Vader tests for ALEInfo command

* Fix ALEInfo tests breaking CI by echoing too much output to screen

* Speculative change to Makefile which seems to fix test hanging problem locally.

* Fix Vader tests to not require a TTY
2017-01-24 15:50:49 +00:00
w0rp
fd89da113d Document the new quickfix and loclist options. 2017-01-22 15:31:28 +00:00
w0rp
b2696b105a Sort the global options in the documentation by name. 2017-01-22 15:06:33 +00:00
w0rp
d7ed49f849 Add a script for custom checks to enforce using the abort flag for functions and trailing whitespace, and fix existing issues. 2017-01-22 14:54:57 +00:00
w0rp
e4a4fcd26b Make the Erlang linter code match the style used in the rest of the codebase. Make the options match the new standard. 2017-01-22 13:51:57 +00:00
Magnus
cae153b3ac Add erlc lint for Erlang (#248) (#255)
* Add erlc lint for Erlang (#248)

* Ignore certain errors in Erlang .hrl files (#248)

A .hrl file does not need to have a -module definition. Additionally, it
is common to have unused elements in such a file, as the entities will
be used in a file including the header.

* Address change requests to Erlang linter
2017-01-22 13:42:18 +00:00
EinfachToll
23f8e7ddc5 Fix parsing of currently shown signs with Spanish locale (#268)
* Fix parsing of currently shown signs with spanish locale

* Add a test for parsing of Spanish signs
2017-01-22 13:40:23 +00:00
w0rp
a37970facd Clean up the list opening tests 2017-01-22 13:33:16 +00:00
yfery
a23173eeb2 Add option to open loclist/quicklist when there are errors (#266)
* Add option to open loclist/quicklist when there are errors

I copied PR #137, and tries to complete it by correcting some issues and
adding vader tests.

About tests, first time with vader, can you give some feedback if there
are what you expected in PR #137.

* Remove old code + fix indent issue

* add g:ale_keep_list_window_open option

* Correct bug with keep open option

* Add comment into vader file

* Fix errors for Travis CI build
2017-01-22 12:57:05 +00:00
w0rp
9820899b9e Improve mypy handling a little bit more 2017-01-20 17:30:34 +00:00
w0rp
ea438be5c1 REVERT "Fix some naming conventions and use abort for all Rust functions, and disable the rust linters for now, re #256"
This reverts commit f412b4f96f.

Conflicts:
	doc/ale.txt
2017-01-19 20:21:54 +00:00
EinfachToll
831f783493 Join the lines Neovim passes to ale (#263)
* Join the lines Neovim passes to ale

Fixes #256

* Refactor line joining into own function

* Add test for line joining

* Fix the test. Sorry.
2017-01-19 20:01:51 +00:00
w0rp
2478d7d925 Merge pull request #262 from KenjiTakahashi/fix_swiftlint
Fix SwiftLint
2017-01-19 13:23:46 +00:00
w0rp
1560f4ce03 Merge pull request #265 from aswins/mypy_fix
Fix using variable g:ale_python_mypy_options that was not defined
2017-01-18 10:35:52 +00:00
Aswin
d45505e135 Fix using variable g:ale_python_mypy_options that was not defined 2017-01-18 16:01:36 +05:30
KenjiTakahashi
62b492c727 Fix SwiftLint
1. Should be defined for 'swift' files, not 'swiftlint'.
2. Use `--use-stdin` option instead of the stdin-wrapper.
2017-01-17 19:59:45 +01:00
w0rp
41686980fd Document the mypy options, and fix spacing issues, largely in the documentation 2017-01-15 13:20:23 +00:00
w0rp
35bdd6f478 Merge pull request #237 from keith/ks/mypy-linter
Add python mypy support
2017-01-15 13:05:37 +00:00
w0rp
f1ac7c9f73 Rename pylint _args variables to _options variables 2017-01-15 13:05:07 +00:00
w0rp
548ff299f4 Merge pull request #243 from SabatierBoris/master
Add options for pylint linter
2017-01-15 13:02:51 +00:00
Junfeng Li
8762a6fa66 Support C# linting with mono compiler mcs. (#250)
* Support netcore project linting.

* Support check on the fly.

* Remove debug.

* Rename csc.vim to mcs.vim as it should be.

* Update README.

* Update doc.

* Using `=~#` instead of `=~`.
2017-01-15 12:42:17 +00:00
Masahiro H
74e7a283c0 Improve Verilator support (#205) (#258)
* improve-verilator-support

* fix for linter
2017-01-15 12:39:13 +00:00
SABATIER Boris
dc8166384c Add doc for pylint options 2017-01-13 11:04:29 +01:00
SABATIER Boris
0a9f9c0811 Add executable and arguments options for pylint linter 2017-01-13 10:59:39 +01:00
w0rp
f412b4f96f Fix some naming conventions and use abort for all Rust functions, and disable the rust linters for now, re #256 2017-01-13 09:23:03 +00:00
w0rp
3b486d3475 Prefix mandatory flake8 arguments with extra spaces so they will always work 2017-01-12 13:11:10 +00:00
w0rp
9191750b5b Fix #175 - Fix the error types for rubocop 2017-01-12 12:57:07 +00:00
EinfachToll
9c5f092b4f Add support for Rust using rustc and cargo (#230)
* Add rustc checker for rust files

* Add documentation for rustc

* Use a nice helper function

* Add cargo as linter

* Complete the doc for rust linters

* Put l: in front of every local variable

* Apply the requested stylistic changes
2017-01-12 09:33:55 +00:00
w0rp
75485d53f6 Merge pull request #245 from zefei/add-eslint-options
Add eslint option to pass in more options
2017-01-12 09:28:06 +00:00
Zefei Xuan
2c176a234e added eslint option to pass in more options 2017-01-05 00:28:32 -08:00
Zefei Xuan
5a0c3fd01e Added hack linter for php (#239)
* added hack linter

* updated docs for hack (hh_client)

* naming
2017-01-04 17:07:21 +00:00
w0rp
ed43b17201 Merge pull request #244 from icgood/fix-perlcritic-typo-exception
Fix typo in perlcritic linter dictionary
2017-01-04 13:10:35 +00:00
w0rp
c17123b631 Fix #238 Make the README show the proper linter name for Flow 2017-01-04 13:05:17 +00:00
w0rp
c9b58136bf Merge pull request #236 from Chronial/patch-1
Pass file name to flake8
2017-01-04 12:57:40 +00:00
w0rp
871c09c123 Merge pull request #235 from still-dreaming-1/fix-php-generic-error
Fix PHP lint generic error without line number
2017-01-04 12:54:54 +00:00
Ian Good
c97ad01bcb Fix typo in perlcritic linter dictionary
The linter validation logic was checking for `stdout`, `stderr`, or
`both`, resulting in an exception being thrown when loading the
perlcritic linter.
2017-01-03 14:55:23 -05:00
Keith Smiley
4566bd65c9 Add python mypy support
This adds support for the official optional python typechecker.
2016-12-30 16:12:30 -08:00
Chronial
e0928d0991 Pass file name to flake8 2016-12-30 17:06:49 +01:00
still-dreaming-1
2b251a2cee Fix PHP lint generic error without line number
This makes php output more specific error messages. The format is the normal one ALE expects, but on some systems ALE does not work with PHP unless the display_errors=1 option is used. Without that option php will only output a generic message without a line number like "Errors parsing index.php"
2016-12-28 11:10:47 -07:00
w0rp
3e1486fc92 Merge pull request #233 from LubergAlexander/master
Fixed a typo scss -> sass
2016-12-26 16:47:02 +00:00
Alexander Luberg
14aff89fb2 Fixed a typo scss -> sass 2016-12-26 08:35:22 -08:00
w0rp
fcfd8d5f56 Merge pull request #232 from grzebiel/master
Added ability to reload compilation flags for c and c++
2016-12-26 13:28:43 +00:00
w0rp
12e99489b2 Merge pull request #231 from fannheyward/master
Redirect go build output to /dev/null
2016-12-26 13:27:46 +00:00
grzebiel
9767fd8732 Added ability to reload compilation flags for c and c++ after loading plugin 2016-12-24 00:18:14 +01:00
Heyward Fann
e46ef0ae19 Redirect go build output to /dev/null
Named file file will be created after ALE, this can redirect the output to /dev/null if go build failed.
2016-12-23 14:56:44 +08:00
dzhou121
55827a9493 add go build for build errors (#180)
* add go build for build errors

* Add go build to doc and README

* Improvement for Go build

Go build works on package level, so copy over the other files
that belong to the same package to the temp folder as well.

* revert back to simple go build

* change gobuild script var name
2016-12-22 12:10:21 +00:00
diartyz
6c0996eb9c [enhancement] add node_modules support for stylelint & htmlhint (#226)
* Add node_modules support for stylelint

* add node_modules support for htmlhint

* fix stdin

* update doc about stylelint & htmlhint
2016-12-22 11:39:01 +00:00
w0rp
cd6d8f2ab6 Fix #229 Disable text linters by default 2016-12-22 11:32:20 +00:00
w0rp
771bfe3b18 #193 Fix a parsing error for parsing errors with eslint 2016-12-22 11:16:22 +00:00
Eric Lehner
bda6df61a0 Elm file filter & Windows bug fixes (#223)
* Filters out unrelated errors in Elm linter

The function now filters out errors that are unrelated to the file,
those that were found in imported modules.

It does this by comparing the temp directory environment variable to the
file name in the elm output. If the file begins with the temp directory,
then it sould be included (it's from the buffer).

* Changing output to '/dev/null'

Turns out the compiler only accepts /dev/null as an ignorable name. It's
hard-coded here
https://github.com/elm-lang/elm-make/blob/master/src/Flags.hs

Changing this allows Windows linting to work. Otherwise the compiler
errors when using "nul"

* Fixes for Windows

Should now be able to successfully handle Windows.

Windows seemed to not handle the ";" properly, so I switched it to "&&",
which probably should've been done anyway to prevent false positives.

Oddly, matchend(l:error.file, l:temp_dir), and various other regex
solutions, couldn't properly match the two. Subsetting did though, hence
the new solution.

* Applying corrections

Made the file check case-insensitive for Windows, case-sensitive for
Unix/non-windows.

Added comment explaining hard coding of 'dev/null'

* Spelling correction

* Minor corrections

Actually uses the is_file_buffer variable now, added space between the
if statements, and added space between '-'
2016-12-16 10:41:21 +00:00
w0rp
8cb9b2ba4e Make sign parsing testable, and add tests for it against various languages. 2016-12-16 10:01:28 +00:00
w0rp
7e6d5292f7 Merge pull request #224 from cympfh/master
Fix: sign pattern
2016-12-16 09:33:52 +00:00
cympfh
8df2444ec4 Fix: sign pattern 2016-12-15 13:57:26 +09:00
w0rp
4ad5c4757c Merge pull request #221 from rob-b/improve-formatting-of-haskell-linters
Improve formatting of ghc and hlint haskell linters
2016-12-14 19:13:19 +00:00
w0rp
54b55bb39c Merge pull request #222 from justinmk/fixfuncref
Nvim: pass functions as funcrefs
2016-12-14 19:09:56 +00:00
Justin M. Keyes
1ae851878a Nvim: pass functions as funcrefs
neovim/neovim#5529 merged support for Vim's partial functions, which
made nvim more strict about dictionary functions and callbacks, to
match Vim behavior.
2016-12-14 17:40:45 +01:00
Rob Berry
0ffef758ae Improve formatting of ghc and hlint haskell linters
For ghc, it seemed that the conditional

```
if l:corrected_lines[-1] =~# ': error:$'
    let l:line = substitute(l:line, '\v^\s+', ' ', '')
endif
```

was never being reached. It's actually better to unconditionally
collapse whitespace anyway and so I simply removed the conditional
check.

For hlint I added more information about the error. This changes the
reported error from `Error:` to something like:
` Error: Avoid lambda. Found: \ x -> foo x Why not: foo`
2016-12-14 12:50:14 +00:00
David Mohundro
3418faf054 Add support for Swift with swiftlint (#214)
* Add support for swift with swiftlint

* Fix issue by adding '.swift' file extension
2016-12-13 15:28:20 +00:00
w0rp
10777d3421 Add tests to cover definitions for linters so far. 2016-12-13 13:33:19 +00:00
w0rp
f950c29035 Implement command chaining. Tests and documentation to come. 2016-12-13 10:19:56 +00:00
w0rp
88f4598ea2 Fix the proeslint linter for plaintext files 2016-12-13 10:19:19 +00:00
w0rp
76a03b0709 Add a Batch stdin wrapper script 2016-12-13 10:00:40 +00:00
Eric Lehner
70e379cc46 Add Elm linting via elm-make (#213)
* Add support for Elm linting

* Adding documentation for Elm

* Adjusting spacing

* Addressing concerns listed in pull request

Removed the s:FindRootDirectory function as it does not make much sense
in this context. Adjusted the rest of the code to handle the removal of
that function, including using the ale#util function to find the nearest
file.

Ensured that when an empty filepath is found, the code does not attempt
to change directories.

Ensured that the linter would take from stdin using the wrapper.
2016-12-13 09:06:04 +00:00
w0rp
25f6445c50 Merge pull request #210 from apuignav/error-cpp
Catch g++ fatal error
2016-12-08 09:05:36 +00:00
Albert Puig
b5013ba54b Catch g++ fatal error 2016-12-08 09:32:57 +01:00
w0rp
815be12649 Merge pull request #209 from apuignav/ignore-pylint
Skip I0011 messages in pylint.
2016-12-07 22:57:12 +00:00
Albert Puig
88c203b686 Skip I0011 messages in pylint.
Ignore 'Locally disabling %s' messages from pylint.
2016-12-07 23:54:41 +01:00
w0rp
aee339f401 Document the new stylelint linter 2016-12-06 13:26:06 +00:00
w0rp
d5c626667e Merge pull request #207 from diartyz/master
[new linter] add stylelint support
2016-12-06 13:22:47 +00:00
diartyz
725957de6e add stylelint support 2016-12-06 21:14:14 +08:00
w0rp
1a749a6b43 Merge pull request #201 from kyrisu/fix-proper_extension_handling_for_tslint
Fix proper extension handling for tslint
2016-12-05 11:14:08 +00:00
Krystian Paszkiewicz
ff8f3673eb Fix proper extension handling for tslint 2016-12-05 08:42:00 +00:00
w0rp
d77e5a9308 #200 Make systemverilog files use the verilog linters by default 2016-12-04 23:13:57 +00:00
Andrew Balmos
35307c0585 LaTeX Linters (#190)
* Add chktex linter

* Alias plaintex to tex

* Add lacheck linter

Closes #179

* Add the chktex warning code

This very useful to have when you want to suppress lint warnings with LaTeX
comments. chktex tends to be a bit noisy so this often needed.

* lacheck: Make regex less specific

To be more robust future changes in `stdin-wrapper`
2016-12-04 22:19:06 +00:00
kyrisu
bbdff82aee Add support for tslint.json file detection in tslint (#198)
* Add support for tslint.json file detection in tslint

* Fix tslint.json path building for tslint
2016-12-04 22:17:22 +00:00
w0rp
3a1caca907 Merge pull request #195 from mortonfox/rubocop-options
Add options variable for ruby-rubocop
2016-12-02 09:18:18 +00:00
Po Shan Cheah
5636626da1 Add options variable for ruby-rubocop 2016-12-01 12:28:27 -05:00
w0rp
f5a4e11894 Add an FAQ section describing how to run linters when files are saved. 2016-12-01 09:52:43 +00:00
w0rp
66b183e1ba Fix #188: Revert to and older version of the Haskell linter, which works better 2016-11-28 09:53:07 +00:00
poohzrn
900b4cdff3 Add Proselint (#185)
* Add Proselint
- Markdown
- Tex
- Text

* Use ale#handler#HandleUnixFormatAsWarning

* Indentation
2016-11-28 09:36:11 +00:00
Alexander "Ace" Olofsson
e03df80a09 Add puppet linters (#183)
* Start adding Puppet linters

* Use the correct output stream for puppet parser

* Finish Puppet and puppet-lint linters

* Add Puppet information to documentation
2016-11-25 12:00:07 +00:00
w0rp
da37989960 Merge pull request #186 from poohzrn/patch-1
Fix links to handlers.vim
2016-11-25 11:53:26 +00:00
poohzrn
10bacf0996 Fix links to handlers.vim 2016-11-24 20:19:24 +01:00
Andrey Popp
f7e6236fe8 Add ocaml linter: merlin (#177)
* Add ocaml linter: merlin

* Add docs for ocaml-merlin integration.

* Remove annoying error message from ocaml merlin linter

* Update doc to list merlin linter
2016-11-23 15:19:36 +00:00
Andrey Popp
d700da8cb8 Flow linter improvements (#176)
* Fix flow linter to provide filename of the buffer

Related #173

* Fix flow linter not to fail on empty response

* Various improvement to message parsing
2016-11-21 09:53:18 +00:00
Marius Gedminas
713a6910d4 Add g:ale_python_flake8_executable (#174)
* Add g:ale_python_flake8_executable

Closes #172.

* Add g:ale_python_flake8_args

* Always add - to flake8 invocations
2016-11-14 17:52:31 +00:00
w0rp
498a9435de Document that typecheck is now supported 2016-11-10 16:24:17 +00:00
w0rp
7669550ae2 Merge pull request #170 from mkusher/typescript_typecheck_linter
Add typecheck linter for typescript
2016-11-10 16:20:28 +00:00
Aleh Kashnikau
0a3faa60f7 removed useless echom from typecheck.vim 2016-11-10 18:48:09 +03:00
Aleh Kashnikau
2e5f3899d1 Add typecheck linter for typescript 2016-11-10 18:41:02 +03:00
w0rp
ccc08d08f6 Merge pull request #164 from delianides/master
flow linting should only happen on flow typed files.
2016-11-05 21:02:59 +00:00
purpleP
60b89abd9c changed while read -r loop to cat > for portability and simplicity (#165)
* changed while read -r loop to cat > for portability and simplicity

* typo fix
2016-11-05 20:43:57 +00:00
w0rp
ec2845eefa Take sign information out of the buffer variables, and make it so dummy signs are set and removed more reliably. 2016-11-04 11:58:56 +00:00
w0rp
ca18a80e3e #159 Change the condition for checking for Vim 8 features to work better in MacVim 7. 2016-11-04 10:17:49 +00:00
delianides
8d5353831e flow linting should only happen on flow typed files. 2016-11-03 15:51:49 -04:00
w0rp
f9cbc69ce1 Re-align documentation markers. 2016-11-03 10:17:25 +00:00
w0rp
175db78f35 Merge pull request #162 from mshr-h/fix-document
Fix docment for c-clang
2016-11-02 09:08:58 +00:00
Masahiro H
8ba5b3cb76 Update ale.txt 2016-11-02 15:19:24 +09:00
mshr-h
afa37e6855 Fix docment for c-clang 2016-11-02 15:16:42 +09:00
w0rp
5b8410f868 Merge pull request #156 from edwlarkey/add_foodcritic
Added support for foodcritic
2016-11-01 20:44:25 +00:00
Edward Larkey
8632e6b4e0 Added support for foodcritic
Adding support the foodcritic linter for Chef files.
Listing all issues as warnings for now
Doesn't get in the way of rubocop linting if ft=ruby.chef
Updated documentation

Closes #127
2016-11-01 15:36:08 -05:00
w0rp
f03fb64e51 #160 Switch back to using readline for writing stdin to the temporary file, because it actually works on all machines. 2016-11-01 20:30:15 +00:00
Zach Perrault
4088347901 Add FlowType support (#157)
* Add `javascript/flow` linter

* Add documentation for flow

* Remove a line from the docs that was from eslint

* Only run if flow gives output; Correct link in doc

* Address PR feedback #157
2016-11-01 09:00:08 +00:00
w0rp
614a30a508 Improve file blacklisting to make Unite.vim not fuck up. 2016-10-31 14:47:08 +00:00
w0rp
cb410927d1 Reduce sign column juttering by waiting for all jobs to complete before updating everything. 2016-10-31 13:45:22 +00:00
w0rp
f44756f347 Merge pull request #158 from mshr-h/support-clang-for-c
Add support for clang for C language
2016-10-31 10:58:40 +00:00
mshr-h
e3a8829d67 Add support for clang for c 2016-10-31 14:38:13 +09:00
w0rp
9028d1f132 Add pylint to the list of supported tools. 2016-10-30 09:47:06 +00:00
w0rp
a6ca60203f Increase the delay for linting on entering a buffer. 2016-10-30 09:29:11 +00:00
w0rp
629e6a3675 Merge pull request #153 from keith/ks/shellcheck
Choose shell dialect based on vim syntax
2016-10-30 09:24:39 +00:00
w0rp
c4ab4855b7 Merge pull request #155 from deathmaz/feature/htmlhint-args
Added options variable for htmlhint
2016-10-30 09:21:55 +00:00
w0rp
8bee64d1b7 Update the documentation to match the code 2016-10-30 09:21:34 +00:00
w0rp
e9bbbbdf3e Merge pull request #151 from keith/ks/pylint
Add pylint formatter
2016-10-30 09:20:02 +00:00
deathmaz
9a4645fc7f Default stdin in htmlhint options 2016-10-28 12:42:55 +03:00
Keith Smiley
5fc2f8f6c0 Choose shell dialect based on vim syntax
Shellcheck is smart enough to check the shebang in a given file to
determine which dialect to use. Unfortunately this doesn't work for
files without shebangs, even if it might be apparent what dialect should
be used, such as "bashrc" or "foo.bash". Luckily `filetype.vim` defines
specific vars based on which shell dialect is being used based on a huge
list of conditions. With this change we take those into account for all
the types shellcheck supports, otherwise we fallback to letting it try
and decide.
2016-10-27 18:46:58 -07:00
Keith Smiley
86cc2aab71 Add pylint formatter
This customizes the output format of pylint in order to use the same
pep8 parser
2016-10-27 18:38:26 -07:00
deathmaz
5b56103c69 Added optoins variable for htmlhint 2016-10-27 18:31:49 +03:00
w0rp
c8821fc049 #144 - Implement commands for moving through warnings/errors 2016-10-26 10:36:53 +01:00
w0rp
1bcee7ef33 Mention the Google Vimscript Style Guide in the contributing file. 2016-10-25 17:41:34 +01:00
w0rp
454dbbe33e Merge remote-tracking branch 'origin/echo-less' 2016-10-25 16:51:50 +01:00
w0rp
aa4c669ea0 #148 - Check the cursor position so we don't try to echo too frequently. 2016-10-25 16:07:20 +01:00
w0rp
60762d5018 Merge pull request #143 from w0rp/better-buffer-cleanup
Stop jobs when buffers close
2016-10-25 16:02:47 +01:00
w0rp
222d9e6908 Fix the autocmd suggestion some more 2016-10-25 15:46:18 +01:00
w0rp
9a019e2342 Fix a mistake in the FAQ code for the autocmd event 2016-10-25 15:01:10 +01:00
w0rp
73c9a1f965 #148 Do not run ALE for NERDTree or Unite.vim buffers. 2016-10-25 14:09:58 +01:00
w0rp
0fbf7bcc99 Fix the headings and table of contents. 2016-10-25 10:44:50 +01:00
w0rp
2bcb21f350 Restructure the README. 2016-10-25 10:39:06 +01:00
w0rp
d6a7b0f518 #119 - Stop ALE clearing the echo message when it doesn't need to. 2016-10-24 20:55:20 +01:00
w0rp
b9428b7db0 Merge #139 - Add Markdown linting support 2016-10-24 20:40:24 +01:00
Alex Layton
95373ddab5 Add support for mlint, a MATLAB linter (#145)
* Add support for mlint, a MATLAB linter

* Fix mlint linter as requested

* Clean up leftover loaded flag for mlint
2016-10-24 20:32:52 +01:00
w0rp
6e66b60b63 Limit Travis to only building master on push. 2016-10-24 20:27:36 +01:00
w0rp
79552872f3 Merge pull request #142 from w0rp/use-local-jshint-program
Add node_modules support for JSHint, and use the global config as a fallback
2016-10-24 20:23:15 +01:00
w0rp
c546f47cc0 Merge everything into the one global map. 2016-10-24 20:21:42 +01:00
w0rp
0dbf08f6d5 Add some comments to some lines to make things clearer. 2016-10-24 09:58:45 +01:00
w0rp
7481facd73 #107 Stop jobs when buffers close 2016-10-23 22:41:00 +01:00
w0rp
226b4ed586 Add node_modules support for JSHint, and use the global config as a fallback. 2016-10-23 13:25:50 +01:00
w0rp
36461b69d7 Support loading eslint from node_modules, re issue #118. 2016-10-23 13:04:41 +01:00
w0rp
f94865c4ce Merge pull request #140 from neersighted/cleanup
Clean up some test filenames and extraneous code
2016-10-23 10:41:58 +01:00
Bjorn Neergaard
dc99282f79 Clean up some test filenames and extraneous code 2016-10-22 08:53:28 -05:00
w0rp
89d8f2a0bc Merge pull request #138 from neersighted/dotft
Add support for dot-seperate linters, improve linter tests
2016-10-22 14:35:13 +01:00
Bjorn Neergaard
99aebcafac Docs! 2016-10-22 08:31:29 -05:00
w0rp
cd00a18c3a Make builds fail again when there are Vint warnings. 2016-10-22 14:20:05 +01:00
Łukasz Jan Niemier
e293e0b5ab Use cat instead of read -r to stream stdin to file (#120)
* Use `cat` instead of `read -r` to stream stdin to file

* Cleanup dmd-wrapper

* Fix typo

* Make wrapper work on macOS

* Use fifo instead of temporary file

* Fix stdin-wrapper

* Use `awk` instead of `read` hackery

* Finish refactoring

* Fix `exec` issue

* Add myself as an coauthor of wrapper scripts (no shame at all :P)

* Fix dmd-wrapper

* Extract check_dubfile
2016-10-22 13:52:49 +01:00
Bjorn Neergaard
f49f615ef6 Add support for dot-seperate linters, improve linter tests
This PR first and formost implements support for dot-seperate filetypes,
a very trivial change.

This closes #132

But more importantly, this PR vastly improves the test quality for
`ale#linter#Get`. It enables us to reset the state of ale's internal
linter cache, to facilitate better testing, as well as making use of
mocked linters instead of depending on linters on disk (which may
change). In addition, a dummy linter is defined to test the autoloading
behavior.

Header guards were removed from all linters as:

* A: ale won't try and load linters if they already exist in memory
* B: we can't reset state for testing if they can't be loaded again
2016-10-21 21:02:20 -05:00
w0rp
216eadbcbe Merge pull request #133 from ehzShelter/master
Added c++14 standard support and POSIX API compile time linker flags and ISO c++14 atomic and thread library support…
2016-10-21 18:08:25 +01:00
ehzShelter
1e83489691 make it less verbose for c and cpp 2016-10-21 20:02:20 +06:00
w0rp
5eee70cf37 Merge pull request #129 from neersighted/ansible
Add ansible-lint support and factor out PEP8 handler
2016-10-21 09:21:50 +01:00
ehzShelter
ce3d79550d Added c++14 standard support and POSIX API compile time linker flags for avoiding annoying errors and warnings 2016-10-21 13:07:51 +06:00
Bjorn Neergaard
c697ef05bb Add PEP8 handler test. 2016-10-20 22:52:25 -05:00
w0rp
7a06d276c2 #131 Keep the error types in the message for eslint 2016-10-20 18:07:55 +01:00
Bjorn Neergaard
a2e4af1626 Document ansible-lint 2016-10-20 09:27:57 -05:00
Bjorn Neergaard
c34664120b Add ansible-lint support and factor out PEP8 handler 2016-10-20 09:23:23 -05:00
Bart Libert
a34fb0a6a7 Add support for cppcheck (#126)
* Add support for cppcheck

* Fix vint error in cppcheck handler

* Add vader test for CppCheck format handler
2016-10-20 12:30:45 +01:00
w0rp
acb209aa11 Fix the D error parsing to handle output without column numbers. 2016-10-19 23:42:00 +01:00
w0rp
6df632218e Add a test which checks that we can find the stdin-wrapper script. 2016-10-19 23:26:07 +01:00
122 changed files with 4855 additions and 1052 deletions

1
.gitattributes vendored
View File

@@ -5,3 +5,4 @@
/README.md export-ignore
/img export-ignore
/test export-ignore
/custom-checks export-ignore

View File

@@ -2,6 +2,9 @@
sudo: required
services:
- docker
branches:
only:
- master
language: python
script: |
make test

View File

@@ -1,8 +1,10 @@
# Contributing to ALE
1. [Guidelines](#guidelines)
2. [Creating Pull Requests](#pull-requests)
3. [Creating Pull Requests](#compiling)
2. [Creating Issues](#issues)
3. [Creating Pull Requests](#pull-requests)
1. [Adding a New Linter](#adding-a-new-linter)
2. [Adding New Options](#adding-new-options)
<a name="guidelines"></a>
@@ -10,16 +12,44 @@
Have fun, and work on whatever floats your boat. Take It Easy :tm:.
When writing code, follow the [Google Vimscript Style
Guide](https://google.github.io/styleguide/vimscriptguide.xml), and run `vint
-s` on your files to check for most of what the guide mentions and more. If you
install this plugin (ALE) and install [Vint](https://github.com/Kuniwak/vint), it
will check your code while you type.
<a name="issues"></a>
# 2. Creating Issues
Before creating any issues, please look through the current list of issues and
pull requests, and ensure that the issue hasn't already been reported. If an
issue has already been reported, but you have some new insight, please add
a comment to the existing issue.
Please read the FAQ in the README before creating any issues. A feature
you desire may already exist and be documented, or the FAQ might explain
how to solve a problem you have already.
Please try and describe any issues reported with as much detail as you can
provide about your Vim version, the linter you were trying to run, your
operating system, or any other information you think might be helpful.
Please describe your issue in clear, grammatically correct, and easy to
understand English. You are more likely to see an issue resolved if others
can understand you.
<a name="pull-requests"></a>
# 2. Creating Pull Requests
# 3. Creating Pull Requests
For code you write, make sure to credit yourself at the top of files you add, and probably those you modify. You can write
some comments at the top of your VIM files.
For code you write, make sure to credit yourself at the top of files you add,
and probably those you modify. You can write some comments at the top of your
VIM files.
```vim
" Author: John Smith <john.smith@gmail.com>
" Description: This file adds support for awesomelinter to the best language ever.
" Description: This file adds support for awesomelinter for the best language ever.
```
If you want to credit multiple authors, you can comma separate them.
@@ -28,34 +58,35 @@ If you want to credit multiple authors, you can comma separate them.
" Author: John Smith <john.smith@gmail.com>, Jane Doe <https://jane-doe.info>
```
# 2.1. Adding a New Linter
<a name="adding-a-new-linter"></a>
If you add a new linter, look for existing handlers first in the [handlers.vim](plugin/ale/handlers.vim) file. One of the handlers
there may already be able to handle your lines of output. If you find that your new linter replicates an existing error handler,
consider pulling it up into the [handlers.vim](plugin/ale/handlers.vim) file, and use the generic handler in both places.
# 3.i. Adding a New Linter
When you add a linter, make sure the language for the linter and the linter itself are present in the table in the
[README.md](README.md) file and in the Vim [help file](doc/ale.txt). The programs and linters are sorted alphabetically in the
table and list.
If you add a new linter, look for existing handlers first in the
[handlers.vim](autoload/ale/handlers.vim) file. One of the handlers there may
already be able to handle your lines of output. If you find that your new
linter replicates an existing error handler, consider pulling it up into the
[handlers.vim](autoload/ale/handlers.vim) file, and use the generic handler in
both places.
# 2.2. Adding New Options
When you add a linter, make sure the language for the linter and the linter
itself are present in the table in the [README.md](README.md) file and in the
Vim [help file](doc/ale.txt). The programs and linters should be sorted
alphabetically in the table and list.
If you add new options to the plugin, make sure to document those new options in the [README.md](README.md) file, and also
in the [help file](doc/ale.txt). Follow the format of other options in each. Global options should appear in the README
file, and in the relevant section in the help file, and options specific to a particular linter should go in the section
for that linter.
<a name="adding-new-options"></a>
<a name="compiling"></a>
# 3.ii. Adding New Options
# 3. Compiling the Windows stdin wrapper
If you add new options to the plugin, make sure to document those new options
in the [README.md](README.md) file, and also in the [help file](doc/ale.txt).
Follow the format of other options in each. Global options should appear in the
README file, and in the relevant section in the help file. Options specific
to a particular linter should appear in the section for that linter.
To compile the stdin wrapper program for Windows, when updating the D program, you will need to compile the program with
[LDC](https://github.com/ldc-developers/ldc) in release mode. Download and install the Community edition of Visual Studio
from [the Visual Studio website](https://www.visualstudio.com/downloads/) first before installing LDC. LDC typically comes in
a ZIP you can just extract somewhere.
Linter options for customizing general argument lists should be named
`g:ale_<filetype>_<linter>_options`, so that all linters can have similar
global variable names.
Make sure to compile with the 32-bit architecture flag, otherwise the EXE will not run on 32-bit machines.
```
ldc2 -m32 -Oz -release stdin_wrapper.d -of=stdin-wrapper.exe
```
Any options for linters should be set to some default value so it is always
easy to see what the default is with `:echo g:ale...`.

View File

@@ -1,3 +1,4 @@
SHELL := /usr/bin/env bash
IMAGE ?= w0rp/ale
CURRENT_IMAGE_ID = 107e4efc4267
DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)"
@@ -25,8 +26,18 @@ test: test-setup
echo '========================================'; \
echo 'Vint warnings/errors follow:'; \
echo; \
set -o pipefail; \
docker run -a stdout $(DOCKER_FLAGS) vint -s /testplugin | sed s:^/testplugin/:: || EXIT=$$?; \
set +o pipefail; \
echo; \
echo '========================================'; \
echo 'Running custom checks'; \
echo '========================================'; \
echo 'Custom warnings/errors follow:'; \
echo; \
set -o pipefail; \
docker run -a stdout $(DOCKER_FLAGS) /testplugin/custom-checks /testplugin | sed s:^/testplugin/:: || EXIT=$$?; \
set +o pipefail; \
echo; \
exit $$EXIT;

305
README.md
View File

@@ -15,7 +15,28 @@ back to a filesystem.
In other words, this plugin allows you to lint while you type.
## Supported Languages and Tools
## Table of Contents
1. [Supported Languages and Tools](#supported-languages)
2. [Usage](#usage)
3. [Installation](#installation)
1. [Installation with Pathogen](#installation-with-pathogen)
2. [Installation with Vundle](#installation-with-vundle)
3. [Manual Installation](#manual-installation)
4. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters)
2. [How can I keep the sign gutter open?](#faq-disable-linters)
3. [How can I change the signs ALE uses?](#faq-change-signs)
4. [How can I show errors or warnings in my statusline?](#faq-statusline)
5. [How can I change the format for echo messages?](#faq-echo-format)
6. [How can I execute some code when ALE stops linting?](#faq-autocmd)
7. [How can I navigate between errors quickly?](#faq-navigation)
8. [How can I run linters only when I save files?](#faq-lint-on-save)
9. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
<a name="supported-languages"></a>
## 1. Supported Languages and Tools
This plugin supports the following languages and tools. All available
tools will be run in combination, so they can be complementary.
@@ -28,44 +49,61 @@ name. That seems to be the fairest way to arrange this table.
| Language | Tools |
| -------- | ----- |
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) |
| Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) |
| Bourne Shell | [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/) |
| C | [gcc](https://gcc.gnu.org/) |
| C++ (filetype cpp)| [gcc](https://gcc.gnu.org/) |
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
| C++ (filetype cpp) | [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
| Chef | [foodcritic](http://www.foodcritic.io/) |
| CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
| CSS | [csslint](http://csslint.net/) |
| CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) |
| Cython (pyrex filetype) | [cython](http://cython.org/) |
| D | [dmd](https://dlang.org/dmd-linux.html)^ |
| D | [dmd](https://dlang.org/dmd-linux.html) |
| Dockerfile | [hadolint](https://github.com/lukasmartinelli/hadolint) |
| Elixir | [credo](https://github.com/rrrene/credo) |
| Elm | [elm-make](https://github.com/elm-lang/elm-make) |
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
| Fortran | [gcc](https://gcc.gnu.org/) |
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint) |
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [go build](https://golang.org/cmd/go/) |
| Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint) |
| HTML | [HTMLHint](http://htmlhint.com/), [tidy](http://www.html-tidy.org/) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/) |
| JSON | [jsonlint](http://zaa.ch/jsonlint/) |
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck) |
| Lua | [luacheck](https://github.com/mpeterv/luacheck) |
| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/)|
| MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) |
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
| PHP | [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Python | [flake8](http://flake8.pycqa.org/en/latest/) |
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
| Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) |
| Ruby | [rubocop](https://github.com/bbatsov/rubocop) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint) |
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint) |
| Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
| Scala | [scalac](http://scala-lang.org) |
| TypeScript | [tslint](https://github.com/palantir/tslint) |
| Swift | [swiftlint](https://swift.org/) |
| Tex | [proselint](http://proselint.com/) |
| Text^^ | [proselint](http://proselint.com/) |
| TypeScript | [tslint](https://github.com/palantir/tslint), typecheck |
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
| Vim | [vint](https://github.com/Kuniwak/vint) |
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
*^ Supported only on Unix machines via a wrapper script.*
* *^^ No text linters are enabled by default.*
If you would like to see support for more languages and tools, please
[create an issue](https://github.com/w0rp/ale/issues)
or [create a pull request](https://github.com/w0rp/ale/pulls).
If your tool can read from stdin or you have code to suggest which is good,
support can be happily added for more tools.
support can be happily added for it.
## Usage
<a name="usage"></a>
## 2. Usage
Once this plugin is installed, while editing your files in supported
languages and tools which have been correctly installed,
@@ -74,32 +112,90 @@ programs for checking the syntax and semantics of your programs. By default,
linters will be re-run in the background to check your syntax when you open
new buffers or as you make edits to your files.
### Options
The behaviour of linting can be configured with a variety of options,
documented in [the Vim help file](doc/ale.txt). For more information on the
options ALE offers, consult `:help ale-options` for global options and `:help
ale-linter-options` for options specified to particular linters.
A full list of options supported for configuring this plugin in your
vimrc file for all given linters is as follows:
<a name="installation"></a>
| Option | Description | Default |
| ------ | ----------- | ------- |
| `g:ale_echo_cursor` | echo errors when the cursor is over them | `1` |
| `g:ale_echo_msg_format` | string format to use for the echoed message | `'%s'` |
| `g:ale_echo_msg_error_str` | string used for error severity in echoed message | `'Error'` |
| `g:ale_echo_msg_warning_str` | string used for warning severity in echoed message | `'Warning'` |
| `g:ale_lint_delay` | milliseconds to wait before linting | `200` |
| `g:ale_linters` | a dictionary of linters to whitelist | _not set_ |
| `g:ale_lint_on_enter` | lint when opening a file | `1` |
| `g:ale_lint_on_save` | lint when saving a file | `0` |
| `g:ale_lint_on_text_changed` | lint while typing | `1` |
| `g:ale_set_loclist` | set the loclist with errors | `1` |
| `g:ale_set_signs` | set gutter signs with error markers | `has('signs')` |
| `g:ale_sign_column_always` | always show the sign gutter | `0` |
| `g:ale_sign_error` | the text to use for errors in the gutter | `'>>'` |
| `g:ale_sign_offset` | an offset for sign ids | `1000000` |
| `g:ale_sign_warning` | the text to use for warnings in the gutter | `'--'` |
| `g:ale_statusline_format` | string format to use in statusline flag | `['%d error(s)', '%d warning(s)', 'OK']` |
| `g:ale_warn_about_trailing_whitespace` | enable trailing whitespace warnings for some linters | `1` |
## 3. Installation
### Selecting Particular Linters
To install this plugin, you should use one of the following methods.
For Windows users, replace usage of the Unix `~/.vim` directory with
`%USERPROFILE%\_vim`, or another directory if you have configured
Vim differently. On Windows, your `~/.vimrc` file will be similarly
stored in `%USERPROFILE%\_vimrc`.
<a name="installation-with-pathogen"></a>
### 3.i. Installation with Pathogen
To install this module with [Pathogen](https://github.com/tpope/vim-pathogen),
you should clone this repository to your bundle directory, and ensure
you have the line `execute pathogen#infect()` in your `~/.vimrc` file.
You can run the following commands in your terminal to do so:
```bash
cd ~/.vim/bundle
git clone https://github.com/w0rp/ale.git
```
<a name="installation-with-vundle"></a>
### 3.ii. Installation with Vundle
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
by using the path on GitHub for this repository.
```vim
Plugin 'w0rp/ale'
```
See the Vundle documentation for more information.
<a name="manual-installation"></a>
### 3.iii. Manual Installation
For installation without a package manager, you can clone this git repository
into a bundle directory as with pathogen, and add the repository to your
runtime path yourself. First clone the repository.
```bash
cd ~/.vim/bundle
git clone https://github.com/w0rp/ale.git
```
Then, modify your `~/.vimrc` file to add this plugin to your runtime path.
```vim
set nocompatible
filetype off
let &runtimepath.=',~/.vim/bundle/ale'
filetype plugin on
```
You can add the following line to generate documentation tags automatically,
if you don't have something similar already, so you can use the `:help` command
to consult ALE's online documentation:
```vim
silent! helptags ALL
```
Because the author of this plugin is a weird nerd, this is his preferred
installation method.
<a name="faq"></a>
## 4. FAQ
<a name="faq-disable-linters"></a>
### 4.i. How do I disable particular linters?
By default, all available tools for all supported languages will be run.
If you want to only select a subset of the tools, simply create a
@@ -121,15 +217,20 @@ This plugin will look for linters in the [`ale_linters`](ale_linters) directory.
Each directory within corresponds to a particular filetype in Vim, and each file
in each directory corresponds to the name of a particular linter.
### Always showing gutter
<a name="faq-keep-signs"></a>
You can keep the sign gutter open at all times by setting the `g:ale_sign_column_always` to 1
### 4.ii. How can I keep the sign gutter open?
You can keep the sign gutter open at all times by setting the
`g:ale_sign_column_always` to 1
```vim
let g:ale_sign_column_always = 1
```
### Customize signs
<a name="faq-change-signs"></a>
### 4.iii. How can I change the signs ALE uses?
Use these options to specify what text should be used for signs:
@@ -138,7 +239,18 @@ let g:ale_sign_error = '>>'
let g:ale_sign_warning = '--'
```
### Statusline
ALE sets some background colors automatically for warnings and errors
in the sign gutter, with the names `ALEErrorSign` and `ALEWarningSign`.
These colors can be customised, or even removed completely:
```vim
highlight clear ALEErrorSign
highlight clear ALEWarningSign
```
<a name="faq-statusline"></a>
### 4.iv. How can I show errors or warnings in my statusline?
You can use `ALEGetStatusLine()` to integrate ALE into vim statusline.
To enable it, you should have in your `statusline` settings
@@ -163,8 +275,9 @@ let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
![Statusline with issues](img/issues.png)
![Statusline with no issues](img/no_issues.png)
<a name="faq-echo-format"></a>
### Customize echoed message
### 4.v. How can I change the format for echo messages?
There are 3 global options that allow customizing the echoed message.
@@ -187,58 +300,78 @@ Will give you:
![Echoed message](img/echo.png)
## Installation
<a name="faq-autocmd"></a>
To install this plugin, you should use one of the following methods.
For Windows users, replace usage of the Unix `~/.vim` directory with
`%USERPROFILE%\_vim`, or another directory if you have configured
Vim differently. On Windows, your `~/.vimrc` file will be similarly
stored in `%USERPROFILE%\_vimrc`.
### 4.vi. How can I execute some code when ALE stops linting?
### Installation with Pathogen
To install this module with [Pathogen](https://github.com/tpope/vim-pathogen),
you should clone this repository to your bundle directory, and ensure
you have the line `execute pathogen#infect()` in your `~/.vimrc` file.
You can run the following commands in your terminal to do so:
```bash
cd ~/.vim/bundle
git clone https://github.com/w0rp/ale.git
```
### Installation with Vundle
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
by using the path on GitHub for this repository.
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
event whenever has a linter has been successfully executed and processed. This
autocmd event can be used to call arbitrary functions after ALE stops linting.
```vim
Plugin 'w0rp/ale'
augroup YourGroup
autocmd!
autocmd User ALELint call YourFunction()
augroup END
```
See the Vundle documentation for more information.
<a name="faq-navigation"></a>
### Manual Installation
### 4.vii. How can I navigate between errors quickly?
For installation without a package manager, you can clone this git repository
into a bundle directory as with pathogen, and add the repository to your
runtime path yourself. First clone the repository.
```bash
cd ~/.vim/bundle
git clone https://github.com/w0rp/ale.git
```
Then, modify your `~/.vimrc` file to add this plugin to your runtime path.
ALE offers some commands with `<Plug>` keybinds for moving between warnings and
errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
for example:
```vim
set nocompatible
filetype off
let &runtimepath.=',~/.vim/bundle/ale'
filetype plugin on
nmap <silent> <C-k> <Plug>(ale_previous_wrap)
nmap <silent> <C-j> <Plug>(ale_next_wrap)
```
Because the author of this plugin is a weird nerd, this is his preferred
installation method.
For more information, consult the online documentation with
`:help ale-navigation-commands`.
<a name="faq-lint-on-save"></a>
### 4.viii. How can I run linters only when I save files?
ALE offers an option `g:ale_lint_on_save` for enabling running the linters
when files are saved. If you wish to run linters when files are saved, not
as you are editing files, then you can turn the option for linting
when text is changed off too.
```vim
" Write this in your vimrc file
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 0
" You can disable this option too
" if you don't want linters to run on opening a file
let g:ale_lint_on_enter = 0
```
<a name="faq-quickfix"></a>
### 4.ix. How can I use the quickfix list instead of the loclist?
The quickfix list can be enabled by turning the `g:ale_set_quickfix`
option on. If you wish to also disable the loclist, you can disable
the `g:ale_set_loclist` option.
```vim
" Write this in your vimrc file
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
```
If you wish to show Vim windows for the loclist or quickfix items
when a file contains warnings or errors, `g:ale_open_list` can be
set to `1`. `g:ale_keep_list_window_open` can be set to `1`
if you wish to keep the window open even after errors disappear.
```vim
let g:ale_open_list = 1
" Set this if you want to.
" This can be useful if you are combining ALE with
" some other plugin which sets quickfix errors, etc.
let g:ale_keep_list_window_open = 1
```

View File

@@ -0,0 +1,9 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com>
" Description: ansible-lint for ansible-yaml files
call ale#linter#Define('ansible', {
\ 'name': 'ansible',
\ 'executable': 'ansible',
\ 'command': g:ale#util#stdin_wrapper . ' .yml ansible-lint -p',
\ 'callback': 'ale#handlers#HandlePEP8Format',
\})

20
ale_linters/c/clang.vim Normal file
View File

@@ -0,0 +1,20 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: clang linter for c files
" Set this option to change the Clang options for warnings for C.
if !exists('g:ale_c_clang_options')
" let g:ale_c_clang_options = '-Wall'
" let g:ale_c_clang_options = '-std=c99 -Wall'
" c11 compatible
let g:ale_c_clang_options = '-std=c11 -Wall'
endif
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': 'clang',
\ 'command': 'clang -S -x c -fsyntax-only '
\ . g:ale_c_clang_options
\ . ' -',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -0,0 +1,16 @@
" Author: Bart Libert <bart.libert@gmail.com>
" Description: cppcheck linter for c files
" Set this option to change the cppcheck options
if !exists('g:ale_c_cppcheck_options')
let g:ale_c_cppcheck_options = '--enable=style'
endif
call ale#linter#Define('c', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
\ 'executable': 'cppcheck',
\ 'command': g:ale#util#stdin_wrapper . ' .c cppcheck -q --language=c '
\ . g:ale_c_cppcheck_options,
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
\})

View File

@@ -1,23 +1,24 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: gcc linter for c files
if exists('g:loaded_ale_linters_c_gcc')
finish
endif
let g:loaded_ale_linters_c_gcc = 1
" Set this option to change the GCC options for warnings for C.
if !exists('g:ale_c_gcc_options')
let g:ale_c_gcc_options = '-Wall'
" let g:ale_c_gcc_options = '-Wall'
" let g:ale_c_gcc_options = '-std=c99 -Wall'
" c11 compatible
let g:ale_c_gcc_options = '-std=c11 -Wall'
endif
function! ale_linters#c#gcc#GetCommand(buffer) abort
return 'gcc -S -x c -fsyntax-only '
\ . g:ale_c_gcc_options . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
\ 'executable': 'gcc',
\ 'command': 'gcc -S -x c -fsyntax-only '
\ . g:ale_c_gcc_options
\ . ' -',
\ 'command_callback': 'ale_linters#c#gcc#GetCommand',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -0,0 +1,41 @@
" Author: Edward Larkey <edwlarkey@mac.com>
" Description: This file adds the foodcritic linter for Chef files.
function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" FC002: Avoid string interpolation where not required: httpd.rb:13
let l:pattern = '^\(.\+:\s.\+\):\s\(.\+\):\(\d\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:text = l:match[1]
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'text': l:text,
\ 'type': 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('chef', {
\ 'name': 'foodcritic',
\ 'executable': 'foodcritic',
\ 'command': g:ale#util#stdin_wrapper . ' .rb foodcritic',
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
\})

View File

@@ -1,12 +1,6 @@
" Author: KabbAmine - https://github.com/KabbAmine
" Description: Coffee for checking coffee files
if exists('g:loaded_ale_linters_coffee_coffee')
finish
endif
let g:loaded_ale_linters_coffee_coffee = 1
call ale#linter#Define('coffee', {
\ 'name': 'coffee',
\ 'executable': 'coffee',
@@ -14,4 +8,3 @@ call ale#linter#Define('coffee', {
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -1,13 +1,7 @@
" Author: Prashanth Chandra https://github.com/prashcr
" Description: coffeelint linter for coffeescript files
if exists('g:loaded_ale_linters_coffee_coffeelint')
finish
endif
let g:loaded_ale_linters_coffee_coffeelint = 1
function! ale_linters#coffee#coffeelint#Handle(buffer, lines)
function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" path,lineNumber,lineNumberEnd,level,message

View File

@@ -0,0 +1,16 @@
" Author: Bart Libert <bart.libert@gmail.com>
" Description: cppcheck linter for cpp files
" Set this option to change the cppcheck options
if !exists('g:ale_cpp_cppcheck_options')
let g:ale_cpp_cppcheck_options = '--enable=style'
endif
call ale#linter#Define('cpp', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
\ 'executable': 'cppcheck',
\ 'command': g:ale#util#stdin_wrapper . ' .cpp cppcheck -q --language=c++ '
\ . g:ale_cpp_cppcheck_options,
\ 'callback': 'ale#handlers#HandleCppCheckFormat',
\})

View File

@@ -1,23 +1,30 @@
" Author: geam <mdelage@student.42.fr>
" Description: gcc linter for cpp files
if exists('g:loaded_ale_linters_cpp_gcc')
finish
endif
let g:loaded_ale_linters_cpp_gcc = 1
" Set this option to change the GCC options for warnings for C.
if !exists('g:ale_cpp_gcc_options')
let g:ale_cpp_gcc_options = '-Wall'
" added c++14 standard support
" POSIX thread and standard c++ thread and atomic library Linker
" let g:ale_cpp_gcc_options = '-std=c++1z' for c++17
" for previous version and default, you can just use
" let g:ale_cpp_gcc_options = '-Wall'
" for more see man pages of gcc
" $ man g++
" make sure g++ in your $PATH
" Add flags according to your requirements
let g:ale_cpp_gcc_options = '-std=c++14 -Wall'
endif
function! ale_linters#cpp#gcc#GetCommand(buffer) abort
return 'gcc -S -x c++ -fsyntax-only '
\ . g:ale_cpp_gcc_options . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'name': 'g++',
\ 'output_stream': 'stderr',
\ 'executable': 'gcc',
\ 'command': 'gcc -S -x c++ -fsyntax-only '
\ . g:ale_cpp_gcc_options
\ . ' -',
\ 'executable': 'g++',
\ 'command_callback': 'ale_linters#cpp#gcc#GetCommand',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

40
ale_linters/cs/mcs.vim Normal file
View File

@@ -0,0 +1,40 @@
if !exists('g:ale_cs_mcs_options')
let g:ale_cs_mcs_options = ''
endif
function! ale_linters#cs#mcs#Handle(buffer, lines) abort
" Look for lines like the following.
"
" Tests.cs(12,29): error CSXXXX: ; expected
let l:pattern = '^.\+.cs(\(\d\+\),\(\d\+\)): \(.\+\): \(.\+\)'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3] . ': ' . l:match[4],
\ 'type': l:match[3] =~# '^error' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('cs',{
\ 'name': 'mcs',
\ 'output_stream': 'stderr',
\ 'executable': 'mcs',
\ 'command': g:ale#util#stdin_wrapper . ' .cs mcs -unsafe --parse' . g:ale_cs_mcs_options,
\ 'callback': 'ale_linters#cs#mcs#Handle',
\ })

View File

@@ -1,12 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file adds support for checking CSS code with csslint.
if exists('g:loaded_ale_linters_css_csslint')
finish
endif
let g:loaded_ale_linters_css_csslint = 1
call ale#linter#Define('css', {
\ 'name': 'csslint',
\ 'executable': 'csslint',

View File

@@ -0,0 +1,31 @@
" Author: diartyz <diartyz@gmail.com>
let g:ale_css_stylelint_executable =
\ get(g:, 'ale_css_stylelint_executable', 'stylelint')
let g:ale_css_stylelint_use_global =
\ get(g:, 'ale_css_stylelint_use_global', 0)
function! ale_linters#css#stylelint#GetExecutable(buffer) abort
if g:ale_css_stylelint_use_global
return g:ale_css_stylelint_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/stylelint',
\ g:ale_css_stylelint_executable
\)
endfunction
function! ale_linters#css#stylelint#GetCommand(buffer) abort
return ale_linters#css#stylelint#GetExecutable(a:buffer)
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('css', {
\ 'name': 'stylelint',
\ 'executable_callback': 'ale_linters#css#stylelint#GetExecutable',
\ 'command_callback': 'ale_linters#css#stylelint#GetCommand',
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
\})

View File

@@ -1,37 +1,61 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: "dmd for D files"
if exists('g:loaded_ale_linters_d_dmd')
finish
endif
function! s:FindDUBConfig(buffer) abort
" Find a DUB configuration file in ancestor paths.
" The most DUB-specific names will be tried first.
for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
let l:dub_file = ale#util#FindNearestFile(a:buffer, l:possible_filename)
let g:loaded_ale_linters_d_dmd = 1
" A function for finding the dmd-wrapper script in the Vim runtime paths
function! s:FindWrapperScript()
for l:parent in split(&runtimepath, ',')
" Expand the path to deal with ~ issues.
let l:path = expand(l:parent . '/' . 'dmd-wrapper')
if filereadable(l:path)
return l:path
if !empty(l:dub_file)
return l:dub_file
endif
endfor
return ''
endfunction
function! ale_linters#d#dmd#GetCommand(buffer)
let l:wrapper_script = s:FindWrapperScript()
function! ale_linters#d#dmd#DUBCommand(buffer) abort
" If we can't run dub, then skip this command.
if !executable('dub')
" Returning an empty string skips to the DMD command.
return ''
endif
let l:command = l:wrapper_script . ' -o- -vcolumns -c'
let l:dub_file = s:FindDUBConfig(a:buffer)
return l:command
if empty(l:dub_file)
return ''
endif
" To support older dub versions, we just change the directory to
" the directory where we found the dub config, and then run `dub describe`
" from that directory.
return 'cd ' . fnameescape(fnamemodify(l:dub_file, ':h'))
\ . ' && dub describe --import-paths'
endfunction
function! ale_linters#d#dmd#Handle(buffer, lines)
function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort
let l:import_list = []
" Build a list of import paths generated from DUB, if available.
for l:line in a:dub_output
if !empty(l:line)
" The arguments must be '-Ifilename', not '-I filename'
call add(l:import_list, '-I' . fnameescape(l:line))
endif
endfor
return g:ale#util#stdin_wrapper . ' .d dmd '
\ . join(l:import_list)
\ . ' -o- -vcolumns -c'
endfunction
function! ale_linters#d#dmd#Handle(buffer, lines) abort
" Matches patterns lines like the following:
"
" /tmp/tmp.qclsa7qLP7/file.d(1): Error: function declaration without return type. (Note that constructors are always named 'this')
" /tmp/tmp.G1L5xIizvB.d(8,8): Error: module weak_reference is in file 'dstruct/weak_reference.d' which cannot be read
let l:pattern = '^[^(]\+(\([0-9]\+\),\([0-9]\+\)): \([^:]\+\): \(.\+\)'
let l:pattern = '^[^(]\+(\([0-9]\+\)\,\?\([0-9]*\)): \([^:]\+\): \(.\+\)'
let l:output = []
for l:line in a:lines
@@ -63,8 +87,10 @@ endfunction
call ale#linter#Define('d', {
\ 'name': 'dmd',
\ 'output_stream': 'stderr',
\ 'executable': 'dmd',
\ 'command_callback': 'ale_linters#d#dmd#GetCommand',
\ 'command_chain': [
\ {'callback': 'ale_linters#d#dmd#DUBCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#d#dmd#DMDCommand', 'output_stream': 'stderr'},
\ ],
\ 'callback': 'ale_linters#d#dmd#Handle',
\})

View File

@@ -0,0 +1,45 @@
" Author: hauleth - https://github.com/hauleth
function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" stdin:19: F: Pipe chain should start with a raw value.
let l:pattern = '\v^/dev/stdin:?(\d+)? (\S+) (.+)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:lnum = 0
if l:match[1] !=# ''
let l:lnum = l:match[1] + 0
endif
let l:type = 'W'
let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': 0,
\ 'type': l:type,
\ 'text': l:text,
\ 'nr': l:match[2],
\})
endfor
return l:output
endfunction
call ale#linter#Define('dockerfile', {
\ 'name': 'hadolint',
\ 'executable': 'hadolint',
\ 'command': 'hadolint -',
\ 'callback': 'ale_linters#dockerfile#hadolint#Handle' })

View File

@@ -1,12 +1,6 @@
" Author: hauleth - https://github.com/haulethe
" Author: hauleth - https://github.com/hauleth
if exists('g:loaded_ale_linters_elixir_credo')
finish
endif
let g:loaded_ale_linters_elixir_credo = 1
function! ale_linters#elixir#credo#Handle(buffer, lines)
function! ale_linters#elixir#credo#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" stdin:19: F: Pipe chain should start with a raw value.

67
ale_linters/elm/make.vim Normal file
View File

@@ -0,0 +1,67 @@
" Author: buffalocoder - https://github.com/buffalocoder
" Description: Elm linting in Ale. Closely follows the Syntastic checker in https://github.com/ElmCast/elm-vim.
function! ale_linters#elm#make#Handle(buffer, lines) abort
let l:output = []
let l:is_windows = has('win32')
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
for l:line in a:lines
if l:line[0] ==# '['
let l:errors = json_decode(l:line)
for l:error in l:errors
" Check if file is from the temp directory.
" Filters out any errors not related to the buffer.
if l:is_windows
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==? l:temp_dir
else
let l:file_is_buffer = l:error.file[0:len(l:temp_dir) - 1] ==# l:temp_dir
endif
if l:file_is_buffer
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:error.region.start.line,
\ 'vcol': 0,
\ 'col': l:error.region.start.column,
\ 'type': (l:error.type ==? 'error') ? 'E' : 'W',
\ 'text': l:error.overview,
\ 'nr': -1,
\})
endif
endfor
endif
endfor
return l:output
endfunction
" Return the command to execute the linter in the projects directory.
" If it doesn't, then this will fail when imports are needed.
function! ale_linters#elm#make#GetCommand(buffer) abort
let l:elm_package = ale#util#FindNearestFile(a:buffer, 'elm-package.json')
if empty(l:elm_package)
let l:dir_set_cmd = ''
else
let l:root_dir = fnamemodify(l:elm_package, ':p:h')
let l:dir_set_cmd = 'cd ' . fnameescape(l:root_dir) . ' && '
endif
" The elm-make compiler, at the time of this writing, uses '/dev/null' as
" a sort of flag to tell the compiler not to generate an output file,
" which is why this is hard coded here.
" Source: https://github.com/elm-lang/elm-make/blob/master/src/Flags.hs
let l:elm_cmd = 'elm-make --report=json --output='.shellescape('/dev/null')
let l:stdin_wrapper = g:ale#util#stdin_wrapper . ' .elm'
return l:dir_set_cmd . ' ' . l:stdin_wrapper . ' ' . l:elm_cmd
endfunction
call ale#linter#Define('elm', {
\ 'name': 'make',
\ 'executable': 'elm-make',
\ 'output_stream': 'both',
\ 'command_callback': 'ale_linters#elm#make#GetCommand',
\ 'callback': 'ale_linters#elm#make#Handle'
\})

View File

@@ -0,0 +1,96 @@
" Author: Magnus Ottenklinger - https://github.com/evnu
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
function! ale_linters#erlang#erlc#GetCommand(buffer) abort
return g:ale#util#stdin_wrapper . ' .erl erlc ' . g:ale_erlang_erlc_options
endfunction
function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" error.erl:4: variable 'B' is unbound
" error.erl:3: Warning: function main/0 is unused
" error.erl:4: Warning: variable 'A' is unused
let l:pattern = '\v^([^:]+):(\d+): (Warning: )?(.+)$'
" parse_transforms are a special case. The error message does not indicate a location:
" error.erl: undefined parse transform 'some_parse_transform'
let l:pattern_parse_transform = '\v(undefined parse transform .*)$'
let l:output = []
let l:pattern_no_module_definition = '\v(no module definition)$'
let l:pattern_unused = '\v(.* is unused)$'
let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') ==# 'hrl'
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
" Determine if the output indicates an error. We distinguish between two cases:
"
" 1) normal errors match l:pattern
" 2) parse_transform errors match l:pattern_parse_transform
"
" If none of the patterns above match, the line can be ignored
if len(l:match) == 0 " not a 'normal' warning or error
let l:match_parse_transform = matchlist(l:line, l:pattern_parse_transform)
if len(l:match_parse_transform) == 0 " also not a parse_transform error
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'type': 'E',
\ 'text': l:match_parse_transform[0],
\ 'nr': -1,
\})
continue
endif
let l:line = l:match[2]
let l:warning_or_text = l:match[3]
let l:text = l:match[4]
" If this file is a header .hrl, ignore the following expected messages:
" - 'no module definition'
" - 'X is unused'
if l:is_hrl && (
\ match(l:text, l:pattern_no_module_definition) != -1
\ || match(l:text, l:pattern_unused) != -1
\)
continue
endif
if !empty(l:warning_or_text)
let l:type = 'W'
else
let l:type = 'E'
endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 0,
\ 'type': l:type,
\ 'text': l:text,
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'erlc',
\ 'executable': 'erlc',
\ 'command_callback': 'ale_linters#erlang#erlc#GetCommand',
\ 'callback': 'ale_linters#erlang#erlc#Handle',
\})

View File

@@ -1,24 +1,18 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: gcc for Fortran files
if exists('g:loaded_ale_linters_fortran_gcc')
finish
endif
let g:loaded_ale_linters_fortran_gcc = 1
" Set this option to change the GCC options for warnings for Fortran.
if !exists('g:ale_fortran_gcc_options')
let g:ale_fortran_gcc_options = '-Wall'
endif
function! ale_linters#fortran#gcc#Handle(buffer, lines)
function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
" We have to match a starting line and a later ending line together,
" like so.
"
" :21.34:
" Error: Expected comma in I/O list at (1)
let l:line_marker_pattern = '^:\(\d\+\)\.\(\d\+\):$'
let l:line_marker_pattern = ':\(\d\+\)[.:]\=\(\d\+\)\=:\=$'
let l:message_pattern = '^\(Error\|Warning\): \(.\+\)$'
let l:looking_for_message = 0
let l:last_loclist_obj = {}

214
ale_linters/go/gobuild.vim Normal file
View File

@@ -0,0 +1,214 @@
" Author: Joshua Rubin <joshua@rubixconsulting.com>
" Description: go build for Go files
" inspired by work from dzhou121 <dzhou121@gmail.com>
function! ale_linters#go#gobuild#GoEnv(buffer) abort
if exists('s:go_env')
return ''
endif
return 'go env GOPATH GOROOT'
endfunction
let s:SplitChar = has('unix') ? ':' : ':'
" get a list of all source directories from $GOPATH and $GOROOT
function! s:SrcDirs() abort
let l:paths = split(s:go_env.GOPATH, s:SplitChar)
call add(l:paths, s:go_env.GOROOT)
return l:paths
endfunction
" figure out from a directory like `/home/user/go/src/some/package` that the
" import for that path is simply `some/package`
function! s:PackageImportPath(buffer) abort
let l:bufname = resolve(bufname(a:buffer))
let l:pkgdir = fnamemodify(l:bufname, ':p:h')
for l:path in s:SrcDirs()
let l:path = l:path . '/src/'
if stridx(l:pkgdir, l:path) == 0
return l:pkgdir[strlen(l:path):]
endif
endfor
return ''
endfunction
" get the package info data structure using `go list`
function! ale_linters#go#gobuild#GoList(buffer, goenv_output) abort
if !empty(a:goenv_output)
let s:go_env = {
\ 'GOPATH': a:goenv_output[0],
\ 'GOROOT': a:goenv_output[1],
\}
endif
return 'go list -json ' . shellescape(s:PackageImportPath(a:buffer))
endfunction
let s:filekeys = [
\ 'GoFiles',
\ 'CgoFiles',
\ 'CFiles',
\ 'CXXFiles',
\ 'MFiles',
\ 'HFiles',
\ 'FFiles',
\ 'SFiles',
\ 'SwigFiles',
\ 'SwigCXXFiles',
\ 'SysoFiles',
\ 'TestGoFiles',
\ 'XTestGoFiles',
\]
" get the go and test go files from the package
" will return empty list if the package has any cgo or other invalid files
function! s:PkgFiles(pkginfo) abort
let l:files = []
for l:key in s:filekeys
if has_key(a:pkginfo, l:key)
call extend(l:files, a:pkginfo[l:key])
endif
endfor
" resolve the path of the file relative to the window directory
return map(l:files, 'shellescape(fnamemodify(resolve(a:pkginfo.Dir . ''/'' . v:val), '':p''))')
endfunction
function! ale_linters#go#gobuild#CopyFiles(buffer, golist_output) abort
let l:tempdir = tempname()
let l:temppkgdir = l:tempdir . '/src/' . s:PackageImportPath(a:buffer)
call mkdir(l:temppkgdir, 'p', 0700)
if empty(a:golist_output)
return 'echo ' . shellescape(l:tempdir)
endif
" parse the output
let l:pkginfo = json_decode(join(a:golist_output, "\n"))
" get all files for the package
let l:files = s:PkgFiles(l:pkginfo)
" copy the files to a temp directory with $GOPATH structure
return 'cp ' . join(l:files, ' ') . ' ' . shellescape(l:temppkgdir) . ' && echo ' . shellescape(l:tempdir)
endfunction
function! ale_linters#go#gobuild#GetCommand(buffer, copy_output) abort
let l:tempdir = a:copy_output[0]
let l:importpath = s:PackageImportPath(a:buffer)
" write the a:buffer and any modified buffers from the package to the tempdir
for l:bufnum in range(1, bufnr('$'))
" ignore unloaded buffers (can't be a:buffer or a modified buffer)
if !bufloaded(l:bufnum)
continue
endif
" ignore non-Go buffers
if getbufvar(l:bufnum, '&ft') !=# 'go'
continue
endif
" only consider buffers other than a:buffer if they have the same import
" path as a:buffer and are modified
if l:bufnum != a:buffer
if s:PackageImportPath(l:bufnum) !=# l:importpath
continue
endif
if !getbufvar(l:bufnum, '&mod')
continue
endif
endif
call writefile(getbufline(l:bufnum, 1, '$'), l:tempdir . '/src/' . s:PkgFile(l:bufnum))
endfor
let l:gopaths = [ l:tempdir ]
call extend(l:gopaths, split(s:go_env.GOPATH, s:SplitChar))
return 'GOPATH=' . shellescape(join(l:gopaths, s:SplitChar)) . ' go test -c -o /dev/null ' . shellescape(l:importpath)
endfunction
function! s:PkgFile(buffer) abort
let l:bufname = resolve(bufname(a:buffer))
let l:importpath = s:PackageImportPath(a:buffer)
let l:fname = fnamemodify(l:bufname, ':t')
return l:importpath . '/' . l:fname
endfunction
function! s:FindBuffer(file) abort
for l:buffer in range(1, bufnr('$'))
if !buflisted(l:buffer)
continue
endif
let l:pkgfile = s:PkgFile(l:buffer)
if a:file =~ '/' . l:pkgfile . '$'
return l:buffer
endif
endfor
return -1
endfunction
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
let s:handler_pattern = '^\(' . s:path_pattern . '\):\(\d\+\):\?\(\d\+\)\?: \(.\+\)$'
let s:multibuffer = 0
function! ale_linters#go#gobuild#Handler(buffer, lines) abort
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, s:handler_pattern)
if len(l:match) == 0
continue
endif
let l:buffer = s:FindBuffer(l:match[1])
if l:buffer == -1
continue
endif
if !s:multibuffer && l:buffer != a:buffer
" strip lines from other buffers
continue
endif
call add(l:output, {
\ 'bufnr': l:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[4],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('go', {
\ 'name': 'go build',
\ 'executable': 'go',
\ 'command_chain': [
\ {'callback': 'ale_linters#go#gobuild#GoEnv', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#go#gobuild#GoList', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#go#gobuild#CopyFiles', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#go#gobuild#GetCommand', 'output_stream': 'stderr'},
\ ],
\ 'callback': 'ale_linters#go#gobuild#Handler',
\})

View File

@@ -1,12 +1,6 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: gofmt for Go files
if exists('g:loaded_ale_linters_go_gofmt')
finish
endif
let g:loaded_ale_linters_go_gofmt = 1
call ale#linter#Define('go', {
\ 'name': 'gofmt',
\ 'output_stream': 'stderr',
@@ -14,4 +8,3 @@ call ale#linter#Define('go', {
\ 'command': g:ale#util#stdin_wrapper . ' .go gofmt -e',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\})

View File

@@ -1,12 +1,6 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: golint for Go files
if exists('g:loaded_ale_linters_go_golint')
finish
endif
let g:loaded_ale_linters_go_golint = 1
call ale#linter#Define('go', {
\ 'name': 'golint',
\ 'executable': 'golint',

View File

@@ -1,12 +1,6 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: go vet for Go files
if exists('g:loaded_ale_linters_go_govet')
finish
endif
let g:loaded_ale_linters_go_govet = 1
call ale#linter#Define('go', {
\ 'name': 'go vet',
\ 'output_stream': 'stderr',
@@ -14,4 +8,3 @@ call ale#linter#Define('go', {
\ 'command': g:ale#util#stdin_wrapper . ' .go go vet',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\})

View File

@@ -7,12 +7,61 @@ endif
let g:loaded_ale_linters_haskell_ghc = 1
function! ale_linters#haskell#ghc#Handle(buffer, lines) abort
" Look for lines like the following.
"
" /dev/stdin:28:26: Not in scope: `>>>>>'
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\): \(.\+\)$'
let l:output = []
" For some reason the output coming out of the GHC through the wrapper
" script breaks the lines up in strange ways. So we have to join some
" lines back together again.
let l:corrected_lines = []
for l:line in a:lines
if len(matchlist(l:line, l:pattern)) > 0
call add(l:corrected_lines, l:line)
if l:line !~# ': error:$'
call add(l:corrected_lines, '')
endif
elseif l:line ==# ''
call add(l:corrected_lines, l:line)
else
if len(l:corrected_lines) > 0
let l:line = substitute(l:line, '\v\s+', ' ', '')
let l:corrected_lines[-1] .= l:line
endif
endif
endfor
for l:line in l:corrected_lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('haskell', {
\ 'name': 'ghc',
\ 'output_stream': 'stderr',
\ 'executable': 'ghc',
\ 'command': g:ale#util#stdin_wrapper . ' .hs ghc -fno-code -v0',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\ 'callback': 'ale_linters#haskell#ghc#Handle',
\})
call ale#linter#Define('haskell', {
@@ -20,5 +69,5 @@ call ale#linter#Define('haskell', {
\ 'output_stream': 'stderr',
\ 'executable': 'stack',
\ 'command': g:ale#util#stdin_wrapper . ' .hs stack ghc -- -fno-code -v0',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\ 'callback': 'ale_linters#haskell#ghc#Handle',
\})

View File

@@ -1,13 +1,7 @@
" Author: jparoz <jesse.paroz@gmail.com>
" Description: hlint for Haskell files
if exists('g:loaded_ale_linters_haskell_hlint')
finish
endif
let g:loaded_ale_linters_haskell_hlint = 1
function! ale_linters#haskell#hlint#Handle(buffer, lines)
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:errors = json_decode(join(a:lines, ''))
let l:output = []
@@ -19,7 +13,7 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines)
\ 'lnum': l:error.startLine + 0,
\ 'vcol': 0,
\ 'col': l:error.startColumn + 0,
\ 'text': l:error.severity . ': ' . l:error.hint,
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',
\})
endfor

View File

@@ -1,15 +1,36 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" Author: KabbAmine <amine.kabb@gmail.com>, deathmaz <00maz1987@gmail.com>, diartyz <diartyz@gmail.com>
" Description: HTMLHint for checking html files
if exists('g:loaded_ale_linters_html_htmlhint')
finish
endif
" CLI options
let g:ale_html_htmlhint_options = get(g:, 'ale_html_htmlhint_options', '--format=unix')
let g:loaded_ale_linters_html_htmlhint = 1
let g:ale_html_htmlhint_executable =
\ get(g:, 'ale_html_htmlhint_executable', 'htmlhint')
let g:ale_html_htmlhint_use_global =
\ get(g:, 'ale_html_htmlhint_use_global', 0)
function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
if g:ale_html_htmlhint_use_global
return g:ale_html_htmlhint_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/htmlhint',
\ g:ale_html_htmlhint_executable
\)
endfunction
function! ale_linters#html#htmlhint#GetCommand(buffer) abort
return g:ale#util#stdin_wrapper . ' .html '
\ . ale_linters#html#htmlhint#GetExecutable(a:buffer)
\ . ' ' . g:ale_html_htmlhint_options
endfunction
call ale#linter#Define('html', {
\ 'name': 'htmlhint',
\ 'executable': 'htmlhint',
\ 'command': 'htmlhint --format=unix stdin',
\ 'executable_callback': 'ale_linters#html#htmlhint#GetExecutable',
\ 'command_callback': 'ale_linters#html#htmlhint#GetCommand',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\})

View File

@@ -1,12 +1,6 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" Description: This file adds support for checking HTML code with tidy.
if exists('g:loaded_ale_linters_html_tidy')
finish
endif
let g:loaded_ale_linters_html_tidy = 1
" CLI options
let g:ale_html_tidy_executable = get(g:, 'ale_html_tidy_executable', 'tidy')
let g:ale_html_tidy_args = get(g:, 'ale_html_tidy_args', '-q -e -language en')

View File

@@ -1,37 +1,64 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: eslint for JavaScript files
if exists('g:loaded_ale_linters_javascript_eslint')
finish
endif
let g:loaded_ale_linters_javascript_eslint = 1
let g:ale_javascript_eslint_executable =
\ get(g:, 'ale_javascript_eslint_executable', 'eslint')
function! ale_linters#javascript#eslint#Handle(buffer, lines)
let g:ale_javascript_eslint_options =
\ get(g:, 'ale_javascript_eslint_options', '')
let g:ale_javascript_eslint_use_global =
\ get(g:, 'ale_javascript_eslint_use_global', 0)
function! ale_linters#javascript#eslint#GetExecutable(buffer) abort
if g:ale_javascript_eslint_use_global
return g:ale_javascript_eslint_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/eslint',
\ g:ale_javascript_eslint_executable
\)
endfunction
function! ale_linters#javascript#eslint#GetCommand(buffer) abort
return ale_linters#javascript#eslint#GetExecutable(a:buffer)
\ . ' ' . g:ale_javascript_eslint_options
\ . ' -f unix --stdin --stdin-filename %s'
endfunction
function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
" /path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$'
" This second pattern matches lines like the following:
"
" /path/to/some-filename.js:13:3: Parsing error: Unexpected token
let l:parsing_pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
" Try the parsing pattern for parsing errors.
let l:match = matchlist(l:line, l:parsing_pattern)
endif
if len(l:match) == 0
continue
endif
let l:type = 'Error'
let l:text = l:match[3]
let l:marker = l:match[4]
let l:marker_parts = split(l:marker, '/')
let l:type = l:marker_parts[0]
if len(l:marker_parts) == 2
let l:text = l:text . ' (' . l:marker_parts[1] . ')'
" Take the error type from the output if available.
if !empty(l:match[4])
let l:type = split(l:match[4], '/')[0]
let l:text .= ' [' . l:match[4] . ']'
endif
" vcol is Needed to indicate that the column is a character.
@@ -51,7 +78,7 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'eslint',
\ 'executable': g:ale_javascript_eslint_executable,
\ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s',
\ 'executable_callback': 'ale_linters#javascript#eslint#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#eslint#GetCommand',
\ 'callback': 'ale_linters#javascript#eslint#Handle',
\})

View File

@@ -0,0 +1,80 @@
" Author: Zach Perrault -- @zperrault
" Description: FlowType checking for JavaScript files
let g:ale_javascript_flow_executable =
\ get(g:, 'ale_javascript_flow_executable', 'flow')
let g:ale_javascript_flow_use_global =
\ get(g:, 'ale_javascript_flow_use_global', 0)
function! ale_linters#javascript#flow#GetExecutable(buffer) abort
if g:ale_javascript_flow_use_global
return g:ale_javascript_flow_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/flow',
\ g:ale_javascript_flow_executable
\)
endfunction
function! ale_linters#javascript#flow#GetCommand(buffer) abort
return ale_linters#javascript#flow#GetExecutable(a:buffer)
\ . ' check-contents --respect-pragma --json --from ale %s'
endfunction
function! ale_linters#javascript#flow#Handle(buffer, lines) abort
let l:str = join(a:lines, '')
if l:str ==# ''
return []
endif
let l:flow_output = json_decode(l:str)
if has_key(l:flow_output, 'errors')
let l:output = []
for l:error in l:flow_output.errors
" Each error is broken up into parts
let l:text = ''
let l:line = 0
let l:col = 0
for l:message in l:error.message
" Comments have no line of column information
if has_key(l:message, 'loc') && l:line ==# 0
let l:line = l:message.loc.start.line + 0
let l:col = l:message.loc.start.column + 0
endif
if l:text ==# ''
let l:text = l:message.descr . ':'
else
let l:text = l:text . ' ' . l:message.descr
endif
endfor
if has_key(l:error, 'operation')
let l:text = l:text . ' See also: ' . l:error.operation.descr
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:error.level ==# 'error' ? 'E' : 'W',
\})
endfor
return l:output
else
return []
endif
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow',
\ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#flow#GetCommand',
\ 'callback': 'ale_linters#javascript#flow#Handle',
\})

View File

@@ -1,12 +1,6 @@
" Author: Chris Kyrouac - https://github.com/fijshion
" Description: jscs for JavaScript files
if exists('g:loaded_ale_linters_javascript_jscs')
finish
endif
let g:loaded_ale_linters_javascript_jscs = 1
call ale#linter#Define('javascript', {
\ 'name': 'jscs',
\ 'executable': 'jscs',

View File

@@ -1,26 +1,34 @@
" Author: Chris Kyrouac - https://github.com/fijshion
" Description: JSHint for Javascript files
if exists('g:loaded_ale_linters_javascript_jshint')
finish
endif
let g:loaded_ale_linters_javascript_jshint = 1
let g:ale_javascript_jshint_executable =
\ get(g:, 'ale_javascript_jshint_executable', 'jshint')
function! ale_linters#javascript#jshint#GetCommand(buffer)
" Set this to the location of the jshint configuration file to
" use a fixed location for .jshintrc
if exists('g:ale_jshint_config_loc')
let l:jshint_config = g:ale_jshint_config_loc
else
" Look for the JSHint config in parent directories.
let l:jshint_config = ale#util#FindNearestFile(a:buffer, '.jshintrc')
let g:ale_javascript_jshint_use_global =
\ get(g:, 'ale_javascript_jshint_use_global', 0)
function! ale_linters#javascript#jshint#GetExecutable(buffer) abort
if g:ale_javascript_jshint_use_global
return g:ale_javascript_jshint_executable
endif
let l:command = g:ale_javascript_jshint_executable . ' --reporter unix'
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/jshint',
\ g:ale_javascript_jshint_executable
\)
endfunction
function! ale_linters#javascript#jshint#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jshint_config = ale#util#ResolveLocalPath(
\ a:buffer,
\ '.jshintrc',
\ get(g:, 'ale_jshint_config_loc', '')
\)
let l:command = ale_linters#javascript#jshint#GetExecutable(a:buffer)
let l:command .= ' --reporter unix'
if !empty(l:jshint_config)
let l:command .= ' --config ' . fnameescape(l:jshint_config)
@@ -33,7 +41,7 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jshint',
\ 'executable': g:ale_javascript_jshint_executable,
\ 'executable_callback': 'ale_linters#javascript#jshint#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
\ 'callback': 'ale#handlers#HandleUnixFormatAsError',
\})

View File

@@ -1,12 +1,6 @@
" Author: KabbAmine <amine.kabb@gmail.com>
if exists('g:loaded_ale_linters_json_jsonlint')
finish
endif
let g:loaded_ale_linters_json_jsonlint = 1
function! ale_linters#json#jsonlint#Handle(buffer, lines)
function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
" Matches patterns like the following:
" line 2, col 15, found: 'STRING' - expected: 'EOF', '}', ',', ']'.

View File

@@ -1,16 +1,10 @@
" Author: Sol Bekic https://github.com/s-ol
" Description: luacheck linter for lua files
if exists('g:loaded_ale_linters_lua_luacheck')
finish
endif
let g:loaded_ale_linters_lua_luacheck = 1
let g:ale_lua_luacheck_executable =
\ get(g:, 'ale_lua_luacheck_executable', 'luacheck')
function! ale_linters#lua#luacheck#Handle(buffer, lines)
function! ale_linters#lua#luacheck#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106

View File

@@ -0,0 +1,35 @@
" Author: Steve Dignam <steve@dignam.xyz>
" Description: Support for mdl, a markdown linter
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
" matches: '(stdin):173: MD004 Unordered list style'
let l:pattern = ':\(\d*\): \(.*\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'text': l:match[2],
\ 'type': 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('markdown', {
\ 'name': 'mdl',
\ 'executable': 'mdl',
\ 'command': 'mdl',
\ 'callback': 'ale_linters#markdown#mdl#Handle'
\})

View File

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

View File

@@ -0,0 +1,55 @@
" Author: awlayton <alex@layton.in>
" Description: mlint for MATLAB files
let g:ale_matlab_mlint_executable =
\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" L 27 (C 1): FNDEF: Terminate statement with semicolon to suppress output.
" L 30 (C 13-15): FNDEF: A quoted string is unterminated.
let l:pattern = '^L \(\d\+\) (C \([0-9-]\+\)): \([A-Z]\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:lnum = l:match[1] + 0
let l:col = l:match[2] + 0
let l:code = l:match[3]
let l:text = l:match[4]
" Suppress erroneous waring about filename
" TODO: Enable this error when copying filename is supported
if l:code ==# 'FNDEF'
continue
endif
" vcol is needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('matlab', {
\ 'name': 'mlint',
\ 'executable': 'mlint',
\ 'command': g:ale#util#stdin_wrapper .
\ ' .m ' . g:ale_matlab_mlint_executable . ' -id',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#matlab#mlint#Handle',
\})

View File

@@ -0,0 +1,19 @@
" Author: Andrey Popp -- @andreypopp
" Description: Report errors in OCaml code with Merlin
if !exists('g:merlin')
finish
endif
function! ale_linters#ocaml#merlin#Handle(buffer, lines) abort
let l:errors = merlin#ErrorLocList()
return l:errors
endfunction
call ale#linter#Define('ocaml', {
\ 'name': 'merlin',
\ 'executable': 'ocamlmerlin',
\ 'command': 'true',
\ 'callback': 'ale_linters#ocaml#merlin#Handle',
\})

View File

@@ -1,12 +1,7 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl syntax
if exists('g:loaded_ale_linters_perl_perlcritic')
finish
endif
let g:loaded_ale_linters_perl_perl = 1
function! ale_linters#perl#perl#Handle(buffer, lines)
function! ale_linters#perl#perl#Handle(buffer, lines) abort
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = []

View File

@@ -1,12 +1,7 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl with perl critic
if exists('g:loaded_ale_linters_perl_perlcritic')
finish
endif
let g:loaded_ale_linters_perl_perlcritic = 1
function! ale_linters#perl#perlcritic#Handle(buffer, lines)
function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = []
@@ -40,7 +35,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perlcritic',
\ 'executable': 'perlcritic',
\ 'output_stream': 'sdtout',
\ 'output_stream': 'stdout',
\ 'command': 'perlcritic --verbose 3 --nocolor',
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
\})

37
ale_linters/php/hack.vim Normal file
View File

@@ -0,0 +1,37 @@
" Author: Zefei Xuan <https://github.com/zefei>
" Description: Hack type checking (http://hacklang.org/)
function! ale_linters#php#hack#Handle(buffer, lines) abort
let l:pattern = '^\(.*\):\(\d\+\):\(\d\+\),\(\d\+\): \(.\+])\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
if a:buffer != bufnr(l:match[1])
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[5],
\ 'type': 'E',
\})
endfor
return l:output
endfunction
call ale#linter#Define('php', {
\ 'name': 'hack',
\ 'executable': 'hh_client',
\ 'command': 'hh_client --retries 0 --retry-if-init false',
\ 'callback': 'ale_linters#php#hack#Handle',
\})

View File

@@ -1,13 +1,7 @@
" Author: Spencer Wood <https://github.com/scwood>
" Description: This file adds support for checking PHP with php-cli
if exists('g:loaded_ale_linters_php_php')
finish
endif
let g:loaded_ale_linters_php_php = 1
function! ale_linters#php#php#Handle(buffer, lines)
function! ale_linters#php#php#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" Parse error: parse error in - on line 7
@@ -40,6 +34,6 @@ call ale#linter#Define('php', {
\ 'name': 'php',
\ 'executable': 'php',
\ 'output_stream': 'both',
\ 'command': 'php -l --',
\ 'command': 'php -l -d display_errors=1 --',
\ 'callback': 'ale_linters#php#php#Handle',
\})

View File

@@ -1,13 +1,7 @@
" Author: jwilliams108 <https://github.com/jwilliams108>
" Description: phpcs for PHP files
if exists('g:loaded_ale_linters_php_phpcs')
finish
endif
let g:loaded_ale_linters_php_phpcs = 1
function! ale_linters#php#phpcs#GetCommand(buffer)
function! ale_linters#php#phpcs#GetCommand(buffer) abort
let l:command = 'phpcs -s --report=emacs --stdin-path=%s'
" This option can be set to change the standard used by phpcs
@@ -18,7 +12,7 @@ function! ale_linters#php#phpcs#GetCommand(buffer)
return l:command
endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines)
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
" Matches against lines like the following:
"
" /path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)

View File

@@ -1,12 +1,6 @@
" Author: w0rp - <devw0rp@gmail.com>
" Description: pug-lint for checking Pug/Jade files.
if exists('g:loaded_ale_linters_pug_puglint')
finish
endif
let g:loaded_ale_linters_pug_puglint = 1
call ale#linter#Define('pug', {
\ 'name': 'puglint',
\ 'executable': 'pug-lint',

View File

@@ -0,0 +1,38 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" Matches patterns like the following:
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
let l:pattern = '^Error: .*: \(.\+\) at .\+:\(\d\+\):\(\d\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
" vcol is needed to indicate that the column is a character
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[1],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('puppet', {
\ 'name': 'puppet',
\ 'executable': 'puppet',
\ 'output_stream': 'stderr',
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet parser validate --color=false',
\ 'callback': 'ale_linters#puppet#puppet#Handle',
\})

View File

@@ -0,0 +1,8 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
call ale#linter#Define('puppet', {
\ 'name': 'puppetlint',
\ 'executable': 'puppet-lint',
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet-lint --no-autoloader_layout-check --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -1,55 +1,76 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: flake8 for python files
if exists('g:loaded_ale_linters_python_flake8')
finish
endif
let g:ale_python_flake8_executable =
\ get(g:, 'ale_python_flake8_executable', 'flake8')
let g:loaded_ale_linters_python_flake8 = 1
let g:ale_python_flake8_args =
\ get(g:, 'ale_python_flake8_args', '')
function! ale_linters#python#flake8#Handle(buffer, lines)
" Matches patterns line the following:
"
" stdin:6:6: E111 indentation is not a multiple of four
let l:pattern = '^stdin:\(\d\+\):\(\d\+\): \([^ ]\+\) \(.\+\)$'
let l:output = []
" A map from Python executable paths to semver strings parsed for those
" executables, so we don't have to look up the version number constantly.
let s:version_cache = {}
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
function! ale_linters#python#flake8#GetExecutable(buffer) abort
return g:ale_python_flake8_executable
endfunction
if len(l:match) == 0
continue
endif
function! ale_linters#python#flake8#VersionCheck(buffer) abort
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:line = l:match[1] + 0
let l:column = l:match[2] + 0
let l:code = l:match[3]
let l:text = l:code . ': ' . l:match[4]
let l:type = l:code[0] ==# 'E' ? 'E' : 'W'
" If we have previously stored the version number in a cache, then
" don't look it up again.
if has_key(s:version_cache, l:executable)
" Returning an empty string skips this command.
return ''
endif
if (l:code ==# 'W291' || l:code ==# 'W293') && !g:ale_warn_about_trailing_whitespace
" Skip warnings for trailing whitespace if the option is off.
continue
endif
return ale_linters#python#flake8#GetExecutable(a:buffer) . ' --version'
endfunction
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
" Get the flake8 version from the output, or the cache.
function! s:GetVersion(buffer, version_output) abort
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:version = []
return l:output
" Get the version from the cache.
if has_key(s:version_cache, l:executable)
return s:version_cache[l:executable]
endif
if !empty(a:version_output)
" Parse the version string, and store it in the cache.
let l:version = ale#semver#Parse(a:version_output[0])
let s:version_cache[l:executable] = l:version
endif
return l:version
endfunction
" flake8 versions 3 and up support the --stdin-display-name argument.
function! s:SupportsDisplayName(version) abort
return !empty(a:version) && ale#semver#GreaterOrEqual(a:version, [3, 0, 0])
endfunction
function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
let l:version = s:GetVersion(a:buffer, a:version_output)
" Only include the --stdin-display-name argument if we can parse the
" flake8 version, and it is recent enough to support it.
let l:display_name_args = s:SupportsDisplayName(l:version)
\ ? '--stdin-display-name %s'
\ : ''
return ale_linters#python#flake8#GetExecutable(a:buffer)
\ . ' ' . g:ale_python_flake8_args . ' ' . l:display_name_args . ' -'
endfunction
call ale#linter#Define('python', {
\ 'name': 'flake8',
\ 'executable': 'flake8',
\ 'command': 'flake8 -',
\ 'callback': 'ale_linters#python#flake8#Handle',
\ 'executable_callback': 'ale_linters#python#flake8#GetExecutable',
\ 'command_chain': [
\ {'callback': 'ale_linters#python#flake8#VersionCheck'},
\ {'callback': 'ale_linters#python#flake8#GetCommand'},
\ ],
\ 'callback': 'ale#handlers#HandlePEP8Format',
\})

View File

@@ -0,0 +1,64 @@
" Author: Keith Smiley <k@keith.so>, w0rp <devw0rp@gmail.com>
" Description: mypy support for optional python typechecking
let g:ale_python_mypy_options = get(g:, 'ale_python_mypy_options', '')
function! g:ale_linters#python#mypy#GetCommand(buffer) abort
let l:automatic_stubs_dir = ale#util#FindNearestDirectory(a:buffer, 'stubs')
" TODO: Add Windows support
let l:automatic_stubs_command = (has('unix') && !empty(l:automatic_stubs_dir))
\ ? 'MYPYPATH=' . l:automatic_stubs_dir . ' '
\ : ''
return l:automatic_stubs_command
\ . g:ale#util#stdin_wrapper
\ . ' .py mypy --show-column-numbers '
\ . g:ale_python_mypy_options
endfunction
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
function! g:ale_linters#python#mypy#Handle(buffer, lines) abort
" Look for lines like the following:
"
" file.py:4: error: No library stub file for module 'django.db'
"
" Lines like these should be ignored below:
"
" file.py:4: note: (Stub files are from https://github.com/python/typeshed)
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \([^:]\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
if l:match[4] =~# 'Stub files are from'
" The lines telling us where to get stub files from make it so
" we can't read the actual errors, so exclude them.
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4],
\ 'type': l:match[3] =~# 'error' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call g:ale#linter#Define('python', {
\ 'name': 'mypy',
\ 'executable': 'mypy',
\ 'command_callback': 'ale_linters#python#mypy#GetCommand',
\ 'callback': 'ale_linters#python#mypy#Handle',
\})

View File

@@ -0,0 +1,26 @@
" Author: keith <k@keith.so>
" Description: pylint for python files
let g:ale_python_pylint_executable =
\ get(g:, 'ale_python_pylint_executable', 'pylint')
let g:ale_python_pylint_options =
\ get(g:, 'ale_python_pylint_options', '')
function! ale_linters#python#pylint#GetExecutable(buffer) abort
return g:ale_python_pylint_executable
endfunction
function! ale_linters#python#pylint#GetCommand(buffer) abort
return g:ale#util#stdin_wrapper . ' .py '
\ . ale_linters#python#pylint#GetExecutable(a:buffer)
\ . ' ' . g:ale_python_pylint_options
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} {msg}" --reports n'
endfunction
call ale#linter#Define('python', {
\ 'name': 'pylint',
\ 'executable_callback': 'ale_linters#python#pylint#GetExecutable',
\ 'command_callback': 'ale_linters#python#pylint#GetCommand',
\ 'callback': 'ale#handlers#HandlePEP8Format',
\})

View File

@@ -1,18 +1,12 @@
" Author: ynonp - https://github.com/ynonp
" Description: rubocop for Ruby files
if exists('g:loaded_ale_linters_ruby_rubocop')
finish
endif
let g:loaded_ale_linters_ruby_rubocop = 1
function! ale_linters#ruby#rubocop#Handle(buffer, lines)
function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" <path>/_:47:14: 83:29: C: Prefer single-quoted strings when you don't
" <path>:83:29: C: Prefer single-quoted strings when you don't
" need string interpolation or special symbols.
let l:pattern = '\v_:(\d+):(\d+): (.): (.+)'
let l:pattern = '\v:(\d+):(\d+): (.): (.+)'
let l:output = []
for l:line in a:lines
@@ -32,7 +26,7 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines)
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type ==# 'C' ? 'E' : 'W',
\ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
@@ -40,10 +34,21 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines)
return l:output
endfunction
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
return 'rubocop --format emacs --force-exclusion ' .
\ g:ale_ruby_rubocop_options .
\ ' --stdin ' . bufname(a:buffer)
endfunction
" Set this option to change Rubocop options.
if !exists('g:ale_ruby_rubocop_options')
" let g:ale_ruby_rubocop_options = '--lint'
let g:ale_ruby_rubocop_options = ''
endif
call ale#linter#Define('ruby', {
\ 'name': 'rubocop',
\ 'executable': 'rubocop',
\ 'command': 'rubocop --format emacs --stdin _',
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
\})

View File

@@ -0,0 +1,20 @@
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
" Description: rustc invoked by cargo for rust files
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#util#FindNearestFile(a:bufnr, 'Cargo.toml') !=# ''
return 'cargo'
else
" if there is no Cargo.toml file, we don't use cargo even if it exists,
" so we return '', because executable('') apparently always fails
return ''
endif
endfunction
call ale#linter#Define('rust', {
\ 'name': 'cargo',
\ 'executable_callback': 'ale_linters#rust#cargo#GetCargoExecutable',
\ 'command': 'cargo build --message-format=json -q',
\ 'callback': 'ale#handlers#rust#HandleRustErrors',
\ 'output_stream': 'stdout',
\})

View File

@@ -0,0 +1,27 @@
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
" Description: rustc for rust files
function! ale_linters#rust#rustc#RustcCommand(buffer_number) abort
" Try to guess the library search path. If the project is managed by cargo,
" it's usually <project root>/target/debug/deps/ or
" <project root>/target/release/deps/
let l:cargo_file = ale#util#FindNearestFile(a:buffer_number, 'Cargo.toml')
if l:cargo_file !=# ''
let l:project_root = fnamemodify(l:cargo_file, ':h')
let l:dependencies = '-L ' . l:project_root . '/target/debug/deps -L ' .
\ l:project_root . '/target/release/deps'
else
let l:dependencies = ''
endif
return 'rustc --error-format=json -Z no-trans ' . l:dependencies . ' -'
endfunction
call ale#linter#Define('rust', {
\ 'name': 'rustc',
\ 'executable': 'rustc',
\ 'command_callback': 'ale_linters#rust#rustc#RustcCommand',
\ 'callback': 'ale#handlers#rust#HandleRustErrors',
\ 'output_stream': 'stderr',
\})

View File

@@ -1,11 +1,5 @@
" Author: KabbAmine - https://github.com/KabbAmine
if exists('g:loaded_ale_linters_sass_sasslint')
finish
endif
let g:loaded_ale_linters_sass_sasslint = 1
call ale#linter#Define('sass', {
\ 'name': 'sasslint',
\ 'executable': 'sass-lint',

View File

@@ -0,0 +1,31 @@
" Author: diartyz <diartyz@gmail.com>
let g:ale_sass_stylelint_executable =
\ get(g:, 'ale_sass_stylelint_executable', 'stylelint')
let g:ale_sass_stylelint_use_global =
\ get(g:, 'ale_sass_stylelint_use_global', 0)
function! ale_linters#sass#stylelint#GetExecutable(buffer) abort
if g:ale_sass_stylelint_use_global
return g:ale_sass_stylelint_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/stylelint',
\ g:ale_sass_stylelint_executable
\)
endfunction
function! ale_linters#sass#stylelint#GetCommand(buffer) abort
return ale_linters#sass#stylelint#GetExecutable(a:buffer)
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('sass', {
\ 'name': 'stylelint',
\ 'executable_callback': 'ale_linters#sass#stylelint#GetExecutable',
\ 'command_callback': 'ale_linters#sass#stylelint#GetCommand',
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
\})

View File

@@ -2,13 +2,7 @@
" Author: Zoltan Kalmar - https://github.com/kalmiz
" Description: Basic scala support using scalac
if exists('g:loaded_ale_linters_scala_scalac')
finish
endif
let g:loaded_ale_linters_scala_scalac = 1
function! ale_linters#scala#scalac#Handle(buffer, lines)
function! ale_linters#scala#scalac#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" /var/folders/5q/20rgxx3x1s34g3m14n5bq0x80000gn/T/vv6pSsy/0:26: error: expected class or object definition

View File

@@ -1,11 +1,5 @@
" Author: KabbAmine - https://github.com/KabbAmine
if exists('g:loaded_ale_linters_scss_sasslint')
finish
endif
let g:loaded_ale_linters_scss_sasslint = 1
call ale#linter#Define('scss', {
\ 'name': 'sasslint',
\ 'executable': 'sass-lint',

View File

@@ -1,13 +1,7 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file add scsslint support for SCSS support
if exists('g:loaded_ale_linters_scss_scsslint')
finish
endif
let g:loaded_ale_linters_scss_scsslint = 1
function! ale_linters#scss#scsslint#Handle(buffer, lines)
function! ale_linters#scss#scsslint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" test.scss:2:1 [W] Indentation: Line should be indented 2 spaces, but was indented 4 spaces

View File

@@ -0,0 +1,31 @@
" Author: diartyz <diartyz@gmail.com>
let g:ale_scss_stylelint_executable =
\ get(g:, 'ale_scss_stylelint_executable', 'stylelint')
let g:ale_scss_stylelint_use_global =
\ get(g:, 'ale_scss_stylelint_use_global', 0)
function! ale_linters#scss#stylelint#GetExecutable(buffer) abort
if g:ale_scss_stylelint_use_global
return g:ale_scss_stylelint_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/stylelint',
\ g:ale_scss_stylelint_executable
\)
endfunction
function! ale_linters#scss#stylelint#GetCommand(buffer) abort
return ale_linters#scss#stylelint#GetExecutable(a:buffer)
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('scss', {
\ 'name': 'stylelint',
\ 'executable_callback': 'ale_linters#scss#stylelint#GetExecutable',
\ 'command_callback': 'ale_linters#scss#stylelint#GetCommand',
\ 'callback': 'ale#handlers#HandleStyleLintFormat',
\})

View File

@@ -1,12 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Lints sh files using bash -n
if exists('g:loaded_ale_linters_sh_shell')
finish
endif
let g:loaded_ale_linters_sh_shell = 1
" This option can be changed to change the default shell when the shell
" cannot be taken from the hashbang line.
if !exists('g:ale_linters_sh_shell_default_shell')
@@ -17,7 +11,7 @@ if !exists('g:ale_linters_sh_shell_default_shell')
endif
endif
function! ale_linters#sh#shell#GetExecutable(buffer)
function! ale_linters#sh#shell#GetExecutable(buffer) abort
let l:banglines = getbufline(a:buffer, 1)
" Take the shell executable from the hashbang, if we can.
@@ -35,11 +29,11 @@ function! ale_linters#sh#shell#GetExecutable(buffer)
return g:ale_linters_sh_shell_default_shell
endfunction
function! ale_linters#sh#shell#GetCommand(buffer)
function! ale_linters#sh#shell#GetCommand(buffer) abort
return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n'
endfunction
function! ale_linters#sh#shell#Handle(buffer, lines)
function! ale_linters#sh#shell#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" bash: line 13: syntax error near unexpected token `d'

View File

@@ -2,12 +2,6 @@
" Description: This file adds support for using the shellcheck linter with
" shell scripts.
if exists('g:loaded_ale_linters_sh_shellcheck')
finish
endif
let g:loaded_ale_linters_sh_shellcheck = 1
" This global variable can be set with a string of comma-seperated error
" codes to exclude from shellcheck. For example:
"
@@ -22,9 +16,25 @@ else
let s:exclude_option = ''
endif
function! s:GetDialectArgument() abort
if exists('b:is_bash') && b:is_bash
return '-s bash'
elseif exists('b:is_sh') && b:is_sh
return '-s sh'
elseif exists('b:is_kornshell') && b:is_kornshell
return '-s ksh'
endif
return ''
endfunction
function! ale_linters#sh#shellcheck#GetCommand(buffer) abort
return 'shellcheck ' . s:exclude_option . ' ' . s:GetDialectArgument() . ' -f gcc -'
endfunction
call ale#linter#Define('sh', {
\ 'name': 'shellcheck',
\ 'executable': 'shellcheck',
\ 'command': 'shellcheck ' . s:exclude_option . ' -f gcc -',
\ 'command_callback': 'ale_linters#sh#shellcheck#GetCommand',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -0,0 +1,9 @@
" Author: David Mohundro <david@mohundro.com>
" Description: swiftlint for swift files
call ale#linter#Define('swift', {
\ 'name': 'swiftlint',
\ 'executable': 'swiftlint',
\ 'command': 'swiftlint lint --use-stdin',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -0,0 +1,10 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: dummy linter to use in tests
call ale#linter#Define('testft', {
\ 'name': 'testlinter',
\ 'output_stream': 'stdout',
\ 'executable': 'testlinter',
\ 'command': 'testlinter',
\ 'callback': 'testCB',
\})

View File

@@ -0,0 +1,63 @@
" Author: Andrew Balmos - <andrew@balmos.org>
" Description: chktex for LaTeX files
let g:ale_tex_chktex_executable =
\ get(g:, 'ale_tex_chktex_executable', 'chktex')
let g:ale_tex_chktex_options =
\ get(g:, 'ale_tex_chktex_options', '-I')
function! ale_linters#tex#chktex#GetCommand(buffer) abort
" Check for optional .chktexrc
let l:chktex_config = ale#util#FindNearestFile(
\ a:buffer,
\ '.chktexrc')
let l:command = g:ale_tex_chktex_executable
" Avoid bug when used without -p (last warning has gibberish for a filename)
let l:command .= ' -v0 -p stdin -q'
if !empty(l:chktex_config)
let l:command .= ' -l ' . fnameescape(l:chktex_config)
endif
let l:command .= ' ' . g:ale_tex_chktex_options
return l:command
endfunction
function! ale_linters#tex#chktex#Handle(buffer, lines) abort
" Mattes lines like:
"
" stdin:499:2:24:Delete this space to maintain correct pagereferences.
" stdin:507:81:3:You should enclose the previous parenthesis with `{}'.
let l:pattern = '^stdin:\(\d\+\):\(\d\+\):\(\d\+\):\(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4] . ' (' . (l:match[3]+0) . ')',
\ 'type': 'W',
\ 'nr': -1
\})
endfor
return l:output
endfunction
call ale#linter#Define('tex', {
\ 'name': 'chktex',
\ 'executable': 'chktex',
\ 'command_callback': 'ale_linters#tex#chktex#GetCommand',
\ 'callback': 'ale_linters#tex#chktex#Handle'
\})

View File

@@ -0,0 +1,50 @@
" Author: Andrew Balmos - <andrew@balmos.org>
" Description: lacheck for LaTeX files
let g:ale_tex_lacheck_executable =
\ get(g:, 'ale_tex_lacheck_executable', 'lacheck')
function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
" Mattes lines like:
"
" "book.tex", line 37: possible unwanted space at "{"
" "book.tex", line 38: missing `\ ' after "etc."
let l:pattern = '^".\+", line \(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
" lacheck follows `\input{}` commands. If the cwd is not the same as the
" file in the buffer then it will fail to find the inputed items. We do not
" want warnings from those items anyway
if !empty(matchstr(l:match[2], '^Could not open ".\+"$'))
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'text': l:match[2],
\ 'type': 'W',
\ 'nr': -1
\})
endfor
return l:output
endfunction
call ale#linter#Define('tex', {
\ 'name': 'lacheck',
\ 'executable': 'lacheck',
\ 'command': g:ale#util#stdin_wrapper . ' .tex '
\ . g:ale_tex_lacheck_executable,
\ 'callback': 'ale_linters#tex#lacheck#Handle'
\})

View File

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

View File

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

View File

@@ -1,19 +1,14 @@
" Author: Prashanth Chandra https://github.com/prashcr
" Description: tslint for TypeScript files
if exists('g:loaded_ale_linters_typescript_tslint')
finish
endif
let g:loaded_ale_linters_typescript_tslint = 1
function! ale_linters#typescript#tslint#Handle(buffer, lines)
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" hello.ts[7, 41]: trailing whitespace
" hello.ts[5, 1]: Forbidden 'var' keyword, use 'let' or 'const' instead
"
let l:pattern = '.\+.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
let l:ext = '.' . fnamemodify(bufname(a:buffer), ':e')
let l:pattern = '.\+' . l:ext . '\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
let l:output = []
for l:line in a:lines
@@ -43,9 +38,18 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines)
return l:output
endfunction
function! ale_linters#typescript#tslint#BuildLintCommand(buffer_n) abort
let l:tsconfig_path = ale#util#FindNearestFile(a:buffer_n, 'tslint.json')
let l:tslint_options = empty(l:tsconfig_path) ? '' : '-c ' . l:tsconfig_path
let l:ext = '.' . fnamemodify(bufname(a:buffer_n), ':e')
return g:ale#util#stdin_wrapper . ' ' . l:ext . ' tslint ' . l:tslint_options
endfunction
call ale#linter#Define('typescript', {
\ 'name': 'tslint',
\ 'executable': 'tslint',
\ 'command': g:ale#util#stdin_wrapper . ' .ts tslint',
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
\ 'callback': 'ale_linters#typescript#tslint#Handle',
\})

View File

@@ -0,0 +1,45 @@
" Author: Prashanth Chandra https://github.com/prashcr, Aleh Kashnikau https://github.com/mkusher
" Description: type checker for TypeScript files
function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" hello.ts[7, 41]: Property 'a' does not exist on type 'A'
" hello.ts[16, 7]: Type 'A' is not assignable to type 'B'
"
let l:pattern = '.\+\.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:line = l:match[1] + 0
let l:column = l:match[2] + 0
let l:type = 'E'
let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('typescript', {
\ 'name': 'typecheck',
\ 'executable': 'typecheck',
\ 'command': 'typecheck %s',
\ 'callback': 'ale_linters#typescript#typecheck#Handle',
\})

View File

@@ -1,13 +1,7 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: iverilog for verilog files
if exists('g:loaded_ale_linters_verilog_iverilog')
finish
endif
let g:loaded_ale_linters_verilog_iverilog = 1
function! ale_linters#verilog#iverilog#Handle(buffer, lines)
function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort
" Look for lines like the following.
"
" tb_me_top.v:37: warning: Instantiating module me_top with dangling input port 1 (rst_n) floating.

View File

@@ -1,13 +1,7 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: verilator for verilog files
if exists('g:loaded_ale_linters_verilog_verilator')
finish
endif
let g:loaded_ale_linters_verilog_verilator = 1
function! ale_linters#verilog#verilator#Handle(buffer, lines)
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
" Look for lines like the following.
"
" %Error: addr_gen.v:3: syntax error, unexpected IDENTIFIER
@@ -16,7 +10,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines)
" %Warning-UNDRIVEN: test.v:3: Signal is not driven: clk
" %Warning-UNUSED: test.v:4: Signal is not used: dout
" %Warning-BLKSEQ: test.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).
let l:pattern = '^%\(Warning\|Error\)[^:]*:[^:]\+:\(\d\+\): \(.\+\)$'
let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
@@ -26,19 +20,22 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines)
continue
endif
let l:line = l:match[2] + 0
let l:line = l:match[3] + 0
let l:type = l:match[1] ==# 'Error' ? 'E' : 'W'
let l:text = l:match[3]
let l:text = l:match[4]
let l:file = l:match[2]
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 1,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
if(l:file =~# '_verilator_linted.v')
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 1,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endif
endfor
return l:output
@@ -48,6 +45,6 @@ call ale#linter#Define('verilog', {
\ 'name': 'verilator',
\ 'output_stream': 'stderr',
\ 'executable': 'verilator',
\ 'command': g:ale#util#stdin_wrapper . ' .v verilator --lint-only -Wall -Wno-DECLFILENAME',
\ 'command': g:ale#util#stdin_wrapper . ' _verilator_linted.v verilator --lint-only -Wall -Wno-DECLFILENAME',
\ 'callback': 'ale_linters#verilog#verilator#Handle',
\})

View File

@@ -1,17 +1,12 @@
" Author: w0rp <devw0rp@gmail.com>, KabbAmine <amine.kabb@gmail.com>
" Description: This file adds support for checking Vim code with Vint.
if exists('g:loaded_ale_linters_vim_vint')
finish
endif
let g:loaded_ale_linters_vim_vint = 1
" This flag can be used to change enable/disable style issues.
let g:ale_vim_vint_show_style_issues =
\ get(g:, 'ale_vim_vint_show_style_issues', 1)
let s:warning_flag = g:ale_vim_vint_show_style_issues ? '-s' : '-w'
let s:enable_neovim = has('nvim') ? ' --enable-neovim ' : ''
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
call ale#linter#Define('vim', {
@@ -21,6 +16,7 @@ call ale#linter#Define('vim', {
\ . ' .vim vint '
\ . s:warning_flag
\ . ' --no-color '
\ . s:enable_neovim
\ . s:format,
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -1,12 +1,6 @@
" Author: KabbAmine <amine.kabb@gmail.com>
if exists('g:loaded_ale_linters_yaml_yamllint')
finish
endif
let g:loaded_ale_linters_yaml_yamllint = 1
function! ale_linters#yaml#yamllint#Handle(buffer, lines)
function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
" Matches patterns line the following:
" something.yaml:1:1: [warning] missing document start "---" (document-start)
" something.yml:2:1: [error] syntax error: expected the node content, but found '<stream end>'

View File

@@ -5,6 +5,11 @@
let s:lint_timer = -1
function! ale#Queue(delay) abort
" Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
return
endif
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
@@ -24,11 +29,19 @@ function! ale#Queue(delay) abort
endfunction
function! ale#Lint(...) abort
" Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
return
endif
let l:buffer = bufnr('%')
let l:linters = ale#linter#Get(&filetype)
" Set a variable telling us to clear the loclist later.
let g:ale_buffer_should_reset_map[l:buffer] = 1
" Initialise the buffer information if needed.
call ale#engine#InitBufferInfo(l:buffer)
" Clear the new loclist again, so we will work with all new items.
let g:ale_buffer_info[l:buffer].new_loclist = []
for l:linter in l:linters
" Check if a given linter has a program which can be executed.

View File

@@ -2,19 +2,12 @@
" Description: Utility functions related to cleaning state.
function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_count_map, a:buffer)
call remove(g:ale_buffer_count_map, a:buffer)
endif
if has_key(g:ale_buffer_info, a:buffer)
" When buffers are removed, clear all of the jobs.
for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
call ale#engine#ClearJob(l:job)
endfor
if has_key(g:ale_buffer_loclist_map, a:buffer)
call remove(g:ale_buffer_loclist_map, a:buffer)
endif
if has_key(g:ale_buffer_should_reset_map, a:buffer)
call remove(g:ale_buffer_should_reset_map, a:buffer)
endif
if has_key(g:ale_buffer_sign_dummy_map, a:buffer)
call remove(g:ale_buffer_sign_dummy_map, a:buffer)
call remove(g:ale_buffer_info, a:buffer)
endif
endfunction

View File

@@ -46,30 +46,51 @@ function! ale#cursor#EchoCursorWarning(...) abort
let l:buffer = bufnr('%')
if !has_key(g:ale_buffer_loclist_map, l:buffer)
if !has_key(g:ale_buffer_info, l:buffer)
return
endif
let l:pos = getcurpos()
let l:loclist = g:ale_buffer_loclist_map[l:buffer]
let l:loclist = g:ale_buffer_info[l:buffer].loclist
let l:index = ale#util#BinarySearch(l:loclist, l:pos[1], l:pos[2])
if l:index >= 0
let l:loc = l:loclist[l:index]
let l:msg = s:GetMessage(l:loc.linter_name, l:loc.type, l:loc.text)
call ale#cursor#TruncatedEcho(l:msg)
let g:ale_buffer_info[l:buffer].echoed = 1
else
echo
" We'll only clear the echoed message when moving off errors once,
" so we don't continually clear the echo line.
if get(g:ale_buffer_info[l:buffer], 'echoed')
echo
let g:ale_buffer_info[l:buffer].echoed = 0
endif
endif
endfunction
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
function! ale#cursor#EchoCursorWarningWithDelay() abort
" Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
return
endif
if s:cursor_timer != -1
call timer_stop(s:cursor_timer)
let s:cursor_timer = -1
endif
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
let l:pos = getcurpos()[0:2]
" Check the current buffer, line, and column number against the last
" recorded position. If the position has actually changed, *then*
" we should echo something. Otherwise we can end up doing processing
" the echo message far too frequently.
if l:pos != s:last_pos
let s:last_pos = l:pos
let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
endif
endfunction

View File

@@ -20,7 +20,20 @@ function! s:GetJobID(job) abort
return ch_info(job_getchannel(a:job)).id
endfunction
function! s:ClearJob(job) abort
function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" job_list will hold the list of jobs
" loclist holds the loclist items after all jobs have completed.
" new_loclist holds loclist items while jobs are being run.
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'loclist': [],
\ 'new_loclist': [],
\}
endif
endfunction
function! ale#engine#ClearJob(job) abort
let l:job_id = s:GetJobID(a:job)
let l:linter = s:job_info_map[l:job_id].linter
@@ -37,25 +50,66 @@ function! s:ClearJob(job) abort
endif
call remove(s:job_info_map, l:job_id)
call remove(l:linter, 'job')
endfunction
function! s:GatherOutput(job, data) abort
function! s:StopPreviousJobs(buffer, linter) abort
if !has_key(g:ale_buffer_info, a:buffer)
" Do nothing if we didn't run anything for the buffer.
return
endif
let l:new_job_list = []
for l:job in g:ale_buffer_info[a:buffer].job_list
let l:job_id = s:GetJobID(l:job)
if has_key(s:job_info_map, l:job_id)
\&& s:job_info_map[l:job_id].linter.name ==# a:linter.name
" Stop jobs which match the buffer and linter.
call ale#engine#ClearJob(l:job)
else
" Keep other jobs in the list.
call add(l:new_job_list, l:job)
endif
endfor
" Update the list, removing the previously run job.
let g:ale_buffer_info[a:buffer].job_list = l:new_job_list
endfunction
function! s:GatherOutputVim(channel, data) abort
let l:job_id = s:GetJobID(ch_getjob(a:channel))
if !has_key(s:job_info_map, l:job_id)
return
endif
call add(s:job_info_map[l:job_id].output, a:data)
endfunction
function! s:GatherOutputNeoVim(job, data, event) abort
let l:job_id = s:GetJobID(a:job)
if !has_key(s:job_info_map, l:job_id)
return
endif
call extend(s:job_info_map[l:job_id].output, a:data)
" Join the lines passed to ale, because Neovim splits them up.
" a:data is a list of strings, where every item is a new line, except the
" first one, which is the continuation of the last item passed last time.
call ale#engine#JoinNeovimOutput(s:job_info_map[l:job_id].output, a:data)
endfunction
function! s:GatherOutputVim(channel, data) abort
call s:GatherOutput(ch_getjob(a:channel), [a:data])
endfunction
function! ale#engine#JoinNeovimOutput(output, data) abort
if empty(a:output)
call extend(a:output, a:data)
else
" Extend the previous line, which can be continued.
let a:output[-1] .= get(a:data, 0, '')
function! s:GatherOutputNeoVim(job, data, event) abort
call s:GatherOutput(a:job, a:data)
" Add the new lines.
call extend(a:output, a:data[1:])
endif
endfunction
function! s:HandleExit(job) abort
@@ -71,15 +125,17 @@ function! s:HandleExit(job) abort
endif
let l:job_info = s:job_info_map[l:job_id]
call s:ClearJob(a:job)
let l:linter = l:job_info.linter
let l:output = l:job_info.output
let l:buffer = l:job_info.buffer
let l:next_chain_index = l:job_info.next_chain_index
if !has_key(g:ale_buffer_should_reset_map, l:buffer)
" A job ended for a buffer which has been closed, so stop here.
" Call the same function for stopping jobs again to clean up the job
" which just closed.
call s:StopPreviousJobs(l:buffer, l:linter)
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
return
endif
@@ -92,30 +148,35 @@ function! s:HandleExit(job) abort
let l:item.linter_name = l:linter.name
endfor
if g:ale_buffer_should_reset_map[l:buffer]
let g:ale_buffer_should_reset_map[l:buffer] = 0
let g:ale_buffer_loclist_map[l:buffer] = []
endif
" Add the loclist items from the linter.
call extend(g:ale_buffer_loclist_map[l:buffer], l:linter_loclist)
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
if !empty(g:ale_buffer_info[l:buffer].job_list)
" Wait for all jobs to complete before doing anything else.
return
endif
" Sort the loclist again.
" We need a sorted list so we can run a binary search against it
" for efficient lookup of the messages in the cursor handler.
call sort(g:ale_buffer_loclist_map[l:buffer], 'ale#util#LocItemCompare')
call sort(g:ale_buffer_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
if g:ale_set_loclist
call setloclist(0, g:ale_buffer_loclist_map[l:buffer])
" Now swap the old and new loclists, after we have collected everything
" and sorted the list again.
let g:ale_buffer_info[l:buffer].loclist = g:ale_buffer_info[l:buffer].new_loclist
let g:ale_buffer_info[l:buffer].new_loclist = []
if g:ale_set_quickfix || g:ale_set_loclist
call ale#list#SetLists(g:ale_buffer_info[l:buffer].loclist)
endif
if g:ale_set_signs
call ale#sign#SetSigns(l:buffer, g:ale_buffer_loclist_map[l:buffer])
call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif
if exists('*ale#statusline#Update')
" Don't load/run if not already loaded.
call ale#statusline#Update(l:buffer, g:ale_buffer_loclist_map[l:buffer])
call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif
" Call user autocommands. This allows users to hook into ALE's lint cycle.
@@ -149,42 +210,37 @@ function! s:FixLocList(buffer, loclist) abort
endfor
endfunction
function! ale#engine#Invoke(buffer, linter) abort
if has_key(a:linter, 'job')
" Stop previous jobs for the same linter.
call s:ClearJob(a:linter.job)
endif
if has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead.
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
else
let l:command = a:linter.command
endif
function! s:RunJob(command, generic_job_options) abort
let l:buffer = a:generic_job_options.buffer
let l:linter = a:generic_job_options.linter
let l:output_stream = a:generic_job_options.output_stream
let l:next_chain_index = a:generic_job_options.next_chain_index
let l:read_buffer = a:generic_job_options.read_buffer
let l:command = a:command
if l:command =~# '%s'
" If there is a '%s' in the command string, replace it with the name
" of the file.
let l:command = printf(l:command, shellescape(fnamemodify(bufname(a:buffer), ':p')))
let l:command = printf(l:command, shellescape(fnamemodify(bufname(l:buffer), ':p')))
endif
if has('nvim')
if a:linter.output_stream ==# 'stderr'
if l:output_stream ==# 'stderr'
" Read from stderr instead of stdout.
let l:job = jobstart(l:command, {
\ 'on_stderr': 's:GatherOutputNeoVim',
\ 'on_exit': 's:HandleExitNeoVim',
\ 'on_stderr': function('s:GatherOutputNeoVim'),
\ 'on_exit': function('s:HandleExitNeoVim'),
\})
elseif a:linter.output_stream ==# 'both'
elseif l:output_stream ==# 'both'
let l:job = jobstart(l:command, {
\ 'on_stdout': 's:GatherOutputNeoVim',
\ 'on_stderr': 's:GatherOutputNeoVim',
\ 'on_exit': 's:HandleExitNeoVim',
\ 'on_stdout': function('s:GatherOutputNeoVim'),
\ 'on_stderr': function('s:GatherOutputNeoVim'),
\ 'on_exit': function('s:HandleExitNeoVim'),
\})
else
let l:job = jobstart(l:command, {
\ 'on_stdout': 's:GatherOutputNeoVim',
\ 'on_exit': 's:HandleExitNeoVim',
\ 'on_stdout': function('s:GatherOutputNeoVim'),
\ 'on_exit': function('s:HandleExitNeoVim'),
\})
endif
else
@@ -195,10 +251,10 @@ function! ale#engine#Invoke(buffer, linter) abort
\ 'close_cb': function('s:HandleExitVim'),
\}
if a:linter.output_stream ==# 'stderr'
if l:output_stream ==# 'stderr'
" Read from stderr instead of stdout.
let l:job_options.err_cb = function('s:GatherOutputVim')
elseif a:linter.output_stream ==# 'both'
elseif l:output_stream ==# 'both'
" Read from both streams.
let l:job_options.out_cb = function('s:GatherOutputVim')
let l:job_options.err_cb = function('s:GatherOutputVim')
@@ -215,10 +271,12 @@ function! ale#engine#Invoke(buffer, linter) abort
" Execute the command with the shell, to fix escaping issues.
let l:command = split(&shell) + split(&shellcmdflag) + [l:command]
" On Unix machines, we can send the Vim buffer directly.
" This is faster than reading the lines ourselves.
let l:job_options.in_io = 'buffer'
let l:job_options.in_buf = a:buffer
if l:read_buffer
" On Unix machines, we can send the Vim buffer directly.
" This is faster than reading the lines ourselves.
let l:job_options.in_io = 'buffer'
let l:job_options.in_buf = l:buffer
endif
endif
" Vim 8 will read the stdin from the file's buffer.
@@ -227,34 +285,116 @@ function! ale#engine#Invoke(buffer, linter) abort
" Only proceed if the job is being run.
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run')
let a:linter.job = l:job
" Add the job to the list of jobs, so we can track them.
call add(g:ale_buffer_info[l:buffer].job_list, l:job)
" Store the ID for the job in the map to read back again.
let s:job_info_map[s:GetJobID(l:job)] = {
\ 'linter': a:linter,
\ 'buffer': a:buffer,
\ 'linter': l:linter,
\ 'buffer': l:buffer,
\ 'output': [],
\ 'next_chain_index': l:next_chain_index,
\}
if has('nvim')
" In NeoVim, we have to send the buffer lines ourselves.
let l:input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
if l:read_buffer
if has('nvim')
" In NeoVim, we have to send the buffer lines ourselves.
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
call jobsend(l:job, l:input)
call jobclose(l:job, 'stdin')
elseif has('win32')
" On some Vim versions, we have to send the buffer data ourselves.
let l:input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
let l:channel = job_getchannel(l:job)
call jobsend(l:job, l:input)
call jobclose(l:job, 'stdin')
elseif has('win32')
" On some Vim versions, we have to send the buffer data ourselves.
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
let l:channel = job_getchannel(l:job)
if ch_status(l:channel) ==# 'open'
call ch_sendraw(l:channel, l:input)
call ch_close_in(l:channel)
if ch_status(l:channel) ==# 'open'
call ch_sendraw(l:channel, l:input)
call ch_close_in(l:channel)
endif
endif
endif
endif
endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
let l:chain_index = a:chain_index
let l:input = a:input
if has_key(a:linter, 'command_chain')
while l:chain_index < len(a:linter.command_chain)
" Run a chain of commands, one asychronous command after the other,
" so that many programs can be run in a sequence.
let l:chain_item = a:linter.command_chain[l:chain_index]
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
endif
if l:chain_index == 0
" The first callback in the chain takes only a buffer number.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer
\)
else
" The second callback in the chain takes some input too.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer,
\ l:input
\)
endif
if !empty(l:command)
" We hit a command to run, so we'll execute that
break
endif
" Command chain items can return an empty string to indicate that
" a command should be skipped, so we should try the next item
" with no input.
let l:input = []
let l:chain_index += 1
endwhile
if empty(l:command)
" Don't run any jobs if the last command is an empty string.
return
endif
elseif has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead.
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
else
let l:command = a:linter.command
endif
let l:is_last_job = l:chain_index >= len(get(a:linter, 'command_chain', [])) - 1
call s:RunJob(l:command, {
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': l:output_stream,
\ 'next_chain_index': l:chain_index + 1,
\ 'read_buffer': l:is_last_job,
\})
endfunction
function! ale#engine#Invoke(buffer, linter) abort
" Stop previous jobs for the same linter.
call s:StopPreviousJobs(a:buffer, a:linter)
call s:InvokeChain(a:buffer, a:linter, 0, [])
endfunction
" Given a buffer number, return the warnings and errors for a given buffer.
function! ale#engine#GetLoclist(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
return []
endif
return g:ale_buffer_info[a:buffer].loclist
endfunction
" This function can be called with a timeout to wait for all jobs to finish.
" If the jobs to not finish in the given number of milliseconds,
" an exception will be thrown.
@@ -270,8 +410,9 @@ function! ale#engine#WaitForJobs(deadline) abort
let l:job_list = []
for l:job_id in keys(s:job_info_map)
call add(l:job_list, s:job_info_map[l:job_id].linter.job)
" Gather all of the jobs from every buffer.
for l:info in values(g:ale_buffer_info)
call extend(l:job_list, l:info.job_list)
endfor
let l:should_wait_more = 1
@@ -301,4 +442,27 @@ function! ale#engine#WaitForJobs(deadline) abort
" prevents the occasional failure where this function exits after jobs
" end, but before handlers are run.
sleep 10ms
" We must check the buffer data again to see if new jobs started
" for command_chain linters.
let l:has_new_jobs = 0
for l:info in values(g:ale_buffer_info)
if !empty(l:info.job_list)
let l:has_new_jobs = 1
endif
endfor
if l:has_new_jobs
" We have to wait more. Offset the timeout by the time taken so far.
let l:now = system('date +%s%3N') + 0
let l:new_deadline = a:deadline - (l:now - l:start_time)
if l:new_deadline <= 0
" Enough time passed already, so stop immediately.
throw 'Jobs did not complete on time!'
endif
call ale#engine#WaitForJobs(l:new_deadline)
endif
endfunction

View File

@@ -4,7 +4,7 @@ scriptencoding utf-8
" linter which outputs warnings and errors in a format accepted by one of
" these functions can simply use one of these pre-defined error handlers.
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.-]\+'
let s:path_pattern = '[a-zA-Z]\?\\\?:\?[[:alnum:]/\.\-_]\+'
function! s:HandleUnixFormat(buffer, lines, type) abort
" Matches patterns line the following:
@@ -12,7 +12,7 @@ function! s:HandleUnixFormat(buffer, lines, type) abort
" file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args
" file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
" file.go:5:2: expected declaration, found 'STRING' "log"
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \(.\+\)$'
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?:\? \(.\+\)$'
let l:output = []
for l:line in a:lines
@@ -45,7 +45,6 @@ function! ale#handlers#HandleUnixFormatAsWarning(buffer, lines) abort
return s:HandleUnixFormat(a:buffer, a:lines, 'W')
endfunction
function! ale#handlers#HandleGCCFormat(buffer, lines) abort
" Look for lines like the following.
"
@@ -68,7 +67,78 @@ function! ale#handlers#HandleGCCFormat(buffer, lines) abort
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4],
\ 'type': l:match[3] ==# 'error' ? 'E' : 'W',
\ 'type': l:match[3] =~# 'error' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
function! ale#handlers#HandleCppCheckFormat(buffer, lines) abort
" Look for lines like the following.
"
" [test.cpp:5]: (error) Array 'a[10]' accessed at index 10, which is out of bounds
let l:pattern = '^\[.\{-}:\(\d\+\)\]: (\(.\{-}\)) \(.\+\)'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'text': l:match[3] . ' (' . l:match[2] . ')',
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
function! ale#handlers#HandlePEP8Format(buffer, lines) abort
" Matches patterns line the following:
"
" Matches patterns line the following:
"
" stdin:6:6: E111 indentation is not a multiple of four
" test.yml:35: [EANSIBLE0002] Trailing whitespace
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \[\?\(\([[:alpha:]]\)[[:alnum:]]\+\)\]\? \(.*\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:code = l:match[3]
if (l:code ==# 'W291' || l:code ==# 'W293' || l:code ==# 'EANSIBLE002')
\ && !g:ale_warn_about_trailing_whitespace
" Skip warnings for trailing whitespace if the option is off.
continue
endif
if l:code ==# 'I0011'
" Skip 'Locally disabling' message
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:code . ': ' . l:match[5],
\ 'type': l:match[4] ==# 'E' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
@@ -116,3 +186,37 @@ function! ale#handlers#HandleCSSLintFormat(buffer, lines) abort
return l:output
endfunction
function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
" Matches patterns line the following:
"
" src/main.css
" 108:10 ✖ Unexpected leading zero number-leading-zero
" 116:20 ✖ Expected a trailing semicolon declaration-block-trailing-semicolon
let l:pattern = '^.* \(\d\+\):\(\d\+\) \s\+\(\S\+\)\s\+ \(\u.\+\) \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:type = l:match[3] ==# '✖' ? 'E' : 'W'
let l:text = l:match[4] . '[' . l:match[5] . ']'
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
return l:output
endfunction

View File

@@ -0,0 +1,90 @@
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>,
" w0rp <devw0rp@gmail.com>
"
" Description: This file implements handlers specific to Rust.
if !exists('g:ale_rust_ignore_error_codes')
let g:ale_rust_ignore_error_codes = []
endif
" returns: a list [lnum, col] with the location of the error or []
function! s:FindErrorInExpansion(span, file_name) abort
if a:span.file_name ==# a:file_name
return [a:span.line_start, a:span.byte_start]
endif
if !empty(a:span.expansion)
return s:FindErrorInExpansion(a:span.expansion.span, a:file_name)
endif
return []
endfunction
" A handler function which accepts a file name, to make unit testing easier.
function! ale#handlers#rust#HandleRustErrorsForFile(buffer, full_filename, lines) abort
let l:filename = fnamemodify(a:full_filename, ':t')
let l:output = []
for l:errorline in a:lines
" ignore everything that is not Json
if l:errorline !~# '^{'
continue
endif
let l:error = json_decode(l:errorline)
if has_key(l:error, 'message') && type(l:error.message) == type({})
let l:error = l:error.message
endif
if !has_key(l:error, 'code')
continue
endif
if !empty(l:error.code) && index(g:ale_rust_ignore_error_codes, l:error.code.code) > -1
continue
endif
for l:span in l:error.spans
let l:span_filename = fnamemodify(l:span.file_name, ':t')
if (
\ l:span.is_primary
\ && (l:span_filename ==# l:filename || l:span_filename ==# '<anon>')
\)
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:span.line_start,
\ 'vcol': 0,
\ 'col': l:span.byte_start,
\ 'nr': -1,
\ 'text': l:error.message,
\ 'type': toupper(l:error.level[0]),
\})
else
" when the error is caused in the expansion of a macro, we have
" to bury deeper
let l:root_cause = s:FindErrorInExpansion(l:span, l:filename)
if !empty(l:root_cause)
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:root_cause[0],
\ 'vcol': 0,
\ 'col': l:root_cause[1],
\ 'nr': -1,
\ 'text': l:error.message,
\ 'type': toupper(l:error.level[0]),
\})
endif
endif
endfor
endfor
return l:output
endfunction
" A handler for output for Rust linters.
function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
return ale#handlers#rust#HandleRustErrorsForFile(a:buffer, bufname(a:buffer), a:lines)
endfunction

View File

@@ -7,52 +7,134 @@ let s:linters = {}
" Default filetype aliaes.
" The user defined aliases will be merged with this Dictionary.
let s:default_ale_linter_aliases = {
\ 'javascript.jsx': 'javascript',
\ 'zsh': 'sh',
\ 'Dockerfile': 'dockerfile',
\ 'csh': 'sh',
\ 'plaintex': 'tex',
\ 'systemverilog': 'verilog',
\ 'zsh': 'sh',
\}
" Default linters to run for particular filetypes.
" The user defined linter selections will be merged with this Dictionary.
"
" No linters are used for plaintext files by default.
let s:default_ale_linters = {
\ 'zsh': ['shell'],
\ 'csh': ['shell'],
\ 'text': [],
\}
" Testing/debugging helper to unload all linters.
function! ale#linter#Reset() abort
let s:linters = {}
endfunction
function! s:IsCallback(value) abort
return type(a:value) == type('') || type(a:value) == type(function('type'))
endfunction
function! ale#linter#PreProcess(linter) abort
if type(a:linter) != type({})
throw 'The linter object must be a Dictionary'
endif
let l:obj = {
\ 'name': get(a:linter, 'name'),
\ 'callback': get(a:linter, 'callback'),
\}
if type(l:obj.name) != type('')
throw '`name` must be defined to name the linter'
endif
if !s:IsCallback(l:obj.callback)
throw '`callback` must be defined with a callback to accept output'
endif
if has_key(a:linter, 'executable_callback')
let l:obj.executable_callback = a:linter.executable_callback
if !s:IsCallback(l:obj.executable_callback)
throw '`executable_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'executable')
let l:obj.executable = a:linter.executable
if type(l:obj.executable) != type('')
throw '`executable` must be a string if defined'
endif
else
throw 'Either `executable` or `executable_callback` must be defined'
endif
if has_key(a:linter, 'command_chain')
let l:obj.command_chain = a:linter.command_chain
if type(l:obj.command_chain) != type([])
throw '`command_chain` must be a List'
endif
if empty(l:obj.command_chain)
throw '`command_chain` must contain at least one item'
endif
let l:link_index = 0
for l:link in l:obj.command_chain
let l:err_prefix = 'The `command_chain` item ' . l:link_index . ' '
if !s:IsCallback(get(l:link, 'callback'))
throw l:err_prefix . 'must define a `callback` function'
endif
if has_key(l:link, 'output_stream')
if type(l:link.output_stream) != type('')
\|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0
throw l:err_prefix . '`output_stream` flag must be '
\ . "'stdout', 'stderr', or 'both'"
endif
endif
let l:link_index += 1
endfor
elseif has_key(a:linter, 'command_callback')
let l:obj.command_callback = a:linter.command_callback
if !s:IsCallback(l:obj.command_callback)
throw '`command_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'command')
let l:obj.command = a:linter.command
if type(l:obj.command) != type('')
throw '`command` must be a string if defined'
endif
else
throw 'Either `command`, `executable_callback`, `command_chain` '
\ . 'must be defined'
endif
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
if type(l:obj.output_stream) != type('')
\|| index(['stdout', 'stderr', 'both'], l:obj.output_stream) < 0
throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
endif
return l:obj
endfunction
function! ale#linter#Define(filetype, linter) abort
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
let l:new_linter = {
\ 'name': a:linter.name,
\ 'callback': a:linter.callback,
\}
if has_key(a:linter, 'executable_callback')
let l:new_linter.executable_callback = a:linter.executable_callback
else
let l:new_linter.executable = a:linter.executable
endif
if has_key(a:linter, 'command_callback')
let l:new_linter.command_callback = a:linter.command_callback
else
let l:new_linter.command = a:linter.command
endif
if has_key(a:linter, 'output_stream')
let l:new_linter.output_stream = a:linter.output_stream
else
let l:new_linter.output_stream = 'stdout'
endif
" TODO: Assert the value of the output_stream to be something sensible.
let l:new_linter = ale#linter#PreProcess(a:linter)
call add(s:linters[a:filetype], l:new_linter)
endfunction
function! s:LoadLinters(filetype) abort
function! ale#linter#GetAll(filetype) abort
if a:filetype ==# ''
" Empty filetype? Nothing to be done about that.
return []
@@ -74,7 +156,7 @@ function! s:LoadLinters(filetype) abort
return s:linters[a:filetype]
endfunction
function! ale#linter#Get(original_filetype) abort
function! s:ResolveFiletype(original_filetype) abort
" Try and get an aliased file type either from the user's Dictionary, or
" our default Dictionary, otherwise use the filetype as-is.
let l:filetype = get(
@@ -87,32 +169,67 @@ function! ale#linter#Get(original_filetype) abort
\ )
\)
" Try and get a list of linters to run, using the original file type,
" not the aliased filetype. We have some linters to limit by default,
" and users may define their own list of linters to run.
let l:linter_names = get(
\ g:ale_linters,
\ a:original_filetype,
\ get(
\ s:default_ale_linters,
\ a:original_filetype,
\ 'all'
\ )
\)
return l:filetype
endfunction
let l:all_linters = s:LoadLinters(l:filetype)
function! ale#linter#Get(original_filetypes) abort
let l:combined_linters = []
if type(l:linter_names) == type('') && l:linter_names ==# 'all'
let l:combined_linters = l:all_linters
elseif type(l:linter_names) == type([])
" Select only the linters we or the user has specified.
for l:linter in l:all_linters
if index(l:linter_names, l:linter.name) >= 0
call add(l:combined_linters, l:linter)
endif
endfor
endif
" Handle dot-seperated filetypes.
for l:original_filetype in split(a:original_filetypes, '\.')
let l:filetype = s:ResolveFiletype(l:original_filetype)
" Try and get a list of linters to run, using the original file type,
" not the aliased filetype. We have some linters to limit by default,
" and users may define their own list of linters to run.
let l:linter_names = get(
\ g:ale_linters,
\ l:original_filetype,
\ get(
\ s:default_ale_linters,
\ l:original_filetype,
\ 'all'
\ )
\)
let l:all_linters = ale#linter#GetAll(l:filetype)
let l:filetype_linters = []
if type(l:linter_names) == type('') && l:linter_names ==# 'all'
let l:filetype_linters = l:all_linters
elseif type(l:linter_names) == type([])
" Select only the linters we or the user has specified.
for l:linter in l:all_linters
if index(l:linter_names, l:linter.name) >= 0
call add(l:filetype_linters, l:linter)
endif
endfor
endif
call extend(l:combined_linters, l:filetype_linters)
endfor
return l:combined_linters
endfunction
function! ale#linter#Info() abort
let l:original_filetypes = &filetype
" We get the list of enabled linters for free by the above function.
let l:enabled_linters = deepcopy(ale#linter#Get(l:original_filetypes))
" But have to build the list of available linters ourselves.
let l:all_linters = []
for l:original_filetype in split(l:original_filetypes, '\.')
let l:filetype = s:ResolveFiletype(l:original_filetype)
let l:filetype_linters = ale#linter#GetAll(l:filetype)
call extend(l:all_linters, l:filetype_linters)
endfor
let l:all_names = map(l:all_linters, 'v:val[''name'']')
let l:enabled_names = map(l:enabled_linters, 'v:val[''name'']')
echom ' Current Filetype: ' . l:original_filetypes
echom 'Available Linters: ' . string(l:all_names)
echom ' Enabled Linters: ' . string(l:enabled_names)
endfunction

49
autoload/ale/list.vim Normal file
View File

@@ -0,0 +1,49 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com>, modified by Yann fery <yann@fery.me>
" Description: Manages the loclist and quickfix lists
" Return 1 if there is a buffer with buftype == 'quickfix' in bufffer list
function! ale#list#IsQuickfixOpen() abort
for l:buf in range(1, bufnr('$'))
if getbufvar(l:buf, '&buftype') ==# 'quickfix'
return 1
endif
endfor
return 0
endfunction
function! ale#list#SetLists(loclist) abort
if g:ale_set_quickfix
call setqflist(a:loclist)
elseif g:ale_set_loclist
call setloclist(0, a:loclist)
endif
" If we don't auto-open lists, bail out here.
if !g:ale_open_list && !g:ale_keep_list_window_open
return
endif
" If we have errors in our list, open the list. Only if it isn't already open
if len(a:loclist) > 0 || g:ale_keep_list_window_open
let l:winnr = winnr()
if g:ale_set_quickfix
copen
elseif g:ale_set_loclist
lopen
endif
" If focus changed, restore it (jump to the last window).
if l:winnr !=# winnr()
wincmd p
endif
" Only close if the list is totally empty (relying on Vim's state, not our
" own). This keeps us from closing the window when other plugins have
" populated it.
elseif !g:ale_keep_list_window_open && g:ale_set_quickfix && len(getqflist()) == 0
cclose
elseif !g:ale_keep_list_window_open && len(getloclist(0)) == 0
lclose
endif
endfunction

View File

@@ -0,0 +1,100 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file implements functions for jumping around in a file
" based on errors and warnings in the loclist or quickfix list.
function! s:GetCurrentList() abort
if g:ale_set_loclist
return getloclist(winnr())
elseif g:ale_set_quickfix
let l:buffer = bufnr('%')
return filter(getqflist(), 'get(v:val, ''bufnr'', -1) == ' . l:buffer)
endif
return []
endfunction
function! s:GetSortedLoclist() abort
let l:loclist = []
for l:item in s:GetCurrentList()
if l:item.lnum < 1
" Remove items we can't even jump to.
continue
endif
call add(l:loclist, l:item)
endfor
" We must sort the list again, as the loclist could contain items set
" by other plugins.
call sort(l:loclist, 'ale#util#LocItemCompare')
return l:loclist
endfunction
" Search for the nearest line either before or after the current position
" in the loclist. The argument 'wrap' can be passed to enable wrapping
" around the end of the list.
"
" If there are no items or we have hit the end with wrapping off, an empty
" List will be returned, otherwise a pair of [line_number, column_number] will
" be returned.
function! ale#loclist_jumping#FindNearest(direction, wrap) abort
let l:loclist = s:GetSortedLoclist()
if empty(l:loclist)
" We couldn't find anything, so stop here.
return []
endif
let l:search_item = {'lnum': getcurpos()[1], 'col': getcurpos()[2]}
" When searching backwards, so we can find the next smallest match.
if a:direction ==# 'before'
call reverse(l:loclist)
endif
" Look for items before or after the current position.
for l:item in l:loclist
" Compare the cursor with a item where the column number is bounded,
" such that it's possible for the cursor to actually be on the given
" column number, without modifying the cursor number we return. This
" will allow us to move through matches, but still let us move the
" cursor to a line without changing the column, in some cases.
let l:cmp_value = ale#util#LocItemCompare(
\ {
\ 'lnum': l:item.lnum,
\ 'col': min([max([l:item.col, 1]), len(getline(l:item.lnum))]),
\ },
\ l:search_item
\)
if a:direction ==# 'before' && l:cmp_value < 0
return [l:item.lnum, l:item.col]
endif
if a:direction ==# 'after' && l:cmp_value > 0
return [l:item.lnum, l:item.col]
endif
endfor
" If we found nothing, and the wrap option is set to 1, then we should
" wrap around the list of warnings/errors
if a:wrap
let l:item = get(l:loclist, 0)
return [l:item.lnum, l:item.col]
endif
return []
endfunction
" As before, find the nearest match, but position the cursor at it.
function! ale#loclist_jumping#Jump(direction, wrap) abort
let l:nearest = ale#loclist_jumping#FindNearest(a:direction, a:wrap)
if !empty(l:nearest)
call cursor(l:nearest)
endif
endfunction

29
autoload/ale/semver.vim Normal file
View File

@@ -0,0 +1,29 @@
" Given some text, parse a semantic versioning string from the text
" into a triple of integeers [major, minor, patch].
"
" If no match can be performed, then an empty List will be returned instead.
function! ale#semver#Parse(text) abort
let l:match = matchlist(a:text, '^ *\(\d\+\)\.\(\d\+\)\.\(\d\+\)')
if empty(l:match)
return []
endif
return [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
endfunction
" Given two triples of integers [major, minor, patch], compare the triples
" and return 1 if the lhs is greater than or equal to the rhs.
function! ale#semver#GreaterOrEqual(lhs, rhs) abort
if a:lhs[0] > a:rhs[0]
return 1
elseif a:lhs[0] == a:rhs[0]
if a:lhs[1] > a:rhs[1]
return 1
elseif a:lhs[1] == a:rhs[1]
return a:lhs[2] >= a:rhs[2]
endif
endif
return 0
endfunction

View File

@@ -27,19 +27,27 @@ execute 'sign define ALEWarningSign text=' . g:ale_sign_warning
\ . ' texthl=ALEWarningSign'
sign define ALEDummySign
function! ale#sign#FindCurrentSigns(buffer) abort
" Read sign data for a buffer to a list of lines.
function! ale#sign#ReadSigns(buffer) abort
redir => l:output
silent exec 'sign place buffer=' . a:buffer
redir end
return split(l:output, "\n")
endfunction
" Given a list of lines for sign output, return a list of sign IDs
function! ale#sign#ParseSigns(line_list) abort
" Matches output like :
" line=4 id=1 name=ALEErrorSign
" строка=1 id=1000001 имя=ALEErrorSign
let l:pattern = 'id=\(\d\+\).*=ALE\(Warning\|Error\)Sign'
redir => l:output
silent exec 'sign place buffer=' . a:buffer
redir END
" 行=1 識別子=1000001 名前=ALEWarningSign
" línea=12 id=1000001 nombre=ALEWarningSign
let l:pattern = '^.*=\d*\s\+.*=\(\d\+\)\s\+.*=ALE\(Warning\|Error\|Dummy\)Sign'
let l:id_list = []
for l:line in split(l:output, "\n")
for l:line in a:line_list
let l:match = matchlist(l:line, l:pattern)
if len(l:match) > 0
@@ -50,6 +58,12 @@ function! ale#sign#FindCurrentSigns(buffer) abort
return l:id_list
endfunction
function! ale#sign#FindCurrentSigns(buffer) abort
let l:line_list = ale#sign#ReadSigns(a:buffer)
return ale#sign#ParseSigns(l:line_list)
endfunction
" Given a loclist, combine the loclist into a list of signs such that only
" one sign appears per line. Error lines will take precedence.
" The loclist will have been previously sorted.
@@ -88,26 +102,36 @@ endfunction
function! ale#sign#SetSigns(buffer, loclist) abort
let l:signlist = ale#sign#CombineSigns(a:loclist)
if len(l:signlist) > 0 || g:ale_sign_column_always
if !get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
" Insert a dummy sign if one is missing.
execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign buffer='
\ . a:buffer
let g:ale_buffer_sign_dummy_map[a:buffer] = 1
endif
endif
" Find the current signs with the markers we use.
" Find the current markers
let l:current_id_list = ale#sign#FindCurrentSigns(a:buffer)
let l:dummy_sign_set = 0
" Remove those markers.
" Check if we set the dummy sign already.
for l:current_id in l:current_id_list
exec 'sign unplace ' . l:current_id . ' buffer=' . a:buffer
if l:current_id == g:ale_sign_offset
let l:dummy_sign_set = 1
endif
endfor
" Now set all of the signs.
" If we haven't already set a dummy sign, and we have some previous signs
" or always want a dummy sign, then set one, to keep the sign column open.
if !l:dummy_sign_set && (len(l:signlist) > 0 || g:ale_sign_column_always)
execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign buffer='
\ . a:buffer
let l:dummy_sign_set = 1
endif
" Now remove the previous signs. The dummy will hold the column open
" while we add the new signs, if we had signs before.
for l:current_id in l:current_id_list
if l:current_id != g:ale_sign_offset
exec 'sign unplace ' . l:current_id . ' buffer=' . a:buffer
endif
endfor
" Add the new signs,
for l:index in range(0, len(l:signlist) - 1)
let l:sign = l:signlist[l:index]
let l:type = l:sign['type'] ==# 'W' ? 'ALEWarningSign' : 'ALEErrorSign'
@@ -120,11 +144,10 @@ function! ale#sign#SetSigns(buffer, loclist) abort
exec l:sign_line
endfor
if !g:ale_sign_column_always && len(l:signlist) > 0
if get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
let g:ale_buffer_sign_dummy_map[a:buffer] = 0
endif
" Remove the dummy sign now we've updated the signs, unless we want
" to keep it, which will keep the sign column open even when there are
" no warnings or errors.
if l:dummy_sign_set && !g:ale_sign_column_always
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
endif
endfunction

View File

@@ -14,34 +14,48 @@ function! ale#statusline#Update(buffer, loclist) abort
endif
endfor
let g:ale_buffer_count_map[a:buffer] = [l:errors, l:warnings]
let g:ale_buffer_info[a:buffer].count = [l:errors, l:warnings]
endfunction
" Set the error and warning counts, calling for an update only if needed.
" If counts cannot be set, return 0.
function! s:SetupCount(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" Linters have not been run for the buffer yet, so stop here.
return 0
endif
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_info[a:buffer], 'count')
call ale#statusline#Update(a:buffer, g:ale_buffer_info[a:buffer].loclist)
endif
return 1
endfunction
" Returns a tuple of errors and warnings for use in third-party integrations.
function! ale#statusline#Count(buffer) abort
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_count_map, a:buffer)
call ale#statusline#Update(a:buffer, get(g:ale_buffer_loclist_map, a:buffer, []))
if !s:SetupCount(a:buffer)
return [0, 0]
endif
return g:ale_buffer_count_map[a:buffer]
return g:ale_buffer_info[a:buffer].count
endfunction
" Returns a formatted string that can be integrated in the statusline.
function! ale#statusline#Status() abort
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
let l:buffer = bufnr('%')
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_count_map, l:buffer)
call ale#statusline#Update(l:buffer, get(g:ale_buffer_loclist_map, l:buffer, []))
if !s:SetupCount(l:buffer)
return l:no_errors
endif
let [l:error_count, l:warning_count] = g:ale_buffer_info[l:buffer].count
" Build strings based on user formatting preferences.
let l:errors = g:ale_buffer_count_map[l:buffer][0] ?
\ printf(g:ale_statusline_format[0], g:ale_buffer_count_map[l:buffer][0]) : ''
let l:warnings = g:ale_buffer_count_map[l:buffer][1] ?
\ printf(g:ale_statusline_format[1], g:ale_buffer_count_map[l:buffer][1]) : ''
let l:no_errors = g:ale_statusline_format[2]
let l:errors = l:error_count ? printf(l:error_format, l:error_count) : ''
let l:warnings = l:warning_count ? printf(l:warning_format, l:warning_count) : ''
" Different formats based on the combination of errors and warnings.
if empty(l:errors) && empty(l:warnings)

View File

@@ -44,6 +44,35 @@ function! ale#util#FindNearestFile(buffer, filename) abort
return ''
endfunction
" Given a buffer and a directory name, find the nearest directory by searching upwards
" through the paths relative to the given buffer.
function! ale#util#FindNearestDirectory(buffer, directory_name) abort
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p')
let l:relative_path = finddir(a:directory_name, l:buffer_filename . ';')
if !empty(l:relative_path)
return fnamemodify(l:relative_path, ':p')
endif
return ''
endfunction
" Given a buffer, a string to search for, an a global fallback for when
" the search fails, look for a file in parent paths, and if that fails,
" use the global fallback path instead.
function! ale#util#ResolveLocalPath(buffer, search_string, global_fallback) abort
" Search for a locally installed file first.
let l:path = ale#util#FindNearestFile(a:buffer, a:search_string)
" If the serach fails, try the global executable instead.
if empty(l:path)
let l:path = a:global_fallback
endif
return l:path
endfunction
function! ale#util#GetFunction(string_or_ref) abort
if type(a:string_or_ref) == type('')
return function(a:string_or_ref)

83
custom-checks Executable file
View File

@@ -0,0 +1,83 @@
#!/bin/bash -eu
# This Bash script implements custom sanity checks for scripts beyond what
# Vint covers, which are easy to check with regex.
# A flag for automatically fixing some errors.
FIX_ERRORS=0
RETURN_CODE=0
function print_help() {
echo "Usage: ./custom-checks [--fix] [DIRECTORY]" 1>&2
echo 1>&2
echo " -h, --help Print this help text" 1>&2
echo " --fix Automatically fix some errors" 1>&2
exit 1
}
while [ $# -ne 0 ]; do
case $1 in
-h) ;& --help)
print_help
;;
--fix)
FIX_ERRORS=1
shift
;;
--)
shift
break
;;
-?*)
echo "Invalid argument: $1" 1>&2
exit 1
;;
*)
break
;;
esac
done
if [ $# -eq 0 ] || [ -z "$1" ]; then
print_help
fi
# Called to output an error.
# If called at least one, the return code for this script will be 1.
output_error() {
echo "$FILENAME:$LINE_NUMBER $1"
RETURN_CODE=1
}
# This function is called for each line in each file to check syntax.
check_line() {
line="$1"
if [[ "$line" =~ ^function ]]; then
if ! [[ "$line" =~ abort$ ]]; then
if ((FIX_ERRORS)); then
# Use sed to add the 'abort' flag
sed -i "${LINE_NUMBER}s/$/ abort/" "$FILENAME"
else
output_error 'Function without abort keyword (See :help except-compat)'
fi
fi
fi
if [[ "$line" =~ ' '+$ ]]; then
output_error 'Trailing whitespace'
fi
}
# Loop through all of the vim files and keep track of the file line numbers.
for FILENAME in $(find "$1" -name '*.vim'); do
LINE_NUMBER=0
while read; do
LINE_NUMBER=$(expr $LINE_NUMBER + 1)
check_line "$REPLY"
done < "$FILENAME"
done
exit $RETURN_CODE

View File

@@ -1,40 +0,0 @@
#!/bin/bash -eu
# Author: w0rp <devw0rp@gmail.com>
# Description: This script wraps DMD so we can get something which is capable of reading
# D code from stdin.
temp_file=`mktemp`
mv "$temp_file" "$temp_file".d
temp_file="$temp_file".d
trap "rm $temp_file" EXIT
while read; do
echo "$REPLY" >> "$temp_file"
done
# Read imports from DUB.
original_path="$(pwd)"
path="$original_path"
import_line_options=''
# We need to look for variable configuration files in parent directories.
while [ "$path" != '/' ]; do
if [ -f "$path/dub.sdl" ] || [ -f "$path/dub.json" ] || [ -f "$path/package.json" ]; then
cd "$path"
while read import_line; do
import_line_options="$import_line_options -I$import_line"
done <<< "$(dub describe --import-paths)"
cd "$original_path"
break
fi
path="$(dirname "$path")"
done
dmd $import_line_options "$@" "$temp_file"

File diff suppressed because it is too large Load Diff

View File

@@ -7,30 +7,34 @@
if exists('g:loaded_ale')
finish
endif
let g:loaded_ale = 1
" A flag for detecting if the required features are set.
if has('nvim')
let s:ale_has_required_features = has('timers')
let s:has_features = has('timers')
else
let s:ale_has_required_features = has('timers') && has('job') && has('channel')
" Check if Job and Channel functions are available, instead of the
" features. This works better on old MacVim versions.
let s:has_features = has('timers') && exists('*job_start') && exists('*ch_close_in')
endif
if !s:ale_has_required_features
if !s:has_features
echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
echoerr 'Please update your editor appropriately.'
finish
endif
" Globals
let g:ale_buffer_count_map = {}
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
" This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against.
let g:ale_buffer_info = {}
" User Configuration
" This option prevents ALE autocmd commands from being run for particular
" filetypes which can cause issues.
let g:ale_filetype_blacklist = ['nerdtree', 'unite']
" This Dictionary configures which linters are enabled for which languages.
let g:ale_linters = get(g:, 'ale_linters', {})
@@ -57,7 +61,7 @@ let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', 1)
if g:ale_lint_on_enter
augroup ALERunOnEnterGroup
autocmd!
autocmd BufEnter,BufRead * call ale#Queue(100)
autocmd BufEnter,BufRead * call ale#Queue(300)
augroup END
endif
@@ -70,8 +74,16 @@ if g:ale_lint_on_save
augroup END
endif
" This flag can be set to 0 to disable setting the loclist.
" These flags dictates if ale uses the quickfix or the loclist (loclist is the
" default, quickfix overrides loclist).
let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1)
let g:ale_set_quickfix = get(g:, 'ale_set_quickfix', 0)
" This flag dictates if ale open the configured loclist
let g:ale_open_list = get(g:, 'ale_open_list', 0)
" This flag dictates if ale keeps open loclist even if there is no error in loclist
let g:ale_keep_list_window_open = get(g:, 'ale_keep_list_window_open', 0)
" This flag can be set to 0 to disable setting signs.
" This is enabled by default only if the 'signs' feature exists.
@@ -120,6 +132,21 @@ let g:ale_statusline_format = get(g:, 'ale_statusline_format',
let g:ale_warn_about_trailing_whitespace =
\ get(g:, 'ale_warn_about_trailing_whitespace', 1)
" Define commands for moving through warnings and errors.
command! ALEPrevious :call ale#loclist_jumping#Jump('before', 0)
command! ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1)
command! ALENext :call ale#loclist_jumping#Jump('after', 0)
command! ALENextWrap :call ale#loclist_jumping#Jump('after', 1)
" Define command to get information about current filetype.
command! ALEInfo :call ale#linter#Info()
" <Plug> mappings for commands
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>
nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return>
nnoremap <silent> <Plug>(ale_next) :ALENext<Return>
nnoremap <silent> <Plug>(ale_next_wrap) :ALENextWrap<Return>
" Housekeeping
augroup ALECleanupGroup
@@ -130,10 +157,10 @@ augroup END
" Backwards Compatibility
function! ALELint(delay)
function! ALELint(delay) abort
call ale#Queue(a:delay)
endfunction
function! ALEGetStatusLine()
function! ALEGetStatusLine() abort
return ale#statusline#Status()
endfunction

View File

@@ -1,20 +1,21 @@
#!/usr/bin/env bash
# Author: w0rp <devw0rp@gmail.com>
# Authors: w0rp <devw0rp@gmail.com>, hauleth <lukasz@niemier.pl>
# Description: This script implements a wrapper for any program which does not accept
# stdin input on most Unix machines. The input to the script is read to a
# temporary file, and the first argument sets a particular file extension
# for the temporary file.
set -eu
# All of the following arguments are read as command to run.
file_extension="$1"
shift
temp_file=$(mktemp --tmpdir "ale-XXXXXXXXX$file_extension")
trap 'rm $temp_file' EXIT
temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'ale_linter')
temp_file="$temp_dir/file$file_extension"
trap 'rm -r "$temp_dir"' EXIT
while read -r; do
echo "$REPLY" >> "$temp_file"
done
cat > "$temp_file"
"$@" "$temp_file"

91
test/test_ale_info.vader Normal file
View File

@@ -0,0 +1,91 @@
Before:
let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout'}
let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout'}
call ale#linter#Reset()
let g:ale_linters = {}
let g:ale_linter_aliases = {}
After:
unlet! g:output
Given nolintersft (Empty buffer with no linters):
Execute (ALEInfo with no linters should return the right output):
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: nolintersft\n
\Available Linters: []\n
\ Enabled Linters: []", g:output
Given (Empty buffer with no filetype):
Execute (ALEInfo with no filetype should return the right output):
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: \n
\Available Linters: []\n
\ Enabled Linters: []", g:output
Given testft (Empty buffer):
Execute (ALEInfo with a single linter should return the right output):
call ale#linter#Define('testft', g:testlinter1)
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: testft\n
\Available Linters: ['testlinter1']\n
\ Enabled Linters: ['testlinter1']", g:output
Given testft (Empty buffer):
Execute (ALEInfo with two linters should return the right output):
call ale#linter#Define('testft', g:testlinter1)
call ale#linter#Define('testft', g:testlinter2)
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: testft\n
\Available Linters: ['testlinter1', 'testlinter2']\n
\ Enabled Linters: ['testlinter1', 'testlinter2']", g:output
Given testft (Empty buffer):
Execute (ALEInfo should calculate enabled linters correctly):
call ale#linter#Define('testft', g:testlinter1)
call ale#linter#Define('testft', g:testlinter2)
let g:ale_linters = { 'testft': ['testlinter2'] }
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: testft\n
\Available Linters: ['testlinter1', 'testlinter2']\n
\ Enabled Linters: ['testlinter2']", g:output
Given testft (Empty buffer):
Execute (ALEInfo should only return linters for current filetype):
call ale#linter#Define('testft', g:testlinter1)
call ale#linter#Define('testft2', g:testlinter2)
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: testft\n
\Available Linters: ['testlinter1']\n
\ Enabled Linters: ['testlinter1']", g:output
Given testft.testft2 (Empty buffer with two filetypes):
Execute (ALEInfo with compound filetypes should return linters for both of them):
call ale#linter#Define('testft', g:testlinter1)
call ale#linter#Define('testft2', g:testlinter2)
redir => g:output
silent ALEInfo
redir END
AssertEqual "\n
\ Current Filetype: testft.testft2\n
\Available Linters: ['testlinter1', 'testlinter2']\n
\ Enabled Linters: ['testlinter1', 'testlinter2']", g:output

View File

@@ -1,19 +0,0 @@
Before:
let g:ale_linters = {}
let g:ale_linter_aliases = {}
After:
let g:ale_linters = {}
let g:ale_linter_aliases = {}
Execute (Defaults should be correct):
AssertEqual [{'output_stream': 'stdout', 'name': 'eslint', 'executable': 'eslint', 'command': 'eslint -f unix --stdin --stdin-filename %s', 'callback': 'ale_linters#javascript#eslint#Handle'}, {'output_stream': 'stdout', 'name': 'jscs', 'executable': 'jscs', 'command': 'jscs -r unix -n -', 'callback': 'ale#handlers#HandleUnixFormatAsError'}, {'output_stream': 'stdout', 'name': 'jshint', 'executable': 'jshint', 'command_callback': 'ale_linters#javascript#jshint#GetCommand', 'callback': 'ale#handlers#HandleUnixFormatAsError'}], ale#linter#Get('javascript')
Execute (You should be able to select only a few linters):
let g:ale_linters = {'javascript': ['eslint']}
AssertEqual [{'output_stream': 'stdout', 'name': 'eslint', 'executable': 'eslint', 'command': 'eslint -f unix --stdin --stdin-filename %s', 'callback': 'ale_linters#javascript#eslint#Handle'}], ale#linter#Get('javascript')
Execute (You should be able to alias filetypes and select different linters):
let g:ale_linter_aliases = {'foobar': 'javascript'}
let g:ale_linters = {'javascript': ['eslint'], 'foobar': ['jshint']}
AssertEqual [{'output_stream': 'stdout', 'name': 'jshint', 'executable': 'jshint', 'command_callback': 'ale_linters#javascript#jshint#GetCommand', 'callback': 'ale#handlers#HandleUnixFormatAsError'}], ale#linter#Get('foobar')

View File

@@ -1,65 +0,0 @@
Before:
let g:ale_buffer_loclist_map = {}
After:
let g:ale_buffer_loclist_map = {}
Execute (Count should be 0 when data is empty):
AssertEqual [0, 0], ale#statusline#Count(bufnr('%'))
Before:
let g:ale_buffer_count_map = {'44': [1, 2]}
After:
let g:ale_buffer_loclist_map = {}
Execute (Count should read data from the cache):
AssertEqual [1, 2], ale#statusline#Count(44)
Execute (Update the cache with new data):
call ale#statusline#Update(44, [])
Then (The cache should reflect the new data):
AssertEqual [0, 0], ale#statusline#Count(44)
Before:
let g:ale_buffer_loclist_map = {'1': [{'lnum': 1, 'bufnr': 1, 'vcol': 0, 'linter_name': 'testlinter', 'nr': -1, 'type': 'E', 'col': 1, 'text': 'Test Error'}]}
After:
let g:ale_buffer_loclist_map = {}
Execute (Count should be match the loclist):
AssertEqual [1, 0], ale#statusline#Count(1)
Execute (Output should be empty for non-existant buffer):
AssertEqual [0, 0], ale#statusline#Count(9001)
Before:
let g:ale_statusline_format = ['%sE', '%sW', 'OKIE']
After:
let g:ale_buffer_loclist_map = {}
Execute (Given some errors):
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}])
Then (Statusline is formatted to the users preference):
AssertEqual '2E', ale#statusline#Status()
Execute (Given some warnings):
call ale#statusline#Update(bufnr('%'), [{'type': 'W'}, {'type': 'W'}, {'type': 'W'}])
Then (Statusline is formatted to the users preference):
AssertEqual '3W', ale#statusline#Status()
Execute (Given some warnings, and errors.):
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'W'}, {'type': 'W'}])
Then (Statusline is formatted to the users preference):
AssertEqual '1E 2W', ale#statusline#Status()
Execute (Given a lack of data):
call ale#statusline#Update(bufnr('%'), [])
Then (Statusline is formatted to the users preference):
AssertEqual 'OKIE', ale#statusline#Status()

View File

@@ -7,11 +7,14 @@ Before:
After:
augroup! VaderTest
let g:ale_buffer_info = {}
Given vim (Vimscript):
Given vim (Some vimscript):
set nocompatible
Execute (Run ALE):
Execute (Lint it):
call ale#Lint()
call ale#engine#WaitForJobs(2000)
Then (Autocommand should have run):
Then (Autocommands should have run):
AssertEqual g:success, 1

View File

@@ -1,32 +1,15 @@
Before:
let g:buffer = bufnr('%')
let g:ale_buffer_count_map = {
\ g:buffer: [1, 1],
\ 10347: [1, 1],
\}
let g:ale_buffer_loclist_map = {
\ g:buffer : [],
\ 10347: [],
\}
let g:ale_buffer_should_reset_map = {
\ g:buffer : 1,
\ 10347: 1,
\}
let g:ale_buffer_sign_dummy_map = {
\ g:buffer : 1,
\ 10347: 1,
let g:ale_buffer_info = {
\ g:buffer : {},
\ 10347: {},
\}
After:
unlet! g:buffer
let g:ale_buffer_count_map = {}
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
let g:ale_buffer_info = {}
Execute('ALE globals should be cleared when the buffer is closed.'):
:q!
AssertEqual {10347: [1, 1]}, g:ale_buffer_count_map
AssertEqual {10347: []}, g:ale_buffer_loclist_map
AssertEqual {10347: 1}, g:ale_buffer_should_reset_map
AssertEqual {10347: 1}, g:ale_buffer_sign_dummy_map
AssertEqual {10347: {}}, g:ale_buffer_info

View File

@@ -0,0 +1,61 @@
Before:
let g:linter_output = []
let g:first_echo_called = 0
let g:second_echo_called = 0
let g:final_callback_called = 0
function! CollectResults(buffer, output)
let g:final_callback_called = 1
let g:linter_output = a:output
return []
endfunction
function! RunFirstEcho(buffer)
let g:first_echo_called = 1
return 'echo foo'
endfunction
function! RunSecondEcho(buffer, output)
let g:second_echo_called = 1
return 'echo bar'
endfunction
call ale#linter#Define('foobar', {
\ 'name': 'testlinter',
\ 'callback': 'CollectResults',
\ 'executable': 'echo',
\ 'command_chain': [
\ {
\ 'callback': 'RunFirstEcho',
\ 'output_stream': 'stdout',
\ },
\ {
\ 'callback': 'RunSecondEcho',
\ 'output_stream': 'stdout',
\ },
\ ],
\})
After:
unlet! g:first_echo_called
unlet! g:second_echo_called
unlet! g:final_callback_called
unlet! g:linter_output
let g:ale_buffer_info = {}
call ale#linter#Reset()
delfunction CollectResults
delfunction RunFirstEcho
delfunction RunSecondEcho
Given foobar (Some imaginary filetype):
anything
Execute(Check the results of running the chain):
AssertEqual 'foobar', &filetype
call ale#Lint()
call ale#engine#WaitForJobs(2000)
Assert g:first_echo_called, 'The first chain item was not called'
Assert g:second_echo_called, 'The second chain item was not called'
Assert g:final_callback_called, 'The final callback was not called'
AssertEqual ['bar'], g:linter_output

View File

@@ -26,6 +26,34 @@ Then (The loclist should be correct):
\ },
\], g:loclist
Execute (Run HandlePEP8Format):
let g:loclist = ale#handlers#HandlePEP8Format(42, [
\ "stdin:6:6: E111 indentation is not a multiple of four",
\ "test.yml:35: [EANSIBLE0002] Trailing whitespace",
\])
Then (The loclist should be correct):
AssertEqual [
\ {
\ 'bufnr': 42,
\ 'vcol': 0,
\ 'nr': -1,
\ 'lnum': 6,
\ 'col': 6,
\ 'type': 'E',
\ 'text': 'E111: indentation is not a multiple of four',
\ },
\ {
\ 'bufnr': 42,
\ 'vcol': 0,
\ 'nr': -1,
\ 'lnum': 35,
\ 'col': 0,
\ 'type': 'E',
\ 'text': "EANSIBLE0002: Trailing whitespace",
\ },
\], g:loclist
Execute (Run HandleGCCFormat):
let g:loclist = ale#handlers#HandleGCCFormat(42, [
\ '<stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]',
@@ -58,6 +86,7 @@ Execute (Run HandleUnixFormatAsError):
let g:loclist = ale#handlers#HandleUnixFormatAsError(42, [
\ 'file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args',
\ 'file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)',
\ 'test.pug:1:1 ".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.',
\])
Then (The loclist should be correct):
@@ -80,6 +109,15 @@ Then (The loclist should be correct):
\ 'type': 'E',
\ 'text': 'if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)',
\ },
\ {
\ 'bufnr': 42,
\ 'vcol': 0,
\ 'nr': -1,
\ 'lnum': 1,
\ 'col': 1,
\ 'type': 'E',
\ 'text': '".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.',
\ },
\], g:loclist
Execute (Run HandleUnixFormatAsWarning):
@@ -138,5 +176,33 @@ Then (The loclist should be correct):
\ },
\], g:loclist
Execute (Run HandleCppCheckFormat):
let g:loclist = ale#handlers#HandleCppCheckFormat(42, [
\ '[/tmp/test.c:5]: (style) Variable a is assigned a value that is never used.',
\ '[/tmp/test.c:12]: (error) Array a[10] accessed at index 10, which is out of bounds.'
\])
Then (The loclist should be correct):
AssertEqual [
\ {
\ 'bufnr': 42,
\ 'vcol': 0,
\ 'nr': -1,
\ 'lnum': 5,
\ 'col': 0,
\ 'type': 'W',
\ 'text': 'Variable a is assigned a value that is never used. (style)',
\ },
\ {
\ 'bufnr': 42,
\ 'vcol': 0,
\ 'nr': -1,
\ 'lnum': 12,
\ 'col': 0,
\ 'type': 'E',
\ 'text': 'Array a[10] accessed at index 10, which is out of bounds. (error)',
\ },
\], g:loclist
After:
unlet g:loclist

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