mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-07 21:24:33 +08:00
Compare commits
351 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08295ce174 | ||
|
|
4ddf742643 | ||
|
|
78fa93bd55 | ||
|
|
62fd83f1dd | ||
|
|
6a367e44aa | ||
|
|
7d90ff56d9 | ||
|
|
b4b75126f9 | ||
|
|
fc2a34e9d8 | ||
|
|
8950f6b812 | ||
|
|
417761b415 | ||
|
|
c36053d4cc | ||
|
|
5bc49d2047 | ||
|
|
152b2cb691 | ||
|
|
0b55098bd0 | ||
|
|
844febb9fb | ||
|
|
d4a14746cd | ||
|
|
ac2100d410 | ||
|
|
cdaeca452e | ||
|
|
31942c99b9 | ||
|
|
4a91f92f28 | ||
|
|
1462de6685 | ||
|
|
0989da4a38 | ||
|
|
33202a39f5 | ||
|
|
303bed6ec1 | ||
|
|
25b572b3bf | ||
|
|
6e2e51b154 | ||
|
|
6888ca46a7 | ||
|
|
f1ecc2e068 | ||
|
|
7e0cdb53ec | ||
|
|
bc3a843e10 | ||
|
|
6b138b965d | ||
|
|
d9a7d6bc23 | ||
|
|
06264c264f | ||
|
|
dd9ad9b5be | ||
|
|
7d4ce4e6aa | ||
|
|
3d5a2690ce | ||
|
|
34e409ea21 | ||
|
|
b8c0ac2e61 | ||
|
|
6874120405 | ||
|
|
36e959a466 | ||
|
|
47fdc02fc7 | ||
|
|
369e3876f0 | ||
|
|
80bd2e18d6 | ||
|
|
ecd7abecc0 | ||
|
|
7545b18ba1 | ||
|
|
6d843715f3 | ||
|
|
6074720dc2 | ||
|
|
af177d7825 | ||
|
|
719f3c62b0 | ||
|
|
5d3d33626c | ||
|
|
571cff932d | ||
|
|
17605777d6 | ||
|
|
66ff00c420 | ||
|
|
f5aa0e8457 | ||
|
|
686f42a2e1 | ||
|
|
c9377e9baf | ||
|
|
a955f5dfa8 | ||
|
|
396fba7cca | ||
|
|
447aea4af0 | ||
|
|
3e2abe3f25 | ||
|
|
1a7366067a | ||
|
|
33eb03ea71 | ||
|
|
d4583f1a63 | ||
|
|
c0566db1d2 | ||
|
|
ba3dd0d027 | ||
|
|
76801743cf | ||
|
|
4bece27bd4 | ||
|
|
2b785688ea | ||
|
|
4d42ebc160 | ||
|
|
90abb7e7ef | ||
|
|
de7b0567b1 | ||
|
|
361027eac6 | ||
|
|
794224aafa | ||
|
|
92cada9913 | ||
|
|
e27d4377b5 | ||
|
|
f8b3a43aab | ||
|
|
5eda1df0a9 | ||
|
|
4df352eee5 | ||
|
|
bc6304bdb0 | ||
|
|
ac56574b55 | ||
|
|
6d33417b15 | ||
|
|
eb864730e2 | ||
|
|
514e5a8baa | ||
|
|
cfda549056 | ||
|
|
d5c1d84230 | ||
|
|
5c778e1ae7 | ||
|
|
5ceda0164c | ||
|
|
5a4fad6172 | ||
|
|
2b2403a20d | ||
|
|
8151e3e8fa | ||
|
|
94a968ef39 | ||
|
|
ed69b074ba | ||
|
|
a4f70163eb | ||
|
|
506a8532d0 | ||
|
|
0b77766337 | ||
|
|
979062235a | ||
|
|
8e6c7bff9a | ||
|
|
34adb997c6 | ||
|
|
64d4c951ae | ||
|
|
7c4b1d8444 | ||
|
|
d5912b53dd | ||
|
|
d3f410b6f7 | ||
|
|
2237f9b462 | ||
|
|
05210846e4 | ||
|
|
bf3c3e9438 | ||
|
|
9e1f511003 | ||
|
|
affeed7a87 | ||
|
|
681ca5fee8 | ||
|
|
2ed09f51b6 | ||
|
|
6d502233d8 | ||
|
|
8bfb5c6407 | ||
|
|
2d174db5b2 | ||
|
|
f741245f11 | ||
|
|
388049dbea | ||
|
|
96d525a287 | ||
|
|
b9a1c0e6d3 | ||
|
|
97d887ae22 | ||
|
|
7cefc80f1b | ||
|
|
19229e8e27 | ||
|
|
9bdabce8df | ||
|
|
667618b399 | ||
|
|
f17b74679f | ||
|
|
4044196047 | ||
|
|
5b3da60cea | ||
|
|
711c90c523 | ||
|
|
cdd8d38e2f | ||
|
|
fa3a927ca3 | ||
|
|
1bd7b3e4ad | ||
|
|
86d5cb81bd | ||
|
|
acf892c4d1 | ||
|
|
316c7c7372 | ||
|
|
9894e92553 | ||
|
|
e2d1e54eb5 | ||
|
|
fc7b4585e6 | ||
|
|
fbfeae0587 | ||
|
|
275b5248e5 | ||
|
|
84a413350c | ||
|
|
72f1d730fd | ||
|
|
ac2ebafadd | ||
|
|
ab6aed17ab | ||
|
|
d49b06e030 | ||
|
|
e03e24c091 | ||
|
|
7cada95683 | ||
|
|
5338dbf680 | ||
|
|
cef64424ce | ||
|
|
428c5f94da | ||
|
|
f4cff3bc06 | ||
|
|
7d40d0a16f | ||
|
|
a9b2f6362d | ||
|
|
5377272d20 | ||
|
|
0e6578cf65 | ||
|
|
75723e4522 | ||
|
|
028485b4de | ||
|
|
c38b2a6524 | ||
|
|
78295024e1 | ||
|
|
b25bb64a4d | ||
|
|
a9799fe90e | ||
|
|
b3ad7bb3d0 | ||
|
|
f26b2e7f01 | ||
|
|
4fc59ccace | ||
|
|
9316b7b3f2 | ||
|
|
ee466de733 | ||
|
|
2987ebcfae | ||
|
|
a2d172c457 | ||
|
|
488df0fa41 | ||
|
|
076f9efbd9 | ||
|
|
9fe208a01f | ||
|
|
68b484a49f | ||
|
|
f31182beee | ||
|
|
f4668c751f | ||
|
|
70ab831001 | ||
|
|
c1c3bd9227 | ||
|
|
54aeeec97f | ||
|
|
d38b92c957 | ||
|
|
26571fa050 | ||
|
|
23c58e63d4 | ||
|
|
d0b7a6e71f | ||
|
|
57423f13ec | ||
|
|
fecffeee91 | ||
|
|
56b92544c2 | ||
|
|
5dbbd2d18b | ||
|
|
8c0b9ecdfd | ||
|
|
4394084d99 | ||
|
|
6c58164094 | ||
|
|
7f881f66a8 | ||
|
|
c136061b3f | ||
|
|
106c27644b | ||
|
|
fd399c527f | ||
|
|
1fcb9d1e1a | ||
|
|
9b8ec86d7f | ||
|
|
b3c6db173a | ||
|
|
834d6f9c48 | ||
|
|
4f25498806 | ||
|
|
1428c7b29e | ||
|
|
b29e9867e8 | ||
|
|
b339a8bfa0 | ||
|
|
4062b05669 | ||
|
|
53bfe41841 | ||
|
|
35c7c297b6 | ||
|
|
7265ceb6d0 | ||
|
|
b209315714 | ||
|
|
7ff87a942b | ||
|
|
0b5d72fecd | ||
|
|
e61e1147b0 | ||
|
|
ff6bfc3d37 | ||
|
|
3635285c02 | ||
|
|
3b4193175e | ||
|
|
6b8f08f7fc | ||
|
|
69d96aa9d9 | ||
|
|
345daf683b | ||
|
|
c2b01f0e28 | ||
|
|
ca97f32258 | ||
|
|
c0d74b8094 | ||
|
|
5f4103fb35 | ||
|
|
70005134e5 | ||
|
|
15d590ee5e | ||
|
|
65bea1a5cb | ||
|
|
2548763d04 | ||
|
|
716f9a9bbb | ||
|
|
f67cb56e5e | ||
|
|
3f34265151 | ||
|
|
d4e1c57026 | ||
|
|
76cd6b0f92 | ||
|
|
e641fe0c5d | ||
|
|
47d941b491 | ||
|
|
36e5337e30 | ||
|
|
60d683da3b | ||
|
|
d2934ba017 | ||
|
|
36b50058bb | ||
|
|
3281321d5c | ||
|
|
4fbfcc9dec | ||
|
|
e0181f8832 | ||
|
|
64b9a2708d | ||
|
|
1f9ac1c6dc | ||
|
|
93a13d7353 | ||
|
|
00eee550ea | ||
|
|
5035281cb9 | ||
|
|
198361bc0d | ||
|
|
dc054f30c8 | ||
|
|
16cd59805b | ||
|
|
82f734a7c2 | ||
|
|
891852de71 | ||
|
|
6087765cad | ||
|
|
58404b5b83 | ||
|
|
b800d24212 | ||
|
|
1c6b9354a8 | ||
|
|
852a6a1753 | ||
|
|
9edefa724b | ||
|
|
fa19bca80e | ||
|
|
7b9855f1fe | ||
|
|
c2aa01199e | ||
|
|
fc6677d405 | ||
|
|
302ce71931 | ||
|
|
c207d6a550 | ||
|
|
bbe5153fcb | ||
|
|
46d7ee564f | ||
|
|
8f7ccdc5e9 | ||
|
|
634c81fd46 | ||
|
|
8012809c3f | ||
|
|
8c0b0f085f | ||
|
|
d6d2a0c770 | ||
|
|
07080066e4 | ||
|
|
07ee4d39c5 | ||
|
|
4afbf2f25d | ||
|
|
72d2c55479 | ||
|
|
57eba1afac | ||
|
|
8c4c8dfd97 | ||
|
|
0cb432cb82 | ||
|
|
874c98b96d | ||
|
|
7a4f5cefba | ||
|
|
6ad8836c68 | ||
|
|
8148a67b37 | ||
|
|
25e457595a | ||
|
|
493705336c | ||
|
|
4cbe16197c | ||
|
|
0cea55924b | ||
|
|
9ee57d4362 | ||
|
|
715733f44d | ||
|
|
1e9f870b74 | ||
|
|
efe120ce9a | ||
|
|
5f84325cd8 | ||
|
|
8fbcba0091 | ||
|
|
d8195e9276 | ||
|
|
5f95d032ee | ||
|
|
31715ff227 | ||
|
|
ece229c06f | ||
|
|
1997a8f7e2 | ||
|
|
b91d82bfaa | ||
|
|
9005a62dc2 | ||
|
|
7665559d0e | ||
|
|
66a8df081e | ||
|
|
b76165abf6 | ||
|
|
abad8e474b | ||
|
|
f09cc26f87 | ||
|
|
e2a67812de | ||
|
|
e6ee613e00 | ||
|
|
6637de46c2 | ||
|
|
5985f8bd63 | ||
|
|
977921461d | ||
|
|
0b5fcbad1f | ||
|
|
4222f32cc4 | ||
|
|
4bdde36661 | ||
|
|
db5fe5659f | ||
|
|
db6b1b5ecc | ||
|
|
a273b9cf4a | ||
|
|
f11f6a2195 | ||
|
|
bde9b1cfcd | ||
|
|
5eefe544ed | ||
|
|
dfbb387cc7 | ||
|
|
2d9380d75c | ||
|
|
e259dd525f | ||
|
|
9a0b604a99 | ||
|
|
47eb3dd0c0 | ||
|
|
af8c8516d1 | ||
|
|
0d4dfb61dc | ||
|
|
463deedc29 | ||
|
|
40890cfcf3 | ||
|
|
ea91209a66 | ||
|
|
cf5120ba75 | ||
|
|
79e9ae4550 | ||
|
|
9017d3ef9c | ||
|
|
67d0ccc398 | ||
|
|
9c797961fa | ||
|
|
c06467438d | ||
|
|
5e69aaf4c2 | ||
|
|
9125ec8739 | ||
|
|
99e64ed084 | ||
|
|
8698c44e2a | ||
|
|
b27df1b169 | ||
|
|
dfe9b7cc26 | ||
|
|
e5a4c82917 | ||
|
|
f4070f6c43 | ||
|
|
fedd3de59f | ||
|
|
4b53d88cb8 | ||
|
|
29d0987859 | ||
|
|
d74db90550 | ||
|
|
81cb40ce4b | ||
|
|
f5c289dce6 | ||
|
|
31d6f72abf | ||
|
|
e19b8c05cd | ||
|
|
c8c142b881 | ||
|
|
a1fab59811 | ||
|
|
d488198c9c | ||
|
|
a62f26434a | ||
|
|
35f51221f1 | ||
|
|
95b8689835 | ||
|
|
618f2d71fc | ||
|
|
62602569b3 | ||
|
|
e5e39a939a | ||
|
|
f89b49a014 | ||
|
|
9ee8067df6 |
@@ -19,6 +19,9 @@ init:
|
||||
# Stop git from changing newlines
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# NOTE: If you change the Vim or Vader versions here, please also update the
|
||||
# instructions for running tests on Windows in ale-development.txt
|
||||
|
||||
install:
|
||||
# Download and unpack Vim
|
||||
- ps: >-
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/report-a-bug.md
vendored
1
.github/ISSUE_TEMPLATE/report-a-bug.md
vendored
@@ -1,5 +1,6 @@
|
||||
---
|
||||
name: Report a bug
|
||||
labels: bug
|
||||
about: Report a bug with ALE.
|
||||
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
name: Suggest a new linter or fixer
|
||||
labels: new tool
|
||||
about: Suggest a new tool ALE can officially integrate with.
|
||||
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
name: Suggest an improvement
|
||||
labels: enhancement
|
||||
about: Suggest some way to improve ALE, or add a new feature.
|
||||
|
||||
---
|
||||
|
||||
17
.github/stale.yml
vendored
Normal file
17
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
# This configuration closes stale PRs after 28 + 7 days.
|
||||
# That's 4 weeks until stale bot complains, and a week until it closes a PR.
|
||||
# Issues in ALE are never, ever stale. They are either resolved or not.
|
||||
only: pulls
|
||||
daysUntilStale: 28
|
||||
daysUntilClose: 7
|
||||
exemptLabels: []
|
||||
staleLabel: stale
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not
|
||||
been updated recently. Make sure to write tests and document your changes.
|
||||
See `:help ale-dev` for information on writing tests.
|
||||
|
||||
If your pull request is good to merge, bother w0rp or another maintainer
|
||||
again, and get them to merge it.
|
||||
closeComment: false
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,11 +1,12 @@
|
||||
!.editorconfig
|
||||
*.obj
|
||||
*.pyc
|
||||
# Ignore all hidden files everywhere.
|
||||
# Use `git add -f` to add hidden files.
|
||||
.*
|
||||
__pycache__
|
||||
*.pyc
|
||||
/doc/tags
|
||||
/init.vim
|
||||
/test/ale-info-test-file
|
||||
/vader_output
|
||||
__pycache__
|
||||
tags
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016-2019, w0rp <devw0rp@gmail.com>
|
||||
Copyright (c) 2016-2020, w0rp <devw0rp@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
159
README.md
159
README.md
@@ -35,6 +35,10 @@ 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.
|
||||
|
||||
**Help Wanted:** If you would like to help maintain this plugin by managing the
|
||||
many issues and pull requests that are submitted, please send the author an
|
||||
email at [dev@w0rp.com](mailto:dev@w0rp.com?subject=Helping%20with%20ALE).
|
||||
|
||||
If you enjoy this plugin, feel free to contribute or check out the author's
|
||||
other content at [w0rp.com](https://w0rp.com).
|
||||
|
||||
@@ -57,23 +61,25 @@ other content at [w0rp.com](https://w0rp.com).
|
||||
4. [Contributing](#contributing)
|
||||
5. [FAQ](#faq)
|
||||
1. [How do I disable particular linters?](#faq-disable-linters)
|
||||
2. [How can I keep the sign gutter open?](#faq-keep-signs)
|
||||
3. [How can I change the signs ALE uses?](#faq-change-signs)
|
||||
4. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
|
||||
5. [How can I show errors or warnings in my statusline?](#faq-statusline)
|
||||
6. [How can I show errors or warnings in my lightline?](#faq-lightline)
|
||||
7. [How can I change the format for echo messages?](#faq-echo-format)
|
||||
8. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
|
||||
9. [How can I navigate between errors quickly?](#faq-navigation)
|
||||
10. [How can I run linters only when I save files?](#faq-lint-on-save)
|
||||
11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
|
||||
12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
|
||||
13. [How can I check Vue files with ESLint?](#faq-vue-eslint)
|
||||
14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
|
||||
15. [How can I configure my C or C++ project?](#faq-c-configuration)
|
||||
16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
|
||||
17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
|
||||
18. [How can I see what ALE has configured for the current file?](#faq-get-info)
|
||||
2. [How can I see what ALE has configured for the current file?](#faq-get-info)
|
||||
3. [How can I use ALE and coc.nvim together?](#faq-coc-nvim)
|
||||
4. [How can I keep the sign gutter open?](#faq-keep-signs)
|
||||
5. [How can I change the signs ALE uses?](#faq-change-signs)
|
||||
6. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
|
||||
7. [How can I show errors or warnings in my statusline?](#faq-statusline)
|
||||
8. [How can I show errors or warnings in my lightline?](#faq-lightline)
|
||||
9. [How can I change the format for echo messages?](#faq-echo-format)
|
||||
10. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
|
||||
11. [How can I navigate between errors quickly?](#faq-navigation)
|
||||
12. [How can I run linters only when I save files?](#faq-lint-on-save)
|
||||
13. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
|
||||
14. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
|
||||
15. [How can I check Vue files with ESLint?](#faq-vue-eslint)
|
||||
16. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
|
||||
17. [How can I configure my C or C++ project?](#faq-c-configuration)
|
||||
18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
|
||||
19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
|
||||
20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
|
||||
|
||||
<a name="supported-languages"></a>
|
||||
|
||||
@@ -98,7 +104,7 @@ programs for checking the syntax and semantics of your programs. By default,
|
||||
linters will be re-run in the background to check your syntax when you open
|
||||
new buffers or as you make edits to your files.
|
||||
|
||||
The behaviour of linting can be configured with a variety of options,
|
||||
The behavior of linting can be configured with a variety of options,
|
||||
documented in [the Vim help file](doc/ale.txt). For more information on the
|
||||
options ALE offers, consult `:help ale-options` for global options and `:help
|
||||
ale-integration-options` for options specified to particular linters.
|
||||
@@ -189,12 +195,11 @@ completion manually with `<C-x><C-o>`.
|
||||
set omnifunc=ale#completion#OmniFunc
|
||||
```
|
||||
|
||||
When working with TypeScript files, ALE supports automatic imports from
|
||||
external modules. This behavior is disabled by default and can be enabled by
|
||||
setting:
|
||||
ALE supports automatic imports from external modules. This behavior is disabled
|
||||
by default and can be enabled by setting:
|
||||
|
||||
```vim
|
||||
let g:ale_completion_tsserver_autoimport = 1
|
||||
let g:ale_completion_autoimport = 1
|
||||
```
|
||||
|
||||
See `:help ale-completion` for more information.
|
||||
@@ -227,6 +232,9 @@ ALE supports "hover" information for printing brief information about symbols at
|
||||
the cursor taken from Language Server Protocol linters and `tsserver` with the
|
||||
`ALEHover` command.
|
||||
|
||||
Truncated information will be displayed when the cursor rests on a symbol by
|
||||
default, as long as there are no problems on the same line.
|
||||
|
||||
The information can be displayed in a `balloon` tooltip in Vim or GVim by
|
||||
hovering your mouse over symbols. Mouse hovering is enabled by default in GVim,
|
||||
and needs to be configured for Vim 8.1+ in terminals.
|
||||
@@ -409,9 +417,56 @@ This plugin will look for linters in the [`ale_linters`](ale_linters) directory.
|
||||
Each directory within corresponds to a particular filetype in Vim, and each file
|
||||
in each directory corresponds to the name of a particular linter.
|
||||
|
||||
<a name="faq-get-info"></a>
|
||||
|
||||
### 5.ii. How can I see what ALE has configured for the current file?
|
||||
|
||||
Run the following to see what is currently configured:
|
||||
|
||||
```vim
|
||||
:ALEInfo
|
||||
```
|
||||
|
||||
<a name="faq-coc-nvim"></a>
|
||||
|
||||
### 5.iii. How can I use ALE and coc.nvim together?
|
||||
|
||||
[coc.nvim](https://github.com/neoclide/coc.nvim) is a popular Vim plugin written
|
||||
in TypeScript and dependent on the [npm](https://www.npmjs.com/) ecosystem for
|
||||
providing full IDE features to Vim. Both ALE and coc.nvim implement
|
||||
[Language Server Protocol](https://microsoft.github.io/language-server-protocol/)
|
||||
(LSP) clients for supporting diagnostics (linting with a live server), and other
|
||||
features like auto-completion, and others listed above.
|
||||
|
||||
ALE is primarily focused on integrating with external programs through virtually
|
||||
any means, provided the plugin remains almost entirely written in Vim script.
|
||||
coc.nvim is primarily focused on bringing IDE features to Vim. If you want to
|
||||
run external programs on your files to check for errors, and also use the most
|
||||
advanced IDE features, you might want to use both plugins at the same time.
|
||||
|
||||
The easiest way to get both plugins to work together is to configure coc.nvim to
|
||||
send diagnostics to ALE, so ALE controls how all problems are presented to you,
|
||||
and to disable all LSP features in ALE, so ALE doesn't try to provide LSP
|
||||
features already provided by coc.nvim, such as auto-completion.
|
||||
|
||||
1. Open your coc.nvim configuration file with `:CocConfig` and add
|
||||
`"diagnostic.displayByAle": true` to your settings.
|
||||
2. Add `let g:ale_disable_lsp = 1` to your vimrc file, before plugins are
|
||||
loaded.
|
||||
|
||||
You can also use `b:ale_disable_lsp` in your ftplugin files to enable or disable
|
||||
LSP features in ALE for different filetypes. After you configure coc.nvim and
|
||||
ALE this way, you can further configure how problems appear to you by using all
|
||||
of the settings mentioned in ALE's help file, including how often diagnostics
|
||||
are requested. See `:help ale-lint`.
|
||||
|
||||
The integration between ALE and coc.nvim works using an API ALE offers for
|
||||
letting any other plugin integrate with ALE. If you are interested in writing a
|
||||
similar integration, see `:help ale-lint-other-sources`.
|
||||
|
||||
<a name="faq-keep-signs"></a>
|
||||
|
||||
### 5.ii. How can I keep the sign gutter open?
|
||||
### 5.iv. How can I keep the sign gutter open?
|
||||
|
||||
You can keep the sign gutter open at all times by setting the
|
||||
`g:ale_sign_column_always` to 1
|
||||
@@ -422,7 +477,7 @@ let g:ale_sign_column_always = 1
|
||||
|
||||
<a name="faq-change-signs"></a>
|
||||
|
||||
### 5.iii. How can I change the signs ALE uses?
|
||||
### 5.v. How can I change the signs ALE uses?
|
||||
|
||||
Use these options to specify what text should be used for signs:
|
||||
|
||||
@@ -442,7 +497,7 @@ highlight clear ALEWarningSign
|
||||
|
||||
<a name="faq-change-highlights"></a>
|
||||
|
||||
### 5.iv. How can I change or disable the highlights ALE uses?
|
||||
### 5.vi. How can I change or disable the highlights ALE uses?
|
||||
|
||||
ALE's highlights problems with highlight groups which link to `SpellBad`,
|
||||
`SpellCap`, `error`, and `todo` groups by default. The characters that are
|
||||
@@ -468,7 +523,7 @@ See `:help ale-highlights` for more information.
|
||||
|
||||
<a name="faq-statusline"></a>
|
||||
|
||||
### 5.v. How can I show errors or warnings in my statusline?
|
||||
### 5.vii. How can I show errors or warnings in my statusline?
|
||||
|
||||
[vim-airline](https://github.com/vim-airline/vim-airline) integrates with ALE
|
||||
for displaying error information in the status bar. If you want to see the
|
||||
@@ -517,7 +572,7 @@ for more information.
|
||||
|
||||
<a name="faq-lightline"></a>
|
||||
|
||||
### 5.vi. How can I show errors or warnings in my lightline?
|
||||
### 5.viii. How can I show errors or warnings in my lightline?
|
||||
|
||||
[lightline](https://github.com/itchyny/lightline.vim) does not have built-in
|
||||
support for ALE, nevertheless there is a plugin that adds this functionality: [maximbaz/lightline-ale](https://github.com/maximbaz/lightline-ale).
|
||||
@@ -526,7 +581,7 @@ For more information, check out the sources of that plugin, `:help ale#statuslin
|
||||
|
||||
<a name="faq-echo-format"></a>
|
||||
|
||||
### 5.vii. How can I change the format for echo messages?
|
||||
### 5.ix. How can I change the format for echo messages?
|
||||
|
||||
There are 3 global options that allow customizing the echoed message.
|
||||
|
||||
@@ -555,7 +610,7 @@ See `:help g:ale_echo_msg_format` for more information.
|
||||
|
||||
<a name="faq-autocmd"></a>
|
||||
|
||||
### 5.viii. How can I execute some code when ALE starts or stops linting?
|
||||
### 5.x. How can I execute some code when ALE starts or stops linting?
|
||||
|
||||
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
|
||||
events when a lint or fix cycle are started and stopped. There is also an event
|
||||
@@ -578,7 +633,7 @@ augroup END
|
||||
|
||||
<a name="faq-navigation"></a>
|
||||
|
||||
### 5.ix. How can I navigate between errors quickly?
|
||||
### 5.xi. How can I navigate between errors quickly?
|
||||
|
||||
ALE offers some commands with `<Plug>` keybinds for moving between warnings and
|
||||
errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
|
||||
@@ -594,7 +649,7 @@ For more information, consult the online documentation with
|
||||
|
||||
<a name="faq-lint-on-save"></a>
|
||||
|
||||
### 5.x. How can I run linters only when I save files?
|
||||
### 5.xii. How can I run linters only when I save files?
|
||||
|
||||
ALE offers an option `g:ale_lint_on_save` for enabling running the linters
|
||||
when files are saved. This option is enabled by default. If you only
|
||||
@@ -615,7 +670,7 @@ files, you can set `g:ale_lint_on_save` to `0`.
|
||||
|
||||
<a name="faq-quickfix"></a>
|
||||
|
||||
### 5.xi. How can I use the quickfix list instead of the loclist?
|
||||
### 5.xiii. How can I use the quickfix list instead of the loclist?
|
||||
|
||||
The quickfix list can be enabled by turning the `g:ale_set_quickfix`
|
||||
option on. If you wish to also disable the loclist, you can disable
|
||||
@@ -645,7 +700,7 @@ instead of the default horizontally.
|
||||
|
||||
<a name="faq-jsx-stylelint-eslint"></a>
|
||||
|
||||
### 5.xii. How can I check JSX files with both stylelint and eslint?
|
||||
### 5.xiv. How can I check JSX files with both stylelint and eslint?
|
||||
|
||||
If you configure ALE options correctly in your vimrc file, and install
|
||||
the right tools, you can check JSX files with stylelint and eslint.
|
||||
@@ -687,7 +742,7 @@ no linter will be run twice for the same file.
|
||||
|
||||
<a name="faq-vue-eslint"></a>
|
||||
|
||||
### 5.xiii. How can I check Vue files with ESLint?
|
||||
### 5.xv. How can I check Vue files with ESLint?
|
||||
|
||||
To check Vue files with ESLint, your ESLint project configuration file must be
|
||||
configured to use the [Vue plugin](https://github.com/vuejs/eslint-plugin-vue).
|
||||
@@ -718,7 +773,7 @@ let g:ale_linters = {'vue': ['eslint', 'vls']}
|
||||
|
||||
<a name="faq-my-battery-is-sad"></a>
|
||||
|
||||
### 5.xiv. Will this plugin eat all of my laptop battery power?
|
||||
### 5.xvi. Will this plugin eat all of my laptop battery power?
|
||||
|
||||
ALE takes advantage of the power of various tools to check your code. This of
|
||||
course means that CPU time will be used to continuously check your code. If you
|
||||
@@ -731,7 +786,7 @@ while you type. ALE uses a timeout which is cancelled and reset every time you
|
||||
type, and this delay can be increased so linters are run less often. See
|
||||
`:help g:ale_lint_delay` for more information.
|
||||
|
||||
If you don't wish to run linters while you type, you can disable that behaviour.
|
||||
If you don't wish to run linters while you type, you can disable that behavior.
|
||||
Set `g:ale_lint_on_text_changed` to `never`. You won't get as frequent error
|
||||
checking, but ALE shouldn't block your ability to edit a document after you save
|
||||
a file, so the asynchronous nature of the plugin will still be an advantage.
|
||||
@@ -742,7 +797,7 @@ including the option `g:ale_lint_on_enter`, and you can run ALE manually with
|
||||
|
||||
<a name="faq-c-configuration"></a>
|
||||
|
||||
### 5.xv. How can I configure my C or C++ project?
|
||||
### 5.xvii. How can I configure my C or C++ project?
|
||||
|
||||
The structure of C and C++ projects varies wildly from project to project, with
|
||||
many different build tools being used for building them, and many different
|
||||
@@ -762,13 +817,24 @@ setting. Consult the documentation for that setting for more information.
|
||||
`b:ale_linters` can be used to select which tools you want to run, say if you
|
||||
want to use only `gcc` for one project, and only `clang` for another.
|
||||
|
||||
ALE will attempt to parse `compile_commands.json` files to discover compiler
|
||||
flags to use when linting code. See `:help g:ale_c_parse_compile_commands` for
|
||||
more information. See Clang's documentation for
|
||||
[compile_commands.json files](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
|
||||
You should strongly consider generating them in your builds, which is easy to do
|
||||
with CMake.
|
||||
|
||||
You can also configure ALE to automatically run `make -n` to run dry runs on
|
||||
`Makefile`s to discover compiler flags. This can execute arbitrary code, so the
|
||||
option is disabled by default. See `:help g:ale_c_parse_makefile`.
|
||||
|
||||
You may also configure buffer-local settings for linters with project-specific
|
||||
vimrc files. [local_vimrc](https://github.com/LucHermitte/local_vimrc) can be
|
||||
used for executing local vimrc files which can be shared in your project.
|
||||
|
||||
<a name="faq-buffer-configuration"></a>
|
||||
|
||||
### 5.xvi. How can I configure ALE differently for different buffers?
|
||||
### 5.xviii. How can I configure ALE differently for different buffers?
|
||||
|
||||
ALE offers various ways to configure which linters or fixers are run, and
|
||||
other settings. For the majority of ALE's settings, they can either be
|
||||
@@ -804,7 +870,7 @@ Buffer-local variables for settings always override the global settings.
|
||||
|
||||
<a name="faq-list-window-height"></a>
|
||||
|
||||
### 5.xvii. How can I configure the height of the list in which ALE displays errors?
|
||||
### 5.xix. How can I configure the height of the list in which ALE displays errors?
|
||||
|
||||
To set a default height for the error list, use the `g:ale_list_window_size` variable.
|
||||
|
||||
@@ -813,12 +879,13 @@ To set a default height for the error list, use the `g:ale_list_window_size` var
|
||||
let g:ale_list_window_size = 5
|
||||
```
|
||||
|
||||
<a name="faq-get-info"></a>
|
||||
<a name="faq-vm"></a>
|
||||
|
||||
### 5.xviii. How can I see what ALE has configured for the current file?
|
||||
### 5.xx. How can I run linters or fixers via Docker or a VM?
|
||||
|
||||
Run the following to see what is currently configured:
|
||||
|
||||
```vim
|
||||
:ALEInfo
|
||||
```
|
||||
ALE supports running linters or fixers via Docker, virtual machines, or in
|
||||
combination with any remote machine with a different file system, so long as the
|
||||
tools are well-integrated with ALE, and ALE is properly configured to run the
|
||||
correct commands and map filename paths between different file systems. See
|
||||
`:help ale-lint-other-machines` for the full documentation on how to configure
|
||||
ALE to support this.
|
||||
|
||||
@@ -18,7 +18,7 @@ function! ale_linters#ada#gcc#GetCommand(buffer) abort
|
||||
" -gnatc: Check syntax and semantics only (no code generation attempted)
|
||||
return '%e -x ada -c -gnatc'
|
||||
\ . ' -o ' . ale#Escape(l:out_file)
|
||||
\ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ' -I %s:h'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
5
ale_linters/asciidoc/languagetool.vim
Normal file
5
ale_linters/asciidoc/languagetool.vim
Normal file
@@ -0,0 +1,5 @@
|
||||
" Author: Horacio Sanson (hsanson [ät] gmail.com)
|
||||
" Description: languagetool for asciidoc files, copied from markdown.
|
||||
|
||||
|
||||
call ale#handlers#languagetool#DefineLinter('asciidoc')
|
||||
@@ -9,7 +9,7 @@ function! ale_linters#asm#gcc#GetCommand(buffer) abort
|
||||
" -fsyntax-only doesn't catch everything.
|
||||
return '%e -x assembler'
|
||||
\ . ' -o ' . g:ale#util#nul_file
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . '-iquote %s:h'
|
||||
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
|
||||
endfunction
|
||||
|
||||
|
||||
4
ale_linters/bats/shellcheck.vim
Normal file
4
ale_linters/bats/shellcheck.vim
Normal file
@@ -0,0 +1,4 @@
|
||||
" Author: Ian2020 <https://github.com/Ian2020>
|
||||
" Description: shellcheck linter for bats scripts.
|
||||
|
||||
call ale#handlers#shellcheck#DefineLinter('bats')
|
||||
53
ale_linters/c/cc.vim
Normal file
53
ale_linters/c/cc.vim
Normal file
@@ -0,0 +1,53 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: A C compiler linter for C files with gcc/clang, etc.
|
||||
|
||||
call ale#Set('c_cc_executable', '<auto>')
|
||||
call ale#Set('c_cc_options', '-std=c11 -Wall')
|
||||
|
||||
function! ale_linters#c#cc#GetExecutable(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'c_cc_executable')
|
||||
|
||||
" Default to either clang or gcc.
|
||||
if l:executable is# '<auto>'
|
||||
if ale#engine#IsExecutable(a:buffer, 'clang')
|
||||
let l:executable = 'clang'
|
||||
else
|
||||
let l:executable = 'gcc'
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#cc#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
let l:ale_flags = ale#Var(a:buffer, 'c_cc_options')
|
||||
|
||||
if l:cflags =~# '-std='
|
||||
let l:ale_flags = substitute(
|
||||
\ l:ale_flags,
|
||||
\ '-std=\(c\|gnu\)[0-9]\{2\}',
|
||||
\ '',
|
||||
\ 'g')
|
||||
endif
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
"
|
||||
" `-o /dev/null` or `-o null` is needed to catch all errors,
|
||||
" -fsyntax-only doesn't catch everything.
|
||||
return '%e -S -x c'
|
||||
\ . ' -o ' . g:ale#util#nul_file
|
||||
\ . ' -iquote %s:h'
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(l:ale_flags) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'cc',
|
||||
\ 'aliases': ['gcc', 'clang'],
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': function('ale_linters#c#cc#GetExecutable'),
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#cc#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
call ale#Set('c_ccls_executable', 'ccls')
|
||||
call ale#Set('c_ccls_init_options', {})
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'ccls',
|
||||
@@ -10,5 +11,5 @@ call ale#linter#Define('c', {
|
||||
\ 'executable': {b -> ale#Var(b, 'c_ccls_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'c_ccls_init_options')},
|
||||
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'c_ccls_init_options')},
|
||||
\})
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
" Author: Masahiro H https://github.com/mshr-h
|
||||
" Description: clang linter for c files
|
||||
|
||||
call ale#Set('c_clang_executable', 'clang')
|
||||
call ale#Set('c_clang_options', '-std=c11 -Wall')
|
||||
|
||||
function! ale_linters#c#clang#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return '%e -S -x c -fsyntax-only'
|
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': {b -> ale#Var(b, 'c_clang_executable')},
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clang#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
call ale#Set('c_clangd_executable', 'clangd')
|
||||
call ale#Set('c_clangd_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
function! ale_linters#c#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
|
||||
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
|
||||
|
||||
return '%e'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
|
||||
\ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
|
||||
@@ -10,9 +10,11 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c'
|
||||
\ . l:template
|
||||
\ . ale#Pad(l:compile_commands_option)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
|
||||
\ . l:buffer_path_include
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: gcc linter for c files
|
||||
|
||||
call ale#Set('c_gcc_executable', 'gcc')
|
||||
call ale#Set('c_gcc_options', '-std=c11 -Wall')
|
||||
|
||||
function! ale_linters#c#gcc#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
"
|
||||
" `-o /dev/null` or `-o null` is needed to catch all errors,
|
||||
" -fsyntax-only doesn't catch everything.
|
||||
return '%e -S -x c'
|
||||
\ . ' -o ' . g:ale#util#nul_file
|
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('c', {
|
||||
\ 'name': 'gcc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': {b -> ale#Var(b, 'c_gcc_executable')},
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#gcc#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -29,6 +29,6 @@ call ale#linter#Define('clojure', {
|
||||
\ 'name': 'clj-kondo',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'clj-kondo',
|
||||
\ 'command': 'clj-kondo --lint %t',
|
||||
\ 'command': 'clj-kondo --cache --lint %t',
|
||||
\ 'callback': 'ale_linters#clojure#clj_kondo#HandleCljKondoFormat',
|
||||
\})
|
||||
|
||||
53
ale_linters/cpp/cc.vim
Normal file
53
ale_linters/cpp/cc.vim
Normal file
@@ -0,0 +1,53 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: A C++ compiler linter for C++ files with gcc/clang, etc.
|
||||
|
||||
call ale#Set('cpp_cc_executable', '<auto>')
|
||||
call ale#Set('cpp_cc_options', '-std=c++14 -Wall')
|
||||
|
||||
function! ale_linters#cpp#cc#GetExecutable(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'cpp_cc_executable')
|
||||
|
||||
" Default to either clang++ or gcc.
|
||||
if l:executable is# '<auto>'
|
||||
if ale#engine#IsExecutable(a:buffer, 'clang++')
|
||||
let l:executable = 'clang++'
|
||||
else
|
||||
let l:executable = 'gcc'
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#cc#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
let l:ale_flags = ale#Var(a:buffer, 'cpp_cc_options')
|
||||
|
||||
if l:cflags =~# '-std='
|
||||
let l:ale_flags = substitute(
|
||||
\ l:ale_flags,
|
||||
\ '-std=\(c\|gnu\)++[0-9]\{2\}',
|
||||
\ '',
|
||||
\ 'g')
|
||||
endif
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
"
|
||||
" `-o /dev/null` or `-o null` is needed to catch all errors,
|
||||
" -fsyntax-only doesn't catch everything.
|
||||
return '%e -S -x c++'
|
||||
\ . ' -o ' . g:ale#util#nul_file
|
||||
\ . ' -iquote %s:h'
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(l:ale_flags) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'cc',
|
||||
\ 'aliases': ['gcc', 'clang', 'g++', 'clang++'],
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': function('ale_linters#cpp#cc#GetExecutable'),
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#cc#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
call ale#Set('cpp_ccls_executable', 'ccls')
|
||||
call ale#Set('cpp_ccls_init_options', {})
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'ccls',
|
||||
@@ -10,5 +11,5 @@ call ale#linter#Define('cpp', {
|
||||
\ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'cpp_ccls_init_options')},
|
||||
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'cpp_ccls_init_options')},
|
||||
\})
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
" Author: Tomota Nakamura <https://github.com/tomotanakamura>
|
||||
" Description: clang linter for cpp files
|
||||
|
||||
call ale#Set('cpp_clang_executable', 'clang++')
|
||||
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
|
||||
|
||||
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return '%e -S -x c++ -fsyntax-only'
|
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clang',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')},
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clang#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -20,7 +20,7 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
|
||||
" being generated. These are only added if no build directory can be
|
||||
" detected.
|
||||
return '%e -analyze %s'
|
||||
\ . (empty(l:build_dir) ? ' -extra-arg -Xclang -extra-arg -analyzer-output=text' : '')
|
||||
\ . (empty(l:build_dir) ? ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics': '')
|
||||
\ . ale#Pad(l:user_options)
|
||||
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
|
||||
endfunction
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
call ale#Set('cpp_clangd_executable', 'clangd')
|
||||
call ale#Set('cpp_clangd_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
function! ale_linters#cpp#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
|
||||
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
|
||||
|
||||
return '%e'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
|
||||
\ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
|
||||
@@ -25,6 +25,11 @@ function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
|
||||
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
|
||||
endif
|
||||
|
||||
" Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file.
|
||||
if expand('#' . a:buffer) =~# '\.h$'
|
||||
let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
|
||||
endif
|
||||
|
||||
" Get the options to pass directly to clang-tidy
|
||||
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
|
||||
|
||||
|
||||
@@ -10,9 +10,11 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c++'
|
||||
\ . l:template
|
||||
\ . ale#Pad(l:compile_commands_option)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
|
||||
\ . l:buffer_path_include
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
" Author: geam <mdelage@student.42.fr>
|
||||
" Description: gcc linter for cpp files
|
||||
"
|
||||
call ale#Set('cpp_gcc_executable', 'gcc')
|
||||
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
|
||||
|
||||
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
"
|
||||
" `-o /dev/null` or `-o null` is needed to catch all errors,
|
||||
" -fsyntax-only doesn't catch everything.
|
||||
return '%e -S -x c++'
|
||||
\ . ' -o ' . g:ale#util#nul_file
|
||||
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . ale#Pad(l:cflags)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cpp', {
|
||||
\ 'name': 'gcc',
|
||||
\ 'aliases': ['g++'],
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')},
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#gcc#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
|
||||
\})
|
||||
@@ -5,6 +5,10 @@ function! ale_linters#crystal#crystal#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
if !has_key(l:error, 'file')
|
||||
continue
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.line + 0,
|
||||
\ 'col': l:error.column + 0,
|
||||
|
||||
@@ -5,9 +5,6 @@ call ale#Set('cuda_nvcc_executable', 'nvcc')
|
||||
call ale#Set('cuda_nvcc_options', '-std=c++11')
|
||||
|
||||
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
|
||||
" Unused: use ale#util#nul_file
|
||||
" let l:output_file = ale#util#Tempname() . '.ii'
|
||||
" call ale#command#ManageFile(a:buffer, l:output_file)
|
||||
return '%e -cuda'
|
||||
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))
|
||||
|
||||
@@ -32,14 +32,29 @@ function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
|
||||
let l:line = get(l:object, 'line', -1)
|
||||
let l:message = l:object['message']
|
||||
|
||||
if get(l:object, 'description', 'None') isnot# 'None'
|
||||
let l:message = l:message . '. ' . l:object['description']
|
||||
let l:link = get(l:object, 'reference_url', '')
|
||||
|
||||
if type(l:link) == v:t_list
|
||||
" Somehow, reference_url is returned as two-part list.
|
||||
" Anchor markers in that list are sometimes duplicated.
|
||||
" See https://github.com/projectatomic/dockerfile_lint/issues/134
|
||||
let l:link = join(l:link, '')
|
||||
let l:link = substitute(l:link, '##', '#', '')
|
||||
endif
|
||||
|
||||
let l:detail = l:message
|
||||
|
||||
if get(l:object, 'description', 'None') isnot# 'None'
|
||||
let l:detail .= "\n\n" . l:object['description']
|
||||
endif
|
||||
|
||||
let l:detail .= "\n\n" . l:link
|
||||
|
||||
call add(l:messages, {
|
||||
\ 'lnum': l:line,
|
||||
\ 'text': l:message,
|
||||
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
|
||||
\ 'detail': l:detail,
|
||||
\})
|
||||
endfor
|
||||
endfor
|
||||
|
||||
@@ -46,7 +46,7 @@ function! ale_linters#elixir#credo#GetMode() abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#elixir#credo#GetCommand(buffer) abort
|
||||
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
|
||||
let l:project_root = ale#handlers#elixir#FindMixUmbrellaRoot(a:buffer)
|
||||
let l:mode = ale_linters#elixir#credo#GetMode()
|
||||
|
||||
return ale#path#CdString(l:project_root)
|
||||
|
||||
@@ -11,7 +11,7 @@ function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
|
||||
\ . ' --format json --force-exclusion '
|
||||
\ . ale#Var(a:buffer, 'eruby_ruumba_options')
|
||||
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort
|
||||
|
||||
@@ -6,7 +6,6 @@ function! ale_linters#go#gofmt#GetCommand(buffer) abort
|
||||
\ . '%e -e %t'
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'gofmt',
|
||||
\ 'output_stream': 'stderr',
|
||||
|
||||
21
ale_linters/go/revive.vim
Normal file
21
ale_linters/go/revive.vim
Normal file
@@ -0,0 +1,21 @@
|
||||
" Author: Penghui Liao <liaoishere@gmail.com>
|
||||
" Description: Adds support for revive
|
||||
|
||||
call ale#Set('go_revive_executable', 'revive')
|
||||
call ale#Set('go_revive_options', '')
|
||||
|
||||
function! ale_linters#go#revive#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'go_revive_options')
|
||||
|
||||
return ale#go#EnvString(a:buffer) . '%e'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'revive',
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': {b -> ale#Var(b, 'go_revive_executable')},
|
||||
\ 'command': function('ale_linters#go#revive#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
|
||||
\})
|
||||
@@ -5,5 +5,5 @@ call ale#linter#Define('graphql', {
|
||||
\ 'name': 'eslint',
|
||||
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#eslint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#Handle',
|
||||
\ 'callback': 'ale#handlers#eslint#HandleJSON',
|
||||
\})
|
||||
|
||||
@@ -4,6 +4,28 @@
|
||||
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
|
||||
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [
|
||||
\ 'node_modules/.bin/ember-template-lint',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer, version) abort
|
||||
" Reading from stdin was introduced in ember-template-lint@1.6.0
|
||||
return ale#semver#GTE(a:version, [1, 6, 0])
|
||||
\ ? '%e --json --filename %s'
|
||||
\ : '%e --json %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck(buffer) abort
|
||||
return ale#semver#RunWithVersionCheck(
|
||||
\ a:buffer,
|
||||
\ ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer),
|
||||
\ '%e --version',
|
||||
\ function('ale_linters#handlebars#embertemplatelint#GetCommand'),
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
|
||||
@@ -30,10 +52,9 @@ function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('handlebars', {
|
||||
\ 'name': 'ember-template-lint',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [
|
||||
\ 'node_modules/.bin/ember-template-lint',
|
||||
\ ])},
|
||||
\ 'command': '%e --json %t',
|
||||
\ 'name': 'embertemplatelint',
|
||||
\ 'aliases': ['ember-template-lint'],
|
||||
\ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'),
|
||||
\ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'),
|
||||
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
|
||||
\})
|
||||
|
||||
@@ -52,7 +52,7 @@ endfunction
|
||||
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
|
||||
let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config')
|
||||
let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option)
|
||||
let l:config = l:options !~# '\v(^| )-c ' && !empty(l:config_option)
|
||||
\ ? s:GetConfig(a:buffer, l:config_option)
|
||||
\ : ''
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls'
|
||||
call ale#Set('java_eclipselsp_config_path', '')
|
||||
call ale#Set('java_eclipselsp_workspace_path', '')
|
||||
call ale#Set('java_eclipselsp_executable', 'java')
|
||||
call ale#Set('java_eclipselsp_javaagent', '')
|
||||
|
||||
function! ale_linters#java#eclipselsp#Executable(buffer) abort
|
||||
return ale#Var(a:buffer, 'java_eclipselsp_executable')
|
||||
@@ -19,25 +20,39 @@ endfunction
|
||||
function! ale_linters#java#eclipselsp#JarPath(buffer) abort
|
||||
let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer)
|
||||
|
||||
" Search jar file within repository path when manually built using mvn
|
||||
let l:repo_path = l:path . '/org.eclipse.jdt.ls.product/target/repository'
|
||||
let l:files = globpath(l:repo_path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
if has('win32')
|
||||
let l:platform = 'win32'
|
||||
elseif has('macunix')
|
||||
let l:platform = 'macosx'
|
||||
else
|
||||
let l:platform = 'linux'
|
||||
endif
|
||||
|
||||
if len(l:files) == 1
|
||||
" Search jar file within repository path when manually built using mvn
|
||||
let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
" Search jar file within VSCode extensions folder.
|
||||
let l:files = globpath(l:path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) == 1
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
" Search jar file within unzipped tar.gz file
|
||||
let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
" Search jar file within system package path
|
||||
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) == 1
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
@@ -100,12 +115,30 @@ function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
|
||||
return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#Javaagent(buffer) abort
|
||||
let l:rets = []
|
||||
let l:raw = ale#Var(a:buffer, 'java_eclipselsp_javaagent')
|
||||
|
||||
if empty(l:raw)
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:jars = split(l:raw)
|
||||
|
||||
for l:jar in l:jars
|
||||
call add(l:rets, ale#Escape('-javaagent:' . l:jar))
|
||||
endfor
|
||||
|
||||
return join(l:rets, ' ')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#Command(buffer, version) abort
|
||||
let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
|
||||
|
||||
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
|
||||
|
||||
let l:cmd = [ ale#Escape(l:executable),
|
||||
\ ale_linters#java#eclipselsp#Javaagent(a:buffer),
|
||||
\ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
|
||||
\ '-Dosgi.bundles.defaultStartLevel=4',
|
||||
\ '-Declipse.product=org.eclipse.jdt.ls.core.product',
|
||||
@@ -147,7 +180,8 @@ function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
|
||||
return ale#command#Run(
|
||||
\ a:buffer,
|
||||
\ l:command,
|
||||
\ function('ale_linters#java#eclipselsp#CommandWithVersion')
|
||||
\ function('ale_linters#java#eclipselsp#CommandWithVersion'),
|
||||
\ { 'output_stream': 'both' }
|
||||
\)
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ let s:classpath_sep = has('unix') ? ':' : ';'
|
||||
call ale#Set('java_javac_executable', 'javac')
|
||||
call ale#Set('java_javac_options', '')
|
||||
call ale#Set('java_javac_classpath', '')
|
||||
call ale#Set('java_javac_sourcepath', '')
|
||||
|
||||
function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
|
||||
let l:command = ''
|
||||
@@ -40,10 +41,15 @@ endfunction
|
||||
function! s:BuildClassPathOption(buffer, import_paths) abort
|
||||
" Filter out lines like [INFO], etc.
|
||||
let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''')
|
||||
call extend(
|
||||
\ l:class_paths,
|
||||
\ split(ale#Var(a:buffer, 'java_javac_classpath'), s:classpath_sep),
|
||||
\)
|
||||
let l:cls_path = ale#Var(a:buffer, 'java_javac_classpath')
|
||||
|
||||
if !empty(l:cls_path) && type(l:cls_path) is v:t_string
|
||||
call extend(l:class_paths, split(l:cls_path, s:classpath_sep))
|
||||
endif
|
||||
|
||||
if !empty(l:cls_path) && type(l:cls_path) is v:t_list
|
||||
call extend(l:class_paths, l:cls_path)
|
||||
endif
|
||||
|
||||
return !empty(l:class_paths)
|
||||
\ ? '-cp ' . ale#Escape(join(l:class_paths, s:classpath_sep))
|
||||
@@ -79,6 +85,27 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:source_paths = []
|
||||
let l:source_path = ale#Var(a:buffer, 'java_javac_sourcepath')
|
||||
|
||||
if !empty(l:source_path) && type(l:source_path) is v:t_string
|
||||
let l:source_paths = split(l:source_path, s:classpath_sep)
|
||||
endif
|
||||
|
||||
if !empty(l:source_path) && type(l:source_path) is v:t_list
|
||||
let l:source_paths = l:source_path
|
||||
endif
|
||||
|
||||
if !empty(l:source_paths)
|
||||
for l:path in l:source_paths
|
||||
let l:sp_path = ale#path#FindNearestDirectory(a:buffer, l:path)
|
||||
|
||||
if !empty(l:sp_path)
|
||||
call add(l:sp_dirs, l:sp_path)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if !empty(l:sp_dirs)
|
||||
let l:sp_option = '-sourcepath '
|
||||
\ . ale#Escape(join(l:sp_dirs, s:classpath_sep))
|
||||
|
||||
@@ -7,6 +7,7 @@ call ale#Set('javascript_standard_options', '')
|
||||
|
||||
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
|
||||
\ 'node_modules/standardx/bin/cmd.js',
|
||||
\ 'node_modules/standard/bin/cmd.js',
|
||||
\ 'node_modules/semistandard/bin/cmd.js',
|
||||
\ 'node_modules/.bin/standard',
|
||||
|
||||
@@ -174,6 +174,7 @@ endfunction
|
||||
call ale#linter#Define('kotlin', {
|
||||
\ 'name': 'kotlinc',
|
||||
\ 'executable': 'kotlinc',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': function('ale_linters#kotlin#kotlinc#RunWithImportPaths'),
|
||||
\ 'callback': 'ale_linters#kotlin#kotlinc#Handle',
|
||||
\ 'lint_file': 1,
|
||||
|
||||
@@ -6,5 +6,5 @@ call ale#linter#Define('kotlin', {
|
||||
\ 'executable': 'ktlint',
|
||||
\ 'command': function('ale#handlers#ktlint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#ktlint#Handle',
|
||||
\ 'lint_file': 1
|
||||
\ 'output_stream': 'stderr'
|
||||
\})
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
|
||||
" Description: Adds support for markdownlint
|
||||
|
||||
call ale#Set('markdown_markdownlint_options', '')
|
||||
|
||||
function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort
|
||||
let l:executable = 'markdownlint'
|
||||
|
||||
let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options')
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('markdown', {
|
||||
\ 'name': 'markdownlint',
|
||||
\ 'executable': 'markdownlint',
|
||||
\ 'lint_file': 1,
|
||||
\ 'output_stream': 'both',
|
||||
\ 'command': 'markdownlint %s',
|
||||
\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#markdownlint#Handle'
|
||||
\})
|
||||
|
||||
@@ -7,10 +7,9 @@ call ale#Set('nasm_nasm_options', '')
|
||||
function! ale_linters#nasm#nasm#GetCommand(buffer) abort
|
||||
" Note that NASM requires a trailing slash for the -I option.
|
||||
let l:separator = has('win32') ? '\' : '/'
|
||||
let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
|
||||
let l:output_null = has('win32') ? 'NUL' : '/dev/null'
|
||||
|
||||
return '%e -X gnu -I ' . ale#Escape(l:path)
|
||||
return '%e -X gnu -I %s:h' . l:separator
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
|
||||
\ . ' %s'
|
||||
\ . ' -o ' . l:output_null
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
" Author: Baabelfish
|
||||
" Description: Typechecking for nim files
|
||||
|
||||
let s:end_col_patterns = [
|
||||
\ '\v''([^'']+)'' is declared but not used.*',
|
||||
\ '\videntifier expected, but found ''([^'']+)''',
|
||||
\ '\vimported and not used: ''([^'']+)''.*',
|
||||
\ '\vundeclared identifier: ''([^'']+)''',
|
||||
\ '\v''([^'']+)'' cannot be assigned to',
|
||||
\ '\vredefinition of ''([^'']+)'';',
|
||||
\]
|
||||
|
||||
function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
|
||||
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p:t')
|
||||
let l:pattern = '^\(.\+\.nim\)(\(\d\+\), \(\d\+\)) \(.\+\)'
|
||||
@@ -43,6 +52,11 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
|
||||
let l:item.code = l:code_match[2]
|
||||
endif
|
||||
|
||||
" Find position end_col.
|
||||
for l:col_match in ale#util#GetMatches(l:item.text, s:end_col_patterns)
|
||||
let l:item.end_col = l:item.col + len(l:col_match[1]) - 1
|
||||
endfor
|
||||
|
||||
call add(l:output, l:item)
|
||||
endfor
|
||||
|
||||
|
||||
33
ale_linters/nim/nimlsp.vim
Normal file
33
ale_linters/nim/nimlsp.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: jeremija <https://github.com/jeremija>
|
||||
" Description: Support for nimlsp (language server for nim)
|
||||
|
||||
call ale#Set('nim_nimlsp_nim_sources', '')
|
||||
|
||||
function! ale_linters#nim#nimlsp#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
|
||||
if !empty(l:project_root)
|
||||
return fnamemodify(l:project_root, ':h:h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#nim#nimlsp#GetCommand(buffer) abort
|
||||
let l:nim_sources = ale#Var(a:buffer, 'nim_nimlsp_nim_sources')
|
||||
|
||||
if !empty(l:nim_sources)
|
||||
let l:nim_sources = ale#Escape(l:nim_sources)
|
||||
endif
|
||||
|
||||
return '%e' . ale#Pad(l:nim_sources)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('nim', {
|
||||
\ 'name': 'nimlsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': 'nimlsp',
|
||||
\ 'command': function('ale_linters#nim#nimlsp#GetCommand'),
|
||||
\ 'language': 'nim',
|
||||
\ 'project_root': function('ale_linters#nim#nimlsp#GetProjectRoot'),
|
||||
\})
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
call ale#Set('objc_ccls_executable', 'ccls')
|
||||
call ale#Set('objc_ccls_init_options', {})
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
call ale#linter#Define('objc', {
|
||||
\ 'name': 'ccls',
|
||||
@@ -10,5 +11,5 @@ call ale#linter#Define('objc', {
|
||||
\ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'objc_ccls_init_options')},
|
||||
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'objc_ccls_init_options')},
|
||||
\})
|
||||
|
||||
@@ -10,7 +10,7 @@ function! ale_linters#objc#clang#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang -S -x objective-c -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . '-iquote %s:h'
|
||||
\ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ function! ale_linters#objcpp#clang#GetCommand(buffer) abort
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return 'clang++ -S -x objective-c++ -fsyntax-only '
|
||||
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
\ . '-iquote %s:h'
|
||||
\ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ call ale#linter#Define('ocaml', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale#handlers#ols#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#ols#GetCommand'),
|
||||
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
|
||||
\ 'language': function('ale#handlers#ols#GetLanguage'),
|
||||
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
" Author: Matt Brown <https://github.com/muglug>
|
||||
" Description: plugin for Psalm, static analyzer for PHP
|
||||
|
||||
call ale#Set('psalm_langserver_executable', 'psalm')
|
||||
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('php_psalm_executable', 'psalm')
|
||||
call ale#Set('php_psalm_options', '')
|
||||
call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
@@ -10,12 +11,16 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#psalm#GetCommand(buffer) abort
|
||||
return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'php_psalm_options'))
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'psalm',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [
|
||||
\ 'vendor/bin/psalm',
|
||||
\ ])},
|
||||
\ 'command': '%e --language-server',
|
||||
\ 'command': function('ale_linters#php#psalm#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -12,6 +12,7 @@ endfunction
|
||||
" https://rkeithhill.wordpress.com/2007/10/30/powershell-quicktip-preparsing-scripts-to-check-for-syntax-errors/
|
||||
function! ale_linters#powershell#powershell#GetCommand(buffer) abort
|
||||
let l:script = ['Param($Script);
|
||||
\ $ErrorView = "Normal";
|
||||
\ trap {$_;continue} & {
|
||||
\ $Contents = Get-Content -Path $Script;
|
||||
\ $Contents = [string]::Join([Environment]::NewLine, $Contents);
|
||||
|
||||
@@ -8,13 +8,15 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
|
||||
" 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: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
|
||||
" Error: Illegal attempt to assign to 'a Name'. Not an assignable reference (file: /tmp/modules/waffles/manifests/syrup.pp, line: 5, column: 11)
|
||||
" Error: Could not parse for environment production: Syntax error at end of input (file: /tmp/modules/bob/manifests/init.pp)
|
||||
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[4] + 0,
|
||||
\ 'col': l:match[6] + 0,
|
||||
\ 'lnum': l:match[5] + 0,
|
||||
\ 'col': l:match[7] + 0,
|
||||
\ 'text': l:match[1],
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -6,9 +6,7 @@ call ale#Set('pyrex_cython_executable', 'cython')
|
||||
call ale#Set('pyrex_cython_options', '--warning-extra')
|
||||
|
||||
function! ale_linters#pyrex#cython#GetCommand(buffer) abort
|
||||
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
|
||||
return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
|
||||
return '%e --working %s:h --include-dir %s:h'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
|
||||
\ . ' --output-file ' . g:ale#util#nul_file . ' %t'
|
||||
endfunction
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
call ale#Set('python_flake8_executable', 'flake8')
|
||||
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)
|
||||
call ale#Set('python_flake8_change_directory', 'project')
|
||||
call ale#Set('python_flake8_auto_pipenv', 0)
|
||||
|
||||
function! s:UsingModule(buffer) abort
|
||||
@@ -38,10 +38,30 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#flake8#GetCdString(buffer) abort
|
||||
let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory')
|
||||
let l:cd_string = ''
|
||||
|
||||
if l:change_directory is# 'project'
|
||||
let l:project_root = ale#python#FindProjectRootIni(a:buffer)
|
||||
|
||||
if !empty(l:project_root)
|
||||
let l:cd_string = ale#path#CdString(l:project_root)
|
||||
endif
|
||||
endif
|
||||
|
||||
if (l:change_directory is# 'project' && empty(l:cd_string))
|
||||
\|| l:change_directory is# 1
|
||||
\|| l:change_directory is# 'file'
|
||||
let l:cd_string = ale#path#BufferCdString(a:buffer)
|
||||
endif
|
||||
|
||||
return l:cd_string
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#flake8#GetCommand(buffer, version) abort
|
||||
let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory')
|
||||
\ ? ale#path#BufferCdString(a:buffer)
|
||||
\ : ''
|
||||
let l:cd_string = ale_linters#python#flake8#GetCdString(a:buffer)
|
||||
|
||||
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
|
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
call ale#Set('python_mypy_executable', 'mypy')
|
||||
call ale#Set('python_mypy_ignore_invalid_syntax', 0)
|
||||
call ale#Set('python_mypy_show_notes', 1)
|
||||
call ale#Set('python_mypy_options', '')
|
||||
call ale#Set('python_mypy_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('python_mypy_auto_pipenv', 0)
|
||||
@@ -18,6 +19,15 @@ endfunction
|
||||
|
||||
" The directory to change to before running mypy
|
||||
function! s:GetDir(buffer) abort
|
||||
" If we find a directory with "mypy.ini" in it use that,
|
||||
" else try and find the "python project" root, or failing
|
||||
" that, run from the same folder as the current file
|
||||
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
|
||||
if filereadable(l:path . '/mypy.ini')
|
||||
return l:path
|
||||
endif
|
||||
endfor
|
||||
|
||||
let l:project_root = ale#python#FindProjectRoot(a:buffer)
|
||||
|
||||
return !empty(l:project_root)
|
||||
@@ -51,7 +61,16 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
" Lines like these should be ignored below:
|
||||
"
|
||||
" file.py:4: note: (Stub files are from https://github.com/python/typeshed)
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$'
|
||||
|
||||
let l:types = 'error|warning'
|
||||
|
||||
if ale#Var(a:buffer, 'python_mypy_show_notes')
|
||||
let l:types = 'error|warning|note'
|
||||
endif
|
||||
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: ('
|
||||
\ . l:types
|
||||
\ . '): (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
@@ -65,7 +84,7 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : (l:match[4] is# 'note' ? 'I': 'W'),
|
||||
\ 'text': l:match[5],
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -16,17 +16,15 @@ function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pydocstyle#GetCommand(buffer) abort
|
||||
let l:dir = fnamemodify(bufname(a:buffer), ':p:h')
|
||||
let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer)
|
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
\ ? ' run pydocstyle'
|
||||
\ : ''
|
||||
|
||||
return ale#path#CdString(l:dir)
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . l:exec_args
|
||||
\ . ' ' . ale#Var(a:buffer, 'python_pydocstyle_options')
|
||||
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:t'))
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options'))
|
||||
\ . ' %s:t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort
|
||||
|
||||
@@ -17,7 +17,7 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
|
||||
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pylint#GetCommand(buffer) abort
|
||||
function! ale_linters#python#pylint#GetCommand(buffer, version) abort
|
||||
let l:cd_string = ''
|
||||
|
||||
if ale#Var(a:buffer, 'python_pylint_change_directory')
|
||||
@@ -38,17 +38,23 @@ function! ale_linters#python#pylint#GetCommand(buffer) abort
|
||||
|
||||
return l:cd_string
|
||||
\ . ale#Escape(l:executable) . l:exec_args
|
||||
\ . ' ' . ale#Var(a:buffer, 'python_pylint_options')
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'python_pylint_options'))
|
||||
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n'
|
||||
\ . (ale#semver#GTE(a:version, [2, 4, 0]) ? ' --from-stdin' : '')
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#pylint#Handle(buffer, lines) abort
|
||||
let l:output = ale#python#HandleTraceback(a:lines, 10)
|
||||
|
||||
if !empty(l:output)
|
||||
return l:output
|
||||
endif
|
||||
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" test.py:4:4: W0101 (unreachable) Unreachable code
|
||||
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ([[:alnum:]]+) \(([^(]*)\) (.*)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
"let l:failed = append(0, l:match)
|
||||
@@ -71,13 +77,19 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
|
||||
let l:code_out = l:match[4]
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
let l:item = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 1,
|
||||
\ 'text': l:match[5],
|
||||
\ 'code': l:code_out,
|
||||
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
|
||||
\})
|
||||
\ 'type': 'W',
|
||||
\}
|
||||
|
||||
if l:code[:0] is# 'E'
|
||||
let l:item.type = 'E'
|
||||
endif
|
||||
|
||||
call add(l:output, l:item)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
@@ -86,7 +98,17 @@ endfunction
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'pylint',
|
||||
\ 'executable': function('ale_linters#python#pylint#GetExecutable'),
|
||||
\ 'command': function('ale_linters#python#pylint#GetCommand'),
|
||||
\ 'lint_file': {buffer -> ale#semver#RunWithVersionCheck(
|
||||
\ buffer,
|
||||
\ ale#Var(buffer, 'python_pylint_executable'),
|
||||
\ '%e --version',
|
||||
\ {buffer, version -> !ale#semver#GTE(version, [2, 4, 0])},
|
||||
\ )},
|
||||
\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
|
||||
\ buffer,
|
||||
\ ale#Var(buffer, 'python_pylint_executable'),
|
||||
\ '%e --version',
|
||||
\ function('ale_linters#python#pylint#GetCommand'),
|
||||
\ )},
|
||||
\ 'callback': 'ale_linters#python#pylint#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
|
||||
43
ale_linters/python/pyright.vim
Normal file
43
ale_linters/python/pyright.vim
Normal file
@@ -0,0 +1,43 @@
|
||||
call ale#Set('python_pyright_executable', 'pyright-langserver')
|
||||
call ale#Set('python_pyright_config', {})
|
||||
|
||||
function! ale_linters#python#pyright#GetConfig(buffer) abort
|
||||
let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config'))
|
||||
|
||||
if !has_key(l:config, 'python')
|
||||
let l:config.python = {}
|
||||
endif
|
||||
|
||||
if type(l:config.python) is v:t_dict
|
||||
" Automatically detect the virtualenv path and use it.
|
||||
if !has_key(l:config.python, 'venvPath')
|
||||
let l:venv = ale#python#FindVirtualenv(a:buffer)
|
||||
|
||||
if !empty(l:venv)
|
||||
let l:config.python.venvPath = l:venv
|
||||
endif
|
||||
endif
|
||||
|
||||
" Automatically use the version of Python in virtualenv.
|
||||
if type(get(l:config.python, 'venvPath')) is v:t_string
|
||||
\&& !empty(l:config.python.venvPath)
|
||||
\&& !has_key(l:config.python, 'pythonPath')
|
||||
let l:config.python.pythonPath = ale#path#Simplify(
|
||||
\ l:config.python.venvPath
|
||||
\ . (has('win32') ? '/Scripts/python' : '/bin/python')
|
||||
\)
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:config
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'pyright',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')},
|
||||
\ 'command': '%e --stdio',
|
||||
\ 'project_root': function('ale#python#FindProjectRoot'),
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'),
|
||||
\})
|
||||
@@ -9,6 +9,6 @@ call ale#linter#Define('reason', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale#handlers#ols#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#ols#GetCommand'),
|
||||
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
|
||||
\ 'language': function('ale#handlers#ols#GetLanguage'),
|
||||
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -10,7 +10,7 @@ function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
|
||||
\ . ' --format json --force-exclusion '
|
||||
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
|
||||
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#rubocop#GetType(severity) abort
|
||||
|
||||
@@ -11,7 +11,7 @@ function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
|
||||
\ . ' --format json --force-exclusion '
|
||||
\ . ale#Var(a:buffer, 'ruby_standardrb_options')
|
||||
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
" standardrb is based on RuboCop so the callback is the same
|
||||
|
||||
24
ale_linters/rust/analyzer.vim
Normal file
24
ale_linters/rust/analyzer.vim
Normal file
@@ -0,0 +1,24 @@
|
||||
" Author: Jon Gjengset <jon@thesquareplanet.com>
|
||||
" Description: The next generation language server for Rust
|
||||
|
||||
call ale#Set('rust_analyzer_executable', 'rust-analyzer')
|
||||
call ale#Set('rust_analyzer_config', {})
|
||||
|
||||
function! ale_linters#rust#analyzer#GetCommand(buffer) abort
|
||||
return '%e'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#rust#analyzer#GetProjectRoot(buffer) abort
|
||||
let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
|
||||
|
||||
return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('rust', {
|
||||
\ 'name': 'analyzer',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'rust_analyzer_config')},
|
||||
\ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')},
|
||||
\ 'command': function('ale_linters#rust#analyzer#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#rust#analyzer#GetProjectRoot'),
|
||||
\})
|
||||
@@ -11,6 +11,7 @@ call ale#Set('rust_cargo_default_feature_behavior', 'default')
|
||||
call ale#Set('rust_cargo_include_features', '')
|
||||
call ale#Set('rust_cargo_use_clippy', 0)
|
||||
call ale#Set('rust_cargo_clippy_options', '')
|
||||
call ale#Set('rust_cargo_target_dir', '')
|
||||
|
||||
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
|
||||
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
|
||||
@@ -31,6 +32,9 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
|
||||
\ && ale#semver#GTE(a:version, [0, 22, 0])
|
||||
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
|
||||
\ && ale#semver#GTE(a:version, [0, 22, 0])
|
||||
let l:target_dir = ale#Var(a:buffer, 'rust_cargo_target_dir')
|
||||
let l:use_target_dir = !empty(l:target_dir)
|
||||
\ && ale#semver#GTE(a:version, [0, 17, 0])
|
||||
|
||||
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
|
||||
|
||||
@@ -82,6 +86,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
|
||||
\ . (l:use_all_targets ? ' --all-targets' : '')
|
||||
\ . (l:use_examples ? ' --examples' : '')
|
||||
\ . (l:use_tests ? ' --tests' : '')
|
||||
\ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '')
|
||||
\ . ' --frozen --message-format=json -q'
|
||||
\ . l:default_feature
|
||||
\ . l:include_features
|
||||
|
||||
@@ -32,6 +32,8 @@ function! ale_linters#scala#metals#GetProjectRoot(buffer) abort
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scala#metals#GetCommand(buffer) abort
|
||||
|
||||
43
ale_linters/sh/bashate.vim
Normal file
43
ale_linters/sh/bashate.vim
Normal file
@@ -0,0 +1,43 @@
|
||||
" Author: hsanson <hsanson@gmail.com>
|
||||
" Description: Lints sh files using bashate
|
||||
" URL: https://github.com/openstack/bashate
|
||||
|
||||
call ale#Set('sh_bashate_executable', 'bashate')
|
||||
call ale#Set('sh_bashate_options', '')
|
||||
|
||||
function! ale_linters#sh#bashate#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'sh_bashate_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#bashate#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'sh_bashate_options')
|
||||
let l:executable = ale_linters#sh#bashate#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable) . ' ' . l:options . ' ' . '%t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#bashate#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" /path/to/script/file:694:1: E003 Indent not multiple of 4
|
||||
let l:pattern = ':\(\d\+\):\(\d\+\): \(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'col': str2nr(l:match[2]),
|
||||
\ 'text': l:match[3],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sh', {
|
||||
\ 'name': 'bashate',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': function('ale_linters#sh#bashate#GetExecutable'),
|
||||
\ 'command': function('ale_linters#sh#bashate#GetCommand'),
|
||||
\ 'callback': 'ale_linters#sh#bashate#Handle',
|
||||
\})
|
||||
@@ -1,5 +1,5 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Lints sh files using bash -n
|
||||
" Description: Lints shell files by invoking the shell with -n
|
||||
|
||||
" Backwards compatibility
|
||||
if exists('g:ale_linters_sh_shell_default_shell')
|
||||
|
||||
@@ -1,107 +1,4 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file adds support for using the shellcheck linter with
|
||||
" shell scripts.
|
||||
" Description: shellcheck linter for shell scripts.
|
||||
|
||||
" This global variable can be set with a string of comma-separated error
|
||||
" codes to exclude from shellcheck. For example:
|
||||
"
|
||||
" let g:ale_sh_shellcheck_exclusions = 'SC2002,SC2004'
|
||||
call ale#Set('sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_exclusions', ''))
|
||||
call ale#Set('sh_shellcheck_executable', 'shellcheck')
|
||||
call ale#Set('sh_shellcheck_dialect', 'auto')
|
||||
call ale#Set('sh_shellcheck_options', '')
|
||||
call ale#Set('sh_shellcheck_change_directory', 1)
|
||||
|
||||
function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort
|
||||
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
|
||||
|
||||
if !empty(l:shell_type)
|
||||
" Use the dash dialect for /bin/ash, etc.
|
||||
if l:shell_type is# 'ash'
|
||||
return 'dash'
|
||||
endif
|
||||
|
||||
return l:shell_type
|
||||
endif
|
||||
|
||||
" If there's no hashbang, try using Vim's buffer variables.
|
||||
if getbufvar(a:buffer, 'is_bash', 0)
|
||||
return 'bash'
|
||||
elseif getbufvar(a:buffer, 'is_sh', 0)
|
||||
return 'sh'
|
||||
elseif getbufvar(a:buffer, 'is_kornshell', 0)
|
||||
return 'ksh'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shellcheck#GetCommand(buffer, version) abort
|
||||
let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
|
||||
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
|
||||
let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect')
|
||||
let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : ''
|
||||
let l:cd_string = ale#Var(a:buffer, 'sh_shellcheck_change_directory')
|
||||
\ ? ale#path#BufferCdString(a:buffer)
|
||||
\ : ''
|
||||
|
||||
if l:dialect is# 'auto'
|
||||
let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer)
|
||||
endif
|
||||
|
||||
return l:cd_string
|
||||
\ . '%e'
|
||||
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
|
||||
\ . l:external_option
|
||||
\ . ' -f gcc -'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#sh#shellcheck#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+) \[([^\]]+)\]$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
if l:match[4] is# 'error'
|
||||
let l:type = 'E'
|
||||
elseif l:match[4] is# 'note'
|
||||
let l:type = 'I'
|
||||
else
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
let l:item = {
|
||||
\ 'lnum': str2nr(l:match[2]),
|
||||
\ 'type': l:type,
|
||||
\ 'text': l:match[5],
|
||||
\ 'code': l:match[6],
|
||||
\}
|
||||
|
||||
if !empty(l:match[3])
|
||||
let l:item.col = str2nr(l:match[3])
|
||||
endif
|
||||
|
||||
" If the filename is something like <stdin>, <nofile> or -, then
|
||||
" this is an error for the file we checked.
|
||||
if l:match[1] isnot# '-' && l:match[1][0] isnot# '<'
|
||||
let l:item['filename'] = l:match[1]
|
||||
endif
|
||||
|
||||
call add(l:output, l:item)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sh', {
|
||||
\ 'name': 'shellcheck',
|
||||
\ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')},
|
||||
\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
|
||||
\ buffer,
|
||||
\ ale#Var(buffer, 'sh_shellcheck_executable'),
|
||||
\ '%e --version',
|
||||
\ function('ale_linters#sh#shellcheck#GetCommand'),
|
||||
\ )},
|
||||
\ 'callback': 'ale_linters#sh#shellcheck#Handle',
|
||||
\})
|
||||
call ale#handlers#shellcheck#DefineLinter('sh')
|
||||
|
||||
33
ale_linters/sql/sqllint.vim
Normal file
33
ale_linters/sql/sqllint.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" ale_linters/sql/sqllint.vim
|
||||
" Author: Joe Reynolds <joereynolds952@gmail.co>
|
||||
" Description: sql-lint for SQL files.
|
||||
" sql-lint can be found at
|
||||
" https://www.npmjs.com/package/sql-lint
|
||||
" https://github.com/joereynolds/sql-lint
|
||||
|
||||
function! ale_linters#sql#sqllint#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
"
|
||||
" stdin:1 [ER_NO_DB_ERROR] No database selected
|
||||
let l:pattern = '\v^[^:]+:(\d+) (.*)'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'type': l:match[3][0],
|
||||
\ 'text': l:match[0],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('sql', {
|
||||
\ 'name': 'sqllint',
|
||||
\ 'aliases': ['sql-lint'],
|
||||
\ 'executable': 'sql-lint',
|
||||
\ 'command': 'sql-lint',
|
||||
\ 'callback': 'ale_linters#sql#sqllint#Handle',
|
||||
\})
|
||||
62
ale_linters/swift/swiftformat.vim
Normal file
62
ale_linters/swift/swiftformat.vim
Normal file
@@ -0,0 +1,62 @@
|
||||
" Author: Klaas Pieter Annema <https://github.com/klaaspieter>
|
||||
" Description: Support for swift-format https://github.com/apple/swift-format
|
||||
|
||||
let s:default_executable = 'swift-format'
|
||||
call ale#Set('swift_swiftformat_executable', s:default_executable)
|
||||
|
||||
function! ale_linters#swift#swiftformat#UseSwift(buffer) abort
|
||||
let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift')
|
||||
let l:executable = ale#Var(a:buffer, 'swift_swiftformat_executable')
|
||||
|
||||
return !empty(l:swift_config) && l:executable is# s:default_executable
|
||||
endfunction
|
||||
|
||||
function! ale_linters#swift#swiftformat#GetExecutable(buffer) abort
|
||||
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
|
||||
return 'swift'
|
||||
endif
|
||||
|
||||
return ale#Var(a:buffer, 'swift_swiftformat_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#swift#swiftformat#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#swift#swiftformat#GetExecutable(a:buffer)
|
||||
let l:args = '--mode lint %t'
|
||||
|
||||
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
|
||||
let l:args = 'run swift-format' . ' ' . l:args
|
||||
endif
|
||||
|
||||
return ale#Escape(l:executable) . ' ' . l:args
|
||||
endfunction
|
||||
|
||||
function! ale_linters#swift#swiftformat#Handle(buffer, lines) abort
|
||||
" Matches lines of the following pattern:
|
||||
"
|
||||
" Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove ';' and move the next statement to the new line
|
||||
" Sources/main.swift:3:12: warning: [Spacing]: remove 1 space
|
||||
let l:pattern = '\v^.*:(\d+):(\d+): (\S+) \[(\S+)\]: (.*)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[4],
|
||||
\ 'text': l:match[5],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('swift', {
|
||||
\ 'name': 'swift-format',
|
||||
\ 'executable': function('ale_linters#swift#swiftformat#GetExecutable'),
|
||||
\ 'command': function('ale_linters#swift#swiftformat#GetCommand'),
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'language': 'swift',
|
||||
\ 'callback': 'ale_linters#swift#swiftformat#Handle'
|
||||
\})
|
||||
25
ale_linters/terraform/terraform_lsp.vim
Normal file
25
ale_linters/terraform/terraform_lsp.vim
Normal file
@@ -0,0 +1,25 @@
|
||||
" Author: OJFord <dev@ojford.com>
|
||||
" Description: terraform-lsp integration for ALE (cf. https://github.com/juliosueiras/terraform-lsp)
|
||||
|
||||
call ale#Set('terraform_langserver_executable', 'terraform-lsp')
|
||||
call ale#Set('terraform_langserver_options', '')
|
||||
|
||||
function! ale_linters#terraform#terraform_lsp#GetCommand(buffer) abort
|
||||
return '%e'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'terraform_langserver_options'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform_lsp#GetProjectRoot(buffer) abort
|
||||
let l:tf_dir = ale#path#FindNearestDirectory(a:buffer, '.terraform')
|
||||
|
||||
return !empty(l:tf_dir) ? fnamemodify(l:tf_dir, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('terraform', {
|
||||
\ 'name': 'terraform_lsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'terraform_langserver_executable')},
|
||||
\ 'command': function('ale_linters#terraform#terraform_lsp#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#terraform#terraform_lsp#GetProjectRoot'),
|
||||
\ 'language': 'terraform',
|
||||
\})
|
||||
31
ale_linters/typescript/standard.vim
Normal file
31
ale_linters/typescript/standard.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Author: Ahmed El Gabri <@ahmedelgabri>
|
||||
" Description: standardjs for typescript files
|
||||
|
||||
call ale#Set('typescript_standard_executable', 'standard')
|
||||
call ale#Set('typescript_standard_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('typescript_standard_options', '')
|
||||
|
||||
function! ale_linters#typescript#standard#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'typescript_standard', [
|
||||
\ 'node_modules/standardx/bin/cmd.js',
|
||||
\ 'node_modules/standard/bin/cmd.js',
|
||||
\ 'node_modules/.bin/standard',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#standard#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#typescript#standard#GetExecutable(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'typescript_standard_options')
|
||||
|
||||
return ale#node#Executable(a:buffer, l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --stdin %s'
|
||||
endfunction
|
||||
|
||||
" standard uses eslint and the output format is the same
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'standard',
|
||||
\ 'executable': function('ale_linters#typescript#standard#GetExecutable'),
|
||||
\ 'command': function('ale_linters#typescript#standard#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#Handle',
|
||||
\})
|
||||
5
ale_linters/verilog/hdl_checker.vim
Normal file
5
ale_linters/verilog/hdl_checker.vim
Normal file
@@ -0,0 +1,5 @@
|
||||
" Author: suoto <andre820@gmail.com>
|
||||
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
|
||||
" or xvhdl. More info on https://github.com/suoto/hdl_checker
|
||||
|
||||
call ale#handlers#hdl_checker#DefineLinter('verilog')
|
||||
@@ -28,21 +28,30 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
|
||||
" %Warning-UNDRIVEN: test.v:3: Signal is not driven: clk
|
||||
" %Warning-UNUSED: test.v:4: Signal is not used: dout
|
||||
" %Warning-BLKSEQ: test.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).
|
||||
let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\): \(.\+\)$'
|
||||
" Since version 4.032 (04/2020) verilator linter messages also contain the column number,
|
||||
" and look like:
|
||||
" %Error: /tmp/test.sv:3:1: syntax error, unexpected endmodule, expecting ';'
|
||||
"
|
||||
" to stay compatible with old versions of the tool, the column number is
|
||||
" optional in the researched pattern
|
||||
let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\):\(\d\+\)\?:\? \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:line = l:match[3] + 0
|
||||
let l:type = l:match[1] is# 'Error' ? 'E' : 'W'
|
||||
let l:text = l:match[4]
|
||||
let l:item = {
|
||||
\ 'lnum': str2nr(l:match[3]),
|
||||
\ 'text': l:match[5],
|
||||
\ 'type': l:match[1] is# 'Error' ? 'E' : 'W',
|
||||
\}
|
||||
|
||||
if !empty(l:match[4])
|
||||
let l:item.col = str2nr(l:match[4])
|
||||
endif
|
||||
|
||||
let l:file = l:match[2]
|
||||
|
||||
if l:file =~# '_verilator_linted.v'
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:line,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
call add(l:output, l:item)
|
||||
endif
|
||||
endfor
|
||||
|
||||
|
||||
@@ -13,14 +13,15 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
|
||||
"Matches patterns like the following:
|
||||
"** Warning: add.v(7): (vlog-2623) Undefined variable: C.
|
||||
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C.
|
||||
let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
|
||||
let l:pattern = '^**\s\(\w*\): \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
|
||||
\ 'text': l:match[3],
|
||||
\ 'text': l:match[4],
|
||||
\ 'filename': l:match[2],
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -28,13 +29,14 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
|
||||
"** Warning: (vlog-2623) add.v(7): Undefined variable: C.
|
||||
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.
|
||||
" let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
|
||||
let l:pattern = '^**\s\(\w*\):\s\([^)]*)\)[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
|
||||
let l:pattern = '^**\s\(\w*\):\s\([^)]*)\) \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'lnum': l:match[4] + 0,
|
||||
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
|
||||
\ 'text': l:match[2] . ' ' . l:match[4],
|
||||
\ 'text': l:match[2] . ' ' . l:match[5],
|
||||
\ 'filename': l:match[3],
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
5
ale_linters/vhdl/hdl_checker.vim
Normal file
5
ale_linters/vhdl/hdl_checker.vim
Normal file
@@ -0,0 +1,5 @@
|
||||
" Author: suoto <andre820@gmail.com>
|
||||
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
|
||||
" or xvhdl. More info on https://github.com/suoto/hdl_checker
|
||||
|
||||
call ale#handlers#hdl_checker#DefineLinter('vhdl')
|
||||
61
ale_linters/vim/vimls.vim
Normal file
61
ale_linters/vim/vimls.vim
Normal file
@@ -0,0 +1,61 @@
|
||||
" Author: Jeffrey Lau - https://github.com/zoonfafer
|
||||
" Description: Vim Language Server integration for ALE
|
||||
|
||||
call ale#Set('vim_vimls_executable', 'vim-language-server')
|
||||
call ale#Set('vim_vimls_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('vim_vimls_config', {})
|
||||
|
||||
function! ale_linters#vim#vimls#GetProjectRoot(buffer) abort
|
||||
let l:trigger_file_candidates = [
|
||||
\ '.vimrc',
|
||||
\ 'init.vim',
|
||||
\]
|
||||
|
||||
for l:candidate in l:trigger_file_candidates
|
||||
let l:trigger_file = fnamemodify(bufname(a:buffer), ':t')
|
||||
|
||||
if l:trigger_file is# l:candidate
|
||||
return fnamemodify(
|
||||
\ bufname(a:buffer),
|
||||
\ ':h',
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
|
||||
let l:trigger_dir_candidates = [
|
||||
\ 'autoload',
|
||||
\ 'plugin',
|
||||
\ '.git',
|
||||
\]
|
||||
|
||||
let l:path_upwards = ale#path#Upwards(fnamemodify(bufname(a:buffer), ':p:h'))
|
||||
|
||||
for l:path in l:path_upwards
|
||||
for l:candidate in l:trigger_dir_candidates
|
||||
let l:trigger_dir = ale#path#Simplify(
|
||||
\ l:path . '/' . l:candidate,
|
||||
\)
|
||||
|
||||
if isdirectory(l:trigger_dir)
|
||||
return fnamemodify(
|
||||
\ l:trigger_dir,
|
||||
\ ':p:h:h',
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('vim', {
|
||||
\ 'name': 'vimls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'vim_vimls_config')},
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'vim_vimls', [
|
||||
\ 'node_modules/.bin/vim-language-server',
|
||||
\ ])},
|
||||
\ 'command': '%e --stdio',
|
||||
\ 'language': 'vim',
|
||||
\ 'project_root': function('ale_linters#vim#vimls#GetProjectRoot'),
|
||||
\})
|
||||
@@ -5,7 +5,7 @@
|
||||
call ale#Set('vim_vint_show_style_issues', 1)
|
||||
call ale#Set('vim_vint_executable', 'vint')
|
||||
let s:enable_neovim = has('nvim') ? ' --enable-neovim' : ''
|
||||
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
|
||||
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"'
|
||||
|
||||
function! ale_linters#vim#vint#GetCommand(buffer, version) abort
|
||||
let l:can_use_no_color_flag = empty(a:version)
|
||||
@@ -13,12 +13,17 @@ function! ale_linters#vim#vint#GetCommand(buffer, version) abort
|
||||
|
||||
let l:warning_flag = ale#Var(a:buffer, 'vim_vint_show_style_issues') ? '-s' : '-w'
|
||||
|
||||
" Use the --stdin-display-name argument if supported, temp file otherwise.
|
||||
let l:stdin_or_temp = ale#semver#GTE(a:version, [0, 4, 0])
|
||||
\ ? ' --stdin-display-name %s -'
|
||||
\ : ' %t'
|
||||
|
||||
return '%e'
|
||||
\ . ' ' . l:warning_flag
|
||||
\ . (l:can_use_no_color_flag ? ' --no-color' : '')
|
||||
\ . s:enable_neovim
|
||||
\ . ' ' . s:format
|
||||
\ . ' %t'
|
||||
\ . l:stdin_or_temp
|
||||
endfunction
|
||||
|
||||
let s:word_regex_list = [
|
||||
|
||||
20
ale_linters/zig/zls.vim
Normal file
20
ale_linters/zig/zls.vim
Normal file
@@ -0,0 +1,20 @@
|
||||
" Author: CherryMan <skipper308@hotmail.ca>
|
||||
" Description: A language server for Zig
|
||||
|
||||
call ale#Set('zig_zls_executable', 'zls')
|
||||
call ale#Set('zig_zls_config', {})
|
||||
|
||||
function! ale_linters#zig#zls#GetProjectRoot(buffer) abort
|
||||
let l:build_rs = ale#path#FindNearestFile(a:buffer, 'build.zig')
|
||||
|
||||
return !empty(l:build_rs) ? fnamemodify(l:build_rs, ':h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('zig', {
|
||||
\ 'name': 'zls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'zig_zls_config')},
|
||||
\ 'executable': {b -> ale#Var(b, 'zig_zls_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale_linters#zig#zls#GetProjectRoot'),
|
||||
\})
|
||||
@@ -5,11 +5,18 @@
|
||||
" Strings used for severity in the echoed message
|
||||
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_log_str = get(g:, 'ale_echo_msg_log_str', 'Log')
|
||||
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 g:ale_disable_lsp = get(g:, 'ale_disable_lsp', 0)
|
||||
|
||||
" LSP window/showMessage format
|
||||
let g:ale_lsp_show_message_format = get(g:, 'ale_lsp_show_message_format', '%severity%:%linter%: %s')
|
||||
" Valid values mimic LSP definitions (error, warning and information; log is
|
||||
" never shown)
|
||||
let g:ale_lsp_show_message_severity = get(g:, 'ale_lsp_show_message_severity', 'error')
|
||||
|
||||
let s:lint_timer = -1
|
||||
let s:getcmdwintype_exists = exists('*getcmdwintype')
|
||||
|
||||
@@ -93,13 +100,7 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
|
||||
" Use the filetype from the buffer
|
||||
let l:filetype = getbufvar(a:buffer, '&filetype')
|
||||
let l:linters = ale#linter#Get(l:filetype)
|
||||
|
||||
" Apply ignore lists for linters only if needed.
|
||||
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
|
||||
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
|
||||
let l:linters = !empty(l:ignore_config) || l:disable_lsp
|
||||
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config, l:disable_lsp)
|
||||
\ : l:linters
|
||||
let l:linters = ale#linter#RemoveIgnored(a:buffer, l:filetype, l:linters)
|
||||
|
||||
" Tell other sources that they can start checking the buffer now.
|
||||
let g:ale_want_results_buffer = a:buffer
|
||||
@@ -156,7 +157,7 @@ function! ale#Queue(delay, ...) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:current_ale_version = [2, 6, 0]
|
||||
let s:current_ale_version = [3, 0, 0]
|
||||
|
||||
" A function used to check for ALE features in files outside of the project.
|
||||
function! ale#Has(feature) abort
|
||||
@@ -251,11 +252,33 @@ function! ale#GetLocItemMessage(item, format_string) abort
|
||||
|
||||
" Replace special markers with certain information.
|
||||
" \=l:variable is used to avoid escaping issues.
|
||||
let l:msg = substitute(l:msg, '\v\%([^\%]*)code([^\%]*)\%', l:code_repl, 'g')
|
||||
let l:msg = substitute(l:msg, '\V%severity%', '\=l:severity', 'g')
|
||||
let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
|
||||
let l:msg = substitute(l:msg, '\v\%([^\%]*)code([^\%]*)\%', l:code_repl, 'g')
|
||||
" Replace %s with the text.
|
||||
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g')
|
||||
" Windows may insert carriage return line endings (^M), strip these characters.
|
||||
let l:msg = substitute(l:msg, '\r', '', 'g')
|
||||
|
||||
return l:msg
|
||||
endfunction
|
||||
|
||||
" Given a buffer and a linter or fixer name, return an Array of two-item
|
||||
" Arrays describing how to map filenames to and from the local to foreign file
|
||||
" systems.
|
||||
function! ale#GetFilenameMappings(buffer, name) abort
|
||||
let l:linter_mappings = ale#Var(a:buffer, 'filename_mappings')
|
||||
|
||||
if type(l:linter_mappings) is v:t_list
|
||||
return l:linter_mappings
|
||||
endif
|
||||
|
||||
let l:name = a:name
|
||||
|
||||
if !has_key(l:linter_mappings, l:name)
|
||||
" Use * as a default setting for all tools.
|
||||
let l:name = '*'
|
||||
endif
|
||||
|
||||
return get(l:linter_mappings, l:name, [])
|
||||
endfunction
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
" Author: Andrew Lee <andrewl@mbda.fun>.
|
||||
" Author: Andrew Lee <andrew.lambda@tuta.io>.
|
||||
" Inspired by ale/gradle.vim by Michael Pardo <michael@michaelpardo.com>
|
||||
" Description: Functions for working with Ant projects.
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ endfunction
|
||||
function! ale#assert#LSPLanguage(expected_language) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:linter = s:GetLinter()
|
||||
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
|
||||
let l:language = ale#linter#GetLanguage(l:buffer, l:linter)
|
||||
|
||||
AssertEqual a:expected_language, l:language
|
||||
endfunction
|
||||
@@ -267,14 +267,22 @@ function! ale#assert#TearDownLinterTest() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#assert#SetUpFixerTest(filetype, name) abort
|
||||
function! ale#assert#SetUpFixerTest(filetype, name, ...) abort
|
||||
" If the suffix of the option names format is different, an additional
|
||||
" argument can be used for that instead.
|
||||
if a:0 > 1
|
||||
throw 'Too many arguments'
|
||||
endif
|
||||
|
||||
" Set up a marker so ALE doesn't create real random temporary filenames.
|
||||
let g:ale_create_dummy_temporary_file = 1
|
||||
|
||||
let l:function_name = ale#fix#registry#GetFunc(a:name)
|
||||
let s:FixerFunction = function(l:function_name)
|
||||
|
||||
let l:prefix = 'ale_' . a:filetype . '_' . a:name
|
||||
let l:option_suffix = get(a:000, 0, a:name)
|
||||
let l:prefix = 'ale_' . a:filetype . '_'
|
||||
\ . substitute(l:option_suffix, '-', '_', 'g')
|
||||
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
|
||||
|
||||
for l:key in filter(keys(g:), b:filter_expr)
|
||||
@@ -286,7 +294,7 @@ function! ale#assert#SetUpFixerTest(filetype, name) abort
|
||||
unlet b:[l:key]
|
||||
endfor
|
||||
|
||||
execute 'runtime autoload/ale/fixers/' . a:name . '.vim'
|
||||
execute 'runtime autoload/ale/fixers/' . substitute(a:name, '-', '_', 'g') . '.vim'
|
||||
|
||||
if !exists('g:dir')
|
||||
call ale#test#SetDirectory('/testplugin/test/fixers')
|
||||
|
||||
@@ -2,20 +2,28 @@
|
||||
" Description: Functions for integrating with C-family linters.
|
||||
|
||||
call ale#Set('c_parse_makefile', 0)
|
||||
call ale#Set('c_parse_compile_commands', 0)
|
||||
call ale#Set('c_always_make', has('unix') && !has('macunix'))
|
||||
call ale#Set('c_parse_compile_commands', 1)
|
||||
|
||||
let s:sep = has('win32') ? '\' : '/'
|
||||
|
||||
" Set just so tests can override it.
|
||||
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
|
||||
|
||||
function! ale#c#GetBuildDirectory(buffer) abort
|
||||
" Don't include build directory for header files, as compile_commands.json
|
||||
" files don't consider headers to be translation units, and provide no
|
||||
" commands for compiling header files.
|
||||
if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
|
||||
return ''
|
||||
endif
|
||||
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
|
||||
\ 'build',
|
||||
\ 'bin',
|
||||
\])
|
||||
|
||||
function! s:CanParseMakefile(buffer) abort
|
||||
" Something somewhere seems to delete this setting in tests, so ensure we
|
||||
" always have a default value.
|
||||
call ale#Set('c_parse_makefile', 0)
|
||||
|
||||
return ale#Var(a:buffer, 'c_parse_makefile')
|
||||
endfunction
|
||||
|
||||
function! ale#c#GetBuildDirectory(buffer) abort
|
||||
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
|
||||
" c_build_dir has the priority if defined
|
||||
@@ -68,14 +76,73 @@ function! ale#c#ShellSplit(line) abort
|
||||
return l:args
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
|
||||
let l:cflags_list = []
|
||||
" Takes the path prefix and a list of cflags and expands @file arguments to
|
||||
" the contents of the file.
|
||||
"
|
||||
" @file arguments are command line arguments recognised by gcc and clang. For
|
||||
" instance, if @./path/to/file was given to gcc, it would load .path/to/file
|
||||
" and use the contents of that file as arguments.
|
||||
function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
|
||||
let l:out_lines = []
|
||||
|
||||
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
|
||||
for l:option in a:raw_split_lines
|
||||
if stridx(l:option, '@') == 0
|
||||
" This is an argument specifying a location of a file containing other arguments
|
||||
let l:path = join(split(l:option, '\zs')[1:], '')
|
||||
|
||||
" Make path absolute
|
||||
if !ale#path#IsAbsolute(l:path)
|
||||
let l:rel_path = substitute(l:path, '"', '', 'g')
|
||||
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
|
||||
let l:path = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
|
||||
endif
|
||||
|
||||
" Read the file and add all the arguments
|
||||
try
|
||||
let l:additional_args = readfile(l:path)
|
||||
catch
|
||||
continue " All we can really do is skip this argument
|
||||
endtry
|
||||
|
||||
let l:file_lines = []
|
||||
|
||||
for l:line in l:additional_args
|
||||
let l:file_lines += ale#c#ShellSplit(l:line)
|
||||
endfor
|
||||
|
||||
" @file arguments can include other @file arguments, so we must
|
||||
" recurse.
|
||||
let l:out_lines += ale#c#ExpandAtArgs(a:path_prefix, l:file_lines)
|
||||
else
|
||||
" This is not an @file argument, so don't touch it.
|
||||
let l:out_lines += [l:option]
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:out_lines
|
||||
endfunction
|
||||
|
||||
" Quote C/C++ a compiler argument, if needed.
|
||||
"
|
||||
" Quoting arguments might cause issues with some systems/compilers, so we only
|
||||
" quote them if we need to.
|
||||
function! ale#c#QuoteArg(arg) abort
|
||||
if a:arg !~# '\v[#$&*()\\|[\]{};''"<>/?! ^%]'
|
||||
return a:arg
|
||||
endif
|
||||
|
||||
return ale#Escape(a:arg)
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
|
||||
" Expand @file arguments now before parsing
|
||||
let l:arguments = ale#c#ExpandAtArgs(a:path_prefix, a:raw_arguments)
|
||||
" A list of [already_quoted, argument]
|
||||
let l:items = []
|
||||
let l:option_index = 0
|
||||
|
||||
while l:option_index < len(l:split_lines)
|
||||
let l:option = l:split_lines[l:option_index]
|
||||
while l:option_index < len(l:arguments)
|
||||
let l:option = l:arguments[l:option_index]
|
||||
let l:option_index = l:option_index + 1
|
||||
|
||||
" Include options, that may need relative path fix
|
||||
@@ -83,56 +150,67 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
|
||||
\ || stridx(l:option, '-iquote') == 0
|
||||
\ || stridx(l:option, '-isystem') == 0
|
||||
\ || stridx(l:option, '-idirafter') == 0
|
||||
\ || stridx(l:option, '-iframework') == 0
|
||||
\ || stridx(l:option, '-include') == 0
|
||||
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
|
||||
let l:arg = join(split(l:option, '\zs')[2:], '')
|
||||
let l:option = '-I'
|
||||
else
|
||||
let l:arg = l:split_lines[l:option_index]
|
||||
let l:arg = l:arguments[l:option_index]
|
||||
let l:option_index = l:option_index + 1
|
||||
endif
|
||||
|
||||
" Fix relative paths if needed
|
||||
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0
|
||||
if !ale#path#IsAbsolute(l:arg)
|
||||
let l:rel_path = substitute(l:arg, '"', '', 'g')
|
||||
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
|
||||
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path)
|
||||
let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
|
||||
endif
|
||||
|
||||
call add(l:cflags_list, l:option)
|
||||
call add(l:cflags_list, l:arg)
|
||||
call add(l:items, [1, l:option])
|
||||
call add(l:items, [1, ale#Escape(l:arg)])
|
||||
" Options with arg that can be grouped with the option or separate
|
||||
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
|
||||
call add(l:cflags_list, l:option)
|
||||
|
||||
if l:option is# '-D' || l:option is# '-B'
|
||||
call add(l:cflags_list, l:split_lines[l:option_index])
|
||||
call add(l:items, [1, l:option])
|
||||
call add(l:items, [0, l:arguments[l:option_index]])
|
||||
let l:option_index = l:option_index + 1
|
||||
else
|
||||
call add(l:items, [0, l:option])
|
||||
endif
|
||||
" Options that have an argument (always separate)
|
||||
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
|
||||
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
|
||||
call add(l:cflags_list, l:option)
|
||||
call add(l:cflags_list, l:split_lines[l:option_index])
|
||||
call add(l:items, [0, l:option])
|
||||
call add(l:items, [0, l:arguments[l:option_index]])
|
||||
let l:option_index = l:option_index + 1
|
||||
" Options without argument
|
||||
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
|
||||
\ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0
|
||||
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0
|
||||
\ || (stridx(l:option, '-f') == 0 && stridx(l:option, '-fdump') != 0 && stridx(l:option, '-fdiagnostics') != 0 && stridx(l:option, '-fno-show-column') != 0)
|
||||
\ || stridx(l:option, '-f') == 0 && l:option !~# '\v^-f(dump|diagnostics|no-show-column|stack-usage)'
|
||||
\ || stridx(l:option, '-O') == 0
|
||||
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs'
|
||||
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
|
||||
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
|
||||
\ || stridx(l:option, '-m') == 0
|
||||
call add(l:cflags_list, l:option)
|
||||
call add(l:items, [0, l:option])
|
||||
endif
|
||||
endwhile
|
||||
|
||||
return join(l:cflags_list, ' ')
|
||||
if a:should_quote
|
||||
" Quote C arguments that haven't already been quoted above.
|
||||
" If and only if we've been asked to quote them.
|
||||
call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])')
|
||||
else
|
||||
call map(l:items, 'v:val[1]')
|
||||
endif
|
||||
|
||||
return join(l:items, ' ')
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
|
||||
if !g:ale_c_parse_makefile
|
||||
if !s:CanParseMakefile(a:buffer)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
@@ -150,7 +228,7 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
|
||||
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
|
||||
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
|
||||
|
||||
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
|
||||
return ale#c#ParseCFlags(l:makefile_dir, 0, ale#c#ShellSplit(l:cflag_line))
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, find the project directory containing
|
||||
@@ -218,6 +296,10 @@ if !exists('s:compile_commands_cache')
|
||||
let s:compile_commands_cache = {}
|
||||
endif
|
||||
|
||||
function! ale#c#ResetCompileCommandsCache() abort
|
||||
let s:compile_commands_cache = {}
|
||||
endfunction
|
||||
|
||||
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
|
||||
let l:empty = [{}, {}]
|
||||
|
||||
@@ -248,9 +330,20 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
|
||||
let l:dir_lookup = {}
|
||||
|
||||
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
|
||||
let l:filename = ale#path#GetAbsPath(l:entry.directory, l:entry.file)
|
||||
|
||||
" Store a key for lookups by the absolute path to the filename.
|
||||
let l:file_lookup[l:filename] = get(l:file_lookup, l:filename, []) + [l:entry]
|
||||
|
||||
" Store a key for fuzzy lookups by the absolute path to the directory.
|
||||
let l:dirname = fnamemodify(l:filename, ':h')
|
||||
let l:dir_lookup[l:dirname] = get(l:dir_lookup, l:dirname, []) + [l:entry]
|
||||
|
||||
" Store a key for fuzzy lookups by just the basename of the file.
|
||||
let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
|
||||
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
|
||||
|
||||
" Store a key for fuzzy lookups by just the basename of the directory.
|
||||
let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t'))
|
||||
let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
|
||||
endfor
|
||||
@@ -265,28 +358,80 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
|
||||
return l:empty
|
||||
endfunction
|
||||
|
||||
function! ale#c#GetCompileCommand(json_item) abort
|
||||
if has_key(a:json_item, 'command')
|
||||
return a:json_item.command
|
||||
elseif has_key(a:json_item, 'arguments')
|
||||
return join(a:json_item.arguments, ' ')
|
||||
" Get [should_quote, arguments] from either 'command' or 'arguments'
|
||||
" 'arguments' should be quoted later, the split 'command' strings should not.
|
||||
function! s:GetArguments(json_item) abort
|
||||
if has_key(a:json_item, 'arguments')
|
||||
return [1, a:json_item.arguments]
|
||||
elseif has_key(a:json_item, 'command')
|
||||
return [0, ale#c#ShellSplit(a:json_item.command)]
|
||||
endif
|
||||
|
||||
return ''
|
||||
return [0, []]
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
|
||||
let l:buffer_filename = ale#path#Simplify(expand('#' . a:buffer . ':p'))
|
||||
let l:basename = tolower(fnamemodify(l:buffer_filename, ':t'))
|
||||
" Look for any file in the same directory if we can't find an exact match.
|
||||
let l:dir = fnamemodify(l:buffer_filename, ':h')
|
||||
|
||||
" Search for an exact file match first.
|
||||
let l:basename = tolower(expand('#' . a:buffer . ':t'))
|
||||
let l:file_list = get(a:file_lookup, l:basename, [])
|
||||
let l:file_list = get(a:file_lookup, l:buffer_filename, [])
|
||||
|
||||
" We may have to look for /foo/bar instead of C:\foo\bar
|
||||
if empty(l:file_list) && has('win32')
|
||||
let l:file_list = get(
|
||||
\ a:file_lookup,
|
||||
\ ale#path#RemoveDriveLetter(l:buffer_filename),
|
||||
\ []
|
||||
\)
|
||||
endif
|
||||
|
||||
" Try the absolute path to the directory second.
|
||||
let l:dir_list = get(a:dir_lookup, l:dir, [])
|
||||
|
||||
if empty(l:dir_list) && has('win32')
|
||||
let l:dir_list = get(
|
||||
\ a:dir_lookup,
|
||||
\ ale#path#RemoveDriveLetter(l:dir),
|
||||
\ []
|
||||
\)
|
||||
endif
|
||||
|
||||
if empty(l:file_list) && empty(l:dir_list)
|
||||
" If we can't find matches with the path to the file, try a
|
||||
" case-insensitive match for any similarly-named file.
|
||||
let l:file_list = get(a:file_lookup, l:basename, [])
|
||||
|
||||
" If we can't find matches with the path to the directory, try a
|
||||
" case-insensitive match for anything in similarly-named directory.
|
||||
let l:dir_list = get(a:dir_lookup, tolower(fnamemodify(l:dir, ':t')), [])
|
||||
endif
|
||||
|
||||
" A source file matching the header filename.
|
||||
let l:source_file = ''
|
||||
|
||||
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
|
||||
for l:suffix in ['.c', '.cpp']
|
||||
let l:key = fnamemodify(l:basename, ':r') . l:suffix
|
||||
" Try to find a source file by an absolute path first.
|
||||
let l:key = fnamemodify(l:buffer_filename, ':r') . l:suffix
|
||||
let l:file_list = get(a:file_lookup, l:key, [])
|
||||
|
||||
if empty(l:file_list) && has('win32')
|
||||
let l:file_list = get(
|
||||
\ a:file_lookup,
|
||||
\ ale#path#RemoveDriveLetter(l:key),
|
||||
\ []
|
||||
\)
|
||||
endif
|
||||
|
||||
if empty(l:file_list)
|
||||
" Look fuzzy matches on the basename second.
|
||||
let l:key = fnamemodify(l:basename, ':r') . l:suffix
|
||||
let l:file_list = get(a:file_lookup, l:key, [])
|
||||
endif
|
||||
|
||||
if !empty(l:file_list)
|
||||
let l:source_file = l:key
|
||||
break
|
||||
@@ -295,28 +440,31 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
|
||||
endif
|
||||
|
||||
for l:item in l:file_list
|
||||
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
|
||||
|
||||
" Load the flags for this file, or for a source file matching the
|
||||
" header file.
|
||||
if (
|
||||
\ bufnr(l:item.file) is a:buffer
|
||||
\ bufnr(l:filename) is a:buffer
|
||||
\ || (
|
||||
\ !empty(l:source_file)
|
||||
\ && l:item.file[-len(l:source_file):] is? l:source_file
|
||||
\ && l:filename[-len(l:source_file):] is? l:source_file
|
||||
\ )
|
||||
\)
|
||||
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
|
||||
let [l:should_quote, l:args] = s:GetArguments(l:item)
|
||||
|
||||
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Look for any file in the same directory if we can't find an exact match.
|
||||
let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h'))
|
||||
|
||||
let l:dirbasename = tolower(expand('#' . a:buffer . ':p:h:t'))
|
||||
let l:dir_list = get(a:dir_lookup, l:dirbasename, [])
|
||||
|
||||
for l:item in l:dir_list
|
||||
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
|
||||
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
|
||||
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
|
||||
|
||||
if ale#path#RemoveDriveLetter(fnamemodify(l:filename, ':h'))
|
||||
\ is? ale#path#RemoveDriveLetter(l:dir)
|
||||
let [l:should_quote, l:args] = s:GetArguments(l:item)
|
||||
|
||||
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -334,10 +482,6 @@ endfunction
|
||||
function! ale#c#GetCFlags(buffer, output) abort
|
||||
let l:cflags = v:null
|
||||
|
||||
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
|
||||
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
|
||||
endif
|
||||
|
||||
if ale#Var(a:buffer, 'c_parse_compile_commands')
|
||||
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
|
||||
|
||||
@@ -346,6 +490,10 @@ function! ale#c#GetCFlags(buffer, output) abort
|
||||
endif
|
||||
endif
|
||||
|
||||
if s:CanParseMakefile(a:buffer) && !empty(a:output) && !empty(l:cflags)
|
||||
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
|
||||
endif
|
||||
|
||||
if l:cflags is v:null
|
||||
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
|
||||
endif
|
||||
@@ -354,11 +502,14 @@ function! ale#c#GetCFlags(buffer, output) abort
|
||||
endfunction
|
||||
|
||||
function! ale#c#GetMakeCommand(buffer) abort
|
||||
if ale#Var(a:buffer, 'c_parse_makefile')
|
||||
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
|
||||
if s:CanParseMakefile(a:buffer)
|
||||
let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
|
||||
|
||||
if !empty(l:makefile_path)
|
||||
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
|
||||
if !empty(l:path)
|
||||
let l:always_make = ale#Var(a:buffer, 'c_always_make')
|
||||
|
||||
return ale#path#CdString(fnamemodify(l:path, ':h'))
|
||||
\ . 'make -n' . (l:always_make ? ' --always-make' : '')
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -427,8 +578,3 @@ function! ale#c#IncludeOptions(include_paths) abort
|
||||
|
||||
return join(l:option_list)
|
||||
endfunction
|
||||
|
||||
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
|
||||
\ 'build',
|
||||
\ 'bin',
|
||||
\])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
" Author: Jerko Steiner <jerko.steiner@gmail.com>
|
||||
" Description: Code action support for LSP / tsserver
|
||||
|
||||
function! ale#code_action#HandleCodeAction(code_action) abort
|
||||
function! ale#code_action#HandleCodeAction(code_action, should_save) abort
|
||||
let l:current_buffer = bufnr('')
|
||||
let l:changes = a:code_action.changes
|
||||
|
||||
@@ -17,11 +17,50 @@ function! ale#code_action#HandleCodeAction(code_action) abort
|
||||
|
||||
for l:file_code_edit in l:changes
|
||||
call ale#code_action#ApplyChanges(
|
||||
\ l:file_code_edit.fileName, l:file_code_edit.textChanges)
|
||||
\ l:file_code_edit.fileName,
|
||||
\ l:file_code_edit.textChanges,
|
||||
\ a:should_save,
|
||||
\ )
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#ApplyChanges(filename, changes) abort
|
||||
function! s:ChangeCmp(left, right) abort
|
||||
if a:left.start.line < a:right.start.line
|
||||
return -1
|
||||
endif
|
||||
|
||||
if a:left.start.line > a:right.start.line
|
||||
return 1
|
||||
endif
|
||||
|
||||
if a:left.start.offset < a:right.start.offset
|
||||
return -1
|
||||
endif
|
||||
|
||||
if a:left.start.offset > a:right.start.offset
|
||||
return 1
|
||||
endif
|
||||
|
||||
if a:left.end.line < a:right.end.line
|
||||
return -1
|
||||
endif
|
||||
|
||||
if a:left.end.line > a:right.end.line
|
||||
return 1
|
||||
endif
|
||||
|
||||
if a:left.end.offset < a:right.end.offset
|
||||
return -1
|
||||
endif
|
||||
|
||||
if a:left.end.offset > a:right.end.offset
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
|
||||
let l:current_buffer = bufnr('')
|
||||
" The buffer is used to determine the fileformat, if available.
|
||||
let l:buffer = bufnr(a:filename)
|
||||
@@ -45,7 +84,8 @@ function! ale#code_action#ApplyChanges(filename, changes) abort
|
||||
let l:column_offset = 0
|
||||
let l:last_end_line = 0
|
||||
|
||||
for l:code_edit in a:changes
|
||||
" Changes have to be sorted so we apply them from top-to-bottom.
|
||||
for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp'))
|
||||
if l:code_edit.start.line isnot l:last_end_line
|
||||
let l:column_offset = 0
|
||||
endif
|
||||
@@ -106,10 +146,17 @@ function! ale#code_action#ApplyChanges(filename, changes) abort
|
||||
call remove(l:lines, -1)
|
||||
endif
|
||||
|
||||
call ale#util#Writefile(l:buffer, l:lines, a:filename)
|
||||
if a:should_save
|
||||
call ale#util#Writefile(l:buffer, l:lines, a:filename)
|
||||
else
|
||||
call ale#util#SetBufferContents(l:buffer, l:lines)
|
||||
endif
|
||||
|
||||
if l:is_current_buffer
|
||||
call ale#util#Execute(':e!')
|
||||
if a:should_save
|
||||
call ale#util#Execute(':e!')
|
||||
endif
|
||||
|
||||
call setpos('.', [0, l:pos[0], l:pos[1], 0])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -133,11 +133,36 @@ function! ale#command#EscapeCommandPart(command_part) abort
|
||||
return substitute(a:command_part, '%', '%%', 'g')
|
||||
endfunction
|
||||
|
||||
" Format a filename, converting it with filename mappings, if non-empty,
|
||||
" and escaping it for putting into a command string.
|
||||
"
|
||||
" The filename can be modified.
|
||||
function! s:FormatFilename(filename, mappings, modifiers) abort
|
||||
let l:filename = a:filename
|
||||
|
||||
if !empty(a:mappings)
|
||||
let l:filename = ale#filename_mapping#Map(l:filename, a:mappings)
|
||||
endif
|
||||
|
||||
if !empty(a:modifiers)
|
||||
let l:filename = fnamemodify(l:filename, a:modifiers)
|
||||
endif
|
||||
|
||||
return ale#Escape(l:filename)
|
||||
endfunction
|
||||
|
||||
" Given a command string, replace every...
|
||||
" %s -> with the current filename
|
||||
" %t -> with the name of an unused file in a temporary directory
|
||||
" %% -> with a literal %
|
||||
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed, input) abort
|
||||
function! ale#command#FormatCommand(
|
||||
\ buffer,
|
||||
\ executable,
|
||||
\ command,
|
||||
\ pipe_file_if_needed,
|
||||
\ input,
|
||||
\ mappings,
|
||||
\) abort
|
||||
let l:temporary_file = ''
|
||||
let l:command = a:command
|
||||
|
||||
@@ -154,14 +179,24 @@ function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_ne
|
||||
" file.
|
||||
if l:command =~# '%s'
|
||||
let l:filename = fnamemodify(bufname(a:buffer), ':p')
|
||||
let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g')
|
||||
let l:command = substitute(
|
||||
\ l:command,
|
||||
\ '\v\%s(%(:h|:t|:r|:e)*)',
|
||||
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
|
||||
\ 'g'
|
||||
\)
|
||||
endif
|
||||
|
||||
if a:input isnot v:false && l:command =~# '%t'
|
||||
" Create a temporary filename, <temp_dir>/<original_basename>
|
||||
" The file itself will not be created by this function.
|
||||
let l:temporary_file = s:TemporaryFilename(a:buffer)
|
||||
let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g')
|
||||
let l:command = substitute(
|
||||
\ l:command,
|
||||
\ '\v\%t(%(:h|:t|:r|:e)*)',
|
||||
\ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))',
|
||||
\ 'g'
|
||||
\)
|
||||
endif
|
||||
|
||||
" Finish formatting so %% becomes %.
|
||||
@@ -265,6 +300,7 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
|
||||
\ a:command,
|
||||
\ get(l:options, 'read_buffer', 0),
|
||||
\ get(l:options, 'input', v:null),
|
||||
\ get(l:options, 'filename_mappings', []),
|
||||
\)
|
||||
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
|
||||
let l:job_options = {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Completion support for LSP linters
|
||||
scriptencoding utf-8
|
||||
|
||||
" The omnicompletion menu is shown through a special Plug mapping which is
|
||||
" only valid in Insert mode. This way, feedkeys() won't send these keys if you
|
||||
" quit Insert mode quickly enough.
|
||||
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o>
|
||||
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o><C-p>
|
||||
" If we hit the key sequence in normal mode, then we won't show the menu, so
|
||||
" we should restore the old settings right away.
|
||||
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
|
||||
@@ -15,30 +16,108 @@ onoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
|
||||
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
|
||||
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
|
||||
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
|
||||
let g:ale_completion_tsserver_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0)
|
||||
let g:ale_completion_autoimport = get(g:, 'ale_completion_autoimport', 0)
|
||||
let g:ale_completion_tsserver_remove_warnings = get(g:, 'ale_completion_tsserver_remove_warnings', 0)
|
||||
|
||||
let s:timer_id = -1
|
||||
let s:last_done_pos = []
|
||||
|
||||
" CompletionItemKind values from the LSP protocol.
|
||||
let s:LSP_COMPLETION_TEXT_KIND = 1
|
||||
let s:LSP_COMPLETION_METHOD_KIND = 2
|
||||
let s:LSP_COMPLETION_FUNCTION_KIND = 3
|
||||
let s:LSP_COMPLETION_CONSTRUCTOR_KIND = 4
|
||||
let s:LSP_COMPLETION_FIELD_KIND = 5
|
||||
let s:LSP_COMPLETION_VARIABLE_KIND = 6
|
||||
let s:LSP_COMPLETION_CLASS_KIND = 7
|
||||
let s:LSP_COMPLETION_INTERFACE_KIND = 8
|
||||
let s:LSP_COMPLETION_MODULE_KIND = 9
|
||||
let s:LSP_COMPLETION_PROPERTY_KIND = 10
|
||||
let s:LSP_COMPLETION_UNIT_KIND = 11
|
||||
let s:LSP_COMPLETION_VALUE_KIND = 12
|
||||
let s:LSP_COMPLETION_ENUM_KIND = 13
|
||||
let s:LSP_COMPLETION_KEYWORD_KIND = 14
|
||||
let s:LSP_COMPLETION_SNIPPET_KIND = 15
|
||||
let s:LSP_COMPLETION_COLOR_KIND = 16
|
||||
let s:LSP_COMPLETION_FILE_KIND = 17
|
||||
let s:LSP_COMPLETION_REFERENCE_KIND = 18
|
||||
let g:ale_lsp_types = {
|
||||
\ 1: 'text',
|
||||
\ 2: 'method',
|
||||
\ 3: 'function',
|
||||
\ 4: 'constructor',
|
||||
\ 5: 'field',
|
||||
\ 6: 'variable',
|
||||
\ 7: 'class',
|
||||
\ 8: 'interface',
|
||||
\ 9: 'module',
|
||||
\ 10: 'property',
|
||||
\ 11: 'unit',
|
||||
\ 12: 'value',
|
||||
\ 13: 'enum',
|
||||
\ 14: 'keyword',
|
||||
\ 15: 'snippet',
|
||||
\ 16: 'color',
|
||||
\ 17: 'file',
|
||||
\ 18: 'reference',
|
||||
\ 19: 'folder',
|
||||
\ 20: 'enum_member',
|
||||
\ 21: 'constant',
|
||||
\ 22: 'struct',
|
||||
\ 23: 'event',
|
||||
\ 24: 'operator',
|
||||
\ 25: 'type_parameter',
|
||||
\ }
|
||||
|
||||
" from https://github.com/microsoft/TypeScript/blob/29becf05012bfa7ba20d50b0d16813971e46b8a6/lib/protocol.d.ts#L2472
|
||||
let g:ale_tsserver_types = {
|
||||
\ 'warning': 'text',
|
||||
\ 'keyword': 'keyword',
|
||||
\ 'script': 'file',
|
||||
\ 'module': 'module',
|
||||
\ 'class': 'class',
|
||||
\ 'local class': 'class',
|
||||
\ 'interface': 'interface',
|
||||
\ 'type': 'class',
|
||||
\ 'enum': 'enum',
|
||||
\ 'enum member': 'enum_member',
|
||||
\ 'var': 'variable',
|
||||
\ 'local var': 'variable',
|
||||
\ 'function': 'function',
|
||||
\ 'local function': 'function',
|
||||
\ 'method': 'method',
|
||||
\ 'getter': 'property',
|
||||
\ 'setter': 'method',
|
||||
\ 'property': 'property',
|
||||
\ 'constructor': 'constructor',
|
||||
\ 'call': 'method',
|
||||
\ 'index': 'index',
|
||||
\ 'construct': 'constructor',
|
||||
\ 'parameter': 'parameter',
|
||||
\ 'type parameter': 'type_parameter',
|
||||
\ 'primitive type': 'unit',
|
||||
\ 'label': 'text',
|
||||
\ 'alias': 'class',
|
||||
\ 'const': 'constant',
|
||||
\ 'let': 'variable',
|
||||
\ 'directory': 'folder',
|
||||
\ 'external module name': 'text',
|
||||
\ 'JSX attribute': 'parameter',
|
||||
\ 'string': 'text'
|
||||
\ }
|
||||
|
||||
" For compatibility reasons, we only use built in VIM completion kinds
|
||||
" See :help complete-items for Vim completion kinds
|
||||
let g:ale_completion_symbols = get(g:, 'ale_completion_symbols', {
|
||||
\ 'text': 'v',
|
||||
\ 'method': 'f',
|
||||
\ 'function': 'f',
|
||||
\ 'constructor': 'f',
|
||||
\ 'field': 'm',
|
||||
\ 'variable': 'v',
|
||||
\ 'class': 't',
|
||||
\ 'interface': 't',
|
||||
\ 'module': 'd',
|
||||
\ 'property': 'm',
|
||||
\ 'unit': 'v',
|
||||
\ 'value': 'v',
|
||||
\ 'enum': 't',
|
||||
\ 'keyword': 'v',
|
||||
\ 'snippet': 'v',
|
||||
\ 'color': 'v',
|
||||
\ 'file': 'v',
|
||||
\ 'reference': 'v',
|
||||
\ 'folder': 'v',
|
||||
\ 'enum_member': 'm',
|
||||
\ 'constant': 'm',
|
||||
\ 'struct': 't',
|
||||
\ 'event': 'v',
|
||||
\ 'operator': 'f',
|
||||
\ 'type_parameter': 'p',
|
||||
\ '<default>': 'v'
|
||||
\ })
|
||||
|
||||
let s:LSP_INSERT_TEXT_FORMAT_PLAIN = 1
|
||||
let s:LSP_INSERT_TEXT_FORMAT_SNIPPET = 2
|
||||
@@ -109,7 +188,13 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
|
||||
function! ale#completion#Filter(
|
||||
\ buffer,
|
||||
\ filetype,
|
||||
\ suggestions,
|
||||
\ prefix,
|
||||
\ exact_prefix_match,
|
||||
\) abort
|
||||
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
|
||||
|
||||
if empty(a:prefix)
|
||||
@@ -136,10 +221,17 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
|
||||
" Dictionaries is accepted here.
|
||||
let l:word = type(l:item) is v:t_string ? l:item : l:item.word
|
||||
|
||||
" Add suggestions if the suggestion starts with a
|
||||
" case-insensitive match for the prefix.
|
||||
if l:word[: len(a:prefix) - 1] is? a:prefix
|
||||
call add(l:filtered_suggestions, l:item)
|
||||
if a:exact_prefix_match
|
||||
" Add suggestions if the word is an exact match.
|
||||
if l:word is# a:prefix
|
||||
call add(l:filtered_suggestions, l:item)
|
||||
endif
|
||||
else
|
||||
" Add suggestions if the suggestion starts with a
|
||||
" case-insensitive match for the prefix.
|
||||
if l:word[: len(a:prefix) - 1] is? a:prefix
|
||||
call add(l:filtered_suggestions, l:item)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
@@ -162,27 +254,25 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
|
||||
return l:filtered_suggestions
|
||||
endfunction
|
||||
|
||||
function! s:ReplaceCompletionOptions() abort
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
|
||||
" Remember the old omnifunc value, if there is one.
|
||||
" If we don't store an old one, we'll just never reset the option.
|
||||
" This will stop some random exceptions from appearing.
|
||||
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
|
||||
let b:ale_old_omnifunc = &l:omnifunc
|
||||
endif
|
||||
|
||||
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
|
||||
function! s:ReplaceCompletionOptions(source) abort
|
||||
" Remember the old omnifunc value, if there is one.
|
||||
" If we don't store an old one, we'll just never reset the option.
|
||||
" This will stop some random exceptions from appearing.
|
||||
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
|
||||
let b:ale_old_omnifunc = &l:omnifunc
|
||||
endif
|
||||
|
||||
if l:source is# 'ale-automatic'
|
||||
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
|
||||
|
||||
if a:source is# 'ale-automatic'
|
||||
if !exists('b:ale_old_completeopt')
|
||||
let b:ale_old_completeopt = &l:completeopt
|
||||
endif
|
||||
|
||||
if &l:completeopt =~# 'preview'
|
||||
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
|
||||
elseif &l:completeopt =~# 'popup'
|
||||
let &l:completeopt = 'menu,menuone,popup,noselect,noinsert'
|
||||
else
|
||||
let &l:completeopt = 'menu,menuone,noselect,noinsert'
|
||||
endif
|
||||
@@ -237,59 +327,112 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort
|
||||
else
|
||||
let l:result = ale#completion#GetCompletionResult()
|
||||
|
||||
call s:ReplaceCompletionOptions()
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
|
||||
call s:ReplaceCompletionOptions(l:source)
|
||||
endif
|
||||
|
||||
return l:result isnot v:null ? l:result : []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:OpenCompletionMenu(...) abort
|
||||
if !&l:paste
|
||||
call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Show(result) abort
|
||||
if ale#util#Mode() isnot# 'i'
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if ale#util#Mode() isnot# 'i' && l:source isnot# 'ale-import'
|
||||
return
|
||||
endif
|
||||
|
||||
" Set the list in the buffer, temporarily replace omnifunc with our
|
||||
" function, and then start omni-completion.
|
||||
" Set the list in the buffer.
|
||||
let b:ale_completion_result = a:result
|
||||
|
||||
" Don't try to open the completion menu if there's nothing to show.
|
||||
if empty(b:ale_completion_result)
|
||||
if l:source is# 'ale-import'
|
||||
" If we ran completion from :ALEImport,
|
||||
" tell the user that nothing is going to happen.
|
||||
call s:message('No possible imports found.')
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
" Replace completion options shortly before opening the menu.
|
||||
call s:ReplaceCompletionOptions()
|
||||
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
|
||||
call timer_start(
|
||||
\ 0,
|
||||
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}
|
||||
\)
|
||||
call s:ReplaceCompletionOptions(l:source)
|
||||
|
||||
call timer_start(0, function('s:OpenCompletionMenu'))
|
||||
endif
|
||||
|
||||
if l:source is# 'ale-callback'
|
||||
call b:CompleteCallback(b:ale_completion_result)
|
||||
endif
|
||||
|
||||
if l:source is# 'ale-import'
|
||||
call ale#completion#HandleUserData(b:ale_completion_result[0])
|
||||
|
||||
let l:text_changed = '' . g:ale_lint_on_text_changed
|
||||
|
||||
" Check the buffer again right away, if linting is enabled.
|
||||
if g:ale_enabled
|
||||
\&& (
|
||||
\ l:text_changed is# '1'
|
||||
\ || l:text_changed is# 'always'
|
||||
\ || l:text_changed is# 'normal'
|
||||
\ || l:text_changed is# 'insert'
|
||||
\)
|
||||
call ale#Queue(0, '')
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetAllTriggers() abort
|
||||
return deepcopy(s:trigger_character_map)
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetCompletionKind(kind) abort
|
||||
let l:lsp_symbol = get(g:ale_lsp_types, a:kind, '')
|
||||
|
||||
if !empty(l:lsp_symbol)
|
||||
return l:lsp_symbol
|
||||
endif
|
||||
|
||||
return get(g:ale_tsserver_types, a:kind, '')
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetCompletionSymbols(kind) abort
|
||||
let l:kind = ale#completion#GetCompletionKind(a:kind)
|
||||
let l:symbol = get(g:ale_completion_symbols, l:kind, '')
|
||||
|
||||
if !empty(l:symbol)
|
||||
return l:symbol
|
||||
endif
|
||||
|
||||
return get(g:ale_completion_symbols, '<default>', 'v')
|
||||
endfunction
|
||||
|
||||
function! s:CompletionStillValid(request_id) abort
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
|
||||
return ale#util#Mode() is# 'i'
|
||||
\&& has_key(b:, 'ale_completion_info')
|
||||
return has_key(b:, 'ale_completion_info')
|
||||
\&& (
|
||||
\ ale#util#Mode() is# 'i'
|
||||
\ || b:ale_completion_info.source is# 'ale-import'
|
||||
\)
|
||||
\&& b:ale_completion_info.request_id == a:request_id
|
||||
\&& b:ale_completion_info.line == l:line
|
||||
\&& (
|
||||
\ b:ale_completion_info.column == l:column
|
||||
\ || b:ale_completion_info.source is# 'deoplete'
|
||||
\ || b:ale_completion_info.source is# 'ale-omnifunc'
|
||||
\ || b:ale_completion_info.source is# 'ale-callback'
|
||||
\ || b:ale_completion_info.source is# 'ale-import'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
@@ -297,10 +440,14 @@ function! ale#completion#ParseTSServerCompletions(response) abort
|
||||
let l:names = []
|
||||
|
||||
for l:suggestion in a:response.body
|
||||
call add(l:names, {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'source': get(l:suggestion, 'source', ''),
|
||||
\})
|
||||
let l:kind = get(l:suggestion, 'kind', '')
|
||||
|
||||
if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning'
|
||||
call add(l:names, {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'source': get(l:suggestion, 'source', ''),
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:names
|
||||
@@ -310,15 +457,26 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:results = []
|
||||
let l:names_with_details = []
|
||||
let l:info = get(b:, 'ale_completion_info', {})
|
||||
|
||||
for l:suggestion in a:response.body
|
||||
let l:displayParts = []
|
||||
let l:local_name = v:null
|
||||
|
||||
for l:action in get(l:suggestion, 'codeActions', [])
|
||||
call add(l:displayParts, l:action.description . ' ')
|
||||
endfor
|
||||
|
||||
for l:part in l:suggestion.displayParts
|
||||
" Stop on stop on line breaks for the menu.
|
||||
if get(l:part, 'kind') is# 'lineBreak'
|
||||
break
|
||||
endif
|
||||
|
||||
if get(l:part, 'kind') is# 'localName'
|
||||
let l:local_name = l:part.text
|
||||
endif
|
||||
|
||||
call add(l:displayParts, l:part.text)
|
||||
endfor
|
||||
|
||||
@@ -329,31 +487,37 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
call add(l:documentationParts, l:part.text)
|
||||
endfor
|
||||
|
||||
if l:suggestion.kind is# 'className'
|
||||
let l:kind = 'f'
|
||||
elseif l:suggestion.kind is# 'parameterName'
|
||||
let l:kind = 'f'
|
||||
else
|
||||
let l:kind = 'v'
|
||||
endif
|
||||
|
||||
" See :help complete-items
|
||||
let l:result = {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'kind': l:kind,
|
||||
\ 'word': (
|
||||
\ l:suggestion.name is# 'default'
|
||||
\ && l:suggestion.kind is# 'alias'
|
||||
\ && !empty(l:local_name)
|
||||
\ ? l:local_name
|
||||
\ : l:suggestion.name
|
||||
\ ),
|
||||
\ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind),
|
||||
\ 'icase': 1,
|
||||
\ 'menu': join(l:displayParts, ''),
|
||||
\ 'dup': g:ale_completion_tsserver_autoimport,
|
||||
\ 'dup': get(l:info, 'additional_edits_only', 0)
|
||||
\ || g:ale_completion_autoimport,
|
||||
\ 'info': join(l:documentationParts, ''),
|
||||
\}
|
||||
" This flag is used to tell if this completion came from ALE or not.
|
||||
let l:user_data = {'_ale_completion_item': 1}
|
||||
|
||||
if has_key(l:suggestion, 'codeActions')
|
||||
let l:result.user_data = json_encode({
|
||||
\ 'codeActions': l:suggestion.codeActions,
|
||||
\ })
|
||||
let l:user_data.code_actions = l:suggestion.codeActions
|
||||
endif
|
||||
|
||||
call add(l:results, l:result)
|
||||
let l:result.user_data = json_encode(l:user_data)
|
||||
|
||||
" Include this item if we'll accept any items,
|
||||
" or if we only want items with additional edits, and this has them.
|
||||
if !get(l:info, 'additional_edits_only', 0)
|
||||
\|| has_key(l:user_data, 'code_actions')
|
||||
call add(l:results, l:result)
|
||||
endif
|
||||
endfor
|
||||
|
||||
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
|
||||
@@ -372,6 +536,7 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
\ 'icase': 1,
|
||||
\ 'menu': '',
|
||||
\ 'info': '',
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\})
|
||||
endfor
|
||||
endif
|
||||
@@ -425,21 +590,14 @@ function! ale#completion#ParseLSPCompletions(response) abort
|
||||
continue
|
||||
endif
|
||||
|
||||
" See :help complete-items for Vim completion kinds
|
||||
if !has_key(l:item, 'kind')
|
||||
let l:kind = 'v'
|
||||
elseif l:item.kind is s:LSP_COMPLETION_METHOD_KIND
|
||||
let l:kind = 'm'
|
||||
elseif l:item.kind is s:LSP_COMPLETION_CONSTRUCTOR_KIND
|
||||
let l:kind = 'm'
|
||||
elseif l:item.kind is s:LSP_COMPLETION_FUNCTION_KIND
|
||||
let l:kind = 'f'
|
||||
elseif l:item.kind is s:LSP_COMPLETION_CLASS_KIND
|
||||
let l:kind = 'f'
|
||||
elseif l:item.kind is s:LSP_COMPLETION_INTERFACE_KIND
|
||||
let l:kind = 'f'
|
||||
else
|
||||
let l:kind = 'v'
|
||||
" Don't use LSP items with additional text edits when autoimport for
|
||||
" completions is turned off.
|
||||
if !empty(get(l:item, 'additionalTextEdits'))
|
||||
\&& !(
|
||||
\ get(l:info, 'additional_edits_only', 0)
|
||||
\ || g:ale_completion_autoimport
|
||||
\)
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:doc = get(l:item, 'documentation', '')
|
||||
@@ -448,17 +606,64 @@ function! ale#completion#ParseLSPCompletions(response) abort
|
||||
let l:doc = l:doc.value
|
||||
endif
|
||||
|
||||
call add(l:results, {
|
||||
let l:result = {
|
||||
\ 'word': l:word,
|
||||
\ 'kind': l:kind,
|
||||
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
|
||||
\ 'icase': 1,
|
||||
\ 'menu': get(l:item, 'detail', ''),
|
||||
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
|
||||
\})
|
||||
\}
|
||||
" This flag is used to tell if this completion came from ALE or not.
|
||||
let l:user_data = {'_ale_completion_item': 1}
|
||||
|
||||
if has_key(l:item, 'additionalTextEdits')
|
||||
let l:text_changes = []
|
||||
|
||||
for l:edit in l:item.additionalTextEdits
|
||||
call add(l:text_changes, {
|
||||
\ 'start': {
|
||||
\ 'line': l:edit.range.start.line + 1,
|
||||
\ 'offset': l:edit.range.start.character + 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:edit.range.end.line + 1,
|
||||
\ 'offset': l:edit.range.end.character + 1,
|
||||
\ },
|
||||
\ 'newText': l:edit.newText,
|
||||
\})
|
||||
endfor
|
||||
|
||||
if !empty(l:text_changes)
|
||||
let l:user_data.code_actions = [{
|
||||
\ 'description': 'completion',
|
||||
\ 'changes': [
|
||||
\ {
|
||||
\ 'fileName': expand('#' . l:buffer . ':p'),
|
||||
\ 'textChanges': l:text_changes,
|
||||
\ },
|
||||
\ ],
|
||||
\}]
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:result.user_data = json_encode(l:user_data)
|
||||
|
||||
" Include this item if we'll accept any items,
|
||||
" or if we only want items with additional edits, and this has them.
|
||||
if !get(l:info, 'additional_edits_only', 0)
|
||||
\|| has_key(l:user_data, 'code_actions')
|
||||
call add(l:results, l:result)
|
||||
endif
|
||||
endfor
|
||||
|
||||
if has_key(l:info, 'prefix')
|
||||
let l:results = ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
|
||||
let l:results = ale#completion#Filter(
|
||||
\ l:buffer,
|
||||
\ &filetype,
|
||||
\ l:results,
|
||||
\ l:info.prefix,
|
||||
\ get(l:info, 'additional_edits_only', 0),
|
||||
\)
|
||||
endif
|
||||
|
||||
return l:results[: g:ale_completion_max_suggestions - 1]
|
||||
@@ -482,20 +687,32 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
|
||||
\ &filetype,
|
||||
\ ale#completion#ParseTSServerCompletions(a:response),
|
||||
\ b:ale_completion_info.prefix,
|
||||
\ get(b:ale_completion_info, 'additional_edits_only', 0),
|
||||
\)[: g:ale_completion_max_suggestions - 1]
|
||||
|
||||
" We need to remember some names for tsserver, as it doesn't send
|
||||
" details back for everything we send.
|
||||
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
|
||||
|
||||
if !empty(l:names)
|
||||
if empty(l:names)
|
||||
" Response with no results now and skip making a redundant request
|
||||
" for nothing.
|
||||
call ale#completion#Show([])
|
||||
else
|
||||
let l:identifiers = []
|
||||
|
||||
for l:name in l:names
|
||||
call add(l:identifiers, {
|
||||
let l:identifier = {
|
||||
\ 'name': l:name.word,
|
||||
\ 'source': get(l:name, 'source', ''),
|
||||
\})
|
||||
\}
|
||||
let l:source = get(l:name, 'source', '')
|
||||
|
||||
" Empty source results in no details for the completed item
|
||||
if !empty(l:source)
|
||||
call extend(l:identifier, { 'source': l:source })
|
||||
endif
|
||||
|
||||
call add(l:identifiers, l:identifier)
|
||||
endfor
|
||||
|
||||
let b:ale_completion_info.request_id = ale#lsp#Send(
|
||||
@@ -546,12 +763,17 @@ function! s:OnReady(linter, lsp_details) abort
|
||||
call ale#lsp#RegisterCallback(l:id, l:Callback)
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
if get(g:, 'ale_completion_tsserver_autoimport') is 1
|
||||
execute 'echom `g:ale_completion_tsserver_autoimport` is deprecated. Use `g:ale_completion_autoimport` instead.'''
|
||||
endif
|
||||
|
||||
let l:message = ale#lsp#tsserver_message#Completions(
|
||||
\ l:buffer,
|
||||
\ b:ale_completion_info.line,
|
||||
\ b:ale_completion_info.column,
|
||||
\ b:ale_completion_info.prefix,
|
||||
\ g:ale_completion_tsserver_autoimport,
|
||||
\ get(b:ale_completion_info, 'additional_edits_only', 0)
|
||||
\ || g:ale_completion_autoimport,
|
||||
\)
|
||||
else
|
||||
" Send a message saying the buffer has changed first, otherwise
|
||||
@@ -610,9 +832,19 @@ function! ale#completion#GetCompletions(...) abort
|
||||
let b:CompleteCallback = l:CompleteCallback
|
||||
endif
|
||||
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
if has_key(l:options, 'line') && has_key(l:options, 'column')
|
||||
" Use a provided line and column, if given.
|
||||
let l:line = l:options.line
|
||||
let l:column = l:options.column
|
||||
else
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
endif
|
||||
|
||||
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
|
||||
if has_key(l:options, 'prefix')
|
||||
let l:prefix = l:options.prefix
|
||||
else
|
||||
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
|
||||
endif
|
||||
|
||||
if l:source is# 'ale-automatic' && empty(l:prefix)
|
||||
return 0
|
||||
@@ -631,6 +863,11 @@ function! ale#completion#GetCompletions(...) abort
|
||||
\}
|
||||
unlet! b:ale_completion_result
|
||||
|
||||
if has_key(l:options, 'additional_edits_only')
|
||||
let b:ale_completion_info.additional_edits_only =
|
||||
\ l:options.additional_edits_only
|
||||
endif
|
||||
|
||||
let l:buffer = bufnr('')
|
||||
let l:Callback = function('s:OnReady')
|
||||
|
||||
@@ -647,6 +884,37 @@ function! ale#completion#GetCompletions(...) abort
|
||||
return l:started
|
||||
endfunction
|
||||
|
||||
function! s:message(message) abort
|
||||
call ale#util#Execute('echom ' . string(a:message))
|
||||
endfunction
|
||||
|
||||
" This function implements the :ALEImport command.
|
||||
function! ale#completion#Import() abort
|
||||
let l:word = expand('<cword>')
|
||||
|
||||
if empty(l:word)
|
||||
call s:message('Nothing to complete at cursor!')
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
let l:column = searchpos('\V' . escape(l:word, '/\'), 'bn', l:line)[1]
|
||||
|
||||
if l:column isnot 0
|
||||
let l:started = ale#completion#GetCompletions('ale-import', {
|
||||
\ 'line': l:line,
|
||||
\ 'column': l:column,
|
||||
\ 'prefix': l:word,
|
||||
\ 'additional_edits_only': 1,
|
||||
\})
|
||||
|
||||
if !l:started
|
||||
call s:message('No completion providers are available.')
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#OmniFunc(findstart, base) abort
|
||||
if a:findstart
|
||||
let l:started = ale#completion#GetCompletions('ale-omnifunc')
|
||||
@@ -720,27 +988,29 @@ function! ale#completion#Queue() abort
|
||||
endfunction
|
||||
|
||||
function! ale#completion#HandleUserData(completed_item) abort
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if l:source isnot# 'ale-automatic' && l:source isnot# 'ale-manual'
|
||||
return
|
||||
endif
|
||||
|
||||
let l:user_data_json = get(a:completed_item, 'user_data', '')
|
||||
|
||||
if empty(l:user_data_json)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:user_data = json_decode(l:user_data_json)
|
||||
let l:user_data = !empty(l:user_data_json)
|
||||
\ ? json_decode(l:user_data_json)
|
||||
\ : v:null
|
||||
|
||||
if type(l:user_data) isnot v:t_dict
|
||||
\|| get(l:user_data, '_ale_completion_item', 0) isnot 1
|
||||
return
|
||||
endif
|
||||
|
||||
for l:code_action in get(l:user_data, 'codeActions', [])
|
||||
call ale#code_action#HandleCodeAction(l:code_action)
|
||||
endfor
|
||||
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
|
||||
|
||||
if l:source is# 'ale-automatic'
|
||||
\|| l:source is# 'ale-manual'
|
||||
\|| l:source is# 'ale-callback'
|
||||
\|| l:source is# 'ale-import'
|
||||
\|| l:source is# 'ale-omnifunc'
|
||||
for l:code_action in get(l:user_data, 'code_actions', [])
|
||||
call ale#code_action#HandleCodeAction(l:code_action, v:false)
|
||||
endfor
|
||||
endif
|
||||
|
||||
silent doautocmd <nomodeline> User ALECompletePost
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Done() abort
|
||||
@@ -752,6 +1022,8 @@ function! ale#completion#Done() abort
|
||||
endfunction
|
||||
|
||||
augroup ALECompletionActions
|
||||
autocmd!
|
||||
|
||||
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
|
||||
augroup END
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ function! ale#cursor#TruncatedEcho(original_message) abort
|
||||
endif
|
||||
|
||||
exec 'echomsg l:message'
|
||||
catch /E481/
|
||||
" Do nothing if running from a visual selection.
|
||||
endtry
|
||||
|
||||
" Reset the cursor position if we moved off the end of the line.
|
||||
|
||||
@@ -8,6 +8,7 @@ let s:global_variable_list = [
|
||||
\ 'ale_completion_delay',
|
||||
\ 'ale_completion_enabled',
|
||||
\ 'ale_completion_max_suggestions',
|
||||
\ 'ale_disable_lsp',
|
||||
\ 'ale_echo_cursor',
|
||||
\ 'ale_echo_msg_error_str',
|
||||
\ 'ale_echo_msg_format',
|
||||
@@ -28,6 +29,7 @@ let s:global_variable_list = [
|
||||
\ 'ale_linter_aliases',
|
||||
\ 'ale_linters',
|
||||
\ 'ale_linters_explicit',
|
||||
\ 'ale_linters_ignore',
|
||||
\ 'ale_list_vertical',
|
||||
\ 'ale_list_window_size',
|
||||
\ 'ale_loclist_msg_format',
|
||||
@@ -196,6 +198,7 @@ function! s:EchoLSPErrorMessages(all_linter_names) abort
|
||||
endfunction
|
||||
|
||||
function! ale#debugging#Info() abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:filetype = &filetype
|
||||
|
||||
" We get the list of enabled linters for free by the above function.
|
||||
@@ -222,10 +225,20 @@ function! ale#debugging#Info() abort
|
||||
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
|
||||
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '')
|
||||
|
||||
let l:non_ignored_names = map(
|
||||
\ copy(ale#linter#RemoveIgnored(l:buffer, l:filetype, l:enabled_linters)),
|
||||
\ 'v:val[''name'']',
|
||||
\)
|
||||
let l:ignored_names = filter(
|
||||
\ copy(l:enabled_names),
|
||||
\ 'index(l:non_ignored_names, v:val) < 0'
|
||||
\)
|
||||
|
||||
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(' Ignored Linters: ' . string(l:ignored_names))
|
||||
call s:Echo(' Suggested Fixers: ' . l:fixers_string)
|
||||
call s:Echo(' Linter Variables:')
|
||||
call s:Echo('')
|
||||
|
||||
@@ -5,6 +5,7 @@ let s:go_to_definition_map = {}
|
||||
|
||||
" Enable automatic updates of the tagstack
|
||||
let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', 1)
|
||||
let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer')
|
||||
|
||||
" Used to get the definition map in tests.
|
||||
function! ale#definition#GetMap() abort
|
||||
@@ -154,3 +155,33 @@ function! ale#definition#GoToType(options) abort
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#definition#GoToCommandHandler(command, ...) abort
|
||||
let l:options = {}
|
||||
|
||||
if len(a:000) > 0
|
||||
for l:option in a:000
|
||||
if l:option is? '-tab'
|
||||
let l:options.open_in = 'tab'
|
||||
elseif l:option is? '-split'
|
||||
let l:options.open_in = 'split'
|
||||
elseif l:option is? '-vsplit'
|
||||
let l:options.open_in = 'vsplit'
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if !has_key(l:options, 'open_in')
|
||||
let l:default_navigation = ale#Var(bufnr(''), 'default_navigation')
|
||||
|
||||
if index(['tab', 'split', 'vsplit'], l:default_navigation) >= 0
|
||||
let l:options.open_in = l:default_navigation
|
||||
endif
|
||||
endif
|
||||
|
||||
if a:command is# 'type'
|
||||
call ale#definition#GoToType(l:options)
|
||||
else
|
||||
call ale#definition#GoTo(l:options)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
" Remapping of linter problems.
|
||||
let g:ale_type_map = get(g:, 'ale_type_map', {})
|
||||
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
|
||||
|
||||
if !has_key(s:, 'executable_cache_map')
|
||||
let s:executable_cache_map = {}
|
||||
@@ -104,42 +105,6 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
|
||||
\ || !empty(get(l:info, 'active_other_sources_list', []))
|
||||
endfunction
|
||||
|
||||
" Register a temporary file to be managed with the ALE engine for
|
||||
" a current job run.
|
||||
function! ale#engine#ManageFile(buffer, filename) abort
|
||||
if !get(g:, 'ale_ignore_2_4_warnings')
|
||||
execute 'echom ''ale#engine#ManageFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
|
||||
endif
|
||||
|
||||
call ale#command#ManageFile(a:buffer, a:filename)
|
||||
endfunction
|
||||
|
||||
" Same as the above, but manage an entire directory.
|
||||
function! ale#engine#ManageDirectory(buffer, directory) abort
|
||||
if !get(g:, 'ale_ignore_2_4_warnings')
|
||||
execute 'echom ''ale#engine#ManageDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
|
||||
endif
|
||||
|
||||
call ale#command#ManageDirectory(a:buffer, a:directory)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#CreateFile(buffer) abort
|
||||
if !get(g:, 'ale_ignore_2_4_warnings')
|
||||
execute 'echom ''ale#engine#CreateFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
|
||||
endif
|
||||
|
||||
return ale#command#CreateFile(a:buffer)
|
||||
endfunction
|
||||
|
||||
" Create a new temporary directory and manage it in one go.
|
||||
function! ale#engine#CreateDirectory(buffer) abort
|
||||
if !get(g:, 'ale_ignore_2_4_warnings')
|
||||
execute 'echom ''ale#engine#CreateDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
|
||||
endif
|
||||
|
||||
return ale#command#CreateDirectory(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
|
||||
@@ -192,7 +157,6 @@ function! s:HandleExit(job_info, buffer, output, data) abort
|
||||
|
||||
let l:linter = a:job_info.linter
|
||||
let l:executable = a:job_info.executable
|
||||
let l:next_chain_index = a:job_info.next_chain_index
|
||||
|
||||
" Remove this job from the list.
|
||||
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
|
||||
@@ -207,20 +171,6 @@ function! s:HandleExit(job_info, buffer, output, data) abort
|
||||
call remove(a:output, -1)
|
||||
endif
|
||||
|
||||
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
|
||||
let [l:command, l:options] = ale#engine#ProcessChain(
|
||||
\ a:buffer,
|
||||
\ l:executable,
|
||||
\ l:linter,
|
||||
\ l:next_chain_index,
|
||||
\ a:output,
|
||||
\)
|
||||
|
||||
call s:RunJob(l:command, l:options)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
|
||||
" Handle the function being unknown, or being deleted.
|
||||
@@ -307,6 +257,13 @@ function! s:RemapItemTypes(type_map, loclist) abort
|
||||
endfunction
|
||||
|
||||
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
|
||||
let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name)
|
||||
|
||||
if !empty(l:mappings)
|
||||
" We need to apply reverse filename mapping here.
|
||||
let l:mappings = ale#filename_mapping#Invert(l:mappings)
|
||||
endif
|
||||
|
||||
let l:bufnr_map = {}
|
||||
let l:new_loclist = []
|
||||
|
||||
@@ -347,13 +304,19 @@ function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist)
|
||||
let l:item.code = l:old_item.code
|
||||
endif
|
||||
|
||||
if has_key(l:old_item, 'filename')
|
||||
\&& !ale#path#IsTempName(l:old_item.filename)
|
||||
let l:old_name = get(l:old_item, 'filename', '')
|
||||
|
||||
" Map parsed from output to local filesystem files.
|
||||
if !empty(l:old_name) && !empty(l:mappings)
|
||||
let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings)
|
||||
endif
|
||||
|
||||
if !empty(l:old_name) && !ale#path#IsTempName(l:old_name)
|
||||
" Use the filename given.
|
||||
" Temporary files are assumed to be for this buffer,
|
||||
" and the filename is not included then, because it looks bad
|
||||
" in the loclist window.
|
||||
let l:filename = l:old_item.filename
|
||||
let l:filename = l:old_name
|
||||
let l:item.filename = l:filename
|
||||
|
||||
if has_key(l:old_item, 'bufnr')
|
||||
@@ -454,20 +417,19 @@ function! s:RunJob(command, options) abort
|
||||
let l:buffer = a:options.buffer
|
||||
let l:linter = a:options.linter
|
||||
let l:output_stream = a:options.output_stream
|
||||
let l:next_chain_index = a:options.next_chain_index
|
||||
let l:read_buffer = a:options.read_buffer
|
||||
let l:read_buffer = a:options.read_buffer && !a:options.lint_file
|
||||
let l:info = g:ale_buffer_info[l:buffer]
|
||||
|
||||
let l:Callback = function('s:HandleExit', [{
|
||||
\ 'linter': l:linter,
|
||||
\ 'executable': l:executable,
|
||||
\ 'next_chain_index': l:next_chain_index,
|
||||
\}])
|
||||
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
|
||||
\ 'output_stream': l:output_stream,
|
||||
\ 'executable': l:executable,
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
\ 'log_output': l:next_chain_index >= len(get(l:linter, 'command_chain', [])),
|
||||
\ 'log_output': 1,
|
||||
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
|
||||
\})
|
||||
|
||||
" Only proceed if the job is being run.
|
||||
@@ -482,69 +444,7 @@ function! s:RunJob(command, options) abort
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
" Determine which commands to run for a link in a command chain, or
|
||||
" just a regular command.
|
||||
function! ale#engine#ProcessChain(buffer, executable, linter, chain_index, input) abort
|
||||
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
|
||||
let l:read_buffer = a:linter.read_buffer
|
||||
let l:chain_index = a:chain_index
|
||||
let l:input = a:input
|
||||
|
||||
while l:chain_index < len(a:linter.command_chain)
|
||||
" Run a chain of commands, one asynchronous command after the other,
|
||||
" so that many programs can be run in a sequence.
|
||||
let l:chain_item = a:linter.command_chain[l:chain_index]
|
||||
|
||||
if l:chain_index == 0
|
||||
" The first callback in the chain takes only a buffer number.
|
||||
let l:command = ale#util#GetFunction(l:chain_item.callback)(
|
||||
\ a:buffer
|
||||
\)
|
||||
else
|
||||
" The second callback in the chain takes some input too.
|
||||
let l:command = ale#util#GetFunction(l:chain_item.callback)(
|
||||
\ a:buffer,
|
||||
\ l:input
|
||||
\)
|
||||
endif
|
||||
|
||||
" If we have a command to run, execute that.
|
||||
if !empty(l:command)
|
||||
" The chain item can override the output_stream option.
|
||||
if has_key(l:chain_item, 'output_stream')
|
||||
let l:output_stream = l:chain_item.output_stream
|
||||
endif
|
||||
|
||||
" The chain item can override the read_buffer option.
|
||||
if has_key(l:chain_item, 'read_buffer')
|
||||
let l:read_buffer = l:chain_item.read_buffer
|
||||
elseif l:chain_index != len(a:linter.command_chain) - 1
|
||||
" Don't read the buffer for commands besides the last one
|
||||
" in the chain by default.
|
||||
let l:read_buffer = 0
|
||||
endif
|
||||
|
||||
break
|
||||
endif
|
||||
|
||||
" Command chain items can return an empty string to indicate that
|
||||
" a command should be skipped, so we should try the next item
|
||||
" with no input.
|
||||
let l:input = []
|
||||
let l:chain_index += 1
|
||||
endwhile
|
||||
|
||||
return [l:command, {
|
||||
\ 'executable': a:executable,
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': a:linter,
|
||||
\ 'output_stream': l:output_stream,
|
||||
\ 'next_chain_index': l:chain_index + 1,
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
|
||||
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort
|
||||
let l:info = get(g:ale_buffer_info, a:buffer, {})
|
||||
call ale#command#StopJobs(a:buffer, 'linter')
|
||||
|
||||
@@ -553,11 +453,25 @@ function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
|
||||
call ale#command#StopJobs(a:buffer, 'file_linter')
|
||||
let l:info.active_linter_list = []
|
||||
else
|
||||
let l:lint_file_map = {}
|
||||
|
||||
" Use a previously computed map of `lint_file` values to find
|
||||
" linters that are used for linting files.
|
||||
for [l:lint_file, l:linter] in a:linter_slots
|
||||
if l:lint_file is 1
|
||||
let l:lint_file_map[l:linter.name] = 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Keep jobs for linting files when we're only linting buffers.
|
||||
call filter(l:info.active_linter_list, 'get(v:val, ''lint_file'')')
|
||||
call filter(l:info.active_linter_list, 'get(l:lint_file_map, v:val.name)')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#Stop(buffer) abort
|
||||
call s:StopCurrentJobs(a:buffer, 1, [])
|
||||
endfunction
|
||||
|
||||
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
|
||||
" Figure out which linters are still enabled, and remove
|
||||
" problems for linters which are no longer enabled.
|
||||
@@ -608,10 +522,15 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:RunIfExecutable(buffer, linter, executable) abort
|
||||
function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
|
||||
if ale#command#IsDeferred(a:executable)
|
||||
let a:executable.result_callback = {
|
||||
\ executable -> s:RunIfExecutable(a:buffer, a:linter, executable)
|
||||
\ executable -> s:RunIfExecutable(
|
||||
\ a:buffer,
|
||||
\ a:linter,
|
||||
\ a:lint_file,
|
||||
\ executable
|
||||
\ )
|
||||
\}
|
||||
|
||||
return 1
|
||||
@@ -619,29 +538,17 @@ function! s:RunIfExecutable(buffer, linter, executable) abort
|
||||
|
||||
if ale#engine#IsExecutable(a:buffer, a:executable)
|
||||
" Use different job types for file or linter jobs.
|
||||
let l:job_type = a:linter.lint_file ? 'file_linter' : 'linter'
|
||||
let l:job_type = a:lint_file ? 'file_linter' : 'linter'
|
||||
call setbufvar(a:buffer, 'ale_job_type', l:job_type)
|
||||
|
||||
if has_key(a:linter, 'command_chain')
|
||||
let [l:command, l:options] = ale#engine#ProcessChain(
|
||||
\ a:buffer,
|
||||
\ a:executable,
|
||||
\ a:linter,
|
||||
\ 0,
|
||||
\ []
|
||||
\)
|
||||
|
||||
return s:RunJob(l:command, l:options)
|
||||
endif
|
||||
|
||||
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
|
||||
let l:options = {
|
||||
\ 'executable': a:executable,
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': a:linter,
|
||||
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
|
||||
\ 'next_chain_index': 1,
|
||||
\ 'read_buffer': a:linter.read_buffer,
|
||||
\ 'lint_file': a:lint_file,
|
||||
\}
|
||||
|
||||
return s:RunJob(l:command, l:options)
|
||||
@@ -653,22 +560,73 @@ endfunction
|
||||
" Run a linter for a buffer.
|
||||
"
|
||||
" Returns 1 if the linter was successfully run.
|
||||
function! s:RunLinter(buffer, linter) abort
|
||||
function! s:RunLinter(buffer, linter, lint_file) abort
|
||||
if !empty(a:linter.lsp)
|
||||
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
|
||||
else
|
||||
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
|
||||
|
||||
return s:RunIfExecutable(a:buffer, a:linter, l:executable)
|
||||
return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable)
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
" Initialise the buffer information if needed.
|
||||
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
|
||||
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
|
||||
function! s:GetLintFileSlots(buffer, linters) abort
|
||||
let l:linter_slots = []
|
||||
|
||||
for l:linter in a:linters
|
||||
let l:LintFile = l:linter.lint_file
|
||||
|
||||
if type(l:LintFile) is v:t_func
|
||||
let l:LintFile = l:LintFile(a:buffer)
|
||||
endif
|
||||
|
||||
call add(l:linter_slots, [l:LintFile, l:linter])
|
||||
endfor
|
||||
|
||||
return l:linter_slots
|
||||
endfunction
|
||||
|
||||
function! s:GetLintFileValues(slots, Callback) abort
|
||||
let l:deferred_list = []
|
||||
let l:new_slots = []
|
||||
|
||||
for [l:lint_file, l:linter] in a:slots
|
||||
while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value')
|
||||
" If we've already computed the return value, use it.
|
||||
let l:lint_file = l:lint_file.value
|
||||
endwhile
|
||||
|
||||
if ale#command#IsDeferred(l:lint_file)
|
||||
" If we are going to return the result later, wait for it.
|
||||
call add(l:deferred_list, l:lint_file)
|
||||
else
|
||||
" If we have the value now, coerce it to 0 or 1.
|
||||
let l:lint_file = l:lint_file is 1
|
||||
endif
|
||||
|
||||
call add(l:new_slots, [l:lint_file, l:linter])
|
||||
endfor
|
||||
|
||||
if !empty(l:deferred_list)
|
||||
for l:deferred in l:deferred_list
|
||||
let l:deferred.result_callback =
|
||||
\ {-> s:GetLintFileValues(l:new_slots, a:Callback)}
|
||||
endfor
|
||||
else
|
||||
call a:Callback(l:new_slots)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:RunLinters(
|
||||
\ buffer,
|
||||
\ linters,
|
||||
\ slots,
|
||||
\ should_lint_file,
|
||||
\ new_buffer,
|
||||
\) abort
|
||||
call s:StopCurrentJobs(a:buffer, a:should_lint_file, a:slots)
|
||||
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
|
||||
|
||||
" We can only clear the results if we aren't checking the buffer.
|
||||
@@ -676,10 +634,10 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
|
||||
silent doautocmd <nomodeline> User ALELintPre
|
||||
|
||||
for l:linter in a:linters
|
||||
for [l:lint_file, l:linter] in a:slots
|
||||
" Only run lint_file linters if we should.
|
||||
if !l:linter.lint_file || a:should_lint_file
|
||||
if s:RunLinter(a:buffer, l:linter)
|
||||
if !l:lint_file || a:should_lint_file
|
||||
if s:RunLinter(a:buffer, l:linter, l:lint_file)
|
||||
" If a single linter ran, we shouldn't clear everything.
|
||||
let l:can_clear_results = 0
|
||||
endif
|
||||
@@ -694,11 +652,32 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
" disabled, or ALE itself is disabled.
|
||||
if l:can_clear_results
|
||||
call ale#engine#SetResults(a:buffer, [])
|
||||
elseif l:new_buffer
|
||||
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
|
||||
elseif a:new_buffer
|
||||
call s:AddProblemsFromOtherBuffers(
|
||||
\ a:buffer,
|
||||
\ map(copy(a:slots), 'v:val[1]')
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
|
||||
" Initialise the buffer information if needed.
|
||||
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
|
||||
|
||||
call s:GetLintFileValues(
|
||||
\ s:GetLintFileSlots(a:buffer, a:linters),
|
||||
\ {
|
||||
\ slots -> s:RunLinters(
|
||||
\ a:buffer,
|
||||
\ a:linters,
|
||||
\ slots,
|
||||
\ a:should_lint_file,
|
||||
\ l:new_buffer,
|
||||
\ )
|
||||
\ }
|
||||
\)
|
||||
endfunction
|
||||
|
||||
" Clean up a buffer.
|
||||
"
|
||||
" This function will stop all current jobs for the buffer,
|
||||
|
||||
@@ -105,11 +105,11 @@ function! ale#events#Init() abort
|
||||
|
||||
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)
|
||||
autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
|
||||
elseif l:text_changed is? 'normal'
|
||||
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
|
||||
autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
|
||||
elseif l:text_changed is? 'insert'
|
||||
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
|
||||
autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
|
||||
endif
|
||||
|
||||
if g:ale_lint_on_enter
|
||||
@@ -147,6 +147,10 @@ function! ale#events#Init() abort
|
||||
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif
|
||||
endif
|
||||
|
||||
if g:ale_hover_cursor
|
||||
autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif
|
||||
endif
|
||||
|
||||
if g:ale_close_preview_on_insert
|
||||
autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
|
||||
endif
|
||||
|
||||
22
autoload/ale/filename_mapping.vim
Normal file
22
autoload/ale/filename_mapping.vim
Normal file
@@ -0,0 +1,22 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Logic for handling mappings between files
|
||||
|
||||
" Invert filesystem mappings so they can be mapped in reverse.
|
||||
function! ale#filename_mapping#Invert(filename_mappings) abort
|
||||
return map(copy(a:filename_mappings), '[v:val[1], v:val[0]]')
|
||||
endfunction
|
||||
|
||||
" Given a filename and some filename_mappings, map a filename.
|
||||
function! ale#filename_mapping#Map(filename, filename_mappings) abort
|
||||
let l:simplified_filename = ale#path#Simplify(a:filename)
|
||||
|
||||
for [l:mapping_from, l:mapping_to] in a:filename_mappings
|
||||
let l:mapping_from = ale#path#Simplify(l:mapping_from)
|
||||
|
||||
if l:simplified_filename[:len(l:mapping_from) - 1] is# l:mapping_from
|
||||
return l:mapping_to . l:simplified_filename[len(l:mapping_from):]
|
||||
endif
|
||||
endfor
|
||||
|
||||
return a:filename
|
||||
endfunction
|
||||
@@ -1,57 +1,43 @@
|
||||
call ale#Set('fix_on_save_ignore', {})
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: Functions for fixing code with programs, or other means.
|
||||
|
||||
let g:ale_fix_on_save_ignore = get(g:, 'ale_fix_on_save_ignore', {})
|
||||
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
|
||||
|
||||
" Apply fixes queued up for buffers which may be hidden.
|
||||
" Vim doesn't let you modify hidden buffers.
|
||||
function! ale#fix#ApplyQueuedFixes(buffer) abort
|
||||
let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0})
|
||||
let l:has_bufline_api = exists('*deletebufline') && exists('*setbufline')
|
||||
|
||||
if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr(''))
|
||||
if !l:data.done || (!ale#util#HasBuflineApi() && a:buffer isnot bufnr(''))
|
||||
return
|
||||
endif
|
||||
|
||||
call remove(g:ale_fix_buffer_data, a:buffer)
|
||||
|
||||
if l:data.changes_made
|
||||
" If the file is in DOS mode, we have to remove carriage returns from
|
||||
" the ends of lines before calling setline(), or we will see them
|
||||
" twice.
|
||||
let l:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
|
||||
\ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
|
||||
\ : l:data.output
|
||||
let l:first_line_to_remove = len(l:new_lines) + 1
|
||||
try
|
||||
if l:data.changes_made
|
||||
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
|
||||
|
||||
" Use a Vim API for setting lines in other buffers, if available.
|
||||
if l:has_bufline_api
|
||||
call setbufline(a:buffer, 1, l:new_lines)
|
||||
call deletebufline(a:buffer, l:first_line_to_remove, '$')
|
||||
" Fall back on setting lines the old way, for the current buffer.
|
||||
else
|
||||
let l:old_line_length = len(l:data.lines_before)
|
||||
|
||||
if l:old_line_length >= l:first_line_to_remove
|
||||
let l:save = winsaveview()
|
||||
silent execute
|
||||
\ l:first_line_to_remove . ',' . l:old_line_length . 'd_'
|
||||
call winrestview(l:save)
|
||||
endif
|
||||
|
||||
call setline(1, l:new_lines)
|
||||
endif
|
||||
|
||||
if l:data.should_save
|
||||
if a:buffer is bufnr('')
|
||||
if empty(&buftype)
|
||||
noautocmd :w!
|
||||
if l:data.should_save
|
||||
if a:buffer is bufnr('')
|
||||
if empty(&buftype)
|
||||
noautocmd :w!
|
||||
else
|
||||
set nomodified
|
||||
endif
|
||||
else
|
||||
set nomodified
|
||||
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
|
||||
call setbufvar(a:buffer, '&modified', 0)
|
||||
endif
|
||||
else
|
||||
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
|
||||
call setbufvar(a:buffer, '&modified', 0)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
catch /E21/
|
||||
" If we cannot modify the buffer now, try again later.
|
||||
let g:ale_fix_buffer_data[a:buffer] = l:data
|
||||
|
||||
return
|
||||
endtry
|
||||
|
||||
if l:data.should_save
|
||||
let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
|
||||
@@ -89,7 +75,10 @@ function! ale#fix#ApplyFixes(buffer, output) abort
|
||||
|
||||
if l:data.lines_before != l:lines
|
||||
call remove(g:ale_fix_buffer_data, a:buffer)
|
||||
execute 'echoerr ''The file was changed before fixing finished'''
|
||||
|
||||
if !l:data.ignore_file_changed_errors
|
||||
execute 'echoerr ''The file was changed before fixing finished'''
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
@@ -115,7 +104,6 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
|
||||
let l:output = a:job_output
|
||||
endif
|
||||
|
||||
let l:ChainCallback = get(a:job_info, 'chain_with', v:null)
|
||||
let l:ProcessWith = get(a:job_info, 'process_with', v:null)
|
||||
|
||||
" Post-process the output with a function if we have one.
|
||||
@@ -127,27 +115,17 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
|
||||
" otherwise skip this job and use the input from before.
|
||||
"
|
||||
" We'll use the input from before for chained commands.
|
||||
if l:ChainCallback is v:null && !empty(split(join(l:output)))
|
||||
if !empty(split(join(l:output)))
|
||||
let l:input = l:output
|
||||
else
|
||||
let l:input = a:job_info.input
|
||||
endif
|
||||
|
||||
if l:ChainCallback isnot v:null && !get(g:, 'ale_ignore_2_4_warnings')
|
||||
execute 'echom ''chain_with is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
|
||||
endif
|
||||
|
||||
let l:next_index = l:ChainCallback is v:null
|
||||
\ ? a:job_info.callback_index + 1
|
||||
\ : a:job_info.callback_index
|
||||
|
||||
call s:RunFixer({
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'output': l:output,
|
||||
\ 'callback_list': a:job_info.callback_list,
|
||||
\ 'callback_index': l:next_index,
|
||||
\ 'chain_callback': l:ChainCallback,
|
||||
\ 'callback_index': a:job_info.callback_index + 1,
|
||||
\})
|
||||
endfunction
|
||||
|
||||
@@ -160,6 +138,7 @@ function! s:RunJob(result, options) abort
|
||||
|
||||
let l:buffer = a:options.buffer
|
||||
let l:input = a:options.input
|
||||
let l:fixer_name = a:options.fixer_name
|
||||
|
||||
if a:result is 0 || type(a:result) is v:t_list
|
||||
if type(a:result) is v:t_list
|
||||
@@ -177,26 +156,21 @@ function! s:RunJob(result, options) abort
|
||||
endif
|
||||
|
||||
let l:command = get(a:result, 'command', '')
|
||||
let l:ChainWith = get(a:result, 'chain_with', v:null)
|
||||
|
||||
if empty(l:command)
|
||||
" If the command is empty, skip to the next item, or call the
|
||||
" chain_with function.
|
||||
" If the command is empty, skip to the next item.
|
||||
call s:RunFixer({
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'callback_index': a:options.callback_index + (l:ChainWith is v:null),
|
||||
\ 'callback_index': a:options.callback_index,
|
||||
\ 'callback_list': a:options.callback_list,
|
||||
\ 'chain_callback': l:ChainWith,
|
||||
\ 'output': [],
|
||||
\})
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
|
||||
" Default to piping the buffer for the last fixer in the chain.
|
||||
let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
|
||||
let l:read_buffer = get(a:result, 'read_buffer', 1)
|
||||
let l:output_stream = get(a:result, 'output_stream', 'stdout')
|
||||
|
||||
if l:read_temporary_file
|
||||
@@ -205,7 +179,6 @@ function! s:RunJob(result, options) abort
|
||||
|
||||
let l:Callback = function('s:HandleExit', [{
|
||||
\ 'input': l:input,
|
||||
\ 'chain_with': l:ChainWith,
|
||||
\ 'callback_index': a:options.callback_index,
|
||||
\ 'callback_list': a:options.callback_list,
|
||||
\ 'process_with': get(a:result, 'process_with', v:null),
|
||||
@@ -217,6 +190,7 @@ function! s:RunJob(result, options) abort
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'log_output': 0,
|
||||
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
|
||||
\})
|
||||
|
||||
if empty(l:run_result)
|
||||
@@ -240,32 +214,22 @@ function! s:RunFixer(options) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:ChainCallback = get(a:options, 'chain_callback', v:null)
|
||||
|
||||
let l:Function = l:ChainCallback isnot v:null
|
||||
\ ? ale#util#GetFunction(l:ChainCallback)
|
||||
\ : a:options.callback_list[l:index]
|
||||
let [l:fixer_name, l:Function] = a:options.callback_list[l:index]
|
||||
|
||||
" Record new jobs started as fixer jobs.
|
||||
call setbufvar(l:buffer, 'ale_job_type', 'fixer')
|
||||
|
||||
if l:ChainCallback isnot v:null
|
||||
" Chained commands accept (buffer, output, [input])
|
||||
let l:result = ale#util#FunctionArgCount(l:Function) == 2
|
||||
\ ? call(l:Function, [l:buffer, a:options.output])
|
||||
\ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
|
||||
else
|
||||
" Regular fixer commands accept (buffer, [input])
|
||||
let l:result = ale#util#FunctionArgCount(l:Function) == 1
|
||||
\ ? call(l:Function, [l:buffer])
|
||||
\ : call(l:Function, [l:buffer, copy(l:input)])
|
||||
endif
|
||||
" Regular fixer commands accept (buffer, [input])
|
||||
let l:result = ale#util#FunctionArgCount(l:Function) == 1
|
||||
\ ? call(l:Function, [l:buffer])
|
||||
\ : call(l:Function, [l:buffer, copy(l:input)])
|
||||
|
||||
call s:RunJob(l:result, {
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'callback_list': a:options.callback_list,
|
||||
\ 'callback_index': l:index,
|
||||
\ 'fixer_name': l:fixer_name,
|
||||
\})
|
||||
endfunction
|
||||
|
||||
@@ -333,16 +297,24 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
|
||||
" Variables with capital characters are needed, or Vim will complain about
|
||||
" funcref variables.
|
||||
for l:Item in l:callback_list
|
||||
" Try to capture the names of registered fixer names, so we can use
|
||||
" them for filename mapping or other purposes later.
|
||||
let l:fixer_name = v:null
|
||||
|
||||
if type(l:Item) is v:t_string
|
||||
let l:Func = ale#fix#registry#GetFunc(l:Item)
|
||||
|
||||
if !empty(l:Func)
|
||||
let l:fixer_name = l:Item
|
||||
let l:Item = l:Func
|
||||
endif
|
||||
endif
|
||||
|
||||
try
|
||||
call add(l:corrected_list, ale#util#GetFunction(l:Item))
|
||||
call add(l:corrected_list, [
|
||||
\ l:fixer_name,
|
||||
\ ale#util#GetFunction(l:Item)
|
||||
\])
|
||||
catch /E475/
|
||||
" Rethrow exceptions for failing to get a function so we can print
|
||||
" a friendly message about it.
|
||||
@@ -360,6 +332,7 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
|
||||
\ 'lines_before': getbufline(a:buffer, 1, '$'),
|
||||
\ 'done': 0,
|
||||
\ 'should_save': a:fixing_flag is# 'save_file',
|
||||
\ 'ignore_file_changed_errors': a:fixing_flag is# '!',
|
||||
\ 'temporary_directory_list': [],
|
||||
\}
|
||||
endfunction
|
||||
@@ -368,19 +341,23 @@ endfunction
|
||||
"
|
||||
" Returns 0 if no fixes can be applied, and 1 if fixing can be done.
|
||||
function! ale#fix#Fix(buffer, fixing_flag, ...) abort
|
||||
if a:fixing_flag isnot# '' && a:fixing_flag isnot# 'save_file'
|
||||
throw "fixing_flag must be either '' or 'save_file'"
|
||||
if a:fixing_flag isnot# ''
|
||||
\&& a:fixing_flag isnot# '!'
|
||||
\&& a:fixing_flag isnot# 'save_file'
|
||||
throw "fixing_flag must be '', '!', or 'save_file'"
|
||||
endif
|
||||
|
||||
try
|
||||
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
|
||||
catch /E700\|BADNAME/
|
||||
let l:function_name = join(split(split(v:exception, ':')[3]))
|
||||
let l:echo_message = printf(
|
||||
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
|
||||
\ l:function_name,
|
||||
\)
|
||||
execute 'echom l:echo_message'
|
||||
if a:fixing_flag isnot# '!'
|
||||
let l:function_name = join(split(split(v:exception, ':')[3]))
|
||||
let l:echo_message = printf(
|
||||
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
|
||||
\ l:function_name,
|
||||
\)
|
||||
execute 'echom l:echo_message'
|
||||
endif
|
||||
|
||||
return 0
|
||||
endtry
|
||||
@@ -414,3 +391,4 @@ endfunction
|
||||
augroup ALEBufferFixGroup
|
||||
autocmd!
|
||||
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
|
||||
augroup END
|
||||
|
||||
@@ -54,6 +54,11 @@ let s:default_registry = {
|
||||
\ 'description': 'Apply elm-format to a file.',
|
||||
\ 'aliases': ['format'],
|
||||
\ },
|
||||
\ 'nimpretty': {
|
||||
\ 'function': 'ale#fixers#nimpretty#Fix',
|
||||
\ 'suggested_filetypes': ['nim'],
|
||||
\ 'description': 'Apply nimpretty to a file.',
|
||||
\ },
|
||||
\ 'eslint': {
|
||||
\ 'function': 'ale#fixers#eslint#Fix',
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript'],
|
||||
@@ -155,6 +160,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['php'],
|
||||
\ 'description': 'Fix PHP files with php-cs-fixer.',
|
||||
\ },
|
||||
\ 'astyle': {
|
||||
\ 'function': 'ale#fixers#astyle#Fix',
|
||||
\ 'suggested_filetypes': ['c', 'cpp'],
|
||||
\ 'description': 'Fix C/C++ with astyle.',
|
||||
\ },
|
||||
\ 'clangtidy': {
|
||||
\ 'function': 'ale#fixers#clangtidy#Fix',
|
||||
\ 'suggested_filetypes': ['c', 'cpp', 'objc'],
|
||||
@@ -235,6 +245,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['haskell'],
|
||||
\ 'description': 'Refactor Haskell files with stylish-haskell.',
|
||||
\ },
|
||||
\ 'purty': {
|
||||
\ 'function': 'ale#fixers#purty#Fix',
|
||||
\ 'suggested_filetypes': ['purescript'],
|
||||
\ 'description': 'Format PureScript files with purty.',
|
||||
\ },
|
||||
\ 'ocamlformat': {
|
||||
\ 'function': 'ale#fixers#ocamlformat#Fix',
|
||||
\ 'suggested_filetypes': ['ocaml'],
|
||||
@@ -350,6 +365,21 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['nix'],
|
||||
\ 'description': 'A formatter for Nix code',
|
||||
\ },
|
||||
\ 'remark-lint': {
|
||||
\ 'function': 'ale#fixers#remark_lint#Fix',
|
||||
\ 'suggested_filetypes': ['markdown'],
|
||||
\ 'description': 'Fix markdown files with remark-lint',
|
||||
\ },
|
||||
\ 'html-beautify': {
|
||||
\ 'function': 'ale#fixers#html_beautify#Fix',
|
||||
\ 'suggested_filetypes': ['html', 'htmldjango'],
|
||||
\ 'description': 'Fix HTML files with html-beautify.',
|
||||
\ },
|
||||
\ 'dhall': {
|
||||
\ 'function': 'ale#fixers#dhall#Fix',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Fix Dhall files with dhall-format.',
|
||||
\ },
|
||||
\}
|
||||
|
||||
" Reset the function registry to the default entries.
|
||||
|
||||
59
autoload/ale/fixers/astyle.vim
Normal file
59
autoload/ale/fixers/astyle.vim
Normal file
@@ -0,0 +1,59 @@
|
||||
" Author: James Kim <jhlink@users.noreply.github.com>
|
||||
" Description: Fix C/C++ files with astyle.
|
||||
|
||||
function! s:set_variables() abort
|
||||
for l:ft in ['c', 'cpp']
|
||||
call ale#Set(l:ft . '_astyle_executable', 'astyle')
|
||||
call ale#Set(l:ft . '_astyle_project_options', '')
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
call s:set_variables()
|
||||
|
||||
|
||||
function! ale#fixers#astyle#Var(buffer, name) abort
|
||||
let l:ft = getbufvar(str2nr(a:buffer), '&filetype')
|
||||
let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c'
|
||||
|
||||
return ale#Var(a:buffer, l:ft . '_astyle_' . a:name)
|
||||
endfunction
|
||||
|
||||
" Try to find a project options file.
|
||||
function! ale#fixers#astyle#FindProjectOptions(buffer) abort
|
||||
let l:proj_options = ale#fixers#astyle#Var(a:buffer, 'project_options')
|
||||
|
||||
" If user has set project options variable then use it and skip any searching.
|
||||
" This would allow users to use project files named differently than .astylerc.
|
||||
if !empty(l:proj_options)
|
||||
return l:proj_options
|
||||
endif
|
||||
|
||||
" Try to find nearest .astylerc file.
|
||||
let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '.astylerc'), ':t')
|
||||
|
||||
if !empty(l:proj_options)
|
||||
return l:proj_options
|
||||
endif
|
||||
|
||||
" Try to find nearest _astylerc file.
|
||||
let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '_astylerc'), ':t')
|
||||
|
||||
if !empty(l:proj_options)
|
||||
return l:proj_options
|
||||
endif
|
||||
|
||||
" If no project options file is found return an empty string.
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#astyle#Fix(buffer) abort
|
||||
let l:executable = ale#fixers#astyle#Var(a:buffer, 'executable')
|
||||
let l:proj_options = ale#fixers#astyle#FindProjectOptions(a:buffer)
|
||||
let l:command = ' --stdin=' . ale#Escape(expand('#' . a:buffer))
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (empty(l:proj_options) ? '' : ' --project=' . l:proj_options)
|
||||
\ . l:command
|
||||
\}
|
||||
endfunction
|
||||
23
autoload/ale/fixers/dhall.vim
Normal file
23
autoload/ale/fixers/dhall.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
" Author: Pat Brisbin <pbrisbin@gmail.com>
|
||||
" Description: Integration of dhall-format with ALE.
|
||||
|
||||
call ale#Set('dhall_format_executable', 'dhall')
|
||||
|
||||
function! ale#fixers#dhall#GetExecutable(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'dhall_format_executable')
|
||||
|
||||
" Dhall is written in Haskell and commonly installed with Stack
|
||||
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall')
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#dhall#Fix(buffer) abort
|
||||
let l:executable = ale#fixers#dhall#GetExecutable(a:buffer)
|
||||
|
||||
return {
|
||||
\ 'command': l:executable
|
||||
\ . ' format'
|
||||
\ . ' --inplace'
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
@@ -53,7 +53,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
" Use --fix-to-stdout with eslint_d
|
||||
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
|
||||
return {
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . ' --stdin-filename %s --stdin --fix-to-stdout',
|
||||
\ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput',
|
||||
@@ -63,7 +64,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
" 4.9.0 is the first version with --fix-dry-run
|
||||
if ale#semver#GTE(a:version, [4, 9, 0])
|
||||
return {
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',
|
||||
\ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput',
|
||||
@@ -71,7 +73,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
|
||||
\ . ' --fix %t',
|
||||
|
||||
21
autoload/ale/fixers/html_beautify.vim
Normal file
21
autoload/ale/fixers/html_beautify.vim
Normal file
@@ -0,0 +1,21 @@
|
||||
" Author: WhyNotHugo <hugo@barrera.io>
|
||||
" Description: Lint HTML files with html-beautify.
|
||||
"
|
||||
call ale#Set('html_beautify_executable', 'html-beautify')
|
||||
call ale#Set('html_beautify_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('html_beautify_options', '')
|
||||
call ale#Set('html_beautify_change_directory', 1)
|
||||
|
||||
function! ale#fixers#html_beautify#Fix(buffer) abort
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'html_beautify',
|
||||
\ ['html-beautify']
|
||||
\)
|
||||
|
||||
let l:options = ale#Var(a:buffer, 'html_beautify_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable). ' ' . l:options . ' -',
|
||||
\}
|
||||
endfunction
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
function! ale#fixers#ktlint#Fix(buffer) abort
|
||||
return {
|
||||
\ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format',
|
||||
\ 'read_temporary_file': 1,
|
||||
\ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format'
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -10,9 +10,7 @@ function! ale#fixers#latexindent#Fix(buffer) abort
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . ' -l -w'
|
||||
\ . ' -l'
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options)
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user