Compare commits

...

125 Commits

Author SHA1 Message Date
w0rp
2ee3dcdd62 Fix #1631 - Disable balloon support for terminals by default 2018-07-20 16:11:38 +01:00
w0rp
465db4daa1 Only temporarily replace TMPDIR if it's defined to be an empty string 2018-07-16 08:50:34 +01:00
w0rp
fb8c090971 unlet $TMPDIR too, where we can 2018-07-15 23:05:04 +01:00
w0rp
d29e32d42d Fix #1687 - Parse highlights when verbose > 0 2018-07-15 21:03:49 +01:00
w0rp
ab2b181012 Handle linter callback functions being unknown or deleted 2018-07-13 09:47:40 +01:00
w0rp
033a6c1178 Merge pull request #1720 from MTDL9/fix-error-response-string-data
Fix E712 error in ale#lsp#response#GetErrorMessage when receiving string primitives in the error.data field
2018-07-13 09:38:19 +01:00
w0rp
7d66293bbc Fix #1716 - Replace tempdir() with a wrapper to preserve TMPDIR 2018-07-12 13:06:11 +01:00
w0rp
1fc3a1563b Update the sandbox test now that functions can be defined in the sandbox 2018-07-11 13:38:22 +01:00
w0rp
a31f54d08f Fix how Docker images are pulled for developers 2018-07-04 09:36:55 +01:00
w0rp
db85b931ec Remove deprecated code for the 2.0 release 2018-07-04 08:36:34 +01:00
w0rp
602e7fa00f #1524 Avoid loading cursor code until engine code has been loaded 2018-07-03 21:14:00 +01:00
w0rp
e10e0934ab Automatically retry running Vader tests so Travis CI will fail less 2018-07-03 20:50:56 +01:00
w0rp
1d8b326f62 Revert "Add a failing test to test re-running tests in AppVeyor"
This reverts commit 1565859eae.
2018-07-03 19:59:40 +01:00
w0rp
1565859eae Add a failing test to test re-running tests in AppVeyor 2018-07-03 19:56:37 +01:00
w0rp
7ce919e690 Re-run Windows tests when they fail at least once 2018-07-03 19:53:40 +01:00
w0rp
25a03dcea1 Use the latest Docker image for tests 2018-07-03 19:21:58 +01:00
w0rp
73d3030cf1 Merge pull request #1691 from dsifford/dsifford-python-pyre
add pyre lsp linter to python linters
2018-07-03 08:31:01 +01:00
w0rp
4987946175 Enable verbose test output, to figure out why NeoVim 0.3 randomly fails 2018-07-03 01:52:18 +01:00
w0rp
e46474ac0a Close #830 - Implement LSP connections via TCP sockets 2018-07-03 01:41:46 +01:00
w0rp
5aba55bb86 #830 Make the LSP socket code so far use the new socket API 2018-07-03 00:30:26 +01:00
w0rp
01c68fedd6 #830 Implement a socket wrapper API for use with LSP connections 2018-07-02 23:49:47 +01:00
Derek P Sifford
20ed48352f add dummy pyre binary and executable 2018-07-02 18:49:12 -04:00
Derek P Sifford
09a53fb363 add command_callback test 2018-07-02 18:23:42 -04:00
w0rp
b637b35ea8 Delete misplaced issue template files 2018-07-01 20:51:34 +01:00
w0rp
ce7d648c7c Update issue templates 2018-07-01 20:50:50 +01:00
w0rp
8ac43b1936 Update issue templates 2018-07-01 20:50:29 +01:00
w0rp
1c5c4a4c8e Split the issue template into multiple files 2018-07-01 20:41:52 +01:00
w0rp
059c5cfca4 Fix a false positive linting issue 2018-07-01 20:37:32 +01:00
Derek P Sifford
23394bf4a5 add pyre to table in doc/ale.txt 2018-07-01 15:14:13 -04:00
Derek P Sifford
ea6d720fec add pyre lsp linter to python linters 2018-07-01 14:59:49 -04:00
w0rp
2a78401066 Close #1685 - Move developer documentation to a help file 2018-07-01 19:56:24 +01:00
w0rp
d456ac19ca Fix a typo in the documentation 2018-07-01 19:56:24 +01:00
Govind KP
9d98e6db0c Added dartfmt fixer (#1683)
* Added dartfmt to Fixers
* Added dartfmt specific documentation
2018-07-01 13:55:41 +01:00
w0rp
06f61eeeb8 Respect ale_warn_about_trailing_whitespace for yamllint 2018-07-01 13:49:40 +01:00
w0rp
e5e14de9ae Capture error codes for yamlllint 2018-07-01 13:15:12 +01:00
w0rp
fee5107d43 Add tests for the yamllint handler 2018-07-01 12:50:46 +01:00
w0rp
cd8dd099d8 Switch back to running everything in one build, which is twice as fast 2018-07-01 12:22:29 +01:00
w0rp
857a07f36a Try running tests in parallel again 2018-07-01 12:18:42 +01:00
w0rp
26aa0cf358 Try splitting up the build into separate jobs 2018-07-01 12:07:54 +01:00
w0rp
3c5b6d1825 Run Vint and custom checks together with just --linters-only 2018-07-01 12:06:59 +01:00
w0rp
ccfed164bc Revert "Try adding Docker caching for Travis CI"
This reverts commit 1990efdba7.
2018-07-01 11:55:07 +01:00
w0rp
1487c8daa0 Make highlight tests pass more in Neovim 0.3 2018-07-01 11:52:02 +01:00
w0rp
1990efdba7 Try adding Docker caching for Travis CI 2018-07-01 11:38:07 +01:00
w0rp
b88bf6ecba Fix #1412 - Use --stdin-filename for newer reek versions 2018-07-01 10:21:59 +01:00
w0rp
ee81351a63 Move design goals to online documentation 2018-06-28 16:20:30 +01:00
w0rp
0b7a29d73b Disable non-Vader tests when targeting Vader tests 2018-06-28 14:00:12 +01:00
w0rp
fc041ae090 Make a test which can fail randomly synchronous instead 2018-06-28 13:59:52 +01:00
w0rp
d581fca35e Get tests running and passing with NeoVim 0.2 and 0.3 2018-06-28 13:53:49 +01:00
w0rp
8b407ed0e7 Try NeoVim 0.2.1, as 0.2.0 is way too slow 2018-06-28 12:07:22 +01:00
w0rp
51a14a4ba8 Update Dockerfile to test NeoVim 0.2 and 0.3, with a newer Vint version 2018-06-28 11:29:20 +01:00
Dan Aloni
d9e139ae23 Rust Cargo linter: Improve workspace support (#1679)
* Rust Cargo linter: Improve workspace support

When using Cargo workspaces [1], there is a 'Cargo.toml' directory in a
top level directory, listing all the crates in the project. If we are
currently editing one of the crates, 'cargo build' should execute in
that directory for that crate's separate `Cargo.toml`, otherwise Cargo
may spend more time possibly rebuilding the entire workspace, and maybe
failing on one of the other crates, instead of succeeding on the current.

[1] https://doc.rust-lang.org/book/second-edition/ch14-03-cargo-workspaces.html
2018-06-27 22:36:02 +01:00
w0rp
980aa35566 Merge pull request #1675 from nicopauss/master
Improve pyrex cython linter.
2018-06-27 21:39:36 +01:00
w0rp
b047271051 Merge pull request #1682 from fennerm/fix_prospector_e474
Fix prospector empty string error
2018-06-27 21:34:28 +01:00
Fenner Macrae
1ca2334846 Fix prospector empty string error
Prospector linter is raising error when no warnings are present in file
(#1680). Copied fix from #779.
2018-06-26 16:58:34 -07:00
Nicolas Pauss
4d935ff32a Add test_pyrex_cython_command_callback.vader
Add common callback tests to check if executable and options are well
configurable.
2018-06-25 22:14:43 +02:00
w0rp
66820ed452 Merge pull request #1641 from docwhat/pr/add-bash-lsp
sh: add bash-language-server linter
2018-06-25 17:03:15 +01:00
Nicolas Pauss
d05936a489 Handle cython warning with custom handle and remove '--warning-errors'.
Add a custom handler to support cython warning format.
Remove '--warning-errors' to keep previous behaviour.
2018-06-25 17:33:53 +02:00
Christian Höltje
49d995a521 sh: add bash-language-server linter 2018-06-25 11:21:53 -04:00
Nicolas Pauss
bedd30ee11 Improve pyrex cython linter.
Like many other linters, use variables for the executable and options
used by the linter.
By default, the linter now report every warnings as errors with
`--warning-errors`.
Also add include directory and set working directory to file directory.
2018-06-25 10:28:59 +02:00
w0rp
620951b6d3 Close #1453 #1172 - Add ale_linters_ignore for ignoring linter results 2018-06-24 21:16:45 +01:00
w0rp
755f1a4ccf Merge pull request #1673 from meain/fixer-tidy
Add fixer tidy for HTML
2018-06-23 22:51:30 +01:00
Abin Simon
17c1aefb5b Add fixer tidy for HTML
Add tests for tidy HTML fixer
2018-06-23 22:59:13 +05:30
w0rp
0f377251dd #1674 - Alias verilog_systemverilog to verilog by default 2018-06-23 18:20:39 +01:00
w0rp
935740cf93 Close #1590 - Automatically close previews for hover 2018-06-21 23:02:36 +01:00
w0rp
8bca073763 Fix #1661 - Do not use :edit when jumping inside of a file 2018-06-21 21:20:54 +01:00
w0rp
22533f2c1f Close #1522 - Show suggested fixers in :ALEInfo 2018-06-21 02:26:41 +01:00
w0rp
69eb2fe86a Close #1417 - Support wildcard filetypes for fixers 2018-06-21 01:21:11 +01:00
w0rp
34755eecdd #1398 document the detail key 2018-06-20 23:10:01 +01:00
w0rp
90dfe8e2a4 Merge pull request #1665 from ashemedai/master
Make CloudFormation linter work again with latest version
2018-06-20 22:51:55 +01:00
w0rp
11f303f853 Merge pull request #1618 from colbydehart/master
[new linter] Add mix linter for elixir
2018-06-20 22:47:56 +01:00
w0rp
b8be25adb4 Remove redundant spaces. 2018-06-20 22:44:56 +01:00
w0rp
d7efb13203 Try to fix the tests on Windows 2018-06-20 22:41:19 +01:00
Jeroen Ruigrok van der Werven
f14e3bb109 Update test to match update to linter
Also make lnum and col proper strings, since that is how it is matched
by the regexp, ALE handles the conversion to number.
2018-06-20 15:29:26 +02:00
Jeroen Ruigrok van der Werven
b7db095221 Make CloudFormation linter work again with latest
- Fix regexp
- Get rid of +0 since ALE does a str2nr() on lnum and col
- Put all matches in numerical order for easier maintenance
2018-06-20 14:59:51 +02:00
w0rp
0e1528ec34 Set up most of the autocmd events in one group 2018-06-20 13:35:57 +01:00
w0rp
9674132933 Remove CallWithCooldown functions to save on time 2018-06-20 08:34:42 +01:00
w0rp
82ea36576c Move ClockMilliseconds to events, so fewer files are loaded some times 2018-06-19 20:53:49 +01:00
w0rp
fd261d7a17 Move the initialization of augroups to then events file 2018-06-19 20:31:58 +01:00
w0rp
3a5887df2c Remove a redundant variable in tests 2018-06-19 20:12:49 +01:00
w0rp
e306e5cdb0 Avoid calling ALE cleanup code if ALE never tried to check a buffer 2018-06-19 20:12:33 +01:00
Alvin Chan
b8a1038a41 Set --parser option in Prettier's fixer (#1620)
* Set `--parser` option in Prettier's fixer
* Add expected `--parser` option to tests
* Disable Prettier `--parser` detection if file extension exists
* Manually default Prettier `--parser` to "babylon"
* Add `--parser` test for TypeScript
* Add tests for Prettier `--parser`
* Add JSON5 to the suggested fixer for Prettier
2018-06-18 22:40:57 +01:00
w0rp
43ce8d7610 Merge pull request #1653 from chaucerbao/feature/js-tsserver-support
Add TSServer support for JavaScript files
2018-06-17 22:14:12 +01:00
w0rp
24fe195311 Merge pull request #1650 from yasuhiroki/support-cfn-python-lint
Add linter for AWS CloudFormation template file
2018-06-17 20:39:07 +01:00
w0rp
49a5d657ee Tell people that there's no cost for LSP support if they don't need it 2018-06-15 10:24:09 +01:00
w0rp
bda89506ba Lazy-load LSP linters, and check b:changedtick before notifying about changes 2018-06-15 10:01:28 +01:00
Alvin Chan
bd4da116ee Add TSServer support for JavaScript files 2018-06-13 17:37:20 -07:00
yasuhiroki
eabf5d55d6 Add end_lnum and end_col in cfn_python_lint handler 2018-06-13 09:11:14 +09:00
P M
f1b72218c3 Add support for qmlfmt fixer (#1651)
* Add support for qmlfmt fixer
2018-06-12 19:38:16 +01:00
w0rp
5283faa511 Try speeding up Travis builds with a generic environment 2018-06-12 19:31:44 +01:00
w0rp
87455a2ef4 Add a test for handling missing detail keys for LSP completion 2018-06-12 19:31:08 +01:00
w0rp
d9746a4572 Merge pull request #1638 from ssiegel/use-vanilla-rscript
Use --vanilla switch for Rscript
2018-06-12 19:01:45 +01:00
yasuhiroki
ae25d71fa8 Add linter for AWS CloudFormation template file 2018-06-12 15:11:53 +09:00
w0rp
22a9dcd03e Merge pull request #1640 from docwhat/pr/lsp-handle-missing-details
lsp: handle missing "detail" key
2018-06-11 21:33:49 +01:00
Christian Höltje
fd7456fce0 lsp: handle missing "detail" key 2018-06-07 13:43:08 -04:00
Colby Dehart
864818a385 WIP cd to project path 2018-06-07 11:47:57 -05:00
Colby Dehart
f0f569f14a added test for command callback 2018-06-07 10:09:08 -05:00
Stefan Siegel
42192c1593 Adapt test to also use Rscript --vanilla 2018-06-07 15:56:14 +02:00
Stefan Siegel
252097bee0 Use --vanilla switch for Rscript
This prevents possibly bad interference with the user's R environment,
e.g. by an auto-activating packrat.
2018-06-07 15:06:09 +02:00
w0rp
10a9177b6b Merge pull request #1636 from zed0/master
#1635 - Use the project base rather than its parent for cquery
2018-06-07 07:23:44 +01:00
Ben Falconer
d1be72f438 #1635 - Use the project base rather than its parent for cquery 2018-06-07 00:12:38 +01:00
w0rp
67753de531 Merge pull request #1632 from zed0/master
Add the cquery LSP
2018-06-06 21:31:36 +01:00
Ben Falconer
20db9ab719 Add the cquery LSP #1475 #1594 2018-06-06 17:58:47 +01:00
Ben Falconer
641c0c797b Pass rootUri to LSPs in addition to rootPath 2018-06-06 17:53:36 +01:00
Ben Falconer
1a4b08539b Allow initialization options to be passed to language servers 2018-06-06 17:53:36 +01:00
w0rp
c49ea1a5e3 Merge pull request #1629 from elebow/pipenv-executable-python-tools
Allow all Python linter executables to be set to `pipenv`.
2018-06-05 08:32:45 +01:00
w0rp
3a6a92283e Merge pull request #1628 from rmorabia/patch-1
Readme Typo: TypeSript -> TypeScript
2018-06-05 07:12:53 +01:00
Eddie Lebow
ca88e67af0 Allow all Python linter executables to be set to pipenv.
It appends ` run {linter_name}`, analogously to the Ruby linters when
the executable is set to `bundle`
2018-06-05 00:33:26 -04:00
Radhika Morabia
b3da52d38d Typo: TypeSript -> TypeScript 2018-06-04 20:22:53 -07:00
w0rp
5addd3abef Merge pull request #1627 from budziq/master
Added linting of tests and examples for rust cargo linter
2018-06-04 13:33:08 +01:00
Michał Budzyński
e272207114 Allow linting rust tests and examples with cargo 2018-06-04 11:08:49 +02:00
w0rp
4ec661b305 Merge pull request #1623 from zoonfafer/scalafmt-fixer
Add 'scalafmt' fixer for Scala files
2018-06-03 19:12:09 +01:00
Jeffrey Lau
03d14324ea doc/scalafmt: Remove wrong bits on initial "enabledness" of fixers 2018-06-04 02:05:19 +08:00
w0rp
a8bbf49a31 Merge pull request #1625 from elebow/flake8-pipenv-run
Allow flake8 executable to be set to `pipenv`.
2018-06-03 18:52:15 +01:00
w0rp
0db12702f3 Respect warn_about_trailing_whitespace for gitlint 2018-06-03 10:46:39 +01:00
Eddie Lebow
dd642b117c Allow flake8 executable to be set to pipenv.
It appends ` run flake8`, analogously to the Ruby tools when the
executable is set to `bundle`
2018-06-02 21:49:12 -04:00
Jeffrey Lau
77d0ac58ed Add 'scalafmt' fixer for Scala files
closes https://github.com/w0rp/ale/issues/1299
2018-06-03 04:40:52 +08:00
Colby Dehart
81739be0a0 handled temp file and env variable correctly; added tests 2018-06-02 13:03:56 -04:00
w0rp
786fc0a62f Merge pull request #1617 from luitzifa/master
Fix for puppet version >= 5.4.0
2018-06-02 12:36:24 +01:00
w0rp
014d27c882 #1621 - Tolerate SetOptions calls when ALE is loaded in a weird way 2018-06-01 21:03:22 +01:00
Colby Dehart
d760558007 added mix build path env var to the mix compile 2018-06-01 11:56:47 -04:00
w0rp
fae9167083 Fix LSP message handling when the handler doesn't get strings, somehow 2018-06-01 14:49:13 +01:00
w0rp
201f8519d9 Update the gitcommit documentation with more examples 2018-06-01 14:22:23 +01:00
w0rp
6a7e00d9ac Handle definition responses without files 2018-06-01 14:15:32 +01:00
Magnus Ottenklinger
801c12a881 Add mix linter for elixir 2018-05-30 10:38:14 -04:00
Daniel Kraemer
3a1d21e5dd Fix for puppet version 5.4.0
i don't know of any version lower than 5.4.0
2018-05-29 08:55:08 +02:00
168 changed files with 4182 additions and 1506 deletions

1
.gitattributes vendored
View File

@@ -2,6 +2,7 @@
/CODE_OF_CONDUCT.md export-ignore
/CONTRIBUTING.md export-ignore
/Dockerfile export-ignore
/ISSUE_TEMPLATE export-ignore
/ISSUE_TEMPLATE.md export-ignore
/Makefile export-ignore
/PULL_REQUEST_TEMPLATE.md export-ignore

40
.github/ISSUE_TEMPLATE/report-a-bug.md vendored Normal file
View File

@@ -0,0 +1,40 @@
---
name: Report a bug
about: Report a bug with ALE.
---
<!--
This is the template for reporting ALE bugs. Make sure you try updating ALE
to a more recent version before reporting a bug. Look through existing bug
reports for similar issues before reporting a new one. Don't leave comments
about new bugs in the comment section for old issues.
Make sure to try disabling other plugins and trying to repeat your bug before
reporting it in ALE. Some times problems can arise when two plugins are used
together, but often your issues might be problems with other plugins.
-->
## Information
**VIM version**
<!-- Paste just the first two lines of :version here. -->
Operating System: <!-- Describe your operating system version. -->
### :ALEInfo
<!-- Paste the output of :ALEInfo here. Try :ALEInfoToClipboard -->
<!-- Make sure to run :ALEInfo from the buffer where the bug occurred. -->
## What went wrong
<!-- Describe what went wrong here. -->
## Reproducing the bug
<!-- Write a list of steps below. -->
1. I did this.
2. Then this happened.

View File

@@ -0,0 +1,20 @@
---
name: Suggest a new linter or fixer
about: Suggest a new tool ALE can officially integrate with.
---
<!--
Write "Add support for foobar" as the issue title, or similar.
Fill out the details below.
-->
**Name:** foobar
**URL:** https://foo.bar.com
<!--
Write a description of the tool, and add any other information you think might
be helpful. Consider creating a pull request to add support for the tool
yourself.
-->

View File

@@ -0,0 +1,7 @@
---
name: Suggest an improvement
about: Suggest some way to improve ALE, or add a new feature.
---
<!-- There's no fixed format for feature requests. Just add your thoughts. -->

View File

@@ -2,6 +2,6 @@
sudo: required
services:
- docker
language: python
language: generic
script: |
./run-tests
./run-tests -v

View File

@@ -1,37 +1,11 @@
# Contributing to ALE
1. [Guidelines](#guidelines)
2. [Creating Issues](#issues)
3. [Creating Pull Requests](#pull-requests)
1. [Adding a New Linter](#adding-a-new-linter)
2. [Adding New Options](#adding-new-options)
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-linter-options)
5. [In Case of Busses](#in-case-of-busses)
<a name="guidelines"></a>
## 1. Guidelines
## Guidelines
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.
For help with contributing to ALE, see `:help ale-development` in Vim, or view
the help file online [here](/w0rp/ale/blob/master/doc/ale-development.txt).
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
install this plugin (ALE) and install [Vint](https://github.com/Kuniwak/vint), it
will check your code while you type.
<a name="issues"></a>
## 2. Creating Issues
## Creating Issues
Before creating any issues, please look through the current list of issues and
pull requests, and ensure that the issue hasn't already been reported. If an
@@ -49,125 +23,3 @@ operating system, or any other information you think might be helpful.
Please describe your issue in clear, grammatically correct, and easy to
understand English. You are more likely to see an issue resolved if others
can understand you.
<a name="pull-requests"></a>
## 3. Creating Pull Requests
For code you write, make sure to credit yourself at the top of files you add,
and probably those you modify. You can write some comments at the top of your
VIM files.
```vim
" Author: John Smith <john.smith@gmail.com>
" Description: This file adds support for awesomelinter for the best language ever.
```
If you want to credit multiple authors, you can comma separate them.
```vim
" Author: John Smith <john.smith@gmail.com>, Jane Doe <https://jane-doe.info>
```
<a name="adding-a-new-linter"></a>
### 3.i. Adding a New Linter
If you add a new linter, look for existing handlers first in the
[handlers](autoload/ale/handlers) directory. One of the handlers there may
already be able to handle your lines of output. If you find that your new
linter replicates an existing error handler, consider pulling it up into the
[handlers](autoload/ale/handlers) directory, and use the generic handler in
both places.
When you add a linter, make sure the language for the linter and the linter
itself are present in the table in the [README.md](README.md) file and in the
Vim [help file](doc/ale.txt). The programs and linters should be sorted
alphabetically in the table and list.
<a name="adding-new-options"></a>
### 3.ii. Adding New Options
If you add new options to the plugin, make sure to document those new options
in the [README.md](README.md) file, and also in the [help file](doc/ale.txt).
Follow the format of other options in each. Global options should appear in the
README file, and in the relevant section in the help file. Options specific
to a particular linter should appear in the section for that linter.
Linter options for customizing general argument lists should be named
`g:ale_<filetype>_<linter>_options`, so that all linters can have similar
global variable names.
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 guidelines 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 abduction, etc., action should be taken to ensure that the
project continues. If no one is left to administer the project where it is
hosted, please fork the project and nominate someone capable to administer it.
Preferably, in such an event, a single fork of the project will replace the
original, and life will go on, except the life of whoever vanished, because
then they will probably be dead.
Should w0rp suddenly disappear, then he was probably killed in a traffic
accident, or the government finally decided to kill him and make it look like
suicide. In the latter event, please subvert said government and restore
order to the universe, and ensure peace for mankind.

View File

@@ -1,7 +1,8 @@
FROM tweekmonster/vim-testbed:latest
RUN install_vim -tag v8.0.0027 -build \
-tag neovim:v0.1.7 -build
-tag neovim:v0.2.0 -build \
-tag neovim:v0.3.0 -build
ENV PACKAGES="\
bash \
@@ -12,7 +13,7 @@ ENV PACKAGES="\
RUN apk --update add $PACKAGES && \
rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
RUN pip install vim-vint==0.3.9
RUN pip install vim-vint==0.3.15
RUN git clone https://github.com/junegunn/vader.vim vader && \
cd vader && git checkout c6243dd81c98350df4dec608fa972df98fa2a3af

View File

@@ -1,28 +0,0 @@
<!--
This is a template for bug reports. If you want to request a new feature,
you can clear this entire form field and write a short description of what
you want.
-->
## Information
**VIM version**
PASTE JUST THE FIRST TWO LINES OF `:version` HERE.
Operating System: WHAT OS WERE YOU USING?
### :ALEInfo
PASTE OUTPUT OF `:ALEInfo` HERE. YOU CAN TRY `:ALEInfoToClipboard`.
## What went wrong
WRITE WHAT WENT WRONG HERE.
## Reproducing the bug
Steps for repeating the bug:
1. Write a list of steps.
2. Otherwise nobody will fix the bug.

View File

@@ -1,22 +1,8 @@
<!--
READ THIS: Before creating a pull request, please consider the following first.
Before creating a pull request, do the following.
* The most important thing you can do is write tests. Code without tests
probably doesn't work, and will almost certainly stop working later on. Pull
requests without tests probably won't be accepted, although there are some
exceptions.
* Read the Contributing guide linked above first.
* If you are adding a new linter, remember to update the README.md file and
doc/ale.txt first.
* If you add or modify a function for converting error lines into loclist items
that ALE can work with, please add Vader tests for them. Look at existing
tests in the test/handler directory, etc.
* If you add or modify a function for computing a command line string for
running a command, please add Vader tests for that. Look at existing
tests in the test/command_callback directory, etc.
* Generally try and cover anything with Vader tests, although some things just
can't be tested with Vader, or at least they can be hard to test. Consider
breaking up your code so that some parts can be tested, and generally open up
a discussion about it.
* Have fun!
* Read the documentation that comes with ALE with `:help ale-development`.
Have fun!
-->

View File

@@ -29,6 +29,10 @@ features, including:
* Finding references (`:ALEFindReferences`)
* Hover information (`:ALEHover`)
If you don't care about Language Server Protocol, ALE won't load any of the code
for working with it unless needed. One of ALE's general missions is that you
won't pay for the features that you don't use.
## Table of Contents
1. [Supported Languages and Tools](#supported-languages)
@@ -90,14 +94,15 @@ formatting.
| API Blueprint | [drafter](https://github.com/apiaryio/drafter) |
| AsciiDoc | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [write-good](https://github.com/btford/write-good) |
| Awk | [gawk](https://www.gnu.org/software/gawk/)|
| Bash | shell [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/), [shfmt](https://github.com/mvdan/sh) |
| Bash | [language-server](https://github.com/mads-hartmann/bash-language-server), shell [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/), [shfmt](https://github.com/mvdan/sh) |
| Bourne Shell | shell [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/), [shfmt](https://github.com/mvdan/sh) |
| C | [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [clang](http://clang.llvm.org/), [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/) |
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) !!, [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) !!, [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/) |
| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) !!, [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) !!, [cquery](https://github.com/cquery-project/cquery), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/) |
| CUDA | [nvcc](http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html) |
| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) see:`help ale-cs-mcs` for details, [mcsc](http://www.mono-project.com/docs/about-mono/languages/csharp/) !! see:`help ale-cs-mcsc` for details and configuration|
| Chef | [foodcritic](http://www.foodcritic.io/) |
| Clojure | [joker](https://github.com/candid82/joker) |
| CloudFormation | [cfn-python-lint](https://github.com/awslabs/cfn-python-lint) |
| CMake | [cmakelint](https://github.com/richq/cmake-lint) |
| CoffeeScript | [coffee](http://coffeescript.org/), [coffeelint](https://www.npmjs.com/package/coffeelint) |
| Crystal | [crystal](https://crystal-lang.org/) !! |
@@ -106,9 +111,9 @@ formatting.
| Cython (pyrex filetype) | [cython](http://cython.org/) |
| D | [dmd](https://dlang.org/dmd-linux.html) |
| Dafny | [dafny](https://rise4fun.com/Dafny) !! |
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) !!, [language_server](https://github.com/natebosch/dart_language_server) |
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) !!, [language_server](https://github.com/natebosch/dart_language_server), [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) |
| Dockerfile | [hadolint](https://github.com/hadolint/hadolint) |
| Elixir | [credo](https://github.com/rrrene/credo), [dialyxir](https://github.com/jeremyjh/dialyxir), [dogma](https://github.com/lpil/dogma) !!|
| Elixir | [credo](https://github.com/rrrene/credo), [dialyxir](https://github.com/jeremyjh/dialyxir), [dogma](https://github.com/lpil/dogma), [mix](https://hexdocs.pm/mix/Mix.html) !!|
| Elm | [elm-format](https://github.com/avh4/elm-format), [elm-make](https://github.com/elm-lang/elm-make) |
| Erb | [erb](https://apidock.com/ruby/ERB), [erubi](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis) |
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html), [SyntaxErl](https://github.com/ten0s/syntaxerl) |
@@ -153,7 +158,7 @@ formatting.
| proto | [protoc-gen-lint](https://github.com/ckaznocha/protoc-gen-lint) |
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](http://github.com/landscapeio/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pylint](https://www.pylint.org/) !!, [yapf](https://github.com/google/yapf) |
| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](http://github.com/landscapeio/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pyre](https://github.com/facebook/pyre-check), [pylint](https://www.pylint.org/) !!, [yapf](https://github.com/google/yapf) |
| QML | [qmlfmt](https://github.com/jesperhh/qmlfmt), [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint) |
| R | [lintr](https://github.com/jimhester/lintr) |
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-reasonml-ols` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server), [refmt](https://github.com/reasonml/reason-cli) |
@@ -164,7 +169,7 @@ formatting.
| Rust | cargo !! (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/), [rustfmt](https://github.com/rust-lang-nursery/rustfmt) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [prettier](https://github.com/prettier/prettier), [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
| Scala | [fsc](https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/tools/fsc.html), [scalac](http://scala-lang.org), [scalastyle](http://www.scalastyle.org) |
| Scala | [fsc](https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/tools/fsc.html), [scalac](http://scala-lang.org), [scalafmt](https://scalameta.org/scalafmt/), [scalastyle](http://www.scalastyle.org) |
| Slim | [slim-lint](https://github.com/sds/slim-lint) |
| SML | [smlnj](http://www.smlnj.org/) |
| Solidity | [solhint](https://github.com/protofire/solhint), [solium](https://github.com/duaraghav8/Solium) |
@@ -253,7 +258,7 @@ See `:help ale-fix` for complete information on how to fix files with ALE.
ALE offers some support for completion via hijacking of omnicompletion while you
type. All of ALE's completion information must come from Language Server
Protocol linters, or from `tsserver` for TypeSript.
Protocol linters, or from `tsserver` for TypeScript.
```vim
" Enable completion where available.
@@ -749,8 +754,9 @@ ALE cannot easily detect which compiler flags to use.
Some tools and build configurations can generate
[compile_commands.json](https://clang.llvm.org/docs/JSONCompilationDatabase.html)
files. The `cppcheck`, `clangcheck` and `clangtidy` linters can read these
files for automatically determining the appropriate compiler flags to use.
files. The `cppcheck`, `clangcheck`, `clangtidy` and `cquery` linters can read
these files for automatically determining the appropriate compiler flags to
use.
For linting with compilers like `gcc` and `clang`, and with other tools, you
will need to tell ALE which compiler flags to use yourself. You can use

View File

@@ -0,0 +1,35 @@
" Author: Yasuhiro Kiyota <yasuhiroki.duck@gmail.com>
" Description: Support cfn-python-lint for AWS Cloudformation template file
function! ale_linters#cloudformation#cfn_python_lint#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" sample.template.yaml:96:7:96:15:E3012:Property Resources/Sample/Properties/FromPort should be of type Integer
let l:pattern = '\v^(.*):(\d+):(\d+):(\d+):(\d+):([[:alnum:]]+):(.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[6]
if ale#path#IsBufferPath(a:buffer, l:match[1])
call add(l:output, {
\ 'lnum': l:match[2],
\ 'col': l:match[3],
\ 'end_lnum': l:match[4],
\ 'end_col': l:match[5],
\ 'code': l:code,
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
\ 'text': l:match[7]
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('cloudformation', {
\ 'name': 'cloudformation',
\ 'executable': 'cfn-lint',
\ 'command': 'cfn-lint --template %t --format parseable',
\ 'callback': 'ale_linters#cloudformation#cfn_python_lint#Handle',
\})

View File

@@ -0,0 +1,34 @@
" Author: Ben Falconer <ben@falconers.me.uk>
" Description: A language server for C++
call ale#Set('cpp_cquery_executable', 'cquery')
call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#cquery#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'cpp_cquery_executable')
endfunction
function! ale_linters#cpp#cquery#GetCommand(buffer) abort
let l:executable = ale_linters#cpp#cquery#GetExecutable(a:buffer)
return ale#Escape(l:executable)
endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort
return {'cacheDirectory': ale#Var(a:buffer, 'cpp_cquery_cache_directory')}
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cquery',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#cpp#cquery#GetExecutable',
\ 'command_callback': 'ale_linters#cpp#cquery#GetCommand',
\ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot',
\ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions',
\ 'language': 'cpp',
\})

View File

@@ -29,7 +29,7 @@ function! ale_linters#cs#mcsc#GetCommand(buffer) abort
\ : ''
" register temporary module target file with ale
let l:out = tempname()
let l:out = ale#util#Tempname()
call ale#engine#ManageFile(a:buffer, l:out)
" The code is compiled as a module and the output is redirected to a

View File

@@ -10,7 +10,7 @@ endfunction
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = tempname() . '.ii'
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#engine#ManageFile(a:buffer, l:output_file)
return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer))

View File

@@ -0,0 +1,61 @@
" Author: evnu - https://github.com/evnu
" Author: colbydehart - https://github.com/colbydehart
" Description: Mix compile checking for Elixir files
function! ale_linters#elixir#mix#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" Error format
" ** (CompileError) apps/sim/lib/sim/server.ex:87: undefined function update_in/4
"
" TODO: Warning format
" warning: variable "foobar" does not exist and is being expanded to "foobar()", please use parentheses to remove the ambiguity or change the variable name
let l:pattern = '\v\(([^\)]+Error)\) ([^:]+):([^:]+): (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:type = 'E'
let l:text = l:match[4]
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[3] + 0,
\ 'col': 0,
\ 'type': l:type,
\ 'text': l:text,
\})
endfor
return l:output
endfunction
function! ale_linters#elixir#mix#FindProjectRoot(buffer) abort
let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
if !empty(l:mix_file)
return fnamemodify(l:mix_file, ':p:h')
endif
return '.'
endfunction
function! ale_linters#elixir#mix#GetCommand(buffer) abort
let l:project_root = ale_linters#elixir#mix#FindProjectRoot(a:buffer)
let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
let l:mix_build_path = has('win32')
\ ? 'set MIX_BUILD_PATH=' . ale#Escape(l:temp_dir) . ' &&'
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root)
\ . l:mix_build_path
\ . ' mix compile %s'
endfunction
call ale#linter#Define('elixir', {
\ 'name': 'mix',
\ 'executable': 'mix',
\ 'command_callback': 'ale_linters#elixir#mix#GetCommand',
\ 'callback': 'ale_linters#elixir#mix#Handle',
\ 'lint_file': 1,
\})

View File

@@ -128,14 +128,7 @@ function! ale_linters#elm#make#HandleElm018Line(line, output) abort
endfunction
function! ale_linters#elm#make#FileIsBuffer(path) abort
let l:is_windows = has('win32')
let l:temp_dir = l:is_windows ? $TMP : $TMPDIR
if has('win32')
return a:path[0:len(l:temp_dir) - 1] is? l:temp_dir
else
return a:path[0:len(l:temp_dir) - 1] is# l:temp_dir
endif
return ale#path#IsTempName(a:path)
endfunction
function! ale_linters#elm#make#ParseMessage(message) abort

View File

@@ -3,7 +3,7 @@
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
function! ale_linters#erlang#erlc#GetCommand(buffer) abort
let l:output_file = tempname()
let l:output_file = ale#util#Tempname()
call ale#engine#ManageFile(a:buffer, l:output_file)
return 'erlc -o ' . ale#Escape(l:output_file)

View File

@@ -28,6 +28,10 @@ function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[2]
if l:code is# 'T2' && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
continue
endif
let l:item = {
\ 'lnum': l:match[1] + 0,
\ 'text': l:match[3],

View File

@@ -1,21 +1,10 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" Description: This file adds support for checking HTML code with tidy.
" CLI options
let g:ale_html_tidy_executable = get(g:, 'ale_html_tidy_executable', 'tidy')
" remove in 2.0
" Look for the old _args variable first.
let s:deprecation_warning_echoed = 0
let s:default_options = get(g:, 'ale_html_tidy_args', '-q -e -language en')
let g:ale_html_tidy_options = get(g:, 'ale_html_tidy_options', s:default_options)
let g:ale_html_tidy_options = get(g:, 'ale_html_tidy_options', '-q -e -language en')
function! ale_linters#html#tidy#GetCommand(buffer) abort
" remove in 2.0
if exists('g:ale_html_tidy_args') && !s:deprecation_warning_echoed
execute 'echom ''Rename your g:ale_html_tidy_args setting to g:ale_html_tidy_options instead. Support for this will removed in ALE 2.0.'''
let s:deprecation_warning_echoed = 1
endif
" Specify file encoding in options
" (Idea taken from https://github.com/scrooloose/syntastic/blob/master/syntax_checkers/html/tidy.vim)
let l:file_encoding = get({

View File

@@ -0,0 +1,26 @@
" Author: Chaucerbao, w0rp <devw0rp@gmail.com>
" Description: tsserver integration for ALE
call ale#Set('javascript_tsserver_executable', 'tsserver')
call ale#Set('javascript_tsserver_config_path', '')
call ale#Set('javascript_tsserver_use_global', get(g:, 'ale_use_global_executables', 0))
" These functions need to be defined just to comply with the API for LSP.
function! ale_linters#javascript#tsserver#GetProjectRoot(buffer) abort
return ''
endfunction
function! ale_linters#javascript#tsserver#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_tsserver', [
\ 'node_modules/.bin/tsserver',
\])
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
\ 'executable_callback': 'ale_linters#javascript#tsserver#GetExecutable',
\ 'command_callback': 'ale_linters#javascript#tsserver#GetExecutable',
\ 'project_root_callback': 'ale_linters#javascript#tsserver#GetProjectRoot',
\ 'language': '',
\})

View File

@@ -4,14 +4,15 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" Matches patterns like the following:
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
" Error: Could not parse for environment production: Syntax error at '='; expected '}' at /root/puppetcode/modules/pancakes/manifests/init.pp:5"
" Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 4, column: 5)
let l:pattern = '^Error: .*: \(.\+\) at .\+\.pp:\(\d\+\):\=\(\d*\)'
let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'lnum': l:match[4] + 0,
\ 'col': l:match[6] + 0,
\ 'text': l:match[1],
\})
endfor

View File

@@ -1,10 +1,43 @@
" Author: w0rp <devw0rp@gmail.com>
" Author: w0rp <devw0rp@gmail.com>,
" Nicolas Pauss <https://github.com/nicopauss>
" Description: cython syntax checking for cython files.
call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra')
function! ale_linters#pyrex#cython#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'pyrex_cython_executable')
endfunction
function! ale_linters#pyrex#cython#GetCommand(buffer) abort
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
return ale#Escape(ale_linters#pyrex#cython#GetExecutable(a:buffer))
\ . ' --working ' . l:local_dir . ' --include-dir ' . l:local_dir
\ . ' ' . ale#Var(a:buffer, 'pyrex_cython_options')
\ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction
function! ale_linters#pyrex#cython#Handle(buffer, lines) abort
let l:pattern = '\v^(\w+: )?[^:]+:(\d+):?(\d+)?:? ?(.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[4],
\ 'type': l:match[1][0] is# 'w' ? 'W' : 'E',
\})
endfor
return l:output
endfunction
call ale#linter#Define('pyrex', {
\ 'name': 'cython',
\ 'output_stream': 'stderr',
\ 'executable': 'cython',
\ 'command': 'cython --warning-extra -o ' . g:ale#util#nul_file . ' %t',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\ 'executable_callback': 'ale_linters#pyrex#cython#GetExecutable',
\ 'command_callback': 'ale_linters#pyrex#cython#GetCommand',
\ 'callback': 'ale_linters#pyrex#cython#Handle',
\})

View File

@@ -1,13 +1,8 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: flake8 for python files
" remove in 2.0
" Support an old setting as a fallback.
let s:deprecation_warning_echoed = 0
let s:default_options = get(g:, 'ale_python_flake8_args', '')
call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', s:default_options)
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 1)
@@ -40,18 +35,16 @@ function! ale_linters#python#flake8#VersionCheck(buffer) abort
endfunction
function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
" remove in 2.0
if exists('g:ale_python_flake8_args') && !s:deprecation_warning_echoed
execute 'echom ''Rename your g:ale_python_flake8_args setting to g:ale_python_flake8_options instead. Support for this will removed in ALE 2.0.'''
let s:deprecation_warning_echoed = 1
endif
let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run flake8'
\ : ''
" Only include the --stdin-display-name argument if we can parse the
" flake8 version, and it is recent enough to support it.
let l:display_name_args = ale#semver#GTE(l:version, [3, 0, 0])
@@ -61,7 +54,7 @@ function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort
let l:options = ale#Var(a:buffer, 'python_flake8_options')
return l:cd_string
\ . ale#Escape(l:executable)
\ . ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --format=default'
\ . l:display_name_args . ' -'

View File

@@ -23,10 +23,14 @@ function! ale_linters#python#mypy#GetCommand(buffer) abort
let l:dir = s:GetDir(a:buffer)
let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run mypy'
\ : ''
" We have to always switch to an explicit directory for a command so
" we can know with certainty the base path for the 'filename' keys below.
return ale#path#CdString(l:dir)
\ . ale#Escape(l:executable)
\ . ale#Escape(l:executable) . l:exec_args
\ . ' --show-column-numbers '
\ . ale#Var(a:buffer, 'python_mypy_options')
\ . ' --shadow-file %s %t %s'

View File

@@ -14,7 +14,14 @@ function! ale_linters#python#prospector#GetExecutable(buffer) abort
endfunction
function! ale_linters#python#prospector#GetCommand(buffer) abort
return ale#Escape(ale_linters#python#prospector#GetExecutable(a:buffer))
let l:executable = ale_linters#python#prospector#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run prospector'
\ : ''
return ale#Escape(l:executable)
\ . l:exec_args
\ . ' ' . ale#Var(a:buffer, 'python_prospector_options')
\ . ' --messages-only --absolute-paths --zero-exit --output-format json'
\ . ' %s'
@@ -23,6 +30,10 @@ endfunction
function! ale_linters#python#prospector#Handle(buffer, lines) abort
let l:output = []
if empty(a:lines)
return []
endif
let l:prospector_error = json_decode(join(a:lines, ''))
for l:error in l:prospector_error.messages

View File

@@ -10,7 +10,13 @@ function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
endfunction
function! ale_linters#python#pycodestyle#GetCommand(buffer) abort
return ale#Escape(ale_linters#python#pycodestyle#GetExecutable(a:buffer))
let l:executable = ale_linters#python#pycodestyle#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pycodestyle'
\ : ''
return ale#Escape(l:executable) . l:exec_args
\ . ' '
\ . ale#Var(a:buffer, 'python_pycodestyle_options')
\ . ' -'

View File

@@ -11,7 +11,13 @@ endfunction
function! ale_linters#python#pyflakes#GetCommand(buffer) abort
let l:executable = ale_linters#python#pyflakes#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' %t'
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pyflakes'
\ : ''
return ale#Escape(l:executable)
\ . l:exec_args
\ . ' %t'
endfunction
function! ale_linters#python#pyflakes#Handle(buffer, lines) abort

View File

@@ -15,8 +15,14 @@ function! ale_linters#python#pylint#GetCommand(buffer) abort
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:executable = ale_linters#python#pylint#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pylint'
\ : ''
return l:cd_string
\ . ale#Escape(ale_linters#python#pylint#GetExecutable(a:buffer))
\ . ale#Escape(l:executable) . l:exec_args
\ . ' ' . ale#Var(a:buffer, 'python_pylint_options')
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n'
\ . ' %s'

View File

@@ -11,7 +11,11 @@ endfunction
function! ale_linters#python#pyls#GetCommand(buffer) abort
let l:executable = ale_linters#python#pyls#GetExecutable(a:buffer)
return ale#Escape(l:executable)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pyls'
\ : ''
return ale#Escape(l:executable) . l:exec_args
endfunction
call ale#linter#Define('python', {

View File

@@ -0,0 +1,29 @@
" Author: dsifford <dereksifford@gmail.com>
" Description: A performant type-checker supporting LSP for Python 3 created by Facebook
call ale#Set('python_pyre_executable', 'pyre')
call ale#Set('python_pyre_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#python#pyre#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pyre', ['pyre'])
endfunction
function! ale_linters#python#pyre#GetCommand(buffer) abort
let l:executable = ale_linters#python#pyre#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pyre persistent'
\ : ' persistent'
return ale#Escape(l:executable) . l:exec_args
endfunction
call ale#linter#Define('python', {
\ 'name': 'pyre',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#python#pyre#GetExecutable',
\ 'command_callback': 'ale_linters#python#pyre#GetCommand',
\ 'language': 'python',
\ 'project_root_callback': 'ale#python#FindProjectRoot',
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\})

View File

@@ -22,7 +22,7 @@ function! ale_linters#r#lintr#GetCommand(buffer) abort
\ . l:lint_cmd
return ale#path#BufferCdString(a:buffer)
\ . 'Rscript -e '
\ . 'Rscript --vanilla -e '
\ . ale#Escape(l:cmd_string) . ' %t'
endfunction

View File

@@ -4,21 +4,27 @@
call ale#Set('ruby_reek_show_context', 0)
call ale#Set('ruby_reek_show_wiki_link', 0)
function! ale_linters#ruby#reek#Handle(buffer, lines) abort
let l:output = []
function! ale_linters#ruby#reek#VersionCheck(buffer) abort
" If we have previously stored the version number in a cache, then
" don't look it up again.
if ale#semver#HasVersion('reek')
" Returning an empty string skips this command.
return ''
endif
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
for l:location in l:error.lines
call add(l:output, {
\ 'lnum': l:location,
\ 'type': 'W',
\ 'text': s:BuildText(a:buffer, l:error),
\ 'code': l:error.smell_type,
\})
endfor
endfor
return 'reek --version'
endfunction
return l:output
function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort
let l:version = ale#semver#GetVersion('reek', a:version_output)
" Tell reek what the filename is if the version of reek is new enough.
let l:display_name_args = ale#semver#GTE(l:version, [5, 0, 0])
\ ? ' --stdin-filename %s'
\ : ''
return 'reek -f json --no-progress --no-color'
\ . l:display_name_args
endfunction
function! s:BuildText(buffer, error) abort
@@ -37,9 +43,29 @@ function! s:BuildText(buffer, error) abort
return join(l:parts, ' ')
endfunction
function! ale_linters#ruby#reek#Handle(buffer, lines) abort
let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
for l:location in l:error.lines
call add(l:output, {
\ 'lnum': l:location,
\ 'type': 'W',
\ 'text': s:BuildText(a:buffer, l:error),
\ 'code': l:error.smell_type,
\})
endfor
endfor
return l:output
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'reek',
\ 'executable': 'reek',
\ 'command': 'reek -f json --no-progress --no-color',
\ 'command_chain': [
\ {'callback': 'ale_linters#ruby#reek#VersionCheck'},
\ {'callback': 'ale_linters#ruby#reek#GetCommand'},
\ ],
\ 'callback': 'ale_linters#ruby#reek#Handle',
\})

View File

@@ -4,6 +4,9 @@
call ale#Set('rust_cargo_use_check', 1)
call ale#Set('rust_cargo_check_all_targets', 0)
call ale#Set('rust_cargo_check_examples', 0)
call ale#Set('rust_cargo_check_tests', 0)
call ale#Set('rust_cargo_avoid_whole_workspace', 1)
call ale#Set('rust_cargo_default_feature_behavior', 'default')
call ale#Set('rust_cargo_include_features', '')
@@ -31,12 +34,30 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
let l:use_all_targets = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_all_targets')
\ && ale#semver#GTE(l:version, [0, 22, 0])
let l:use_examples = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_examples')
\ && ale#semver#GTE(l:version, [0, 22, 0])
let l:use_tests = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(l:version, [0, 22, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
if !empty(l:include_features)
let l:include_features = ' --features ' . ale#Escape(l:include_features)
endif
let l:avoid_whole_workspace = ale#Var(a:buffer, 'rust_cargo_avoid_whole_workspace')
let l:nearest_cargo_prefix = ''
if l:avoid_whole_workspace
let l:nearest_cargo = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
let l:nearest_cargo_dir = fnamemodify(l:nearest_cargo, ':h')
if l:nearest_cargo_dir isnot# '.'
let l:nearest_cargo_prefix = 'cd '. ale#Escape(l:nearest_cargo_dir) .' && '
endif
endif
let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior')
if l:default_feature_behavior is# 'all'
let l:include_features = ''
@@ -47,9 +68,11 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
let l:default_feature = ''
endif
return 'cargo '
return l:nearest_cargo_prefix . 'cargo '
\ . (l:use_check ? 'check' : 'build')
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features

View File

@@ -0,0 +1,33 @@
" Author: Christian Höltje (https://docwhat.org/)
" Description: BASH Language server integration for ALE
scriptencoding utf-8
call ale#Set('sh_language_server_executable', 'bash-language-server')
call ale#Set('sh_language_server_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#sh#language_server#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'sh_language_server', [
\ 'node_modules/.bin/bash-language-server',
\])
endfunction
function! ale_linters#sh#language_server#GetCommand(buffer) abort
let l:exe = ale#Escape(ale_linters#sh#language_server#GetExecutable(a:buffer))
return l:exe . ' start'
endfunction
function! ale_linters#sh#language_server#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
call ale#linter#Define('sh', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#sh#language_server#GetExecutable',
\ 'command_callback': 'ale_linters#sh#language_server#GetCommand',
\ 'language': 'sh',
\ 'project_root_callback': 'ale_linters#sh#language_server#GetProjectRoot',
\})

View File

@@ -20,7 +20,7 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:generators = ['cpp']
endif
let l:output_dir = tempname()
let l:output_dir = ale#util#Tempname()
call mkdir(l:output_dir)
call ale#engine#ManageDirectory(a:buffer, l:output_dir)

View File

@@ -7,7 +7,7 @@ if !exists('g:ale_verilog_verilator_options')
endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = tempname() . '_verilator_linted.v'
let l:filename = ale#util#Tempname() . '_verilator_linted.v'
" Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename)

View File

@@ -20,21 +20,31 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
" Matches patterns line the following:
" something.yaml:1:1: [warning] missing document start "---" (document-start)
" something.yml:2:1: [error] syntax error: expected the node content, but found '<stream end>'
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \[\(error\|warning\)\] \(.\+\)$'
let l:pattern = '\v^.*:(\d+):(\d+): \[(error|warning)\] (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:line = l:match[1] + 0
let l:col = l:match[2] + 0
let l:type = l:match[3]
let l:text = l:match[4]
let l:item = {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4],
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
\}
call add(l:output, {
\ 'lnum': l:line,
\ 'col': l:col,
\ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W',
\})
let l:code_match = matchlist(l:item.text, '\v^(.+) \(([^)]+)\)$')
if !empty(l:code_match)
if l:code_match[2] is# 'trailing-spaces'
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
" Skip warnings for trailing whitespace if the option is off.
continue
endif
let l:item.text = l:code_match[1]
let l:item.code = l:code_match[2]
endif
call add(l:output, l:item)
endfor
return l:output

View File

@@ -6,35 +6,12 @@
let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error')
let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info')
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
" Ignoring linters, for disabling some, or ignoring LSP diagnostics.
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
let s:lint_timer = -1
let s:queued_buffer_number = -1
let s:should_lint_file_for_buffer = {}
let s:error_delay_ms = 1000 * 60 * 2
let s:timestamp_map = {}
" Given a key for a script variable for tracking the time to wait until
" a given function should be called, a funcref for a function to call, and
" a List of arguments, call the function and return whatever value it returns.
"
" If the function throws an exception, then the function will not be called
" for a while, and 0 will be returned instead.
function! ale#CallWithCooldown(timestamp_key, func, arglist) abort
let l:now = ale#util#ClockMilliseconds()
if l:now < get(s:timestamp_map, a:timestamp_key, -1)
return 0
endif
let s:timestamp_map[a:timestamp_key] = l:now + s:error_delay_ms
let l:return_value = call(a:func, a:arglist)
let s:timestamp_map[a:timestamp_key] = -1
return l:return_value
endfunction
" Return 1 if a file is too large for ALE to handle.
function! ale#FileTooLarge(buffer) abort
@@ -114,30 +91,22 @@ function! ale#Queue(delay, ...) abort
let l:linting_flag = get(a:000, 0, '')
let l:buffer = get(a:000, 1, bufnr(''))
return ale#CallWithCooldown(
\ 'dont_queue_until',
\ function('s:ALEQueueImpl'),
\ [a:delay, l:linting_flag, l:buffer],
\)
endfunction
function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
if a:linting_flag isnot# '' && a:linting_flag isnot# 'lint_file'
if l:linting_flag isnot# '' && l:linting_flag isnot# 'lint_file'
throw "linting_flag must be either '' or 'lint_file'"
endif
if type(a:buffer) != type(0)
if type(l:buffer) != type(0)
throw 'buffer_number must be a Number'
endif
if ale#ShouldDoNothing(a:buffer)
if ale#ShouldDoNothing(l:buffer)
return
endif
" Remember that we want to check files for this buffer.
" We will remember this until we finally run the linters, via any event.
if a:linting_flag is# 'lint_file'
let s:should_lint_file_for_buffer[a:buffer] = 1
if l:linting_flag is# 'lint_file'
let s:should_lint_file_for_buffer[l:buffer] = 1
endif
if s:lint_timer != -1
@@ -145,24 +114,24 @@ function! s:ALEQueueImpl(delay, linting_flag, buffer) abort
let s:lint_timer = -1
endif
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
" Don't set up buffer data and so on if there are no linters to run.
if empty(l:linters)
" If we have some previous buffer data, then stop any jobs currently
" running and clear everything.
if has_key(g:ale_buffer_info, a:buffer)
call ale#engine#RunLinters(a:buffer, [], 1)
if has_key(g:ale_buffer_info, l:buffer)
call ale#engine#RunLinters(l:buffer, [], 1)
endif
return
endif
if a:delay > 0
let s:queued_buffer_number = a:buffer
let s:queued_buffer_number = l:buffer
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
else
call ale#Lint(-1, a:buffer)
call ale#Lint(-1, l:buffer)
endif
endfunction
@@ -178,30 +147,29 @@ function! ale#Lint(...) abort
let l:buffer = bufnr('')
endif
return ale#CallWithCooldown(
\ 'dont_lint_until',
\ function('s:ALELintImpl'),
\ [l:buffer],
\)
endfunction
function! s:ALELintImpl(buffer) abort
if ale#ShouldDoNothing(a:buffer)
if ale#ShouldDoNothing(l:buffer)
return
endif
" Use the filetype from the buffer
let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype'))
let l:filetype = getbufvar(l:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype)
let l:should_lint_file = 0
" Check if we previously requested checking the file.
if has_key(s:should_lint_file_for_buffer, a:buffer)
unlet s:should_lint_file_for_buffer[a:buffer]
if has_key(s:should_lint_file_for_buffer, l:buffer)
unlet s:should_lint_file_for_buffer[l:buffer]
" Lint files if they exist.
let l:should_lint_file = filereadable(expand('#' . a:buffer . ':p'))
let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
endif
call ale#engine#RunLinters(a:buffer, l:linters, l:should_lint_file)
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(l:buffer, 'linters_ignore')
let l:linters = !empty(l:ignore_config)
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
\ : l:linters
call ale#engine#RunLinters(l:buffer, l:linters, l:should_lint_file)
endfunction
" Reset flags indicating that files should be checked for all buffers.
@@ -209,10 +177,6 @@ function! ale#ResetLintFileMarkers() abort
let s:should_lint_file_for_buffer = {}
endfunction
function! ale#ResetErrorDelays() abort
let s:timestamp_map = {}
endfunction
let g:ale_has_override = get(g:, 'ale_has_override', {})
" Call has(), but check a global Dictionary so we can force flags on or off

View File

@@ -1,77 +0,0 @@
function! ale#autocmd#InitAuGroups() abort
" This value used to be a Boolean as a Number, and is now a String.
let l:text_changed = '' . g:ale_lint_on_text_changed
augroup ALEPatternOptionsGroup
autocmd!
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
augroup END
augroup ALERunOnTextChangedGroup
autocmd!
if g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1'
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'normal'
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'insert'
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
endif
endif
augroup END
augroup ALERunOnEnterGroup
autocmd!
if g:ale_enabled
" Handle everything that needs to happen when buffers are entered.
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
endif
if g:ale_enabled && g:ale_lint_on_enter
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
" Track when the file is changed outside of Vim.
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
endif
augroup END
augroup ALERunOnFiletypeChangeGroup
autocmd!
if g:ale_enabled && g:ale_lint_on_filetype_changed
" Only start linting if the FileType actually changes after
" opening a buffer. The FileType will fire when buffers are opened.
autocmd FileType * call ale#events#FileTypeEvent(
\ str2nr(expand('<abuf>')),
\ expand('<amatch>')
\)
endif
augroup END
augroup ALERunOnSaveGroup
autocmd!
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
augroup END
augroup ALERunOnInsertLeave
autocmd!
if g:ale_enabled && g:ale_lint_on_insert_leave
autocmd InsertLeave * call ale#Queue(0)
endif
augroup END
augroup ALECursorGroup
autocmd!
if g:ale_enabled && g:ale_echo_cursor
autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay()
" Look for a warning to echo as soon as we leave Insert mode.
" The script's position variable used when moving the cursor will
" not be changed here.
autocmd InsertLeave * call ale#cursor#EchoCursorWarning()
endif
augroup END
if !g:ale_enabled
augroup! ALERunOnTextChangedGroup
augroup! ALERunOnEnterGroup
augroup! ALERunOnInsertLeave
augroup! ALECursorGroup
endif
endfunction

View File

@@ -34,7 +34,11 @@ function! ale#balloon#Expr() abort
endfunction
function! ale#balloon#Disable() abort
set noballooneval noballoonevalterm
if has('balloon_eval_term')
set noballoonevalterm
endif
set noballooneval
set balloonexpr=
endfunction

View File

@@ -13,7 +13,7 @@ function! s:TemporaryFilename(buffer) abort
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
return tempname() . (has('win32') ? '\' : '/') . l:filename
return ale#util#Tempname() . (has('win32') ? '\' : '/') . l:filename
endfunction
" Given a command string, replace every...

View File

@@ -317,7 +317,7 @@ function! ale#completion#ParseLSPCompletions(response) abort
\ 'word': l:word,
\ 'kind': l:kind,
\ 'icase': 1,
\ 'menu': l:item.detail,
\ 'menu': get(l:item, 'detail', ''),
\ 'info': get(l:item, 'documentation', ''),
\})
endfor
@@ -389,14 +389,13 @@ function! s:GetLSPCompletions(linter) abort
\ ? function('ale#completion#HandleTSServerResponse')
\ : function('ale#completion#HandleLSPResponse')
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Completions(
@@ -408,7 +407,7 @@ function! s:GetLSPCompletions(linter) abort
else
" Send a message saying the buffer has changed first, otherwise
" completions won't know what text is nearby.
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
call ale#lsp#NotifyForChanges(l:lsp_details)
" For LSP completions, we need to clamp the column to the length of
" the line. python-language-server and perhaps others do not implement
@@ -424,7 +423,7 @@ function! s:GetLSPCompletions(linter) abort
\)
endif
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
if l:request_id
let b:ale_completion_info.conn_id = l:id

View File

@@ -56,10 +56,6 @@ function! s:StopCursorTimer() abort
endfunction
function! ale#cursor#EchoCursorWarning(...) abort
return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), [])
endfunction
function! s:EchoImpl() abort
if !g:ale_echo_cursor
return
endif

View File

@@ -214,10 +214,15 @@ function! ale#debugging#Info() abort
" This must be done after linters are loaded.
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype)
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '')
call s:Echo(' Current Filetype: ' . l:filetype)
call s:Echo('Available Linters: ' . string(l:all_names))
call s:EchoLinterAliases(l:all_linters)
call s:Echo(' Enabled Linters: ' . string(l:enabled_names))
call s:Echo(' Suggested Fixers: ' . l:fixers_string)
call s:Echo(' Linter Variables:')
call s:Echo('')
call s:EchoLinterVariables(l:variable_list)

View File

@@ -22,7 +22,7 @@ function! ale#definition#HandleTSServerResponse(conn_id, response) abort
\&& has_key(s:go_to_definition_map, a:response.request_seq)
let l:options = remove(s:go_to_definition_map, a:response.request_seq)
if get(a:response, 'success', v:false) is v:true
if get(a:response, 'success', v:false) is v:true && !empty(a:response.body)
let l:filename = a:response.body[0].file
let l:line = a:response.body[0].start.line
let l:column = a:response.body[0].start.offset
@@ -65,14 +65,13 @@ function! s:GoToLSPDefinition(linter, options) abort
\ ? function('ale#definition#HandleTSServerResponse')
\ : function('ale#definition#HandleLSPResponse')
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Definition(
@@ -83,7 +82,7 @@ function! s:GoToLSPDefinition(linter, options) abort
else
" Send a message saying the buffer has changed first, or the
" definition position probably won't make sense.
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
call ale#lsp#NotifyForChanges(l:lsp_details)
let l:column = min([l:column, len(getline(l:line))])
@@ -93,7 +92,7 @@ function! s:GoToLSPDefinition(linter, options) abort
let l:message = ale#lsp#message#Definition(l:buffer, l:line, l:column)
endif
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
let s:go_to_definition_map[l:request_id] = {
\ 'open_in_tab': get(a:options, 'open_in_tab', 0),

View File

@@ -14,11 +14,6 @@ if !has_key(s:, 'job_info_map')
let s:job_info_map = {}
endif
" Associates LSP connection IDs with linter names.
if !has_key(s:, 'lsp_linter_map')
let s:lsp_linter_map = {}
endif
if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {}
endif
@@ -79,16 +74,6 @@ function! ale#engine#InitBufferInfo(buffer) abort
return 0
endfunction
" Clear LSP linter data for the linting engine.
function! ale#engine#ClearLSPData() abort
let s:lsp_linter_map = {}
endfunction
" Just for tests.
function! ale#engine#SetLSPLinterMap(replacement_map) abort
let s:lsp_linter_map = a:replacement_map
endfunction
" This function is documented and part of the public API.
"
" Return 1 if ALE is busy checking a given buffer
@@ -113,7 +98,7 @@ endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
let l:temporary_directory = tempname()
let l:temporary_directory = ale#util#Tempname()
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:temporary_directory, '', 0750)
@@ -236,93 +221,16 @@ function! s:HandleExit(job_id, exit_code) abort
call ale#history#RememberOutput(l:buffer, a:job_id, l:output[:])
endif
try
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
" Handle the function being unknown, or being deleted.
catch /E700/
let l:loclist = []
endtry
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename)
if l:buffer <= 0
return
endif
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:buffer = bufnr(a:response.body.file)
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
return
endif
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
" tsserver sends syntax and semantic errors in separate messages, so we
" have to collect the messages separately for each buffer and join them
" back together again.
if a:error_type is# 'syntax'
let l:info.syntax_loclist = l:thislist
else
let l:info.semantic_loclist = l:thislist
endif
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
call ale#engine#HandleLoclist('tsserver', l:buffer, l:loclist)
endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort
if !g:ale_history_enabled || !g:ale_history_log_output
return
endif
if empty(a:linter_name)
return
endif
let l:message = ale#lsp#response#GetErrorMessage(a:response)
if empty(l:message)
return
endif
" This global variable is set here so we don't load the debugging.vim file
" until someone uses :ALEInfo.
let g:ale_lsp_error_messages = get(g:, 'ale_lsp_error_messages', {})
if !has_key(g:ale_lsp_error_messages, a:linter_name)
let g:ale_lsp_error_messages[a:linter_name] = []
endif
call add(g:ale_lsp_error_messages[a:linter_name], l:message)
endfunction
function! ale#engine#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '')
let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
call s:HandleLSPErrorMessage(l:linter_name, a:response)
elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response)
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'semanticDiag'
call s:HandleTSServerDiagnostics(a:response, 'semantic')
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'syntaxDiag'
call s:HandleTSServerDiagnostics(a:response, 'syntax')
endif
endfunction
function! ale#engine#SetResults(buffer, loclist) abort
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
@@ -367,9 +275,6 @@ function! ale#engine#SetResults(buffer, loclist) abort
" Call user autocommands. This allows users to hook into ALE's lint cycle.
silent doautocmd <nomodeline> User ALELintPost
" remove in 2.0
" Old DEPRECATED name; call it for backwards compatibility.
silent doautocmd <nomodeline> User ALELint
endif
endfunction
@@ -739,44 +644,6 @@ function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort
let l:info.active_linter_list = l:new_active_linter_list
endfunction
function! s:CheckWithLSP(buffer, linter) abort
let l:info = g:ale_buffer_info[a:buffer]
let l:lsp_details = ale#linter#StartLSP(
\ a:buffer,
\ a:linter,
\ function('ale#engine#HandleLSPResponse'),
\)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
" Remember the linter this connection is for.
let s:lsp_linter_map[l:id] = a:linter.name
let l:change_message = a:linter.lsp is# 'tsserver'
\ ? ale#lsp#tsserver_message#Geterr(a:buffer)
\ : ale#lsp#message#DidChange(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:change_message, l:root)
" If this was a file save event, also notify the server of that.
if a:linter.lsp isnot# 'tsserver'
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0)
let l:save_message = ale#lsp#message#DidSave(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:save_message, l:root)
endif
if l:request_id != 0
if index(l:info.active_linter_list, a:linter.name) < 0
call add(l:info.active_linter_list, a:linter.name)
endif
endif
return l:request_id != 0
endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
@@ -832,7 +699,7 @@ endfunction
" Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter) abort
if !empty(a:linter.lsp)
return s:CheckWithLSP(a:buffer, a:linter)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
@@ -914,7 +781,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 = ale#util#ClockMilliseconds()
let l:start_time = ale#events#ClockMilliseconds()
if l:start_time == 0
throw 'Failed to read milliseconds from the clock!'
@@ -945,7 +812,7 @@ function! ale#engine#WaitForJobs(deadline) abort
for l:job_id in l:job_list
if ale#job#IsRunning(l:job_id)
let l:now = ale#util#ClockMilliseconds()
let l:now = ale#events#ClockMilliseconds()
if l:now - l:start_time > a:deadline
" Stop waiting after a timeout, so we don't wait forever.
@@ -982,7 +849,7 @@ function! ale#engine#WaitForJobs(deadline) abort
if l:has_new_jobs
" We have to wait more. Offset the timeout by the time taken so far.
let l:now = ale#util#ClockMilliseconds()
let l:now = ale#events#ClockMilliseconds()
let l:new_deadline = a:deadline - (l:now - l:start_time)
if l:new_deadline <= 0

View File

@@ -0,0 +1,46 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Code for ignoring linters. Only loaded and if configured.
" Given a filetype and a configuration for ignoring linters, return a List of
" Strings for linter names to ignore.
function! ale#engine#ignore#GetList(filetype, config) abort
if type(a:config) is type([])
return a:config
endif
if type(a:config) is type({})
let l:names_to_remove = []
for l:part in split(a:filetype , '\.')
call extend(l:names_to_remove, get(a:config, l:part, []))
endfor
return l:names_to_remove
endif
return []
endfunction
" Given a List of linter descriptions, exclude the linters to be ignored.
function! ale#engine#ignore#Exclude(filetype, all_linters, config) abort
let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config)
let l:filtered_linters = []
for l:linter in a:all_linters
let l:name_list = [l:linter.name] + l:linter.aliases
let l:should_include = 1
for l:name in l:name_list
if index(l:names_to_remove, l:name) >= 0
let l:should_include = 0
break
endif
endfor
if l:should_include
call add(l:filtered_linters, l:linter)
endif
endfor
return l:filtered_linters
endfunction

View File

@@ -1,14 +1,25 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: ALE functions for autocmd events.
" Get the number of milliseconds since some vague, but consistent, point in
" the past.
"
" This function can be used for timing execution, etc.
"
" The time will be returned as a Number.
function! ale#events#ClockMilliseconds() abort
return float2nr(reltimefloat(reltime()) * 1000)
endfunction
function! ale#events#QuitEvent(buffer) abort
" Remember when ALE is quitting for BufWrite, etc.
call setbufvar(a:buffer, 'ale_quitting', ale#util#ClockMilliseconds())
call setbufvar(a:buffer, 'ale_quitting', ale#events#ClockMilliseconds())
endfunction
function! ale#events#QuitRecently(buffer) abort
let l:time = getbufvar(a:buffer, 'ale_quitting', 0)
return l:time && ale#util#ClockMilliseconds() - l:time < 1000
return l:time && ale#events#ClockMilliseconds() - l:time < 1000
endfunction
function! ale#events#SaveEvent(buffer) abort
@@ -67,3 +78,56 @@ function! ale#events#FileChangedEvent(buffer) abort
call s:LintOnEnter(a:buffer)
endif
endfunction
function! ale#events#Init() abort
" This value used to be a Boolean as a Number, and is now a String.
let l:text_changed = '' . g:ale_lint_on_text_changed
augroup ALEEvents
autocmd!
" These events always need to be set up.
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
if g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1'
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'normal'
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'insert'
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
endif
" Handle everything that needs to happen when buffers are entered.
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
if g:ale_lint_on_enter
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
" Track when the file is changed outside of Vim.
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
endif
if g:ale_lint_on_filetype_changed
" Only start linting if the FileType actually changes after
" opening a buffer. The FileType will fire when buffers are opened.
autocmd FileType * call ale#events#FileTypeEvent(
\ str2nr(expand('<abuf>')),
\ expand('<amatch>')
\)
endif
if g:ale_lint_on_insert_leave
autocmd InsertLeave * call ale#Queue(0)
endif
if g:ale_echo_cursor
autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif
" Look for a warning to echo as soon as we leave Insert mode.
" The script's position variable used when moving the cursor will
" not be changed here.
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif
endif
endif
augroup END
endfunction

View File

@@ -356,9 +356,21 @@ function! s:RunFixer(options) abort
call ale#fix#ApplyFixes(l:buffer, l:input)
endfunction
function! s:GetCallbacks(buffer, linters) abort
if len(a:linters)
let l:callback_list = a:linters
function! s:AddSubCallbacks(full_list, callbacks) abort
if type(a:callbacks) == type('')
call add(a:full_list, a:callbacks)
elseif type(a:callbacks) == type([])
call extend(a:full_list, a:callbacks)
else
return 0
endif
return 1
endfunction
function! s:GetCallbacks(buffer, fixers) abort
if len(a:fixers)
let l:callback_list = a:fixers
elseif type(get(b:, 'ale_fixers')) is type([])
" Lists can be used for buffer-local variables only
let l:callback_list = b:ale_fixers
@@ -367,16 +379,18 @@ function! s:GetCallbacks(buffer, linters) abort
" callbacks to run.
let l:fixers = ale#Var(a:buffer, 'fixers')
let l:callback_list = []
let l:matched = 0
for l:sub_type in split(&filetype, '\.')
let l:sub_type_callacks = get(l:fixers, l:sub_type, [])
if type(l:sub_type_callacks) == type('')
call add(l:callback_list, l:sub_type_callacks)
else
call extend(l:callback_list, l:sub_type_callacks)
if s:AddSubCallbacks(l:callback_list, get(l:fixers, l:sub_type))
let l:matched = 1
endif
endfor
" If we couldn't find fixers for a filetype, default to '*' fixers.
if !l:matched
call s:AddSubCallbacks(l:callback_list, get(l:fixers, '*'))
endif
endif
if empty(l:callback_list)

View File

@@ -22,6 +22,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with black.',
\ },
\ 'tidy': {
\ 'function': 'ale#fixers#tidy#Fix',
\ 'suggested_filetypes': ['html'],
\ 'description': 'Fix HTML files with tidy.',
\ },
\ 'prettier_standard': {
\ 'function': 'ale#fixers#prettier_standard#Fix',
\ 'suggested_filetypes': ['javascript'],
@@ -51,7 +56,7 @@ let s:default_registry = {
\ },
\ 'prettier': {
\ 'function': 'ale#fixers#prettier#Fix',
\ 'suggested_filetypes': ['javascript', 'typescript', 'json', 'css', 'scss', 'less', 'markdown', 'graphql', 'vue'],
\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue'],
\ 'description': 'Apply prettier to a file.',
\ },
\ 'prettier_eslint': {
@@ -95,6 +100,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['ruby'],
\ 'description': 'Fix ruby files with rufo',
\ },
\ 'scalafmt': {
\ 'function': 'ale#fixers#scalafmt#Fix',
\ 'suggested_filetypes': ['scala'],
\ 'description': 'Fix Scala files using scalafmt',
\ },
\ 'standard': {
\ 'function': 'ale#fixers#standard#Fix',
\ 'suggested_filetypes': ['javascript'],
@@ -195,6 +205,16 @@ let s:default_registry = {
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Fix JavaScript files using xo --fix.',
\ },
\ 'qmlfmt': {
\ 'function': 'ale#fixers#qmlfmt#Fix',
\ 'suggested_filetypes': ['qml'],
\ 'description': 'Fix QML files with qmlfmt.',
\ },
\ 'dartfmt': {
\ 'function': 'ale#fixers#dartfmt#Fix',
\ 'suggested_filetypes': ['dart'],
\ 'description': 'Fix Dart files with dartfmt.',
\ },
\}
" Reset the function registry to the default entries.
@@ -335,8 +355,7 @@ function! ale#fix#registry#CompleteFixers(ArgLead, CmdLine, CursorPos) abort
return filter(ale#fix#registry#GetApplicableFixers(&filetype), 'v:val =~? a:ArgLead')
endfunction
" Suggest functions to use from the registry.
function! ale#fix#registry#Suggest(filetype) abort
function! ale#fix#registry#SuggestedFixers(filetype) abort
let l:type_list = split(a:filetype, '\.')
let l:filetype_fixer_list = []
@@ -362,6 +381,15 @@ function! ale#fix#registry#Suggest(filetype) abort
endif
endfor
return [l:filetype_fixer_list, l:generic_fixer_list]
endfunction
" Suggest functions to use from the registry.
function! ale#fix#registry#Suggest(filetype) abort
let l:suggested = ale#fix#registry#SuggestedFixers(a:filetype)
let l:filetype_fixer_list = l:suggested[0]
let l:generic_fixer_list = l:suggested[1]
let l:filetype_fixer_header = !empty(l:filetype_fixer_list)
\ ? ['Try the following fixers appropriate for the filetype:', '']
\ : []

View File

@@ -0,0 +1,18 @@
" Author: reisub0 <reisub0@gmail.com>
" Description: Integration of dartfmt with ALE.
call ale#Set('dart_dartfmt_executable', 'dartfmt')
call ale#Set('dart_dartfmt_options', '')
function! ale#fixers#dartfmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'dart_dartfmt_executable')
let l:options = ale#Var(a:buffer, 'dart_dartfmt_options')
return {
\ 'command': ale#Escape(l:executable)
\ . ' -w'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -30,8 +30,26 @@ endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
let l:parser = ''
" Append the --parser flag depending on the current filetype (unless it's
" already set in g:javascript_prettier_options).
if empty(expand('#' . a:buffer . ':e')) && match(l:options, '--parser') == -1
let l:prettier_parsers = ['typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue']
let l:parser = 'babylon'
for l:filetype in split(getbufvar(a:buffer, '&filetype'), '\.')
if index(l:prettier_parsers, l:filetype) > -1
let l:parser = l:filetype
break
endif
endfor
endif
if !empty(l:parser)
let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--parser ' . l:parser
endif
" 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(l:version, [1, 4, 0])

View File

@@ -0,0 +1,11 @@
call ale#Set('qml_qmlfmt_executable', 'qmlfmt')
function! ale#fixers#qmlfmt#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'qml_qmlfmt_executable')
endfunction
function! ale#fixers#qmlfmt#Fix(buffer) abort
return {
\ 'command': ale#Escape(ale#fixers#qmlfmt#GetExecutable(a:buffer)),
\}
endfunction

View File

@@ -0,0 +1,26 @@
" Author: Jeffrey Lau https://github.com/zoonfafer
" Description: Integration of Scalafmt with ALE.
call ale#Set('scala_scalafmt_executable', 'scalafmt')
call ale#Set('scala_scalafmt_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('scala_scalafmt_options', '')
function! ale#fixers#scalafmt#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'scala_scalafmt_executable')
let l:options = ale#Var(a:buffer, 'scala_scalafmt_options')
let l:exec_args = l:executable =~? 'ng$'
\ ? ' scalafmt'
\ : ''
return ale#Escape(l:executable) . l:exec_args
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t'
endfunction
function! ale#fixers#scalafmt#Fix(buffer) abort
return {
\ 'command': ale#fixers#scalafmt#GetCommand(a:buffer),
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -0,0 +1,26 @@
" Author: meain <abinsimon10@gmail.com>
" Description: Fixing HTML files with tidy.
call ale#Set('html_tidy_executable', 'tidy')
call ale#Set('html_tidy_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#tidy#Fix(buffer) abort
let l:executable = ale#node#FindExecutable(
\ a:buffer,
\ 'html_tidy',
\ ['tidy'],
\)
if !executable(l:executable)
return 0
endif
let l:config = ale#path#FindNearestFile(a:buffer, '.tidyrc')
let l:config_options = !empty(l:config)
\ ? ' -q --tidy-mark no --show-errors 0 --show-warnings 0 -config ' . ale#Escape(l:config)
\ : ' -q --tidy-mark no --show-errors 0 --show-warnings 0'
return {
\ 'command': ale#Escape(l:executable) . l:config_options,
\}
endfunction

View File

@@ -2,7 +2,7 @@
" Description: Error handling for the format GHC outputs.
" Remember the directory used for temporary files for Vim.
let s:temp_dir = fnamemodify(tempname(), ':h')
let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')
" Build part of a regular expression for matching ALE temporary filenames.
let s:temp_regex_prefix =
\ '\M'

View File

@@ -97,14 +97,14 @@ function! s:ShowDetails(linter, buffer, line, column, opt) abort
\ ? function('ale#hover#HandleTSServerResponse')
\ : function('ale#hover#HandleLSPResponse')
let l:lsp_details = ale#linter#StartLSP(a:buffer, a:linter, l:Callback)
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter, l:Callback)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
let l:language_id = l:lsp_details.language_id
if a:linter.lsp is# 'tsserver'
let l:column = a:column
@@ -117,14 +117,14 @@ function! s:ShowDetails(linter, buffer, line, column, opt) abort
else
" Send a message saying the buffer has changed first, or the
" hover position probably won't make sense.
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(a:buffer), l:root)
call ale#lsp#NotifyForChanges(l:lsp_details)
let l:column = min([a:column, len(getbufline(a:buffer, a:line)[0])])
let l:message = ale#lsp#message#Hover(a:buffer, a:line, l:column)
endif
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
let s:hover_map[l:request_id] = {
\ 'buffer': a:buffer,

View File

@@ -26,34 +26,11 @@ function! s:KillHandler(timer) abort
call job_stop(l:job, 'kill')
endfunction
" Note that jobs and IDs are the same thing on NeoVim.
function! ale#job#JoinNeovimOutput(job, last_line, data, mode, callback) abort
if a:mode is# 'raw'
call a:callback(a:job, join(a:data, "\n"))
return ''
endif
let l:lines = a:data[:-2]
if len(a:data) > 1
let l:lines[0] = a:last_line . l:lines[0]
let l:new_last_line = a:data[-1]
else
let l:new_last_line = a:last_line . get(a:data, 0, '')
endif
for l:line in l:lines
call a:callback(a:job, l:line)
endfor
return l:new_last_line
endfunction
function! s:NeoVimCallback(job, data, event) abort
let l:info = s:job_map[a:job]
if a:event is# 'stdout'
let l:info.out_cb_line = ale#job#JoinNeovimOutput(
let l:info.out_cb_line = ale#util#JoinNeovimOutput(
\ a:job,
\ l:info.out_cb_line,
\ a:data,
@@ -61,7 +38,7 @@ function! s:NeoVimCallback(job, data, event) abort
\ ale#util#GetFunction(l:info.out_cb),
\)
elseif a:event is# 'stderr'
let l:info.err_cb_line = ale#job#JoinNeovimOutput(
let l:info.err_cb_line = ale#util#JoinNeovimOutput(
\ a:job,
\ l:info.err_cb_line,
\ a:data,

View File

@@ -15,6 +15,7 @@ let s:default_ale_linter_aliases = {
\ 'csh': 'sh',
\ 'plaintex': 'tex',
\ 'systemverilog': 'verilog',
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
\ 'vimwiki': 'markdown',
\ 'zsh': 'sh',
\}
@@ -227,6 +228,21 @@ function! ale#linter#PreProcess(linter) abort
throw '`completion_filter` must be a callback'
endif
endif
if has_key(a:linter, 'initialization_options_callback')
if has_key(a:linter, 'initialization_options')
throw 'Only one of `initialization_options` or '
\ . '`initialization_options_callback` should be set'
endif
let l:obj.initialization_options_callback = a:linter.initialization_options_callback
if !s:IsCallback(l:obj.initialization_options_callback)
throw '`initialization_options_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
endif
endif
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
@@ -436,72 +452,3 @@ function! ale#linter#GetAddress(buffer, linter) abort
\ ? ale#util#GetFunction(a:linter.address_callback)(a:buffer)
\ : a:linter.address
endfunction
" Given a buffer, an LSP linter, and a callback to register for handling
" messages, start up an LSP linter and get ready to receive errors or
" completions.
function! ale#linter#StartLSP(buffer, linter, callback) abort
let l:command = ''
let l:address = ''
let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
if empty(l:root) && a:linter.lsp isnot# 'tsserver'
" If there's no project root, then we can't check files with LSP,
" unless we are using tsserver, which doesn't use project roots.
return {}
endif
if a:linter.lsp is# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
let l:conn_id = ale#lsp#ConnectToAddress(
\ l:address,
\ l:root,
\ a:callback,
\)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if !executable(l:executable)
return {}
endif
let l:command = ale#job#PrepareCommand(
\ a:buffer,
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:conn_id = ale#lsp#StartProgram(
\ l:executable,
\ l:command,
\ l:root,
\ a:callback,
\)
endif
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
if !l:conn_id
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
endif
return {}
endif
if ale#lsp#OpenDocumentIfNeeded(l:conn_id, a:buffer, l:root, l:language_id)
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
endif
endif
" The change message needs to be sent for tsserver before doing anything.
if a:linter.lsp is# 'tsserver'
call ale#lsp#Send(l:conn_id, ale#lsp#tsserver_message#Change(a:buffer))
endif
return {
\ 'connection_id': l:conn_id,
\ 'command': l:command,
\ 'project_root': l:root,
\ 'language_id': l:language_id,
\}
endfunction

View File

@@ -3,21 +3,25 @@
" A List of connections, used for tracking servers which have been connected
" to, and programs which are run.
let s:connections = []
let s:connections = get(s:, 'connections', [])
let g:ale_lsp_next_message_id = 1
function! s:NewConnection() abort
" Exposed only so tests can get at it.
" Do not call this function basically anywhere.
function! ale#lsp#NewConnection(initialization_options) abort
" id: The job ID as a Number, or the server address as a string.
" data: The message data received so far.
" executable: An executable only set for program connections.
" open_documents: A list of buffers we told the server we opened.
" open_documents: A Dictionary mapping buffers to b:changedtick, keeping
" track of when documents were opened, and when we last changed them.
" callback_list: A list of callbacks for handling LSP responses.
let l:conn = {
\ 'id': '',
\ 'data': '',
\ 'projects': {},
\ 'open_documents': [],
\ 'open_documents': {},
\ 'callback_list': [],
\ 'initialization_options': a:initialization_options,
\}
call add(s:connections, l:conn)
@@ -25,9 +29,14 @@ function! s:NewConnection() abort
return l:conn
endfunction
" Remove an LSP connection with a given ID. This is only for tests.
function! ale#lsp#RemoveConnectionWithID(id) abort
call filter(s:connections, 'v:val.id isnot a:id')
endfunction
function! s:FindConnection(key, value) abort
for l:conn in s:connections
if has_key(l:conn, a:key) && get(l:conn, a:key) == a:value
if has_key(l:conn, a:key) && get(l:conn, a:key) is# a:value
return l:conn
endif
endfor
@@ -207,6 +216,11 @@ function! ale#lsp#HandleOtherInitializeResponses(conn, response) abort
endfunction
function! ale#lsp#HandleMessage(conn, message) abort
if type(a:message) != type('')
" Ignore messages that aren't strings.
return
endif
let a:conn.data .= a:message
" Parse the objects now if we can, and keep the remaining text.
@@ -227,9 +241,8 @@ function! ale#lsp#HandleMessage(conn, message) abort
endfor
endfunction
function! s:HandleChannelMessage(channel, message) abort
let l:info = ch_info(a:channel)
let l:address = l:info.hostname . l:info.address
function! s:HandleChannelMessage(channel_id, message) abort
let l:address = ale#socket#GetAddress(a:channel_id)
let l:conn = s:FindConnection('id', l:address)
call ale#lsp#HandleMessage(l:conn, a:message)
@@ -266,7 +279,7 @@ endfunction
"
" The job ID will be returned for for the program if it ran, otherwise
" 0 will be returned.
function! ale#lsp#StartProgram(executable, command, project_root, callback) abort
function! ale#lsp#StartProgram(executable, command, project_root, callback, initialization_options) abort
if !executable(a:executable)
return 0
endif
@@ -274,7 +287,7 @@ function! ale#lsp#StartProgram(executable, command, project_root, callback) abor
let l:conn = s:FindConnection('executable', a:executable)
" Get the current connection or a new one.
let l:conn = !empty(l:conn) ? l:conn : s:NewConnection()
let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:initialization_options)
let l:conn.executable = a:executable
if !has_key(l:conn, 'id') || !ale#job#IsRunning(l:conn.id)
@@ -300,21 +313,19 @@ function! ale#lsp#StartProgram(executable, command, project_root, callback) abor
endfunction
" Connect to an address and set up a callback for handling responses.
function! ale#lsp#ConnectToAddress(address, project_root, callback) abort
function! ale#lsp#ConnectToAddress(address, project_root, callback, initialization_options) abort
let l:conn = s:FindConnection('id', a:address)
" Get the current connection or a new one.
let l:conn = !empty(l:conn) ? l:conn : s:NewConnection()
let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:initialization_options)
if !has_key(l:conn, 'channel') || ch_status(l:conn.channel) isnot# 'open'
let l:conn.channnel = ch_open(a:address, {
\ 'mode': 'raw',
\ 'waittime': 0,
if !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id)
let l:conn.channel_id = ale#socket#Open(a:address, {
\ 'callback': function('s:HandleChannelMessage'),
\})
endif
if ch_status(l:conn.channnel) is# 'fail'
return 0
if l:conn.channel_id < 0
return ''
endif
let l:conn.id = a:address
@@ -322,15 +333,15 @@ function! ale#lsp#ConnectToAddress(address, project_root, callback) abort
call uniq(sort(add(l:conn.callback_list, a:callback)))
call ale#lsp#RegisterProject(l:conn, a:project_root)
return 1
return a:address
endfunction
" Stop all LSP connections, closing all jobs and channels, and removing any
" queued messages.
function! ale#lsp#StopAll() abort
for l:conn in s:connections
if has_key(l:conn, 'channel')
call ch_close(l:conn.channel)
if has_key(l:conn, 'channel_id')
call ale#socket#Close(l:conn.channel_id)
else
call ale#job#Stop(l:conn.id)
endif
@@ -342,9 +353,9 @@ endfunction
function! s:SendMessageData(conn, data) abort
if has_key(a:conn, 'executable')
call ale#job#SendRaw(a:conn.id, a:data)
elseif has_key(a:conn, 'channel') && ch_status(a:conn.channnel) is# 'open'
elseif has_key(a:conn, 'channel_id') && ale#socket#IsOpen(a:conn.channel_id)
" Send the message to the server
call ch_sendraw(a:conn.channel, a:data)
call ale#socket#Send(a:conn.channel_id, a:data)
else
return 0
endif
@@ -378,7 +389,7 @@ function! ale#lsp#Send(conn_id, message, ...) abort
" Only send the init message once.
if !l:project.init_request_id
let [l:init_id, l:init_data] = ale#lsp#CreateMessageData(
\ ale#lsp#message#Initialize(l:project_root),
\ ale#lsp#message#Initialize(l:project_root, l:conn.initialization_options),
\)
let l:project.init_request_id = l:init_id
@@ -400,21 +411,72 @@ function! ale#lsp#Send(conn_id, message, ...) abort
return l:id == 0 ? -1 : l:id
endfunction
function! ale#lsp#OpenDocumentIfNeeded(conn_id, buffer, project_root, language_id) abort
let l:conn = s:FindConnection('id', a:conn_id)
" The Document details Dictionary should contain the following keys.
"
" buffer - The buffer number for the document.
" connection_id - The connection ID for the LSP server.
" command - The command to run to start the LSP connection.
" project_root - The project root for the LSP project.
" language_id - The language ID for the project, like 'python', 'rust', etc.
" Create a new Dictionary containing more connection details, with the
" following information added:
"
" conn - An existing LSP connection for the document.
" document_open - 1 if the document is currently open, 0 otherwise.
function! s:ExtendDocumentDetails(details) abort
let l:extended = copy(a:details)
let l:conn = s:FindConnection('id', a:details.connection_id)
let l:extended.conn = l:conn
let l:extended.document_open = !empty(l:conn)
\ && has_key(l:conn.open_documents, a:details.buffer)
return l:extended
endfunction
" Notify LSP servers or tsserver if a document is opened, if needed.
" If a document is opened, 1 will be returned, otherwise 0 will be returned.
function! ale#lsp#OpenDocument(basic_details) abort
let l:d = s:ExtendDocumentDetails(a:basic_details)
let l:opened = 0
if !empty(l:conn) && index(l:conn.open_documents, a:buffer) < 0
if empty(a:language_id)
let l:message = ale#lsp#tsserver_message#Open(a:buffer)
if !empty(l:d.conn) && !l:d.document_open
if empty(l:d.language_id)
let l:message = ale#lsp#tsserver_message#Open(l:d.buffer)
else
let l:message = ale#lsp#message#DidOpen(a:buffer, a:language_id)
let l:message = ale#lsp#message#DidOpen(l:d.buffer, l:d.language_id)
endif
call ale#lsp#Send(a:conn_id, l:message, a:project_root)
call add(l:conn.open_documents, a:buffer)
call ale#lsp#Send(l:d.connection_id, l:message, l:d.project_root)
let l:d.conn.open_documents[l:d.buffer] = getbufvar(l:d.buffer, 'changedtick')
let l:opened = 1
endif
return l:opened
endfunction
" Notify LSP servers or tsserver that a document has changed, if needed.
" If a notification is sent, 1 will be returned, otherwise 0 will be returned.
function! ale#lsp#NotifyForChanges(basic_details) abort
let l:d = s:ExtendDocumentDetails(a:basic_details)
let l:notified = 0
if l:d.document_open
let l:new_tick = getbufvar(l:d.buffer, 'changedtick')
if l:d.conn.open_documents[l:d.buffer] < l:new_tick
if empty(l:d.language_id)
let l:message = ale#lsp#tsserver_message#Change(l:d.buffer)
else
let l:message = ale#lsp#message#DidChange(l:d.buffer)
endif
call ale#lsp#Send(l:d.connection_id, l:message, l:d.project_root)
let l:d.conn.open_documents[l:d.buffer] = l:new_tick
let l:notified = 1
endif
endif
return l:notified
endfunction

View File

@@ -24,12 +24,15 @@ function! ale#lsp#message#GetNextVersionID() abort
return l:id
endfunction
function! ale#lsp#message#Initialize(root_path) abort
function! ale#lsp#message#Initialize(root_path, initialization_options) abort
" TODO: Define needed capabilities.
" NOTE: rootPath is deprecated in favour of rootUri
return [0, 'initialize', {
\ 'processId': getpid(),
\ 'rootPath': a:root_path,
\ 'capabilities': {},
\ 'initializationOptions': a:initialization_options,
\ 'rootUri': ale#path#ToURI(a:root_path),
\}]
endfunction

View File

@@ -7,9 +7,9 @@ function! ale#lsp#reset#StopAllLSPs() abort
call ale#definition#ClearLSPData()
endif
if exists('*ale#engine#ClearLSPData')
if exists('*ale#lsp_linter#ClearLSPData')
" Clear the mapping for connections, etc.
call ale#engine#ClearLSPData()
call ale#lsp_linter#ClearLSPData()
" Remove the problems for all of the LSP linters in every buffer.
for l:buffer_string in keys(g:ale_buffer_info)

View File

@@ -105,12 +105,18 @@ function! ale#lsp#response#GetErrorMessage(response) abort
return ''
endif
" Include the traceback as details, if it's there.
let l:traceback = get(get(a:response.error, 'data', {}), 'traceback', [])
" Include the traceback or error data as details, if present.
let l:error_data = get(a:response.error, 'data', {})
if type(l:error_data) is type('')
let l:message .= "\n" . l:error_data
else
let l:traceback = get(l:error_data, 'traceback', [])
if type(l:traceback) is type([]) && !empty(l:traceback)
let l:message .= "\n" . join(l:traceback, "\n")
endif
endif
return l:message
endfunction

252
autoload/ale/lsp_linter.vim Normal file
View File

@@ -0,0 +1,252 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Integration between linters and LSP/tsserver.
" This code isn't loaded if a user never users LSP features or linters.
" Associates LSP connection IDs with linter names.
if !has_key(s:, 'lsp_linter_map')
let s:lsp_linter_map = {}
endif
" Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnore(buffer, linter_name) abort
let l:config = ale#Var(a:buffer, 'linters_ignore')
" Don't load code for ignoring diagnostics if there's nothing to ignore.
if empty(l:config)
return 0
endif
let l:filetype = getbufvar(a:buffer, '&filetype')
let l:ignore_list = ale#engine#ignore#GetList(l:filetype, l:config)
return index(l:ignore_list, a:linter_name) >= 0
endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename)
if s:ShouldIgnore(l:buffer, l:linter_name)
return
endif
if l:buffer <= 0
return
endif
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver'
let l:buffer = bufnr(a:response.body.file)
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
return
endif
if s:ShouldIgnore(l:buffer, l:linter_name)
return
endif
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
" tsserver sends syntax and semantic errors in separate messages, so we
" have to collect the messages separately for each buffer and join them
" back together again.
if a:error_type is# 'syntax'
let l:info.syntax_loclist = l:thislist
else
let l:info.semantic_loclist = l:thislist
endif
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort
if !g:ale_history_enabled || !g:ale_history_log_output
return
endif
if empty(a:linter_name)
return
endif
let l:message = ale#lsp#response#GetErrorMessage(a:response)
if empty(l:message)
return
endif
" This global variable is set here so we don't load the debugging.vim file
" until someone uses :ALEInfo.
let g:ale_lsp_error_messages = get(g:, 'ale_lsp_error_messages', {})
if !has_key(g:ale_lsp_error_messages, a:linter_name)
let g:ale_lsp_error_messages[a:linter_name] = []
endif
call add(g:ale_lsp_error_messages[a:linter_name], l:message)
endfunction
function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '')
let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
call s:HandleLSPErrorMessage(l:linter_name, a:response)
elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response)
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'semanticDiag'
call s:HandleTSServerDiagnostics(a:response, 'semantic')
elseif get(a:response, 'type', '') is# 'event'
\&& get(a:response, 'event', '') is# 'syntaxDiag'
call s:HandleTSServerDiagnostics(a:response, 'syntax')
endif
endfunction
" Given a buffer, an LSP linter, and a callback to register for handling
" messages, start up an LSP linter and get ready to receive errors or
" completions.
function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
let l:command = ''
let l:address = ''
let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
if empty(l:root) && a:linter.lsp isnot# 'tsserver'
" If there's no project root, then we can't check files with LSP,
" unless we are using tsserver, which doesn't use project roots.
return {}
endif
let l:initialization_options = {}
if has_key(a:linter, 'initialization_options_callback')
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
elseif has_key(a:linter, 'initialization_options')
let l:initialization_options = a:linter.initialization_options
endif
if a:linter.lsp is# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
let l:conn_id = ale#lsp#ConnectToAddress(
\ l:address,
\ l:root,
\ a:callback,
\ l:initialization_options,
\)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if !executable(l:executable)
return {}
endif
let l:command = ale#job#PrepareCommand(
\ a:buffer,
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:conn_id = ale#lsp#StartProgram(
\ l:executable,
\ l:command,
\ l:root,
\ a:callback,
\ l:initialization_options,
\)
endif
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
if empty(l:conn_id)
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
endif
return {}
endif
let l:details = {
\ 'buffer': a:buffer,
\ 'connection_id': l:conn_id,
\ 'command': l:command,
\ 'project_root': l:root,
\ 'language_id': l:language_id,
\}
if ale#lsp#OpenDocument(l:details)
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
endif
endif
" The change message needs to be sent for tsserver before doing anything.
if a:linter.lsp is# 'tsserver'
call ale#lsp#NotifyForChanges(l:details)
endif
return l:details
endfunction
function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
let l:info = g:ale_buffer_info[a:buffer]
let l:lsp_details = ale#lsp_linter#StartLSP(
\ a:buffer,
\ a:linter,
\ function('ale#lsp_linter#HandleLSPResponse'),
\)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
" Remember the linter this connection is for.
let s:lsp_linter_map[l:id] = a:linter.name
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Geterr(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
let l:notified = l:request_id != 0
else
let l:notified = ale#lsp#NotifyForChanges(l:lsp_details)
endif
" If this was a file save event, also notify the server of that.
if a:linter.lsp isnot# 'tsserver'
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0)
let l:save_message = ale#lsp#message#DidSave(a:buffer)
let l:request_id = ale#lsp#Send(l:id, l:save_message, l:root)
let l:notified = l:request_id != 0
endif
if l:notified
if index(l:info.active_linter_list, a:linter.name) < 0
call add(l:info.active_linter_list, a:linter.name)
endif
endif
return l:notified
endfunction
" Clear LSP linter data for the linting engine.
function! ale#lsp_linter#ClearLSPData() abort
let s:lsp_linter_map = {}
endfunction
" Just for tests.
function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort
let s:lsp_linter_map = a:replacement_map
endfunction

View File

@@ -84,7 +84,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(tempname(), ':h'))
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h'))
" Given a filename, return 1 if the file represents some temporary file
" created by Vim.

View File

@@ -23,7 +23,8 @@ function! s:CmpPatterns(left_item, right_item) abort
endfunction
function! ale#pattern_options#SetOptions(buffer) abort
if !g:ale_pattern_options_enabled || empty(g:ale_pattern_options)
if !get(g:, 'ale_pattern_options_enabled', 0)
\|| empty(get(g:, 'ale_pattern_options', 0))
return
endif

View File

@@ -2,22 +2,41 @@
" Description: Preview windows for showing whatever information in.
" Open a preview window and show some lines in it.
" An optional second argument can set an alternative filetype for the window.
" A second argument can be passed as a Dictionary with options. They are...
"
" filetype - The filetype to use, defaulting to 'ale-preview'
" stay_here - If 1, stay in the window you came from.
function! ale#preview#Show(lines, ...) abort
let l:filetype = get(a:000, 0, 'ale-preview')
let l:options = get(a:000, 0, {})
silent pedit ALEPreviewWindow
wincmd P
setlocal modifiable
setlocal noreadonly
setlocal nobuflisted
let &l:filetype = l:filetype
let &l:filetype = get(l:options, 'filetype', 'ale-preview')
setlocal buftype=nofile
setlocal bufhidden=wipe
:%d
call setline(1, a:lines)
setlocal nomodifiable
setlocal readonly
if get(l:options, 'stay_here')
wincmd p
endif
endfunction
" Close the preview window if the filetype matches the given one.
function! ale#preview#CloseIfTypeMatches(filetype) abort
for l:win in getwininfo()
let l:wintype = gettabwinvar(l:win.tabnr, l:win.winnr, '&filetype')
if l:wintype is# a:filetype
silent! pclose!
endif
endfor
endfunction
" Show a location selection preview window, given some items.
@@ -35,7 +54,7 @@ function! ale#preview#ShowSelection(item_list) abort
\)
endfor
call ale#preview#Show(l:lines, 'ale-preview-selection')
call ale#preview#Show(l:lines, {'filetype': 'ale-preview-selection'})
let b:ale_preview_item_list = a:item_list
endfunction

View File

@@ -72,14 +72,13 @@ function! s:FindReferences(linter) abort
\ ? function('ale#references#HandleTSServerResponse')
\ : function('ale#references#HandleLSPResponse')
let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback)
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:root = l:lsp_details.project_root
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#References(
@@ -90,14 +89,14 @@ function! s:FindReferences(linter) abort
else
" Send a message saying the buffer has changed first, or the
" references position probably won't make sense.
call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root)
call ale#lsp#NotifyForChanges(l:lsp_details)
let l:column = min([l:column, len(getline(l:line))])
let l:message = ale#lsp#message#References(l:buffer, l:line, l:column)
endif
let l:request_id = ale#lsp#Send(l:id, l:message, l:root)
let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
let s:references_map[l:request_id] = {}
endfunction

View File

@@ -45,14 +45,12 @@ if !hlexists('ALESignColumnWithErrors')
highlight link ALESignColumnWithErrors error
endif
if !hlexists('ALESignColumnWithoutErrors')
function! s:SetSignColumnWithoutErrorsHighlight() abort
function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort
redir => l:output
silent highlight SignColumn
0verbose silent highlight SignColumn
redir end
let l:highlight_syntax = join(split(l:output)[2:])
let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
if !empty(l:match)
@@ -60,10 +58,10 @@ if !hlexists('ALESignColumnWithoutErrors')
elseif l:highlight_syntax isnot# 'cleared'
execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax
endif
endfunction
endfunction
call s:SetSignColumnWithoutErrorsHighlight()
delfunction s:SetSignColumnWithoutErrorsHighlight
if !hlexists('ALESignColumnWithoutErrors')
call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight()
endif
" Signs show up on the left for error markers.

144
autoload/ale/socket.vim Normal file
View File

@@ -0,0 +1,144 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: APIs for working with asynchronous sockets, with an API
" normalised between Vim 8 and NeoVim. Socket connections only work in NeoVim
" 0.3+, and silently do nothing in earlier NeoVim versions.
"
" Important functions are described below. They are:
"
" ale#socket#Open(address, options) -> channel_id (>= 0 if successful)
" ale#socket#IsOpen(channel_id) -> 1 if open, 0 otherwise
" ale#socket#Close(channel_id)
" ale#socket#Send(channel_id, data)
" ale#socket#GetAddress(channel_id) -> Return the address for a job
let s:channel_map = get(s:, 'channel_map', {})
function! s:VimOutputCallback(channel, data) abort
let l:channel_id = ch_info(a:channel).id
" Only call the callbacks for jobs which are valid.
if l:channel_id >= 0 && has_key(s:channel_map, l:channel_id)
call ale#util#GetFunction(s:channel_map[l:channel_id].callback)(l:channel_id, a:data)
endif
endfunction
function! s:NeoVimOutputCallback(channel_id, data, event) abort
let l:info = s:channel_map[a:channel_id]
if a:event is# 'data'
let l:info.last_line = ale#util#JoinNeovimOutput(
\ a:channel_id,
\ l:info.last_line,
\ a:data,
\ l:info.mode,
\ ale#util#GetFunction(l:info.callback),
\)
endif
endfunction
" Open a socket for a given address. The following options are accepted:
"
" callback - A callback for receiving input. (required)
"
" A non-negative number representing a channel ID will be returned is the
" connection was successful. 0 is a valid channel ID in Vim, so test if the
" connection ID is >= 0.
function! ale#socket#Open(address, options) abort
let l:mode = get(a:options, 'mode', 'raw')
let l:Callback = a:options.callback
let l:channel_info = {
\ 'address': a:address,
\ 'mode': l:mode,
\ 'callback': a:options.callback,
\}
if !has('nvim')
" Vim
let l:channel_info.channel = ch_open(a:address, {
\ 'mode': l:mode,
\ 'waittime': 0,
\ 'callback': function('s:VimOutputCallback'),
\})
let l:vim_info = ch_info(l:channel_info.channel)
let l:channel_id = !empty(l:vim_info) ? l:vim_info.id : -1
elseif exists('*chansend') && exists('*sockconnect')
" NeoVim 0.3+
try
let l:channel_id = sockconnect('tcp', a:address, {
\ 'on_data': function('s:NeoVimOutputCallback'),
\})
let l:channel_info.last_line = ''
catch /connection failed/
let l:channel_id = -1
endtry
" 0 means the connection failed some times in NeoVim, so make the ID
" invalid to match Vim.
if l:channel_id is 0
let l:channel_id = -1
endif
let l:channel_info.channel = l:channel_id
else
" Other Vim versions.
let l:channel_id = -1
endif
if l:channel_id >= 0
let s:channel_map[l:channel_id] = l:channel_info
endif
return l:channel_id
endfunction
" Return 1 is a channel is open, 0 otherwise.
function! ale#socket#IsOpen(channel_id) abort
if !has_key(s:channel_map, a:channel_id)
return 0
endif
if has('nvim')
" In NeoVim, we have to check if this channel is in the global list.
return index(map(nvim_list_chans(), 'v:val.id'), a:channel_id) >= 0
endif
let l:channel = s:channel_map[a:channel_id].channel
return ch_status(l:channel) is# 'open'
endfunction
" Close a socket, if it's still open.
function! ale#socket#Close(channel_id) abort
" IsRunning isn't called here, so we don't check nvim_list_chans()
if !has_key(s:channel_map, a:channel_id)
return 0
endif
let l:channel = remove(s:channel_map, a:channel_id).channel
if has('nvim')
silent! call chanclose(l:channel)
elseif ch_status(l:channel) is# 'open'
call ch_close(l:channel)
endif
endfunction
" Send some data to a socket.
function! ale#socket#Send(channel_id, data) abort
if !has_key(s:channel_map, a:channel_id)
return
endif
let l:channel = s:channel_map[a:channel_id].channel
if has('nvim')
call chansend(l:channel, a:data)
else
call ch_sendraw(l:channel, a:data)
endif
endfunction
" Get an address for a channel, or an empty string.
function! ale#socket#GetAddress(channel_id) abort
return get(get(s:channel_map, a:channel_id, {}), 'address', '')
endfunction

View File

@@ -1,14 +1,6 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" Description: Statusline related function(s)
" remove in 2.0
"
" A deprecated setting for ale#statusline#Status()
" See :help ale#statusline#Count() for getting status reports.
let g:ale_statusline_format = get(g:, 'ale_statusline_format',
\ ['%d error(s)', '%d warning(s)', 'OK']
\)
function! s:CreateCountDict() abort
" Keys 0 and 1 are for backwards compatibility.
" The count object used to be a List of [error_count, warning_count].
@@ -76,47 +68,3 @@ function! ale#statusline#Count(buffer) abort
" The Dictionary is copied here before exposing it to other plugins.
return copy(s:GetCounts(a:buffer))
endfunction
" This is the historical format setting which could be configured before.
function! s:StatusForListFormat() abort
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
let l:counts = s:GetCounts(bufnr(''))
" Build strings based on user formatting preferences.
let l:errors = l:counts[0] ? printf(l:error_format, l:counts[0]) : ''
let l:warnings = l:counts[1] ? printf(l:warning_format, l:counts[1]) : ''
" Different formats based on the combination of errors and warnings.
if empty(l:errors) && empty(l:warnings)
let l:res = l:no_errors
elseif !empty(l:errors) && !empty(l:warnings)
let l:res = printf('%s %s', l:errors, l:warnings)
else
let l:res = empty(l:errors) ? l:warnings : l:errors
endif
return l:res
endfunction
" remove in 2.0
"
" Returns a formatted string that can be integrated in the statusline.
"
" This function is deprecated, and should not be used. Use the airline plugin
" instead, or write your own status function with ale#statusline#Count()
function! ale#statusline#Status() abort
if !get(g:, 'ale_deprecation_ale_statusline_status', 0)
execute 'echom ''ale#statusline#Status() is deprecated, use ale#statusline#Count() to write your own function.'''
let g:ale_deprecation_ale_statusline_status = 1
endif
if !exists('g:ale_statusline_format')
return 'OK'
endif
if type(g:ale_statusline_format) == type([])
return s:StatusForListFormat()
endif
return ''
endfunction

View File

@@ -48,7 +48,7 @@ function! ale#toggle#Toggle() abort
endif
endif
call ale#autocmd#InitAuGroups()
call ale#events#Init()
endfunction
function! ale#toggle#Enable() abort

View File

@@ -17,11 +17,18 @@ endfunction
" but NeoVim does. Small messages can be echoed in Vim 8, and larger messages
" have to be shown in preview windows.
function! ale#util#ShowMessage(string) abort
if !has('nvim')
call ale#preview#CloseIfTypeMatches('ale-preview.message')
endif
" We have to assume the user is using a monospace font.
if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns)
execute 'echo a:string'
else
call ale#preview#Show(split(a:string, "\n"))
call ale#preview#Show(split(a:string, "\n"), {
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1,
\})
endif
endfunction
@@ -39,6 +46,33 @@ if !exists('g:ale#util#nul_file')
endif
endif
" Given a job, a buffered line of data, a list of parts of lines, a mode data
" is being read in, and a callback, join the lines of output for a NeoVim job
" or socket together, and call the callback with the joined output.
"
" Note that jobs and IDs are the same thing on NeoVim.
function! ale#util#JoinNeovimOutput(job, last_line, data, mode, callback) abort
if a:mode is# 'raw'
call a:callback(a:job, join(a:data, "\n"))
return ''
endif
let l:lines = a:data[:-2]
if len(a:data) > 1
let l:lines[0] = a:last_line . l:lines[0]
let l:new_last_line = a:data[-1]
else
let l:new_last_line = a:last_line . get(a:data, 0, '')
endif
for l:line in l:lines
call a:callback(a:job, l:line)
endfor
return l:new_last_line
endfunction
" Return the number of lines for a given buffer.
function! ale#util#GetLineCount(buffer) abort
return len(getbufline(a:buffer, 1, '$'))
@@ -56,8 +90,11 @@ function! ale#util#Open(filename, line, column, options) abort
if get(a:options, 'open_in_tab', 0)
call ale#util#Execute('tabedit ' . fnameescape(a:filename))
else
" Open another file only if we need to.
if bufnr(a:filename) isnot bufnr('')
call ale#util#Execute('edit ' . fnameescape(a:filename))
endif
endif
call cursor(a:line, a:column)
endfunction
@@ -231,9 +268,8 @@ endfunction
" See :help sandbox
function! ale#util#InSandbox() abort
try
function! s:SandboxCheck() abort
endfunction
catch /^Vim\%((\a\+)\)\=:E48/
let &equalprg=&equalprg
catch /E48/
" E48 is the sandbox error.
return 1
endtry
@@ -241,14 +277,23 @@ function! ale#util#InSandbox() abort
return 0
endfunction
" Get the number of milliseconds since some vague, but consistent, point in
" the past.
"
" This function can be used for timing execution, etc.
"
" The time will be returned as a Number.
function! ale#util#ClockMilliseconds() abort
return float2nr(reltimefloat(reltime()) * 1000)
function! ale#util#Tempname() abort
let l:clear_tempdir = 0
if exists('$TMPDIR') && empty($TMPDIR)
let l:clear_tempdir = 1
let $TMPDIR = '/tmp'
endif
try
let l:name = tempname() " no-custom-checks
finally
if l:clear_tempdir
let $TMPDIR = ''
endif
endtry
return l:name
endfunction
" Given a single line, or a List of lines, and a single pattern, or a List

View File

@@ -0,0 +1,14 @@
===============================================================================
ALE CloudFormation Integration *ale-cloudformation-options*
===============================================================================
cfn-python-lint *ale-cloudformation-cfn-python-lint*
cfn-python-lint is a linter for AWS CloudFormation template file.
https://github.com/awslabs/cfn-python-lint
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -156,6 +156,26 @@ g:ale_cpp_cpplint_options *g:ale_cpp_cpplint_options*
This variable can be changed to modify flags given to cpplint.
===============================================================================
cquery *ale-cpp-cquery*
g:ale_cpp_cquery_executable *g:ale_cpp_cquery_executable*
*b:ale_cpp_cquery_executable*
Type: |String|
Default: `'cquery'`
This variable can be changed to use a different executable for cquery.
g:ale_cpp_cquery_cache_directory *g:ale_cpp_cquery_cache_directory*
*b:ale_cpp_cquery_cache_directory*
Type: |String|
Default: `'~/.cache/cquery'`
This variable can be changed to decide which directory cquery uses for its
cache.
===============================================================================
flawfinder *ale-cpp-flawfinder*

View File

@@ -35,4 +35,37 @@ g:ale_dart_dartanalyzer_executable *g:ale_dart_dartanalyzer_executable*
===============================================================================
dartfmt *ale-dart-dartfmt*
Installation
-------------------------------------------------------------------------------
Installing Dart should probably ensure that `dartfmt` is in your `$PATH`.
In case it is not, try to set the executable option to its absolute path. : >
" Set the executable path for dartfmt to the absolute path to it.
let g:ale_dart_dartfmt_executable = '/usr/lib/dart/bin/dartfmt'
>
Options
-------------------------------------------------------------------------------
g:ale_dart_dartfmt_executable *g:ale_dart_dartfmt_executable*
*b:ale_dart_dartfmt_executable*
Type: |String|
Default: `''`
This variable can be set to specify an absolute path to the
dartfmt executable (or to specify an alternate executable).
g:ale_dart_dartfmt_options *g:ale_dart_dartfmt_options*
*b:ale_dart_dartfmt_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to the dartfmt fixer.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

226
doc/ale-development.txt Normal file
View File

@@ -0,0 +1,226 @@
*ale-development.txt* For Vim version 8.0.
*ale-development*
ALE Development Documentation
===============================================================================
CONTENTS *ale-development-contents*
1. Introduction.........................|ale-development-introduction|
2. Design Goals.........................|ale-design-goals|
3. Coding Standards.....................|ale-coding-standards|
4. Testing ALE..........................|ale-development-tests|
===============================================================================
1. Introduction *ale-development-introduction*
This document contains helpful information for ALE developers, including
design goals, information on how to run the tests, coding standards, and so
on. You should read this document if you want to get involved with ALE
development.
===============================================================================
2. Design Goals *ale-design-goals*
This section lists design goals for ALE, in no particular order. They are as
follows.
ALE code should be almost 100% VimL. This makes the plugin as portable as
possible.
ALE should run without needing any other plugins to be installed, to make
installation simple. ALE can integrate with other plugins for more advanced
functionality, non-essential functionality, or improving on basic first party
functionality.
ALE should check files with as many tools as possible by default, except where
they cause security issues or make excessive use of resources on modern
machines.
ALE should be free of breaking changes to the public API, which is comprised of
documented functions and options, until a major version is planned. Breaking
changes should be preceded by a deprecation phase complete with warnings.
Changes required for security may be an exception.
ALE supports Vim 8 and above, and NeoVim 0.2.0 or newer. These are the
earliest versions of Vim and NeoVim which support |job|, |timer|, |closure|,
and |lambda| features. All ALE code should be written so it is compatible with
these versions of Vim, or with version checks so particular features can
degrade or fail gracefully.
Just about everything should be documented and covered with tests.
By and large, people shouldn't pay for the functionality they don't use. Care
should be taken when adding new features, so supporting new features doesn't
degrade the general performance of anything ALE does.
LSP support will become more important as time goes on. ALE should provide
better support for LSP features as time goes on.
When merging pull requests, you should respond with `Cheers! :beers:`, purely
for comedy value.
===============================================================================
3. Coding Standards *ale-coding-standards*
The following general coding standards should be adhered to for Vim code.
* Check your Vim code with `Vint` and do everything it says. ALE will check
your Vim code with Vint automatically. See: https://github.com/Kuniwak/vint
Read ALE's `Dockerfile` to see which version of `Vint` it uses.
* Try to write descriptive and concise names for variables and functions.
Names shouldn't be too short or too long. Think about others reading your
code later on.
* Use `snake_case` names for variables and arguments, and `PascalCase` names
for functions. Prefix every variable name with its scope. (`l:`, `g:`, etc.)
* Try to keep lines no longer than 80 characters, but this isn't an absolute
requirement.
* Use 4 spaces for every level of indentation in Vim code.
* Add a blank line before every `function`, `if`, `for`, `while`, or `return`,
which doesn't start a new level of indentation. This makes the logic in
your code easier to follow.
* End every file with a trailing newline character, but not with extra blank
lines. Remove trailing whitespace from the ends of lines.
* Write the full names of commands instead of abbreviations. For example, write
`function` instead of `func`, and `endif` instead of `end`.
* Write functions with `!`, so files can be reloaded. Use the |abort| keyword
for all functions, so functions exit on the first error.
* Make sure to credit yourself in files you have authored with `Author:`
and `Description:` comments.
In addition to the above general guidelines for the style of your code, you
should also follow some additional rules designed to prevent mistakes. Some of
these are reported with ALE's `custom-linting-rules` script. See
|ale-development-tests|.
* Don't leave stray `:echo` lines in code. Use `execute 'echo' ...` if you must
echo something.
* For strings use |is#| instead of |==#|, `is?` instead of `==?`, `isnot#`
instead of `!=#`, and `isnot?` instead of `!=?`. This is because `'x' ==# 0`
returns 1, while `'x' is# 0` returns 0, so you will experience fewer issues
when numbers are compared with strings. `is` and `isnot` also do not throw
errors when other objects like List or Dictionaries are compared with
strings.
* Don't use the `getcwd()` function in the ALE codebase. Most of ALE's code
runs from asynchronous callback functions, and these functions can execute
from essentially random buffers. Therefore, the `getcwd()` output is
useless. Use `expand('#' . a:buffer . ':p:h')` instead. Don't use
`expand('%...')` for the same reason.
* Don't use the `simplify()` function. It doesn't simplify paths enough. Use
`ale#path#Simplify()` instead.
* Don't use the `shellescape()` function. It doesn't escape arguments properly
on Windows. Use `ale#Escape()` instead, which will avoid escaping where it
isn't needed, and generally escape arguments better on Windows.
* Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't
set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR`
appropriately where needed.
Apply the following guidelines when writing Vader test files.
* Use 2 spaces for Vader test files, instead of the 4 spaces for Vim files.
* If you write `Before` and `After` blocks, you should typically write them at
the top of the file, so they run for all tests. There may be some tests
where it make sense to modify the `Before` and `After` code part of the way
through the file.
* If you modify any settings or global variables, reset them in `After`
blocks. The Vader `Save` and `Restore` commands can be useful for this
purpose.
* If you load or define linters in tests, write `call ale#linter#Reset()` in
an `After` block.
* Just write `Execute` blocks for Vader tests, and don't bother writing `Then`
blocks. `Then` blocks execute after `After` blocks in older versions, and
that can be confusing.
Apply the following rules when writing Bash scripts.
* Run `shellcheck`, and do everything it says.
See: https://github.com/koalaman/shellcheck
* Try to write scripts so they will run on Linux, BSD, or Mac OSX.
===============================================================================
4. Testing ALE *ale-development-tests*
ALE is tested with a suite of tests executed in Travis CI and AppVeyor. ALE
runs tests with the following versions of Vim in the following environments.
1. Vim 8.0.0027 on Linux via Travis CI.
2. NeoVim 0.2.0 on Linux via Travis CI.
3. NeoVim 0.3.0 on Linux via Travis CI.
4. Vim 8 (stable builds) on Windows via AppVeyor.
If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
tests by installing Docker and running the `run-tests` script. Follow the
instructions on the Docker site for installing Docker.
See: https://docs.docker.com/install/
NOTE: Don't forget to add your user to the `docker` group on Linux, or Docker
just won't work. See: https://docs.docker.com/install/linux/linux-postinstall/
If you run simply `./run-tests` from the ALE repository root directory, the
latest Docker image for tests will be downloaded if needed, and the script
will run all of the tests in Vader, Vint checks, and several Bash scripts for
finding extra issues. Run `./run-tests --help` to see all of the options the
script supports. Note that the script supports selecting particular test files.
Generally write tests for any changes you make. The following types of tests
are recommended for the following types of code.
* New/edited error handler callbacks -> Write tests in `test/handler`
* New/edited command callbacks -> Write tests in `test/command_callback`
* New/edited fixer functions -> Write tests in `test/fixers`
Look at existing tests in the codebase for examples of how to write tests.
Refer to the Vader documentation for general information on how to write Vader
tests: https://github.com/junegunn/vader.vim
When you add new linters or fixers, make sure to add them into the table in
the README, and also into the |ale-support| list in the main help file. If you
forget to keep them both in sync, you should see an error like the following
in Travis CI. >
========================================
diff README.md and doc/ale.txt tables
========================================
Differences follow:
--- /tmp/readme.qLjNhJdB 2018-07-01 16:29:55.590331972 +0100
+++ /tmp/doc.dAi8zfVE 2018-07-01 16:29:55.582331877 +0100
@@ -1 +1 @@
- ASM: gcc, foobar
+ ASM: gcc
<
Make sure to list documentation entries for linters and fixers in individual
help files in the table of contents, and to align help tags to the right
margin. For example, if you add a heading for an `aardvark` tool to
`ale-python.txt` with a badly aligned doc tag, you will see errors like so. >
========================================
Look for badly aligned doc tags
========================================
Badly aligned tags follow:
doc/ale-python.txt:aardvark ...
========================================
Look for table of contents issues
========================================
Check for bad ToC sorting:
Check for mismatched ToC and headings:
--- /tmp/table-of-contents.mwCFOgSI 2018-07-01 16:33:25.068811878 +0100
+++ /tmp/headings.L4WU0hsO 2018-07-01 16:33:25.076811973 +0100
@@ -168,6 +168,7 @@
pyrex (cython), ale-pyrex-options
cython, ale-pyrex-cython
python, ale-python-options
+ aardvark, ale-python-aardvark
autopep8, ale-python-autopep8
black, ale-python-black
flake8, ale-python-flake8
<
Make sure to make the table of contents match the headings, and to keep the
doc tags on the right margin.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -19,13 +19,15 @@ g:ale_gitcommit_gitlint_options *g:ale_gitcommit_gitlint_options*
Default: `''`
This variable can be changed to add command-line arguments to the gitlint
invocation.
For example, to dinamically set the gitlint configuration file path, you
may want to set >
invocation. For example, you can specify the path to a configuration file. >
let g:ale_gitcommit_gitlint_options = '-C /home/user/.config/gitlint.ini'
<
You can also disable particular error codes using this option. For example,
you can ignore errors for git commits with a missing body. >
let g:ale_gitcommit_gitlint_options = '--ignore B6'
<
g:ale_gitcommit_gitlint_use_global *g:ale_gitcommit_gitlint_use_global*
*b:ale_gitcommit_gitlint_use_global*

View File

@@ -71,6 +71,14 @@ g:ale_html_tidy_options *g:ale_html_tidy_options*
(mac), sjis (shiftjis), utf-16le, utf-16, utf-8
g:ale_html_tidy_use_global *g:html_tidy_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
write-good *ale-html-write-good*

25
doc/ale-pyrex.txt Normal file
View File

@@ -0,0 +1,25 @@
===============================================================================
ALE Pyrex (Cython) Integration *ale-pyrex-options*
===============================================================================
cython *ale-pyrex-cython*
g:ale_pyrex_cython_executable *g:ale_pyrex_cython_executable*
*b:ale_pyrex_cython_executable*
Type: |String|
Default: `'cython'`
This variable can be changed to use a different executable for cython.
g:ale_pyrex_cython_options *g:ale_pyrex_cython_options*
*b:ale_pyrex_cython_options*
Type: |String|
Default: `'--warning-extra --warning-errors'`
This variable can be changed to modify flags given to cython.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -100,7 +100,8 @@ g:ale_python_flake8_executable *g:ale_python_flake8_executable*
Type: |String|
Default: `'flake8'`
This variable can be changed to modify the executable used for flake8.
This variable can be changed to modify the executable used for flake8. Set
this to `'pipenv'` to invoke `'pipenv` `run` `flake8'`.
g:ale_python_flake8_options *g:ale_python_flake8_options*
@@ -169,6 +170,8 @@ g:ale_python_mypy_executable *g:ale_python_mypy_executable*
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `mypy'`.
g:ale_python_mypy_ignore_invalid_syntax
*g:ale_python_mypy_ignore_invalid_syntax*
*b:ale_python_mypy_ignore_invalid_syntax*
@@ -207,6 +210,8 @@ g:ale_python_prospector_executable *g:ale_python_prospector_executable*
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `prospector'`.
g:ale_python_prospector_options *g:ale_python_prospector_options*
*b:ale_python_prospector_options*
@@ -248,6 +253,8 @@ g:ale_python_pycodestyle_executable *g:ale_python_pycodestyle_executable*
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pycodestyle'`.
g:ale_python_pycodestyle_options *g:ale_python_pycodestyle_options*
*b:ale_python_pycodestyle_options*
@@ -266,6 +273,20 @@ g:ale_python_pycodestyle_use_global *g:ale_python_pycodestyle_use_global*
See |ale-integrations-local-executables|
===============================================================================
pyflakes *ale-python-pyflakes*
g:ale_python_pyflakes_executable *g:ale_python_pyflakes_executable*
*b:ale_python_pyflakes_executable*
Type: |String|
Default: `'pyflakes'`
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pyflakes'`.
===============================================================================
pylint *ale-python-pylint*
@@ -287,6 +308,8 @@ g:ale_python_pylint_executable *g:ale_python_pylint_executable*
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pylint'`.
g:ale_python_pylint_options *g:ale_python_pylint_options*
*b:ale_python_pylint_options*
@@ -329,6 +352,8 @@ g:ale_python_pyls_executable *g:ale_python_pyls_executable*
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pyls'`.
g:ale_python_pyls_use_global *g:ale_python_pyls_use_global*
*b:ale_python_pyls_use_global*
@@ -338,6 +363,30 @@ g:ale_python_pyls_use_global *g:ale_python_pyls_use_global*
See |ale-integrations-local-executables|
===============================================================================
pyre *ale-python-pyre*
`pyre` will be run from a detected project root, per |ale-python-root|.
g:ale_python_pyre_executable *g:ale_python_pyre_executable*
*b:ale_python_pyre_executable*
Type: |String|
Default: `'pyre'`
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pyre'`.
g:ale_python_pyre_use_global *g:ale_python_pyre_use_global*
*b:ale_python_pyre_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
yapf *ale-python-yapf*

View File

@@ -59,6 +59,26 @@ g:ale_rust_cargo_check_all_targets *g:ale_rust_cargo_check_all_targets*
is used. See |g:ale_rust_cargo_use_check|,
g:ale_rust_cargo_check_tests *g:ale_rust_cargo_check_tests*
*b:ale_rust_cargo_check_tests*
Type: |Number|
Default: `0`
When set to `1`, ALE will set the `--tests` option when `cargo check`
is used. This allows for linting of tests which are normally excluded.
See |g:ale_rust_cargo_use_check|,
g:ale_rust_cargo_check_examples *g:ale_rust_cargo_check_examples*
*b:ale_rust_cargo_check_examples*
Type: |Number|
Default: `0`
When set to `1`, ALE will set the `--examples` option when `cargo check`
is used. This allows for linting of examples which are normally excluded.
See |g:ale_rust_cargo_use_check|,
g:ale_rust_cargo_default_feature_behavior
*g:ale_rust_cargo_default_feature_behavior*
*b:ale_rust_cargo_default_feature_behavior*
@@ -88,6 +108,15 @@ g:ale_rust_cargo_include_features *g:ale_rust_cargo_include_features*
When defined, ALE will set the `--features` option when invoking `cargo` to
perform the lint check. See |g:ale_rust_cargo_default_feature_behavior|.
g:ale_rust_cargo_avoid_whole_workspace *g:ale_rust_cargo_avoid_whole_workspace*
*b:ale_rust_cargo_avoid_whole_workspace*
Type: |Number|
Default: `1`
When set to 1, and ALE is used to edit a crate that is part of a Cargo
workspace, avoid building the entire entire workspace by invoking
`cargo` directly in the crate's directory. Otherwise, behave as usual.
===============================================================================
rls *ale-rust-rls*

View File

@@ -2,6 +2,31 @@
ALE Scala Integration *ale-scala-options*
===============================================================================
scalafmt *ale-scala-scalafmt*
If Nailgun is used, override `g:ale_scala_scalafmt_executable` like so: >
let g:ale_scala_scalafmt_executable = 'ng'
g:ale_scala_scalafmt_executable *g:ale_scala_scalafmt_executable*
*b:ale_scala_scalafmt_executable*
Type: |String|
Default: `'scalafmt'`
Override the invoked `scalafmt` binary. This is useful for running `scalafmt`
with Nailgun.
g:ale_scala_scalafmt_options *g:ale_scala_scalafmt_options*
*b:ale_scala_scalafmt_options*
Type: |String|
Default: `''`
A string containing additional options to pass to `'scalafmt'`, or
`'ng scalafmt'` if Nailgun is used.
===============================================================================
scalastyle *ale-scala-scalastyle*

View File

@@ -2,6 +2,25 @@
ALE Shell Integration *ale-sh-options*
===============================================================================
sh-language-server *ale-sh-language-server*
g:ale_sh_language_server_executable *g:ale_sh_language_server_executable*
*b:ale_sh_language_server_executable*
Type: |String|
Default: `'bash-language-server'`
See |ale-integrations-local-executables|
g:ale_sh_language_server_use_global *g:ale_sh_language_server_use_global*
*b:ale_sh_language_server_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
shell *ale-sh-shell*

View File

@@ -35,6 +35,8 @@ CONTENTS *ale-contents*
foodcritic..........................|ale-chef-foodcritic|
clojure...............................|ale-clojure-options|
joker...............................|ale-clojure-joker|
cloudformation........................|ale-cloudformation-options|
cfn-python-lint.....................|ale-cloudformation-cfn-python-lint|
cmake.................................|ale-cmake-options|
cmakelint...........................|ale-cmake-cmakelint|
cpp...................................|ale-cpp-options|
@@ -44,6 +46,7 @@ CONTENTS *ale-contents*
clangtidy...........................|ale-cpp-clangtidy|
cppcheck............................|ale-cpp-cppcheck|
cpplint.............................|ale-cpp-cpplint|
cquery..............................|ale-cpp-cquery|
flawfinder..........................|ale-cpp-flawfinder|
gcc.................................|ale-cpp-gcc|
c#....................................|ale-cs-options|
@@ -56,6 +59,7 @@ CONTENTS *ale-contents*
nvcc................................|ale-cuda-nvcc|
dart..................................|ale-dart-options|
dartanalyzer........................|ale-dart-dartanalyzer|
dartfmt.............................|ale-dart-dartfmt|
dockerfile............................|ale-dockerfile-options|
hadolint............................|ale-dockerfile-hadolint|
elixir................................|ale-elixir-options|
@@ -182,6 +186,8 @@ CONTENTS *ale-contents*
puglint.............................|ale-pug-puglint|
puppet................................|ale-puppet-options|
puppetlint..........................|ale-puppet-puppetlint|
pyrex (cython)........................|ale-pyrex-options|
cython..............................|ale-pyrex-cython|
python................................|ale-python-options|
autopep8............................|ale-python-autopep8|
black...............................|ale-python-black|
@@ -190,8 +196,10 @@ CONTENTS *ale-contents*
mypy................................|ale-python-mypy|
prospector..........................|ale-python-prospector|
pycodestyle.........................|ale-python-pycodestyle|
pyflakes............................|ale-python-pyflakes|
pylint..............................|ale-python-pylint|
pyls................................|ale-python-pyls|
pyre................................|ale-python-pyre|
yapf................................|ale-python-yapf|
qml...................................|ale-qml-options|
qmlfmt..............................|ale-qml-qmlfmt|
@@ -218,11 +226,13 @@ CONTENTS *ale-contents*
sass..................................|ale-sass-options|
stylelint...........................|ale-sass-stylelint|
scala.................................|ale-scala-options|
scalafmt............................|ale-scala-scalafmt|
scalastyle..........................|ale-scala-scalastyle|
scss..................................|ale-scss-options|
prettier............................|ale-scss-prettier|
stylelint...........................|ale-scss-stylelint|
sh....................................|ale-sh-options|
sh-language-server..................|ale-sh-language-server|
shell...............................|ale-sh-shell|
shellcheck..........................|ale-sh-shellcheck|
shfmt...............................|ale-sh-shfmt|
@@ -299,6 +309,9 @@ control functionality used for checking for problems. Try using the
|ALEFixSuggest| command for browsing tools that can be used to fix problems
for the current buffer.
If you are interested in contributing to the development of ALE, read the
developer documentation. See |ale-development|
===============================================================================
2. Supported Languages & Tools *ale-support*
@@ -314,14 +327,15 @@ Notes:
* API Blueprint: `drafter`
* AsciiDoc: `alex`!!, `proselint`, `redpen`, `write-good`
* Awk: `gawk`
* Bash: `shell` (-n flag), `shellcheck`, `shfmt`
* Bash: `language-server`, `shell` (-n flag), `shellcheck`, `shfmt`
* Bourne Shell: `shell` (-n flag), `shellcheck`, `shfmt`
* C: `cppcheck`, `cpplint`!!, `clang`, `clangtidy`!!, `clang-format`, `flawfinder`, `gcc`
* C++ (filetype cpp): `clang`, `clangcheck`!!, `clangtidy`!!, `clang-format`, `cppcheck`, `cpplint`!!, `flawfinder`, `gcc`
* C++ (filetype cpp): `clang`, `clangcheck`!!, `clangtidy`!!, `clang-format`, `cppcheck`, `cpplint`!!, `cquery`, `flawfinder`, `gcc`
* CUDA: `nvcc`!!
* C#: `mcs`, `mcsc`!!
* Chef: `foodcritic`
* Clojure: `joker`
* CloudFormation: `cfn-python-lint`
* CMake: `cmakelint`
* CoffeeScript: `coffee`, `coffeelint`
* Crystal: `crystal`!!
@@ -330,9 +344,9 @@ Notes:
* Cython (pyrex filetype): `cython`
* D: `dmd`
* Dafny: `dafny`!!
* Dart: `dartanalyzer`!!, `language_server`
* Dart: `dartanalyzer`!!, `language_server`, dartfmt!!
* Dockerfile: `hadolint`
* Elixir: `credo`, `dialyxir`, `dogma`!!
* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!
* Elm: `elm-format, elm-make`
* Erb: `erb`, `erubi`, `erubis`
* Erlang: `erlc`, `SyntaxErl`
@@ -377,7 +391,7 @@ Notes:
* proto: `protoc-gen-lint`
* Pug: `pug-lint`
* Puppet: `puppet`, `puppet-lint`
* Python: `autopep8`, `black`, `flake8`, `isort`, `mypy`, `prospector`, `pycodestyle`, `pyls`, `pylint`!!, `yapf`
* Python: `autopep8`, `black`, `flake8`, `isort`, `mypy`, `prospector`, `pycodestyle`, `pyls`, `pyre`, `pylint`!!, `yapf`
* QML: `qmlfmt`, `qmllint`
* R: `lintr`
* ReasonML: `merlin`, `ols`, `refmt`
@@ -388,7 +402,7 @@ Notes:
* Rust: `cargo`!!, `rls`, `rustc` (see |ale-integration-rust|), `rustfmt`
* SASS: `sass-lint`, `stylelint`
* SCSS: `prettier`, `sass-lint`, `scss-lint`, `stylelint`
* Scala: `fsc`, `scalac`, `scalastyle`
* Scala: `fsc`, `scalac`, `scalafmt`, `scalastyle`
* Slim: `slim-lint`
* SML: `smlnj`
* Solidity: `solhint`, `solium`
@@ -932,6 +946,14 @@ g:ale_fixers *g:ale_fixers*
`b:ale_fixers` can be set to a |List| of callbacks instead, which can be
more convenient.
A special `'*'` key be used as a wildcard filetype for configuring fixers
for every other type of file. For example: >
" Fix Python files with 'bar'.
" Don't fix 'html' files.
" Fix everything else with 'foo'.
let g:ale_fixers = {'python': ['bar'], 'html': [], '*': ['foo']}
<
g:ale_fix_on_save *g:ale_fix_on_save*
b:ale_fix_on_save *b:ale_fix_on_save*
@@ -1111,6 +1133,7 @@ g:ale_linter_aliases *g:ale_linter_aliases*
\ 'csh': 'sh',
\ 'plaintex': 'tex',
\ 'systemverilog': 'verilog',
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
\ 'vimwiki': 'markdown',
\ 'zsh': 'sh',
\}
@@ -1216,6 +1239,32 @@ g:ale_linters_explicit *g:ale_linters_explicit*
as possible, unless otherwise specified.
g:ale_linters_ignore *g:ale_linters_ignore*
*b:ale_linters_ignore*
Type: |Dictionary| or |List|
Default: `{}`
Linters to ignore. Commands for ignored linters will not be run, and
diagnostics for LSP linters will be ignored. (See |ale-lsp|)
This setting can be set to a |Dictionary| mapping filetypes to linter names,
just like |g:ale_linters|, to list linters to ignore. Ignore lists will be
applied after everything else. >
" Select flake8 and pylint, and ignore pylint, so only flake8 is run.
let g:ale_linters = {'python': ['flake8', 'pylint']}
let g:ale_linters_ignore = {'python': ['pylint']}
<
This setting can be set to simply a |List| of linter names, which is
especially more convenient when using the setting in ftplugin files for
particular buffers. >
" The same as above, in a ftplugin/python.vim.
let b:ale_linters = ['flake8', 'pylint']
let b:ale_linters_ignore = ['pylint']
<
g:ale_list_vertical *g:ale_list_vertical*
*b:ale_list_vertical*
Type: |Number|
@@ -1352,8 +1401,7 @@ g:ale_set_balloons *g:ale_set_balloons*
*b:ale_set_balloons*
Type: |Number|
Default: `(has('balloon_eval') && has('gui_running'))`
`|| (has('balloon_eval_term') && !has('gui_running'))`
Default: `has('balloon_eval') && has('gui_running')`
When this option is set to `1`, balloon messages will be displayed for
problems or hover information if available.
@@ -1363,6 +1411,12 @@ g:ale_set_balloons *g:ale_set_balloons*
supporting "Hover" information, per |ale-hover|, then brief information
about the symbol under the cursor will be displayed in a balloon.
Balloons can be enabled for terminal versions of Vim that support balloons,
but some versions of Vim will produce strange mouse behavior when balloons
are enabled. To configure balloons for your terminal, you should first
configure your |ttymouse| setting, and then consider setting
`g:ale_set_balloons` to `1` before ALE is loaded.
`b:ale_set_balloons` can be set to `0` to disable balloons for a buffer.
Balloons cannot be enabled for a specific buffer when not initially enabled
globally.
@@ -1964,9 +2018,13 @@ ALEDisableBuffer *ALEDisableBuffer*
*:ALEDetail*
ALEDetail *ALEDetail*
Show the full linter message for the current line in the preview window.
This will only have an effect on lines that contain a linter message. The
preview window can be easily closed with the `q` key.
Show the full linter message for the problem nearest to the cursor on the
given line in the preview window. The preview window can be easily closed
with the `q` key. If there is no message to show, the window will not be
opened.
If a loclist item has a `detail` key set, the message for that key will be
preferred over `text`. See |ale-loclist-format|.
A plug mapping `<Plug>(ale_detail)` is defined for this command.
@@ -2150,13 +2208,20 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
This argument is required, unless the linter is an
LSP linter. In which case, this argument must not be
defined, as LSP linters handle diangostics
defined, as LSP linters handle diagnostics
automatically. See |ale-lsp-linters|.
If the function named does not exist, including if
the function is later deleted, ALE will behave as if
the callback returned an empty list.
The keys for each item in the List will be handled in
the following manner:
*ale-loclist-format*
`text` - This error message is required.
`detail` - An optional, more descriptive message.
This message can be displayed with the |ALEDetail|
command instead of the message for `text`, if set.
`lnum` - The line number is required. Any strings
will be automatically converted to numbers by
using `str2nr()`.
@@ -2316,8 +2381,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
When this argument is set to `'stdio'`, then the
linter will be defined as an LSP linter which keeps a
process for a language server runnning, and
process for a language server running, and
communicates with it directly via a |channel|.
`executable` or `executable_callback` must be set,
and `command` or `command_callback` must be set.
When this argument is set to `'socket'`, then the
linter will be defined as an LSP linter via a TCP
socket connection. `address_callback` must be set
with a callback returning an address to connect to.
ALE will not start a server automatically.
When this argument is not empty, only one of either
`language` or `language_callback` must be defined,
@@ -2329,6 +2402,17 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
An optional `completion_filter` callback may be
defined for filtering completion results.
An optional `initialization_options` or
`initialization_options_callback` may be defined to
pass initialization options to the LSP.
`address_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |String| should be
returned with an address to connect to.
This argument must only be set if the `lsp` argument
is set to `'socket'`.
`project_root_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |String| should be
returned representing the path to the project for the
@@ -2370,6 +2454,17 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
setting can make it easier to guess the linter name
by offering a few alternatives.
`initialization_options` A |Dictionary| of initialization options for LSPs.
This will be fed (as JSON) to the LSP in the
initialize command.
`initialization_options_callback`
A |String| or |Funcref| for a callback function
accepting a buffer number. A |Dictionary| should be
returned for initialization options to pass the LSP.
This can be used in place of `initialization_options`
when more complicated processing is needed.
Only one of `command`, `command_callback`, or `command_chain` should be
specified. `command_callback` is generally recommended when a command string
needs to be generated dynamically, or any global options are used.
@@ -2546,5 +2641,5 @@ free to send an email to devw0rp@gmail.com.
Please drink responsibly, or not at all, which is ironically the preference
of w0rp, who is teetotal.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -32,21 +32,9 @@ if !s:has_features
finish
endif
" remove in 2.0
if has('nvim') && !has('nvim-0.2.0') && !get(g:, 'ale_use_deprecated_neovim')
execute 'echom ''ALE support for NeoVim versions below 0.2.0 is deprecated.'''
execute 'echom ''Use `let g:ale_use_deprecated_neovim = 1` to silence this warning for now.'''
endif
" Set this flag so that other plugins can use it, like airline.
let g:loaded_ale = 1
" Set the TMPDIR environment variable if it is not set automatically.
" This can automatically fix some environments.
if has('unix') && empty($TMPDIR)
let $TMPDIR = '/tmp'
endif
" This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against.
let g:ale_buffer_info = {}
@@ -120,10 +108,7 @@ let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax'))
let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
" This flag can be set to 0 to disable balloon support.
let g:ale_set_balloons = get(g:, 'ale_set_balloons',
\ (has('balloon_eval') && has('gui_running'))
\ || (has('balloon_eval_term') && !has('gui_running'))
\)
let g:ale_set_balloons = get(g:, 'ale_set_balloons', has('balloon_eval') && has('gui_running'))
" This flag can be set to 0 to disable warnings for trailing whitespace
let g:ale_warn_about_trailing_whitespace = get(g:, 'ale_warn_about_trailing_whitespace', 1)
@@ -221,35 +206,13 @@ nnoremap <silent> <Plug>(ale_find_references) :ALEFindReferences<Return>
nnoremap <silent> <Plug>(ale_hover) :ALEHover<Return>
" Set up autocmd groups now.
call ale#autocmd#InitAuGroups()
call ale#events#Init()
" Housekeeping
augroup ALECleanupGroup
autocmd!
" Clean up buffers automatically when they are unloaded.
autocmd BufDelete * call ale#engine#Cleanup(str2nr(expand('<abuf>')))
autocmd BufDelete * if exists('*ale#engine#Cleanup') | call ale#engine#Cleanup(str2nr(expand('<abuf>'))) | endif
autocmd QuitPre * call ale#events#QuitEvent(str2nr(expand('<abuf>')))
augroup END
" Backwards Compatibility
" remove in 2.0
function! ALELint(delay) abort
if !get(g:, 'ale_deprecation_ale_lint', 0)
execute 'echom ''ALELint() is deprecated, use ale#Queue() instead.'''
let g:ale_deprecation_ale_lint = 1
endif
call ale#Queue(a:delay)
endfunction
" remove in 2.0
function! ALEGetStatusLine() abort
if !get(g:, 'ale_deprecation_ale_get_status_line', 0)
execute 'echom ''ALEGetStatusLine() is deprecated.'''
let g:ale_deprecation_ale_get_status_line = 1
endif
return ale#statusline#Status()
endfunction

View File

@@ -5,24 +5,25 @@ set -u
# Author: w0rp <devw0rp@gmail.com>
#
# This script runs tests for the ALE project. The following options are
# accepted:
# This script runs tests for the ALE project. Run `./run-tests --help` for
# options, or read the output below.
#
# -v Enable verbose output
# --neovim-only Run tests only for NeoVim
# --vim-only Run tests only for Vim
current_image_id=d5a1b5915b09
image=w0rp/ale
current_image_id=71553d0ab3e8
# Used in all test scripts for running the selected Docker image.
DOCKER_RUN_IMAGE="$image"
export DOCKER_RUN_IMAGE
tests='test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*.vader'
# These flags are forwarded to the script for running Vader tests.
verbose_flag=''
quiet_flag=''
run_neovim_tests=1
run_neovim_02_tests=1
run_neovim_03_tests=1
run_vim_tests=1
run_vint=1
run_custom_checks=1
run_linters=1
while [ $# -ne 0 ]; do
case $1 in
@@ -36,35 +37,50 @@ while [ $# -ne 0 ]; do
;;
--neovim-only)
run_vim_tests=0
run_vint=0
run_custom_checks=0
run_linters=0
shift
;;
--neovim-02-only)
run_neovim_03_tests=0
run_vim_tests=0
run_linters=0
shift
;;
--neovim-03-only)
run_neovim_02_tests=0
run_vim_tests=0
run_linters=0
shift
;;
--vim-only)
run_neovim_tests=0
run_vint=0
run_custom_checks=0
run_neovim_02_tests=0
run_neovim_03_tests=0
run_linters=0
shift
;;
--no-vint)
run_vint=0
shift
;;
--vint-only)
--linters-only)
run_vim_tests=0
run_neovim_tests=0
run_custom_checks=0
run_neovim_02_tests=0
run_neovim_03_tests=0
shift
;;
--no-custom-checks)
run_custom_checks=0
shift
;;
--custom-checks-only)
run_vim_tests=0
run_neovim_tests=0
run_vint=0
shift
--help)
echo 'Usage: ./run-tests [OPTION]... [FILE]...'
echo
echo 'Filenames can be given as arguments to run a subset of tests.'
echo 'For example: ./run-tests test/test_ale_var.vader'
echo
echo 'Options:'
echo ' -v Enable verbose output'
echo ' -q Hide output for successful tests'
echo ' --neovim-only Run tests only for NeoVim 0.2 and 0.3'
echo ' --neovim-02-only Run tests only for NeoVim 0.2'
echo ' --neovim-03-only Run tests only for NeoVim 0.3'
echo ' --vim-only Run tests only for Vim'
echo ' --linters-only Run only Vint and custom checks'
echo ' --help Show this help text'
echo ' -- Stop parsing options after this'
exit 0
;;
--)
shift
@@ -85,6 +101,9 @@ if [ $# -ne 0 ]; then
# This doesn't perfectly handle work splitting, but none of our files
# have spaces in the names.
tests="$*"
# Don't run other tools when targeting tests.
run_linters=0
fi
# Delete .swp files in the test directory, which cause Vim 8 to hang.
@@ -100,8 +119,10 @@ trap '{ rm -rf "$output_dir"; }' EXIT
file_number=0
pid_list=''
for vim in $(docker run --rm "$image" ls /vim-build/bin | grep '^neovim\|^vim' ); do
if ((run_vim_tests)) || [[ $vim =~ ^neovim ]] && ((run_neovim_tests)); then
for vim in $(docker run --rm "$DOCKER_RUN_IMAGE" ls /vim-build/bin | grep '^neovim\|^vim' ); do
if ( [[ $vim =~ ^vim ]] && ((run_vim_tests)) ) \
|| ( [[ $vim =~ ^neovim-v0.2 ]] && ((run_neovim_02_tests)) ) \
|| ( [[ $vim =~ ^neovim-v0.3 ]] && ((run_neovim_03_tests)) ); then
echo "Starting Vim: $vim..."
file_number=$((file_number+1))
test/script/run-vader-tests $quiet_flag $verbose_flag "$vim" "$tests" \
@@ -110,14 +131,12 @@ for vim in $(docker run --rm "$image" ls /vim-build/bin | grep '^neovim\|^vim' )
fi
done
if ((run_vint)); then
if ((run_linters)); then
echo "Starting Vint..."
file_number=$((file_number+1))
test/script/run-vint > "$output_dir/$file_number" 2>&1 &
pid_list="$pid_list $!"
fi
if ((run_custom_checks)); then
echo "Starting Custom checks..."
file_number=$((file_number+1))
test/script/custom-checks &> "$output_dir/$file_number" 2>&1 &
@@ -139,4 +158,10 @@ for pid in $pid_list; do
cat "$output_dir/$index"
done
if ((failed)); then
echo 'Something went wrong!'
else
echo 'All tests passed!'
fi
exit $failed

View File

@@ -10,7 +10,21 @@ REM Use the first argument for selecting tests to run.
if not "%1"=="" set tests=%1
set VADER_OUTPUT_FILE=%~dp0\vader_output
REM Automatically re-run Windows tests, which can fail some times.
set tries=0
RUN_TESTS:
set /a tries=%tries%+1
type nul > "%VADER_OUTPUT_FILE%"
C:\vim\vim\vim80\vim.exe -u test/vimrc "+Vader! %tests%"
set code=%ERRORLEVEL%
IF %code% EQU 0 GOTO :SHOW_RESULTS
IF %tries% GEQ 2 GOTO :SHOW_RESULTS
GOTO :RUN_TESTS
SHOW_RESULTS:
type "%VADER_OUTPUT_FILE%"
del "%VADER_OUTPUT_FILE%"
exit /B %code%

View File

@@ -0,0 +1 @@
use Mix.Config

View File

@@ -1,13 +1,19 @@
Before:
Save g:ale_rust_cargo_use_check
Save g:ale_rust_cargo_check_all_targets
Save g:ale_rust_cargo_check_tests
Save g:ale_rust_cargo_check_examples
Save g:ale_rust_cargo_default_feature_behavior
Save g:ale_rust_cargo_include_features
Save g:ale_rust_cargo_avoid_whole_workspace
unlet! g:ale_rust_cargo_use_check
unlet! g:ale_cargo_check_all_targets
unlet! g:ale_rust_cargo_check_all_targets
unlet! g:ale_rust_cargo_check_tests
unlet! g:ale_rust_cargo_check_examples
unlet! g:ale_rust_cargo_default_feature_behavior
unlet! g:ale_rust_cargo_include_features
unlet! g:ale_rust_cargo_avoid_whole_workspace
runtime ale_linters/rust/cargo.vim
call ale#test#SetDirectory('/testplugin/test/command_callback')
@@ -119,6 +125,38 @@ Execute(--all-targets should be used when g:ale_rust_cargo_check_all_targets is
AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr(''))
Execute(--tests should be used when g:ale_rust_cargo_check_tests is set to 1):
let g:ale_rust_cargo_check_tests = 1
AssertEqual
\ 'cargo check --tests' . g:suffix,
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [
\ 'cargo 0.22.0 (3423351a5 2017-10-06)',
\ ])
" We should cache the version check
AssertEqual
\ 'cargo check --tests' . g:suffix,
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [])
AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr(''))
Execute(--examples should be used when g:ale_rust_cargo_check_examples is set to 1):
let g:ale_rust_cargo_check_examples = 1
AssertEqual
\ 'cargo check --examples' . g:suffix,
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [
\ 'cargo 0.22.0 (3423351a5 2017-10-06)',
\ ])
" We should cache the version check
AssertEqual
\ 'cargo check --examples' . g:suffix,
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [])
AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr(''))
Execute(--no-default-features should be used when g:ale_rust_cargo_default_feature_behavior is none):
let g:ale_rust_cargo_default_feature_behavior = 'none'
@@ -162,3 +200,24 @@ Execute(--all-features should be used when g:ale_rust_cargo_default_feature_beha
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [
\ 'cargo 0.22.0 (3423351a5 2017-10-06)',
\ ])
Execute(When a crate belongs to a workspace we chdir into the crate.):
call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs')
if ale#Has('win32')
let test_cdprefix = "C:\\testplugin\\test\\command_callback\\cargo_workspace_paths\\subpath"
else
let test_cdprefix = "'/testplugin/test/command_callback/cargo_workspace_paths/subpath'"
endif
AssertEqual
\ "cd ".test_cdprefix." && cargo build --frozen --message-format=json -q",
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [])
Execute(When a crate belongs to a workspace we chdir into the crate, unless we disabled it):
let g:ale_rust_cargo_avoid_whole_workspace = 0
call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs')
AssertEqual
\ "cargo build --frozen --message-format=json -q",
\ ale_linters#rust#cargo#GetCommand(bufnr(''), [])

View File

@@ -0,0 +1,48 @@
" Author: Ben Falconer <ben@falconers.me.uk>
" Description: A language server for C++
Before:
Save g:ale_cpp_cquery_executable
Save g:ale_cpp_cquery_cache_directory
unlet! g:ale_cpp_cquery_executable
unlet! b:ale_cpp_cquery_executable
unlet! g:ale_cpp_cquery_cache_directory
unlet! b:ale_cpp_cquery_cache_directory
runtime ale_linters/cpp/cquery.vim
After:
Restore
unlet! b:ale_cpp_cquery_executable
unlet! b:ale_cpp_cquery_cache_directory
call ale#linter#Reset()
Execute(The executable should be configurable):
AssertEqual 'cquery', ale_linters#cpp#cquery#GetExecutable(bufnr(''))
let b:ale_cpp_cquery_executable = 'foobar'
AssertEqual 'foobar', ale_linters#cpp#cquery#GetExecutable(bufnr(''))
Execute(The executable should be used in the command):
AssertEqual
\ ale#Escape('cquery'),
\ ale_linters#cpp#cquery#GetCommand(bufnr(''))
let b:ale_cpp_cquery_executable = 'foobar'
AssertEqual
\ ale#Escape('foobar'),
\ ale_linters#cpp#cquery#GetCommand(bufnr(''))
Execute(The cache directory should be configurable):
AssertEqual
\ {'cacheDirectory': expand('$HOME/.cache/cquery')},
\ ale_linters#cpp#cquery#GetInitializationOptions(bufnr(''))
let b:ale_cpp_cquery_cache_directory = '/foo/bar'
AssertEqual
\ {'cacheDirectory': '/foo/bar'},
\ ale_linters#cpp#cquery#GetInitializationOptions(bufnr(''))

View File

@@ -0,0 +1,37 @@
Before:
runtime ale_linters/elixir/mix.vim
call ale#test#SetDirectory('/testplugin/test/command_callback')
let g:project_root = ale#path#Simplify(g:dir . '/mix_paths/wrapped_project')
let g:env_prefix = has('win32')
\ ? 'set MIX_BUILD_PATH=TEMP && '
\ : 'MIX_BUILD_PATH=TEMP '
function! GetCommand(buffer) abort
let l:command = ale_linters#elixir#mix#GetCommand(a:buffer)
return substitute(l:command, 'MIX_BUILD_PATH=[^ ]\+', 'MIX_BUILD_PATH=TEMP', '')
endfunction
After:
Restore
unlet! g:env_prefix
unlet! g:project_root
call ale#linter#Reset()
call ale#test#RestoreDirectory()
delfunction GetCommand
Execute(The default mix command should be correct):
call ale#test#SetFilename('mix_paths/wrapped_project/lib/app.ex')
AssertEqual
\ GetCommand(bufnr('')),
\ ale#path#CdString(g:project_root)
\ . g:env_prefix
\ . 'mix compile %s'

View File

@@ -174,3 +174,11 @@ Execute(Using `python -m flake8` should be supported for running flake8):
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('python') . ' -m flake8 --some-option --format=default -',
\ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9'])
Execute(Setting executable to 'pipenv' appends 'run flake8'):
let g:ale_python_flake8_executable = 'path/to/pipenv'
AssertEqual
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run flake8 --format=default --stdin-display-name %s -',
\ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0'])

View File

@@ -16,7 +16,7 @@ After:
Execute(The default lintr command should be correct):
AssertEqual
\ 'cd ' . ale#Escape(getcwd()) . ' && '
\ . 'Rscript -e '
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), '
\ . 'with_defaults())')
@@ -28,7 +28,7 @@ Execute(The lintr options should be configurable):
AssertEqual
\ 'cd ' . ale#Escape(getcwd()) . ' && '
\ . 'Rscript -e '
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), '
\ . 'with_defaults(object_usage_linter = NULL))')
@@ -40,7 +40,7 @@ Execute(If the lint_package flag is set, lintr::lint_package should be called):
AssertEqual
\ 'cd ' . ale#Escape(getcwd()) . ' && '
\ . 'Rscript -e '
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint_package(cache = FALSE, '
\ . 'linters = with_defaults())')

View File

@@ -95,3 +95,12 @@ Execute(You should able able to use the global mypy instead):
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s',
\ ale_linters#python#mypy#GetCommand(bufnr(''))
Execute(Setting executable to 'pipenv' appends 'run mypy'):
let g:ale_python_mypy_executable = 'path/to/pipenv'
AssertEqual
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run mypy'
\ . ' --show-column-numbers --shadow-file %s %t %s',
\ ale_linters#python#mypy#GetCommand(bufnr(''))

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