mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-07 05:04:28 +08:00
Compare commits
314 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b24fd13423 | ||
|
|
7c5825ecbc | ||
|
|
01219f0308 | ||
|
|
af1643a948 | ||
|
|
5a1505ad62 | ||
|
|
3fe2223a48 | ||
|
|
e8de12c9f0 | ||
|
|
f932211309 | ||
|
|
6d88801789 | ||
|
|
59b34dd017 | ||
|
|
f2b231dd76 | ||
|
|
8fda1cebff | ||
|
|
8097d51e33 | ||
|
|
06082ef377 | ||
|
|
d3a3f4011b | ||
|
|
cebbb67ea6 | ||
|
|
32b784219b | ||
|
|
7795898841 | ||
|
|
06a97a8541 | ||
|
|
0fa2d18230 | ||
|
|
d0e87c0df4 | ||
|
|
89fa43551f | ||
|
|
98b0dcd7d6 | ||
|
|
b96574e5b5 | ||
|
|
a486aa1d24 | ||
|
|
7c2f5e83ab | ||
|
|
889e6338fe | ||
|
|
41ff80dc9e | ||
|
|
6746eaeaa0 | ||
|
|
d7dbc8f2cf | ||
|
|
e329413a31 | ||
|
|
e6241ee0d2 | ||
|
|
07c11e4e7f | ||
|
|
ab8e043353 | ||
|
|
e6946de98a | ||
|
|
6ab264ff0f | ||
|
|
d93512fe60 | ||
|
|
7b38e97943 | ||
|
|
f5e44415e8 | ||
|
|
e3784c4c4e | ||
|
|
b531a4e0b3 | ||
|
|
dd6bd6f0fe | ||
|
|
529f57a66f | ||
|
|
b8949aaac3 | ||
|
|
dc42c0f948 | ||
|
|
41ed10be4e | ||
|
|
34431d885b | ||
|
|
61cfb3fefb | ||
|
|
321ee6d26b | ||
|
|
58b7c281c5 | ||
|
|
a6c59faa0f | ||
|
|
3e8c8d3ccb | ||
|
|
b66d202c1d | ||
|
|
05ba522c9a | ||
|
|
34f2943fdd | ||
|
|
84a455185c | ||
|
|
fbe7cea91c | ||
|
|
cda46636f4 | ||
|
|
2e323b529d | ||
|
|
bd1f7e1420 | ||
|
|
6e18c03d80 | ||
|
|
9f814a8ce9 | ||
|
|
67ee2b9586 | ||
|
|
7d7ddf22d3 | ||
|
|
2b12c8ccbf | ||
|
|
5fcb24bb3e | ||
|
|
cf47bda024 | ||
|
|
da262f40dd | ||
|
|
6aeb462171 | ||
|
|
442fb2d22f | ||
|
|
08a5bfcaa9 | ||
|
|
73812c3e41 | ||
|
|
91636cff06 | ||
|
|
d787369f37 | ||
|
|
c4bdf165ca | ||
|
|
ddb559b3be | ||
|
|
ee62cc6898 | ||
|
|
219fb5873c | ||
|
|
b62e306222 | ||
|
|
5388ff1d54 | ||
|
|
266fa1c0a4 | ||
|
|
b70eeaadb4 | ||
|
|
74a43755c6 | ||
|
|
58e8d32d79 | ||
|
|
8aa1578605 | ||
|
|
501af8dd8b | ||
|
|
b1810b2752 | ||
|
|
28c93ab185 | ||
|
|
ab0bf61512 | ||
|
|
20cc6d3e05 | ||
|
|
dd1e1025b8 | ||
|
|
3ae01ba249 | ||
|
|
9c7673e6c9 | ||
|
|
8f5ecf0120 | ||
|
|
d1c56769b7 | ||
|
|
b1230873b6 | ||
|
|
4fe7402e89 | ||
|
|
e47c1965a6 | ||
|
|
c675212ddd | ||
|
|
d25711a516 | ||
|
|
aae6d30b1e | ||
|
|
bafa1c619d | ||
|
|
240bb8abae | ||
|
|
36a50111b9 | ||
|
|
abb38955d3 | ||
|
|
fa5aecc250 | ||
|
|
6e6ad2e430 | ||
|
|
79dde5f0e5 | ||
|
|
6c47d7fc35 | ||
|
|
a5240009ba | ||
|
|
46ab7c5904 | ||
|
|
8700586890 | ||
|
|
221aceb6db | ||
|
|
49db8210f6 | ||
|
|
89f7292138 | ||
|
|
6feeca793a | ||
|
|
53b0e6c37d | ||
|
|
a3521de64e | ||
|
|
e52388b8b1 | ||
|
|
0843efc7a5 | ||
|
|
65ba4b85ec | ||
|
|
bf0d0597cb | ||
|
|
9ad8fd6a1b | ||
|
|
d2c3141f26 | ||
|
|
418f8a6fed | ||
|
|
9c48c584a9 | ||
|
|
38a55fa9fe | ||
|
|
4e1c46947d | ||
|
|
e0f8304860 | ||
|
|
f5a908bf99 | ||
|
|
f2e52b9432 | ||
|
|
40bf6e6b5c | ||
|
|
c5a4bbf8b0 | ||
|
|
1c71da5624 | ||
|
|
701c1e4f17 | ||
|
|
15f23532b7 | ||
|
|
3acfa0813e | ||
|
|
e0871be22b | ||
|
|
6e28eec243 | ||
|
|
86205967ea | ||
|
|
eb6a7b7516 | ||
|
|
0135fb3ad3 | ||
|
|
80ab12c7b6 | ||
|
|
ce91972c94 | ||
|
|
168768b326 | ||
|
|
8b46fa3ee7 | ||
|
|
22e7a6f6c2 | ||
|
|
1ba1a9ef0e | ||
|
|
fea666bd27 | ||
|
|
730752523b | ||
|
|
d9bad6c0b8 | ||
|
|
b41eecd31b | ||
|
|
e84c9b300b | ||
|
|
efa95e2657 | ||
|
|
56641e0230 | ||
|
|
507f164a09 | ||
|
|
92d515c211 | ||
|
|
59829bc194 | ||
|
|
d9931b9891 | ||
|
|
3aa58ca179 | ||
|
|
5826b4927c | ||
|
|
6eb68b4507 | ||
|
|
3c799abb44 | ||
|
|
3b8fb39b4a | ||
|
|
3e4b8ea466 | ||
|
|
7b78f2b846 | ||
|
|
e7317e05ea | ||
|
|
381fff0e4c | ||
|
|
5ce97f8cdb | ||
|
|
42a1fc2d29 | ||
|
|
bb7481effb | ||
|
|
7d4a83ecd4 | ||
|
|
eb6015c6fd | ||
|
|
4496c9b3c1 | ||
|
|
4129c356e8 | ||
|
|
c6a5cbb3c7 | ||
|
|
a76f056bd9 | ||
|
|
a730a6d5d5 | ||
|
|
79d1b99067 | ||
|
|
135de34d22 | ||
|
|
5542db1507 | ||
|
|
3321685940 | ||
|
|
7053d468cc | ||
|
|
27146ade32 | ||
|
|
4f02edc3f8 | ||
|
|
166435dbf1 | ||
|
|
ca0cdd26fc | ||
|
|
6b819dd74a | ||
|
|
90b1ea230d | ||
|
|
67d7caee30 | ||
|
|
bc0abc3b96 | ||
|
|
181bc69c8c | ||
|
|
47ad24c221 | ||
|
|
8d8b295ef5 | ||
|
|
bb08b81bf7 | ||
|
|
36c35d840b | ||
|
|
88fa0b9294 | ||
|
|
1a9b8a58c7 | ||
|
|
33b4a90507 | ||
|
|
85b3a4a5c6 | ||
|
|
092748caac | ||
|
|
2f13c2d263 | ||
|
|
b41836130c | ||
|
|
5a8ba75265 | ||
|
|
67d49c75a8 | ||
|
|
0427ee84b4 | ||
|
|
f6ae056d02 | ||
|
|
3e3801e81e | ||
|
|
89db85121c | ||
|
|
26e5948617 | ||
|
|
42f5e8c62c | ||
|
|
28819eedd3 | ||
|
|
937138dad4 | ||
|
|
143af2b9fd | ||
|
|
781bf1502f | ||
|
|
5e64acc6ab | ||
|
|
4ee28d3129 | ||
|
|
9d908ecc66 | ||
|
|
3b7c86e401 | ||
|
|
57736cdccc | ||
|
|
57b9d8bc0e | ||
|
|
652d991077 | ||
|
|
e6745a3811 | ||
|
|
e5ea809094 | ||
|
|
8cb6d043b4 | ||
|
|
8c76b88392 | ||
|
|
975cc7af8f | ||
|
|
d0f2a0ae94 | ||
|
|
9b89ec3d86 | ||
|
|
4234d39d87 | ||
|
|
381fe1badf | ||
|
|
07b596efb5 | ||
|
|
70604828fa | ||
|
|
ab7e5b264f | ||
|
|
c88ebc5e70 | ||
|
|
42cbff29f8 | ||
|
|
bf17bbf898 | ||
|
|
aa047b5ba3 | ||
|
|
6b919e88be | ||
|
|
bfc79bd2aa | ||
|
|
fb6fd80bd2 | ||
|
|
7943bfab96 | ||
|
|
3303f596e5 | ||
|
|
df90725c85 | ||
|
|
edd3114394 | ||
|
|
f0152bca98 | ||
|
|
afa20d96ca | ||
|
|
79e42fed14 | ||
|
|
f444abdfe6 | ||
|
|
722c3e8dae | ||
|
|
bff3d253e9 | ||
|
|
77c5802fc7 | ||
|
|
a223253f35 | ||
|
|
d390abd721 | ||
|
|
53db52e713 | ||
|
|
63abd2dfef | ||
|
|
5f64f8dc57 | ||
|
|
c10da0e390 | ||
|
|
548ee56f40 | ||
|
|
e6ba936a0c | ||
|
|
7f0954b89e | ||
|
|
c6aae3bcfc | ||
|
|
4c6f67a3d0 | ||
|
|
5d65f93033 | ||
|
|
eae124e8ce | ||
|
|
114198e082 | ||
|
|
2f3bce5a1d | ||
|
|
b34274ab10 | ||
|
|
69b7ec1c4c | ||
|
|
737ed31de5 | ||
|
|
46c743a247 | ||
|
|
01331266a8 | ||
|
|
ce0b14979e | ||
|
|
893ac34cca | ||
|
|
c36f3e78e4 | ||
|
|
2303b05baa | ||
|
|
fcc2c3ba71 | ||
|
|
2eb68f6d23 | ||
|
|
104980e40b | ||
|
|
5bbce34605 | ||
|
|
9e95032b30 | ||
|
|
59f8c35a2f | ||
|
|
24d277384c | ||
|
|
3a010f68b8 | ||
|
|
23a8208498 | ||
|
|
7f31065fce | ||
|
|
61c1ddd904 | ||
|
|
99361b2ca9 | ||
|
|
495bce32e9 | ||
|
|
f0f0cc3c18 | ||
|
|
784d1a9a62 | ||
|
|
6428162f79 | ||
|
|
2ed53108c4 | ||
|
|
751838621a | ||
|
|
d7395906ba | ||
|
|
fb7099d440 | ||
|
|
df806c511c | ||
|
|
4b6691f602 | ||
|
|
d4841cedf2 | ||
|
|
c820089c44 | ||
|
|
f02e2ec54c | ||
|
|
4813165614 | ||
|
|
16b43a5708 | ||
|
|
2ef3f9806c | ||
|
|
2e8c8085a6 | ||
|
|
042b351b7a | ||
|
|
81423701b0 | ||
|
|
abcefe7a6e | ||
|
|
864d0861e4 | ||
|
|
9a0ece1ecb | ||
|
|
6d14dc0ac0 | ||
|
|
1427a090df | ||
|
|
8b0879212f | ||
|
|
c7292ce892 |
@@ -5,6 +5,11 @@ clone_depth: 10
|
||||
# Use the directory C:\testplugin so test directories will mostly work.
|
||||
clone_folder: C:\testplugin
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /v\d+\.\d+\.(x|\d+)/
|
||||
|
||||
# Cache the vim and vader directories between builds.
|
||||
cache:
|
||||
- C:\vim -> .appveyor.yml
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,6 +3,8 @@
|
||||
# Ignore all hidden files everywhere.
|
||||
# Use `git add -f` to add hidden files.
|
||||
.*
|
||||
__pycache__
|
||||
*.pyc
|
||||
/doc/tags
|
||||
/init.vim
|
||||
/test/ale-info-test-file
|
||||
|
||||
@@ -3,6 +3,10 @@ sudo: required
|
||||
services:
|
||||
- docker
|
||||
language: generic
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^v\d+\.\d+\.(x|\d+)$/
|
||||
env:
|
||||
- OPTIONS=--vim-80-only
|
||||
- OPTIONS=--vim-81-only
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FROM tweekmonster/vim-testbed:latest
|
||||
|
||||
RUN install_vim -tag v8.0.0027 -build \
|
||||
-tag v8.1.0204 -build \
|
||||
-tag v8.1.0519 -build \
|
||||
-tag neovim:v0.2.0 -build \
|
||||
-tag neovim:v0.3.0 -build
|
||||
-tag neovim:v0.3.5 -build
|
||||
|
||||
ENV PACKAGES="\
|
||||
bash \
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016-2018, w0rp <devw0rp@gmail.com>
|
||||
Copyright (c) 2016-2019, w0rp <devw0rp@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
76
README.md
76
README.md
@@ -1,13 +1,13 @@
|
||||
# Asynchronous Lint Engine [](https://travis-ci.org/w0rp/ale) [](https://ci.appveyor.com/project/w0rp/ale) [](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
# Asynchronous Lint Engine [](https://travis-ci.com/dense-analysis/ale) [](https://ci.appveyor.com/project/dense-analysis/ale) [](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
ALE (Asynchronous Lint Engine) is a plugin for providing linting (checking
|
||||
syntax and semantics) in NeoVim 0.2.0+ and Vim 8 while you edit your text files,
|
||||
ALE (Asynchronous Lint Engine) is a plugin providing linting (syntax checking
|
||||
and semantic errors) in NeoVim 0.2.0+ and Vim 8 while you edit your text files,
|
||||
and acts as a Vim [Language Server Protocol](https://langserver.org/) client.
|
||||
|
||||
<img src="img/example.gif?raw=true" alt="A linting example with the darkspectrum color scheme in GVim." title="A linting example with the darkspectrum color scheme in GVim.">
|
||||
<img src="https://user-images.githubusercontent.com/3518142/59195938-3a81b100-8b85-11e9-8e8d-6a601b1db908.gif" alt="A linting example with the darkspectrum color scheme in GVim." title="A linting example with the darkspectrum color scheme in GVim.">
|
||||
|
||||
ALE makes use of NeoVim and Vim 8 job control functions and timers to
|
||||
run linters on the contents of text buffers and return errors as
|
||||
@@ -26,7 +26,7 @@ features, including:
|
||||
|
||||
* Diagnostics (via Language Server Protocol linters)
|
||||
* Go To Definition (`:ALEGoToDefinition`)
|
||||
* Completion (`let g:ale_completion_enabled = 1` before ALE is loaded)
|
||||
* Completion (Built in completion support, or with Deoplete)
|
||||
* Finding references (`:ALEFindReferences`)
|
||||
* Hover information (`:ALEHover`)
|
||||
* Symbol search (`:ALESymbolSearch`)
|
||||
@@ -159,12 +159,44 @@ ALE offers some support for completion via hijacking of omnicompletion while you
|
||||
type. All of ALE's completion information must come from Language Server
|
||||
Protocol linters, or from `tsserver` for TypeScript.
|
||||
|
||||
ALE integrates with [Deoplete](https://github.com/Shougo/deoplete.nvim) as a
|
||||
completion source, named `'ale'`. You can configure Deoplete to only use ALE as
|
||||
the source of completion information, or mix it with other sources.
|
||||
|
||||
```vim
|
||||
" Use ALE and also some plugin 'foobar' as completion sources for all code.
|
||||
call deoplete#custom#option('sources', {
|
||||
\ '_': ['ale', 'foobar'],
|
||||
\})
|
||||
```
|
||||
|
||||
ALE also offers its own automatic completion support, which does not require any
|
||||
other plugins, and can be enabled by changing a setting before ALE is loaded.
|
||||
|
||||
```vim
|
||||
" Enable completion where available.
|
||||
" This setting must be set before ALE is loaded.
|
||||
"
|
||||
" You should not turn this setting on if you wish to use ALE as a completion
|
||||
" source for other completion plugins, like Deoplete.
|
||||
let g:ale_completion_enabled = 1
|
||||
```
|
||||
|
||||
ALE provides an omni-completion function you can use for triggering
|
||||
completion manually with `<C-x><C-o>`.
|
||||
|
||||
```vim
|
||||
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:
|
||||
|
||||
```vim
|
||||
let g:ale_completion_tsserver_autoimport = 1
|
||||
```
|
||||
|
||||
See `:help ale-completion` for more information.
|
||||
|
||||
<a name="usage-go-to-definition"></a>
|
||||
@@ -234,14 +266,14 @@ any other tools. Simply clone the plugin into your `pack` directory.
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.vim/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/.vim/pack/git-plugins/start/ale
|
||||
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.vim/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### NeoVim on Unix
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
|
||||
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### Vim 8 on Windows
|
||||
@@ -249,7 +281,7 @@ git clone https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plug
|
||||
```bash
|
||||
# Run these commands in the "Git for Windows" Bash terminal
|
||||
mkdir -p ~/vimfiles/pack/git-plugins/start
|
||||
git clone https://github.com/w0rp/ale.git ~/vimfiles/pack/git-plugins/start/ale
|
||||
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/vimfiles/pack/git-plugins/start/ale
|
||||
```
|
||||
|
||||
#### Generating Vim help files
|
||||
@@ -280,7 +312,7 @@ You can run the following commands in your terminal to do so:
|
||||
|
||||
```bash
|
||||
cd ~/.vim/bundle
|
||||
git clone https://github.com/w0rp/ale.git
|
||||
git clone https://github.com/dense-analysis/ale.git
|
||||
```
|
||||
|
||||
<a name="installation-with-vundle"></a>
|
||||
@@ -291,7 +323,7 @@ You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.v
|
||||
by using the path on GitHub for this repository.
|
||||
|
||||
```vim
|
||||
Plugin 'w0rp/ale'
|
||||
Plugin 'dense-analysis/ale'
|
||||
```
|
||||
|
||||
See the Vundle documentation for more information.
|
||||
@@ -305,7 +337,7 @@ by adding the GitHub path for this repository to your `~/.vimrc`
|
||||
and running `:PlugInstall`.
|
||||
|
||||
```vim
|
||||
Plug 'w0rp/ale'
|
||||
Plug 'dense-analysis/ale'
|
||||
```
|
||||
|
||||
<a name="contributing"></a>
|
||||
@@ -313,14 +345,14 @@ Plug 'w0rp/ale'
|
||||
## 4. Contributing
|
||||
|
||||
If you would like to see support for more languages and tools, please
|
||||
[create an issue](https://github.com/w0rp/ale/issues)
|
||||
or [create a pull request](https://github.com/w0rp/ale/pulls).
|
||||
[create an issue](https://github.com/dense-analysis/ale/issues)
|
||||
or [create a pull request](https://github.com/dense-analysis/ale/pulls).
|
||||
If your tool can read from stdin or you have code to suggest which is good,
|
||||
support can be happily added for it.
|
||||
|
||||
If you are interested in the general direction of the project, check out the
|
||||
[wiki home page](https://github.com/w0rp/ale/wiki). The wiki includes a
|
||||
Roadmap for the future, and more.
|
||||
[wiki home page](https://github.com/dense-analysis/ale/wiki). The wiki includes
|
||||
a Roadmap for the future, and more.
|
||||
|
||||
If you'd liked to discuss the project more directly, check out the `#vim-ale` channel
|
||||
on Freenode. Web chat is available [here](https://webchat.freenode.net/?channels=vim-ale).
|
||||
@@ -517,7 +549,7 @@ let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
|
||||
|
||||
Will give you:
|
||||
|
||||

|
||||

|
||||
|
||||
See `:help g:ale_echo_msg_format` for more information.
|
||||
|
||||
@@ -572,6 +604,7 @@ options off.
|
||||
```vim
|
||||
" Write this in your vimrc file
|
||||
let g:ale_lint_on_text_changed = 'never'
|
||||
let g:ale_lint_on_insert_leave = 0
|
||||
" You can disable this option too
|
||||
" if you don't want linters to run on opening a file
|
||||
let g:ale_lint_on_enter = 0
|
||||
@@ -698,11 +731,10 @@ while you type. ALE uses a timeout which is cancelled and reset every time you
|
||||
type, and this delay can be increased so linters are run less often. See
|
||||
`:help g:ale_lint_delay` for more information.
|
||||
|
||||
If you don't wish to run linters while you type, you can disable that
|
||||
behaviour. Set `g:ale_lint_on_text_changed` to `never` or `normal`. You won't
|
||||
get as frequent error checking, but ALE shouldn't block your ability to edit a
|
||||
document after you save a file, so the asynchronous nature of the plugin will
|
||||
still be an advantage.
|
||||
If you don't wish to run linters while you type, you can disable that behaviour.
|
||||
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.
|
||||
|
||||
If you are still concerned, you can turn the automatic linting off altogether,
|
||||
including the option `g:ale_lint_on_enter`, and you can run ALE manually with
|
||||
|
||||
@@ -5,7 +5,10 @@ call ale#Set('asm_gcc_executable', 'gcc')
|
||||
call ale#Set('asm_gcc_options', '-Wall')
|
||||
|
||||
function! ale_linters#asm#gcc#GetCommand(buffer) abort
|
||||
return '%e -x assembler -fsyntax-only '
|
||||
" `-o /dev/null` or `-o null` is needed to catch all errors,
|
||||
" -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'))
|
||||
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
|
||||
endfunction
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
call ale#Set('c_clangd_executable', 'clangd')
|
||||
call ale#Set('c_clangd_options', '')
|
||||
|
||||
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
|
||||
endfunction
|
||||
@@ -19,5 +13,5 @@ call ale#linter#Define('c', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'c_clangd_executable')},
|
||||
\ 'command': function('ale_linters#c#clangd#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'),
|
||||
\ 'project_root': function('ale#c#FindProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -11,22 +11,32 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
|
||||
" http://clang.llvm.org/extra/clang-tidy/checks/list.html
|
||||
|
||||
call ale#Set('c_clangtidy_checks', [])
|
||||
" Set this option to manually set some options for clang-tidy.
|
||||
" Set this option to manually set some options for clang-tidy to use as compile
|
||||
" flags.
|
||||
" This will disable compile_commands.json detection.
|
||||
call ale#Set('c_clangtidy_options', '')
|
||||
" Set this option to manually set options for clang-tidy directly.
|
||||
call ale#Set('c_clangtidy_extra_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
function! ale_linters#c#clangtidy#GetCommand(buffer) abort
|
||||
function! ale_linters#c#clangtidy#GetCommand(buffer, output) abort
|
||||
let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',')
|
||||
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
|
||||
let l:options = ''
|
||||
|
||||
" Get the extra options if we couldn't find a build directory.
|
||||
let l:options = empty(l:build_dir)
|
||||
\ ? ale#Var(a:buffer, 'c_clangtidy_options')
|
||||
\ : ''
|
||||
if empty(l:build_dir)
|
||||
let l:options = ale#Var(a:buffer, 'c_clangtidy_options')
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
|
||||
endif
|
||||
|
||||
" Get the options to pass directly to clang-tidy
|
||||
let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options')
|
||||
|
||||
return '%e'
|
||||
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
|
||||
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
|
||||
\ . ' %s'
|
||||
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
|
||||
\ . (!empty(l:options) ? ' -- ' . l:options : '')
|
||||
@@ -36,7 +46,7 @@ call ale#linter#Define('c', {
|
||||
\ 'name': 'clangtidy',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': {b -> ale#Var(b, 'c_clangtidy_executable')},
|
||||
\ 'command': function('ale_linters#c#clangtidy#GetCommand'),
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clangtidy#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
|
||||
@@ -5,23 +5,17 @@ call ale#Set('c_cppcheck_executable', 'cppcheck')
|
||||
call ale#Set('c_cppcheck_options', '--enable=style')
|
||||
|
||||
function! ale_linters#c#cppcheck#GetCommand(buffer) abort
|
||||
" Search upwards from the file for compile_commands.json.
|
||||
"
|
||||
" If we find it, we'll `cd` to where the compile_commands.json file is,
|
||||
" then use the file to set up import paths, etc.
|
||||
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
let l:cd_command = !empty(l:compile_commmands_path)
|
||||
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
|
||||
\ : ''
|
||||
let l:compile_commands_option = !empty(l:compile_commmands_path)
|
||||
\ ? '--project=compile_commands.json '
|
||||
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
|
||||
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c '
|
||||
\ . l:compile_commands_option
|
||||
\ . ale#Var(a:buffer, 'c_cppcheck_options')
|
||||
\ . '%e -q --language=c'
|
||||
\ . ale#Pad(l:compile_commands_option)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
|
||||
\ . l:buffer_path_include
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -5,13 +5,15 @@ call ale#Set('c_cquery_executable', 'cquery')
|
||||
call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
|
||||
|
||||
function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
" Try to find cquery configuration files first.
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
|
||||
|
||||
if empty(l:project_root)
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
" Fall back on default project root detection.
|
||||
return ale#c#FindProjectRoot(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort
|
||||
|
||||
@@ -9,7 +9,11 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return '%e -S -x c -fsyntax-only'
|
||||
"
|
||||
" `-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')) . ' -'
|
||||
|
||||
54
ale_linters/chef/cookstyle.vim
Normal file
54
ale_linters/chef/cookstyle.vim
Normal file
@@ -0,0 +1,54 @@
|
||||
" Author: Raphael Hoegger - https://github.com/pfuender
|
||||
" Description: Cookstyle (RuboCop based), a code style analyzer for Ruby files
|
||||
|
||||
call ale#Set('chef_cookstyle_executable', 'cookstyle')
|
||||
call ale#Set('chef_cookstyle_options', '')
|
||||
|
||||
function! ale_linters#chef#cookstyle#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'chef_cookstyle_options')
|
||||
|
||||
return '%e' . ale#Pad(escape(l:options, '~')) . ' --force-exclusion --format json --stdin ' . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#chef#cookstyle#Handle(buffer, lines) abort
|
||||
if len(a:lines) == 0
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], {})
|
||||
|
||||
if !has_key(l:errors, 'summary')
|
||||
\|| l:errors['summary']['offense_count'] == 0
|
||||
\|| empty(l:errors['files'])
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:output = []
|
||||
|
||||
for l:error in l:errors['files'][0]['offenses']
|
||||
let l:start_col = str2nr(l:error['location']['start_column'])
|
||||
let l:end_col = str2nr(l:error['location']['last_column'])
|
||||
|
||||
if !l:end_col
|
||||
let l:end_col = l:start_col + 1
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:error['location']['line']),
|
||||
\ 'col': l:start_col,
|
||||
\ 'end_col': l:end_col,
|
||||
\ 'code': l:error['cop_name'],
|
||||
\ 'text': l:error['message'],
|
||||
\ 'type': l:error['severity'] is? 'convention' ? 'W' : 'E',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('chef', {
|
||||
\ 'name': 'cookstyle',
|
||||
\ 'executable': {b -> ale#Var(b, 'chef_cookstyle_executable')},
|
||||
\ 'command': function('ale_linters#chef#cookstyle#GetCommand'),
|
||||
\ 'callback': 'ale_linters#chef#cookstyle#Handle',
|
||||
\})
|
||||
34
ale_linters/clojure/clj_kondo.vim
Normal file
34
ale_linters/clojure/clj_kondo.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" Author: Masashi Iizuka <liquidz.uo@gmail.com>
|
||||
" Description: linter for clojure using clj-kondo https://github.com/borkdude/clj-kondo
|
||||
|
||||
function! ale_linters#clojure#clj_kondo#HandleCljKondoFormat(buffer, lines) abort
|
||||
" output format
|
||||
" <filename>:<line>:<column>: <issue type>: <message>
|
||||
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+):? ((Exception|error|warning): ?(.+))$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:type = 'E'
|
||||
|
||||
if l:match[4] is? 'warning'
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('clojure', {
|
||||
\ 'name': 'clj-kondo',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'clj-kondo',
|
||||
\ 'command': 'clj-kondo --lint %t',
|
||||
\ 'callback': 'ale_linters#clojure#clj_kondo#HandleCljKondoFormat',
|
||||
\})
|
||||
@@ -12,7 +12,8 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
|
||||
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
|
||||
|
||||
if empty(l:build_dir)
|
||||
let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
|
||||
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
|
||||
let l:build_dir = ale#path#Dirname(l:json_file)
|
||||
endif
|
||||
|
||||
" The extra arguments in the command are used to prevent .plist files from
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
call ale#Set('cpp_clangd_executable', 'clangd')
|
||||
call ale#Set('cpp_clangd_options', '')
|
||||
|
||||
function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
|
||||
endfunction
|
||||
@@ -19,5 +13,5 @@ call ale#linter#Define('cpp', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')},
|
||||
\ 'command': function('ale_linters#cpp#clangd#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'),
|
||||
\ 'project_root': function('ale#c#FindProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -5,22 +5,32 @@
|
||||
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
|
||||
" Set this option to check the checks clang-tidy will apply.
|
||||
call ale#Set('cpp_clangtidy_checks', [])
|
||||
" Set this option to manually set some options for clang-tidy.
|
||||
" Set this option to manually set some options for clang-tidy to use as compile
|
||||
" flags.
|
||||
" This will disable compile_commands.json detection.
|
||||
call ale#Set('cpp_clangtidy_options', '')
|
||||
" Set this option to manually set options for clang-tidy directly.
|
||||
call ale#Set('cpp_clangtidy_extra_options', '')
|
||||
call ale#Set('c_build_dir', '')
|
||||
|
||||
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
|
||||
function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
|
||||
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
|
||||
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
|
||||
let l:options = ''
|
||||
|
||||
" Get the extra options if we couldn't find a build directory.
|
||||
let l:options = empty(l:build_dir)
|
||||
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
|
||||
\ : ''
|
||||
if empty(l:build_dir)
|
||||
let l:options = ale#Var(a:buffer, 'cpp_clangtidy_options')
|
||||
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
|
||||
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
|
||||
endif
|
||||
|
||||
" Get the options to pass directly to clang-tidy
|
||||
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
|
||||
|
||||
return '%e'
|
||||
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
|
||||
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
|
||||
\ . ' %s'
|
||||
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
|
||||
\ . (!empty(l:options) ? ' -- ' . l:options : '')
|
||||
@@ -30,7 +40,7 @@ call ale#linter#Define('cpp', {
|
||||
\ 'name': 'clangtidy',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': {b -> ale#Var(b, 'cpp_clangtidy_executable')},
|
||||
\ 'command': function('ale_linters#cpp#clangtidy#GetCommand'),
|
||||
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clangtidy#GetCommand'))},
|
||||
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
|
||||
@@ -5,23 +5,17 @@ call ale#Set('cpp_cppcheck_executable', 'cppcheck')
|
||||
call ale#Set('cpp_cppcheck_options', '--enable=style')
|
||||
|
||||
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
|
||||
" Search upwards from the file for compile_commands.json.
|
||||
"
|
||||
" If we find it, we'll `cd` to where the compile_commands.json file is,
|
||||
" then use the file to set up import paths, etc.
|
||||
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
let l:cd_command = !empty(l:compile_commmands_path)
|
||||
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
|
||||
\ : ''
|
||||
let l:compile_commands_option = !empty(l:compile_commmands_path)
|
||||
\ ? '--project=compile_commands.json '
|
||||
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
|
||||
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c++ '
|
||||
\ . l:compile_commands_option
|
||||
\ . ale#Var(a:buffer, 'cpp_cppcheck_options')
|
||||
\ . '%e -q --language=c++'
|
||||
\ . ale#Pad(l:compile_commands_option)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
|
||||
\ . l:buffer_path_include
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -5,13 +5,15 @@ call ale#Set('cpp_cquery_executable', 'cquery')
|
||||
call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
|
||||
|
||||
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
" Try to find cquery configuration files first.
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
|
||||
|
||||
if empty(l:project_root)
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
" Fall back on default project root detection.
|
||||
return ale#c#FindProjectRoot(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort
|
||||
|
||||
@@ -9,7 +9,11 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
|
||||
|
||||
" -iquote with the directory the file is in makes #include work for
|
||||
" headers in the same directory.
|
||||
return '%e -S -x c++ -fsyntax-only'
|
||||
"
|
||||
" `-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')) . ' -'
|
||||
|
||||
95
ale_linters/cs/csc.vim
Normal file
95
ale_linters/cs/csc.vim
Normal file
@@ -0,0 +1,95 @@
|
||||
call ale#Set('cs_csc_options', '')
|
||||
call ale#Set('cs_csc_source', '')
|
||||
call ale#Set('cs_csc_assembly_path', [])
|
||||
call ale#Set('cs_csc_assemblies', [])
|
||||
|
||||
function! s:GetWorkingDirectory(buffer) abort
|
||||
let l:working_directory = ale#Var(a:buffer, 'cs_csc_source')
|
||||
|
||||
if !empty(l:working_directory)
|
||||
return l:working_directory
|
||||
endif
|
||||
|
||||
return expand('#' . a:buffer . ':p:h')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cs#csc#GetCommand(buffer) abort
|
||||
" Pass assembly paths via the -lib: parameter.
|
||||
let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path')
|
||||
|
||||
let l:lib_option = !empty(l:path_list)
|
||||
\ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',')
|
||||
\ : ''
|
||||
|
||||
" Pass paths to DLL files via the -r: parameter.
|
||||
let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies')
|
||||
|
||||
let l:r_option = !empty(l:assembly_list)
|
||||
\ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',')
|
||||
\ : ''
|
||||
|
||||
" register temporary module target file with ale
|
||||
" register temporary module target file with ALE.
|
||||
let l:out = ale#command#CreateFile(a:buffer)
|
||||
|
||||
" The code is compiled as a module and the output is redirected to a
|
||||
" temporary file.
|
||||
return ale#path#CdString(s:GetWorkingDirectory(a:buffer))
|
||||
\ . 'csc /unsafe'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options'))
|
||||
\ . ale#Pad(l:lib_option)
|
||||
\ . ale#Pad(l:r_option)
|
||||
\ . ' /out:' . l:out
|
||||
\ . ' /t:module'
|
||||
\ . ' /recurse:' . ale#Escape('*.cs')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#cs#csc#Handle(buffer, lines) abort
|
||||
" Look for lines like the following.
|
||||
"
|
||||
" Tests.cs(12,29): error CSXXXX: ; expected
|
||||
"
|
||||
" NOTE: pattern also captures file name as linter compiles all
|
||||
" files within the source tree rooted at the specified source
|
||||
" path and not just the file loaded in the buffer
|
||||
let l:patterns = [
|
||||
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
|
||||
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
|
||||
\]
|
||||
let l:output = []
|
||||
|
||||
let l:dir = s:GetWorkingDirectory(a:buffer)
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:patterns)
|
||||
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[5],
|
||||
\ 'text': l:match[6] ,
|
||||
\})
|
||||
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
|
||||
call add(l:output, {
|
||||
\ 'filename':'<csc>',
|
||||
\ 'lnum': -1,
|
||||
\ 'col': -1,
|
||||
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[2],
|
||||
\ 'text': l:match[3],
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('cs',{
|
||||
\ 'name': 'csc',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': 'csc',
|
||||
\ 'command': function('ale_linters#cs#csc#GetCommand'),
|
||||
\ 'callback': 'ale_linters#cs#csc#Handle',
|
||||
\ 'lint_file': 1
|
||||
\})
|
||||
@@ -52,20 +52,34 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort
|
||||
" NOTE: pattern also captures file name as linter compiles all
|
||||
" files within the source tree rooted at the specified source
|
||||
" path and not just the file loaded in the buffer
|
||||
let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$'
|
||||
let l:patterns = [
|
||||
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
|
||||
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
|
||||
\]
|
||||
let l:output = []
|
||||
|
||||
let l:dir = s:GetWorkingDirectory(a:buffer)
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[5],
|
||||
\ 'text': l:match[6],
|
||||
\})
|
||||
for l:match in ale#util#GetMatches(a:lines, l:patterns)
|
||||
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[5],
|
||||
\ 'text': l:match[6] ,
|
||||
\})
|
||||
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
|
||||
call add(l:output, {
|
||||
\ 'filename':'<mcs>',
|
||||
\ 'lnum': -1,
|
||||
\ 'col': -1,
|
||||
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
|
||||
\ 'code': l:match[2],
|
||||
\ 'text': l:match[3],
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
|
||||
9
ale_linters/css/fecs.vim
Normal file
9
ale_linters/css/fecs.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: harttle <yangjvn@126.com>
|
||||
" Description: fecs for CSS files
|
||||
|
||||
call ale#linter#Define('css', {
|
||||
\ 'name': 'fecs',
|
||||
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#fecs#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#fecs#Handle',
|
||||
\})
|
||||
40
ale_linters/elm/elm_ls.vim
Normal file
40
ale_linters/elm/elm_ls.vim
Normal file
@@ -0,0 +1,40 @@
|
||||
" Author: antew - https://github.com/antew
|
||||
" Description: elm-language-server integration for elm (diagnostics, formatting, and more)
|
||||
|
||||
call ale#Set('elm_ls_executable', 'elm-language-server')
|
||||
call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1))
|
||||
|
||||
" elm-language-server will search for local and global binaries, if empty
|
||||
call ale#Set('elm_ls_elm_path', '')
|
||||
call ale#Set('elm_ls_elm_format_path', '')
|
||||
call ale#Set('elm_ls_elm_test_path', '')
|
||||
call ale#Set('elm_ls_elm_analyse_trigger', 'change')
|
||||
|
||||
function! elm_ls#GetRootDir(buffer) abort
|
||||
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
|
||||
|
||||
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
|
||||
endfunction
|
||||
|
||||
function! elm_ls#GetOptions(buffer) abort
|
||||
return {
|
||||
\ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'),
|
||||
\ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'),
|
||||
\ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'),
|
||||
\ 'elmAnalyseTrigger': ale#Var(a:buffer, 'elm_ls_elm_analyse_trigger'),
|
||||
\}
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('elm', {
|
||||
\ 'name': 'elm_ls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_ls', [
|
||||
\ 'node_modules/.bin/elm-language-server',
|
||||
\ 'node_modules/.bin/elm-lsp',
|
||||
\ 'elm-lsp'
|
||||
\ ])},
|
||||
\ 'command': '%e --stdio',
|
||||
\ 'project_root': function('elm_ls#GetRootDir'),
|
||||
\ 'language': 'elm',
|
||||
\ 'initialization_options': function('elm_ls#GetOptions')
|
||||
\})
|
||||
@@ -1,22 +0,0 @@
|
||||
" Author: antew - https://github.com/antew
|
||||
" Description: LSP integration for elm, currently supports diagnostics (linting)
|
||||
|
||||
call ale#Set('elm_lsp_executable', 'elm-lsp')
|
||||
call ale#Set('elm_lsp_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! elm_lsp#GetRootDir(buffer) abort
|
||||
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
|
||||
|
||||
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('elm', {
|
||||
\ 'name': 'elm_lsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_lsp', [
|
||||
\ 'node_modules/.bin/elm-lsp',
|
||||
\ ])},
|
||||
\ 'command': '%e --stdio',
|
||||
\ 'project_root': function('elm_lsp#GetRootDir'),
|
||||
\ 'language': 'elm'
|
||||
\})
|
||||
93
ale_linters/erlang/dialyzer.vim
Normal file
93
ale_linters/erlang/dialyzer.vim
Normal file
@@ -0,0 +1,93 @@
|
||||
" Author: Autoine Gagne - https://github.com/AntoineGagne
|
||||
" Description: Define a checker that runs dialyzer on Erlang files.
|
||||
|
||||
let g:ale_erlang_dialyzer_executable =
|
||||
\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer')
|
||||
let g:ale_erlang_dialyzer_plt_file =
|
||||
\ get(g:, 'ale_erlang_dialyzer_plt_file', '')
|
||||
let g:ale_erlang_dialyzer_rebar3_profile =
|
||||
\ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default')
|
||||
|
||||
function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort
|
||||
return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort
|
||||
let l:plt_file = ''
|
||||
let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer)
|
||||
let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build/' . l:rebar3_profile)
|
||||
|
||||
if !empty(l:plt_file_directory)
|
||||
let l:plt_file = globpath(l:plt_file_directory, '*_plt', 0, 1)
|
||||
endif
|
||||
|
||||
if !empty(l:plt_file)
|
||||
return l:plt_file[0]
|
||||
endif
|
||||
|
||||
if !empty($REBAR_PLT_DIR)
|
||||
return expand('$REBAR_PLT_DIR/dialyzer/plt')
|
||||
endif
|
||||
|
||||
return expand('$HOME/.dialyzer_plt')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort
|
||||
let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file')
|
||||
|
||||
if !empty(l:plt_file)
|
||||
return l:plt_file
|
||||
endif
|
||||
|
||||
return ale_linters#erlang#dialyzer#FindPlt(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'erlang_dialyzer_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort
|
||||
let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer))
|
||||
\ . ' -n'
|
||||
\ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer))
|
||||
\ . ' -Wunmatched_returns'
|
||||
\ . ' -Werror_handling'
|
||||
\ . ' -Wrace_conditions'
|
||||
\ . ' -Wunderspecs'
|
||||
\ . ' %s'
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort
|
||||
" Match patterns like the following:
|
||||
"
|
||||
" erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available
|
||||
let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, l:pattern)
|
||||
|
||||
if len(l:match) != 0
|
||||
let l:code = l:match[2]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'lcol': 0,
|
||||
\ 'text': l:code,
|
||||
\ 'type': 'W'
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('erlang', {
|
||||
\ 'name': 'dialyzer',
|
||||
\ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'),
|
||||
\ 'command': function('ale_linters#erlang#dialyzer#GetCommand'),
|
||||
\ 'callback': function('ale_linters#erlang#dialyzer#Handle'),
|
||||
\ 'lint_file': 1
|
||||
\})
|
||||
@@ -8,7 +8,7 @@ call ale#Set('eruby_ruumba_options', '')
|
||||
function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'eruby_ruumba_executable')
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'ruumba')
|
||||
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'))
|
||||
|
||||
@@ -5,11 +5,13 @@ call ale#Set('go_bingo_executable', 'bingo')
|
||||
call ale#Set('go_bingo_options', '--mode stdio')
|
||||
|
||||
function! ale_linters#go#bingo#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
|
||||
return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#bingo#FindProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod')
|
||||
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
|
||||
let l:project_root = l:go_modules_off ?
|
||||
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
|
||||
let l:mods = ':h'
|
||||
|
||||
if empty(l:project_root)
|
||||
|
||||
@@ -11,6 +11,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
|
||||
|
||||
" Run go test in local directory with relative path
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . ale#Var(a:buffer, 'go_go_executable') . ' test'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' -c -o /dev/null ./'
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
" Author: neersighted <bjorn@neersighted.com>
|
||||
" Description: gofmt for Go files
|
||||
|
||||
function! ale_linters#go#gofmt#GetCommand(buffer) abort
|
||||
return ale#go#EnvString(a:buffer)
|
||||
\ . '%e -e %t'
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'gofmt',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'gofmt',
|
||||
\ 'command': 'gofmt -e %t',
|
||||
\ 'command': function('ale_linters#go#gofmt#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsError',
|
||||
\})
|
||||
|
||||
@@ -10,13 +10,16 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
|
||||
let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
|
||||
|
||||
|
||||
if l:lint_package
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . '%e run '
|
||||
\ . l:options
|
||||
endif
|
||||
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . '%e run '
|
||||
\ . ale#Escape(l:filename)
|
||||
\ . ' ' . l:options
|
||||
|
||||
@@ -7,7 +7,7 @@ call ale#Set('go_golint_options', '')
|
||||
function! ale_linters#go#golint#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'go_golint_options')
|
||||
|
||||
return '%e'
|
||||
return ale#go#EnvString(a:buffer) . '%e'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
@@ -14,11 +14,13 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
|
||||
" be calculated to absolute paths in the Handler
|
||||
if l:lint_package
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . '%e'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
|
||||
endif
|
||||
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . '%e'
|
||||
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
|
||||
|
||||
34
ale_linters/go/gopls.vim
Normal file
34
ale_linters/go/gopls.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Author: Jerko Steiner <https://github.com/jeremija>
|
||||
" Description: https://github.com/saibing/gopls
|
||||
|
||||
call ale#Set('go_gopls_executable', 'gopls')
|
||||
call ale#Set('go_gopls_options', '--mode stdio')
|
||||
|
||||
function! ale_linters#go#gopls#GetCommand(buffer) abort
|
||||
return ale#go#EnvString(a:buffer)
|
||||
\ . '%e'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#go#gopls#FindProjectRoot(buffer) abort
|
||||
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
|
||||
let l:project_root = l:go_modules_off ?
|
||||
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
|
||||
let l:mods = ':h'
|
||||
|
||||
if empty(l:project_root)
|
||||
let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
let l:mods = ':h:h'
|
||||
endif
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, l:mods) : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
\ 'name': 'gopls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'go_gopls_executable')},
|
||||
\ 'command': function('ale_linters#go#gopls#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#go#gopls#FindProjectRoot'),
|
||||
\})
|
||||
@@ -2,7 +2,8 @@
|
||||
" Description: gosimple for Go files
|
||||
|
||||
function! ale_linters#go#gosimple#GetCommand(buffer) abort
|
||||
return ale#path#BufferCdString(a:buffer) . ' gosimple .'
|
||||
return ale#path#BufferCdString(a:buffer) . ' '
|
||||
\ . ale#go#EnvString(a:buffer) . 'gosimple .'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
|
||||
@@ -6,7 +6,8 @@ function! ale_linters#go#gotype#GetCommand(buffer) abort
|
||||
return ''
|
||||
endif
|
||||
|
||||
return ale#path#BufferCdString(a:buffer) . ' gotype -e .'
|
||||
return ale#path#BufferCdString(a:buffer) . ' '
|
||||
\ . ale#go#EnvString(a:buffer) . 'gotype -e .'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
|
||||
@@ -11,6 +11,7 @@ function! ale_linters#go#govet#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'go_govet_options')
|
||||
|
||||
return ale#path#BufferCdString(a:buffer) . ' '
|
||||
\ . ale#go#EnvString(a:buffer)
|
||||
\ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' .'
|
||||
|
||||
@@ -15,8 +15,9 @@ function! ale_linters#go#langserver#GetCommand(buffer) abort
|
||||
endif
|
||||
|
||||
let l:options = uniq(sort(l:options))
|
||||
let l:env = ale#go#EnvString(a:buffer)
|
||||
|
||||
return join(extend(l:executable, l:options), ' ')
|
||||
return l:env . join(extend(l:executable, l:options), ' ')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('go', {
|
||||
|
||||
@@ -8,17 +8,18 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort
|
||||
let l:filename = expand('#' . a:buffer . ':t')
|
||||
let l:options = ale#Var(a:buffer, 'go_staticcheck_options')
|
||||
let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package')
|
||||
let l:env = ale#go#EnvString(a:buffer)
|
||||
|
||||
" BufferCdString is used so that we can be sure the paths output from
|
||||
" staticcheck can be calculated to absolute paths in the Handler
|
||||
if l:lint_package
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . 'staticcheck'
|
||||
\ . l:env . 'staticcheck'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
|
||||
endif
|
||||
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . 'staticcheck'
|
||||
\ . l:env . 'staticcheck'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' ' . ale#Escape(l:filename)
|
||||
endfunction
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
call ale#Set('haskell_cabal_ghc_options', '-fno-code -v0')
|
||||
|
||||
function! ale_linters#haskell#cabal_ghc#GetCommand(buffer) abort
|
||||
return 'cabal exec -- ghc '
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . 'cabal exec -- ghc '
|
||||
\ . ale#Var(a:buffer, 'haskell_cabal_ghc_options')
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
call ale#Set('haskell_stack_ghc_options', '-fno-code -v0')
|
||||
|
||||
function! ale_linters#haskell#stack_ghc#GetCommand(buffer) abort
|
||||
return ale#handlers#haskell#GetStackExecutable(a:buffer)
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#handlers#haskell#GetStackExecutable(a:buffer)
|
||||
\ . ' ghc -- '
|
||||
\ . ale#Var(a:buffer, 'haskell_stack_ghc_options')
|
||||
\ . ' %t'
|
||||
|
||||
9
ale_linters/html/fecs.vim
Normal file
9
ale_linters/html/fecs.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
" Author: harttle <yangjvn@126.com>
|
||||
" Description: fecs for HTMl files
|
||||
|
||||
call ale#linter#Define('html', {
|
||||
\ 'name': 'fecs',
|
||||
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#fecs#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#fecs#Handle',
|
||||
\})
|
||||
35
ale_linters/ink/ls.vim
Normal file
35
ale_linters/ink/ls.vim
Normal file
@@ -0,0 +1,35 @@
|
||||
" Author: Andreww Hayworth <ahayworth@gmail.com>
|
||||
" Description: Integrate ALE with ink-language-server
|
||||
|
||||
call ale#Set('ink_ls_executable', 'ink-language-server')
|
||||
call ale#Set('ink_ls_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('ink_ls_initialization_options', {})
|
||||
|
||||
function! ale_linters#ink#ls#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'ink_ls', [
|
||||
\ 'ink-language-server',
|
||||
\ 'node_modules/.bin/ink-language-server',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ink#ls#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#ink#ls#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable) . ' --stdio'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ink#ls#FindProjectRoot(buffer) abort
|
||||
let l:main_file = get(ale#Var(a:buffer, 'ink_ls_initialization_options'), 'mainStoryPath', 'main.ink')
|
||||
let l:config = ale#path#ResolveLocalPath(a:buffer, l:main_file, expand('#' . a:buffer . ':p'))
|
||||
|
||||
return ale#path#Dirname(l:config)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ink', {
|
||||
\ 'name': 'ink-language-server',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale_linters#ink#ls#GetExecutable'),
|
||||
\ 'command': function('ale_linters#ink#ls#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#ink#ls#FindProjectRoot'),
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'ink_ls_initialization_options')},
|
||||
\})
|
||||
@@ -1,6 +1,10 @@
|
||||
" Author: Devon Meunier <devon.meunier@gmail.com>
|
||||
" Description: checkstyle for Java files
|
||||
|
||||
call ale#Set('java_checkstyle_executable', 'checkstyle')
|
||||
call ale#Set('java_checkstyle_config', '/google_checks.xml')
|
||||
call ale#Set('java_checkstyle_options', '')
|
||||
|
||||
function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
@@ -17,6 +21,10 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
|
||||
\})
|
||||
endfor
|
||||
|
||||
if !empty(l:output)
|
||||
return l:output
|
||||
endif
|
||||
|
||||
" old checkstyle versions
|
||||
let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'
|
||||
|
||||
@@ -31,19 +39,32 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! s:GetConfig(buffer, config) abort
|
||||
if ale#path#IsAbsolute(a:config)
|
||||
return a:config
|
||||
endif
|
||||
|
||||
let s:file = ale#path#FindNearestFile(a:buffer, a:config)
|
||||
|
||||
return !empty(s:file) ? s:file : a:config
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
|
||||
return 'checkstyle '
|
||||
\ . ale#Var(a:buffer, 'java_checkstyle_options')
|
||||
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)
|
||||
\ ? s:GetConfig(a:buffer, l:config_option)
|
||||
\ : ''
|
||||
|
||||
return '%e'
|
||||
\ . ale#Pad(l:options)
|
||||
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
if !exists('g:ale_java_checkstyle_options')
|
||||
let g:ale_java_checkstyle_options = '-c /google_checks.xml'
|
||||
endif
|
||||
|
||||
call ale#linter#Define('java', {
|
||||
\ 'name': 'checkstyle',
|
||||
\ 'executable': 'checkstyle',
|
||||
\ 'executable': {b -> ale#Var(b, 'java_checkstyle_executable')},
|
||||
\ 'command': function('ale_linters#java#checkstyle#GetCommand'),
|
||||
\ 'callback': 'ale_linters#java#checkstyle#Handle',
|
||||
\ 'lint_file': 1,
|
||||
|
||||
161
ale_linters/java/eclipselsp.vim
Normal file
161
ale_linters/java/eclipselsp.vim
Normal file
@@ -0,0 +1,161 @@
|
||||
" Author: Horacio Sanson <https://github.com/hsanson>
|
||||
" Description: Support for the Eclipse language server https://github.com/eclipse/eclipse.jdt.ls
|
||||
|
||||
let s:version_cache = {}
|
||||
|
||||
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')
|
||||
|
||||
function! ale_linters#java#eclipselsp#Executable(buffer) abort
|
||||
return ale#Var(a:buffer, 'java_eclipselsp_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#TargetPath(buffer) abort
|
||||
return ale#Var(a:buffer, 'java_eclipselsp_path')
|
||||
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 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)
|
||||
|
||||
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
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort
|
||||
let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h')
|
||||
let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path')
|
||||
|
||||
if !empty(l:config_path)
|
||||
return ale#path#Simplify(l:config_path)
|
||||
endif
|
||||
|
||||
if has('win32')
|
||||
let l:path = l:path . '/config_win'
|
||||
elseif has('macunix')
|
||||
let l:path = l:path . '/config_mac'
|
||||
else
|
||||
let l:path = l:path . '/config_linux'
|
||||
endif
|
||||
|
||||
return ale#path#Simplify(l:path)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#VersionCheck(version_lines) abort
|
||||
return s:GetVersion('', a:version_lines)
|
||||
endfunction
|
||||
|
||||
function! s:GetVersion(executable, version_lines) abort
|
||||
let l:version = []
|
||||
|
||||
for l:line in a:version_lines
|
||||
let l:match = matchlist(l:line, '\(\d\+\)\.\(\d\+\)\.\(\d\+\)')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
|
||||
let s:version_cache[a:executable] = l:version
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:version
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines, meta) abort
|
||||
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
|
||||
let l:version = s:GetVersion(l:executable, a:version_lines)
|
||||
|
||||
return ale_linters#java#eclipselsp#Command(a:buffer, l:version)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
|
||||
let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path')
|
||||
|
||||
if !empty(l:wspath)
|
||||
return l:wspath
|
||||
endif
|
||||
|
||||
return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
|
||||
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),
|
||||
\ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
|
||||
\ '-Dosgi.bundles.defaultStartLevel=4',
|
||||
\ '-Declipse.product=org.eclipse.jdt.ls.core.product',
|
||||
\ '-Dlog.level=ALL',
|
||||
\ '-noverify',
|
||||
\ '-Xmx1G',
|
||||
\ '-jar',
|
||||
\ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)),
|
||||
\ '-configuration',
|
||||
\ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)),
|
||||
\ '-data',
|
||||
\ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer))
|
||||
\ ]
|
||||
|
||||
if ale#semver#GTE(a:version, [1, 9])
|
||||
call add(l:cmd, '--add-modules=ALL-SYSTEM')
|
||||
call add(l:cmd, '--add-opens java.base/java.util=ALL-UNNAMED')
|
||||
call add(l:cmd, '--add-opens java.base/java.lang=ALL-UNNAMED')
|
||||
endif
|
||||
|
||||
return join(l:cmd, ' ')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
|
||||
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
|
||||
|
||||
if empty(l:executable)
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:cache = s:version_cache
|
||||
|
||||
if has_key(s:version_cache, l:executable)
|
||||
return ale_linters#java#eclipselsp#Command(a:buffer, s:version_cache[l:executable])
|
||||
endif
|
||||
|
||||
let l:command = ale#Escape(l:executable) . ' -version'
|
||||
|
||||
return ale#command#Run(
|
||||
\ a:buffer,
|
||||
\ l:command,
|
||||
\ function('ale_linters#java#eclipselsp#CommandWithVersion')
|
||||
\)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('java', {
|
||||
\ 'name': 'eclipselsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale_linters#java#eclipselsp#Executable'),
|
||||
\ 'command': function('ale_linters#java#eclipselsp#RunWithVersionCheck'),
|
||||
\ 'language': 'java',
|
||||
\ 'project_root': function('ale#java#FindProjectRoot'),
|
||||
\})
|
||||
@@ -21,6 +21,11 @@ function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
|
||||
let l:command = ale#gradle#BuildClasspathCommand(a:buffer)
|
||||
endif
|
||||
|
||||
" Try to use Ant if Gradle and Maven aren't available
|
||||
if empty(l:command)
|
||||
let l:command = ale#ant#BuildClasspathCommand(a:buffer)
|
||||
endif
|
||||
|
||||
if empty(l:command)
|
||||
return ale_linters#java#javac#GetCommand(a:buffer, [], {})
|
||||
endif
|
||||
@@ -99,7 +104,7 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort
|
||||
" Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
|
||||
" Main.java:16: error: ';' expected
|
||||
let l:directory = expand('#' . a:buffer . ':p:h')
|
||||
let l:pattern = '\v^(.*):(\d+): (.+):(.+)$'
|
||||
let l:pattern = '\v^(.*):(\d+): (.{-1,}):(.+)$'
|
||||
let l:col_pattern = '\v^(\s*\^)$'
|
||||
let l:symbol_pattern = '\v^ +symbol: *(class|method) +([^ ]+)'
|
||||
let l:output = []
|
||||
|
||||
@@ -1,16 +1,47 @@
|
||||
" Author: Horacio Sanson <https://github.com/hsanson>
|
||||
" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
|
||||
|
||||
call ale#Set('java_javalsp_executable', 'java')
|
||||
call ale#Set('java_javalsp_executable', '')
|
||||
call ale#Set('java_javalsp_config', {})
|
||||
|
||||
function! ale_linters#java#javalsp#Executable(buffer) abort
|
||||
return ale#Var(a:buffer, 'java_javalsp_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#javalsp#Config(buffer) abort
|
||||
let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } }
|
||||
let l:config = ale#Var(a:buffer, 'java_javalsp_config')
|
||||
|
||||
" Ensure the config dictionary contains both classPath and
|
||||
" externalDependencies keys to avoid a NPE crash on Java Language Server.
|
||||
call extend(l:config, l:defaults, 'keep')
|
||||
call extend(l:config['java'], l:defaults['java'], 'keep')
|
||||
|
||||
return l:config
|
||||
endfunction
|
||||
|
||||
function! ale_linters#java#javalsp#Command(buffer) abort
|
||||
let l:executable = ale_linters#java#javalsp#Executable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable) . ' -Xverify:none -m javacs/org.javacs.Main'
|
||||
if fnamemodify(l:executable, ':t') is# 'java'
|
||||
" For backward compatibility.
|
||||
let l:cmd = [
|
||||
\ ale#Escape(l:executable),
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs',
|
||||
\ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs',
|
||||
\ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs',
|
||||
\ '-m javacs/org.javacs.Main',
|
||||
\]
|
||||
|
||||
return join(l:cmd, ' ')
|
||||
else
|
||||
return ale#Escape(l:executable)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('java', {
|
||||
@@ -20,4 +51,5 @@ call ale#linter#Define('java', {
|
||||
\ 'command': function('ale_linters#java#javalsp#Command'),
|
||||
\ 'language': 'java',
|
||||
\ 'project_root': function('ale#java#FindProjectRoot'),
|
||||
\ 'lsp_config': function('ale_linters#java#javalsp#Config')
|
||||
\})
|
||||
|
||||
@@ -6,5 +6,5 @@ call ale#linter#Define('javascript', {
|
||||
\ 'output_stream': 'both',
|
||||
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#eslint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#Handle',
|
||||
\ 'callback': 'ale#handlers#eslint#HandleJSON',
|
||||
\})
|
||||
|
||||
10
ale_linters/javascript/fecs.vim
Normal file
10
ale_linters/javascript/fecs.vim
Normal file
@@ -0,0 +1,10 @@
|
||||
" Author: harttle <yangjvn@126.com>
|
||||
" Description: fecs for JavaScript files
|
||||
|
||||
call ale#linter#Define('javascript', {
|
||||
\ 'name': 'fecs',
|
||||
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#fecs#GetCommand'),
|
||||
\ 'read_buffer': 0,
|
||||
\ 'callback': 'ale#handlers#fecs#Handle',
|
||||
\})
|
||||
0
ale_linters/javascript/flow.vim
Executable file → Normal file
0
ale_linters/javascript/flow.vim
Executable file → Normal file
@@ -8,6 +8,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/standard/bin/cmd.js',
|
||||
\ 'node_modules/semistandard/bin/cmd.js',
|
||||
\ 'node_modules/.bin/standard',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
@@ -14,7 +14,7 @@ endfunction
|
||||
function! ale_linters#javascript#xo#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#javascript#xo#GetExecutable(a:buffer))
|
||||
\ . ' ' . ale#Var(a:buffer, 'javascript_xo_options')
|
||||
\ . ' --reporter unix --stdin --stdin-filename %s'
|
||||
\ . ' --reporter json --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
" xo uses eslint and the output format is the same
|
||||
@@ -22,5 +22,5 @@ call ale#linter#Define('javascript', {
|
||||
\ 'name': 'xo',
|
||||
\ 'executable': function('ale_linters#javascript#xo#GetExecutable'),
|
||||
\ 'command': function('ale_linters#javascript#xo#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#Handle',
|
||||
\ 'callback': 'ale#handlers#eslint#HandleJSON',
|
||||
\})
|
||||
|
||||
@@ -12,6 +12,8 @@ let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_fi
|
||||
let s:classpath_sep = has('unix') ? ':' : ';'
|
||||
|
||||
function! ale_linters#kotlin#kotlinc#RunWithImportPaths(buffer) abort
|
||||
let l:command = ''
|
||||
|
||||
" exec maven/gradle only if classpath is not set
|
||||
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# ''
|
||||
return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {})
|
||||
|
||||
0
ale_linters/less/lessc.vim
Executable file → Normal file
0
ale_linters/less/lessc.vim
Executable file → Normal file
@@ -17,18 +17,17 @@ function! ale_linters#markdown#mdl#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'markdown_mdl_options')
|
||||
|
||||
return ale#Escape(l:executable) . l:exec_args
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' -j' . (!empty(l:options) ? ' ' . l:options : '')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
|
||||
" matches: '(stdin):173: MD004 Unordered list style'
|
||||
let l:pattern = ':\(\d*\): \(.*\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'text': l:match[2],
|
||||
\ 'lnum': l:error['line'],
|
||||
\ 'code': l:error['rule'] . '/' . join(l:error['aliases'], '/'),
|
||||
\ 'text': l:error['description'],
|
||||
\ 'type': 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
call ale#Set('objc_clangd_executable', 'clangd')
|
||||
call ale#Set('objc_clangd_options', '')
|
||||
|
||||
function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#objc#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
|
||||
endfunction
|
||||
@@ -19,5 +13,5 @@ call ale#linter#Define('objc', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')},
|
||||
\ 'command': function('ale_linters#objc#clangd#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'),
|
||||
\ 'project_root': function('ale#c#FindProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
call ale#Set('objcpp_clangd_executable', 'clangd')
|
||||
call ale#Set('objcpp_clangd_options', '')
|
||||
|
||||
function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
|
||||
endfunction
|
||||
@@ -19,5 +13,5 @@ call ale#linter#Define('objcpp', {
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')},
|
||||
\ 'command': function('ale_linters#objcpp#clangd#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'),
|
||||
\ 'project_root': function('ale#c#FindProjectRoot'),
|
||||
\})
|
||||
|
||||
@@ -10,13 +10,13 @@ call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
function! ale_linters#php#phpcs#GetCommand(buffer) abort
|
||||
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
|
||||
let l:standard_option = !empty(l:standard)
|
||||
\ ? '--standard=' . l:standard
|
||||
\ ? '--standard=' . ale#Escape(l:standard)
|
||||
\ : ''
|
||||
let l:options = ale#Var(a:buffer, 'php_phpcs_options')
|
||||
|
||||
return '%e -s --report=emacs --stdin-path=%s'
|
||||
\ . ale#Pad(l:standard_option)
|
||||
\ . ale#Pad(l:options)
|
||||
return ale#path#BufferCdString(a:buffer)
|
||||
\ . '%e -s --report=emacs --stdin-path=%s'
|
||||
\ . ale#Pad(l:standard_option)
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
@@ -36,6 +36,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type is# 'error' ? 'E' : 'W',
|
||||
\ 'sub_type': 'style',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -3,23 +3,42 @@
|
||||
|
||||
" Set to change the ruleset
|
||||
let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan')
|
||||
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4')
|
||||
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '')
|
||||
let g:ale_php_phpstan_configuration = get(g:, 'ale_php_phpstan_configuration', '')
|
||||
let g:ale_php_phpstan_autoload = get(g:, 'ale_php_phpstan_autoload', '')
|
||||
|
||||
function! ale_linters#php#phpstan#GetCommand(buffer, version) abort
|
||||
let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration')
|
||||
let l:configuration_option = !empty(l:configuration)
|
||||
\ ? ' -c ' . l:configuration
|
||||
\ ? ' -c ' . ale#Escape(l:configuration)
|
||||
\ : ''
|
||||
|
||||
let l:autoload = ale#Var(a:buffer, 'php_phpstan_autoload')
|
||||
let l:autoload_option = !empty(l:autoload)
|
||||
\ ? ' -a ' . ale#Escape(l:autoload)
|
||||
\ : ''
|
||||
|
||||
let l:level = ale#Var(a:buffer, 'php_phpstan_level')
|
||||
let l:config_file_exists = ale#path#FindNearestFile(a:buffer, 'phpstan.neon')
|
||||
|
||||
if empty(l:level) && empty(l:config_file_exists)
|
||||
" if no configuration file is found, then use 4 as a default level
|
||||
let l:level = '4'
|
||||
endif
|
||||
|
||||
let l:level_option = !empty(l:level)
|
||||
\ ? ' -l ' . ale#Escape(l:level)
|
||||
\ : ''
|
||||
|
||||
let l:error_format = ale#semver#GTE(a:version, [0, 10, 3])
|
||||
\ ? ' --error-format raw'
|
||||
\ : ' --errorFormat raw'
|
||||
|
||||
return '%e analyze -l'
|
||||
\ . ale#Var(a:buffer, 'php_phpstan_level')
|
||||
return '%e analyze --no-progress'
|
||||
\ . l:error_format
|
||||
\ . l:configuration_option
|
||||
\ . l:autoload_option
|
||||
\ . l:level_option
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
@@ -35,7 +54,7 @@ function! ale_linters#php#phpstan#Handle(buffer, lines) abort
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': 'W',
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
" Author: Matt Brown <https://github.com/muglug>
|
||||
" Description: plugin for Psalm, static analyzer for PHP
|
||||
|
||||
call ale#Set('psalm_langserver_executable', 'psalm-language-server')
|
||||
call ale#Set('psalm_langserver_executable', 'psalm')
|
||||
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
|
||||
@@ -14,8 +14,8 @@ call ale#linter#Define('php', {
|
||||
\ 'name': 'psalm',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
|
||||
\ 'vendor/bin/psalm-language-server',
|
||||
\ 'vendor/bin/psalm',
|
||||
\ ])},
|
||||
\ 'command': '%e',
|
||||
\ 'command': '%e --language-server',
|
||||
\ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'),
|
||||
\})
|
||||
|
||||
99
ale_linters/powershell/powershell.vim
Normal file
99
ale_linters/powershell/powershell.vim
Normal file
@@ -0,0 +1,99 @@
|
||||
" Author: Jesse Harris - https://github.com/zigford
|
||||
" Description: This file adds support for powershell scripts synatax errors
|
||||
|
||||
call ale#Set('powershell_powershell_executable', 'pwsh')
|
||||
|
||||
function! ale_linters#powershell#powershell#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'powershell_powershell_executable')
|
||||
endfunction
|
||||
|
||||
" Some powershell magic to show syntax errors without executing the script
|
||||
" thanks to keith hill:
|
||||
" 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);
|
||||
\ trap {$_;continue} & {
|
||||
\ $Contents = Get-Content -Path $Script;
|
||||
\ $Contents = [string]::Join([Environment]::NewLine, $Contents);
|
||||
\ [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Contents);
|
||||
\ };']
|
||||
|
||||
return ale#powershell#RunPowerShell(
|
||||
\ a:buffer, 'powershell_powershell', l:script)
|
||||
endfunction
|
||||
|
||||
" Parse powershell error output using regex into a list of dicts
|
||||
function! ale_linters#powershell#powershell#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
" Our 3 patterns we need to scrape the data for the dicts
|
||||
let l:patterns = [
|
||||
\ '\v^At line:(\d+) char:(\d+)',
|
||||
\ '\v^(At|\+| )@!.*',
|
||||
\ '\vFullyQualifiedErrorId : (\w+)',
|
||||
\]
|
||||
|
||||
let l:matchcount = 0
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:patterns)
|
||||
" We want to work with 3 matches per syntax error
|
||||
let l:matchcount = l:matchcount + 1
|
||||
|
||||
if l:matchcount == 1 || str2nr(l:match[1])
|
||||
" First match consists of 2 capture groups, and
|
||||
" can capture the line and col
|
||||
if exists('l:item')
|
||||
" We may be here because the last syntax
|
||||
" didn't emit a code, and so only had 2
|
||||
" matches
|
||||
call add(l:output, l:item)
|
||||
let l:matchcount = 1
|
||||
endif
|
||||
|
||||
" If the match is 0, it was a failed match
|
||||
" probably due to an unexpected token which
|
||||
" contained a newline. Reset matchcount. to
|
||||
" continue to the next match
|
||||
if !empty(l:match[1])
|
||||
let l:item = {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'col': str2nr(l:match[2]),
|
||||
\ 'type': 'E',
|
||||
\}
|
||||
else
|
||||
let l:matchcount = 0
|
||||
endif
|
||||
elseif l:matchcount == 2
|
||||
" Second match[0] grabs the full line in order
|
||||
" to handles the text
|
||||
let l:item['text'] = l:match[0]
|
||||
else
|
||||
" Final match handles the code, however
|
||||
" powershell only emits 1 code for all errors
|
||||
" so, we get the final code on the last error
|
||||
" and loop over the previously added items to
|
||||
" append the code we now know
|
||||
call add(l:output, l:item)
|
||||
unlet l:item
|
||||
|
||||
if len(l:match[1]) > 0
|
||||
for l:i in l:output
|
||||
let l:i['code'] = l:match[1]
|
||||
endfor
|
||||
endif
|
||||
|
||||
" Reset the matchcount so we can begin gathering
|
||||
" matches for the next syntax error
|
||||
let l:matchcount = 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('powershell', {
|
||||
\ 'name': 'powershell',
|
||||
\ 'executable': function('ale_linters#powershell#powershell#GetExecutable'),
|
||||
\ 'command': function('ale_linters#powershell#powershell#GetCommand'),
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'callback': 'ale_linters#powershell#powershell#Handle',
|
||||
\})
|
||||
@@ -13,37 +13,6 @@ function! ale_linters#powershell#psscriptanalyzer#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'powershell_psscriptanalyzer_executable')
|
||||
endfunction
|
||||
|
||||
" Write a powershell script to a temp file for execution
|
||||
" return the command used to execute it
|
||||
function! s:TemporaryPSScript(buffer, input) abort
|
||||
let l:filename = 'script.ps1'
|
||||
" Create a temp dir to house our temp .ps1 script
|
||||
" a temp dir is needed as powershell needs the .ps1
|
||||
" extension
|
||||
let l:tempdir = ale#util#Tempname() . (has('win32') ? '\' : '/')
|
||||
let l:tempscript = l:tempdir . l:filename
|
||||
" Create the temporary directory for the file, unreadable by 'other'
|
||||
" users.
|
||||
call mkdir(l:tempdir, '', 0750)
|
||||
" Automatically delete the directory later.
|
||||
call ale#command#ManageDirectory(a:buffer, l:tempdir)
|
||||
" Write the script input out to a file.
|
||||
call ale#util#Writefile(a:buffer, a:input, l:tempscript)
|
||||
|
||||
return l:tempscript
|
||||
endfunction
|
||||
|
||||
function! ale_linters#powershell#psscriptanalyzer#RunPowerShell(buffer, command) abort
|
||||
let l:executable = ale_linters#powershell#psscriptanalyzer#GetExecutable(
|
||||
\ a:buffer)
|
||||
let l:tempscript = s:TemporaryPSScript(a:buffer, a:command)
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
\ . ' -Exe Bypass -NoProfile -File '
|
||||
\ . ale#Escape(l:tempscript)
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
" Run Invoke-ScriptAnalyzer and output each linting message as 4 seperate lines
|
||||
" for each parsing
|
||||
function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
|
||||
@@ -60,8 +29,10 @@ function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
|
||||
\ $_.Message;
|
||||
\ $_.RuleName}']
|
||||
|
||||
return ale_linters#powershell#psscriptanalyzer#RunPowerShell(
|
||||
\ a:buffer, l:script)
|
||||
return ale#powershell#RunPowerShell(
|
||||
\ a:buffer,
|
||||
\ 'powershell_psscriptanalyzer',
|
||||
\ l:script)
|
||||
endfunction
|
||||
|
||||
" add every 4 lines to an item(Dict) and every item to a list
|
||||
@@ -98,8 +69,8 @@ endfunction
|
||||
|
||||
call ale#linter#Define('powershell', {
|
||||
\ 'name': 'psscriptanalyzer',
|
||||
\ 'executable_callback': 'ale_linters#powershell#psscriptanalyzer#GetExecutable',
|
||||
\ 'command_callback': 'ale_linters#powershell#psscriptanalyzer#GetCommand',
|
||||
\ 'executable': function('ale_linters#powershell#psscriptanalyzer#GetExecutable'),
|
||||
\ 'command': function('ale_linters#powershell#psscriptanalyzer#GetCommand'),
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'callback': 'ale_linters#powershell#psscriptanalyzer#Handle',
|
||||
\})
|
||||
|
||||
@@ -31,6 +31,20 @@ function! ale_linters#pug#puglint#GetCommand(buffer) abort
|
||||
\ . ' -r inline %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#pug#puglint#Handle(buffer, lines) abort
|
||||
for l:line in a:lines[:10]
|
||||
if l:line =~# '^SyntaxError: '
|
||||
return [{
|
||||
\ 'lnum': 1,
|
||||
\ 'text': 'puglint configuration error (type :ALEDetail for more information)',
|
||||
\ 'detail': join(a:lines, "\n"),
|
||||
\}]
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ale#handlers#unix#HandleAsError(a:buffer, a:lines)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('pug', {
|
||||
\ 'name': 'puglint',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [
|
||||
@@ -38,5 +52,5 @@ call ale#linter#Define('pug', {
|
||||
\ ])},
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': function('ale_linters#pug#puglint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#unix#HandleAsError',
|
||||
\ 'callback': 'ale_linters#pug#puglint#Handle',
|
||||
\})
|
||||
|
||||
49
ale_linters/purescript/ls.vim
Normal file
49
ale_linters/purescript/ls.vim
Normal file
@@ -0,0 +1,49 @@
|
||||
" Author: Drew Olson <drew@drewolson.org>
|
||||
" Description: Integrate ALE with purescript-language-server.
|
||||
|
||||
call ale#Set('purescript_ls_executable', 'purescript-language-server')
|
||||
call ale#Set('purescript_ls_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('purescript_ls_config', {})
|
||||
|
||||
function! ale_linters#purescript#ls#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'purescript_ls', [
|
||||
\ 'node_modules/.bin/purescript-language-server',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#purescript#ls#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#purescript#ls#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable) . ' --stdio'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#purescript#ls#FindProjectRoot(buffer) abort
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, 'bower.json')
|
||||
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, 'psc-package.json')
|
||||
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, 'spago.dhall')
|
||||
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('purescript', {
|
||||
\ 'name': 'purescript-language-server',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale_linters#purescript#ls#GetExecutable'),
|
||||
\ 'command': function('ale_linters#purescript#ls#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#purescript#ls#FindProjectRoot'),
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'purescript_ls_config')},
|
||||
\})
|
||||
@@ -78,4 +78,5 @@ call ale#linter#Define('python', {
|
||||
\ 'executable': function('ale_linters#python#mypy#GetExecutable'),
|
||||
\ 'command': function('ale_linters#python#mypy#GetCommand'),
|
||||
\ 'callback': 'ale_linters#python#mypy#Handle',
|
||||
\ 'output_stream': 'both'
|
||||
\})
|
||||
|
||||
@@ -6,6 +6,7 @@ call ale#Set('python_pylint_options', '')
|
||||
call ale#Set('python_pylint_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('python_pylint_change_directory', 1)
|
||||
call ale#Set('python_pylint_auto_pipenv', 0)
|
||||
call ale#Set('python_pylint_use_msg_id', 0)
|
||||
|
||||
function! ale_linters#python#pylint#GetExecutable(buffer) abort
|
||||
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylint_auto_pipenv'))
|
||||
@@ -64,11 +65,17 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
|
||||
continue
|
||||
endif
|
||||
|
||||
if ale#Var(a:buffer, 'python_pylint_use_msg_id') is# 1
|
||||
let l:code_out = l:code
|
||||
else
|
||||
let l:code_out = l:match[4]
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 1,
|
||||
\ 'text': l:match[5],
|
||||
\ 'code': l:match[4],
|
||||
\ 'code': l:code_out,
|
||||
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
23
ale_linters/reason/ls.vim
Normal file
23
ale_linters/reason/ls.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
" Author: David Buchan-Swanson <github@deecewan.com>
|
||||
" Description: Integrate ALE with reason-language-server.
|
||||
|
||||
call ale#Set('reason_ls_executable', '')
|
||||
|
||||
function! ale_linters#reason#ls#FindProjectRoot(buffer) abort
|
||||
let l:reason_config = ale#path#FindNearestFile(a:buffer, 'bsconfig.json')
|
||||
|
||||
if !empty(l:reason_config)
|
||||
return fnamemodify(l:reason_config, ':h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('reason', {
|
||||
\ 'name': 'reason-language-server',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale_linters#reason#ls#FindProjectRoot'),
|
||||
\ 'language': 'reason',
|
||||
\})
|
||||
@@ -36,7 +36,7 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
|
||||
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'brakeman')
|
||||
\ . ' -f json -q '
|
||||
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
|
||||
\ . ' -p ' . ale#Escape(l:rails_root)
|
||||
|
||||
42
ale_linters/ruby/debride.vim
Normal file
42
ale_linters/ruby/debride.vim
Normal file
@@ -0,0 +1,42 @@
|
||||
" Author: Eddie Lebow https://github.com/elebow
|
||||
" Description: debride, a dead method detector for Ruby files
|
||||
|
||||
call ale#Set('ruby_debride_executable', 'debride')
|
||||
call ale#Set('ruby_debride_options', '')
|
||||
|
||||
function! ale_linters#ruby#debride#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_debride_executable')
|
||||
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'debride')
|
||||
\ . ale#Var(a:buffer, 'ruby_debride_options')
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ruby#debride#HandleOutput(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
if l:line !~# '^ '
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:elements = split(l:line)
|
||||
let l:method_name = l:elements[0]
|
||||
let l:lnum = split(l:elements[1], ':')[1]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': 0 + l:lnum,
|
||||
\ 'text': 'Possible unused method: ' . l:method_name,
|
||||
\ 'type': 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'debride',
|
||||
\ 'executable': {b -> ale#Var(b, 'ruby_debride_executable')},
|
||||
\ 'command': function('ale_linters#ruby#debride#GetCommand'),
|
||||
\ 'callback': 'ale_linters#ruby#debride#HandleOutput',
|
||||
\})
|
||||
@@ -33,7 +33,7 @@ function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
|
||||
let l:output_file = has('win32') ? '%t ' : '/dev/stdout '
|
||||
let l:cat_file = has('win32') ? '; type %t' : ''
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
|
||||
\ . ' --silent -f json --output-file ' . l:output_file
|
||||
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
|
||||
\ . ale#Escape(l:rails_root)
|
||||
|
||||
@@ -14,7 +14,7 @@ function! ale_linters#ruby#reek#GetCommand(buffer, version) abort
|
||||
\ ? ' --stdin-filename %s'
|
||||
\ : ''
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'reek')
|
||||
\ . ' -f json --no-progress --no-color --force-exclusion'
|
||||
\ . l:display_name_args
|
||||
endfunction
|
||||
|
||||
@@ -7,7 +7,7 @@ call ale#Set('ruby_rubocop_options', '')
|
||||
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
|
||||
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'))
|
||||
|
||||
23
ale_linters/ruby/sorbet.vim
Normal file
23
ale_linters/ruby/sorbet.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
call ale#Set('ruby_sorbet_executable', 'srb')
|
||||
call ale#Set('ruby_sorbet_options', '')
|
||||
|
||||
function! ale_linters#ruby#sorbet#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable')
|
||||
let l:options = ale#Var(a:buffer, 'ruby_sorbet_options')
|
||||
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'srb')
|
||||
\ . ' tc'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --lsp --disable-watchman'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
\ 'name': 'sorbet',
|
||||
\ 'aliases': ['srb'],
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'language': 'ruby',
|
||||
\ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')},
|
||||
\ 'command': function('ale_linters#ruby#sorbet#GetCommand'),
|
||||
\ 'project_root': function('ale#ruby#FindProjectRoot')
|
||||
\})
|
||||
|
||||
@@ -8,7 +8,7 @@ call ale#Set('ruby_standardrb_options', '')
|
||||
function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'ruby_standardrb_executable')
|
||||
|
||||
return ale#handlers#ruby#EscapeExecutable(l:executable, 'standardrb')
|
||||
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'))
|
||||
|
||||
@@ -25,14 +25,11 @@ endfunction
|
||||
function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
|
||||
let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check')
|
||||
\ && ale#semver#GTE(a:version, [0, 17, 0])
|
||||
let l:use_all_targets = l:use_check
|
||||
\ && ale#Var(a:buffer, 'rust_cargo_check_all_targets')
|
||||
let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets')
|
||||
\ && ale#semver#GTE(a:version, [0, 22, 0])
|
||||
let l:use_examples = l:use_check
|
||||
\ && ale#Var(a:buffer, 'rust_cargo_check_examples')
|
||||
let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples')
|
||||
\ && ale#semver#GTE(a:version, [0, 22, 0])
|
||||
let l:use_tests = l:use_check
|
||||
\ && ale#Var(a:buffer, 'rust_cargo_check_tests')
|
||||
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
|
||||
\ && ale#semver#GTE(a:version, [0, 22, 0])
|
||||
|
||||
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
|
||||
@@ -69,7 +66,15 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
|
||||
|
||||
if ale#Var(a:buffer, 'rust_cargo_use_clippy')
|
||||
let l:subcommand = 'clippy'
|
||||
let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options')
|
||||
let l:clippy_options = ale#Var(a:buffer, 'rust_cargo_clippy_options')
|
||||
|
||||
if l:clippy_options =~# '^-- '
|
||||
let l:clippy_options = join(split(l:clippy_options, '-- '))
|
||||
endif
|
||||
|
||||
if l:clippy_options isnot# ''
|
||||
let l:clippy_options = ' -- ' . l:clippy_options
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:nearest_cargo_prefix . 'cargo '
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
" Description: A language server for Rust
|
||||
|
||||
call ale#Set('rust_rls_executable', 'rls')
|
||||
call ale#Set('rust_rls_toolchain', 'nightly')
|
||||
call ale#Set('rust_rls_toolchain', '')
|
||||
call ale#Set('rust_rls_config', {})
|
||||
|
||||
function! ale_linters#rust#rls#GetCommand(buffer) abort
|
||||
|
||||
48
ale_linters/scala/metals.vim
Normal file
48
ale_linters/scala/metals.vim
Normal file
@@ -0,0 +1,48 @@
|
||||
" Author: Jeffrey Lau - https://github.com/zoonfafer
|
||||
" Description: Metals Language Server for Scala https://scalameta.org/metals/
|
||||
|
||||
call ale#Set('scala_metals_executable', 'metals-vim')
|
||||
call ale#Set('scala_metals_project_root', '')
|
||||
|
||||
function! ale_linters#scala#metals#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#Var(a:buffer, 'scala_metals_project_root')
|
||||
|
||||
if !empty(l:project_root)
|
||||
return l:project_root
|
||||
endif
|
||||
|
||||
let l:potential_roots = [
|
||||
\ 'build.sc',
|
||||
\ 'build.sbt',
|
||||
\ '.bloop',
|
||||
\ '.metals',
|
||||
\]
|
||||
|
||||
for l:root in l:potential_roots
|
||||
let l:project_root = ale#path#ResolveLocalPath(
|
||||
\ a:buffer,
|
||||
\ l:root,
|
||||
\ ''
|
||||
\)
|
||||
|
||||
if !empty(l:project_root)
|
||||
return fnamemodify(
|
||||
\ l:project_root,
|
||||
\ ':h',
|
||||
\)
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale_linters#scala#metals#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad('stdio')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('scala', {
|
||||
\ 'name': 'metals',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'language': 'scala',
|
||||
\ 'executable': {b -> ale#Var(b, 'scala_metals_executable')},
|
||||
\ 'command': function('ale_linters#scala#metals#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#scala#metals#GetProjectRoot'),
|
||||
\})
|
||||
@@ -34,8 +34,10 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
"
|
||||
" bash: line 13: syntax error near unexpected token `d'
|
||||
" bash:行0: 未预期的符号“done”附近有语法错误
|
||||
" bash: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符
|
||||
" sh: 11: Syntax error: "(" unexpected
|
||||
let l:pattern = '\v(line |: ?)(\d+): (.+)$'
|
||||
let l:pattern = '\v([^:]+:\D*)(\d+): (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
|
||||
@@ -10,6 +10,7 @@ call ale#Set('sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_excl
|
||||
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)
|
||||
@@ -40,12 +41,15 @@ function! ale_linters#sh#shellcheck#GetCommand(buffer, version) abort
|
||||
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 ale#path#BufferCdString(a:buffer)
|
||||
return l:cd_string
|
||||
\ . '%e'
|
||||
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
|
||||
35
ale_linters/solidity/solc.vim
Normal file
35
ale_linters/solidity/solc.vim
Normal file
@@ -0,0 +1,35 @@
|
||||
" Author: Karl Bartel <karl42@gmail.com> - http://karl.berlin/
|
||||
" Description: Report solc compiler errors in Solidity code
|
||||
|
||||
call ale#Set('solidity_solc_options', '')
|
||||
|
||||
function! ale_linters#solidity#solc#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" /path/to/file/file.sol:1:10: Error: Identifier not found or not unique.
|
||||
let l:pattern = '\v^[^:]+:(\d+):(\d+): (Error|Warning): (.*)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:isError = l:match[3] is? 'error'
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:isError ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#solidity#solc#GetCommand(buffer) abort
|
||||
return 'solc' . ale#Pad(ale#Var(a:buffer, 'solidity_solc_options')) . ' %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('solidity', {
|
||||
\ 'name': 'solc',
|
||||
\ 'executable': 'solc',
|
||||
\ 'command': function('ale_linters#solidity#solc#GetCommand'),
|
||||
\ 'callback': 'ale_linters#solidity#solc#Handle',
|
||||
\ 'output_stream': 'stderr',
|
||||
\})
|
||||
13
ale_linters/swift/sourcekitlsp.vim
Normal file
13
ale_linters/swift/sourcekitlsp.vim
Normal file
@@ -0,0 +1,13 @@
|
||||
" Author: Dan Loman <https://github.com/namolnad>
|
||||
" Description: Support for sourcekit-lsp https://github.com/apple/sourcekit-lsp
|
||||
|
||||
call ale#Set('sourcekit_lsp_executable', 'sourcekit-lsp')
|
||||
|
||||
call ale#linter#Define('swift', {
|
||||
\ 'name': 'sourcekitlsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'sourcekit_lsp_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale#swift#FindProjectRoot'),
|
||||
\ 'language': 'swift',
|
||||
\})
|
||||
49
ale_linters/terraform/terraform.vim
Normal file
49
ale_linters/terraform/terraform.vim
Normal file
@@ -0,0 +1,49 @@
|
||||
" Author: Keith Maxwell <keith.maxwell@gmail.com>
|
||||
" Description: terraform fmt to check for errors
|
||||
|
||||
call ale#Set('terraform_terraform_executable', 'terraform')
|
||||
|
||||
function! ale_linters#terraform#terraform#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'terraform_terraform_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer))
|
||||
\ . ' fmt -no-color --check=true -'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
|
||||
let l:head = '^Error running fmt: In <standard input>: '
|
||||
let l:output = []
|
||||
let l:patterns = [
|
||||
\ l:head.'At \(\d\+\):\(\d\+\): \(.*\)$',
|
||||
\ l:head.'\(.*\)$'
|
||||
\]
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:patterns)
|
||||
if len(l:match[2]) > 0
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'col': str2nr(l:match[2]),
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
else
|
||||
call add(l:output, {
|
||||
\ 'lnum': line('$'),
|
||||
\ 'text': l:match[1],
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('terraform', {
|
||||
\ 'name': 'terraform',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'),
|
||||
\ 'command': function('ale_linters#terraform#terraform#GetCommand'),
|
||||
\ 'callback': 'ale_linters#terraform#terraform#Handle',
|
||||
\})
|
||||
@@ -9,23 +9,69 @@ call ale#Set('terraform_tflint_executable', 'tflint')
|
||||
|
||||
function! ale_linters#terraform#tflint#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
let l:pattern = '\v^(.*):(\d+),(\d+)-(\d+)?,?(\d+): (.{-1,}); (.+)$'
|
||||
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
|
||||
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
if l:error.type is# 'ERROR'
|
||||
let l:type = 'E'
|
||||
elseif l:error.type is# 'NOTICE'
|
||||
let l:type = 'I'
|
||||
else
|
||||
let l:type = 'W'
|
||||
endif
|
||||
" This is a rough test for tflint's output format
|
||||
" On versions prior to 0.11 it outputs all errors as a single level list
|
||||
if type(l:json) is v:t_list
|
||||
for l:error in l:json
|
||||
if l:error.type is# 'ERROR'
|
||||
let l:type = 'E'
|
||||
elseif l:error.type is# 'NOTICE'
|
||||
let l:type = 'I'
|
||||
else
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.line,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': l:type,
|
||||
\ 'code': l:error.detector,
|
||||
\})
|
||||
endfor
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.line,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': l:type,
|
||||
\ 'code': l:error.detector,
|
||||
\})
|
||||
endfor
|
||||
else
|
||||
for l:error in get(l:json, 'errors', [])
|
||||
for l:match in ale#util#GetMatches(l:error.message, [l:pattern])
|
||||
if l:match[4] is# ''
|
||||
let l:match[4] = l:match[2]
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'filename': l:match[1],
|
||||
\ 'lnum': str2nr(l:match[2]),
|
||||
\ 'col': str2nr(l:match[3]),
|
||||
\ 'end_lnum': str2nr(l:match[4]),
|
||||
\ 'end_col': str2nr(l:match[5]),
|
||||
\ 'text': l:match[7],
|
||||
\ 'code': l:match[6],
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
endfor
|
||||
|
||||
for l:error in get(l:json, 'issues', [])
|
||||
if l:error.rule.severity is# 'ERROR'
|
||||
let l:type = 'E'
|
||||
elseif l:error.rule.severity is# 'NOTICE'
|
||||
let l:type = 'I'
|
||||
else
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'filename': l:error.range.filename,
|
||||
\ 'lnum': l:error.range.start.line,
|
||||
\ 'col': l:error.range.start.column,
|
||||
\ 'end_lnum': l:error.range.end.line,
|
||||
\ 'end_col': l:error.range.end.column,
|
||||
\ 'text': l:error.message,
|
||||
\ 'code': l:error.rule.name,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
21
ale_linters/tex/texlab.vim
Normal file
21
ale_linters/tex/texlab.vim
Normal file
@@ -0,0 +1,21 @@
|
||||
" Author: Ricardo Liang <ricardoliang@gmail.com>
|
||||
" Description: Texlab language server (Rust rewrite)
|
||||
|
||||
call ale#Set('tex_texlab_executable', 'texlab')
|
||||
call ale#Set('tex_texlab_options', '')
|
||||
|
||||
function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#tex#texlab#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'tex_texlab_options'))
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('tex', {
|
||||
\ 'name': 'texlab',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'tex_texlab_executable')},
|
||||
\ 'command': function('ale_linters#tex#texlab#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#tex#texlab#GetProjectRoot'),
|
||||
\})
|
||||
@@ -5,5 +5,5 @@ call ale#linter#Define('typescript', {
|
||||
\ 'name': 'eslint',
|
||||
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#eslint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#Handle',
|
||||
\ 'callback': 'ale#handlers#eslint#HandleJSON',
|
||||
\})
|
||||
|
||||
23
ale_linters/typescript/xo.vim
Normal file
23
ale_linters/typescript/xo.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
call ale#Set('typescript_xo_executable', 'xo')
|
||||
call ale#Set('typescript_xo_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('typescript_xo_options', '')
|
||||
|
||||
function! ale_linters#typescript#xo#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'typescript_xo', [
|
||||
\ 'node_modules/.bin/xo',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#typescript#xo#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#typescript#xo#GetExecutable(a:buffer))
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'typescript_xo_options'))
|
||||
\ . ' --reporter json --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
" xo uses eslint and the output format is the same
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'xo',
|
||||
\ 'executable': function('ale_linters#typescript#xo#GetExecutable'),
|
||||
\ 'command': function('ale_linters#typescript#xo#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#eslint#HandleJSON',
|
||||
\})
|
||||
@@ -24,6 +24,20 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
|
||||
\})
|
||||
endfor
|
||||
|
||||
"Matches patterns like the following:
|
||||
"** 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\+\(.*\)'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
|
||||
\ 'text': l:match[2] . ' ' . l:match[4],
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -43,6 +43,11 @@ function! ale#ShouldDoNothing(buffer) abort
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Do nothing for diff buffers.
|
||||
if getbufvar(a:buffer, '&diff')
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Do nothing for blacklisted files.
|
||||
if index(get(g:, 'ale_filetype_blacklist', []), l:filetype) >= 0
|
||||
return 1
|
||||
@@ -92,7 +97,7 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
|
||||
" 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)
|
||||
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
|
||||
|
||||
@@ -151,7 +156,7 @@ function! ale#Queue(delay, ...) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:current_ale_version = [2, 4, 0]
|
||||
let s:current_ale_version = [2, 6, 0]
|
||||
|
||||
" A function used to check for ALE features in files outside of the project.
|
||||
function! ale#Has(feature) abort
|
||||
|
||||
41
autoload/ale/ant.vim
Normal file
41
autoload/ale/ant.vim
Normal file
@@ -0,0 +1,41 @@
|
||||
" Author: Andrew Lee <andrewl@mbda.fun>.
|
||||
" Inspired by ale/gradle.vim by Michael Pardo <michael@michaelpardo.com>
|
||||
" Description: Functions for working with Ant projects.
|
||||
|
||||
" Given a buffer number, find an Ant project root
|
||||
function! ale#ant#FindProjectRoot(buffer) abort
|
||||
let l:build_xml_path = ale#path#FindNearestFile(a:buffer, 'build.xml')
|
||||
|
||||
if !empty(l:build_xml_path)
|
||||
return fnamemodify(l:build_xml_path, ':h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, find the path to the `ant` executable. Returns an empty
|
||||
" string if cannot find the executable.
|
||||
function! ale#ant#FindExecutable(buffer) abort
|
||||
if executable('ant')
|
||||
return 'ant'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, build a command to print the classpath of the root
|
||||
" project. Returns an empty string if cannot build the command.
|
||||
function! ale#ant#BuildClasspathCommand(buffer) abort
|
||||
let l:executable = ale#ant#FindExecutable(a:buffer)
|
||||
let l:project_root = ale#ant#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:executable) && !empty(l:project_root)
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ . ' classpath'
|
||||
\ . ' -S'
|
||||
\ . ' -q'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
@@ -96,6 +96,13 @@ function! ale#assert#Fixer(expected_result) abort
|
||||
AssertEqual a:expected_result, l:result
|
||||
endfunction
|
||||
|
||||
function! ale#assert#FixerNotExecuted() abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1]
|
||||
|
||||
Assert empty(l:result), "The fixer will be executed when it shouldn't be"
|
||||
endfunction
|
||||
|
||||
function! ale#assert#LinterNotExecuted() abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:linter = s:GetLinter()
|
||||
@@ -158,6 +165,7 @@ endfunction
|
||||
function! ale#assert#SetUpFixerTestCommands() abort
|
||||
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
|
||||
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
|
||||
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
|
||||
endfunction
|
||||
|
||||
" A dummy function for making sure this module is loaded.
|
||||
@@ -316,4 +324,8 @@ function! ale#assert#TearDownFixerTest() abort
|
||||
if exists(':AssertFixer')
|
||||
delcommand AssertFixer
|
||||
endif
|
||||
|
||||
if exists(':AssertFixerNotExecuted')
|
||||
delcommand AssertFixerNotExecuted
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -23,104 +23,117 @@ function! ale#c#GetBuildDirectory(buffer) abort
|
||||
return l:build_dir
|
||||
endif
|
||||
|
||||
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
|
||||
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
|
||||
|
||||
return ale#path#Dirname(l:json_file)
|
||||
endfunction
|
||||
|
||||
|
||||
function! ale#c#FindProjectRoot(buffer) abort
|
||||
for l:project_filename in g:__ale_c_project_filenames
|
||||
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
|
||||
|
||||
if !empty(l:full_path)
|
||||
let l:path = fnamemodify(l:full_path, ':h')
|
||||
|
||||
" Correct .git path detection.
|
||||
if fnamemodify(l:path, ':t') is# '.git'
|
||||
let l:path = fnamemodify(l:path, ':h')
|
||||
endif
|
||||
|
||||
return l:path
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#c#AreSpecialCharsBalanced(option) abort
|
||||
" Escape \"
|
||||
let l:option_escaped = substitute(a:option, '\\"', '', 'g')
|
||||
|
||||
" Retain special chars only
|
||||
let l:special_chars = substitute(l:option_escaped, '[^"''()`]', '', 'g')
|
||||
let l:special_chars = split(l:special_chars, '\zs')
|
||||
|
||||
" Check if they are balanced
|
||||
function! ale#c#ShellSplit(line) abort
|
||||
let l:stack = []
|
||||
let l:args = ['']
|
||||
let l:prev = ''
|
||||
|
||||
for l:char in l:special_chars
|
||||
if l:char is# ')'
|
||||
if len(l:stack) == 0 || get(l:stack, -1) isnot# '('
|
||||
return 0
|
||||
endif
|
||||
|
||||
call remove(l:stack, -1)
|
||||
elseif l:char is# '('
|
||||
call add(l:stack, l:char)
|
||||
else
|
||||
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
|
||||
for l:char in split(a:line, '\zs')
|
||||
if l:char is# ''''
|
||||
if len(l:stack) > 0 && get(l:stack, -1) is# ''''
|
||||
call remove(l:stack, -1)
|
||||
else
|
||||
elseif (len(l:stack) == 0 || get(l:stack, -1) isnot# '"') && l:prev isnot# '\'
|
||||
call add(l:stack, l:char)
|
||||
endif
|
||||
elseif (l:char is# '"' || l:char is# '`') && l:prev isnot# '\'
|
||||
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
|
||||
call remove(l:stack, -1)
|
||||
elseif len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
|
||||
call add(l:stack, l:char)
|
||||
endif
|
||||
elseif (l:char is# '(' || l:char is# '[' || l:char is# '{') && l:prev isnot# '\'
|
||||
if len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
|
||||
call add(l:stack, l:char)
|
||||
endif
|
||||
elseif (l:char is# ')' || l:char is# ']' || l:char is# '}') && l:prev isnot# '\'
|
||||
if len(l:stack) > 0 && get(l:stack, -1) is# {')': '(', ']': '[', '}': '{'}[l:char]
|
||||
call remove(l:stack, -1)
|
||||
endif
|
||||
elseif l:char is# ' ' && len(l:stack) == 0
|
||||
if len(get(l:args, -1)) > 0
|
||||
call add(l:args, '')
|
||||
endif
|
||||
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:args[-1] = get(l:args, -1) . l:char
|
||||
endfor
|
||||
|
||||
return len(l:stack) == 0
|
||||
return l:args
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
|
||||
let l:split_lines = split(a:cflag_line)
|
||||
let l:cflags_list = []
|
||||
|
||||
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
|
||||
let l:option_index = 0
|
||||
|
||||
while l:option_index < len(l:split_lines)
|
||||
let l:next_option_index = l:option_index + 1
|
||||
|
||||
" Join space-separated option
|
||||
while l:next_option_index < len(l:split_lines)
|
||||
\&& stridx(l:split_lines[l:next_option_index], '-') != 0
|
||||
let l:next_option_index += 1
|
||||
endwhile
|
||||
|
||||
let l:option = join(l:split_lines[l:option_index : l:next_option_index-1], ' ')
|
||||
call remove(l:split_lines, l:option_index, l:next_option_index-1)
|
||||
call insert(l:split_lines, l:option, l:option_index)
|
||||
|
||||
" Ignore invalid or conflicting options
|
||||
if stridx(l:option, '-') != 0
|
||||
\|| stridx(l:option, '-o') == 0
|
||||
\|| stridx(l:option, '-c') == 0
|
||||
call remove(l:split_lines, l:option_index)
|
||||
let l:option_index = l:option_index - 1
|
||||
" Fix relative path
|
||||
elseif stridx(l:option, '-I') == 0
|
||||
if !(stridx(l:option, ':') == 2+1 || stridx(l:option, '/') == 2+0)
|
||||
let l:option = '-I' . a:path_prefix . s:sep . l:option[2:]
|
||||
call remove(l:split_lines, l:option_index)
|
||||
call insert(l:split_lines, l:option, l:option_index)
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:option = l:split_lines[l:option_index]
|
||||
let l:option_index = l:option_index + 1
|
||||
|
||||
" Include options, that may need relative path fix
|
||||
if stridx(l:option, '-I') == 0
|
||||
\ || stridx(l:option, '-iquote') == 0
|
||||
\ || stridx(l:option, '-isystem') == 0
|
||||
\ || stridx(l:option, '-idirafter') == 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:option_index = l:option_index + 1
|
||||
endif
|
||||
|
||||
" Fix relative paths if needed
|
||||
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0
|
||||
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)
|
||||
endif
|
||||
|
||||
call add(l:cflags_list, l:option)
|
||||
call add(l:cflags_list, 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])
|
||||
let l:option_index = l:option_index + 1
|
||||
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])
|
||||
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, '-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)
|
||||
endif
|
||||
endwhile
|
||||
|
||||
call uniq(l:split_lines)
|
||||
|
||||
return join(l:split_lines, ' ')
|
||||
return join(l:cflags_list, ' ')
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
|
||||
if !g:ale_c_parse_makefile
|
||||
return ''
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:buffer_filename = expand('#' . a:buffer . ':t')
|
||||
@@ -140,14 +153,17 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
|
||||
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, find the build subdirectory with compile commands
|
||||
" The subdirectory is returned without the trailing /
|
||||
" Given a buffer number, find the project directory containing
|
||||
" compile_commands.json, and the path to the compile_commands.json file.
|
||||
"
|
||||
" If compile_commands.json cannot be found, two empty strings will be
|
||||
" returned.
|
||||
function! ale#c#FindCompileCommands(buffer) abort
|
||||
" Look above the current source file to find compile_commands.json
|
||||
let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
|
||||
|
||||
if !empty(l:json_file)
|
||||
return l:json_file
|
||||
return [fnamemodify(l:json_file, ':h'), l:json_file]
|
||||
endif
|
||||
|
||||
" Search in build directories if we can't find it in the project.
|
||||
@@ -157,12 +173,42 @@ function! ale#c#FindCompileCommands(buffer) abort
|
||||
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
|
||||
|
||||
if filereadable(l:json_file)
|
||||
return l:json_file
|
||||
return [l:path, l:json_file]
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return ''
|
||||
return ['', '']
|
||||
endfunction
|
||||
|
||||
" Find the project root for C/C++ projects.
|
||||
"
|
||||
" The location of compile_commands.json will be used to find project roots.
|
||||
"
|
||||
" If compile_commands.json cannot be found, other common configuration files
|
||||
" will be used to detect the project root.
|
||||
function! ale#c#FindProjectRoot(buffer) abort
|
||||
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
|
||||
|
||||
" Fall back on detecting the project root based on other filenames.
|
||||
if empty(l:root)
|
||||
for l:project_filename in g:__ale_c_project_filenames
|
||||
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
|
||||
|
||||
if !empty(l:full_path)
|
||||
let l:path = fnamemodify(l:full_path, ':h')
|
||||
|
||||
" Correct .git path detection.
|
||||
if fnamemodify(l:path, ':t') is# '.git'
|
||||
let l:path = fnamemodify(l:path, ':h')
|
||||
endif
|
||||
|
||||
return l:path
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:root
|
||||
endfunction
|
||||
|
||||
" Cache compile_commands.json data in a Dictionary, so we don't need to read
|
||||
@@ -194,10 +240,14 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
|
||||
let l:raw_data = []
|
||||
silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), ''))
|
||||
|
||||
if type(l:raw_data) isnot v:t_list
|
||||
let l:raw_data = []
|
||||
endif
|
||||
|
||||
let l:file_lookup = {}
|
||||
let l:dir_lookup = {}
|
||||
|
||||
for l:entry in l:raw_data
|
||||
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
|
||||
let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
|
||||
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
|
||||
|
||||
@@ -215,14 +265,46 @@ 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, ' ')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
|
||||
" 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, [])
|
||||
" 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
|
||||
let l:file_list = get(a:file_lookup, l:key, [])
|
||||
|
||||
if !empty(l:file_list)
|
||||
let l:source_file = l:key
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
for l:item in l:file_list
|
||||
if bufnr(l:item.file) is a:buffer && has_key(l:item, 'command')
|
||||
return ale#c#ParseCFlags(l:item.directory, l:item.command)
|
||||
" Load the flags for this file, or for a source file matching the
|
||||
" header file.
|
||||
if (
|
||||
\ bufnr(l:item.file) is a:buffer
|
||||
\ || (
|
||||
\ !empty(l:source_file)
|
||||
\ && l:item.file[-len(l:source_file):] is? l:source_file
|
||||
\ )
|
||||
\)
|
||||
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -234,8 +316,7 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
|
||||
|
||||
for l:item in l:dir_list
|
||||
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
|
||||
\&& has_key(l:item, 'command')
|
||||
return ale#c#ParseCFlags(l:item.directory, l:item.command)
|
||||
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -251,25 +332,25 @@ function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
|
||||
endfunction
|
||||
|
||||
function! ale#c#GetCFlags(buffer, output) abort
|
||||
let l:cflags = ' '
|
||||
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:json_file = ale#c#FindCompileCommands(a:buffer)
|
||||
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
|
||||
|
||||
if !empty(l:json_file)
|
||||
let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
|
||||
endif
|
||||
endif
|
||||
|
||||
if l:cflags is# ' '
|
||||
if l:cflags is v:null
|
||||
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
|
||||
endif
|
||||
|
||||
return l:cflags
|
||||
return l:cflags isnot v:null ? l:cflags : ''
|
||||
endfunction
|
||||
|
||||
function! ale#c#GetMakeCommand(buffer) abort
|
||||
|
||||
163
autoload/ale/code_action.vim
Normal file
163
autoload/ale/code_action.vim
Normal file
@@ -0,0 +1,163 @@
|
||||
" Author: Jerko Steiner <jerko.steiner@gmail.com>
|
||||
" Description: Code action support for LSP / tsserver
|
||||
|
||||
function! ale#code_action#HandleCodeAction(code_action) abort
|
||||
let l:current_buffer = bufnr('')
|
||||
let l:changes = a:code_action.changes
|
||||
|
||||
for l:file_code_edit in l:changes
|
||||
let l:buf = bufnr(l:file_code_edit.fileName)
|
||||
|
||||
if l:buf != -1 && l:buf != l:current_buffer && getbufvar(l:buf, '&mod')
|
||||
call ale#util#Execute('echom ''Aborting action, file is unsaved''')
|
||||
|
||||
return
|
||||
endif
|
||||
endfor
|
||||
|
||||
for l:file_code_edit in l:changes
|
||||
call ale#code_action#ApplyChanges(
|
||||
\ l:file_code_edit.fileName, l:file_code_edit.textChanges)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#ApplyChanges(filename, changes) abort
|
||||
let l:current_buffer = bufnr('')
|
||||
" The buffer is used to determine the fileformat, if available.
|
||||
let l:buffer = bufnr(a:filename)
|
||||
let l:is_current_buffer = l:buffer > 0 && l:buffer == l:current_buffer
|
||||
|
||||
if l:buffer > 0
|
||||
let l:lines = getbufline(l:buffer, 1, '$')
|
||||
else
|
||||
let l:lines = readfile(a:filename, 'b')
|
||||
endif
|
||||
|
||||
if l:is_current_buffer
|
||||
let l:pos = getpos('.')[1:2]
|
||||
else
|
||||
let l:pos = [1, 1]
|
||||
endif
|
||||
|
||||
" We have to keep track of how many lines we have added, and offset
|
||||
" changes accordingly.
|
||||
let l:line_offset = 0
|
||||
let l:column_offset = 0
|
||||
let l:last_end_line = 0
|
||||
|
||||
for l:code_edit in a:changes
|
||||
if l:code_edit.start.line isnot l:last_end_line
|
||||
let l:column_offset = 0
|
||||
endif
|
||||
|
||||
let l:line = l:code_edit.start.line + l:line_offset
|
||||
let l:column = l:code_edit.start.offset + l:column_offset
|
||||
let l:end_line = l:code_edit.end.line + l:line_offset
|
||||
let l:end_column = l:code_edit.end.offset + l:column_offset
|
||||
let l:text = l:code_edit.newText
|
||||
|
||||
let l:cur_line = l:pos[0]
|
||||
let l:cur_column = l:pos[1]
|
||||
|
||||
let l:last_end_line = l:end_line
|
||||
|
||||
" Adjust the ends according to previous edits.
|
||||
if l:end_line > len(l:lines)
|
||||
let l:end_line_len = 0
|
||||
else
|
||||
let l:end_line_len = len(l:lines[l:end_line - 1])
|
||||
endif
|
||||
|
||||
let l:insertions = split(l:text, '\n', 1)
|
||||
|
||||
if l:line is 1
|
||||
" Same logic as for column below. Vimscript's slice [:-1] will not
|
||||
" be an empty list.
|
||||
let l:start = []
|
||||
else
|
||||
let l:start = l:lines[: l:line - 2]
|
||||
endif
|
||||
|
||||
if l:column is 1
|
||||
" We need to handle column 1 specially, because we can't slice an
|
||||
" empty string ending on index 0.
|
||||
let l:middle = [l:insertions[0]]
|
||||
else
|
||||
let l:middle = [l:lines[l:line - 1][: l:column - 2] . l:insertions[0]]
|
||||
endif
|
||||
|
||||
call extend(l:middle, l:insertions[1:])
|
||||
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
|
||||
|
||||
let l:lines_before_change = len(l:lines)
|
||||
let l:lines = l:start + l:middle + l:lines[l:end_line :]
|
||||
|
||||
let l:current_line_offset = len(l:lines) - l:lines_before_change
|
||||
let l:line_offset += l:current_line_offset
|
||||
let l:column_offset = len(l:middle[-1]) - l:end_line_len
|
||||
|
||||
let l:pos = s:UpdateCursor(l:pos,
|
||||
\ [l:line, l:column],
|
||||
\ [l:end_line, l:end_column],
|
||||
\ [l:current_line_offset, l:column_offset])
|
||||
endfor
|
||||
|
||||
if l:lines[-1] is# ''
|
||||
call remove(l:lines, -1)
|
||||
endif
|
||||
|
||||
call ale#util#Writefile(l:buffer, l:lines, a:filename)
|
||||
|
||||
if l:is_current_buffer
|
||||
call ale#util#Execute(':e!')
|
||||
call setpos('.', [0, l:pos[0], l:pos[1], 0])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:UpdateCursor(cursor, start, end, offset) abort
|
||||
let l:cur_line = a:cursor[0]
|
||||
let l:cur_column = a:cursor[1]
|
||||
let l:line = a:start[0]
|
||||
let l:column = a:start[1]
|
||||
let l:end_line = a:end[0]
|
||||
let l:end_column = a:end[1]
|
||||
let l:line_offset = a:offset[0]
|
||||
let l:column_offset = a:offset[1]
|
||||
|
||||
if l:end_line < l:cur_line
|
||||
" both start and end lines are before the cursor. only line offset
|
||||
" needs to be updated
|
||||
let l:cur_line += l:line_offset
|
||||
elseif l:end_line == l:cur_line
|
||||
" end line is at the same location as cursor, which means
|
||||
" l:line <= l:cur_line
|
||||
if l:line < l:cur_line || l:column <= l:cur_column
|
||||
" updates are happening either before or around the cursor
|
||||
if l:end_column < l:cur_column
|
||||
" updates are happening before the cursor, update the
|
||||
" column offset for cursor
|
||||
let l:cur_line += l:line_offset
|
||||
let l:cur_column += l:column_offset
|
||||
else
|
||||
" updates are happening around the cursor, move the cursor
|
||||
" to the end of the changes
|
||||
let l:cur_line += l:line_offset
|
||||
let l:cur_column = l:end_column + l:column_offset
|
||||
endif
|
||||
" else is not necessary, it means modifications are happening
|
||||
" after the cursor so no cursor updates need to be done
|
||||
endif
|
||||
else
|
||||
" end line is after the cursor
|
||||
if l:line < l:cur_line || l:line == l:cur_line && l:column <= l:cur_column
|
||||
" changes are happening around the cursor, move the cursor
|
||||
" to the end of the changes
|
||||
let l:cur_line = l:end_line + l:line_offset
|
||||
let l:cur_column = l:end_column + l:column_offset
|
||||
" else is not necesary, it means modifications are happening
|
||||
" after the cursor so no cursor updates need to be done
|
||||
endif
|
||||
endif
|
||||
|
||||
return [l:cur_line, l:cur_column]
|
||||
endfunction
|
||||
@@ -15,6 +15,7 @@ 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 s:timer_id = -1
|
||||
let s:last_done_pos = []
|
||||
@@ -52,6 +53,7 @@ let s:should_complete_map = {
|
||||
\ 'lisp': s:lisp_regex,
|
||||
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$',
|
||||
\ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$',
|
||||
\ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$',
|
||||
\}
|
||||
|
||||
" Regular expressions for finding the start column to replace with completion.
|
||||
@@ -59,11 +61,13 @@ let s:omni_start_map = {
|
||||
\ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
|
||||
\}
|
||||
|
||||
" A map of exact characters for triggering LSP completions.
|
||||
" A map of exact characters for triggering LSP completions. Do not forget to
|
||||
" update self.input_patterns in ale.py in updating entries in this map.
|
||||
let s:trigger_character_map = {
|
||||
\ '<default>': ['.'],
|
||||
\ 'typescript': ['.', '''', '"'],
|
||||
\ 'rust': ['.', '::'],
|
||||
\ 'cpp': ['.', '::', '->'],
|
||||
\}
|
||||
|
||||
function! s:GetFiletypeValue(map, filetype) abort
|
||||
@@ -159,18 +163,20 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
|
||||
endfunction
|
||||
|
||||
function! s:ReplaceCompletionOptions() 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
|
||||
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'
|
||||
endif
|
||||
|
||||
let &l:omnifunc = 'ale#completion#OmniFunc'
|
||||
|
||||
let l:info = get(b:, 'ale_completion_info', {})
|
||||
|
||||
if !get(l:info, 'manual')
|
||||
if l:source is# 'ale-automatic'
|
||||
if !exists('b:ale_old_completeopt')
|
||||
let b:ale_old_completeopt = &l:completeopt
|
||||
endif
|
||||
@@ -199,47 +205,77 @@ function! ale#completion#RestoreCompletionOptions() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#OmniFunc(findstart, base) abort
|
||||
function! ale#completion#GetCompletionPosition() abort
|
||||
if !exists('b:ale_completion_info')
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:line = b:ale_completion_info.line
|
||||
let l:column = b:ale_completion_info.column
|
||||
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
|
||||
let l:up_to_column = getline(l:line)[: l:column - 2]
|
||||
let l:match = matchstr(l:up_to_column, l:regex)
|
||||
|
||||
return l:column - len(l:match) - 1
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetCompletionPositionForDeoplete(input) abort
|
||||
return match(a:input, '\k*$')
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetCompletionResult() abort
|
||||
if exists('b:ale_completion_result')
|
||||
return b:ale_completion_result
|
||||
endif
|
||||
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
function! ale#completion#AutomaticOmniFunc(findstart, base) abort
|
||||
if a:findstart
|
||||
let l:line = b:ale_completion_info.line
|
||||
let l:column = b:ale_completion_info.column
|
||||
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
|
||||
let l:up_to_column = getline(l:line)[: l:column - 2]
|
||||
let l:match = matchstr(l:up_to_column, l:regex)
|
||||
|
||||
return l:column - len(l:match) - 1
|
||||
return ale#completion#GetCompletionPosition()
|
||||
else
|
||||
" Parse a new response if there is one.
|
||||
if exists('b:ale_completion_response')
|
||||
\&& exists('b:ale_completion_parser')
|
||||
let l:response = b:ale_completion_response
|
||||
let l:parser = b:ale_completion_parser
|
||||
|
||||
unlet b:ale_completion_response
|
||||
unlet b:ale_completion_parser
|
||||
|
||||
let b:ale_completion_result = function(l:parser)(l:response)
|
||||
endif
|
||||
let l:result = ale#completion#GetCompletionResult()
|
||||
|
||||
call s:ReplaceCompletionOptions()
|
||||
|
||||
return get(b:, 'ale_completion_result', [])
|
||||
return l:result isnot v:null ? l:result : []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Show(response, completion_parser) abort
|
||||
function! ale#completion#Show(result) abort
|
||||
if ale#util#Mode() isnot# 'i'
|
||||
return
|
||||
endif
|
||||
|
||||
" Set the list in the buffer, temporarily replace omnifunc with our
|
||||
" function, and then start omni-completion.
|
||||
let b:ale_completion_response = a:response
|
||||
let b:ale_completion_parser = a:completion_parser
|
||||
let 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)
|
||||
return
|
||||
endif
|
||||
|
||||
" Replace completion options shortly before opening the menu.
|
||||
call s:ReplaceCompletionOptions()
|
||||
|
||||
call timer_start(0, {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")})
|
||||
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)")}
|
||||
\)
|
||||
endif
|
||||
|
||||
if l:source is# 'ale-callback'
|
||||
call b:CompleteCallback(b:ale_completion_result)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#completion#GetAllTriggers() abort
|
||||
return deepcopy(s:trigger_character_map)
|
||||
endfunction
|
||||
|
||||
function! s:CompletionStillValid(request_id) abort
|
||||
@@ -249,14 +285,22 @@ function! s:CompletionStillValid(request_id) abort
|
||||
\&& has_key(b:, 'ale_completion_info')
|
||||
\&& b:ale_completion_info.request_id == a:request_id
|
||||
\&& b:ale_completion_info.line == l:line
|
||||
\&& b:ale_completion_info.column == l:column
|
||||
\&& (
|
||||
\ 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'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale#completion#ParseTSServerCompletions(response) abort
|
||||
let l:names = []
|
||||
|
||||
for l:suggestion in a:response.body
|
||||
call add(l:names, l:suggestion.name)
|
||||
call add(l:names, {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'source': get(l:suggestion, 'source', ''),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:names
|
||||
@@ -270,6 +314,10 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
for l:suggestion in a:response.body
|
||||
let l:displayParts = []
|
||||
|
||||
for l:action in get(l:suggestion, 'codeActions', [])
|
||||
call add(l:displayParts, l:action.description . ' ')
|
||||
endfor
|
||||
|
||||
for l:part in l:suggestion.displayParts
|
||||
call add(l:displayParts, l:part.text)
|
||||
endfor
|
||||
@@ -290,13 +338,22 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
endif
|
||||
|
||||
" See :help complete-items
|
||||
call add(l:results, {
|
||||
let l:result = {
|
||||
\ 'word': l:suggestion.name,
|
||||
\ 'kind': l:kind,
|
||||
\ 'icase': 1,
|
||||
\ 'menu': join(l:displayParts, ''),
|
||||
\ 'dup': g:ale_completion_tsserver_autoimport,
|
||||
\ 'info': join(l:documentationParts, ''),
|
||||
\})
|
||||
\}
|
||||
|
||||
if has_key(l:suggestion, 'codeActions')
|
||||
let l:result.user_data = json_encode({
|
||||
\ 'codeActions': l:suggestion.codeActions,
|
||||
\ })
|
||||
endif
|
||||
|
||||
call add(l:results, l:result)
|
||||
endfor
|
||||
|
||||
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
|
||||
@@ -305,12 +362,12 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||
let l:names_with_details = map(copy(l:results), 'v:val.word')
|
||||
let l:missing_names = filter(
|
||||
\ copy(l:names),
|
||||
\ 'index(l:names_with_details, v:val) < 0',
|
||||
\ 'index(l:names_with_details, v:val.word) < 0',
|
||||
\)
|
||||
|
||||
for l:name in l:missing_names
|
||||
call add(l:results, {
|
||||
\ 'word': l:name,
|
||||
\ 'word': l:name.word,
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'menu': '',
|
||||
@@ -356,6 +413,8 @@ function! ale#completion#ParseLSPCompletions(response) abort
|
||||
if get(l:item, 'insertTextFormat') is s:LSP_INSERT_TEXT_FORMAT_PLAIN
|
||||
\&& type(get(l:item, 'textEdit')) is v:t_dict
|
||||
let l:text = l:item.textEdit.newText
|
||||
elseif type(get(l:item, 'insertText')) is v:t_string
|
||||
let l:text = l:item.insertText
|
||||
else
|
||||
let l:text = l:item.label
|
||||
endif
|
||||
@@ -430,20 +489,28 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
|
||||
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
|
||||
|
||||
if !empty(l:names)
|
||||
let l:identifiers = []
|
||||
|
||||
for l:name in l:names
|
||||
call add(l:identifiers, {
|
||||
\ 'name': l:name.word,
|
||||
\ 'source': get(l:name, 'source', ''),
|
||||
\})
|
||||
endfor
|
||||
|
||||
let b:ale_completion_info.request_id = ale#lsp#Send(
|
||||
\ b:ale_completion_info.conn_id,
|
||||
\ ale#lsp#tsserver_message#CompletionEntryDetails(
|
||||
\ l:buffer,
|
||||
\ b:ale_completion_info.line,
|
||||
\ b:ale_completion_info.column,
|
||||
\ l:names,
|
||||
\ l:identifiers,
|
||||
\ ),
|
||||
\)
|
||||
endif
|
||||
elseif l:command is# 'completionEntryDetails'
|
||||
call ale#completion#Show(
|
||||
\ a:response,
|
||||
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
|
||||
\ ale#completion#ParseTSServerCompletionEntryDetails(a:response),
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
@@ -455,8 +522,7 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
|
||||
endif
|
||||
|
||||
call ale#completion#Show(
|
||||
\ a:response,
|
||||
\ 'ale#completion#ParseLSPCompletions',
|
||||
\ ale#completion#ParseLSPCompletions(a:response),
|
||||
\)
|
||||
endfunction
|
||||
|
||||
@@ -485,6 +551,7 @@ function! s:OnReady(linter, lsp_details) abort
|
||||
\ b:ale_completion_info.line,
|
||||
\ b:ale_completion_info.column,
|
||||
\ b:ale_completion_info.prefix,
|
||||
\ g:ale_completion_tsserver_autoimport,
|
||||
\)
|
||||
else
|
||||
" Send a message saying the buffer has changed first, otherwise
|
||||
@@ -497,10 +564,7 @@ function! s:OnReady(linter, lsp_details) abort
|
||||
let l:message = ale#lsp#message#Completion(
|
||||
\ l:buffer,
|
||||
\ b:ale_completion_info.line,
|
||||
\ min([
|
||||
\ b:ale_completion_info.line_length,
|
||||
\ b:ale_completion_info.column,
|
||||
\ ]) + 1,
|
||||
\ b:ale_completion_info.column,
|
||||
\ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
|
||||
\)
|
||||
endif
|
||||
@@ -517,15 +581,41 @@ function! s:OnReady(linter, lsp_details) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" This function can be called to check if ALE can provide completion data for
|
||||
" the current buffer. 1 will be returned if there's a potential source of
|
||||
" completion data ALE can use, and 0 will be returned otherwise.
|
||||
function! ale#completion#CanProvideCompletions() abort
|
||||
for l:linter in ale#linter#Get(&filetype)
|
||||
if !empty(l:linter.lsp)
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" This function can be used to manually trigger autocomplete, even when
|
||||
" g:ale_completion_enabled is set to false
|
||||
function! ale#completion#GetCompletions(manual) abort
|
||||
function! ale#completion#GetCompletions(...) abort
|
||||
let l:source = get(a:000, 0, '')
|
||||
let l:options = get(a:000, 1, {})
|
||||
|
||||
if len(a:000) > 2
|
||||
throw 'Too many arguments!'
|
||||
endif
|
||||
|
||||
let l:CompleteCallback = get(l:options, 'callback', v:null)
|
||||
|
||||
if l:CompleteCallback isnot v:null
|
||||
let b:CompleteCallback = l:CompleteCallback
|
||||
endif
|
||||
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
|
||||
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
|
||||
|
||||
if !a:manual && empty(l:prefix)
|
||||
return
|
||||
if l:source is# 'ale-automatic' && empty(l:prefix)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:line_length = len(getline('.'))
|
||||
@@ -537,21 +627,51 @@ function! ale#completion#GetCompletions(manual) abort
|
||||
\ 'prefix': l:prefix,
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\ 'manual': a:manual,
|
||||
\ 'source': l:source,
|
||||
\}
|
||||
unlet! b:ale_completion_result
|
||||
|
||||
let l:buffer = bufnr('')
|
||||
let l:Callback = function('s:OnReady')
|
||||
|
||||
let l:started = 0
|
||||
|
||||
for l:linter in ale#linter#Get(&filetype)
|
||||
if !empty(l:linter.lsp)
|
||||
call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
|
||||
if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
|
||||
let l:started = 1
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:started
|
||||
endfunction
|
||||
|
||||
function! ale#completion#OmniFunc(findstart, base) abort
|
||||
if a:findstart
|
||||
let l:started = ale#completion#GetCompletions('ale-omnifunc')
|
||||
|
||||
if !l:started
|
||||
" This is the special value for cancelling completions silently.
|
||||
" See :help complete-functions
|
||||
return -3
|
||||
endif
|
||||
|
||||
return ale#completion#GetCompletionPosition()
|
||||
else
|
||||
let l:result = ale#completion#GetCompletionResult()
|
||||
|
||||
while l:result is v:null && !complete_check()
|
||||
sleep 2ms
|
||||
let l:result = ale#completion#GetCompletionResult()
|
||||
endwhile
|
||||
|
||||
return l:result isnot v:null ? l:result : []
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:TimerHandler(...) abort
|
||||
if !g:ale_completion_enabled
|
||||
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -562,7 +682,7 @@ function! s:TimerHandler(...) abort
|
||||
" When running the timer callback, we have to be sure that the cursor
|
||||
" hasn't moved from where it was when we requested completions by typing.
|
||||
if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i'
|
||||
call ale#completion#GetCompletions(0)
|
||||
call ale#completion#GetCompletions('ale-automatic')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@@ -576,7 +696,7 @@ function! ale#completion#StopTimer() abort
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Queue() abort
|
||||
if !g:ale_completion_enabled
|
||||
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -599,6 +719,30 @@ function! ale#completion#Queue() abort
|
||||
let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler'))
|
||||
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)
|
||||
|
||||
if type(l:user_data) isnot v:t_dict
|
||||
return
|
||||
endif
|
||||
|
||||
for l:code_action in get(l:user_data, 'codeActions', [])
|
||||
call ale#code_action#HandleCodeAction(l:code_action)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! ale#completion#Done() abort
|
||||
silent! pclose
|
||||
|
||||
@@ -607,6 +751,10 @@ function! ale#completion#Done() abort
|
||||
let s:last_done_pos = getpos('.')[1:2]
|
||||
endfunction
|
||||
|
||||
augroup ALECompletionActions
|
||||
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
|
||||
augroup END
|
||||
|
||||
function! s:Setup(enabled) abort
|
||||
augroup ALECompletionGroup
|
||||
autocmd!
|
||||
|
||||
@@ -25,7 +25,7 @@ function! ale#cursor#TruncatedEcho(original_message) abort
|
||||
let l:cursor_position = getpos('.')
|
||||
|
||||
" The message is truncated and saved to the history.
|
||||
setlocal shortmess+=T
|
||||
silent! setlocal shortmess+=T
|
||||
|
||||
try
|
||||
exec "norm! :echomsg l:message\n"
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
" Author: Auri <me@aurieh.me>
|
||||
" Description: Functions for integrating with D linters.
|
||||
|
||||
function! otherproject#util#Double(x) abort
|
||||
return a:x * 2
|
||||
endfunction
|
||||
|
||||
function! ale#d#FindDUBConfig(buffer) abort
|
||||
" Find a DUB configuration file in ancestor paths.
|
||||
" The most DUB-specific names will be tried first.
|
||||
|
||||
@@ -50,6 +50,7 @@ let s:global_variable_list = [
|
||||
\ 'ale_sign_style_error',
|
||||
\ 'ale_sign_style_warning',
|
||||
\ 'ale_sign_warning',
|
||||
\ 'ale_sign_highlight_linenrs',
|
||||
\ 'ale_statusline_format',
|
||||
\ 'ale_type_map',
|
||||
\ 'ale_use_global_executables',
|
||||
@@ -62,7 +63,7 @@ function! s:Echo(message) abort
|
||||
execute 'echo a:message'
|
||||
endfunction
|
||||
|
||||
function! s:GetLinterVariables(filetype, linter_names) abort
|
||||
function! s:GetLinterVariables(filetype, exclude_linter_names) abort
|
||||
let l:variable_list = []
|
||||
let l:filetype_parts = split(a:filetype, '\.')
|
||||
|
||||
@@ -73,7 +74,7 @@ function! s:GetLinterVariables(filetype, linter_names) abort
|
||||
" Include matching variables.
|
||||
if !empty(l:match)
|
||||
\&& index(l:filetype_parts, l:match[1]) >= 0
|
||||
\&& index(a:linter_names, l:match[2]) >= 0
|
||||
\&& index(a:exclude_linter_names, l:match[2]) == -1
|
||||
call add(l:variable_list, l:key)
|
||||
endif
|
||||
endfor
|
||||
@@ -211,10 +212,11 @@ function! ale#debugging#Info() abort
|
||||
|
||||
let l:all_names = map(copy(l:all_linters), 'v:val[''name'']')
|
||||
let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']')
|
||||
let l:exclude_names = filter(copy(l:all_names), 'index(l:enabled_names, v:val) == -1')
|
||||
|
||||
" Load linter variables to display
|
||||
" This must be done after linters are loaded.
|
||||
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
|
||||
let l:variable_list = s:GetLinterVariables(l:filetype, l:exclude_names)
|
||||
|
||||
let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype)
|
||||
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
|
||||
@@ -238,6 +240,12 @@ function! ale#debugging#Info() abort
|
||||
endfunction
|
||||
|
||||
function! ale#debugging#InfoToClipboard() abort
|
||||
if !has('clipboard')
|
||||
call s:Echo('clipboard not available. Try :ALEInfoToFile instead.')
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
redir => l:output
|
||||
silent call ale#debugging#Info()
|
||||
redir END
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
let s:go_to_definition_map = {}
|
||||
|
||||
" Enable automatic updates of the tagstack
|
||||
let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', 1)
|
||||
|
||||
" Used to get the definition map in tests.
|
||||
function! ale#definition#GetMap() abort
|
||||
return deepcopy(s:go_to_definition_map)
|
||||
@@ -17,6 +20,20 @@ function! ale#definition#ClearLSPData() abort
|
||||
let s:go_to_definition_map = {}
|
||||
endfunction
|
||||
|
||||
function! ale#definition#UpdateTagStack() abort
|
||||
let l:should_update_tagstack = exists('*gettagstack') && exists('*settagstack') && g:ale_update_tagstack
|
||||
|
||||
if l:should_update_tagstack
|
||||
" Grab the old location (to jump back to) and the word under the
|
||||
" cursor (as a label for the tagstack)
|
||||
let l:old_location = [bufnr('%'), line('.'), col('.'), 0]
|
||||
let l:tagname = expand('<cword>')
|
||||
let l:winid = win_getid()
|
||||
call settagstack(l:winid, {'items': [{'from': l:old_location, 'tagname': l:tagname}]}, 'a')
|
||||
call settagstack(l:winid, {'curidx': len(gettagstack(l:winid)['items']) + 1})
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#definition#HandleTSServerResponse(conn_id, response) abort
|
||||
if get(a:response, 'command', '') is# 'definition'
|
||||
\&& has_key(s:go_to_definition_map, a:response.request_seq)
|
||||
@@ -27,6 +44,7 @@ function! ale#definition#HandleTSServerResponse(conn_id, response) abort
|
||||
let l:line = a:response.body[0].start.line
|
||||
let l:column = a:response.body[0].start.offset
|
||||
|
||||
call ale#definition#UpdateTagStack()
|
||||
call ale#util#Open(l:filename, l:line, l:column, l:options)
|
||||
endif
|
||||
endif
|
||||
@@ -51,6 +69,7 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
|
||||
let l:line = l:item.range.start.line + 1
|
||||
let l:column = l:item.range.start.character + 1
|
||||
|
||||
call ale#definition#UpdateTagStack()
|
||||
call ale#util#Open(l:filename, l:line, l:column, l:options)
|
||||
break
|
||||
endfor
|
||||
|
||||
@@ -39,8 +39,8 @@ function! ale#engine#MarkLinterActive(info, linter) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#engine#MarkLinterInactive(info, linter) abort
|
||||
call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter.name')
|
||||
function! ale#engine#MarkLinterInactive(info, linter_name) abort
|
||||
call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter_name')
|
||||
endfunction
|
||||
|
||||
function! ale#engine#ResetExecutableCache() abort
|
||||
@@ -195,7 +195,7 @@ function! s:HandleExit(job_info, buffer, output, data) abort
|
||||
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)
|
||||
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
|
||||
|
||||
" Stop here if we land in the handle for a job completing if we're in
|
||||
" a sandbox.
|
||||
@@ -710,6 +710,10 @@ function! ale#engine#Cleanup(buffer) abort
|
||||
return
|
||||
endif
|
||||
|
||||
if exists('*ale#lsp#CloseDocument')
|
||||
call ale#lsp#CloseDocument(a:buffer)
|
||||
endif
|
||||
|
||||
if !has_key(g:ale_buffer_info, a:buffer)
|
||||
return
|
||||
endif
|
||||
|
||||
@@ -128,7 +128,7 @@ function! ale#events#Init() abort
|
||||
endif
|
||||
|
||||
if g:ale_lint_on_insert_leave
|
||||
autocmd InsertLeave * call ale#Queue(0)
|
||||
autocmd InsertLeave * if ale#Var(str2nr(expand('<abuf>')), 'lint_on_insert_leave') | call ale#Queue(0) | endif
|
||||
endif
|
||||
|
||||
if g:ale_echo_cursor || g:ale_cursor_detail
|
||||
|
||||
@@ -1,45 +1,61 @@
|
||||
call ale#Set('fix_on_save_ignore', {})
|
||||
|
||||
" Apply fixes queued up for buffers which may be hidden.
|
||||
" Vim doesn't let you modify hidden buffers.
|
||||
function! ale#fix#ApplyQueuedFixes() abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0})
|
||||
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
|
||||
if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr(''))
|
||||
return
|
||||
endif
|
||||
|
||||
call remove(g:ale_fix_buffer_data, l:buffer)
|
||||
call remove(g:ale_fix_buffer_data, a:buffer)
|
||||
|
||||
if l:data.changes_made
|
||||
let l:start_line = len(l:data.output) + 1
|
||||
let l:end_line = len(l:data.lines_before)
|
||||
|
||||
if l:end_line >= l:start_line
|
||||
let l:save = winsaveview()
|
||||
silent execute l:start_line . ',' . l:end_line . 'd_'
|
||||
call winrestview(l:save)
|
||||
endif
|
||||
|
||||
" 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:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos'
|
||||
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
|
||||
|
||||
call setline(1, l:lines_to_set)
|
||||
" 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 empty(&buftype)
|
||||
noautocmd :w!
|
||||
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
|
||||
endif
|
||||
endif
|
||||
|
||||
if l:data.should_save
|
||||
let l:should_lint = g:ale_fix_on_save
|
||||
let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
|
||||
\ && ale#Var(a:buffer, 'lint_on_save')
|
||||
else
|
||||
let l:should_lint = l:data.changes_made
|
||||
endif
|
||||
@@ -50,7 +66,7 @@ function! ale#fix#ApplyQueuedFixes() abort
|
||||
" fixing problems.
|
||||
if g:ale_enabled
|
||||
\&& l:should_lint
|
||||
\&& !ale#events#QuitRecently(l:buffer)
|
||||
\&& !ale#events#QuitRecently(a:buffer)
|
||||
call ale#Queue(0, l:data.should_save ? 'lint_file' : '')
|
||||
endif
|
||||
endfunction
|
||||
@@ -58,7 +74,7 @@ endfunction
|
||||
function! ale#fix#ApplyFixes(buffer, output) abort
|
||||
let l:data = g:ale_fix_buffer_data[a:buffer]
|
||||
let l:data.output = a:output
|
||||
let l:data.changes_made = l:data.lines_before != l:data.output
|
||||
let l:data.changes_made = l:data.lines_before !=# l:data.output " no-custom-checks
|
||||
let l:data.done = 1
|
||||
|
||||
call ale#command#RemoveManagedFiles(a:buffer)
|
||||
@@ -81,7 +97,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
|
||||
|
||||
" We can only change the lines of a buffer which is currently open,
|
||||
" so try and apply the fixes to the current buffer.
|
||||
call ale#fix#ApplyQueuedFixes()
|
||||
call ale#fix#ApplyQueuedFixes(a:buffer)
|
||||
endfunction
|
||||
|
||||
function! s:HandleExit(job_info, buffer, job_output, data) abort
|
||||
@@ -265,7 +281,21 @@ function! s:AddSubCallbacks(full_list, callbacks) abort
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:GetCallbacks(buffer, fixers) abort
|
||||
function! s:IgnoreFixers(callback_list, filetype, config) abort
|
||||
if type(a:config) is v:t_list
|
||||
let l:ignore_list = a:config
|
||||
else
|
||||
let l:ignore_list = []
|
||||
|
||||
for l:part in split(a:filetype , '\.')
|
||||
call extend(l:ignore_list, get(a:config, l:part, []))
|
||||
endfor
|
||||
endif
|
||||
|
||||
call filter(a:callback_list, 'index(l:ignore_list, v:val) < 0')
|
||||
endfunction
|
||||
|
||||
function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
|
||||
if len(a:fixers)
|
||||
let l:callback_list = a:fixers
|
||||
elseif type(get(b:, 'ale_fixers')) is v:t_list
|
||||
@@ -290,8 +320,12 @@ function! s:GetCallbacks(buffer, fixers) abort
|
||||
endif
|
||||
endif
|
||||
|
||||
if empty(l:callback_list)
|
||||
return []
|
||||
if a:fixing_flag is# 'save_file'
|
||||
let l:config = ale#Var(a:buffer, 'fix_on_save_ignore')
|
||||
|
||||
if !empty(l:config)
|
||||
call s:IgnoreFixers(l:callback_list, &filetype, l:config)
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:corrected_list = []
|
||||
@@ -339,7 +373,7 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort
|
||||
endif
|
||||
|
||||
try
|
||||
let l:callback_list = s:GetCallbacks(a:buffer, a:000)
|
||||
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(
|
||||
@@ -379,5 +413,4 @@ endfunction
|
||||
" Set up an autocmd command to try and apply buffer fixes when available.
|
||||
augroup ALEBufferFixGroup
|
||||
autocmd!
|
||||
autocmd BufEnter * call ale#fix#ApplyQueuedFixes()
|
||||
augroup END
|
||||
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user