Compare commits

..

172 Commits

Author SHA1 Message Date
w0rp
5582711680 Fix #413 Stop tests failing randomly due to issues with reading buffers too quickly 2017-03-26 02:13:21 +01:00
w0rp
822b19ac83 Merge pull request #411 from lucaskolstad/lint_on_enter_bugfix
#272 Check if quickfix window is open before reopening
2017-03-24 21:04:49 +00:00
Lucas Kolstad
b3f6f56745 Fix #272 by checking if quickfix is open before reopening to avoid triggering a BufEnter event that causes quickly repeating linting runs when g:ale_lint_on_enter = 1.
Add test assertions that quickfix window closes when lists become empty again.
2017-03-24 10:39:37 -07:00
w0rp
a5ac3e4e4b Merge pull request #409 from lucaskolstad/document_hdevtools_support
Document support for hdevtools
2017-03-23 23:56:45 +00:00
Lucas Kolstad
3ca4c7de96 Document support for hdevtools 2017-03-23 15:57:37 -07:00
baabelfish
9f3cdf8270 Fix problems with nim check (#404)
* Fix problems with nim check

- Multi file errors are not shown in the same buffer
- Fixes parsing of error type that contain ':'

* Remove redundant fnameescape
2017-03-22 09:11:32 +00:00
w0rp
59b5644fb3 Clean up the documentation some more, and make the description of the ALELint autocmd clearer 2017-03-22 08:57:29 +00:00
w0rp
18bae7da2e #333 Finish implementing the lint_file option 2017-03-21 14:52:02 +00:00
w0rp
c59204b94f Remove a test for experimental functionality which was removed 2017-03-21 13:58:08 +00:00
w0rp
3e13e10e03 #333 Change arguments for ale#Queue so they are more obvious, and check files in more places 2017-03-21 13:38:27 +00:00
w0rp
2d1d6fb850 Add some utility functions for changing directories for commands 2017-03-21 13:09:02 +00:00
w0rp
6550cdfbd0 Make it clearer that global variables should be set in vimrc, in the Rust documentation 2017-03-21 12:39:12 +00:00
Dylan Araps
551d53aa67 Fix shellcheck typo in docs. shellckeck -> shellcheck (#402) 2017-03-21 12:35:44 +00:00
Ruben Paz
5122dc498d tslint parameterized executable and config path (#400)
* Allow modifying the location of the tsling executable

* Allow definition of config file path

* fnameescape configuration file
2017-03-21 12:30:32 +00:00
w0rp
51729346bf Merge pull request #399 from baabelfish/master
Add support for nim check
2017-03-19 20:34:11 +00:00
baabelfish
297bc8553c Add support for nim check 2017-03-18 19:45:37 +02:00
w0rp
e7d32fe376 #333 Pass in a flag indicating that linters should be run against files, and clear more jobs 2017-03-14 23:51:57 +00:00
w0rp
790c614b7a #333 Update line numbers for loclist items when current sign_id values are set 2017-03-14 23:04:25 +00:00
w0rp
d19a35485f #333 Keep any loclist items which have match_id values set on them 2017-03-14 20:26:44 +00:00
w0rp
5836d9a9a7 Stop using globstar for tests, so they can be run on Mac OSX 2017-03-14 15:08:26 +00:00
w0rp
6f0fc965ab #394 Attempt to fix running linters when bufwinid() doesn't exist 2017-03-13 23:45:32 +00:00
Markus Doits
fae26369d4 add slim-lint (#388)
* add slim-lint

* add slim readme entry

* add slim entry to doc

* add slimlint vader test
2017-03-13 23:21:59 +00:00
w0rp
3f3d8b0014 Merge pull request #393 from naoina/fix-coffeelint-pattern
Fix pattern of output for coffeelint
2017-03-13 23:18:06 +00:00
Naoya Inada
e969d97843 Fix pattern of output for coffeelint 2017-03-13 20:09:49 +09:00
w0rp
711ab99362 #333 Remember the IDs for highlights 2017-03-12 22:46:33 +00:00
w0rp
382e569f66 Revert "Don't save the sign ID on loclist items. This approach won't work."
This reverts commit f25a543260.
2017-03-12 22:34:32 +00:00
w0rp
f25a543260 Don't save the sign ID on loclist items. This approach won't work. 2017-03-12 21:48:40 +00:00
w0rp
a4ae5ca997 Merge pull request #389 from jparise/erlc-output-tmpdir
Write erlc output files to the temporary directory
2017-03-12 16:50:17 +00:00
Jon Parise
f3eab445ee Use tempname() to create the temporary output file
Also, "manage" this filename so ALE can clean it up.
2017-03-11 19:33:32 -08:00
w0rp
4bf6784d7d #333 Save sign IDs back on loclist items, and make it possible to get line numbers again 2017-03-11 20:33:29 +00:00
w0rp
ca78e4c150 Support older versions of Vint 2017-03-11 19:45:33 +00:00
w0rp
892fff03cc Cover error priority in the sign tests 2017-03-11 17:39:51 +00:00
w0rp
d58a18b8ed #277 #318 Support all same-directory includes for gcc and clang 2017-03-11 16:48:49 +00:00
Paul Johnson
c2ceb9e085 FIX #344 - Add options to Perl linter
Conflicts:
	doc/ale.txt
2017-03-11 14:53:30 +00:00
Jon Parise
7d6b313065 Write erlc output files to the temporary directory
In particular, if we're working with a leex (.xrl) or yecc (.yrl) source
file, erlc would otherwise generate the corresponding .erl file in the
current directory (often the project root), which is generally not what
we want.

Unconditionally writing erlc output to a temporary directory also
matches Flycheck's behavior.
2017-03-10 08:24:21 -08:00
w0rp
bd07d04670 Cover parsing of Italian signs with tests 2017-03-10 13:21:08 +00:00
w0rp
3b981e22cc Fix sign tests. 2017-03-09 22:45:22 +00:00
w0rp
587360e760 Group sign tests 2017-03-09 22:18:45 +00:00
w0rp
3cababc83b Fix #386 report problems with eslint configuration files 2017-03-09 21:05:00 +00:00
w0rp
fc072a0772 Get milliseconds timestamps without system() calls for tests 2017-03-09 20:22:02 +00:00
w0rp
ad49846a48 #376 Use the window ID for a given buffer for setting the loclist 2017-03-09 00:43:53 +00:00
w0rp
1c3f0b1e19 #333 Add the List needed for the lint_file option, and option itself. Neither do anything meaningful yet 2017-03-08 00:23:14 +00:00
w0rp
21caf54543 Make the navigation commands only work with ALE's pre-sorted list 2017-03-07 23:31:25 +00:00
w0rp
b487c62130 Speed up and simplify the custom checks a lot 2017-03-07 00:16:35 +00:00
w0rp
b3ab89ac15 Make sure to reset linters after running the nix handler test 2017-03-06 23:34:19 +00:00
w0rp
663d8f832f Group handler test cases in a directory 2017-03-06 23:32:48 +00:00
w0rp
75a2dc5ff5 Complain loudly when other conflicting plugins are installed 2017-03-06 23:15:34 +00:00
w0rp
70fb1606ad Merge pull request #383 from alibabzo/add-nix-linter
Add support for nix linting
2017-03-06 18:33:00 +00:00
Alistair Bill
f659d97504 Add nix handler test cases 2017-03-05 20:36:29 +00:00
Alistair Bill
be57b545b7 Add support for nix linting 2017-03-05 20:36:29 +00:00
w0rp
76df2d393b Fix detailed messages with newline characters 2017-03-04 23:55:12 +00:00
w0rp
c1947d13cf #384 Try and stop stupid errors coming from the gobuild functions 2017-03-04 23:34:57 +00:00
w0rp
fb8df75ac3 Remove a now redundant line 2017-03-04 01:22:44 +00:00
Patrick Lewis
9e9e15bc87 Add hamllint linter for Haml (#377)
* Add hamllint linter for Haml

* Simplify hamllint
2017-03-03 20:27:07 +00:00
w0rp
2750c605c1 Fix cursor issues, and clean up the cursor tests 2017-03-03 20:14:03 +00:00
w0rp
da8a0f25cc Fix the tests again 2017-03-03 19:37:24 +00:00
w0rp
1f211dbe3e Merge pull request #374 from jwoudenberg/master
WIP: Add support for error details
2017-03-03 19:36:52 +00:00
Jasper Woudenberg
7030758da6 Fix documentation error. 2017-03-02 23:20:00 -08:00
Jasper Woudenberg
edc5dee226 Merge remote-tracking branch 'upstream/master' 2017-03-02 19:04:28 -08:00
Jasper Woudenberg
ae88263f0f Add documentation for ALEDetail 2017-03-02 18:55:22 -08:00
Jasper Woudenberg
f5ddc51d85 Address some feedback 2017-03-02 18:40:07 -08:00
w0rp
969274ccc2 Try and fix issues on Travis 2017-03-03 01:01:24 +00:00
w0rp
0e50a7d278 Fix #373 - echo the cursor message after lint cycles or when leaving Insert mode 2017-03-02 23:36:31 +00:00
w0rp
fab9e8f5ea Merge pull request #375 from manuelvio/patch-1
Update sign regex for LANG = it_IT.UTF-8
2017-03-02 22:04:55 +00:00
Manuel Unno Vio
79f18e7d87 Update sign regex for LANG = it_IT.UTF-8
I've noticed that signs weren't unplaced and, learning that this was an issue depending on locale and :sign place, I've fixed the regular expression used to match those messages in my locale (it_IT.UTF-8).
2017-03-02 12:17:43 +01:00
Jasper Woudenberg
70711022db Add support for error details
Some review needed.
2017-03-01 23:27:48 -08:00
Daniel M. Capella
18508f7453 proselint: Add more supported filetypes (#367)
* proselint: Add more suported filetypes

* proselint: Minor consistency fixes

* Vim help: Disable linters by default
2017-03-02 00:06:09 +00:00
Adriaan Zonnenberg
6befe9e37c Fix PHP column matching for unexpected single quotes (#370)
* PHP: Fix column matching for unexpected single quotes

Unexpected single quotes resulted in an empty match, because PHP
surrounds the errors with quotes, and we check for the next quote to be
the ending delimiter.

For example: an unexpected string 'foo' would be presented as
`unexpected ''foo''`, and then the match would be `''`. The inner part
of that match is an empty string.

This adds a check for the keyword "expecting". Any quote after
"expecting" won't be matched, so we can use greedy matching instead of
non-greedy.

* PHP: Use "very magic"

The pattern started to get unreadable

Also replaced non-greedy matching (`\{-}`) by greedy matching, because
we don't need to match non-greedily anymore and it reads a little nicer.

* PHP: Add tests for column matches

And with that, also a test for unexpected single quotes.
2017-03-01 23:26:03 +00:00
w0rp
f578c4a792 Merge pull request #369 from equal-l2/fix-cpp-clang-standard-flag
Use latest C++ standard
2017-03-01 15:19:52 +00:00
equal-l2
4fa52fd98a Use latest C++ standard 2017-03-01 02:42:35 +09:00
w0rp
ceeff6c723 Fix #288 - Add a command for running ALE 2017-02-28 09:10:58 +00:00
w0rp
31d328b272 Fix a mistake in the documentation 2017-02-27 22:22:39 +00:00
w0rp
7a92c3a046 Merge pull request #366 from kbenzie/cmakelint
Add cmakelint support for cmake filetype
2017-02-27 22:21:42 +00:00
w0rp
b2fe1b2567 Copy all loclist items returned from handlers, and set up defaults for convenience 2017-02-26 14:51:22 +00:00
w0rp
f1e80b800c Merge pull request #364 from jsivak/feature/pylint_symbol
Add the pylint symbol name for the msg_id of the error/warning.
2017-02-25 19:19:45 +00:00
John Sivak
9c93e79a66 Add display of the pylint symbol name for the msg_id. 2017-02-25 13:23:36 -05:00
Kenneth Benzie (Benie)
b5e603bbc5 Add cmakelint support for cmake filetype 2017-02-25 17:27:03 +00:00
w0rp
f48f306ab9 Create a Contributing section in the README 2017-02-23 22:51:08 +00:00
Jon Parise
c2c6c9f491 Fix Credo's line-matching pattern (#360)
* Fix Credo's line-matching pattern

In d3e7d3d5, the line matching pattern was changed to handle filenames
other than `stdin`. Unfortunately, this broke the pattern's ability to
reliably extract both line and column numbers because the latter is an
optional match and the filename portion was very greedy. This resulted
in line numbers being discarded (treated as part of the filename) and
column numbers being interpreted as line numbers.

This change simplifies the pattern to only anchor on the line's suffix,
ignoring the filename portion entirely.

Alternatively, we could use vim's `\f` ("file name characters") class,
but that could still run into problems when `:`'s naturally appear in
the filename.

* Add a Vader test case for the Credo handler
2017-02-22 23:33:05 +00:00
Chris Paul
fef3276f34 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:32:37 +00:00
w0rp
6a02c5812c Fix #314 - quickfix should take precedence over loclist for jumping 2017-02-21 12:51:49 +00:00
w0rp
c310080359 #314 filter both lists, and add tests to cover the list retrieval 2017-02-21 12:46:07 +00:00
w0rp
1a9c8b8d06 Merge pull request #353 from pauloalem/master
Add sml support via smlnj
2017-02-21 12:10:48 +00:00
w0rp
884109c6f4 Add an extra custom check for using endif instead of end, etc. 2017-02-21 11:50:59 +00:00
w0rp
3c4af280f0 Remove a flaky PHP handler 2017-02-21 11:35:37 +00:00
w0rp
3786322cf0 Merge remote-tracking branch 'adriaanzon/php-columns' 2017-02-21 11:34:39 +00:00
w0rp
8eca101fd1 Merge pull request #348 from rob-b/add-hdevtools-linter
Add hdevtools linter for haskell
2017-02-21 11:09:15 +00:00
paulo alem
677e55df0f Add sml support via smlnj 2017-02-18 00:05:33 -02:00
Adriaan Zonnenberg
cca0222cf1 PHP: Make parser work with more error messages 2017-02-18 00:51:33 +01:00
Adriaan Zonnenberg
a18e172a96 PHP: Fix test for column highlighting 2017-02-18 00:04:59 +01:00
Rob Berry
06fe8a043f Add hdevtools linter for haskell
This adds support for the hdevtools haskell linter
https://github.com/hdevtools/hdevtools

The output for hdevtools is near identical to the ghc output so this
also extracts the ghc handler into the handle file and adds tests

* Add testing for previous major release of ghc
2017-02-17 17:18:38 +00:00
w0rp
b21ca4ed4e Use a more reliable method for getting an ID for a job 2017-02-17 10:19:44 +00:00
w0rp
bdbf36991d Prevent some stupid exceptions 2017-02-17 09:56:36 +00:00
w0rp
5041246c0e Modify the issue template to note how to capture the output of commands 2017-02-16 23:24:23 +00:00
w0rp
eac0a41ae1 #254 Add an option for logging the output of commands 2017-02-16 23:18:57 +00:00
w0rp
843370b96f #254 Capture command exit codes in the history 2017-02-16 22:19:53 +00:00
w0rp
ca17b5aebd Add an option for completely disabling command history, and add documentation 2017-02-16 21:33:44 +00:00
w0rp
3a2286a1b8 Refactor history management functions into their own file 2017-02-16 21:18:03 +00:00
w0rp
434ff01f59 Add a missing question mark 2017-02-16 21:00:39 +00:00
w0rp
8c3c84c45e Add an FAQ section to address concerns about battery life 2017-02-16 20:59:37 +00:00
w0rp
406d784f7a Merge pull request #350 from qantik/clang-fix
Fix clang++ flag typo
2017-02-16 20:38:51 +00:00
Andrea Caforio
a7272466f7 Fix clang++ flag typo. 2017-02-16 18:12:41 +01:00
Rob Berry
c4afd72792 Add hdevtools linter for haskell
This adds support for the hdevtools haskell linter
https://github.com/hdevtools/hdevtools

The output for hdevtools is near identical to the ghc output so this
also extracts the ghc handler into the handle file and adds tests
2017-02-16 10:06:48 +00:00
w0rp
8c758e339c Fix a typo 2017-02-15 23:01:15 +00:00
w0rp
9e7034c6e2 Fix #319 - Enable only cargo for Rust by default 2017-02-15 22:59:33 +00:00
Adriaan Zonnenberg
b2241e991b Support columns on php handler
Also added some tests for different error messages
2017-02-15 23:59:18 +01:00
w0rp
732e8a813f Merge pull request #346 from AlexMasterov/fix/yaml-yamllint-syntax
Fix 'yamllint' syntax
2017-02-15 22:24:58 +00:00
w0rp
ba1eb90212 #338 Don't do anything from tags files. 2017-02-15 22:03:18 +00:00
Alex Masterov
903a6dc885 Fix 'yamllint' syntax 2017-02-16 00:58:48 +03:00
w0rp
c49819e892 Merge pull request #345 from AlexMasterov/feature/yaml-yamllint-options
Add yamllint option to pass in more options
2017-02-15 21:45:19 +00:00
w0rp
cb60a2c06e Cover ALEToggle with Vader tests 2017-02-15 21:36:16 +00:00
w0rp
2e7050dbe2 Create a make target and variable for running specific tests 2017-02-15 20:40:50 +00:00
w0rp
721a850e21 Merge pull request #343 from vimeitor/master
Fix spelling
2017-02-15 19:48:41 +00:00
Alex Masterov
7ef1d485fe Add yamllint option to pass in more options 2017-02-15 11:36:16 +03:00
w0rp
14679f0bd4 Add an issue template 2017-02-14 23:56:14 +00:00
w0rp
0131526261 #254 Add a command for copying ALEInfo to your clipboard quickly 2017-02-14 23:45:22 +00:00
w0rp
ed370667c8 #254 Add command history to ALEInfo 2017-02-14 23:44:37 +00:00
w0rp
c460602cbb #338 Try and stop ALE from throwing ALEs when run from a sandbox 2017-02-14 21:02:49 +00:00
Adrià Farrés
4afa415bd9 Fix spelling 2017-02-14 20:26:19 +01:00
w0rp
78135103fb Merge pull request #342 from Exteris/bugfix/gfortran-6.3.1
Update line marker pattern for new gfortran
2017-02-14 19:06:25 +00:00
Daan van Vugt
68b6be57f1 Update line marker pattern for new gfortran
Add tests for GCC 4.1.2, 4.9.2 and 6.3.1
2017-02-14 14:31:31 +01:00
w0rp
afd0730248 #274 Stop airline from doing anything if ALE doesn't load by using a different flag for loading with a very ugly name 2017-02-14 09:18:54 +00:00
w0rp
810e420510 #274 Don't emit the warning if ALE isn't working for git commits or blank files 2017-02-13 23:48:36 +00:00
w0rp
f39e88cfa8 #274 - Fix airline integration when ALE is not loaded fully 2017-02-13 23:31:29 +00:00
w0rp
c0814934af Output ALE global variables for :ALEInfo 2017-02-13 23:15:52 +00:00
w0rp
0589022c76 Include most linter variables in ALEInfo 2017-02-13 22:11:35 +00:00
w0rp
f6bc73b749 Fix a style issue 2017-02-13 12:52:44 +00:00
w0rp
a5ec5366c4 Actually catch all Job ID problems 2017-02-13 12:13:54 +00:00
w0rp
f9815fcdef Merge pull request #336 from ninjawithaneedle/master
Highlighting should not filter linter messages without column info
2017-02-13 11:02:51 +00:00
ninjawithaneedle
a2f59049dc Highlighting should not filter linter messages without column info 2017-02-13 16:30:32 +05:30
w0rp
5cdd1498b4 #283 Fix linting buffers with no filename, by creating a filename with a guess for the file extension 2017-02-13 10:36:38 +00:00
w0rp
3aa1d57b57 Fix #171 - Implement basic error highlighting 2017-02-13 00:24:25 +00:00
w0rp
a995daa827 Fix #325 - document the ALEToggle option 2017-02-12 19:26:18 +00:00
w0rp
83b46f66f8 Make a note to ask for Vader tests 2017-02-12 17:59:05 +00:00
w0rp
f0bd08ec11 Merge pull request #331 from AlexMasterov/feature/css-stylelint-options
Add stylelint option to pass in more options
2017-02-12 17:49:22 +00:00
Alex Masterov
4e082b9217 Add stylelint option to pass in more options 2017-02-12 09:25:40 +03:00
w0rp
820896315d Update the contributing guide 2017-02-12 00:26:45 +00:00
w0rp
ed269b8831 Fix the clangtidy linter, and document everything 2017-02-11 23:45:06 +00:00
Tim van Deurzen
355608b031 Add clang-tidy linter for cpp. (#275)
* Add clang-tidy linter for cpp.

* Use stdin-wrapper to allow linting as you type.
2017-02-11 23:32:56 +00:00
w0rp
4a71638061 Feed files to commands via stdin by first writing the file to a temporary file, and then piping them in via the shell instead 2017-02-11 22:43:13 +00:00
w0rp
341ea5f367 Fix the custom check issue. 2017-02-11 22:06:20 +00:00
w0rp
112f71fb17 Make javac work in a basic way 2017-02-11 22:02:38 +00:00
Valentin Finini
8c4846b68a Added support for javac (with eclipse classpath support for now) (#141)
* A try at javac support for ALE

* Small cleanup: moved '/tmp/java_ale' string into script var

* Fixed Travis-CI build failing on autocmd not being in augroup and stupid omission

* One more fix for Travis-CI

* For some reason, expandtab was not set

* Indentation and removal of header guard.

Used examples from ale_linters/c/gcc.vim and
ale_linters/javascript/eslint.vim for the indentation of string concat blocks.
2017-02-11 21:29:48 +00:00
w0rp
3551bde012 Fix #330 - Explain how to check JSX with eslint and stylelint 2017-02-11 21:18:24 +00:00
w0rp
2078255ec3 Fix filename substitution, especially on Windows 2017-02-11 20:34:14 +00:00
w0rp
ecbb276805 Replace every stdin-wrapper script with the new %t formatting support 2017-02-11 19:40:57 +00:00
w0rp
c33602534e Fix Pug linting 2017-02-11 18:49:12 +00:00
w0rp
beeef28b1a Use writefile() for temporary files, which works better 2017-02-11 18:19:01 +00:00
w0rp
03ab963d1a Add support for temporary filename substitution, for replacing stdin_wrapper 2017-02-11 18:14:18 +00:00
w0rp
88192e8662 Add support for managing temporary files/directories 2017-02-11 15:16:08 +00:00
w0rp
8ad85858b8 Merge pull request #329 from tomotanakamura/AddClangToCpp
Add clang to cpp linters.
2017-02-11 13:10:18 +00:00
tomotanakamura
2ba2aff65e Add clang to cpp linters. 2017-02-11 21:35:34 +09:00
w0rp
4737e09bcf Try and fix Travis builds again 2017-02-11 00:20:16 +00:00
w0rp
14c38cdb63 Fix #116 - Send SIGKILL to processes if they don't respond to SIGTERM 2017-02-11 00:08:05 +00:00
w0rp
81779e60bb Document the command empty string behaviour 2017-02-10 23:11:26 +00:00
w0rp
49f7ce4f6d Fix #246 Don't run flow if there's no .flowconfig 2017-02-10 22:47:56 +00:00
w0rp
926cd1a953 Fix #283 Add an option for using ch_sendraw(), which can be better for some users 2017-02-10 19:34:44 +00:00
w0rp
c528ab1eaa Fix #269 Set $TMPDIR to a default value, if not set 2017-02-10 09:45:42 +00:00
w0rp
5bda827143 Merge pull request #327 from jparise/credo-stdin-filename
Pass the buffer's filename to Credo
2017-02-10 09:20:45 +00:00
Jon Parise
d3e7d3d5e7 Pass the buffer's filename to Credo
By default, Credo attributes input from STDIN as though it came from a
file named `stdin`. This change passes the buffer's filename, too, so
that Credo can use that information when applying its configuration.

This is a nice improvement because files like `mix.exs` are normally
excluded from Credo-based linting. Previously, ALE would show lint
warnings for those files as they were edited. Now, they are correctly
honor the Credo configuration and don't produce lint output.
2017-02-09 19:24:28 -08:00
w0rp
5de445c041 Fix #315 Implement the read_buffer option 2017-02-09 23:32:57 +00:00
w0rp
9f8c76b5b9 Make ALE complain when conflicting command options are used 2017-02-09 20:44:13 +00:00
w0rp
38d9802d12 Don't export the custom-checks script in archives 2017-02-09 20:14:03 +00:00
w0rp
b0190fd080 Merge pull request #306 from ahmedelgabri/standardjs
Add standard linter
2017-02-09 18:56:40 +00:00
Daniel Lupu
d8efd4fa73 add xo support (#304)
* add xo support

* add documentation

* Fix a screw up when fixing conflicts

* Fix it harder
2017-02-09 18:54:49 +00:00
Daniel Lupu
6dfed8576e add ALEToggle command (#303)
* add ALEToggle command

* stop active jobs when toggled off

* small logic cleanup & ensure ale can be ran manually while toggled off
2017-02-09 18:47:14 +00:00
w0rp
943fe9b4b0 Merge pull request #295 from metakirby5/pr/coffeelint-local
Add support for locally installed coffee and coffeelint
2017-02-09 18:44:52 +00:00
w0rp
f67cf17070 Merge pull request #285 from medains/master
Linter addition of PHP Mess Detector
2017-02-09 18:43:26 +00:00
Ahmed El Gabri
119695bd08 Add standard linter 2017-02-05 21:19:34 +01:00
Ethan Chan
69ce8502a4 add support for locally installed coffee 2017-02-02 17:03:26 -08:00
Ethan Chan
1da187a6e5 add support for locally installed coffeelint 2017-02-02 16:56:09 -08:00
medains
ff096124c6 Linter addition of PHP Mess Detector 2017-02-01 16:28:51 +00:00
164 changed files with 5382 additions and 1034 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

@@ -5,6 +5,11 @@
3. [Creating Pull Requests](#pull-requests)
1. [Adding a New Linter](#adding-a-new-linter)
2. [Adding New Options](#adding-new-options)
4. [Writing Documentation](#writing-documentation)
1. [Documenting New Linters](#documenting-new-linters)
2. [Editing the Online Documentation](#editing-online-documentation)
3. [Documenting Linter Options](#documenting-new-options)
5. [In Case of Busses](#in-case-of-busses)
<a name="guidelines"></a>
@@ -12,6 +17,12 @@
Have fun, and work on whatever floats your boat. Take It Easy :tm:.
Don't forget to **write documentation** for whatever it is you are doing.
See the ["Writing Documentation"](#writing-documentation) section.
Remember to write Vader tests for most of the code you write. You can look at
existing Vader tests in the `test` directory for examples.
When writing code, follow the [Google Vimscript Style
Guide](https://google.github.io/styleguide/vimscriptguide.xml), and run `vint
-s` on your files to check for most of what the guide mentions and more. If you
@@ -90,3 +101,73 @@ global variable names.
Any options for linters should be set to some default value so it is always
easy to see what the default is with `:echo g:ale...`.
<a name="writing-documentation"></a>
# 4. Writing Documentation
If you are adding new linters, changing the API, adding new options, etc., you
_must_ write some documentation describing it in the `doc/ale.txt` file. New
linters _must_ be added to the `README.md` file too, so other users can get a
quick overview of the supported tools.
<a name="documenting-new-linters"></a>
# 4.i Documenting New Linters
If you add a new linter to the project, edit the table in the `README.md` file,
and edit the list of linters at the top of the `doc/ale.txt` file. The linters
should be sorted vertically in lexicographic (alphabetical) order by the
programming language name or filetype, and the tools for each language should
be sorted in lexicographic order horizontally. Sorting in this manner is a fair
manner of presenting all of the information in an easy to scan way, without
giving some unfair preference to any particular tool or language.
<a name="editing-online-documentation"></a>
# 4.ii Editing the Online Documentation
The "online documentation" file used for this project lives in `doc/ale.txt`.
This is the file used for generating `:help` text inside Vim itself. There are
some guidlines to follow for this file.
1. Keep all text within a column size of 79 characters, inclusive.
2. Open a section with 79 `=` or `-` characters, for headings and subheadings.
3. Sections should have a _single_ blank line before or after.
4. Between descriptions of variables/functions/commands, use _two_ blank lines.
5. Up-indent the description of a variable/function/command by two spaces.
6. Place tags at the ends of lines, with the final characters on column 79.
All of the tags should line up perfectly on the same column as you scan
down through the document.
7. Keep the table of contents balanced so the longest tag link ends on column
79, and so all links line up perfectly on their first character, on the
left.
<a name="documenting-linter-options"></a>
# 4.iii Documenting Linter Options
For documenting new linter options, please add a new sub-section under the
"Linter Specific Options" section describing all of the global options added
for each linter, and what the default values of the options are. All global
options for linters should be set to some default value. This will allow users
to look up the default value easily by typing `:echo g:ale_...`.
<a name="in-case-of-busses"></a>
# 5. In Case of Busses
Should the principal author of the ALE project and all collaborators with the
required access needed to properly administrate the project on GitHub or any
other website either perish or disappear, whether by tragic traffic accident
or government adduction, etc., action should be taken to ensure that the
project continues. If no one is left to administer the project where it is
hosted, please fork the project and nominate someone capable to administer it.
Preferably, in such an event, a single fork of the project will replace the
original, and life will go on, except the life of whoever vanished, because
then they will probably be dead.
Should w0rp suddenly disappear, then he was probably killed in a traffic
accident, or the government finally decided to kill him and make it look like
suicide. In the latter event, please subvert said government and restore
order to the universe, and ensure peace for mankind.

10
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,10 @@
For bugs, paste output from your clipboard after running :ALEInfoToClipboard
here. If that doesn't work for some reason, try running :ALEInfo and copying
the output from that here instead. If everything is broken, run around in
circles and scream.
If you are experiencing a bug where ALE is not correctly parsing the output of
commands, set g:ale_history_log_output to 1, and run ALE again, and then
:ALEInfo should include the full output of each command which ran.
Whatever the case, describe the your issue here.

View File

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

132
README.md
View File

@@ -23,7 +23,8 @@ In other words, this plugin allows you to lint while you type.
1. [Installation with Pathogen](#installation-with-pathogen)
2. [Installation with Vundle](#installation-with-vundle)
3. [Manual Installation](#manual-installation)
4. [FAQ](#faq)
4. [Contributing](#contributing)
5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters)
2. [How can I keep the sign gutter open?](#faq-disable-linters)
3. [How can I change the signs ALE uses?](#faq-change-signs)
@@ -33,6 +34,8 @@ In other words, this plugin allows you to lint while you type.
7. [How can I navigate between errors quickly?](#faq-navigation)
8. [How can I run linters only when I save files?](#faq-lint-on-save)
9. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
10. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
11. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
<a name="supported-languages"></a>
@@ -50,12 +53,14 @@ name. That seems to be the fairest way to arrange this table.
| Language | Tools |
| -------- | ----- |
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) |
| AsciiDoc | [proselint](http://proselint.com/)|
| Bash | [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/) |
| Bourne Shell | [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/) |
| C | [cppcheck](http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/), [clang](http://clang.llvm.org/)|
| C++ (filetype cpp) | [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangtidy](http://clang.llvm.org/extra/clang-tidy/), [cppcheck] (http://cppcheck.sourceforge.net), [gcc](https://gcc.gnu.org/)|
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) |
| Chef | [foodcritic](http://www.foodcritic.io/) |
| CMake | [cmakelint](https://github.com/richq/cmake-lint) |
| CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
| CSS | [csslint](http://csslint.net/), [stylelint](https://github.com/stylelint/stylelint) |
| Cython (pyrex filetype) | [cython](http://cython.org/) |
@@ -66,40 +71,46 @@ name. That seems to be the fairest way to arrange this table.
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html) |
| Fortran | [gcc](https://gcc.gnu.org/) |
| Go | [gofmt -e](https://golang.org/cmd/gofmt/), [go vet](https://golang.org/cmd/vet/), [golint](https://godoc.org/github.com/golang/lint), [go build](https://golang.org/cmd/go/) |
| Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint) |
| HTML | [HTMLHint](http://htmlhint.com/), [tidy](http://www.html-tidy.org/) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/) |
| Haml | [haml-lint](https://github.com/brigade/haml-lint)
| Haskell | [ghc](https://www.haskell.org/ghc/), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools) |
| HTML | [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/) |
| Java | [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [standard](http://standardjs.com/)
| JSON | [jsonlint](http://zaa.ch/jsonlint/) |
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck) |
| Lua | [luacheck](https://github.com/mpeterv/luacheck) |
| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/)|
| MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) |
| Nim | [nim](https://nim-lang.org/docs/nimc.html) |
| nix | [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate) |
| nroff | [proselint](http://proselint.com/)|
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) |
| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) |
| Pod | [proselint](http://proselint.com/)|
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
| Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) |
| reStructuredText | [proselint](http://proselint.com/)|
| Ruby | [rubocop](https://github.com/bbatsov/rubocop) |
| Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
| Scala | [scalac](http://scala-lang.org) |
| Slim | [slim-lint](https://github.com/sds/slim-lint)
| SML | [smlnj](http://www.smlnj.org/) |
| Swift | [swiftlint](https://swift.org/) |
| Tex | [proselint](http://proselint.com/) |
| Text^^ | [proselint](http://proselint.com/) |
| Texinfo | [proselint](http://proselint.com/)|
| Text^ | [proselint](http://proselint.com/) |
| TypeScript | [tslint](https://github.com/palantir/tslint), typecheck |
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
| Vim | [vint](https://github.com/Kuniwak/vint) |
| Vim help^ | [proselint](http://proselint.com/)|
| XHTML | [proselint](http://proselint.com/)|
| YAML | [yamllint](https://yamllint.readthedocs.io/) |
* *^^ No text linters are enabled by default.*
If you would like to see support for more languages and tools, please
[create an issue](https://github.com/w0rp/ale/issues)
or [create a pull request](https://github.com/w0rp/ale/pulls).
If your tool can read from stdin or you have code to suggest which is good,
support can be happily added for it.
* *^ No linters for text or Vim help filetypes are enabled by default.*
<a name="usage"></a>
@@ -189,13 +200,27 @@ silent! helptags ALL
Because the author of this plugin is a weird nerd, this is his preferred
installation method.
<a name="contributing"></a>
## 4. Contributing
If you would like to see support for more languages and tools, please
[create an issue](https://github.com/w0rp/ale/issues)
or [create a pull request](https://github.com/w0rp/ale/pulls).
If your tool can read from stdin or you have code to suggest which is good,
support can be happily added for it.
If you are interested in the general direction of the project, check out the
[wiki home page](https://github.com/w0rp/ale/wiki). The wiki includes a
Roadmap for the future, and more.
<a name="faq"></a>
## 4. FAQ
## 5. FAQ
<a name="faq-disable-linters"></a>
### 4.i. How do I disable particular linters?
### 5.i. How do I disable particular linters?
By default, all available tools for all supported languages will be run.
If you want to only select a subset of the tools, simply create a
@@ -219,7 +244,7 @@ in each directory corresponds to the name of a particular linter.
<a name="faq-keep-signs"></a>
### 4.ii. How can I keep the sign gutter open?
### 5.ii. How can I keep the sign gutter open?
You can keep the sign gutter open at all times by setting the
`g:ale_sign_column_always` to 1
@@ -230,7 +255,7 @@ let g:ale_sign_column_always = 1
<a name="faq-change-signs"></a>
### 4.iii. How can I change the signs ALE uses?
### 5.iii. How can I change the signs ALE uses?
Use these options to specify what text should be used for signs:
@@ -250,7 +275,7 @@ highlight clear ALEWarningSign
<a name="faq-statusline"></a>
### 4.iv. How can I show errors or warnings in my statusline?
### 5.iv. How can I show errors or warnings in my statusline?
You can use `ALEGetStatusLine()` to integrate ALE into vim statusline.
To enable it, you should have in your `statusline` settings
@@ -277,7 +302,7 @@ let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
<a name="faq-echo-format"></a>
### 4.v. How can I change the format for echo messages?
### 5.v. How can I change the format for echo messages?
There are 3 global options that allow customizing the echoed message.
@@ -302,7 +327,7 @@ Will give you:
<a name="faq-autocmd"></a>
### 4.vi. How can I execute some code when ALE stops linting?
### 5.vi. How can I execute some code when ALE stops linting?
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
event whenever has a linter has been successfully executed and processed. This
@@ -317,7 +342,7 @@ augroup END
<a name="faq-navigation"></a>
### 4.vii. How can I navigate between errors quickly?
### 5.vii. How can I navigate between errors quickly?
ALE offers some commands with `<Plug>` keybinds for moving between warnings and
errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
@@ -333,7 +358,7 @@ For more information, consult the online documentation with
<a name="faq-lint-on-save"></a>
### 4.viii. How can I run linters only when I save files?
### 5.viii. How can I run linters only when I save files?
ALE offers an option `g:ale_lint_on_save` for enabling running the linters
when files are saved. If you wish to run linters when files are saved, not
@@ -351,7 +376,7 @@ let g:ale_lint_on_enter = 0
<a name="faq-quickfix"></a>
### 4.ix. How can I use the quickfix list instead of the loclist?
### 5.ix. How can I use the quickfix list instead of the loclist?
The quickfix list can be enabled by turning the `g:ale_set_quickfix`
option on. If you wish to also disable the loclist, you can disable
@@ -375,3 +400,62 @@ let g:ale_open_list = 1
" some other plugin which sets quickfix errors, etc.
let g:ale_keep_list_window_open = 1
```
<a name="faq-jsx-stylelint-eslint"></a>
### 5.x. How can I check JSX files with both stylelint and eslint?
If you configure ALE options correctly in your vimrc file, and install
the right tools, you can check JSX files with stylelint and eslint.
First, install eslint and install stylelint with
[https://github.com/styled-components/stylelint-processor-styled-components](stylelint-processor-styled-components).
Supposing you have installed both tools correctly, configure your .jsx files so
`jsx` is included in the filetype. You can use an `autocmd` for this.
```vim
augroup FiletypeGroup
autocmd!
au BufNewFile,BufRead *.jsx set filetype=javascript.jsx
augroup END
```
Supposing the filetype has been set correctly, you can set the following
options in your vimrc file:
```vim
let g:ale_linters = {'jsx': ['stylelint', 'eslint']}
let g:ale_linter_aliases = {'jsx': 'css'}
```
ALE will alias the `jsx` filetype so it uses the `css` filetype linters, and
use the original Array of selected linters for `jsx` from the `g:ale_linters`
object. All available linters will be used for the filetype `javascript`, and
no linter will be run twice for the same file.
<a name="faq-my-battery-is-sad"></a>
### 5.xi. Will this plugin eat all of my laptop battery power?
ALE takes advantage of the power of various tools to check your code. This of
course means that CPU time will be used to continuously check your code. If you
are concerned about the CPU time ALE will spend, which will of course imply
some cost to battery life, you can adjust your settings to make your CPU do
less work.
First, consider increasing the delay before which ALE will run any linters
while you type. ALE uses a timeout which is cancelled and reset every time you
type, and this delay can be increased so linters are run less often. See
`:help g:ale_lint_delay` for more information.
If you don't wish to run linters while you type, you can disable that
behaviour. Set `g:ale_lint_on_text_changed` to `0`, and consider setting
`g:ale_lint_on_save` to `1` to enable linting when you save files. You won't
get as frequent error checking, but ALE shouldn't block your ability to edit a
document after you save a file, so the asynchronous nature of the plugin will
still be an advantage.
If you are still concerned, you can turn the automatic linting off altogether,
including the option `g:ale_lint_on_enter`, and you can run ALE manually with
`:call ale#Lint()`.

28
after/plugin/ale.vim Normal file
View File

@@ -0,0 +1,28 @@
if exists('g:loaded_ale_after')
finish
endif
let g:loaded_ale_after = 1
if !g:ale_emit_conflict_warnings
finish
endif
function! s:GetConflictingPluginWarning(plugin_name) abort
return 'ALE conflicts with ' . a:plugin_name
\ . '. Uninstall it, or disable this warning with '
\ . '`let g:ale_emit_conflict_warnings = 0` in your vimrc file, '
\ . '*before* plugins are loaded.'
endfunction
if exists('g:loaded_syntastic_plugin')
throw s:GetConflictingPluginWarning('Syntastic')
endif
if exists('g:loaded_neomake')
throw s:GetConflictingPluginWarning('Neomake')
endif
if exists('g:loaded_validator_plugin')
throw s:GetConflictingPluginWarning('Validator')
endif

View File

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

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for AsciiDoc files
call ale#linter#Define('asciidoc', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -9,12 +9,18 @@ if !exists('g:ale_c_clang_options')
let g:ale_c_clang_options = '-std=c11 -Wall'
endif
function! ale_linters#c#clang#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return 'clang -S -x c -fsyntax-only '
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . g:ale_c_clang_options . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': 'clang',
\ 'command': 'clang -S -x c -fsyntax-only '
\ . g:ale_c_clang_options
\ . ' -',
\ 'command_callback': 'ale_linters#c#clang#GetCommand',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

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

View File

@@ -10,9 +10,11 @@ if !exists('g:ale_c_gcc_options')
endif
function! ale_linters#c#gcc#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return 'gcc -S -x c -fsyntax-only '
\ . g:ale_c_gcc_options . ' -'
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . g:ale_c_gcc_options . ' -'
endfunction
call ale#linter#Define('c', {

View File

@@ -21,11 +21,9 @@ function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0,
\ 'vcol': 0,
\ 'col': 0,
\ 'text': l:text,
\ 'type': 'W',
\ 'nr': -1,
\})
endfor
@@ -35,7 +33,7 @@ endfunction
call ale#linter#Define('chef', {
\ 'name': 'foodcritic',
\ 'executable': 'foodcritic',
\ 'command': g:ale#util#stdin_wrapper . ' .rb foodcritic',
\ 'command': 'foodcritic %t',
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
\})

View File

@@ -0,0 +1,24 @@
" Author: Kenneth Benzie <k.benzie83@gmail.com>
" Description: cmakelint for cmake files
let g:ale_cmake_cmakelint_executable =
\ get(g:, 'ale_cmake_cmakelint_executable', 'cmakelint')
let g:ale_cmake_cmakelint_options =
\ get(g:, 'ale_cmake_cmakelint_options', '')
function! ale_linters#cmake#cmakelint#Executable(buffer) abort
return g:ale_cmake_cmakelint_executable
endfunction
function! ale_linters#cmake#cmakelint#Command(buffer) abort
return ale_linters#cmake#cmakelint#Executable(a:buffer)
\ . ' ' . g:ale_cmake_cmakelint_options . ' %t'
endfunction
call ale#linter#Define('cmake', {
\ 'name': 'cmakelint',
\ 'executable_callback': 'ale_linters#cmake#cmakelint#Executable',
\ 'command_callback': 'ale_linters#cmake#cmakelint#Command',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -1,10 +1,23 @@
" Author: KabbAmine - https://github.com/KabbAmine
" Description: Coffee for checking coffee files
function! ale_linters#coffee#coffee#GetExecutable(buffer) abort
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/coffee',
\ 'coffee'
\)
endfunction
function! ale_linters#coffee#coffee#GetCommand(buffer) abort
return ale_linters#coffee#coffee#GetExecutable(a:buffer)
\ . ' -cp -s'
endfunction
call ale#linter#Define('coffee', {
\ 'name': 'coffee',
\ 'executable': 'coffee',
\ 'command': 'coffee -cp -s',
\ 'executable_callback': 'ale_linters#coffee#coffee#GetExecutable',
\ 'command_callback': 'ale_linters#coffee#coffee#GetCommand',
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

@@ -1,6 +1,19 @@
" Author: Prashanth Chandra https://github.com/prashcr
" Description: coffeelint linter for coffeescript files
function! ale_linters#coffee#coffeelint#GetExecutable(buffer) abort
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/coffeelint',
\ 'coffeelint'
\)
endfunction
function! ale_linters#coffee#coffeelint#GetCommand(buffer) abort
return ale_linters#coffee#coffeelint#GetExecutable(a:buffer)
\ . ' --stdin --reporter csv'
endfunction
function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
@@ -8,7 +21,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
" stdin,14,,error,Throwing strings is forbidden
"
" Note that we currently ignore lineNumberEnd for multiline errors
let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\+\),\(.\+\)'
let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\{-1,}\),\(.\+\)'
let l:output = []
for l:line in a:lines
@@ -27,11 +40,9 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
@@ -40,7 +51,7 @@ endfunction
call ale#linter#Define('coffee', {
\ 'name': 'coffeelint',
\ 'executable': 'coffeelint',
\ 'command': 'coffeelint --stdin --reporter csv',
\ 'executable_callback': 'ale_linters#coffee#coffeelint#GetExecutable',
\ 'command_callback': 'ale_linters#coffee#coffeelint#GetCommand',
\ 'callback': 'ale_linters#coffee#coffeelint#Handle',
\})

23
ale_linters/cpp/clang.vim Normal file
View File

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

View File

@@ -0,0 +1,18 @@
" Author: vdeurzen <tim@kompiler.org>, w0rp <devw0rp@gmail.com>
" Description: clang-tidy linter for cpp files
" Set this option to change the clang-tidy options for warnings for C.
let g:ale_cpp_clangtidy_options =
\ get(g:, 'ale_cpp_clangtidy_options', '-std=c++14 -Wall')
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
return 'clang-tidy %t -- ' . g:ale_cpp_clangtidy_options
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
\ 'executable': 'clang-tidy',
\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
\ 'callback': 'ale#handlers#HandleGCCFormat',
\})

View File

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

View File

@@ -16,9 +16,11 @@ if !exists('g:ale_cpp_gcc_options')
endif
function! ale_linters#cpp#gcc#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return 'gcc -S -x c++ -fsyntax-only '
\ . g:ale_cpp_gcc_options . ' -'
\ . '-iquote ' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . g:ale_cpp_gcc_options . ' -'
endfunction
call ale#linter#Define('cpp', {

View File

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

View File

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

View File

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

View File

@@ -46,9 +46,7 @@ function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort
endif
endfor
return g:ale#util#stdin_wrapper . ' .d dmd '
\ . join(l:import_list)
\ . ' -o- -vcolumns -c'
return 'dmd '. join(l:import_list) . ' -o- -vcolumns -c %t'
endfunction
function! ale_linters#d#dmd#Handle(buffer, lines) abort
@@ -74,11 +72,9 @@ function! ale_linters#d#dmd#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': bufnr('%'),
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type ==# 'Warning' ? 'W' : 'E',
\ 'nr': -1,
\})
endfor

View File

@@ -27,7 +27,6 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': 0,
\ 'type': l:type,
\ 'text': l:text,

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
"
" :21.34:
" Error: Expected comma in I/O list at (1)
let l:line_marker_pattern = '^:\(\d\+\)\.\(\d\+\):$'
let l:line_marker_pattern = ':\(\d\+\)[.:]\=\(\d\+\)\=:\=$'
let l:message_pattern = '^\(Error\|Warning\): \(.\+\)$'
let l:looking_for_message = 0
let l:last_loclist_obj = {}
@@ -41,9 +41,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
let l:last_loclist_obj = {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'nr': -1,
\}
" Start looking for the message and error type.

View File

@@ -101,6 +101,12 @@ function! ale_linters#go#gobuild#CopyFiles(buffer, golist_output) abort
endfunction
function! ale_linters#go#gobuild#GetCommand(buffer, copy_output) abort
" If for some reason we don't get any output from the last command, stop
" here.
if empty(a:copy_output)
return ''
endif
let l:tempdir = a:copy_output[0]
let l:importpath = s:PackageImportPath(a:buffer)
@@ -190,11 +196,9 @@ function! ale_linters#go#gobuild#Handler(buffer, lines) abort
call add(l:output, {
\ 'bufnr': l:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[4],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
" Author: Patrick Lewis - https://github.com/patricklewis
" Description: haml-lint for Haml files
function! ale_linters#haml#hamllint#Handle(buffer, lines) abort
" Matches patterns like the following:
" <path>:51 [W] RuboCop: Use the new Ruby 1.9 hash syntax.
let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'type': l:match[2],
\ 'text': l:match[3]
\})
endfor
return l:output
endfunction
call ale#linter#Define('haml', {
\ 'name': 'hamllint',
\ 'executable': 'haml-lint',
\ 'command': 'haml-lint %t',
\ 'callback': 'ale_linters#haml#hamllint#Handle'
\})

View File

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

View File

@@ -0,0 +1,9 @@
" Author: rob-b
" Description: hdevtools for Haskell files
call ale#linter#Define('haskell', {
\ 'name': 'hdevtools',
\ 'executable': 'hdevtools',
\ 'command': 'hdevtools check -g -Wall -p %s %t',
\ 'callback': 'ale#handlers#HandleGhcFormat',
\})

View File

@@ -11,7 +11,6 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:error.startLine + 0,
\ 'vcol': 0,
\ 'col': l:error.startColumn + 0,
\ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to,
\ 'type': l:error.severity ==# 'Error' ? 'E' : 'W',

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Vim help files
call ale#linter#Define('help', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

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

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for HTML files
call ale#linter#Define('html', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -53,11 +53,9 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor

View File

@@ -0,0 +1,52 @@
" Author: farenjihn <farenjihn@gmail.com>, w0rp <devw0rp@gmail.com>
" Description: Lints java files using javac
let g:ale_java_javac_options = get(g:, 'ale_java_javac_options', '')
let g:ale_java_javac_classpath = get(g:, 'ale_java_javac_classpath', '')
function! ale_linters#java#javac#GetCommand(buffer) abort
let l:cp_option = !empty(g:ale_java_javac_classpath)
\ ? '-cp ' . g:ale_java_javac_classpath
\ : ''
return 'javac -Xlint '
\ . l:cp_option
\ . ' ' . g:ale_java_javac_options
\ . ' %t'
endfunction
function! ale_linters#java#javac#Handle(buffer, lines) abort
" Look for lines like the following.
"
" Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
" Main.java:16: error: ';' expected
let l:pattern = '^.*\:\(\d\+\):\ \(.*\):\(.*\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'col': 1,
\ 'text': l:match[2] . ':' . l:match[3],
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('java', {
\ 'name': 'javac',
\ 'output_stream': 'stderr',
\ 'executable': 'javac',
\ 'command_callback': 'ale_linters#java#javac#GetCommand',
\ 'callback': 'ale_linters#java#javac#Handle',
\})

View File

@@ -29,6 +29,21 @@ function! ale_linters#javascript#eslint#GetCommand(buffer) abort
endfunction
function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
let l:config_error_pattern = '\v^ESLint couldn''t find a configuration file'
\ . '|^Cannot read config file'
" Look for a message in the first few lines which indicates that
" a configuration file couldn't be found.
for l:line in a:lines[:10]
if len(matchlist(l:line, l:config_error_pattern)) > 0
return [{
\ 'lnum': 1,
\ 'text': 'eslint configuration error (type :ALEDetail for more information)',
\ 'detail': join(a:lines, "\n"),
\}]
endif
endfor
" Matches patterns line the following:
"
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
@@ -65,11 +80,9 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type ==# 'Warning' ? 'W' : 'E',
\ 'nr': -1,
\})
endfor

View File

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

View File

@@ -0,0 +1,69 @@
" Author: Ahmed El Gabri <@ahmedelgabri>
" Description: standardjs for JavaScript files
let g:ale_javascript_standard_executable =
\ get(g:, 'ale_javascript_standard_executable', 'standard')
let g:ale_javascript_standard_options =
\ get(g:, 'ale_javascript_standard_options', '')
let g:ale_javascript_standard_use_global =
\ get(g:, 'ale_javascript_standard_use_global', 0)
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
if g:ale_javascript_standard_use_global
return g:ale_javascript_standard_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/standard',
\ g:ale_javascript_standard_executable
\)
endfunction
function! ale_linters#javascript#standard#GetCommand(buffer) abort
return ale_linters#javascript#standard#GetExecutable(a:buffer)
\ . ' ' . g:ale_javascript_standard_options
\ . ' --stdin %s'
endfunction
function! ale_linters#javascript#standard#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" /path/to/some-filename.js:47:14: Strings must use singlequote.
" /path/to/some-filename.js:56:41: Expected indentation of 2 spaces but found 4.
" /path/to/some-filename.js:13:3: Parsing error: Unexpected token
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:type = 'Error'
let l:text = l:match[3]
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': 'E',
\})
endfor
return l:output
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'standard',
\ 'executable_callback': 'ale_linters#javascript#standard#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#standard#GetCommand',
\ 'callback': 'ale_linters#javascript#standard#Handle',
\})

View File

@@ -0,0 +1,41 @@
" Author: Daniel Lupu <lupu.daniel.f@gmail.com>
" Description: xo for JavaScript files
let g:ale_javascript_xo_executable =
\ get(g:, 'ale_javascript_xo_executable', 'xo')
let g:ale_javascript_xo_options =
\ get(g:, 'ale_javascript_xo_options', '')
let g:ale_javascript_xo_use_global =
\ get(g:, 'ale_javascript_xo_use_global', 0)
function! ale_linters#javascript#xo#GetExecutable(buffer) abort
if g:ale_javascript_xo_use_global
return g:ale_javascript_xo_executable
endif
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/xo',
\ g:ale_javascript_xo_executable
\)
endfunction
function! ale_linters#javascript#xo#GetCommand(buffer) abort
return ale_linters#javascript#xo#GetExecutable(a:buffer)
\ . ' ' . g:ale_javascript_xo_options
\ . ' --reporter unix --stdin --stdin-filename %s'
endfunction
function! ale_linters#javascript#xo#Handle(buffer, lines) abort
" xo uses eslint and the output format is the same
return ale_linters#javascript#eslint#Handle(a:buffer, a:lines)
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'xo',
\ 'executable_callback': 'ale_linters#javascript#xo#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#xo#GetCommand',
\ 'callback': 'ale_linters#javascript#xo#Handle',
\})

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,16 @@
let g:ale_matlab_mlint_executable =
\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
function! ale_linters#matlab#mlint#GetExecutable(buffer) abort
return g:ale_matlab_mlint_executable
endfunction
function! ale_linters#matlab#mlint#GetCommand(buffer) abort
let l:executable = ale_linters#matlab#mlint#GetExecutable(a:buffer)
return l:executable . ' -id %t'
endfunction
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
@@ -34,11 +44,9 @@ function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:lnum,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': 'W',
\ 'nr': -1,
\})
endfor
@@ -47,9 +55,8 @@ endfunction
call ale#linter#Define('matlab', {
\ 'name': 'mlint',
\ 'executable': 'mlint',
\ 'command': g:ale#util#stdin_wrapper .
\ ' .m ' . g:ale_matlab_mlint_executable . ' -id',
\ 'executable_callback': 'ale_linters#matlab#mlint#GetExecutable',
\ 'command_callback': 'ale_linters#matlab#mlint#GetCommand',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#matlab#mlint#Handle',
\})

View File

@@ -0,0 +1,65 @@
" Author: Baabelfish
" Description: Typechecking for nim files
function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p:t')
let l:pattern = '^\(.\+\.nim\)(\(\d\+\), \(\d\+\)) \(.\+\)'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
" Only show errors of the current buffer
" NOTE: Checking filename only is OK because nim enforces unique
" module names.
let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t')
if l:buffer_filename !=# '' && l:temp_buffer_filename !=# l:buffer_filename
continue
endif
let l:line = l:match[2] + 0
let l:column = l:match[3] + 0
let l:text = l:match[4]
let l:type = 'W'
" Extract error type from message of type 'Error: Some error message'
let l:textmatch = matchlist(l:match[4], '^\(.\{-}\): .\+$')
if len(l:textmatch) > 0
let l:errortype = l:textmatch[1]
if l:errortype ==# 'Error'
let l:type = 'E'
endif
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\})
endfor
return l:output
endfunction
function! ale_linters#nim#nimcheck#GetCommand(buffer)
return 'nim check --path:' . fnameescape(fnamemodify(bufname(a:buffer), ':p:h')) . ' --verbosity:0 --colors:off --listFullPaths %t'
endfunction
call ale#linter#Define('nim', {
\ 'name': 'nimcheck',
\ 'executable': 'nim',
\ 'output_stream': 'both',
\ 'command_callback': 'ale_linters#nim#nimcheck#GetCommand',
\ 'callback': 'ale_linters#nim#nimcheck#Handle'
\})

34
ale_linters/nix/nix.vim Normal file
View File

@@ -0,0 +1,34 @@
" Author: Alistair Bill <@alibabzo>
" Description: nix-instantiate linter for nix files
function! ale_linters#nix#nix#Handle(buffer, lines) abort
let l:pattern = '^\(.\+\): \(.\+\), at .*:\(\d\+\):\(\d\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0,
\ 'col': l:match[4] + 0,
\ 'text': l:match[1] . ': ' . l:match[2],
\ 'type': l:match[1] =~# '^error' ? 'E' : 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('nix', {
\ 'name': 'nix',
\ 'output_stream': 'stderr',
\ 'executable': 'nix-instantiate',
\ 'command': 'nix-instantiate --parse -',
\ 'callback': 'ale_linters#nix#nix#Handle',
\})

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for nroff files
call ale#linter#Define('nroff', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -1,6 +1,22 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl syntax
let g:ale_perl_perl_executable =
\ get(g:, 'ale_perl_perl_executable', 'perl')
let g:ale_perl_perl_options =
\ get(g:, 'ale_perl_perl_options', '-X -c -Mwarnings -Ilib')
function! ale_linters#perl#perl#GetExecutable(buffer) abort
return g:ale_perl_perl_executable
endfunction
function! ale_linters#perl#perl#GetCommand(buffer) abort
return ale_linters#perl#perl#GetExecutable(a:buffer)
\ . ' ' . g:ale_perl_perl_options
\ . ' %t'
endfunction
function! ale_linters#perl#perl#Handle(buffer, lines) abort
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = []
@@ -21,11 +37,9 @@ function! ale_linters#perl#perl#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
@@ -34,8 +48,8 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perl',
\ 'executable': 'perl',
\ 'executable_callback': 'ale_linters#perl#perl#GetExecutable',
\ 'output_stream': 'both',
\ 'command': 'perl -X -c -Mwarnings -Ilib',
\ 'command_callback': 'ale_linters#perl#perl#GetCommand',
\ 'callback': 'ale_linters#perl#perl#Handle',
\})

View File

@@ -21,11 +21,9 @@ function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor

View File

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

View File

@@ -4,8 +4,9 @@
function! ale_linters#php#php#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" Parse error: parse error in - on line 7
let l:pattern = 'Parse error:\s\+\(.\+\) on line \(\d\+\)'
" PHP Parse error: syntax error, unexpected ';', expecting ']' in - on line 15
let l:pattern = '\vParse error:\s+(.+unexpected ''(.+)%(expecting.+)@<!''.*|.+) in - on line (\d+)'
let l:output = []
for l:line in a:lines
@@ -18,12 +19,10 @@ function! ale_linters#php#php#Handle(buffer, lines) abort
" vcol is needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': 1,
\ 'lnum': l:match[3] + 0,
\ 'col': empty(l:match[2]) ? 0 : stridx(getline(l:match[3]), l:match[2]) + 1,
\ 'text': l:match[1],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor

View File

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

39
ale_linters/php/phpmd.vim Normal file
View File

@@ -0,0 +1,39 @@
" Author: medains <https://github.com/medains>
" Description: phpmd for PHP files
" Set to change the ruleset
let g:ale_php_phpmd_ruleset = get(g:, 'ale_php_phpmd_ruleset', 'cleancode,codesize,controversial,design,naming,unusedcode')
function! ale_linters#php#phpmd#Handle(buffer, lines) abort
" Matches against lines like the following:
"
" /path/to/some-filename.php:18 message
let l:pattern = '^.*:\(\d\+\)\t\(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
" vcol is Needed to indicate that the column is a character.
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'col': 0,
\ 'text': l:match[2],
\ 'type': 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('php', {
\ 'name': 'phpmd',
\ 'executable': 'phpmd',
\ 'command': 'phpmd %s text ' . g:ale_php_phpmd_ruleset . ' --ignore-violations-on-exit %t',
\ 'callback': 'ale_linters#php#phpmd#Handle',
\})

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Pod files
call ale#linter#Define('pod', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

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

View File

@@ -18,11 +18,9 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[2] + 0,
\ 'vcol': 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[1],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor
@@ -33,6 +31,6 @@ call ale#linter#Define('puppet', {
\ 'name': 'puppet',
\ 'executable': 'puppet',
\ 'output_stream': 'stderr',
\ 'command': g:ale#util#stdin_wrapper . ' .pp puppet parser validate --color=false',
\ 'command': 'puppet parser validate --color=false %t',
\ 'callback': 'ale_linters#puppet#puppet#Handle',
\})

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for reStructuredText files
call ale#linter#Define('rst', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -23,11 +23,9 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': index(['C', 'E'], l:type) != -1 ? 'E' : 'W',
\ 'nr': -1,
\})
endfor

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,11 +57,9 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor

View File

@@ -0,0 +1,33 @@
" Author: Markus Doits - https://github.com/doits
" Description: slim-lint for Slim files, based on hamllint.vim
function! ale_linters#slim#slimlint#Handle(buffer, lines) abort
" Matches patterns like the following:
" <path>:5 [W] LineLength: Line is too long. [150/120]
let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'type': l:match[2],
\ 'text': l:match[3]
\})
endfor
return l:output
endfunction
call ale#linter#Define('slim', {
\ 'name': 'slimlint',
\ 'executable': 'slim-lint',
\ 'command': 'slim-lint %t',
\ 'callback': 'ale_linters#slim#slimlint#Handle'
\})

40
ale_linters/sml/smlnj.vim Normal file
View File

@@ -0,0 +1,40 @@
" Author: Paulo Alem <paulo.alem@gmail.com>
" Description: Rudimentary SML checking with smlnj compiler
if exists('g:loaded_ale_sml_smlnj_checker')
finish
endif
let g:loaded_ale_sml_smlnj_checker = 1
function! ale_linters#sml#smlnj#Handle(buffer, lines) abort
" Try to match basic sml errors
let l:out = []
let l:pattern = '^.*\:\([0-9\.]\+\)\ \(\w\+\)\:\ \(.*\)'
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:out, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'col': 1,
\ 'text': l:match[2] . ': ' . l:match[3],
\ 'type': l:match[2] ==# 'error' ? 'E' : 'W',
\})
endfor
return l:out
endfunction
call g:ale#linter#Define('sml', {
\ 'name': 'smlnj',
\ 'executable': 'sml',
\ 'command': 'sml',
\ 'callback': 'ale_linters#sml#smlnj#Handle',
\})

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Texinfo files
call ale#linter#Define('texinfo', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

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

View File

@@ -1,6 +1,20 @@
" Author: Prashanth Chandra https://github.com/prashcr
" Description: tslint for TypeScript files
let g:ale_typescript_tslint_executable =
\ get(g:, 'ale_typescript_tslint_executable', 'tslint')
let g:ale_typescript_tslint_config_path =
\ get(g:, 'ale_typescript_tslint_config_path', '')
function! ale_linters#typescript#tslint#GetExecutable(buffer) abort
return ale#util#ResolveLocalPath(
\ a:buffer,
\ 'node_modules/.bin/tslint',
\ g:ale_typescript_tslint_executable
\)
endfunction
function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
@@ -27,29 +41,34 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
return l:output
endfunction
function! ale_linters#typescript#tslint#BuildLintCommand(buffer_n) abort
let l:tsconfig_path = ale#util#FindNearestFile(a:buffer_n, 'tslint.json')
let l:tslint_options = empty(l:tsconfig_path) ? '' : '-c ' . l:tsconfig_path
function! ale_linters#typescript#tslint#BuildLintCommand(buffer) abort
let g:ale_typescript_tslint_config_path =
\ empty(g:ale_typescript_tslint_config_path) ?
\ ale#util#FindNearestFile(a:buffer, 'tslint.json')
\ : g:ale_typescript_tslint_config_path
let l:ext = '.' . fnamemodify(bufname(a:buffer_n), ':e')
let l:tslint_options =
\ empty(g:ale_typescript_tslint_config_path) ?
\ ''
\ : '-c ' . fnameescape(g:ale_typescript_tslint_config_path)
return g:ale#util#stdin_wrapper . ' ' . l:ext . ' tslint ' . l:tslint_options
return ale_linters#typescript#tslint#GetExecutable(a:buffer)
\ . ' ' . l:tslint_options
\ . ' %t'
endfunction
call ale#linter#Define('typescript', {
\ 'name': 'tslint',
\ 'executable': 'tslint',
\ 'executable_callback': 'ale_linters#typescript#tslint#GetExecutable',
\ 'command_callback': 'ale_linters#typescript#tslint#BuildLintCommand',
\ 'callback': 'ale_linters#typescript#tslint#Handle',
\})

View File

@@ -7,7 +7,7 @@ function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
" hello.ts[7, 41]: Property 'a' does not exist on type 'A'
" hello.ts[16, 7]: Type 'A' is not assignable to type 'B'
"
let l:pattern = '.\+.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
let l:pattern = '.\+\.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)'
let l:output = []
for l:line in a:lines
@@ -26,11 +26,9 @@ function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:column,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor

View File

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

View File

@@ -1,6 +1,16 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: verilator for verilog files
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = tempname() . '_verilator_linted.v'
" Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename)
call writefile(getbufline(a:buffer, 1, '$'), l:filename)
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' . fnameescape(l:filename)
endfunction
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
" Look for lines like the following.
"
@@ -25,16 +35,14 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
let l:text = l:match[4]
let l:file = l:match[2]
if(l:file =~# '_verilator_linted.v')
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': 1,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
if l:file =~# '_verilator_linted.v'
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'col': 1,
\ 'text': l:text,
\ 'type': l:type,
\})
endif
endfor
@@ -45,6 +53,7 @@ call ale#linter#Define('verilog', {
\ 'name': 'verilator',
\ 'output_stream': 'stderr',
\ 'executable': 'verilator',
\ 'command': g:ale#util#stdin_wrapper . ' _verilator_linted.v verilator --lint-only -Wall -Wno-DECLFILENAME',
\ 'command_callback': 'ale_linters#verilog#verilator#GetCommand',
\ 'callback': 'ale_linters#verilog#verilator#Handle',
\ 'read_buffer': 0,
\})

View File

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

View File

@@ -0,0 +1,9 @@
" Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for XHTML files
call ale#linter#Define('xhtml', {
\ 'name': 'proselint',
\ 'executable': 'proselint',
\ 'command': 'proselint %t',
\ 'callback': 'ale#handlers#HandleUnixFormatAsWarning',
\})

View File

@@ -1,5 +1,21 @@
" Author: KabbAmine <amine.kabb@gmail.com>
let g:ale_yaml_yamllint_executable =
\ get(g:, 'ale_yaml_yamllint_executable', 'yamllint')
let g:ale_yaml_yamllint_options =
\ get(g:, 'ale_yaml_yamllint_options', '')
function! ale_linters#yaml#yamllint#GetExecutable(buffer) abort
return g:ale_yaml_yamllint_executable
endfunction
function! ale_linters#yaml#yamllint#GetCommand(buffer) abort
return ale_linters#yaml#yamllint#GetExecutable(a:buffer)
\ . ' ' . g:ale_yaml_yamllint_options
\ . ' -f parsable %t'
endfunction
function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
" Matches patterns line the following:
" something.yaml:1:1: [warning] missing document start "---" (document-start)
@@ -23,11 +39,9 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:line,
\ 'vcol': 0,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:type ==# 'error' ? 'E' : 'W',
\ 'nr': -1,
\})
endfor
@@ -36,7 +50,7 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'yamllint',
\ 'executable': 'yamllint',
\ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable',
\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable',
\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand',
\ 'callback': 'ale_linters#yaml#yamllint#Handle',
\})

View File

@@ -3,13 +3,40 @@
" Manages execution of linters when requested by autocommands
let s:lint_timer = -1
let s:should_lint_file_for_buffer = {}
function! ale#Queue(delay) abort
" Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
" A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing() abort
" Do nothing for blacklisted files
" OR if ALE is running in the sandbox
return index(g:ale_filetype_blacklist, &filetype) >= 0
\ || ale#util#InSandbox()
endfunction
" (delay, [linting_flag])
function! ale#Queue(delay, ...) abort
if len(a:0) > 1
throw 'too many arguments!'
endif
" Default linting_flag to ''
let l:linting_flag = get(a:000, 0, '')
if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
throw "linting_flag must be either '' or 'lint_file'"
endif
if ale#ShouldDoNothing()
return
endif
" Remember that we want to check files for this buffer.
" We will remember this until we finally run the linters, via any event.
if l:linting_flag ==# 'lint_file'
let s:should_lint_file_for_buffer[bufnr('%')] = 1
endif
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
@@ -29,13 +56,19 @@ function! ale#Queue(delay) abort
endfunction
function! ale#Lint(...) abort
" Do nothing for blacklisted files.
if index(g:ale_filetype_blacklist, &filetype) >= 0
if ale#ShouldDoNothing()
return
endif
let l:buffer = bufnr('%')
let l:linters = ale#linter#Get(&filetype)
let l:should_lint_file = 0
" Check if we previously requested checking the file.
if has_key(s:should_lint_file_for_buffer, l:buffer)
unlet s:should_lint_file_for_buffer[l:buffer]
let l:should_lint_file = 1
endif
" Initialise the buffer information if needed.
call ale#engine#InitBufferInfo(l:buffer)
@@ -43,19 +76,22 @@ function! ale#Lint(...) abort
" Clear the new loclist again, so we will work with all new items.
let g:ale_buffer_info[l:buffer].new_loclist = []
if l:should_lint_file
" Clear loclist items for files if we are checking files again.
let g:ale_buffer_info[l:buffer].lint_file_loclist = []
else
" Otherwise, don't run any `lint_file` linters
" We will continue running any linters which are currently checking
" the file, and the items will be mixed together with any new items.
call filter(l:linters, '!v:val.lint_file')
endif
for l:linter in l:linters
" Check if a given linter has a program which can be executed.
if has_key(l:linter, 'executable_callback')
let l:executable = ale#util#GetFunction(l:linter.executable_callback)(l:buffer)
else
let l:executable = l:linter.executable
endif
if !executable(l:executable)
" The linter's program cannot be executed, so skip it.
continue
endif
call ale#engine#Invoke(l:buffer, l:linter)
endfor
endfunction
" Reset flags indicating that files should be checked for all buffers.
function! ale#ResetLintFileMarkers() abort
let s:should_lint_file_for_buffer = {}
endfunction

View File

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

View File

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

142
autoload/ale/debugging.vim Normal file
View File

@@ -0,0 +1,142 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file implements debugging information for ALE
let s:global_variable_list = [
\ 'ale_echo_cursor',
\ 'ale_echo_msg_error_str',
\ 'ale_echo_msg_format',
\ 'ale_echo_msg_warning_str',
\ 'ale_enabled',
\ 'ale_keep_list_window_open',
\ 'ale_lint_delay',
\ 'ale_lint_on_enter',
\ 'ale_lint_on_save',
\ 'ale_lint_on_text_changed',
\ 'ale_linter_aliases',
\ 'ale_linters',
\ 'ale_open_list',
\ 'ale_set_highlights',
\ 'ale_set_loclist',
\ 'ale_set_quickfix',
\ 'ale_set_signs',
\ 'ale_sign_column_always',
\ 'ale_sign_error',
\ 'ale_sign_offset',
\ 'ale_sign_warning',
\ 'ale_statusline_format',
\ 'ale_warn_about_trailing_whitespace',
\]
function! s:GetLinterVariables(filetype, linter_names) abort
let l:variable_list = []
let l:filetype_parts = split(a:filetype, '\.')
for l:key in keys(g:)
" Extract variable names like: 'ale_python_flake8_executable'
let l:match = matchlist(l:key, '\v^ale_([^_]+)_([^_]+)_.+$')
" Include matching variables.
if !empty(l:match)
\&& index(l:filetype_parts, l:match[1]) >= 0
\&& index(a:linter_names, l:match[2]) >= 0
call add(l:variable_list, l:key)
endif
endfor
call sort(l:variable_list)
return l:variable_list
endfunction
function! s:EchoLinterVariables(variable_list) abort
for l:key in a:variable_list
echom 'let g:' . l:key . ' = ' . string(g:[l:key])
endfor
endfunction
function! s:EchoGlobalVariables() abort
for l:key in s:global_variable_list
echom 'let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))
endfor
endfunction
function! s:EchoCommandHistory() abort
let l:buffer = bufnr('%')
if !has_key(g:ale_buffer_info, l:buffer)
return
endif
for l:item in g:ale_buffer_info[l:buffer].history
let l:status_message = l:item.status
" Include the exit code in output if we have it.
if l:item.status ==# 'finished'
let l:status_message .= ' - exit code ' . l:item.exit_code
endif
echom '(' . l:status_message . ') ' . string(l:item.command)
if g:ale_history_log_output && has_key(l:item, 'output')
if empty(l:item.output)
echom ''
echom '<<<NO OUTPUT RETURNED>>>'
echom ''
else
echom ''
echom '<<<OUTPUT STARTS>>>'
for l:line in l:item.output
echom l:line
endfor
echom '<<<OUTPUT ENDS>>>'
echom ''
endif
endif
endfor
endfunction
function! ale#debugging#Info() abort
let l:filetype = &filetype
" We get the list of enabled linters for free by the above function.
let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype))
" But have to build the list of available linters ourselves.
let l:all_linters = []
let l:linter_variable_list = []
for l:part in split(l:filetype, '\.')
let l:aliased_filetype = ale#linter#ResolveFiletype(l:part)
call extend(l:all_linters, ale#linter#GetAll(l:aliased_filetype))
endfor
let l:all_names = map(l:all_linters, 'v:val[''name'']')
let l:enabled_names = map(l:enabled_linters, 'v:val[''name'']')
" Load linter variables to display
" This must be done after linters are loaded.
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
echom ' Current Filetype: ' . l:filetype
echom 'Available Linters: ' . string(l:all_names)
echom ' Enabled Linters: ' . string(l:enabled_names)
echom ' Linter Variables:'
echom ''
call s:EchoLinterVariables(l:variable_list)
echom ' Global Variables:'
echom ''
call s:EchoGlobalVariables()
echom ' Command History:'
echom ''
call s:EchoCommandHistory()
endfunction
function! ale#debugging#InfoToClipboard() abort
redir @+>
silent call ale#debugging#Info()
redir END
echom 'ALEInfo copied to your clipboard'
endfunction

View File

@@ -9,33 +9,53 @@
" output: The array of lines for the output of the job.
let s:job_info_map = {}
function! ale#engine#ParseVim8ProcessID(job_string) abort
return matchstr(a:job_string, '\d\+') + 0
endfunction
function! s:GetJobID(job) abort
if has('nvim')
"In NeoVim, job values are just IDs.
return a:job
endif
" In Vim 8, the job is a special variable, and we open a channel for each
" job. We'll use the ID of the channel instead as the job ID.
return ch_info(job_getchannel(a:job)).id
" For Vim 8, the job is a different variable type, and we can parse the
" process ID from the string.
return ale#engine#ParseVim8ProcessID(string(a:job))
endfunction
function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" job_list will hold the list of jobs
" loclist holds the loclist items after all jobs have completed.
" lint_file_loclist holds items from the last run including linters
" which use the lint_file option.
" new_loclist holds loclist items while jobs are being run.
" temporary_file_list holds temporary files to be cleaned up
" temporary_directory_list holds temporary directories to be cleaned up
" history holds a list of previously run commands for this buffer
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'loclist': [],
\ 'lint_file_loclist': [],
\ 'new_loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
\ 'history': [],
\}
endif
endfunction
" A map from timer IDs to Vim 8 jobs, for tracking jobs that need to be killed
" with SIGKILL if they don't terminate right away.
let s:job_kill_timers = {}
function! s:KillHandler(timer) abort
call job_stop(remove(s:job_kill_timers, a:timer), 'kill')
endfunction
function! ale#engine#ClearJob(job) abort
let l:job_id = s:GetJobID(a:job)
let l:linter = s:job_info_map[l:job_id].linter
if has('nvim')
call jobstop(a:job)
@@ -46,10 +66,19 @@ function! ale#engine#ClearJob(job) abort
call ch_close_in(job_getchannel(a:job))
endif
" Ask nicely for the job to stop.
call job_stop(a:job)
" If a job doesn't stop immediately, queue a timer which will
" send SIGKILL to the job, if it's alive by the time the timer ticks.
if job_status(a:job) ==# 'run'
let s:job_kill_timers[timer_start(100, function('s:KillHandler'))] = a:job
endif
endif
call remove(s:job_info_map, l:job_id)
if has_key(s:job_info_map, l:job_id)
call remove(s:job_info_map, l:job_id)
endif
endfunction
function! s:StopPreviousJobs(buffer, linter) abort
@@ -112,6 +141,46 @@ function! ale#engine#JoinNeovimOutput(output, data) abort
endif
endfunction
" Register a temporary file to be managed with the ALE engine for
" a current job run.
function! ale#engine#ManageFile(buffer, filename) abort
call add(g:ale_buffer_info[a:buffer].temporary_file_list, a:filename)
endfunction
" Same as the above, but manage an entire directory.
function! ale#engine#ManageDirectory(buffer, directory) abort
call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory)
endfunction
function! ale#engine#RemoveManagedFiles(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
return
endif
" We can't delete anything in a sandbox, so wait until we escape from
" it to delete temporary files and directories.
if ale#util#InSandbox()
return
endif
" Delete files with a call akin to a plan `rm` command.
for l:filename in g:ale_buffer_info[a:buffer].temporary_file_list
call delete(l:filename)
endfor
let g:ale_buffer_info[a:buffer].temporary_file_list = []
" Delete directories like `rm -rf`.
" Directories are handled differently from files, so paths that are
" intended to be single files can be set up for automatic deletion without
" accidentally deleting entire directories.
for l:directory in g:ale_buffer_info[a:buffer].temporary_directory_list
call delete(l:directory, 'rf')
endfor
let g:ale_buffer_info[a:buffer].temporary_directory_list = []
endfunction
function! s:HandleExit(job) abort
if a:job ==# 'no process'
" Stop right away when the job is not valid in Vim 8.
@@ -134,59 +203,110 @@ function! s:HandleExit(job) abort
" which just closed.
call s:StopPreviousJobs(l:buffer, l:linter)
" Stop here if we land in the handle for a job completing if we're in
" a sandbox.
if ale#util#InSandbox()
return
endif
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
return
endif
" Log the output of the command for ALEInfo if we should.
if g:ale_history_enabled && g:ale_history_log_output
call ale#history#RememberOutput(l:buffer, l:job_id, l:output[:])
endif
let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
" Make some adjustments to the loclists to fix common problems.
call s:FixLocList(l:buffer, l:linter_loclist)
for l:item in l:linter_loclist
let l:item.linter_name = l:linter.name
endfor
" Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items.
let l:linter_loclist = ale#engine#FixLocList(l:buffer, l:linter, l:linter_loclist)
" Add the loclist items from the linter.
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
" loclist items for files which are checked go into a different list,
" and are kept between runs.
if l:linter.lint_file
call extend(g:ale_buffer_info[l:buffer].lint_file_loclist, l:linter_loclist)
else
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
endif
if !empty(g:ale_buffer_info[l:buffer].job_list)
" Wait for all jobs to complete before doing anything else.
return
endif
" Automatically remove all managed temporary files and directories
" now that all jobs have completed.
call ale#engine#RemoveManagedFiles(l:buffer)
" Combine the lint_file List and the List for everything else.
let l:combined_list = g:ale_buffer_info[l:buffer].lint_file_loclist
\ + g:ale_buffer_info[l:buffer].new_loclist
" Sort the loclist again.
" We need a sorted list so we can run a binary search against it
" for efficient lookup of the messages in the cursor handler.
call sort(g:ale_buffer_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
call sort(l:combined_list, 'ale#util#LocItemCompare')
" Now swap the old and new loclists, after we have collected everything
" and sorted the list again.
let g:ale_buffer_info[l:buffer].loclist = g:ale_buffer_info[l:buffer].new_loclist
let g:ale_buffer_info[l:buffer].loclist = l:combined_list
let g:ale_buffer_info[l:buffer].new_loclist = []
if g:ale_set_quickfix || g:ale_set_loclist
call ale#list#SetLists(g:ale_buffer_info[l:buffer].loclist)
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist)
" Call user autocommands. This allows users to hook into ALE's lint cycle.
silent doautocmd User ALELint
endfunction
function! ale#engine#SetResults(buffer, loclist) abort
" Set signs first. This could potentially fix some line numbers.
" The List could be sorted again here by SetSigns.
if g:ale_set_signs
call ale#sign#SetSigns(a:buffer, a:loclist)
endif
if g:ale_set_signs
call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
if g:ale_set_quickfix || g:ale_set_loclist
call ale#list#SetLists(a:buffer, a:loclist)
endif
if exists('*ale#statusline#Update')
" Don't load/run if not already loaded.
call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
call ale#statusline#Update(a:buffer, a:loclist)
endif
" Call user autocommands. This allows users to hook into ALE's lint cycle.
silent doautocmd User ALELint
if g:ale_set_highlights
call ale#highlight#SetHighlights(a:buffer, a:loclist)
endif
" Mark line 200, column 17 with a squiggly line or something
" matchadd('ALEError', '\%200l\%17v')
if g:ale_echo_cursor
" Try and echo the warning now.
" This will only do something meaningful if we're in normal mode.
call ale#cursor#EchoCursorWarning()
endif
endfunction
function! s:HandleExitNeoVim(job, data, event) abort
function! s:SetExitCode(job, exit_code) abort
let l:job_id = s:GetJobID(a:job)
if !has_key(s:job_info_map, l:job_id)
return
endif
let l:buffer = s:job_info_map[l:job_id].buffer
call ale#history#SetExitCode(l:buffer, l:job_id, a:exit_code)
endfunction
function! s:HandleExitNeoVim(job, exit_code, event) abort
if g:ale_history_enabled
call s:SetExitCode(a:job, a:exit_code)
endif
call s:HandleExit(a:job)
endfunction
@@ -194,34 +314,154 @@ function! s:HandleExitVim(channel) abort
call s:HandleExit(ch_getjob(a:channel))
endfunction
function! s:FixLocList(buffer, loclist) abort
" Vim returns the exit status with one callback,
" and the channel will close later in another callback.
function! s:HandleExitStatusVim(job, exit_code) abort
call s:SetExitCode(a:job, a:exit_code)
endfunction
function! ale#engine#FixLocList(buffer, linter, loclist) abort
let l:new_loclist = []
" Some errors have line numbers beyond the end of the file,
" so we need to adjust them so they set the error at the last line
" of the file instead.
let l:last_line_number = ale#util#GetLineCount(a:buffer)
for l:item in a:loclist
for l:old_item in a:loclist
" Copy the loclist item with some default values and corrections.
"
" line and column numbers will be converted to numbers.
" The buffer will default to the buffer being checked.
" The vcol setting will default to 0, a byte index.
" The error type will default to 'E' for errors.
" The error number will default to -1.
"
" The line number and text are the only required keys.
"
" The linter_name will be set on the errors so it can be used in
" output, filtering, etc..
let l:item = {
\ 'text': l:old_item.text,
\ 'lnum': str2nr(l:old_item.lnum),
\ 'col': str2nr(get(l:old_item, 'col', 0)),
\ 'bufnr': get(l:old_item, 'bufnr', a:buffer),
\ 'vcol': get(l:old_item, 'vcol', 0),
\ 'type': get(l:old_item, 'type', 'E'),
\ 'nr': get(l:old_item, 'nr', -1),
\ 'linter_name': a:linter.name,
\}
if has_key(l:old_item, 'detail')
let l:item.detail = l:old_item.detail
endif
if l:item.lnum == 0
" When errors appear at line 0, put them at line 1 instead.
let l:item.lnum = 1
elseif l:item.lnum > l:last_line_number
" When errors go beyond the end of the file, put them at the end.
let l:item.lnum = l:last_line_number
endif
call add(l:new_loclist, l:item)
endfor
return l:new_loclist
endfunction
function! s:RunJob(command, generic_job_options) abort
let l:buffer = a:generic_job_options.buffer
let l:linter = a:generic_job_options.linter
let l:output_stream = a:generic_job_options.output_stream
let l:next_chain_index = a:generic_job_options.next_chain_index
let l:read_buffer = a:generic_job_options.read_buffer
" Given part of a command, replace any % with %%, so that no characters in
" the string will be replaced with filenames, etc.
function! ale#engine#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g')
endfunction
function! s:TemporaryFilename(buffer) abort
let l:filename = fnamemodify(bufname(a:buffer), ':t')
if empty(l:filename)
" If the buffer's filename is empty, create a dummy filename.
let l:ft = getbufvar(a:buffer, '&filetype')
let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft)
endif
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
return tempname() . (has('win32') ? '\' : '/') . l:filename
endfunction
" Given a command string, replace every...
" %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory
" %% -> with a literal %
function! ale#engine#FormatCommand(buffer, command) abort
let l:temporary_file = ''
let l:command = a:command
" First replace all uses of %%, used for literal percent characters,
" with an ugly string.
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
" Replace all %s occurences in the string with the name of the current
" file.
if l:command =~# '%s'
" If there is a '%s' in the command string, replace it with the name
" of the file.
let l:command = printf(l:command, shellescape(fnamemodify(bufname(l:buffer), ':p')))
let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute(l:command, '%s', '\=fnameescape(l:filename)', 'g')
endif
if l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
let l:temporary_file = s:TemporaryFilename(a:buffer)
let l:command = substitute(l:command, '%t', '\=fnameescape(l:temporary_file)', 'g')
endif
" Finish formatting so %% becomes %.
let l:command = substitute(l:command, '<<PERCENTS>>', '%', 'g')
return [l:temporary_file, l:command]
endfunction
function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort
if empty(a:temporary_file)
" There is no file, so we didn't create anything.
return 0
endif
let l:temporary_directory = fnamemodify(a:temporary_file, ':h')
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:temporary_directory, '', 0750)
" Automatically delete the directory later.
call ale#engine#ManageDirectory(a:buffer, l:temporary_directory)
" Write the buffer out to a file.
call writefile(getbufline(a:buffer, 1, '$'), a:temporary_file)
return 1
endfunction
function! s:RunJob(options) abort
let l:command = a:options.command
let l:buffer = a:options.buffer
let l:linter = a:options.linter
let l:output_stream = a:options.output_stream
let l:next_chain_index = a:options.next_chain_index
let l:read_buffer = a:options.read_buffer
let [l:temporary_file, l:command] = ale#engine#FormatCommand(l:buffer, l:command)
if l:read_buffer && empty(l:temporary_file)
" If we are to send the Vim buffer to a command, we'll do it
" in the shell. We'll write out the file to a temporary file,
" and then read it back in, in the shell.
let l:temporary_file = s:TemporaryFilename(l:buffer)
let l:command = l:command . ' < ' . fnameescape(l:temporary_file)
endif
if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file)
" If a temporary filename has been formatted in to the command, then
" we do not need to send the Vim buffer to the command.
let l:read_buffer = 0
endif
if has('nvim')
@@ -251,6 +491,12 @@ function! s:RunJob(command, generic_job_options) abort
\ 'close_cb': function('s:HandleExitVim'),
\}
if g:ale_history_enabled
" We only need to capture the exit status if we are going to
" save it in the history. Otherwise, we don't care.
let l:job_options.exit_cb = function('s:HandleExitStatusVim')
endif
if l:output_stream ==# 'stderr'
" Read from stderr instead of stdout.
let l:job_options.err_cb = function('s:GatherOutputVim')
@@ -262,63 +508,50 @@ function! s:RunJob(command, generic_job_options) abort
let l:job_options.out_cb = function('s:GatherOutputVim')
endif
if has('win32')
" job_start commands on Windows have to be run with cmd /c,
" othwerwise %PATHTEXT% will not be used to programs ending int
" .cmd, .bat, .exe, etc.
let l:command = 'cmd /c ' . l:command
else
" Execute the command with the shell, to fix escaping issues.
let l:command = split(&shell) + split(&shellcmdflag) + [l:command]
if l:read_buffer
" On Unix machines, we can send the Vim buffer directly.
" This is faster than reading the lines ourselves.
let l:job_options.in_io = 'buffer'
let l:job_options.in_buf = l:buffer
endif
endif
" The command will be executed in a subshell. This fixes a number of
" issues, including reading the PATH variables correctly, %PATHEXT%
" expansion on Windows, etc.
"
" NeoVim handles this issue automatically if the command is a String.
let l:command = has('win32')
\ ? 'cmd /c ' . l:command
\ : split(&shell) + split(&shellcmdflag) + [l:command]
" Vim 8 will read the stdin from the file's buffer.
let l:job = job_start(l:command, l:job_options)
endif
let l:status = 'failed'
let l:job_id = 0
" Only proceed if the job is being run.
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run')
" Add the job to the list of jobs, so we can track them.
call add(g:ale_buffer_info[l:buffer].job_list, l:job)
let l:status = 'started'
let l:job_id = s:GetJobID(l:job)
" Store the ID for the job in the map to read back again.
let s:job_info_map[s:GetJobID(l:job)] = {
let s:job_info_map[l:job_id] = {
\ 'linter': l:linter,
\ 'buffer': l:buffer,
\ 'output': [],
\ 'next_chain_index': l:next_chain_index,
\}
endif
if l:read_buffer
if has('nvim')
" In NeoVim, we have to send the buffer lines ourselves.
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
call jobsend(l:job, l:input)
call jobclose(l:job, 'stdin')
elseif has('win32')
" On some Vim versions, we have to send the buffer data ourselves.
let l:input = join(getbufline(l:buffer, 1, '$'), "\n") . "\n"
let l:channel = job_getchannel(l:job)
if ch_status(l:channel) ==# 'open'
call ch_sendraw(l:channel, l:input)
call ch_close_in(l:channel)
endif
endif
endif
if g:ale_history_enabled
call ale#history#Add(l:buffer, l:status, l:job_id, l:command)
else
let g:ale_buffer_info[l:buffer].history = []
endif
endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort
" Determine which commands to run for a link in a command chain, or
" just a regular command.
function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
let l:read_buffer = a:linter.read_buffer
let l:chain_index = a:chain_index
let l:input = a:input
@@ -328,11 +561,6 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
" so that many programs can be run in a sequence.
let l:chain_item = a:linter.command_chain[l:chain_index]
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
endif
if l:chain_index == 0
" The first callback in the chain takes only a buffer number.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
@@ -348,6 +576,21 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
if !empty(l:command)
" We hit a command to run, so we'll execute that
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
endif
" The chain item can override the read_buffer option.
if has_key(l:chain_item, 'read_buffer')
let l:read_buffer = l:chain_item.read_buffer
elseif l:chain_index != len(a:linter.command_chain) - 1
" Don't read the buffer for commands besides the last one
" in the chain by default.
let l:read_buffer = 0
endif
break
endif
@@ -357,11 +600,6 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
let l:input = []
let l:chain_index += 1
endwhile
if empty(l:command)
" Don't run any jobs if the last command is an empty string.
return
endif
elseif has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead.
let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
@@ -369,21 +607,45 @@ function! s:InvokeChain(buffer, linter, chain_index, input) abort
let l:command = a:linter.command
endif
let l:is_last_job = l:chain_index >= len(get(a:linter, 'command_chain', [])) - 1
if empty(l:command)
" Don't run any jobs if the command is an empty string.
return {}
endif
call s:RunJob(l:command, {
return {
\ 'command': l:command,
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': l:output_stream,
\ 'next_chain_index': l:chain_index + 1,
\ 'read_buffer': l:is_last_job,
\})
\ 'read_buffer': l:read_buffer,
\}
endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
if !empty(l:options)
call s:RunJob(l:options)
elseif empty(g:ale_buffer_info[a:buffer].job_list)
" If we cancelled running a command, and we have no jobs in progress,
" then delete the managed temporary files now.
call ale#engine#RemoveManagedFiles(a:buffer)
endif
endfunction
function! ale#engine#Invoke(buffer, linter) abort
" Stop previous jobs for the same linter.
call s:StopPreviousJobs(a:buffer, a:linter)
call s:InvokeChain(a:buffer, a:linter, 0, [])
let l:executable = has_key(a:linter, 'executable_callback')
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
\ : a:linter.executable
" Run this program if it can be executed.
if executable(l:executable)
call s:InvokeChain(a:buffer, a:linter, 0, [])
endif
endfunction
" Given a buffer number, return the warnings and errors for a given buffer.
@@ -402,7 +664,7 @@ endfunction
" The time taken will be a very rough approximation, and more time may be
" permitted than is specified.
function! ale#engine#WaitForJobs(deadline) abort
let l:start_time = system('date +%s%3N') + 0
let l:start_time = ale#util#ClockMilliseconds()
if l:start_time == 0
throw 'Failed to read milliseconds from the clock!'
@@ -422,7 +684,7 @@ function! ale#engine#WaitForJobs(deadline) abort
for l:job in l:job_list
if job_status(l:job) ==# 'run'
let l:now = system('date +%s%3N') + 0
let l:now = ale#util#ClockMilliseconds()
if l:now - l:start_time > a:deadline
" Stop waiting after a timeout, so we don't wait forever.
@@ -447,15 +709,19 @@ function! ale#engine#WaitForJobs(deadline) abort
" for command_chain linters.
let l:has_new_jobs = 0
" Check again to see if any jobs are running.
for l:info in values(g:ale_buffer_info)
if !empty(l:info.job_list)
let l:has_new_jobs = 1
endif
for l:job in l:info.job_list
if job_status(l:job) ==# 'run'
let l:has_new_jobs = 1
break
endif
endfor
endfor
if l:has_new_jobs
" We have to wait more. Offset the timeout by the time taken so far.
let l:now = system('date +%s%3N') + 0
let l:now = ale#util#ClockMilliseconds()
let l:new_deadline = a:deadline - (l:now - l:start_time)
if l:new_deadline <= 0

View File

@@ -0,0 +1,60 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file handles guessing file extensions for filetypes, etc.
function! ale#filetypes#LoadExtensionMap() abort
" Output includes:
" '*.erl setf erlang'
redir => l:output
silent exec 'autocmd'
redir end
let l:map = {}
for l:line in split(l:output, "\n")
" Parse filetypes, like so:
"
" *.erl setf erlang
" *.md set filetype=markdown
" *.snippet setlocal filetype=snippets
let l:match = matchlist(l:line, '\v^ *\*(\.[^ ]+).*set(f *| *filetype=|local *filetype=)([^ ]+)')
if !empty(l:match)
let l:map[substitute(l:match[3], '^=', '', '')] = l:match[1]
endif
endfor
return l:map
endfunction
let s:cached_map = {}
function! s:GetCachedExtensionMap() abort
if empty(s:cached_map)
let s:cached_map = ale#filetypes#LoadExtensionMap()
endif
return s:cached_map
endfunction
function! ale#filetypes#GuessExtension(filetype) abort
let l:map = s:GetCachedExtensionMap()
let l:ext = get(l:map, a:filetype, '')
" If we have an exact match, like something for javascript.jsx, use that.
if !empty(l:ext)
return l:ext
endif
" If we don't have an exact match, use the first filetype in the compound
" filetype.
for l:part in split(a:filetype, '\.')
let l:ext = get(l:map, l:part, '')
if !empty(l:ext)
return l:ext
endif
endfor
" Return an empty string if we don't find anything.
return ''
endfunction

View File

@@ -12,7 +12,7 @@ function! s:HandleUnixFormat(buffer, lines, type) abort
" file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args
" file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
" file.go:5:2: expected declaration, found 'STRING' "log"
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?: \(.\+\)$'
let l:pattern = '^' . s:path_pattern . ':\(\d\+\):\?\(\d\+\)\?:\? \(.\+\)$'
let l:output = []
for l:line in a:lines
@@ -220,3 +220,58 @@ function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
return l:output
endfunction
function! ale#handlers#HandleGhcFormat(buffer, lines) abort
" Look for lines like the following.
"
"Appoint/Lib.hs:8:1: warning:
"Appoint/Lib.hs:8:1:
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\):\(.*\)\?$'
let l:output = []
let l:corrected_lines = []
for l:line in a:lines
if len(matchlist(l:line, l:pattern)) > 0
call add(l:corrected_lines, l:line)
elseif l:line ==# ''
call add(l:corrected_lines, l:line)
else
if len(l:corrected_lines) > 0
let l:line = substitute(l:line, '\v^\s+', ' ', '')
let l:corrected_lines[-1] .= l:line
endif
endif
endfor
for l:line in l:corrected_lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
let l:errors = matchlist(l:match[3], '\(warning:\|error:\)\(.*\)')
if len(l:errors) > 0
let l:type = l:errors[1]
let l:text = l:errors[2]
else
let l:type = ''
let l:text = l:match[3]
endif
let l:type = l:type ==# '' ? 'E' : toupper(l:type[0])
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type,
\ 'nr': -1,
\})
endfor
return l:output
endfunction

102
autoload/ale/highlight.vim Normal file
View File

@@ -0,0 +1,102 @@
scriptencoding utf8
" Author: w0rp <devw0rp@gmail.com>
" Description: This module implements error/warning highlighting.
if !hlexists('ALEError')
highlight link ALEError SpellBad
endif
if !hlexists('ALEWarning')
highlight link ALEWarning SpellCap
endif
" This map holds highlights to be set when buffers are opened.
" We can only set highlights for whatever the current buffer is, so we will
" wait until the buffer is entered again to show the highlights, unless
" the buffer is in focus when linting completes.
let s:buffer_highlights = {}
function! ale#highlight#UnqueueHighlights(buffer) abort
if has_key(s:buffer_highlights, a:buffer)
call remove(s:buffer_highlights, a:buffer)
endif
endfunction
function! s:GetALEMatches() abort
let l:list = []
for l:match in getmatches()
if l:match['group'] ==# 'ALEError' || l:match['group'] ==# 'ALEWarning'
call add(l:list, l:match)
endif
endfor
return l:list
endfunction
function! s:GetCurrentMatchIDs(loclist) abort
let l:current_id_map = {}
for l:item in a:loclist
if has_key(l:item, 'match_id')
let l:current_id_map[l:item.match_id] = 1
endif
endfor
return l:current_id_map
endfunction
function! ale#highlight#UpdateHighlights() abort
let l:buffer = bufnr('%')
let l:has_new_items = has_key(s:buffer_highlights, l:buffer)
let l:loclist = l:has_new_items ? remove(s:buffer_highlights, l:buffer) : []
let l:current_id_map = s:GetCurrentMatchIDs(l:loclist)
if l:has_new_items || !g:ale_enabled
for l:match in s:GetALEMatches()
if !has_key(l:current_id_map, l:match.id)
call matchdelete(l:match.id)
endif
endfor
endif
" Remove anything with a current match_id
call filter(l:loclist, '!has_key(v:val, ''match_id'')')
if l:has_new_items
for l:item in l:loclist
let l:col = l:item.col
let l:group = l:item.type ==# 'E' ? 'ALEError' : 'ALEWarning'
let l:line = l:item.lnum
let l:size = 1
" Rememeber the match ID for the item.
" This ID will be used to preserve loclist items which are set
" many times.
let l:item.match_id = matchaddpos(l:group, [[l:line, l:col, l:size]])
endfor
endif
endfunction
augroup ALEHighlightBufferGroup
autocmd!
autocmd BufEnter * call ale#highlight#UpdateHighlights()
augroup END
function! ale#highlight#SetHighlights(buffer, loclist) abort
" Only set set items for the buffer if ALE is enabled.
if g:ale_enabled
" Set a list of items to be set as highlights for a buffer when
" we next open it.
"
" We'll filter the loclist down to items we can set now.
let s:buffer_highlights[a:buffer] = filter(
\ copy(a:loclist),
\ 'v:val.bufnr == a:buffer && v:val.col > 0'
\)
" Update highlights for the current buffer, which may or may not
" be the buffer we just set highlights for.
call ale#highlight#UpdateHighlights()
endif
endfunction

58
autoload/ale/history.vim Normal file
View File

@@ -0,0 +1,58 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Tools for managing command history
"
function! ale#history#Add(buffer, status, job_id, command) abort
if g:ale_max_buffer_history_size <= 0
" Don't save anything if the history isn't a positive number.
let g:ale_buffer_info[a:buffer].history = []
return
endif
let l:history = g:ale_buffer_info[a:buffer].history
" Remove the first item if we hit the max history size.
if len(l:history) >= g:ale_max_buffer_history_size
let l:history = l:history[1:]
endif
call add(l:history, {
\ 'status': a:status,
\ 'job_id': a:job_id,
\ 'command': a:command,
\})
let g:ale_buffer_info[a:buffer].history = l:history
endfunction
function! s:FindHistoryItem(buffer, job_id) abort
" Search backwards to find a matching job ID. IDs might be recycled,
" so finding the last one should be good enough.
for l:obj in reverse(g:ale_buffer_info[a:buffer].history[:])
if l:obj.job_id == a:job_id
return l:obj
endif
endfor
return {}
endfunction
" Set an exit code for a command which finished.
function! ale#history#SetExitCode(buffer, job_id, exit_code) abort
let l:obj = s:FindHistoryItem(a:buffer, a:job_id)
if !empty(l:obj)
" If we find a match, then set the code and status.
let l:obj.exit_code = a:exit_code
let l:obj.status = 'finished'
endif
endfunction
" Set the output for a command which finished.
function! ale#history#RememberOutput(buffer, job_id, output) abort
let l:obj = s:FindHistoryItem(a:buffer, a:job_id)
if !empty(l:obj)
let l:obj.output = a:output
endif
endfunction

View File

@@ -18,10 +18,14 @@ let s:default_ale_linter_aliases = {
" The user defined linter selections will be merged with this Dictionary.
"
" No linters are used for plaintext files by default.
"
" Only cargo is enabled for Rust by default.
let s:default_ale_linters = {
\ 'zsh': ['shell'],
\ 'csh': ['shell'],
\ 'help': [],
\ 'rust': ['cargo'],
\ 'text': [],
\ 'zsh': ['shell'],
\}
" Testing/debugging helper to unload all linters.
@@ -33,6 +37,10 @@ function! s:IsCallback(value) abort
return type(a:value) == type('') || type(a:value) == type(function('type'))
endfunction
function! s:IsBoolean(value) abort
return type(a:value) == type(0) && (a:value == 0 || a:value == 1)
endfunction
function! ale#linter#PreProcess(linter) abort
if type(a:linter) != type({})
throw 'The linter object must be a Dictionary'
@@ -95,6 +103,10 @@ function! ale#linter#PreProcess(linter) abort
endif
endif
if has_key(l:link, 'read_buffer') && !s:IsBoolean(l:link.read_buffer)
throw l:err_prefix . 'value for `read_buffer` must be `0` or `1`'
endif
let l:link_index += 1
endfor
elseif has_key(a:linter, 'command_callback')
@@ -114,6 +126,15 @@ function! ale#linter#PreProcess(linter) abort
\ . 'must be defined'
endif
if (
\ has_key(a:linter, 'command')
\ + has_key(a:linter, 'command_chain')
\ + has_key(a:linter, 'command_callback')
\) > 1
throw 'Only one of `command`, `command_callback`, or `command_chain` '
\ . 'should be set'
endif
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
if type(l:obj.output_stream) != type('')
@@ -121,6 +142,25 @@ function! ale#linter#PreProcess(linter) abort
throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
endif
" An option indicating that this linter should only be run against the
" file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0)
if !s:IsBoolean(l:obj.lint_file)
throw '`lint_file` must be `0` or `1`'
endif
" An option indicating that the buffer should be read.
let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file)
if !s:IsBoolean(l:obj.read_buffer)
throw '`read_buffer` must be `0` or `1`'
endif
if l:obj.lint_file && l:obj.read_buffer
throw 'Only one of `lint_file` or `read_buffer` can be `1`'
endif
return l:obj
endfunction
@@ -156,7 +196,7 @@ function! ale#linter#GetAll(filetype) abort
return s:linters[a:filetype]
endfunction
function! s:ResolveFiletype(original_filetype) abort
function! ale#linter#ResolveFiletype(original_filetype) abort
" Try and get an aliased file type either from the user's Dictionary, or
" our default Dictionary, otherwise use the filetype as-is.
let l:filetype = get(
@@ -177,7 +217,7 @@ function! ale#linter#Get(original_filetypes) abort
" Handle dot-seperated filetypes.
for l:original_filetype in split(a:original_filetypes, '\.')
let l:filetype = s:ResolveFiletype(l:original_filetype)
let l:filetype = ale#linter#ResolveFiletype(l:original_filetype)
" Try and get a list of linters to run, using the original file type,
" not the aliased filetype. We have some linters to limit by default,
@@ -211,25 +251,3 @@ function! ale#linter#Get(original_filetypes) abort
return l:combined_linters
endfunction
function! ale#linter#Info() abort
let l:original_filetypes = &filetype
" We get the list of enabled linters for free by the above function.
let l:enabled_linters = deepcopy(ale#linter#Get(l:original_filetypes))
" But have to build the list of available linters ourselves.
let l:all_linters = []
for l:original_filetype in split(l:original_filetypes, '\.')
let l:filetype = s:ResolveFiletype(l:original_filetype)
let l:filetype_linters = ale#linter#GetAll(l:filetype)
call extend(l:all_linters, l:filetype_linters)
endfor
let l:all_names = map(l:all_linters, 'v:val[''name'']')
let l:enabled_names = map(l:enabled_linters, 'v:val[''name'']')
echom ' Current Filetype: ' . l:original_filetypes
echom 'Available Linters: ' . string(l:all_names)
echom ' Enabled Linters: ' . string(l:enabled_names)
endfunction

View File

@@ -11,11 +11,20 @@ function! ale#list#IsQuickfixOpen() abort
return 0
endfunction
function! ale#list#SetLists(loclist) abort
function! ale#list#SetLists(buffer, loclist) abort
if g:ale_set_quickfix
call setqflist(a:loclist)
elseif g:ale_set_loclist
call setloclist(0, a:loclist)
" If windows support is off, bufwinid() may not exist.
if exists('*bufwinid')
" Set the results on the window for the buffer.
call setloclist(bufwinid(str2nr(a:buffer)), a:loclist)
else
" Set the results in the current window.
" This may not be the same window we ran the linters for, but
" it's better than nothing.
call setloclist(0, a:loclist)
endif
endif
" If we don't auto-open lists, bail out here.
@@ -27,10 +36,12 @@ function! ale#list#SetLists(loclist) abort
if len(a:loclist) > 0 || g:ale_keep_list_window_open
let l:winnr = winnr()
if g:ale_set_quickfix
copen
elseif g:ale_set_loclist
lopen
if !ale#list#IsQuickfixOpen()
if g:ale_set_quickfix
copen
elseif g:ale_set_loclist
lopen
endif
endif
" If focus changed, restore it (jump to the last window).

View File

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

View File

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

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