mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 20:54:26 +08:00
Compare commits
322 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2702c6829 | ||
|
|
388cf33743 | ||
|
|
77c034884b | ||
|
|
8beb67b4d1 | ||
|
|
99eb68e6ca | ||
|
|
f9f2ad2765 | ||
|
|
b88d3c4e4b | ||
|
|
cf53eb3667 | ||
|
|
27130efc65 | ||
|
|
ae916d49fd | ||
|
|
787ab2a366 | ||
|
|
f612805801 | ||
|
|
4c7e843fd0 | ||
|
|
26b92f73b5 | ||
|
|
cc67bc0541 | ||
|
|
98caa19cc7 | ||
|
|
9b5c090473 | ||
|
|
c747c277c2 | ||
|
|
1457e54528 | ||
|
|
e8080be08b | ||
|
|
4894c760c2 | ||
|
|
7572ec3489 | ||
|
|
e5e851fadc | ||
|
|
2d07fa0cc2 | ||
|
|
dd1c665db2 | ||
|
|
d511d5af11 | ||
|
|
7c44f4e403 | ||
|
|
64d430438e | ||
|
|
82c8e3a3a3 | ||
|
|
bafe1c0fd6 | ||
|
|
c9f4005820 | ||
|
|
cab4280d02 | ||
|
|
3a1728297a | ||
|
|
72dbd7f648 | ||
|
|
471e20ed2b | ||
|
|
65bfb07e43 | ||
|
|
18eb6a0758 | ||
|
|
580271b510 | ||
|
|
105bc55695 | ||
|
|
0ac7595fe9 | ||
|
|
bacb8bb902 | ||
|
|
2c1c5b06d9 | ||
|
|
10d2b8797c | ||
|
|
9fd9435cd5 | ||
|
|
1101346657 | ||
|
|
c1b6628425 | ||
|
|
3e94c42ec0 | ||
|
|
a6dfc611f6 | ||
|
|
3c3dcd4041 | ||
|
|
66b3e768db | ||
|
|
997dd7f8fe | ||
|
|
5a47d878fb | ||
|
|
c374736301 | ||
|
|
5200e6c734 | ||
|
|
fe666a7a6c | ||
|
|
e16c3b09f7 | ||
|
|
9b362634f7 | ||
|
|
4f2666265a | ||
|
|
d7ed80346c | ||
|
|
56951932e0 | ||
|
|
4999ae2e85 | ||
|
|
4f8f2a4a0c | ||
|
|
542ba5a04a | ||
|
|
df91bc9046 | ||
|
|
32c0eb7c42 | ||
|
|
99a809c814 | ||
|
|
33f2f8ddcd | ||
|
|
1ca780a08a | ||
|
|
1b010bbabb | ||
|
|
985a5295a9 | ||
|
|
efe65f3477 | ||
|
|
a8acac1f4a | ||
|
|
850c41b2a9 | ||
|
|
847f729cd4 | ||
|
|
075c3e0ad0 | ||
|
|
35b8bb8a55 | ||
|
|
53ff5f2d88 | ||
|
|
9a1e91e075 | ||
|
|
64550062dc | ||
|
|
451e99341e | ||
|
|
03bd494fd4 | ||
|
|
5fd5fa5305 | ||
|
|
4edfac4db6 | ||
|
|
23ff19a162 | ||
|
|
1991313ee7 | ||
|
|
f17beadb49 | ||
|
|
8ffde14039 | ||
|
|
e75ac9f497 | ||
|
|
289f808ccd | ||
|
|
4a6136c27e | ||
|
|
6bfcb9cdff | ||
|
|
6b0b8cec79 | ||
|
|
897f6b2b23 | ||
|
|
db816b5c3f | ||
|
|
33485ffb92 | ||
|
|
8d5b3e827d | ||
|
|
e3e1ddce95 | ||
|
|
4328fe7dca | ||
|
|
04550717bf | ||
|
|
2dbf4ee271 | ||
|
|
67c3fa9001 | ||
|
|
ed2afafd62 | ||
|
|
823b094f56 | ||
|
|
89403b4a06 | ||
|
|
280d2dedae | ||
|
|
c15d9538cd | ||
|
|
b3010ad793 | ||
|
|
9eb6dace88 | ||
|
|
e94d23b1d9 | ||
|
|
7f1dd5f66a | ||
|
|
3e820207e7 | ||
|
|
4ed520a219 | ||
|
|
9bc4b468c2 | ||
|
|
65824feef3 | ||
|
|
4aa11cbc05 | ||
|
|
014b00d4d7 | ||
|
|
03eae9e085 | ||
|
|
27a22e7161 | ||
|
|
7fe61cdf0e | ||
|
|
a1e6df987c | ||
|
|
42bf5ca911 | ||
|
|
80a0108fcf | ||
|
|
6a3d215571 | ||
|
|
7e3d2930d8 | ||
|
|
7b42dd7387 | ||
|
|
16c45b8213 | ||
|
|
8de0e7b9ba | ||
|
|
783cf4ab82 | ||
|
|
bfc412a77b | ||
|
|
9387ccfbc5 | ||
|
|
bbac230008 | ||
|
|
45a28383a2 | ||
|
|
6fbdec8587 | ||
|
|
8dce126a6c | ||
|
|
f398faa8d3 | ||
|
|
39f393ef07 | ||
|
|
97ce2423b0 | ||
|
|
7b187af10a | ||
|
|
aabca5b0ac | ||
|
|
012348582c | ||
|
|
12d28ca34f | ||
|
|
49f8aa4703 | ||
|
|
7b1ed2733e | ||
|
|
54dd731cf1 | ||
|
|
4c454c96a9 | ||
|
|
7e4c125d38 | ||
|
|
8c34c738ab | ||
|
|
b4d889b682 | ||
|
|
3229d5aba4 | ||
|
|
6b97af680d | ||
|
|
3fca5e73b6 | ||
|
|
7fca451cf9 | ||
|
|
8375ee2766 | ||
|
|
02255dd967 | ||
|
|
9c7e1fe4dd | ||
|
|
8af805cefe | ||
|
|
e358afdd9b | ||
|
|
f996ede599 | ||
|
|
6043eeb25a | ||
|
|
1f0cbc7dbd | ||
|
|
fa2186d95e | ||
|
|
6d7cff9c00 | ||
|
|
b85207d524 | ||
|
|
730222bcd8 | ||
|
|
7e12be0c64 | ||
|
|
303b89a6b4 | ||
|
|
3f01cc247c | ||
|
|
d9b74caf43 | ||
|
|
03b6978a27 | ||
|
|
84c95aff9b | ||
|
|
65b09cfa9d | ||
|
|
6b0250a843 | ||
|
|
d52dce2e6f | ||
|
|
e300a48e13 | ||
|
|
469af2a734 | ||
|
|
99f1874e86 | ||
|
|
f72e60c12a | ||
|
|
09b8cc97de | ||
|
|
1365dce921 | ||
|
|
0a2ad516d4 | ||
|
|
12eb8d1523 | ||
|
|
ce3d891bed | ||
|
|
713e53e3f6 | ||
|
|
340e966055 | ||
|
|
c69d696e1b | ||
|
|
7e9d4fbfc8 | ||
|
|
491ceacb64 | ||
|
|
05d5cc4988 | ||
|
|
7d8275daf5 | ||
|
|
433b23be17 | ||
|
|
d27a3f453c | ||
|
|
6efca486e8 | ||
|
|
ae86d10e48 | ||
|
|
64471e6ea8 | ||
|
|
373ffa0f31 | ||
|
|
681a6e371d | ||
|
|
9692c0c64c | ||
|
|
5458a1b291 | ||
|
|
b4550f361b | ||
|
|
b09ccc12c3 | ||
|
|
e1184e31f6 | ||
|
|
96428425fe | ||
|
|
2873be2d6a | ||
|
|
d1246ea8d5 | ||
|
|
2e91f0e689 | ||
|
|
a139599d39 | ||
|
|
06e7f2195e | ||
|
|
b8aaff2cf7 | ||
|
|
342e5af4e3 | ||
|
|
e4bfcb44b3 | ||
|
|
edd96f4414 | ||
|
|
d23c9125c5 | ||
|
|
c10e807492 | ||
|
|
e5d16caebe | ||
|
|
8e28de142a | ||
|
|
df3163223f | ||
|
|
9f2215d69b | ||
|
|
81d16823a7 | ||
|
|
17c0c3c731 | ||
|
|
c098a07d67 | ||
|
|
2ab46d4b8e | ||
|
|
d0b5909fd8 | ||
|
|
7c04ee5c20 | ||
|
|
f156548c16 | ||
|
|
ddfc43e774 | ||
|
|
b74827de99 | ||
|
|
48fe0dd4f6 | ||
|
|
e9140c740b | ||
|
|
01800a23ad | ||
|
|
42e4b14861 | ||
|
|
01b661ea25 | ||
|
|
1ec573bf0d | ||
|
|
96d8415946 | ||
|
|
31b7a2de41 | ||
|
|
73632312c2 | ||
|
|
6c22936303 | ||
|
|
db96b00720 | ||
|
|
a49f664aea | ||
|
|
194660660d | ||
|
|
9d1a71a5cb | ||
|
|
983c7e8805 | ||
|
|
62f2c6d326 | ||
|
|
7d69cdf4ad | ||
|
|
15f44933c2 | ||
|
|
513e6ee972 | ||
|
|
b496c4b164 | ||
|
|
cafe8621e2 | ||
|
|
af5a8e1abf | ||
|
|
b84d41f9ea | ||
|
|
557a1ed5da | ||
|
|
477eb89793 | ||
|
|
f384d61c3d | ||
|
|
f125c11faa | ||
|
|
c4eb41f091 | ||
|
|
160af49450 | ||
|
|
47da7483d8 | ||
|
|
c37cc1c8a3 | ||
|
|
96ec33e6d6 | ||
|
|
d7557ef9be | ||
|
|
9a8ab764d5 | ||
|
|
b91c6c2edd | ||
|
|
4466c47990 | ||
|
|
bd1b671e82 | ||
|
|
ef145bda1c | ||
|
|
3410c1b1e2 | ||
|
|
81b92bcbfa | ||
|
|
e32d5fc03d | ||
|
|
abe1440268 | ||
|
|
2d3ed956b9 | ||
|
|
7857098cb0 | ||
|
|
ac3c0c093a | ||
|
|
7186b0437f | ||
|
|
96dcbd1f20 | ||
|
|
56242cb874 | ||
|
|
94927195ee | ||
|
|
5f2aeba8cc | ||
|
|
e089969404 | ||
|
|
48cbf1cb36 | ||
|
|
6bebdcfa30 | ||
|
|
f8351c1b22 | ||
|
|
8a855e3e64 | ||
|
|
fec6b63494 | ||
|
|
9769565f88 | ||
|
|
63a528eac2 | ||
|
|
ed47008710 | ||
|
|
b32954a46c | ||
|
|
1781b1eab0 | ||
|
|
d1f48e5ede | ||
|
|
d3932c0242 | ||
|
|
20f6bebdf2 | ||
|
|
f07ecbc579 | ||
|
|
49718e0ec6 | ||
|
|
c78be86103 | ||
|
|
0de847a8e1 | ||
|
|
62f07d820c | ||
|
|
04bd84e914 | ||
|
|
167e2e7750 | ||
|
|
f1080a2bbe | ||
|
|
80b93a3606 | ||
|
|
973c4ea053 | ||
|
|
9a9d12cf4f | ||
|
|
e06060a31f | ||
|
|
ddf4e7e9ba | ||
|
|
0f45d3d01d | ||
|
|
a5e7f2c8bb | ||
|
|
b6828ac5c5 | ||
|
|
b8d69cb0d5 | ||
|
|
b454e43143 | ||
|
|
f63fd23f2e | ||
|
|
09209dc54b | ||
|
|
3c80c67633 | ||
|
|
3e4a23cb14 | ||
|
|
2f181658e6 | ||
|
|
8239b76c5a | ||
|
|
6d5d3fa4dd | ||
|
|
5cbf7007ff | ||
|
|
c30869617f | ||
|
|
321a3892a7 | ||
|
|
c74cc93140 | ||
|
|
38e0e3feef | ||
|
|
489b7d64e4 | ||
|
|
87a0227d01 |
36
.github/workflows/main.yml
vendored
Normal file
36
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: CI
|
||||
on: # yamllint disable-line rule:truthy
|
||||
push:
|
||||
branches: [ master ] # yamllint disable-line rule:brackets
|
||||
tags:
|
||||
- /^v\d+\.\d+\.(x|\d+)$/
|
||||
pull_request:
|
||||
branches: [ master ] # yamllint disable-line rule:brackets
|
||||
|
||||
jobs:
|
||||
build_image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docker run image
|
||||
shell: bash
|
||||
env:
|
||||
DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }}
|
||||
DOCKER_HUB_PASS: ${{ secrets.DOCKER_HUB_PASS }}
|
||||
run: ./run-tests --build-image
|
||||
test_ale:
|
||||
needs: build_image
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
vim-version:
|
||||
- '--vim-80-only'
|
||||
- '--vim-82-only'
|
||||
- '--neovim-02-only'
|
||||
- '--neovim-04-only'
|
||||
- '--linters-only'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run tests
|
||||
run: ./run-tests -v ${{ matrix.vim-version }}
|
||||
16
.travis.yml
16
.travis.yml
@@ -1,16 +0,0 @@
|
||||
---
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
language: generic
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^v\d+\.\d+\.(x|\d+)$/
|
||||
env:
|
||||
- OPTIONS=--vim-80-only
|
||||
- OPTIONS=--vim-81-only
|
||||
- OPTIONS=--neovim-only
|
||||
- OPTIONS=--linters-only
|
||||
script: |
|
||||
./run-tests -v $OPTIONS
|
||||
10
Dockerfile
10
Dockerfile
@@ -1,15 +1,17 @@
|
||||
FROM tweekmonster/vim-testbed:latest
|
||||
|
||||
RUN install_vim -tag v8.0.0027 -build \
|
||||
-tag v8.1.0519 -build \
|
||||
-tag v8.2.2401 -build \
|
||||
-tag neovim:v0.2.0 -build \
|
||||
-tag neovim:v0.3.5 -build
|
||||
-tag neovim:v0.4.4 -build
|
||||
|
||||
ENV PACKAGES="\
|
||||
bash \
|
||||
git \
|
||||
python \
|
||||
py-pip \
|
||||
grep \
|
||||
sed \
|
||||
"
|
||||
RUN apk --update add $PACKAGES && \
|
||||
rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
|
||||
@@ -18,3 +20,7 @@ RUN pip install vim-vint==0.3.15
|
||||
|
||||
RUN git clone https://github.com/junegunn/vader.vim vader && \
|
||||
cd vader && git checkout c6243dd81c98350df4dec608fa972df98fa2a3af
|
||||
|
||||
ARG GIT_VERSION
|
||||
LABEL Version=${GIT_VERSION}
|
||||
LABEL Name=w0rp/ale
|
||||
|
||||
26
README.md
26
README.md
@@ -1,4 +1,4 @@
|
||||
# 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)
|
||||
# Asynchronous Lint Engine [](https://github.com/dense-analysis/ale/actions?query=event%3Apush+workflow%3ACI+branch%3Amaster++) [](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)
|
||||
|
||||
|
||||

|
||||
@@ -53,6 +53,7 @@ other content at [w0rp.com](https://w0rp.com).
|
||||
5. [Find References](#usage-find-references)
|
||||
6. [Hovering](#usage-hover)
|
||||
7. [Symbol Search](#usage-symbol-search)
|
||||
8. [Refactoring: Rename, Actions](#usage-refactoring)
|
||||
3. [Installation](#installation)
|
||||
1. [Installation with Vim package management](#standard-installation)
|
||||
2. [Installation with Pathogen](#installation-with-pathogen)
|
||||
@@ -253,6 +254,18 @@ similar to a given query string.
|
||||
|
||||
See `:help ale-symbol-search` for more information.
|
||||
|
||||
<a name="usage-refactoring"></a>
|
||||
|
||||
### 2.viii Refactoring: Rename, Actions
|
||||
|
||||
ALE supports renaming symbols in symbols in code such as variables or class
|
||||
names with the `ALERename` command.
|
||||
|
||||
`ALECodeAction` will execute actions on the cursor or applied to a visual
|
||||
range selection, such as automatically fixing errors.
|
||||
|
||||
See `:help ale-refactor` for more information.
|
||||
|
||||
<a name="installation"></a>
|
||||
|
||||
## 3. Installation
|
||||
@@ -328,12 +341,14 @@ git clone https://github.com/dense-analysis/ale.git
|
||||
### 3.iii. Installation with Vundle
|
||||
|
||||
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
|
||||
by using the path on GitHub for this repository.
|
||||
by adding the GitHub path for this repository to your `~/.vimrc`:
|
||||
|
||||
```vim
|
||||
Plugin 'dense-analysis/ale'
|
||||
```
|
||||
|
||||
Then run the command `:PluginInstall` in Vim.
|
||||
|
||||
See the Vundle documentation for more information.
|
||||
|
||||
<a name="installation-with-vim-plug"></a>
|
||||
@@ -341,13 +356,16 @@ See the Vundle documentation for more information.
|
||||
### 3.iiii. Installation with Vim-Plug
|
||||
|
||||
You can install this plugin using [Vim-Plug](https://github.com/junegunn/vim-plug)
|
||||
by adding the GitHub path for this repository to your `~/.vimrc`
|
||||
and running `:PlugInstall`.
|
||||
by adding the GitHub path for this repository to your `~/.vimrc`:
|
||||
|
||||
```vim
|
||||
Plug 'dense-analysis/ale'
|
||||
```
|
||||
|
||||
Then run the command `:PlugInstall` in Vim.
|
||||
|
||||
See the Vim-Plug documentation for more information.
|
||||
|
||||
<a name="contributing"></a>
|
||||
|
||||
## 4. Contributing
|
||||
|
||||
26
ale_linters/ada/adals.vim
Normal file
26
ale_linters/ada/adals.vim
Normal file
@@ -0,0 +1,26 @@
|
||||
" Author: Bartek Jasicki http://github.com/thindil
|
||||
" Description: Support for Ada Language Server
|
||||
|
||||
call ale#Set('ada_adals_executable', 'ada_language_server')
|
||||
call ale#Set('ada_adals_project', 'default.gpr')
|
||||
call ale#Set('ada_adals_encoding', 'utf-8')
|
||||
|
||||
function! ale_linters#ada#adals#GetAdaLSConfig(buffer) abort
|
||||
return {
|
||||
\ 'ada.projectFile': ale#Var(a:buffer, 'ada_adals_project'),
|
||||
\ 'ada.defaultCharset': ale#Var(a:buffer, 'ada_adals_encoding')
|
||||
\}
|
||||
endfunction
|
||||
|
||||
function! ale_linters#ada#adals#GetRootDirectory(buffer) abort
|
||||
return fnamemodify(bufname(a:buffer), ':p:h')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ada', {
|
||||
\ 'name': 'adals',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'ada_adals_executable')},
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale_linters#ada#adals#GetRootDirectory'),
|
||||
\ 'lsp_config': function('ale_linters#ada#adals#GetAdaLSConfig')
|
||||
\})
|
||||
12
ale_linters/apkbuild/apkbuild_lint.vim
Normal file
12
ale_linters/apkbuild/apkbuild_lint.vim
Normal file
@@ -0,0 +1,12 @@
|
||||
" Author: Leo <thinkabit.ukim@gmail.com>
|
||||
" Description: apkbuild-lint from atools linter for APKBUILDs
|
||||
|
||||
call ale#Set('apkbuild_apkbuild_lint_executable', 'apkbuild-lint')
|
||||
|
||||
call ale#linter#Define('apkbuild', {
|
||||
\ 'name': 'apkbuild_lint',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': {b -> ale#Var(b, 'apkbuild_apkbuild_lint_executable')},
|
||||
\ 'command': '%e %t',
|
||||
\ 'callback': 'ale#handlers#atools#Handle',
|
||||
\})
|
||||
12
ale_linters/apkbuild/secfixes_check.vim
Normal file
12
ale_linters/apkbuild/secfixes_check.vim
Normal file
@@ -0,0 +1,12 @@
|
||||
" Author: Leo <thinkabit.ukim@gmail.com>
|
||||
" Description: secfixes-check from atools linter for APKBUILDs
|
||||
|
||||
call ale#Set('apkbuild_secfixes_check_executable', 'secfixes-check')
|
||||
|
||||
call ale#linter#Define('apkbuild', {
|
||||
\ 'name': 'secfixes_check',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': {b -> ale#Var(b, 'apkbuild_secfixes_check_executable')},
|
||||
\ 'command': '%e %t',
|
||||
\ 'callback': 'ale#handlers#atools#Handle',
|
||||
\})
|
||||
@@ -18,7 +18,12 @@ function! ale_linters#bib#bibclean#get_type(str) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#bib#bibclean#match_msg(line) abort
|
||||
return matchlist(a:line, '^\(.*\) "stdin", line \(.*\): \(.*\)$')
|
||||
" Legacy message pattern works for bibclean <= v2.11.4. If empty, try
|
||||
" the new message pattern for bibtex > v2.11.4
|
||||
let l:matches_legacy = matchlist(a:line, '^\(.*\) "stdin", line \(\d\+\): \(.*\)$')
|
||||
|
||||
return ! empty(l:matches_legacy) ? l:matches_legacy
|
||||
\ : matchlist(a:line, '^\(.*\) stdin:\(\d\+\):\(.*\)$')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#bib#bibclean#match_entry(line) abort
|
||||
|
||||
@@ -10,7 +10,7 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
|
||||
let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c'
|
||||
|
||||
@@ -29,6 +29,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('cloudformation', {
|
||||
\ 'name': 'cloudformation',
|
||||
\ 'aliases': ['cfn-lint'],
|
||||
\ 'executable': 'cfn-lint',
|
||||
\ 'command': 'cfn-lint --template %t --format parseable',
|
||||
\ 'callback': 'ale_linters#cloudformation#cfn_python_lint#Handle',
|
||||
|
||||
@@ -23,11 +23,13 @@ function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
|
||||
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
|
||||
|
||||
" Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file.
|
||||
if expand('#' . a:buffer) =~# '\.h$'
|
||||
let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
|
||||
" Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file
|
||||
" only when compile-commands.json file is not there. Adding these
|
||||
" flags makes clang-tidy completely ignore compile commmands.
|
||||
if expand('#' . a:buffer) =~# '\.h$'
|
||||
let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
|
||||
endif
|
||||
endif
|
||||
|
||||
" Get the options to pass directly to clang-tidy
|
||||
|
||||
@@ -10,7 +10,7 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
|
||||
let l:buffer_path_include = empty(l:compile_commands_option)
|
||||
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
|
||||
\ : ''
|
||||
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
|
||||
let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
|
||||
|
||||
return l:cd_command
|
||||
\ . '%e -q --language=c++'
|
||||
|
||||
@@ -6,7 +6,7 @@ function! ale_linters#dafny#dafny#Handle(buffer, lines) abort
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'bufnr': a:buffer,
|
||||
\ 'filename': l:match[1],
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'text': l:match[5],
|
||||
@@ -14,13 +14,28 @@ function! ale_linters#dafny#dafny#Handle(buffer, lines) abort
|
||||
\ })
|
||||
endfor
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, '\v(.*)\((\d+),(\d+)\): (Verification of .{-} timed out after \d+ seconds)')
|
||||
call add(l:output, {
|
||||
\ 'filename': l:match[1],
|
||||
\ 'col': l:match[3] + 0,
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': 'E',
|
||||
\ })
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dafny#dafny#GetCommand(buffer) abort
|
||||
return printf('dafny %%s /compile:0 /timeLimit:%d', ale#Var(a:buffer, 'dafny_dafny_timelimit'))
|
||||
endfunction
|
||||
|
||||
call ale#Set('dafny_dafny_timelimit', 10)
|
||||
call ale#linter#Define('dafny', {
|
||||
\ 'name': 'dafny',
|
||||
\ 'executable': 'dafny',
|
||||
\ 'command': 'dafny %s /compile:0',
|
||||
\ 'command': function('ale_linters#dafny#dafny#GetCommand'),
|
||||
\ 'callback': 'ale_linters#dafny#dafny#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\ })
|
||||
|
||||
29
ale_linters/dart/analysis_server.vim
Normal file
29
ale_linters/dart/analysis_server.vim
Normal file
@@ -0,0 +1,29 @@
|
||||
" Author: Nelson Yeung <nelsyeung@gmail.com>
|
||||
" Description: Check Dart files with dart analysis server LSP
|
||||
|
||||
call ale#Set('dart_analysis_server_executable', 'dart')
|
||||
|
||||
function! ale_linters#dart#analysis_server#GetProjectRoot(buffer) abort
|
||||
" Note: pub only looks for pubspec.yaml, there's no point in adding
|
||||
" support for pubspec.yml
|
||||
let l:pubspec = ale#path#FindNearestFile(a:buffer, 'pubspec.yaml')
|
||||
|
||||
return !empty(l:pubspec) ? fnamemodify(l:pubspec, ':h:h') : '.'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#dart#analysis_server#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'dart_analysis_server_executable')
|
||||
let l:dart = resolve(exepath(l:executable))
|
||||
|
||||
return '%e '
|
||||
\ . fnamemodify(l:dart, ':h') . '/snapshots/analysis_server.dart.snapshot'
|
||||
\ . ' --lsp'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('dart', {
|
||||
\ 'name': 'analysis_server',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'dart_analysis_server_executable')},
|
||||
\ 'command': function('ale_linters#dart#analysis_server#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#dart#analysis_server#GetProjectRoot'),
|
||||
\})
|
||||
@@ -9,7 +9,7 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
"
|
||||
" /dev/stdin:19 DL3001 Pipe chain should start with a raw value.
|
||||
" /dev/stdin:19:3 unexpected thing
|
||||
let l:pattern = '\v^/dev/stdin:(\d+):?(\d+)? ((DL|SC)(\d+) )?(.+)$'
|
||||
let l:pattern = '\v^/dev/stdin:(\d+):?(\d+)? ((DL|SC)(\d+) )?((.+)?: )?(.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
@@ -24,9 +24,19 @@ function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort
|
||||
let l:colnum = l:match[2] + 0
|
||||
endif
|
||||
|
||||
let l:type = 'W'
|
||||
let l:text = l:match[6]
|
||||
let l:detail = l:match[6]
|
||||
" Shellcheck knows a 'style' severity - pin it to info level as well.
|
||||
if l:match[7] is# 'style'
|
||||
let l:type = 'I'
|
||||
elseif l:match[7] is# 'info'
|
||||
let l:type = 'I'
|
||||
elseif l:match[7] is# 'warning'
|
||||
let l:type = 'W'
|
||||
else
|
||||
let l:type = 'E'
|
||||
endif
|
||||
|
||||
let l:text = l:match[8]
|
||||
let l:detail = l:match[8]
|
||||
let l:domain = 'https://github.com/hadolint/hadolint/wiki/'
|
||||
|
||||
if l:match[4] is# 'SC'
|
||||
|
||||
@@ -45,6 +45,16 @@ function! ale_linters#elixir#credo#GetMode() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale_linters#elixir#credo#GetConfigFile() abort
|
||||
let l:config_file = get(g:, 'ale_elixir_credo_config_file', '')
|
||||
|
||||
if empty(l:config_file)
|
||||
return ''
|
||||
endif
|
||||
|
||||
return ' --config-file ' . l:config_file
|
||||
endfunction
|
||||
|
||||
function! ale_linters#elixir#credo#GetCommand(buffer) abort
|
||||
let l:project_root = ale#handlers#elixir#FindMixUmbrellaRoot(a:buffer)
|
||||
let l:mode = ale_linters#elixir#credo#GetMode()
|
||||
@@ -52,6 +62,7 @@ function! ale_linters#elixir#credo#GetCommand(buffer) abort
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . 'mix help credo && '
|
||||
\ . 'mix credo ' . ale_linters#elixir#credo#GetMode()
|
||||
\ . ale_linters#elixir#credo#GetConfigFile()
|
||||
\ . ' --format=flycheck --read-from-stdin %s'
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
let g:ale_erlang_dialyzer_executable =
|
||||
\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer')
|
||||
let g:ale_erlang_dialyzer_options =
|
||||
\ get(g:, 'ale_erlang_dialyzer_options', '-Wunmatched_returns'
|
||||
\ . ' -Werror_handling'
|
||||
\ . ' -Wrace_conditions'
|
||||
\ . ' -Wunderspecs')
|
||||
let g:ale_erlang_dialyzer_plt_file =
|
||||
\ get(g:, 'ale_erlang_dialyzer_plt_file', '')
|
||||
let g:ale_erlang_dialyzer_rebar3_profile =
|
||||
@@ -47,13 +52,12 @@ function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'erlang_dialyzer_options')
|
||||
|
||||
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'
|
||||
\ . ' ' . l:options
|
||||
\ . ' %s'
|
||||
|
||||
return l:command
|
||||
|
||||
39
ale_linters/erlang/elvis.vim
Normal file
39
ale_linters/erlang/elvis.vim
Normal file
@@ -0,0 +1,39 @@
|
||||
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com>
|
||||
" Description: Elvis linter for Erlang files
|
||||
|
||||
call ale#Set('erlang_elvis_executable', 'elvis')
|
||||
|
||||
function! ale_linters#erlang#elvis#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v:(\d+):[^:]+:(.+)'
|
||||
let l:loclist = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:loclist, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'text': s:AbbreviateMessage(l:match[2]),
|
||||
\ 'type': 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:loclist
|
||||
endfunction
|
||||
|
||||
function! s:AbbreviateMessage(text) abort
|
||||
let l:pattern = '\v\c^(line \d+ is too long):.*$'
|
||||
|
||||
return substitute(a:text, l:pattern, '\1.', '')
|
||||
endfunction
|
||||
|
||||
function! s:GetCommand(buffer) abort
|
||||
let l:file = ale#Escape(expand('#' . a:buffer . ':.'))
|
||||
|
||||
return '%e rock --output-format=parsable ' . l:file
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('erlang', {
|
||||
\ 'name': 'elvis',
|
||||
\ 'callback': 'ale_linters#erlang#elvis#Handle',
|
||||
\ 'executable': {b -> ale#Var(b, 'erlang_elvis_executable')},
|
||||
\ 'command': function('s:GetCommand'),
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
@@ -1,14 +1,22 @@
|
||||
" Author: Magnus Ottenklinger - https://github.com/evnu
|
||||
|
||||
let g:ale_erlang_erlc_executable = get(g:, 'ale_erlang_erlc_executable', 'erlc')
|
||||
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
|
||||
|
||||
function! ale_linters#erlang#erlc#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'erlang_erlc_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#erlc#GetCommand(buffer) abort
|
||||
let l:output_file = ale#util#Tempname()
|
||||
call ale#command#ManageFile(a:buffer, l:output_file)
|
||||
|
||||
return 'erlc -o ' . ale#Escape(l:output_file)
|
||||
\ . ' ' . ale#Var(a:buffer, 'erlang_erlc_options')
|
||||
\ . ' %t'
|
||||
let l:command = ale#Escape(ale_linters#erlang#erlc#GetExecutable(a:buffer))
|
||||
\ . ' -o ' . ale#Escape(l:output_file)
|
||||
\ . ' ' . ale#Var(a:buffer, 'erlang_erlc_options')
|
||||
\ . ' %t'
|
||||
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! ale_linters#erlang#erlc#Handle(buffer, lines) abort
|
||||
@@ -90,7 +98,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('erlang', {
|
||||
\ 'name': 'erlc',
|
||||
\ 'executable': 'erlc',
|
||||
\ 'executable': function('ale_linters#erlang#erlc#GetExecutable'),
|
||||
\ 'command': function('ale_linters#erlang#erlc#GetCommand'),
|
||||
\ 'callback': 'ale_linters#erlang#erlc#Handle',
|
||||
\})
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
call ale#Set('go_gopls_executable', 'gopls')
|
||||
call ale#Set('go_gopls_options', '--mode stdio')
|
||||
call ale#Set('go_gopls_init_options', {})
|
||||
|
||||
function! ale_linters#go#gopls#GetCommand(buffer) abort
|
||||
return ale#go#EnvString(a:buffer)
|
||||
@@ -31,4 +32,5 @@ call ale#linter#Define('go', {
|
||||
\ 'executable': {b -> ale#Var(b, 'go_gopls_executable')},
|
||||
\ 'command': function('ale_linters#go#gopls#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#go#gopls#FindProjectRoot'),
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'go_gopls_init_options')},
|
||||
\})
|
||||
|
||||
63
ale_linters/haskell/hls.vim
Normal file
63
ale_linters/haskell/hls.vim
Normal file
@@ -0,0 +1,63 @@
|
||||
" Author: Yen3 <yen3rc@gmail.com>
|
||||
" Description: A language server for haskell
|
||||
" The file is based on hie.vim (author: Luxed
|
||||
" <devildead13@gmail.com>). It search more project root files.
|
||||
"
|
||||
call ale#Set('haskell_hls_executable', 'haskell-language-server-wrapper')
|
||||
|
||||
function! ale_linters#haskell#hls#FindRootFile(buffer) abort
|
||||
let l:serach_root_files = [
|
||||
\ 'stack.yaml',
|
||||
\ 'cabal.project',
|
||||
\ 'package.yaml',
|
||||
\ 'hie.yaml'
|
||||
\ ]
|
||||
|
||||
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
|
||||
for l:root_file in l:serach_root_files
|
||||
if filereadable(l:path . l:root_file)
|
||||
return l:path
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#haskell#hls#GetProjectRoot(buffer) abort
|
||||
" Search for the project file first
|
||||
let l:project_file = ale_linters#haskell#hls#FindRootFile(a:buffer)
|
||||
|
||||
" If it's empty, search for the cabal file
|
||||
if empty(l:project_file)
|
||||
" Search all of the paths except for the root filesystem path.
|
||||
let l:paths = join(
|
||||
\ ale#path#Upwards(expand('#' . a:buffer . ':p:h'))[:-2],
|
||||
\ ','
|
||||
\)
|
||||
let l:project_file = globpath(l:paths, '*.cabal')
|
||||
endif
|
||||
|
||||
" If we still can't find one, use the current file.
|
||||
if empty(l:project_file)
|
||||
let l:project_file = expand('#' . a:buffer . ':p')
|
||||
endif
|
||||
|
||||
return fnamemodify(l:project_file, ':h')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#haskell#hls#GetCommand(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'haskell_hls_executable')
|
||||
|
||||
return ale#handlers#haskell_stack#EscapeExecutable(l:executable,
|
||||
\ 'haskell-language-server-wrapper')
|
||||
\ . ' --lsp'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('haskell', {
|
||||
\ 'name': 'hls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'command': function('ale_linters#haskell#hls#GetCommand'),
|
||||
\ 'executable': {b -> ale#Var(b, 'haskell_hls_executable')},
|
||||
\ 'project_root': function('ale_linters#haskell#hls#GetProjectRoot'),
|
||||
\})
|
||||
33
ale_linters/inko/inko.vim
Normal file
33
ale_linters/inko/inko.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: Yorick Peterse <yorick@yorickpeterse.com>
|
||||
" Description: linting of Inko source code using the Inko compiler
|
||||
|
||||
call ale#Set('inko_inko_executable', 'inko')
|
||||
|
||||
function! ale_linters#inko#inko#GetCommand(buffer) abort
|
||||
let l:include = ''
|
||||
|
||||
" Include the tests source directory, but only for test files.
|
||||
if expand('#' . a:buffer . ':p') =~? '\vtests[/\\]test[/\\]'
|
||||
let l:test_dir = ale#path#FindNearestDirectory(a:buffer, 'tests')
|
||||
|
||||
if isdirectory(l:test_dir)
|
||||
let l:include = '--include ' . ale#Escape(l:test_dir)
|
||||
endif
|
||||
endif
|
||||
|
||||
" We use %s instead of %t so the compiler determines the correct module
|
||||
" names for the file being edited. Not doing so may lead to errors in
|
||||
" certain cases.
|
||||
return '%e build --check --format=json'
|
||||
\ . ale#Pad(l:include)
|
||||
\ . ' %s'
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('inko', {
|
||||
\ 'name': 'inko',
|
||||
\ 'executable': {b -> ale#Var(b, 'inko_inko_executable')},
|
||||
\ 'command': function('ale_linters#inko#inko#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#inko#Handle',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'lint_file': 1
|
||||
\})
|
||||
@@ -9,7 +9,7 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
" modern checkstyle versions
|
||||
let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]$'
|
||||
let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
|
||||
@@ -29,28 +29,28 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
|
||||
endif
|
||||
|
||||
" Search jar file within repository path when manually built using mvn
|
||||
let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_*\.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, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
endif
|
||||
|
||||
" Search jar file within unzipped tar.gz file
|
||||
let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
|
||||
let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_*\.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)
|
||||
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_*\.jar', 1, 1)
|
||||
|
||||
if len(l:files) >= 1
|
||||
return l:files[0]
|
||||
|
||||
@@ -9,13 +9,7 @@ call ale#Set('java_javac_classpath', '')
|
||||
call ale#Set('java_javac_sourcepath', '')
|
||||
|
||||
function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
|
||||
let l:command = ''
|
||||
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
|
||||
|
||||
if !empty(l:pom_path) && executable('mvn')
|
||||
let l:command = ale#path#CdString(fnamemodify(l:pom_path, ':h'))
|
||||
\ . 'mvn dependency:build-classpath'
|
||||
endif
|
||||
let l:command = ale#maven#BuildClasspathCommand(a:buffer)
|
||||
|
||||
" Try to use Gradle if Maven isn't available.
|
||||
if empty(l:command)
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
" Author: Daniel Lupu <lupu.daniel.f@gmail.com>
|
||||
" Description: xo for JavaScript files
|
||||
|
||||
call ale#Set('javascript_xo_executable', 'xo')
|
||||
call ale#Set('javascript_xo_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('javascript_xo_options', '')
|
||||
|
||||
function! ale_linters#javascript#xo#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_xo', [
|
||||
\ 'node_modules/.bin/xo',
|
||||
\])
|
||||
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 json --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
" xo uses eslint and the output format is the same
|
||||
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#HandleJSON',
|
||||
\ 'executable': function('ale#handlers#xo#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#xo#GetLintCommand'),
|
||||
\ 'callback': 'ale#handlers#xo#HandleJSON',
|
||||
\})
|
||||
|
||||
32
ale_linters/json/jq.vim
Normal file
32
ale_linters/json/jq.vim
Normal file
@@ -0,0 +1,32 @@
|
||||
" Author: jD91mZM2 <me@krake.one>
|
||||
|
||||
function! ale_linters#json#jq#GetCommand(buffer) abort
|
||||
let l:executable = ale#fixers#jq#GetExecutable(a:buffer)
|
||||
|
||||
return ale#Escape(l:executable)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#json#jq#Handle(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" parse error: Expected another key-value pair at line 4, column 3
|
||||
let l:pattern = '^parse error: \(.\+\) at line \(\d\+\), column \(\d\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'text': l:match[1],
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'col': l:match[3] + 0,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('json', {
|
||||
\ 'name': 'jq',
|
||||
\ 'executable': function('ale#fixers#jq#GetExecutable'),
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'command': function('ale_linters#json#jq#GetCommand'),
|
||||
\ 'callback': 'ale_linters#json#jq#Handle',
|
||||
\})
|
||||
14
ale_linters/json/spectral.vim
Normal file
14
ale_linters/json/spectral.vim
Normal file
@@ -0,0 +1,14 @@
|
||||
" Author: t2h5 <https://github.com/t2h5>
|
||||
" Description: Integration of Stoplight Spectral CLI with ALE.
|
||||
|
||||
call ale#Set('json_spectral_executable', 'spectral')
|
||||
call ale#Set('json_spectral_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
call ale#linter#Define('json', {
|
||||
\ 'name': 'spectral',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'json_spectral', [
|
||||
\ 'node_modules/.bin/spectral',
|
||||
\ ])},
|
||||
\ 'command': '%e lint --ignore-unknown-format -q -f text %t',
|
||||
\ 'callback': 'ale#handlers#spectral#HandleSpectralOutput'
|
||||
\})
|
||||
@@ -6,9 +6,9 @@ call ale#Set('julia_executable', 'julia')
|
||||
|
||||
function! ale_linters#julia#languageserver#GetCommand(buffer) abort
|
||||
let l:julia_executable = ale#Var(a:buffer, 'julia_executable')
|
||||
let l:cmd_string = 'using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);'
|
||||
let l:cmd_string = 'using LanguageServer; using Pkg; import StaticLint; import SymbolServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, dirname(Pkg.Types.Context().env.project_file)); server.runlinter = true; run(server);'
|
||||
|
||||
return ale#Escape(l:julia_executable) . ' --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string)
|
||||
return ale#Escape(l:julia_executable) . ' --project=@. --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('julia', {
|
||||
|
||||
@@ -1,18 +1,51 @@
|
||||
" Author: Alistair Bill <@alibabzo>
|
||||
" Author: Maximilian Bosch <maximilian@mbosch.me>
|
||||
" Description: nix-instantiate linter for nix files
|
||||
|
||||
function! ale_linters#nix#nix#Command(buffer, output, meta) abort
|
||||
let l:version = a:output[0][22:]
|
||||
|
||||
if l:version =~# '^\(2.4\|3\).*'
|
||||
return 'nix-instantiate --log-format internal-json --parse -'
|
||||
else
|
||||
return 'nix-instantiate --parse -'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale_linters#nix#nix#Handle(buffer, lines) abort
|
||||
let l:pattern = '^\(.\+\): \(.\+\), at .*:\(\d\+\):\(\d\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'col': l:match[4] + 0,
|
||||
\ 'text': l:match[1] . ': ' . l:match[2],
|
||||
\ 'type': l:match[1] =~# '^error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
if empty(a:lines)
|
||||
return l:output
|
||||
endif
|
||||
|
||||
if a:lines[0] =~# '^@nix .*'
|
||||
for l:line in a:lines
|
||||
if l:line =~# '^@nix .*'
|
||||
let l:result = json_decode(strpart(l:line, 4))
|
||||
|
||||
if has_key(l:result, 'column')
|
||||
call add(l:output, {
|
||||
\ 'type': 'E',
|
||||
\ 'lnum': l:result.line,
|
||||
\ 'col': l:result.column,
|
||||
\ 'text': l:result.raw_msg
|
||||
\})
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
else
|
||||
let l:pattern = '^\(.\+\): \(.\+\) at .*:\(\d\+\):\(\d\+\)$'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[3] + 0,
|
||||
\ 'col': l:match[4] + 0,
|
||||
\ 'text': l:match[1] . ': ' . substitute(l:match[2], ',$', '', ''),
|
||||
\ 'type': l:match[1] =~# '^error' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
@@ -21,6 +54,10 @@ call ale#linter#Define('nix', {
|
||||
\ 'name': 'nix',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'executable': 'nix-instantiate',
|
||||
\ 'command': 'nix-instantiate --parse -',
|
||||
\ 'command': {buffer -> ale#command#Run(
|
||||
\ buffer,
|
||||
\ 'nix-instantiate --version',
|
||||
\ function('ale_linters#nix#nix#Command')
|
||||
\ )},
|
||||
\ 'callback': 'ale_linters#nix#nix#Handle',
|
||||
\})
|
||||
|
||||
16
ale_linters/nix/rnix_lsp.vim
Normal file
16
ale_linters/nix/rnix_lsp.vim
Normal file
@@ -0,0 +1,16 @@
|
||||
" Author: jD91mZM2 <me@krake.one>
|
||||
" Description: rnix-lsp language client
|
||||
|
||||
function! ale_linters#nix#rnix_lsp#GetProjectRoot(buffer) abort
|
||||
" rnix-lsp does not yet use the project root, so getting it right is not
|
||||
" important
|
||||
return fnamemodify(a:buffer, ':h')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('nix', {
|
||||
\ 'name': 'rnix_lsp',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': 'rnix-lsp',
|
||||
\ 'command': '%e',
|
||||
\ 'project_root': function('ale_linters#nix#rnix_lsp#GetProjectRoot'),
|
||||
\})
|
||||
58
ale_linters/openapi/ibm_validator.vim
Normal file
58
ale_linters/openapi/ibm_validator.vim
Normal file
@@ -0,0 +1,58 @@
|
||||
" Author: Horacio Sanson <hsanson@gmail.com>
|
||||
|
||||
call ale#Set('openapi_ibm_validator_executable', 'lint-openapi')
|
||||
call ale#Set('openapi_ibm_validator_options', '')
|
||||
|
||||
function! ale_linters#openapi#ibm_validator#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'openapi_ibm_validator_options'))
|
||||
\ . ' %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#openapi#ibm_validator#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
let l:type = 'E'
|
||||
let l:message = ''
|
||||
let l:nr = -1
|
||||
|
||||
for l:line in a:lines
|
||||
let l:match = matchlist(l:line, '^errors$')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:type = 'E'
|
||||
endif
|
||||
|
||||
let l:match = matchlist(l:line, '^warnings$')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
let l:match = matchlist(l:line, '^ *Message : *\(.\+\)$')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:message = l:match[1]
|
||||
endif
|
||||
|
||||
let l:match = matchlist(l:line, '^ *Line *: *\(\d\+\)$')
|
||||
|
||||
if !empty(l:match)
|
||||
let l:nr = l:match[1]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:nr + 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:message,
|
||||
\ 'type': l:type,
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('openapi', {
|
||||
\ 'name': 'ibm_validator',
|
||||
\ 'executable': {b -> ale#Var(b, 'openapi_ibm_validator_executable')},
|
||||
\ 'command': function('ale_linters#openapi#ibm_validator#GetCommand'),
|
||||
\ 'callback': 'ale_linters#openapi#ibm_validator#Handle',
|
||||
\})
|
||||
9
ale_linters/openapi/yamllint.vim
Normal file
9
ale_linters/openapi/yamllint.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
call ale#Set('yaml_yamllint_executable', 'yamllint')
|
||||
call ale#Set('yaml_yamllint_options', '')
|
||||
|
||||
call ale#linter#Define('openapi', {
|
||||
\ 'name': 'yamllint',
|
||||
\ 'executable': {b -> ale#Var(b, 'yaml_yamllint_executable')},
|
||||
\ 'command': function('ale#handlers#yamllint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#yamllint#Handle',
|
||||
\})
|
||||
@@ -88,7 +88,7 @@ function! ale_linters#perl6#perl6#Handle(buffer, lines) abort
|
||||
|
||||
try
|
||||
let l:json = json_decode(join(a:lines, ''))
|
||||
catch /E474/
|
||||
catch /E474\|E491/
|
||||
call add(l:output, {
|
||||
\ 'lnum': '1',
|
||||
\ 'text': 'Received output in the default Perl6 error format. See :ALEDetail for details',
|
||||
|
||||
32
ale_linters/php/intelephense.vim
Executable file
32
ale_linters/php/intelephense.vim
Executable file
@@ -0,0 +1,32 @@
|
||||
" Author: Eric Stern <eric@ericstern.com>,
|
||||
" Arnold Chand <creativenull@outlook.com>
|
||||
" Description: Intelephense language server integration for ALE
|
||||
|
||||
call ale#Set('php_intelephense_executable', 'intelephense')
|
||||
call ale#Set('php_intelephense_use_global', 1)
|
||||
call ale#Set('php_intelephense_config', {})
|
||||
|
||||
function! ale_linters#php#intelephense#GetProjectRoot(buffer) abort
|
||||
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json')
|
||||
|
||||
if (!empty(l:composer_path))
|
||||
return fnamemodify(l:composer_path, ':h')
|
||||
endif
|
||||
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#intelephense#GetInitializationOptions(buffer) abort
|
||||
return ale#Var(a:buffer, 'php_intelephense_config')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'intelephense',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'initialization_options': function('ale_linters#php#intelephense#GetInitializationOptions'),
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_intelephense', [])},
|
||||
\ 'command': '%e --stdio',
|
||||
\ 'project_root': function('ale_linters#php#intelephense#GetProjectRoot'),
|
||||
\})
|
||||
@@ -39,7 +39,7 @@ function! ale_linters#php#phan#Handle(buffer, lines) abort
|
||||
let l:pattern = '^Phan error: \(\w\+\): \(.\+\) in \(.\+\) on line \(\d\+\)$'
|
||||
else
|
||||
" /path/to/some-filename.php:18 ERRORTYPE message
|
||||
let l:pattern = '^.*:\(\d\+\)\s\(\w\+\)\s\(.\+\)$'
|
||||
let l:pattern = '^\(.*\):\(\d\+\)\s\(\w\+\)\s\(.\+\)$'
|
||||
endif
|
||||
|
||||
let l:output = []
|
||||
@@ -49,13 +49,15 @@ function! ale_linters#php#phan#Handle(buffer, lines) abort
|
||||
let l:dict = {
|
||||
\ 'lnum': l:match[4] + 0,
|
||||
\ 'text': l:match[2],
|
||||
\ 'filename': l:match[3],
|
||||
\ 'type': 'W',
|
||||
\}
|
||||
else
|
||||
let l:dict = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'lnum': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': 'W',
|
||||
\ 'filename': l:match[1],
|
||||
\}
|
||||
endif
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
|
||||
" Matches against lines like the following:
|
||||
"
|
||||
" /path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
|
||||
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) - \(.\+\) (\(.\+\))$'
|
||||
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) - \(.\+\) (\(.\+\)).*$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
|
||||
80
ale_linters/php/tlint.vim
Normal file
80
ale_linters/php/tlint.vim
Normal file
@@ -0,0 +1,80 @@
|
||||
" Author: Jose Soto <jose@tighten.co>
|
||||
"
|
||||
" Description: Tighten Opinionated PHP Linting
|
||||
" Website: https://github.com/tightenco/tlint
|
||||
|
||||
call ale#Set('php_tlint_executable', 'tlint')
|
||||
call ale#Set('php_tlint_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('php_tlint_options', '')
|
||||
|
||||
function! ale_linters#php#tlint#GetProjectRoot(buffer) abort
|
||||
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json')
|
||||
|
||||
if !empty(l:composer_path)
|
||||
return fnamemodify(l:composer_path, ':h')
|
||||
endif
|
||||
|
||||
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
|
||||
|
||||
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#tlint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'php_tlint', [
|
||||
\ 'vendor/bin/tlint',
|
||||
\ 'tlint',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#tlint#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#php#tlint#GetExecutable(a:buffer)
|
||||
let l:options = ale#Var(a:buffer, 'php_tlint_options')
|
||||
|
||||
return ale#node#Executable(a:buffer, l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' lint %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#php#tlint#Handle(buffer, lines) abort
|
||||
" Matches against lines like the following:
|
||||
"
|
||||
" ! There should be 1 space around `.` concatenations, and additional lines should always start with a `.`
|
||||
" 22 : ` $something = 'a'.'name';`
|
||||
"
|
||||
let l:loop_count = 0
|
||||
let l:messages_pattern = '^\! \(.*\)'
|
||||
let l:output = []
|
||||
let l:pattern = '^\(\d\+\) \:'
|
||||
let l:temp_messages = []
|
||||
|
||||
for l:message in ale#util#GetMatches(a:lines, l:messages_pattern)
|
||||
call add(l:temp_messages, l:message)
|
||||
endfor
|
||||
|
||||
let l:loop_count = 0
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:num = l:match[1]
|
||||
let l:text = l:temp_messages[l:loop_count]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:num,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:text,
|
||||
\ 'type': 'W',
|
||||
\ 'sub_type': 'style',
|
||||
\})
|
||||
|
||||
let l:loop_count += 1
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('php', {
|
||||
\ 'name': 'tlint',
|
||||
\ 'executable': function('ale_linters#php#tlint#GetExecutable'),
|
||||
\ 'command': function('ale_linters#php#tlint#GetCommand'),
|
||||
\ 'callback': 'ale_linters#php#tlint#Handle',
|
||||
\ 'project_root': function('ale_linters#php#tlint#GetProjectRoot'),
|
||||
\})
|
||||
@@ -35,10 +35,11 @@ function! s:Subst(format, vars) abort
|
||||
endfunction
|
||||
|
||||
function! ale_linters#prolog#swipl#Handle(buffer, lines) abort
|
||||
let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$'
|
||||
let l:output = []
|
||||
let l:i = 0
|
||||
|
||||
let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$'
|
||||
|
||||
while l:i < len(a:lines)
|
||||
let l:match = matchlist(a:lines[l:i], l:pattern)
|
||||
|
||||
@@ -72,8 +73,17 @@ function! s:GetErrMsg(i, lines, text) abort
|
||||
let l:i = a:i + 1
|
||||
let l:text = []
|
||||
|
||||
while l:i < len(a:lines) && a:lines[l:i] =~# '^\s'
|
||||
call add(l:text, s:Trim(a:lines[l:i]))
|
||||
let l:pattern = '\v^(ERROR|Warning)?:?(.*)$'
|
||||
|
||||
while l:i < len(a:lines)
|
||||
let l:match = matchlist(a:lines[l:i], l:pattern)
|
||||
|
||||
if empty(l:match) || empty(l:match[2])
|
||||
let l:i += 1
|
||||
break
|
||||
endif
|
||||
|
||||
call add(l:text, s:Trim(l:match[2]))
|
||||
let l:i += 1
|
||||
endwhile
|
||||
|
||||
|
||||
34
ale_linters/python/jedils.vim
Normal file
34
ale_linters/python/jedils.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" Author: Dalius Dobravolskas <dalius.dobravolskas@gmail.com>
|
||||
" Description: https://github.com/pappasam/jedi-language-server
|
||||
|
||||
call ale#Set('python_jedils_executable', 'jedi-language-server')
|
||||
call ale#Set('python_jedils_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('python_jedils_auto_pipenv', 0)
|
||||
|
||||
function! ale_linters#python#jedils#GetExecutable(buffer) abort
|
||||
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_jedils_auto_pipenv'))
|
||||
\ && ale#python#PipenvPresent(a:buffer)
|
||||
return 'pipenv'
|
||||
endif
|
||||
|
||||
return ale#python#FindExecutable(a:buffer, 'python_jedils', ['jedi-language-server'])
|
||||
endfunction
|
||||
|
||||
function! ale_linters#python#jedils#GetCommand(buffer) abort
|
||||
let l:executable = ale_linters#python#jedils#GetExecutable(a:buffer)
|
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
\ ? ' run jedi-language-server'
|
||||
\ : ''
|
||||
|
||||
return ale#Escape(l:executable) . l:exec_args
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'jedils',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale_linters#python#jedils#GetExecutable'),
|
||||
\ 'command': function('ale_linters#python#jedils#GetCommand'),
|
||||
\ 'project_root': function('ale#python#FindProjectRoot'),
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\})
|
||||
26
ale_linters/r/languageserver.vim
Normal file
26
ale_linters/r/languageserver.vim
Normal file
@@ -0,0 +1,26 @@
|
||||
" Author: Eric Zhao <21zhaoe@protonmail.com>
|
||||
" Description: Implementation of the Language Server Protocol for R.
|
||||
|
||||
call ale#Set('r_languageserver_cmd', 'languageserver::run()')
|
||||
call ale#Set('r_languageserver_config', {})
|
||||
|
||||
function! ale_linters#r#languageserver#GetCommand(buffer) abort
|
||||
let l:cmd_string = ale#Var(a:buffer, 'r_languageserver_cmd')
|
||||
|
||||
return 'Rscript --vanilla -e ' . ale#Escape(l:cmd_string)
|
||||
endfunction
|
||||
|
||||
function! ale_linters#r#languageserver#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, '.Rprofile')
|
||||
|
||||
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : fnamemodify(a:buffer, ':h')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('r', {
|
||||
\ 'name': 'languageserver',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')},
|
||||
\ 'executable': 'Rscript',
|
||||
\ 'command': function('ale_linters#r#languageserver#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#r#languageserver#GetProjectRoot')
|
||||
\})
|
||||
@@ -1,14 +1,17 @@
|
||||
call ale#Set('ruby_sorbet_executable', 'srb')
|
||||
call ale#Set('ruby_sorbet_options', '')
|
||||
call ale#Set('ruby_sorbet_enable_watchman', 0)
|
||||
|
||||
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')
|
||||
let l:enable_watchman = ale#Var(a:buffer, 'ruby_sorbet_enable_watchman')
|
||||
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'srb')
|
||||
\ . ' tc'
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --lsp --disable-watchman'
|
||||
\ . ' --lsp'
|
||||
\ . (l:enable_watchman ? '' : ' --disable-watchman')
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('ruby', {
|
||||
|
||||
@@ -17,7 +17,7 @@ endfunction
|
||||
call ale#linter#Define('rust', {
|
||||
\ 'name': 'analyzer',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'lsp_config': {b -> ale#Var(b, 'rust_analyzer_config')},
|
||||
\ 'initialization_options': {b -> ale#Var(b, 'rust_analyzer_config')},
|
||||
\ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')},
|
||||
\ 'command': function('ale_linters#rust#analyzer#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#rust#analyzer#GetProjectRoot'),
|
||||
|
||||
33
ale_linters/salt/salt_lint.vim
Normal file
33
ale_linters/salt/salt_lint.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
" Author: Benjamin BINIER <poulpatine@gmail.com>
|
||||
" Description: salt-lint, saltstack linter
|
||||
|
||||
call ale#Set('salt_salt_lint_executable', 'salt-lint')
|
||||
call ale#Set('salt_salt_lint_options', '')
|
||||
|
||||
function! ale_linters#salt#salt_lint#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'salt_salt_lint_options'))
|
||||
\ . ' --json'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#salt#salt_lint#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:error.linenumber + 0,
|
||||
\ 'code': l:error.id + 0,
|
||||
\ 'text': l:error.message,
|
||||
\ 'type': l:error.severity is# 'HIGH' ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('salt', {
|
||||
\ 'name': 'salt_lint',
|
||||
\ 'aliases': ['salt-lint'],
|
||||
\ 'executable': {b -> ale#Var(b, 'salt_salt_lint_executable')},
|
||||
\ 'command': function('ale_linters#salt#salt_lint#GetCommand'),
|
||||
\ 'callback': 'ale_linters#salt#salt_lint#Handle'
|
||||
\})
|
||||
@@ -9,30 +9,40 @@ endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform#GetCommand(buffer) abort
|
||||
return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer))
|
||||
\ . ' fmt -no-color --check=true -'
|
||||
\ . ' validate -no-color -json '
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform#GetType(severity) abort
|
||||
if a:severity is? 'warning'
|
||||
return 'W'
|
||||
endif
|
||||
|
||||
return 'E'
|
||||
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
|
||||
let l:errors = ale#util#FuzzyJSONDecode(a:lines, {'diagnostics': []})
|
||||
let l:dir = expand('#' . a:buffer . ':p:h')
|
||||
let l:file = expand('#' . a:buffer . ':p')
|
||||
|
||||
for l:error in l:errors['diagnostics']
|
||||
if has_key(l:error, 'range')
|
||||
call add(l:output, {
|
||||
\ 'lnum': str2nr(l:match[1]),
|
||||
\ 'col': str2nr(l:match[2]),
|
||||
\ 'text': l:match[3],
|
||||
\ 'type': 'E',
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:error['range']['filename']),
|
||||
\ 'lnum': l:error['range']['start']['line'],
|
||||
\ 'col': l:error['range']['start']['column'],
|
||||
\ 'text': l:error['detail'],
|
||||
\ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']),
|
||||
\})
|
||||
else
|
||||
call add(l:output, {
|
||||
\ 'lnum': line('$'),
|
||||
\ 'text': l:match[1],
|
||||
\ 'type': 'E',
|
||||
\ 'filename': l:file,
|
||||
\ 'lnum': 0,
|
||||
\ 'col': 0,
|
||||
\ 'text': l:error['detail'],
|
||||
\ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']),
|
||||
\})
|
||||
endif
|
||||
endfor
|
||||
@@ -42,7 +52,7 @@ endfunction
|
||||
|
||||
call ale#linter#Define('terraform', {
|
||||
\ 'name': 'terraform',
|
||||
\ 'output_stream': 'stderr',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'),
|
||||
\ 'command': function('ale_linters#terraform#terraform#GetCommand'),
|
||||
\ 'callback': 'ale_linters#terraform#terraform#Handle',
|
||||
|
||||
38
ale_linters/terraform/terraform_ls.vim
Normal file
38
ale_linters/terraform/terraform_ls.vim
Normal file
@@ -0,0 +1,38 @@
|
||||
" Author: Horacio Sanson <hsanson@gmail.com>
|
||||
" Description: terraform-ls integration for ALE (cf. https://github.com/hashicorp/terraform-ls)
|
||||
|
||||
call ale#Set('terraform_terraform_executable', 'terraform')
|
||||
call ale#Set('terraform_ls_executable', 'terraform-ls')
|
||||
call ale#Set('terraform_ls_options', '')
|
||||
|
||||
function! ale_linters#terraform#terraform_ls#GetTerraformExecutable(buffer) abort
|
||||
let l:terraform_executable = ale#Var(a:buffer, 'terraform_terraform_executable')
|
||||
|
||||
if(ale#path#IsAbsolute(l:terraform_executable))
|
||||
return '-tf-exec ' . l:terraform_executable
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform_ls#GetCommand(buffer) abort
|
||||
return '%e'
|
||||
\ . ale#Pad('serve')
|
||||
\ . ale#Pad(ale_linters#terraform#terraform_ls#GetTerraformExecutable(a:buffer))
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'terraform_ls_options'))
|
||||
endfunction
|
||||
|
||||
function! ale_linters#terraform#terraform_ls#GetProjectRoot(buffer) abort
|
||||
let l:tf_dir = ale#path#FindNearestDirectory(a:buffer, '.terraform')
|
||||
|
||||
return !empty(l:tf_dir) ? fnamemodify(l:tf_dir, ':h:h') : ''
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('terraform', {
|
||||
\ 'name': 'terraform_ls',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': {b -> ale#Var(b, 'terraform_ls_executable')},
|
||||
\ 'command': function('ale_linters#terraform#terraform_ls#GetCommand'),
|
||||
\ 'project_root': function('ale_linters#terraform#terraform_ls#GetProjectRoot'),
|
||||
\ 'language': 'terraform',
|
||||
\})
|
||||
25
ale_linters/typescript/deno.vim
Normal file
25
ale_linters/typescript/deno.vim
Normal file
@@ -0,0 +1,25 @@
|
||||
" Author: Mohammed Chelouti - https://github.com/motato1
|
||||
" Description: Deno lsp linter for TypeScript files.
|
||||
|
||||
call ale#linter#Define('typescript', {
|
||||
\ 'name': 'deno',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': function('ale#handlers#deno#GetExecutable'),
|
||||
\ 'command': '%e lsp',
|
||||
\ 'project_root': function('ale#handlers#deno#GetProjectRoot'),
|
||||
\ 'initialization_options': function('ale_linters#typescript#deno#GetInitializationOptions'),
|
||||
\})
|
||||
|
||||
function! ale_linters#typescript#deno#GetInitializationOptions(buffer) abort
|
||||
let l:options = {
|
||||
\ 'enable': v:true,
|
||||
\ 'lint': v:true,
|
||||
\ 'unstable': v:false,
|
||||
\ }
|
||||
|
||||
if ale#Var(a:buffer, 'deno_unstable')
|
||||
let l:options.unstable = v:true
|
||||
endif
|
||||
|
||||
return l:options
|
||||
endfunction
|
||||
@@ -9,6 +9,7 @@ call ale#linter#Define('typescript', {
|
||||
\ 'name': 'tsserver',
|
||||
\ 'lsp': 'tsserver',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'typescript_tsserver', [
|
||||
\ '.yarn/sdks/typescript/bin/tsserver',
|
||||
\ 'node_modules/.bin/tsserver',
|
||||
\ ])},
|
||||
\ 'command': '%e',
|
||||
|
||||
@@ -1,23 +1,6 @@
|
||||
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',
|
||||
\ 'executable': function('ale#handlers#xo#GetExecutable'),
|
||||
\ 'command': function('ale#handlers#xo#GetLintCommand'),
|
||||
\ 'callback': 'ale#handlers#xo#HandleJSON',
|
||||
\})
|
||||
|
||||
66
ale_linters/vala/vala_lint.vim
Normal file
66
ale_linters/vala/vala_lint.vim
Normal file
@@ -0,0 +1,66 @@
|
||||
" Author: Atsuya Takagi <asoftonight@gmail.com>
|
||||
" Description: A linter for Vala using Vala-Lint.
|
||||
|
||||
call ale#Set('vala_vala_lint_config_filename', 'vala-lint.conf')
|
||||
call ale#Set('vala_vala_lint_executable', 'io.elementary.vala-lint')
|
||||
|
||||
function! ale_linters#vala#vala_lint#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'vala_vala_lint_executable')
|
||||
endfunction
|
||||
|
||||
function! ale_linters#vala#vala_lint#GetCommand(buffer) abort
|
||||
let l:command = ale_linters#vala#vala_lint#GetExecutable(a:buffer)
|
||||
|
||||
let l:config_filename = ale#Var(a:buffer, 'vala_vala_lint_config_filename')
|
||||
let l:config_path = ale#path#FindNearestFile(a:buffer, l:config_filename)
|
||||
|
||||
if !empty(l:config_path)
|
||||
let l:command .= ' -c ' . l:config_path
|
||||
endif
|
||||
|
||||
return l:command . ' %s'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#vala#vala_lint#Handle(buffer, lines) abort
|
||||
let l:pattern = '^\s*\(\d\+\)\.\(\d\+\)\s\+\(error\|warn\)\s\+\(.\+\)\s\([A-Za-z0-9_\-]\+\)'
|
||||
let l:output = []
|
||||
|
||||
for l:line in a:lines
|
||||
" remove color escape sequences since vala-lint doesn't support
|
||||
" output without colors
|
||||
let l:cleaned_line = substitute(l:line, '\e\[[0-9;]\+[mK]', '', 'g')
|
||||
let l:match = matchlist(l:cleaned_line, l:pattern)
|
||||
|
||||
if len(l:match) == 0
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:refined_type = l:match[3] is# 'warn' ? 'W' : 'E'
|
||||
let l:cleaned_text = substitute(l:match[4], '^\s*\(.\{-}\)\s*$', '\1', '')
|
||||
|
||||
let l:lnum = l:match[1] + 0
|
||||
let l:column = l:match[2] + 0
|
||||
let l:type = l:refined_type
|
||||
let l:text = l:cleaned_text
|
||||
let l:code = l:match[5]
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:lnum,
|
||||
\ 'col': l:column,
|
||||
\ 'text': l:text,
|
||||
\ 'type': l:type,
|
||||
\ 'code': l:code,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('vala', {
|
||||
\ 'name': 'vala_lint',
|
||||
\ 'output_stream': 'stdout',
|
||||
\ 'executable': function('ale_linters#vala#vala_lint#GetExecutable'),
|
||||
\ 'command': function('ale_linters#vala#vala_lint#GetCommand'),
|
||||
\ 'callback': 'ale_linters#vala#vala_lint#Handle',
|
||||
\ 'lint_file': 1,
|
||||
\})
|
||||
14
ale_linters/yaml/spectral.vim
Normal file
14
ale_linters/yaml/spectral.vim
Normal file
@@ -0,0 +1,14 @@
|
||||
" Author: t2h5 <https://github.com/t2h5>
|
||||
" Description: Integration of Stoplight Spectral CLI with ALE.
|
||||
|
||||
call ale#Set('yaml_spectral_executable', 'spectral')
|
||||
call ale#Set('yaml_spectral_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
call ale#linter#Define('yaml', {
|
||||
\ 'name': 'spectral',
|
||||
\ 'executable': {b -> ale#node#FindExecutable(b, 'yaml_spectral', [
|
||||
\ 'node_modules/.bin/spectral',
|
||||
\ ])},
|
||||
\ 'command': '%e lint --ignore-unknown-format -q -f text %t',
|
||||
\ 'callback': 'ale#handlers#spectral#HandleSpectralOutput'
|
||||
\})
|
||||
@@ -3,48 +3,9 @@
|
||||
call ale#Set('yaml_yamllint_executable', 'yamllint')
|
||||
call ale#Set('yaml_yamllint_options', '')
|
||||
|
||||
function! ale_linters#yaml#yamllint#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_yamllint_options'))
|
||||
\ . ' -f parsable %t'
|
||||
endfunction
|
||||
|
||||
function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
" something.yaml:1:1: [warning] missing document start "---" (document-start)
|
||||
" something.yml:2:1: [error] syntax error: expected the node content, but found '<stream end>'
|
||||
let l:pattern = '\v^.*:(\d+):(\d+): \[(error|warning)\] (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:item = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
|
||||
\}
|
||||
|
||||
let l:code_match = matchlist(l:item.text, '\v^(.+) \(([^)]+)\)$')
|
||||
|
||||
if !empty(l:code_match)
|
||||
if l:code_match[2] is# 'trailing-spaces'
|
||||
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:item.text = l:code_match[1]
|
||||
let l:item.code = l:code_match[2]
|
||||
endif
|
||||
|
||||
call add(l:output, l:item)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('yaml', {
|
||||
\ 'name': 'yamllint',
|
||||
\ 'executable': {b -> ale#Var(b, 'yaml_yamllint_executable')},
|
||||
\ 'command': function('ale_linters#yaml#yamllint#GetCommand'),
|
||||
\ 'callback': 'ale_linters#yaml#yamllint#Handle',
|
||||
\ 'command': function('ale#handlers#yamllint#GetCommand'),
|
||||
\ 'callback': 'ale#handlers#yamllint#Handle',
|
||||
\})
|
||||
|
||||
@@ -157,7 +157,7 @@ function! ale#Queue(delay, ...) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:current_ale_version = [3, 0, 0]
|
||||
let s:current_ale_version = [3, 1, 0]
|
||||
|
||||
" A function used to check for ALE features in files outside of the project.
|
||||
function! ale#Has(feature) abort
|
||||
|
||||
@@ -2,23 +2,39 @@
|
||||
" Description: balloonexpr support for ALE.
|
||||
|
||||
function! ale#balloon#MessageForPos(bufnr, lnum, col) abort
|
||||
let l:set_balloons = ale#Var(a:bufnr, 'set_balloons')
|
||||
let l:show_problems = 0
|
||||
let l:show_hover = 0
|
||||
|
||||
if l:set_balloons is 1
|
||||
let l:show_problems = 1
|
||||
let l:show_hover = 1
|
||||
elseif l:set_balloons is# 'hover'
|
||||
let l:show_hover = 1
|
||||
endif
|
||||
|
||||
" Don't show balloons if they are disabled, or linting is disabled.
|
||||
if !ale#Var(a:bufnr, 'set_balloons')
|
||||
if !(l:show_problems || l:show_hover)
|
||||
\|| !g:ale_enabled
|
||||
\|| !getbufvar(a:bufnr, 'ale_enabled', 1)
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
|
||||
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col)
|
||||
if l:show_problems
|
||||
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
|
||||
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col)
|
||||
endif
|
||||
|
||||
" Show the diagnostics message if found, 'Hover' output otherwise
|
||||
if l:index >= 0
|
||||
if l:show_problems && l:index >= 0
|
||||
return l:loclist[l:index].text
|
||||
elseif exists('*balloon_show') || getbufvar(
|
||||
\ a:bufnr,
|
||||
\ 'ale_set_balloons_legacy_echo',
|
||||
\ get(g:, 'ale_set_balloons_legacy_echo', 0)
|
||||
elseif l:show_hover && (
|
||||
\ exists('*balloon_show')
|
||||
\ || getbufvar(
|
||||
\ a:bufnr,
|
||||
\ 'ale_set_balloons_legacy_echo',
|
||||
\ get(g:, 'ale_set_balloons_legacy_echo', 0)
|
||||
\ )
|
||||
\)
|
||||
" Request LSP/tsserver hover information, but only if this version of
|
||||
" Vim supports the balloon_show function, or if we turned a legacy
|
||||
|
||||
@@ -152,6 +152,7 @@ function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
|
||||
\ || stridx(l:option, '-idirafter') == 0
|
||||
\ || stridx(l:option, '-iframework') == 0
|
||||
\ || stridx(l:option, '-include') == 0
|
||||
\ || stridx(l:option, '-imacros') == 0
|
||||
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
|
||||
let l:arg = join(split(l:option, '\zs')[2:], '')
|
||||
let l:option = '-I'
|
||||
@@ -490,7 +491,7 @@ function! ale#c#GetCFlags(buffer, output) abort
|
||||
endif
|
||||
endif
|
||||
|
||||
if s:CanParseMakefile(a:buffer) && !empty(a:output) && !empty(l:cflags)
|
||||
if empty(l:cflags) && s:CanParseMakefile(a:buffer) && !empty(a:output)
|
||||
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
|
||||
endif
|
||||
|
||||
@@ -505,6 +506,10 @@ function! ale#c#GetMakeCommand(buffer) abort
|
||||
if s:CanParseMakefile(a:buffer)
|
||||
let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
|
||||
|
||||
if empty(l:path)
|
||||
let l:path = ale#path#FindNearestFile(a:buffer, 'GNUmakefile')
|
||||
endif
|
||||
|
||||
if !empty(l:path)
|
||||
let l:always_make = ale#Var(a:buffer, 'c_always_make')
|
||||
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
" Author: Jerko Steiner <jerko.steiner@gmail.com>
|
||||
" Description: Code action support for LSP / tsserver
|
||||
|
||||
function! ale#code_action#HandleCodeAction(code_action, should_save) abort
|
||||
function! ale#code_action#ReloadBuffer() abort
|
||||
let l:buffer = bufnr('')
|
||||
|
||||
execute 'augroup ALECodeActionReloadGroup' . l:buffer
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
silent! execute 'augroup! ALECodeActionReloadGroup' . l:buffer
|
||||
|
||||
call ale#util#Execute(':e!')
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#HandleCodeAction(code_action, options) 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
|
||||
let l:should_save = get(a:options, 'should_save')
|
||||
|
||||
for l:file_code_edit in l:changes
|
||||
call ale#code_action#ApplyChanges(
|
||||
\ l:file_code_edit.fileName,
|
||||
\ l:file_code_edit.textChanges,
|
||||
\ a:should_save,
|
||||
\ )
|
||||
\ l:file_code_edit.fileName,
|
||||
\ l:file_code_edit.textChanges,
|
||||
\ l:should_save,
|
||||
\)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
@@ -78,29 +81,14 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
|
||||
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
|
||||
|
||||
" Changes have to be sorted so we apply them from top-to-bottom.
|
||||
for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp'))
|
||||
if l:code_edit.start.line isnot l:last_end_line
|
||||
let l:column_offset = 0
|
||||
endif
|
||||
|
||||
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
|
||||
" Changes have to be sorted so we apply them from bottom-to-top
|
||||
for l:code_edit in reverse(sort(copy(a:changes), function('s:ChangeCmp')))
|
||||
let l:line = l:code_edit.start.line
|
||||
let l:column = l:code_edit.start.offset
|
||||
let l:end_line = l:code_edit.end.line
|
||||
let l:end_column = l:code_edit.end.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
|
||||
@@ -118,6 +106,12 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
|
||||
let l:start = l:lines[: l:line - 2]
|
||||
endif
|
||||
|
||||
" Special case when text must be added after new line
|
||||
if l:column > len(l:lines[l:line - 1])
|
||||
call extend(l:start, [l:lines[l:line - 1]])
|
||||
let l:column = 1
|
||||
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.
|
||||
@@ -127,13 +121,17 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
|
||||
endif
|
||||
|
||||
call extend(l:middle, l:insertions[1:])
|
||||
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
|
||||
|
||||
if l:end_line <= len(l:lines)
|
||||
" Only extend the last line if end_line is within the range of
|
||||
" lines.
|
||||
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
|
||||
endif
|
||||
|
||||
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,
|
||||
@@ -159,6 +157,20 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
|
||||
|
||||
call setpos('.', [0, l:pos[0], l:pos[1], 0])
|
||||
endif
|
||||
|
||||
if a:should_save && l:buffer > 0 && !l:is_current_buffer
|
||||
" Set up a one-time use event that will delete itself to reload the
|
||||
" buffer next time it's entered to view the changes made to it.
|
||||
execute 'augroup ALECodeActionReloadGroup' . l:buffer
|
||||
autocmd!
|
||||
|
||||
execute printf(
|
||||
\ 'autocmd BufEnter <buffer=%d>'
|
||||
\ . ' call ale#code_action#ReloadBuffer()',
|
||||
\ l:buffer
|
||||
\)
|
||||
augroup END
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:UpdateCursor(cursor, start, end, offset) abort
|
||||
@@ -208,3 +220,163 @@ function! s:UpdateCursor(cursor, start, end, offset) abort
|
||||
|
||||
return [l:cur_line, l:cur_column]
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#GetChanges(workspace_edit) abort
|
||||
let l:changes = {}
|
||||
|
||||
if has_key(a:workspace_edit, 'changes') && !empty(a:workspace_edit.changes)
|
||||
return a:workspace_edit.changes
|
||||
elseif has_key(a:workspace_edit, 'documentChanges')
|
||||
let l:document_changes = []
|
||||
|
||||
if type(a:workspace_edit.documentChanges) is v:t_dict
|
||||
\ && has_key(a:workspace_edit.documentChanges, 'edits')
|
||||
call add(l:document_changes, a:workspace_edit.documentChanges)
|
||||
elseif type(a:workspace_edit.documentChanges) is v:t_list
|
||||
let l:document_changes = a:workspace_edit.documentChanges
|
||||
endif
|
||||
|
||||
for l:text_document_edit in l:document_changes
|
||||
let l:filename = l:text_document_edit.textDocument.uri
|
||||
let l:edits = l:text_document_edit.edits
|
||||
let l:changes[l:filename] = l:edits
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:changes
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#BuildChangesList(changes_map) abort
|
||||
let l:changes = []
|
||||
|
||||
for l:file_name in keys(a:changes_map)
|
||||
let l:text_edits = a:changes_map[l:file_name]
|
||||
let l:text_changes = []
|
||||
|
||||
for l:edit in l:text_edits
|
||||
let l:range = l:edit.range
|
||||
let l:new_text = l:edit.newText
|
||||
|
||||
call add(l:text_changes, {
|
||||
\ 'start': {
|
||||
\ 'line': l:range.start.line + 1,
|
||||
\ 'offset': l:range.start.character + 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:range.end.line + 1,
|
||||
\ 'offset': l:range.end.character + 1,
|
||||
\ },
|
||||
\ 'newText': l:new_text,
|
||||
\})
|
||||
endfor
|
||||
|
||||
call add(l:changes, {
|
||||
\ 'fileName': ale#path#FromURI(l:file_name),
|
||||
\ 'textChanges': l:text_changes,
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:changes
|
||||
endfunction
|
||||
|
||||
function! s:EscapeMenuName(text) abort
|
||||
return substitute(a:text, '\\\| \|\.\|&', '\\\0', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:UpdateMenu(data, menu_items) abort
|
||||
silent! aunmenu PopUp.Refactor\.\.\.
|
||||
|
||||
if empty(a:data)
|
||||
return
|
||||
endif
|
||||
|
||||
for [l:type, l:item] in a:menu_items
|
||||
let l:name = l:type is# 'tsserver' ? l:item.name : l:item.title
|
||||
let l:func_name = l:type is# 'tsserver'
|
||||
\ ? 'ale#codefix#ApplyTSServerCodeAction'
|
||||
\ : 'ale#codefix#ApplyLSPCodeAction'
|
||||
|
||||
execute printf(
|
||||
\ 'anoremenu <silent> PopUp.&Refactor\.\.\..%s'
|
||||
\ . ' :call %s(%s, %s)<CR>',
|
||||
\ s:EscapeMenuName(l:name),
|
||||
\ l:func_name,
|
||||
\ string(a:data),
|
||||
\ string(l:item),
|
||||
\)
|
||||
endfor
|
||||
|
||||
if empty(a:menu_items)
|
||||
silent! anoremenu PopUp.Refactor\.\.\..(None) :silent
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GetCodeActions(linter, options) abort
|
||||
let l:buffer = bufnr('')
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
let l:column = min([l:column, len(getline(l:line))])
|
||||
|
||||
let l:location = {
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'line': l:line,
|
||||
\ 'column': l:column,
|
||||
\ 'end_line': l:line,
|
||||
\ 'end_column': l:column,
|
||||
\}
|
||||
let l:Callback = function('s:OnReady', [l:location, a:options])
|
||||
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#GetCodeActions(options) abort
|
||||
silent! aunmenu PopUp.Rename
|
||||
silent! aunmenu PopUp.Refactor\.\.\.
|
||||
|
||||
" Only display the menu items if there's an LSP server.
|
||||
let l:has_lsp = 0
|
||||
|
||||
for l:linter in ale#linter#Get(&filetype)
|
||||
if !empty(l:linter.lsp)
|
||||
let l:has_lsp = 1
|
||||
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if l:has_lsp
|
||||
if !empty(expand('<cword>'))
|
||||
silent! anoremenu <silent> PopUp.Rename :ALERename<CR>
|
||||
endif
|
||||
|
||||
silent! anoremenu <silent> PopUp.Refactor\.\.\..(None) :silent<CR>
|
||||
|
||||
call ale#codefix#Execute(
|
||||
\ mode() is# 'v' || mode() is# "\<C-V>",
|
||||
\ function('s:UpdateMenu')
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:Setup(enabled) abort
|
||||
augroup ALECodeActionsGroup
|
||||
autocmd!
|
||||
|
||||
if a:enabled
|
||||
autocmd MenuPopup * :call ale#code_action#GetCodeActions({})
|
||||
endif
|
||||
augroup END
|
||||
|
||||
if !a:enabled
|
||||
silent! augroup! ALECodeActionsGroup
|
||||
|
||||
silent! aunmenu PopUp.Rename
|
||||
silent! aunmenu PopUp.Refactor\.\.\.
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#EnablePopUpMenu() abort
|
||||
call s:Setup(1)
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#DisablePopUpMenu() abort
|
||||
call s:Setup(0)
|
||||
endfunction
|
||||
|
||||
487
autoload/ale/codefix.vim
Normal file
487
autoload/ale/codefix.vim
Normal file
@@ -0,0 +1,487 @@
|
||||
" Author: Dalius Dobravolskas <dalius.dobravolskas@gmail.com>
|
||||
" Description: Code Fix support for tsserver and LSP servers
|
||||
|
||||
let s:codefix_map = {}
|
||||
|
||||
" Used to get the codefix map in tests.
|
||||
function! ale#codefix#GetMap() abort
|
||||
return deepcopy(s:codefix_map)
|
||||
endfunction
|
||||
|
||||
" Used to set the codefix map in tests.
|
||||
function! ale#codefix#SetMap(map) abort
|
||||
let s:codefix_map = a:map
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#ClearLSPData() abort
|
||||
let s:codefix_map = {}
|
||||
endfunction
|
||||
|
||||
function! s:message(message) abort
|
||||
call ale#util#Execute('echom ' . string(a:message))
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#ApplyTSServerCodeAction(data, item) abort
|
||||
if has_key(a:item, 'changes')
|
||||
let l:changes = a:item.changes
|
||||
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'codefix',
|
||||
\ 'changes': l:changes,
|
||||
\ },
|
||||
\ {},
|
||||
\)
|
||||
else
|
||||
let l:message = ale#lsp#tsserver_message#GetEditsForRefactor(
|
||||
\ a:data.buffer,
|
||||
\ a:data.line,
|
||||
\ a:data.column,
|
||||
\ a:data.end_line,
|
||||
\ a:data.end_column,
|
||||
\ a:item.id[0],
|
||||
\ a:item.id[1],
|
||||
\)
|
||||
|
||||
let l:request_id = ale#lsp#Send(a:data.connection_id, l:message)
|
||||
|
||||
let s:codefix_map[l:request_id] = a:data
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
|
||||
if !has_key(a:response, 'request_seq')
|
||||
\ || !has_key(s:codefix_map, a:response.request_seq)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:data = remove(s:codefix_map, a:response.request_seq)
|
||||
let l:MenuCallback = get(l:data, 'menu_callback', v:null)
|
||||
|
||||
if get(a:response, 'command', '') is# 'getCodeFixes'
|
||||
if get(a:response, 'success', v:false) is v:false
|
||||
\&& l:MenuCallback is v:null
|
||||
let l:message = get(a:response, 'message', 'unknown')
|
||||
call s:message('Error while getting code fixes. Reason: ' . l:message)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:result = get(a:response, 'body', [])
|
||||
call filter(l:result, 'has_key(v:val, ''changes'')')
|
||||
|
||||
if l:MenuCallback isnot v:null
|
||||
call l:MenuCallback(
|
||||
\ l:data,
|
||||
\ map(copy(l:result), '[''tsserver'', v:val]')
|
||||
\)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
if len(l:result) == 0
|
||||
call s:message('No code fixes available.')
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:code_fix_to_apply = 0
|
||||
|
||||
if len(l:result) == 1
|
||||
let l:code_fix_to_apply = 1
|
||||
else
|
||||
let l:codefix_no = 1
|
||||
let l:codefixstring = "Code Fixes:\n"
|
||||
|
||||
for l:codefix in l:result
|
||||
let l:codefixstring .= l:codefix_no . ') '
|
||||
\ . l:codefix.description . "\n"
|
||||
let l:codefix_no += 1
|
||||
endfor
|
||||
|
||||
let l:codefixstring .= 'Type number and <Enter> (empty cancels): '
|
||||
|
||||
let l:code_fix_to_apply = ale#util#Input(l:codefixstring, '')
|
||||
let l:code_fix_to_apply = str2nr(l:code_fix_to_apply)
|
||||
|
||||
if l:code_fix_to_apply == 0
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
call ale#codefix#ApplyTSServerCodeAction(
|
||||
\ l:data,
|
||||
\ l:result[l:code_fix_to_apply - 1],
|
||||
\)
|
||||
elseif get(a:response, 'command', '') is# 'getApplicableRefactors'
|
||||
if get(a:response, 'success', v:false) is v:false
|
||||
\&& l:MenuCallback is v:null
|
||||
let l:message = get(a:response, 'message', 'unknown')
|
||||
call s:message('Error while getting applicable refactors. Reason: ' . l:message)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:result = get(a:response, 'body', [])
|
||||
|
||||
if len(l:result) == 0
|
||||
call s:message('No applicable refactors available.')
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:refactors = []
|
||||
|
||||
for l:item in l:result
|
||||
for l:action in l:item.actions
|
||||
call add(l:refactors, {
|
||||
\ 'name': l:action.description,
|
||||
\ 'id': [l:item.name, l:action.name],
|
||||
\})
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if l:MenuCallback isnot v:null
|
||||
call l:MenuCallback(
|
||||
\ l:data,
|
||||
\ map(copy(l:refactors), '[''tsserver'', v:val]')
|
||||
\)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:refactor_no = 1
|
||||
let l:refactorstring = "Applicable refactors:\n"
|
||||
|
||||
for l:refactor in l:refactors
|
||||
let l:refactorstring .= l:refactor_no . ') '
|
||||
\ . l:refactor.name . "\n"
|
||||
let l:refactor_no += 1
|
||||
endfor
|
||||
|
||||
let l:refactorstring .= 'Type number and <Enter> (empty cancels): '
|
||||
|
||||
let l:refactor_to_apply = ale#util#Input(l:refactorstring, '')
|
||||
let l:refactor_to_apply = str2nr(l:refactor_to_apply)
|
||||
|
||||
if l:refactor_to_apply == 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:id = l:refactors[l:refactor_to_apply - 1].id
|
||||
|
||||
call ale#codefix#ApplyTSServerCodeAction(
|
||||
\ l:data,
|
||||
\ l:refactors[l:refactor_to_apply - 1],
|
||||
\)
|
||||
elseif get(a:response, 'command', '') is# 'getEditsForRefactor'
|
||||
if get(a:response, 'success', v:false) is v:false
|
||||
let l:message = get(a:response, 'message', 'unknown')
|
||||
call s:message('Error while getting edits for refactor. Reason: ' . l:message)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'editsForRefactor',
|
||||
\ 'changes': a:response.body.edits,
|
||||
\ },
|
||||
\ {},
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#ApplyLSPCodeAction(data, item) abort
|
||||
if has_key(a:item, 'command')
|
||||
\&& type(a:item.command) == v:t_dict
|
||||
let l:command = a:item.command
|
||||
let l:message = ale#lsp#message#ExecuteCommand(
|
||||
\ l:command.command,
|
||||
\ l:command.arguments,
|
||||
\)
|
||||
|
||||
let l:request_id = ale#lsp#Send(a:data.connection_id, l:message)
|
||||
elseif has_key(a:item, 'edit') || has_key(a:item, 'arguments')
|
||||
if has_key(a:item, 'edit')
|
||||
let l:topass = a:item.edit
|
||||
else
|
||||
let l:topass = a:item.arguments[0]
|
||||
endif
|
||||
|
||||
let l:changes_map = ale#code_action#GetChanges(l:topass)
|
||||
|
||||
if empty(l:changes_map)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
|
||||
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'codeaction',
|
||||
\ 'changes': l:changes,
|
||||
\ },
|
||||
\ {},
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#HandleLSPResponse(conn_id, response) abort
|
||||
if has_key(a:response, 'method')
|
||||
\ && a:response.method is# 'workspace/applyEdit'
|
||||
\ && has_key(a:response, 'params')
|
||||
let l:params = a:response.params
|
||||
|
||||
let l:changes_map = ale#code_action#GetChanges(l:params.edit)
|
||||
|
||||
if empty(l:changes_map)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
|
||||
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'applyEdit',
|
||||
\ 'changes': l:changes,
|
||||
\ },
|
||||
\ {}
|
||||
\)
|
||||
elseif has_key(a:response, 'id')
|
||||
\&& has_key(s:codefix_map, a:response.id)
|
||||
let l:data = remove(s:codefix_map, a:response.id)
|
||||
let l:MenuCallback = get(l:data, 'menu_callback', v:null)
|
||||
|
||||
let l:result = get(a:response, 'result')
|
||||
|
||||
if type(l:result) != v:t_list
|
||||
let l:result = []
|
||||
endif
|
||||
|
||||
" Send the results to the menu callback, if set.
|
||||
if l:MenuCallback isnot v:null
|
||||
call l:MenuCallback(
|
||||
\ l:data,
|
||||
\ map(copy(l:result), '[''lsp'', v:val]')
|
||||
\)
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
if len(l:result) == 0
|
||||
call s:message('No code actions received from server')
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
let l:codeaction_no = 1
|
||||
let l:codeactionstring = "Code Fixes:\n"
|
||||
|
||||
for l:codeaction in l:result
|
||||
let l:codeactionstring .= l:codeaction_no . ') '
|
||||
\ . l:codeaction.title . "\n"
|
||||
let l:codeaction_no += 1
|
||||
endfor
|
||||
|
||||
let l:codeactionstring .= 'Type number and <Enter> (empty cancels): '
|
||||
|
||||
let l:codeaction_to_apply = ale#util#Input(l:codeactionstring, '')
|
||||
let l:codeaction_to_apply = str2nr(l:codeaction_to_apply)
|
||||
|
||||
if l:codeaction_to_apply == 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:item = l:result[l:codeaction_to_apply - 1]
|
||||
|
||||
call ale#codefix#ApplyLSPCodeAction(l:data, l:item)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:FindError(buffer, line, column, end_line, end_column) abort
|
||||
let l:nearest_error = v:null
|
||||
|
||||
if a:line == a:end_line
|
||||
\&& a:column == a:end_column
|
||||
\&& has_key(g:ale_buffer_info, a:buffer)
|
||||
let l:nearest_error_diff = -1
|
||||
|
||||
for l:error in get(g:ale_buffer_info[a:buffer], 'loclist', [])
|
||||
if has_key(l:error, 'code') && l:error.lnum == a:line
|
||||
let l:diff = abs(l:error.col - a:column)
|
||||
|
||||
if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff
|
||||
let l:nearest_error_diff = l:diff
|
||||
let l:nearest_error = l:error
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:nearest_error
|
||||
endfunction
|
||||
|
||||
function! s:OnReady(
|
||||
\ line,
|
||||
\ column,
|
||||
\ end_line,
|
||||
\ end_column,
|
||||
\ MenuCallback,
|
||||
\ linter,
|
||||
\ lsp_details,
|
||||
\) abort
|
||||
let l:id = a:lsp_details.connection_id
|
||||
|
||||
if !ale#lsp#HasCapability(l:id, 'code_actions')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffer = a:lsp_details.buffer
|
||||
|
||||
if a:linter.lsp is# 'tsserver'
|
||||
let l:nearest_error =
|
||||
\ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
|
||||
|
||||
if l:nearest_error isnot v:null
|
||||
let l:message = ale#lsp#tsserver_message#GetCodeFixes(
|
||||
\ l:buffer,
|
||||
\ a:line,
|
||||
\ a:column,
|
||||
\ a:line,
|
||||
\ a:column,
|
||||
\ [l:nearest_error.code],
|
||||
\)
|
||||
else
|
||||
let l:message = ale#lsp#tsserver_message#GetApplicableRefactors(
|
||||
\ l:buffer,
|
||||
\ a:line,
|
||||
\ a:column,
|
||||
\ a:end_line,
|
||||
\ a:end_column,
|
||||
\)
|
||||
endif
|
||||
else
|
||||
" Send a message saying the buffer has changed first, otherwise
|
||||
" completions won't know what text is nearby.
|
||||
call ale#lsp#NotifyForChanges(l:id, l:buffer)
|
||||
|
||||
let l:diagnostics = []
|
||||
let l:nearest_error =
|
||||
\ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
|
||||
|
||||
if l:nearest_error isnot v:null
|
||||
let l:diagnostics = [
|
||||
\ {
|
||||
\ 'code': l:nearest_error.code,
|
||||
\ 'message': l:nearest_error.text,
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': l:nearest_error.lnum - 1,
|
||||
\ 'character': l:nearest_error.col - 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:nearest_error.end_lnum - 1,
|
||||
\ 'character': l:nearest_error.end_col,
|
||||
\ },
|
||||
\ },
|
||||
\ },
|
||||
\]
|
||||
endif
|
||||
|
||||
let l:message = ale#lsp#message#CodeAction(
|
||||
\ l:buffer,
|
||||
\ a:line,
|
||||
\ a:column,
|
||||
\ a:end_line,
|
||||
\ a:end_column,
|
||||
\ l:diagnostics,
|
||||
\)
|
||||
endif
|
||||
|
||||
let l:Callback = a:linter.lsp is# 'tsserver'
|
||||
\ ? function('ale#codefix#HandleTSServerResponse')
|
||||
\ : function('ale#codefix#HandleLSPResponse')
|
||||
|
||||
call ale#lsp#RegisterCallback(l:id, l:Callback)
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message)
|
||||
|
||||
let s:codefix_map[l:request_id] = {
|
||||
\ 'connection_id': l:id,
|
||||
\ 'buffer': l:buffer,
|
||||
\ 'line': a:line,
|
||||
\ 'column': a:column,
|
||||
\ 'end_line': a:end_line,
|
||||
\ 'end_column': a:end_column,
|
||||
\ 'menu_callback': a:MenuCallback,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
function! s:ExecuteGetCodeFix(linter, range, MenuCallback) abort
|
||||
let l:buffer = bufnr('')
|
||||
|
||||
if a:range == 0
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
let l:end_line = l:line
|
||||
let l:end_column = l:column
|
||||
|
||||
" Expand the range to cover the current word, if there is one.
|
||||
let l:cword = expand('<cword>')
|
||||
|
||||
if !empty(l:cword)
|
||||
let l:search_pos = searchpos('\V' . l:cword, 'bn', l:line)
|
||||
|
||||
if l:search_pos != [0, 0]
|
||||
let l:column = l:search_pos[1]
|
||||
let l:end_column = l:column + len(l:cword) - 1
|
||||
endif
|
||||
endif
|
||||
elseif mode() is# 'v' || mode() is# "\<C-V>"
|
||||
" You need to get the start and end in a different way when you're in
|
||||
" visual mode.
|
||||
let [l:line, l:column] = getpos('v')[1:2]
|
||||
let [l:end_line, l:end_column] = getpos('.')[1:2]
|
||||
else
|
||||
let [l:line, l:column] = getpos("'<")[1:2]
|
||||
let [l:end_line, l:end_column] = getpos("'>")[1:2]
|
||||
endif
|
||||
|
||||
let l:column = min([l:column, len(getline(l:line))])
|
||||
let l:end_column = min([l:end_column, len(getline(l:end_line))])
|
||||
|
||||
let l:Callback = function(
|
||||
\ 's:OnReady', [l:line, l:column, l:end_line, l:end_column, a:MenuCallback]
|
||||
\)
|
||||
|
||||
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
endfunction
|
||||
|
||||
function! ale#codefix#Execute(range, ...) abort
|
||||
if a:0 > 1
|
||||
throw 'Too many arguments'
|
||||
endif
|
||||
|
||||
let l:MenuCallback = get(a:000, 0, v:null)
|
||||
let l:lsp_linters = []
|
||||
|
||||
for l:linter in ale#linter#Get(&filetype)
|
||||
if !empty(l:linter.lsp)
|
||||
call add(l:lsp_linters, l:linter)
|
||||
endif
|
||||
endfor
|
||||
|
||||
if empty(l:lsp_linters)
|
||||
if l:MenuCallback is v:null
|
||||
call s:message('No active LSPs')
|
||||
else
|
||||
call l:MenuCallback({}, [])
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
for l:lsp_linter in l:lsp_linters
|
||||
call s:ExecuteGetCodeFix(l:lsp_linter, a:range, l:MenuCallback)
|
||||
endfor
|
||||
endfunction
|
||||
@@ -606,17 +606,23 @@ function! ale#completion#ParseLSPCompletions(response) abort
|
||||
let l:doc = l:doc.value
|
||||
endif
|
||||
|
||||
" Collapse whitespaces and line breaks into a single space.
|
||||
let l:detail = substitute(get(l:item, 'detail', ''), '\_s\+', ' ', 'g')
|
||||
|
||||
let l:result = {
|
||||
\ 'word': l:word,
|
||||
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
|
||||
\ 'icase': 1,
|
||||
\ 'menu': get(l:item, 'detail', ''),
|
||||
\ 'menu': l:detail,
|
||||
\ 'dup': get(l:info, 'additional_edits_only', 0)
|
||||
\ || g:ale_completion_autoimport,
|
||||
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
|
||||
\}
|
||||
" This flag is used to tell if this completion came from ALE or not.
|
||||
let l:user_data = {'_ale_completion_item': 1}
|
||||
|
||||
if has_key(l:item, 'additionalTextEdits')
|
||||
\ && l:item.additionalTextEdits isnot v:null
|
||||
let l:text_changes = []
|
||||
|
||||
for l:edit in l:item.additionalTextEdits
|
||||
@@ -1006,7 +1012,7 @@ function! ale#completion#HandleUserData(completed_item) abort
|
||||
\|| l:source is# 'ale-import'
|
||||
\|| l:source is# 'ale-omnifunc'
|
||||
for l:code_action in get(l:user_data, 'code_actions', [])
|
||||
call ale#code_action#HandleCodeAction(l:code_action, v:false)
|
||||
call ale#code_action#HandleCodeAction(l:code_action, {})
|
||||
endfor
|
||||
endif
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ let g:ale_echo_delay = get(g:, 'ale_echo_delay', 10)
|
||||
let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%code: %%s')
|
||||
|
||||
let s:cursor_timer = -1
|
||||
let s:last_pos = [0, 0, 0]
|
||||
|
||||
function! ale#cursor#TruncatedEcho(original_message) abort
|
||||
let l:message = a:original_message
|
||||
@@ -118,14 +117,18 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
|
||||
|
||||
let l:pos = getpos('.')[0:2]
|
||||
|
||||
if !exists('w:last_pos')
|
||||
let w:last_pos = [0, 0, 0]
|
||||
endif
|
||||
|
||||
" Check the current buffer, line, and column number against the last
|
||||
" recorded position. If the position has actually changed, *then*
|
||||
" we should echo something. Otherwise we can end up doing processing
|
||||
" the echo message far too frequently.
|
||||
if l:pos != s:last_pos
|
||||
if l:pos != w:last_pos
|
||||
let l:delay = ale#Var(l:buffer, 'echo_delay')
|
||||
|
||||
let s:last_pos = l:pos
|
||||
let w:last_pos = l:pos
|
||||
let s:cursor_timer = timer_start(
|
||||
\ l:delay,
|
||||
\ function('ale#cursor#EchoCursorWarning')
|
||||
@@ -139,11 +142,16 @@ function! s:ShowCursorDetailForItem(loc, options) abort
|
||||
let s:last_detailed_line = line('.')
|
||||
let l:message = get(a:loc, 'detail', a:loc.text)
|
||||
let l:lines = split(l:message, "\n")
|
||||
call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
|
||||
|
||||
" Clear the echo message if we manually displayed details.
|
||||
if !l:stay_here
|
||||
execute 'echo'
|
||||
if g:ale_floating_preview || g:ale_detail_to_floating_preview
|
||||
call ale#floating_preview#Show(l:lines)
|
||||
else
|
||||
call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
|
||||
|
||||
" Clear the echo message if we manually displayed details.
|
||||
if !l:stay_here
|
||||
execute 'echo'
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
24
autoload/ale/dhall.vim
Normal file
24
autoload/ale/dhall.vim
Normal file
@@ -0,0 +1,24 @@
|
||||
" Author: Pat Brisbin <pbrisbin@gmail.com>, toastal <toastal@protonmail.com>
|
||||
" Description: Functions for working with Dhall’s executable
|
||||
|
||||
call ale#Set('dhall_executable', 'dhall')
|
||||
call ale#Set('dhall_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('dhall_options', '')
|
||||
|
||||
function! ale#dhall#GetExecutable(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'dhall_executable')
|
||||
|
||||
" Dhall is written in Haskell and commonly installed with Stack
|
||||
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall')
|
||||
endfunction
|
||||
|
||||
function! ale#dhall#GetExecutableWithOptions(buffer) abort
|
||||
let l:executable = ale#dhall#GetExecutable(a:buffer)
|
||||
|
||||
return l:executable
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'dhall_options'))
|
||||
endfunction
|
||||
|
||||
function! ale#dhall#GetCommand(buffer) abort
|
||||
return '%e ' . ale#Pad(ale#Var(a:buffer, 'dhall_options'))
|
||||
endfunction
|
||||
@@ -12,6 +12,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['help'],
|
||||
\ 'description': 'Align help tags to the right margin',
|
||||
\ },
|
||||
\ 'autoimport': {
|
||||
\ 'function': 'ale#fixers#autoimport#Fix',
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
\ 'description': 'Fix import issues with autoimport.',
|
||||
\ },
|
||||
\ 'autopep8': {
|
||||
\ 'function': 'ale#fixers#autopep8#Fix',
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
@@ -27,11 +32,37 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
\ 'description': 'Fix PEP8 issues with black.',
|
||||
\ },
|
||||
\ 'deno': {
|
||||
\ 'function': 'ale#fixers#deno#Fix',
|
||||
\ 'suggested_filetypes': ['typescript'],
|
||||
\ 'description': 'Fix TypeScript using deno fmt.',
|
||||
\ },
|
||||
\ 'dfmt': {
|
||||
\ 'function': 'ale#fixers#dfmt#Fix',
|
||||
\ 'suggested_filetypes': ['d'],
|
||||
\ 'description': 'Fix D files with dfmt.',
|
||||
\ },
|
||||
\ 'dhall': {
|
||||
\ 'function': 'ale#fixers#dhall#Fix',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Fix Dhall files with dhall-format.',
|
||||
\ },
|
||||
\ 'dhall-format': {
|
||||
\ 'function': 'ale#fixers#dhall_format#Fix',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Standard code formatter for the Dhall language',
|
||||
\ 'aliases': ['dhall'],
|
||||
\ },
|
||||
\ 'dhall-freeze': {
|
||||
\ 'function': 'ale#fixers#dhall_freeze#Freeze',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Add integrity checks to remote import statements of an expression for the Dhall language',
|
||||
\ },
|
||||
\ 'dhall-lint': {
|
||||
\ 'function': 'ale#fixers#dhall_lint#Fix',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Standard code formatter for the Dhall language and removing dead code',
|
||||
\ },
|
||||
\ 'fecs': {
|
||||
\ 'function': 'ale#fixers#fecs#Fix',
|
||||
\ 'suggested_filetypes': ['javascript', 'css', 'html'],
|
||||
@@ -76,7 +107,7 @@ let s:default_registry = {
|
||||
\ },
|
||||
\ 'prettier': {
|
||||
\ 'function': 'ale#fixers#prettier#Fix',
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'html', 'yaml'],
|
||||
\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'html', 'yaml', 'openapi'],
|
||||
\ 'description': 'Apply prettier to a file.',
|
||||
\ },
|
||||
\ 'prettier_eslint': {
|
||||
@@ -105,6 +136,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': [],
|
||||
\ 'description': 'Remove all trailing whitespace characters at the end of every line.',
|
||||
\ },
|
||||
\ 'yamlfix': {
|
||||
\ 'function': 'ale#fixers#yamlfix#Fix',
|
||||
\ 'suggested_filetypes': ['yaml'],
|
||||
\ 'description': 'Fix yaml files with yamlfix.',
|
||||
\ },
|
||||
\ 'yapf': {
|
||||
\ 'function': 'ale#fixers#yapf#Fix',
|
||||
\ 'suggested_filetypes': ['python'],
|
||||
@@ -122,7 +158,7 @@ let s:default_registry = {
|
||||
\ },
|
||||
\ 'scalafmt': {
|
||||
\ 'function': 'ale#fixers#scalafmt#Fix',
|
||||
\ 'suggested_filetypes': ['scala'],
|
||||
\ 'suggested_filetypes': ['sbt', 'scala'],
|
||||
\ 'description': 'Fix Scala files using scalafmt',
|
||||
\ },
|
||||
\ 'sorbet': {
|
||||
@@ -180,6 +216,11 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['cmake'],
|
||||
\ 'description': 'Fix CMake files with cmake-format.',
|
||||
\ },
|
||||
\ 'fish_indent': {
|
||||
\ 'function': 'ale#fixers#fish_indent#Fix',
|
||||
\ 'suggested_filetypes': ['fish'],
|
||||
\ 'description': 'Format fish scripts using fish_indent.',
|
||||
\ },
|
||||
\ 'gofmt': {
|
||||
\ 'function': 'ale#fixers#gofmt#Fix',
|
||||
\ 'suggested_filetypes': ['go'],
|
||||
@@ -332,7 +373,7 @@ let s:default_registry = {
|
||||
\ },
|
||||
\ 'ktlint': {
|
||||
\ 'function': 'ale#fixers#ktlint#Fix',
|
||||
\ 'suggested_filetypes': ['kt'],
|
||||
\ 'suggested_filetypes': ['kt', 'kotlin'],
|
||||
\ 'description': 'Fix Kotlin files with ktlint.',
|
||||
\ },
|
||||
\ 'styler': {
|
||||
@@ -375,11 +416,16 @@ let s:default_registry = {
|
||||
\ 'suggested_filetypes': ['html', 'htmldjango'],
|
||||
\ 'description': 'Fix HTML files with html-beautify.',
|
||||
\ },
|
||||
\ 'dhall': {
|
||||
\ 'function': 'ale#fixers#dhall#Fix',
|
||||
\ 'suggested_filetypes': ['dhall'],
|
||||
\ 'description': 'Fix Dhall files with dhall-format.',
|
||||
\ 'luafmt': {
|
||||
\ 'function': 'ale#fixers#luafmt#Fix',
|
||||
\ 'suggested_filetypes': ['lua'],
|
||||
\ 'description': 'Fix Lua files with luafmt.',
|
||||
\ },
|
||||
\ 'ormolu': {
|
||||
\ 'function': 'ale#fixers#ormolu#Fix',
|
||||
\ 'suggested_filetypes': ['haskell'],
|
||||
\ 'description': 'A formatter for Haskell source code.',
|
||||
\ }
|
||||
\}
|
||||
|
||||
" Reset the function registry to the default entries.
|
||||
|
||||
25
autoload/ale/fixers/autoimport.vim
Normal file
25
autoload/ale/fixers/autoimport.vim
Normal file
@@ -0,0 +1,25 @@
|
||||
" Author: lyz-code
|
||||
" Description: Fixing Python imports with autoimport.
|
||||
|
||||
call ale#Set('python_autoimport_executable', 'autoimport')
|
||||
call ale#Set('python_autoimport_options', '')
|
||||
call ale#Set('python_autoimport_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale#fixers#autoimport#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'python_autoimport_options')
|
||||
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'python_autoimport',
|
||||
\ ['autoimport'],
|
||||
\)
|
||||
|
||||
if !executable(l:executable)
|
||||
return 0
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\}
|
||||
endfunction
|
||||
17
autoload/ale/fixers/deno.vim
Normal file
17
autoload/ale/fixers/deno.vim
Normal file
@@ -0,0 +1,17 @@
|
||||
function! ale#fixers#deno#Fix(buffer) abort
|
||||
let l:executable = ale#handlers#deno#GetExecutable(a:buffer)
|
||||
|
||||
if !executable(l:executable)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:options = ' fmt -'
|
||||
|
||||
if ale#Var(a:buffer, 'deno_unstable')
|
||||
let l:options = l:options . ' --unstable'
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable) . l:options
|
||||
\}
|
||||
endfunction
|
||||
@@ -1,23 +0,0 @@
|
||||
" Author: Pat Brisbin <pbrisbin@gmail.com>
|
||||
" Description: Integration of dhall-format with ALE.
|
||||
|
||||
call ale#Set('dhall_format_executable', 'dhall')
|
||||
|
||||
function! ale#fixers#dhall#GetExecutable(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'dhall_format_executable')
|
||||
|
||||
" Dhall is written in Haskell and commonly installed with Stack
|
||||
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall')
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#dhall#Fix(buffer) abort
|
||||
let l:executable = ale#fixers#dhall#GetExecutable(a:buffer)
|
||||
|
||||
return {
|
||||
\ 'command': l:executable
|
||||
\ . ' format'
|
||||
\ . ' --inplace'
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
14
autoload/ale/fixers/dhall_format.vim
Normal file
14
autoload/ale/fixers/dhall_format.vim
Normal file
@@ -0,0 +1,14 @@
|
||||
" Author: toastal <toastal@protonmail.com>
|
||||
" Description: Dhall’s built-in formatter
|
||||
"
|
||||
function! ale#fixers#dhall_format#Fix(buffer) abort
|
||||
let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer)
|
||||
let l:command = l:executable
|
||||
\ . ' format'
|
||||
\ . ' --inplace %t'
|
||||
|
||||
return {
|
||||
\ 'command': l:command,
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
18
autoload/ale/fixers/dhall_freeze.vim
Normal file
18
autoload/ale/fixers/dhall_freeze.vim
Normal file
@@ -0,0 +1,18 @@
|
||||
" Author: toastal <toastal@protonmail.com>
|
||||
" Description: Dhall’s package freezing
|
||||
|
||||
call ale#Set('dhall_freeze_options', '')
|
||||
|
||||
function! ale#fixers#dhall_freeze#Freeze(buffer) abort
|
||||
let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer)
|
||||
let l:command = l:executable
|
||||
\ . ' freeze'
|
||||
\ . ale#Pad(ale#Var(a:buffer, 'dhall_freeze_options'))
|
||||
\ . ' --inplace %t'
|
||||
|
||||
|
||||
return {
|
||||
\ 'command': l:command,
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
14
autoload/ale/fixers/dhall_lint.vim
Normal file
14
autoload/ale/fixers/dhall_lint.vim
Normal file
@@ -0,0 +1,14 @@
|
||||
" Author: toastal <toastal@protonmail.com>
|
||||
" Description: Dhall’s built-in linter/formatter
|
||||
|
||||
function! ale#fixers#dhall_lint#Fix(buffer) abort
|
||||
let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer)
|
||||
let l:command = l:executable
|
||||
\ . ' lint'
|
||||
\ . ' --inplace %t'
|
||||
|
||||
return {
|
||||
\ 'command': l:command,
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
19
autoload/ale/fixers/fish_indent.vim
Normal file
19
autoload/ale/fixers/fish_indent.vim
Normal file
@@ -0,0 +1,19 @@
|
||||
" Author: Chen YuanYuan <cyyever@outlook.com>
|
||||
" Description: Integration of fish_indent with ALE.
|
||||
|
||||
call ale#Set('fish_fish_indent_executable', 'fish_indent')
|
||||
call ale#Set('fish_fish_indent_options', '')
|
||||
|
||||
function! ale#fixers#fish_indent#Fix(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'fish_fish_indent_executable')
|
||||
let l:options = ale#Var(a:buffer, 'fish_fish_indent_options')
|
||||
let l:filename = ale#Escape(bufname(a:buffer))
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . ' -w '
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options)
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
@@ -11,9 +11,6 @@ function! ale#fixers#gofmt#Fix(buffer) abort
|
||||
|
||||
return {
|
||||
\ 'command': l:env . ale#Escape(l:executable)
|
||||
\ . ' -l -w'
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options)
|
||||
\ . ' %t',
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -2,24 +2,35 @@
|
||||
" Description: Fixing Python imports with isort.
|
||||
|
||||
call ale#Set('python_isort_executable', 'isort')
|
||||
call ale#Set('python_isort_options', '')
|
||||
call ale#Set('python_isort_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('python_isort_options', '')
|
||||
call ale#Set('python_isort_auto_pipenv', 0)
|
||||
|
||||
function! ale#fixers#isort#GetExecutable(buffer) abort
|
||||
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_isort_auto_pipenv'))
|
||||
\ && ale#python#PipenvPresent(a:buffer)
|
||||
return 'pipenv'
|
||||
endif
|
||||
|
||||
return ale#python#FindExecutable(a:buffer, 'python_isort', ['isort'])
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#isort#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'python_isort_options')
|
||||
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'python_isort',
|
||||
\ ['isort'],
|
||||
\)
|
||||
let l:executable = ale#fixers#isort#GetExecutable(a:buffer)
|
||||
|
||||
if !executable(l:executable)
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
\ ? ' run isort'
|
||||
\ : ''
|
||||
|
||||
if !executable(l:executable) && l:executable isnot# 'pipenv'
|
||||
return 0
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\ . ale#Escape(l:executable) . l:exec_args
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\}
|
||||
endfunction
|
||||
|
||||
13
autoload/ale/fixers/luafmt.vim
Normal file
13
autoload/ale/fixers/luafmt.vim
Normal file
@@ -0,0 +1,13 @@
|
||||
call ale#Set('lua_luafmt_executable', 'luafmt')
|
||||
call ale#Set('lua_luafmt_options', '')
|
||||
|
||||
function! ale#fixers#luafmt#Fix(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'lua_luafmt_executable')
|
||||
let l:options = ale#Var(a:buffer, 'lua_luafmt_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options)
|
||||
\ . ' --stdin',
|
||||
\}
|
||||
endfunction
|
||||
12
autoload/ale/fixers/ormolu.vim
Normal file
12
autoload/ale/fixers/ormolu.vim
Normal file
@@ -0,0 +1,12 @@
|
||||
call ale#Set('haskell_ormolu_executable', 'ormolu')
|
||||
call ale#Set('haskell_ormolu_options', '')
|
||||
|
||||
function! ale#fixers#ormolu#Fix(buffer) abort
|
||||
let l:executable = ale#Var(a:buffer, 'haskell_ormolu_executable')
|
||||
let l:options = ale#Var(a:buffer, 'haskell_ormolu_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (empty(l:options) ? '' : ' ' . l:options),
|
||||
\}
|
||||
endfunction
|
||||
@@ -2,6 +2,7 @@
|
||||
" Description: Fixing files with phpcbf.
|
||||
|
||||
call ale#Set('php_phpcbf_standard', '')
|
||||
call ale#Set('php_phpcbf_options', '')
|
||||
call ale#Set('php_phpcbf_executable', 'phpcbf')
|
||||
call ale#Set('php_phpcbf_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
@@ -20,6 +21,6 @@ function! ale#fixers#phpcbf#Fix(buffer) abort
|
||||
\ : ''
|
||||
|
||||
return {
|
||||
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ' -'
|
||||
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ale#Pad(ale#Var(a:buffer, 'php_phpcbf_options')) . ' -'
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -83,6 +83,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
|
||||
\ 'markdown': 'markdown',
|
||||
\ 'vue': 'vue',
|
||||
\ 'yaml': 'yaml',
|
||||
\ 'openapi': 'yaml',
|
||||
\ 'html': 'html',
|
||||
\}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ function! ale#fixers#standardrb#GetCommand(buffer) abort
|
||||
return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
|
||||
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --fix --force-exclusion %t'
|
||||
\ . ' --fix --force-exclusion --stdin %s'
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#standardrb#Fix(buffer) abort
|
||||
return {
|
||||
\ 'command': ale#fixers#standardrb#GetCommand(a:buffer),
|
||||
\ 'read_temporary_file': 1,
|
||||
\ 'process_with': 'ale#fixers#rubocop#PostProcess'
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -1,23 +1,36 @@
|
||||
" Author: Albert Marquez - https://github.com/a-marquez
|
||||
" Description: Fixing files with XO.
|
||||
|
||||
call ale#Set('javascript_xo_executable', 'xo')
|
||||
call ale#Set('javascript_xo_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('javascript_xo_options', '')
|
||||
function! ale#fixers#xo#Fix(buffer) abort
|
||||
let l:executable = ale#handlers#xo#GetExecutable(a:buffer)
|
||||
let l:options = ale#handlers#xo#GetOptions(a:buffer)
|
||||
|
||||
function! ale#fixers#xo#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_xo', [
|
||||
\ 'node_modules/xo/cli.js',
|
||||
\ 'node_modules/.bin/xo',
|
||||
\])
|
||||
return ale#semver#RunWithVersionCheck(
|
||||
\ a:buffer,
|
||||
\ l:executable,
|
||||
\ '%e --version',
|
||||
\ {b, v -> ale#fixers#xo#ApplyFixForVersion(b, v, l:executable, l:options)}
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#xo#Fix(buffer) abort
|
||||
let l:executable = ale#fixers#xo#GetExecutable(a:buffer)
|
||||
function! ale#fixers#xo#ApplyFixForVersion(buffer, version, executable, options) abort
|
||||
let l:executable = ale#node#Executable(a:buffer, a:executable)
|
||||
let l:options = ale#Pad(a:options)
|
||||
|
||||
" 0.30.0 is the first version with a working --stdin --fix
|
||||
if ale#semver#GTE(a:version, [0, 30, 0])
|
||||
return {
|
||||
\ 'command': l:executable
|
||||
\ . ' --stdin --stdin-filename %s'
|
||||
\ . ' --fix'
|
||||
\ . l:options,
|
||||
\}
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ' --fix %t',
|
||||
\ 'command': l:executable
|
||||
\ . ' --fix %t'
|
||||
\ . l:options,
|
||||
\ 'read_temporary_file': 1,
|
||||
\}
|
||||
endfunction
|
||||
|
||||
25
autoload/ale/fixers/yamlfix.vim
Normal file
25
autoload/ale/fixers/yamlfix.vim
Normal file
@@ -0,0 +1,25 @@
|
||||
" Author: lyz-code
|
||||
" Description: Fixing yaml files with yamlfix.
|
||||
|
||||
call ale#Set('yaml_yamlfix_executable', 'yamlfix')
|
||||
call ale#Set('yaml_yamlfix_options', '')
|
||||
call ale#Set('yaml_yamlfix_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
|
||||
function! ale#fixers#yamlfix#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options')
|
||||
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'yaml_yamlfix',
|
||||
\ ['yamlfix'],
|
||||
\)
|
||||
|
||||
if !executable(l:executable)
|
||||
return 0
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\}
|
||||
endfunction
|
||||
91
autoload/ale/floating_preview.vim
Normal file
91
autoload/ale/floating_preview.vim
Normal file
@@ -0,0 +1,91 @@
|
||||
" Author: Jan-Grimo Sobez <jan-grimo.sobez@phys.chem.ethz.ch>
|
||||
" Author: Kevin Clark <kevin.clark@gmail.com>
|
||||
" Description: Floating preview window for showing whatever information in.
|
||||
|
||||
" Precondition: exists('*nvim_open_win')
|
||||
|
||||
function! ale#floating_preview#Show(lines, ...) abort
|
||||
if !exists('*nvim_open_win')
|
||||
execute 'echom ''Floating windows not supported in this vim instance.'''
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
" Remove the close autocmd so it doesn't happen mid update
|
||||
augroup ale_floating_preview_window
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
let l:options = get(a:000, 0, {})
|
||||
|
||||
" Only create a new window if we need it
|
||||
if !exists('w:preview') || index(nvim_list_wins(), w:preview['id']) is# -1
|
||||
call s:Create(l:options)
|
||||
else
|
||||
call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:true)
|
||||
endif
|
||||
|
||||
" Execute commands in window context
|
||||
let l:parent_window = nvim_get_current_win()
|
||||
|
||||
call nvim_set_current_win(w:preview['id'])
|
||||
|
||||
for l:command in get(l:options, 'commands', [])
|
||||
call execute(l:command)
|
||||
endfor
|
||||
|
||||
call nvim_set_current_win(l:parent_window)
|
||||
|
||||
" Return to parent context on move
|
||||
augroup ale_floating_preview_window
|
||||
autocmd!
|
||||
|
||||
if g:ale_close_preview_on_insert
|
||||
autocmd CursorMoved,TabLeave,WinLeave,InsertEnter <buffer> ++once call s:Close()
|
||||
else
|
||||
autocmd CursorMoved,TabLeave,WinLeave <buffer> ++once call s:Close()
|
||||
endif
|
||||
augroup END
|
||||
|
||||
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
|
||||
let l:height = min([len(a:lines), 10])
|
||||
call nvim_win_set_width(w:preview['id'], l:width)
|
||||
call nvim_win_set_height(w:preview['id'], l:height)
|
||||
|
||||
call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, a:lines)
|
||||
call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false)
|
||||
call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false)
|
||||
endfunction
|
||||
|
||||
function! s:Create(options) abort
|
||||
let l:buffer = nvim_create_buf(v:false, v:false)
|
||||
let l:winid = nvim_open_win(l:buffer, v:false, {
|
||||
\ 'relative': 'cursor',
|
||||
\ 'row': 1,
|
||||
\ 'col': 0,
|
||||
\ 'width': 42,
|
||||
\ 'height': 4,
|
||||
\ 'style': 'minimal'
|
||||
\ })
|
||||
call nvim_buf_set_option(l:buffer, 'buftype', 'acwrite')
|
||||
call nvim_buf_set_option(l:buffer, 'bufhidden', 'delete')
|
||||
call nvim_buf_set_option(l:buffer, 'swapfile', v:false)
|
||||
call nvim_buf_set_option(l:buffer, 'filetype', get(a:options, 'filetype', 'ale-preview'))
|
||||
|
||||
let w:preview = {'id': l:winid, 'buffer': l:buffer}
|
||||
endfunction
|
||||
|
||||
function! s:Close() abort
|
||||
if !exists('w:preview')
|
||||
return
|
||||
endif
|
||||
|
||||
call setbufvar(w:preview['buffer'], '&modified', 0)
|
||||
|
||||
if win_id2win(w:preview['id']) > 0
|
||||
execute win_id2win(w:preview['id']).'wincmd c'
|
||||
endif
|
||||
|
||||
unlet w:preview
|
||||
endfunction
|
||||
|
||||
41
autoload/ale/handlers/atools.vim
Normal file
41
autoload/ale/handlers/atools.vim
Normal file
@@ -0,0 +1,41 @@
|
||||
" Author: Leo <thinkabit.ukim@gmail.com>
|
||||
" Description: Handlers for output expected from atools
|
||||
|
||||
function! ale#handlers#atools#Handle(buffer, lines) abort
|
||||
" Format: SEVERITY:[TAG]:PATH:LINENUM:MSG
|
||||
" Example: MC:[AL5]:./APKBUILD:12:variable set to empty string: install=
|
||||
let l:pattern = '\([^:]\+\):\([^:]\+\):\([^:]\+\):\(\d\+\):\(.\+\)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
" We are expected to receive 2 characters, the first character
|
||||
" can be 'S', 'I', 'M' 'T', which are respectively:
|
||||
" Serious (Error)
|
||||
" Important (Error)
|
||||
" Minor (Warning)
|
||||
" Style (Warning)
|
||||
"
|
||||
" The second character can be either 'C' or 'P', which are respectively:
|
||||
" Certain (Error)
|
||||
" Possible (Warning)
|
||||
let l:severity = matchstr(l:match[1], '^.')
|
||||
let l:certainty = matchstr(l:match[1], '.$')
|
||||
|
||||
let l:type = 'E'
|
||||
" If the tag returns 'Minor' or 'Style' or is 'Possible'
|
||||
" then return a warning
|
||||
|
||||
if l:severity is# 'M' || l:severity is# 'T' || l:certainty is# 'P'
|
||||
let l:type = 'W'
|
||||
endif
|
||||
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[4] + 0,
|
||||
\ 'text': l:match[5],
|
||||
\ 'type': l:type,
|
||||
\ 'code': matchstr(l:match[2], 'AL[0-9]*'),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
52
autoload/ale/handlers/deno.vim
Normal file
52
autoload/ale/handlers/deno.vim
Normal file
@@ -0,0 +1,52 @@
|
||||
" Author: Mohammed Chelouti - https://github.com/motato1
|
||||
" Description: Handler functions for Deno.
|
||||
|
||||
call ale#Set('deno_executable', 'deno')
|
||||
call ale#Set('deno_unstable', 0)
|
||||
call ale#Set('deno_lsp_project_root', '')
|
||||
|
||||
function! ale#handlers#deno#GetExecutable(buffer) abort
|
||||
return ale#Var(a:buffer, 'deno_executable')
|
||||
endfunction
|
||||
|
||||
" Find project root for Deno's language server.
|
||||
"
|
||||
" Deno projects do not require a project or configuration file at the project root.
|
||||
" This means the root directory has to be guessed,
|
||||
" unless it is explicitly specified by the user.
|
||||
"
|
||||
" The project root is determined by ...
|
||||
" 1. using a user-specified value from deno_lsp_project_root
|
||||
" 2. looking for common top-level files/dirs
|
||||
" 3. using the buffer's directory
|
||||
function! ale#handlers#deno#GetProjectRoot(buffer) abort
|
||||
let l:project_root = ale#Var(a:buffer, 'deno_lsp_project_root')
|
||||
|
||||
if !empty(l:project_root)
|
||||
return l:project_root
|
||||
endif
|
||||
|
||||
let l:possible_project_roots = [
|
||||
\ 'tsconfig.json',
|
||||
\ '.git',
|
||||
\ bufname(a:buffer),
|
||||
\]
|
||||
|
||||
for l:possible_root in l:possible_project_roots
|
||||
let l:project_root = ale#path#FindNearestFile(a:buffer, l:possible_root)
|
||||
|
||||
if empty(l:project_root)
|
||||
let l:project_root = ale#path#FindNearestDirectory(a:buffer, l:possible_root)
|
||||
endif
|
||||
|
||||
if !empty(l:project_root)
|
||||
" dir:p expands to /full/path/to/dir/ whereas
|
||||
" file:p expands to /full/path/to/file (no trailing slash)
|
||||
" Appending '/' ensures that :h:h removes the path's last segment
|
||||
" regardless of whether it is a directory or not.
|
||||
return fnamemodify(l:project_root . '/', ':p:h:h')
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
@@ -5,6 +5,7 @@ let s:executables = [
|
||||
\ 'node_modules/.bin/eslint_d',
|
||||
\ 'node_modules/eslint/bin/eslint.js',
|
||||
\ 'node_modules/.bin/eslint',
|
||||
\ '.yarn/sdks/eslint/bin/eslint',
|
||||
\]
|
||||
let s:sep = has('win32') ? '\' : '/'
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ function! ale#handlers#hdl_checker#GetProjectRoot(buffer) abort
|
||||
if ale#handlers#hdl_checker#IsDotGit(l:project_root)
|
||||
return fnamemodify(l:project_root, ':h:h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#hdl_checker#GetExecutable(buffer) abort
|
||||
|
||||
37
autoload/ale/handlers/inko.vim
Normal file
37
autoload/ale/handlers/inko.vim
Normal file
@@ -0,0 +1,37 @@
|
||||
" Author: Yorick Peterse <yorick@yorickpeterse.com>
|
||||
" Description: output handlers for the Inko JSON format
|
||||
|
||||
function! ale#handlers#inko#GetType(severity) abort
|
||||
if a:severity is? 'warning'
|
||||
return 'W'
|
||||
endif
|
||||
|
||||
return 'E'
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#inko#Handle(buffer, lines) abort
|
||||
try
|
||||
let l:errors = json_decode(join(a:lines, ''))
|
||||
catch
|
||||
return []
|
||||
endtry
|
||||
|
||||
if empty(l:errors)
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:output = []
|
||||
let l:dir = expand('#' . a:buffer . ':p:h')
|
||||
|
||||
for l:error in l:errors
|
||||
call add(l:output, {
|
||||
\ 'filename': ale#path#GetAbsPath(l:dir, l:error['file']),
|
||||
\ 'lnum': l:error['line'],
|
||||
\ 'col': l:error['column'],
|
||||
\ 'text': l:error['message'],
|
||||
\ 'type': ale#handlers#inko#GetType(l:error['level']),
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
@@ -1,18 +1,28 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
|
||||
" Get the shell type for a buffer, based on the hashbang line.
|
||||
function! ale#handlers#sh#GetShellType(buffer) abort
|
||||
let l:bang_line = get(getbufline(a:buffer, 1), 0, '')
|
||||
let l:shebang = get(getbufline(a:buffer, 1), 0, '')
|
||||
|
||||
let l:command = ''
|
||||
|
||||
" Take the shell executable from the hashbang, if we can.
|
||||
if l:bang_line[:1] is# '#!'
|
||||
" Take the shell executable from the shebang, if we can.
|
||||
if l:shebang[:1] is# '#!'
|
||||
" Remove options like -e, etc.
|
||||
let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g')
|
||||
let l:command = substitute(l:shebang, ' --\?[a-zA-Z0-9]\+', '', 'g')
|
||||
endif
|
||||
|
||||
" If we couldn't find a hashbang, try the filetype
|
||||
" With no shebang line, attempt to use Vim's buffer-local variables.
|
||||
if l:command is# ''
|
||||
if getbufvar(a:buffer, 'is_bash', 0)
|
||||
let l:command = 'bash'
|
||||
elseif getbufvar(a:buffer, 'is_sh', 0)
|
||||
let l:command = 'sh'
|
||||
elseif getbufvar(a:buffer, 'is_kornshell', 0)
|
||||
let l:command = 'ksh'
|
||||
endif
|
||||
endif
|
||||
|
||||
" If we couldn't find a shebang, try the filetype
|
||||
if l:command is# ''
|
||||
let l:command = &filetype
|
||||
endif
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
" Author: w0rp <devw0rp@gmail.com>
|
||||
" Description: This file adds support for using the shellcheck linter
|
||||
|
||||
" Shellcheck supports shell directives to define the shell dialect for scripts
|
||||
" that do not have a shebang for some reason.
|
||||
" https://github.com/koalaman/shellcheck/wiki/Directive#shell
|
||||
function! ale#handlers#shellcheck#GetShellcheckDialectDirective(buffer) abort
|
||||
let l:linenr = 0
|
||||
let l:pattern = '\s\{-}#\s\{-}shellcheck\s\{-}shell=\(.*\)'
|
||||
let l:possible_shell = ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh']
|
||||
|
||||
while l:linenr < min([50, line('$')])
|
||||
let l:linenr += 1
|
||||
let l:match = matchlist(getline(l:linenr), l:pattern)
|
||||
|
||||
if len(l:match) > 1 && index(l:possible_shell, l:match[1]) >= 0
|
||||
return l:match[1]
|
||||
endif
|
||||
endwhile
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort
|
||||
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
|
||||
let l:shell_type = ale#handlers#shellcheck#GetShellcheckDialectDirective(a:buffer)
|
||||
|
||||
if empty(l:shell_type)
|
||||
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
|
||||
endif
|
||||
|
||||
if !empty(l:shell_type)
|
||||
" Use the dash dialect for /bin/ash, etc.
|
||||
@@ -13,15 +37,6 @@ function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort
|
||||
return l:shell_type
|
||||
endif
|
||||
|
||||
" If there's no hashbang, try using Vim's buffer variables.
|
||||
if getbufvar(a:buffer, 'is_bash', 0)
|
||||
return 'bash'
|
||||
elseif getbufvar(a:buffer, 'is_sh', 0)
|
||||
return 'sh'
|
||||
elseif getbufvar(a:buffer, 'is_kornshell', 0)
|
||||
return 'ksh'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
|
||||
31
autoload/ale/handlers/spectral.vim
Normal file
31
autoload/ale/handlers/spectral.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Author: t2h5 <https://github.com/t2h5>
|
||||
" Description: Integration of Stoplight Spectral CLI with ALE.
|
||||
|
||||
function! ale#handlers#spectral#HandleSpectralOutput(buffer, lines) abort
|
||||
" Matches patterns like the following:
|
||||
" openapi.yml:1:1 error oas3-schema "Object should have required property `info`."
|
||||
" openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array."
|
||||
let l:pattern = '\v^.*:(\d+):(\d+) (error|warning) (.*)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:obj = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
|
||||
\ 'text': l:match[4],
|
||||
\}
|
||||
|
||||
let l:code_match = matchlist(l:obj.text, '\v^(.+) "(.+)"$')
|
||||
|
||||
if !empty(l:code_match)
|
||||
let l:obj.code = l:code_match[1]
|
||||
let l:obj.text = l:code_match[2]
|
||||
endif
|
||||
|
||||
call add(l:output, l:obj)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
44
autoload/ale/handlers/xo.vim
Normal file
44
autoload/ale/handlers/xo.vim
Normal file
@@ -0,0 +1,44 @@
|
||||
call ale#Set('javascript_xo_executable', 'xo')
|
||||
call ale#Set('javascript_xo_use_global', get(g:, 'ale_use_global_executables', 0))
|
||||
call ale#Set('javascript_xo_options', '')
|
||||
|
||||
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#handlers#xo#GetExecutable(buffer) abort
|
||||
let l:type = ale#handlers#xo#GetType(a:buffer)
|
||||
|
||||
return ale#node#FindExecutable(a:buffer, l:type . '_xo', [
|
||||
\ 'node_modules/xo/cli.js',
|
||||
\ 'node_modules/.bin/xo',
|
||||
\])
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#xo#GetLintCommand(buffer) abort
|
||||
return ale#Escape(ale#handlers#xo#GetExecutable(a:buffer))
|
||||
\ . ale#Pad(ale#handlers#xo#GetOptions(a:buffer))
|
||||
\ . ' --reporter json --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#xo#GetOptions(buffer) abort
|
||||
let l:type = ale#handlers#xo#GetType(a:buffer)
|
||||
|
||||
return ale#Var(a:buffer, l:type . '_xo_options')
|
||||
endfunction
|
||||
|
||||
" xo uses eslint and the output format is the same
|
||||
function! ale#handlers#xo#HandleJSON(buffer, lines) abort
|
||||
return ale#handlers#eslint#HandleJSON(a:buffer, a:lines)
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#xo#GetType(buffer) abort
|
||||
let l:filetype = getbufvar(a:buffer, '&filetype')
|
||||
let l:type = 'javascript'
|
||||
|
||||
if l:filetype =~# 'typescript'
|
||||
let l:type = 'typescript'
|
||||
endif
|
||||
|
||||
return l:type
|
||||
endfunction
|
||||
39
autoload/ale/handlers/yamllint.vim
Normal file
39
autoload/ale/handlers/yamllint.vim
Normal file
@@ -0,0 +1,39 @@
|
||||
function! ale#handlers#yamllint#GetCommand(buffer) abort
|
||||
return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_yamllint_options'))
|
||||
\ . ' -f parsable %t'
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#yamllint#Handle(buffer, lines) abort
|
||||
" Matches patterns line the following:
|
||||
" something.yaml:1:1: [warning] missing document start "---" (document-start)
|
||||
" something.yml:2:1: [error] syntax error: expected the node content, but found '<stream end>'
|
||||
let l:pattern = '\v^.*:(\d+):(\d+): \[(error|warning)\] (.+)$'
|
||||
let l:output = []
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:pattern)
|
||||
let l:item = {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[4],
|
||||
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
|
||||
\}
|
||||
|
||||
let l:code_match = matchlist(l:item.text, '\v^(.+) \(([^)]+)\)$')
|
||||
|
||||
if !empty(l:code_match)
|
||||
if l:code_match[2] is# 'trailing-spaces'
|
||||
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
|
||||
" Skip warnings for trailing whitespace if the option is off.
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:item.text = l:code_match[1]
|
||||
let l:item.code = l:code_match[2]
|
||||
endif
|
||||
|
||||
call add(l:output, l:item)
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
@@ -24,6 +24,8 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
|
||||
|
||||
if get(a:response, 'success', v:false) is v:true
|
||||
\&& get(a:response, 'body', v:null) isnot v:null
|
||||
let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons')
|
||||
|
||||
" If we pass the show_documentation flag, we should show the full
|
||||
" documentation, and always in the preview window.
|
||||
if get(l:options, 'show_documentation', 0)
|
||||
@@ -40,10 +42,14 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
|
||||
endif
|
||||
elseif get(l:options, 'hover_from_balloonexpr', 0)
|
||||
\&& exists('*balloon_show')
|
||||
\&& ale#Var(l:options.buffer, 'set_balloons')
|
||||
\&& (l:set_balloons is 1 || l:set_balloons is# 'hover')
|
||||
call balloon_show(a:response.body.displayString)
|
||||
elseif get(l:options, 'truncated_echo', 0)
|
||||
call ale#cursor#TruncatedEcho(split(a:response.body.displayString, "\n")[0])
|
||||
elseif g:ale_hover_to_floating_preview || g:ale_floating_preview
|
||||
call ale#floating_preview#Show(split(a:response.body.displayString, "\n"), {
|
||||
\ 'filetype': 'ale-preview.message',
|
||||
\})
|
||||
elseif g:ale_hover_to_preview
|
||||
call ale#preview#Show(split(a:response.body.displayString, "\n"), {
|
||||
\ 'filetype': 'ale-preview.message',
|
||||
@@ -216,12 +222,19 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
|
||||
let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents)
|
||||
|
||||
if !empty(l:lines)
|
||||
let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons')
|
||||
|
||||
if get(l:options, 'hover_from_balloonexpr', 0)
|
||||
\&& exists('*balloon_show')
|
||||
\&& ale#Var(l:options.buffer, 'set_balloons')
|
||||
\&& (l:set_balloons is 1 || l:set_balloons is# 'hover')
|
||||
call balloon_show(join(l:lines, "\n"))
|
||||
elseif get(l:options, 'truncated_echo', 0)
|
||||
call ale#cursor#TruncatedEcho(l:lines[0])
|
||||
elseif g:ale_hover_to_floating_preview || g:ale_floating_preview
|
||||
call ale#floating_preview#Show(l:lines, {
|
||||
\ 'filetype': 'ale-preview.message',
|
||||
\ 'commands': l:commands,
|
||||
\})
|
||||
elseif g:ale_hover_to_preview
|
||||
call ale#preview#Show(l:lines, {
|
||||
\ 'filetype': 'ale-preview.message',
|
||||
|
||||
@@ -38,11 +38,13 @@ let s:default_ale_linter_aliases = {
|
||||
"
|
||||
" NOTE: Update the g:ale_linters documentation when modifying this.
|
||||
let s:default_ale_linters = {
|
||||
\ 'apkbuild': ['apkbuild_lint', 'secfixes_check'],
|
||||
\ 'csh': ['shell'],
|
||||
\ 'elixir': ['credo', 'dialyxir', 'dogma'],
|
||||
\ 'go': ['gofmt', 'golint', 'go vet'],
|
||||
\ 'hack': ['hack'],
|
||||
\ 'help': [],
|
||||
\ 'inko': ['inko'],
|
||||
\ 'perl': ['perlcritic'],
|
||||
\ 'perl6': [],
|
||||
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
|
||||
|
||||
@@ -20,11 +20,17 @@ endif
|
||||
|
||||
" Return 1 if there is a buffer with buftype == 'quickfix' in bufffer list
|
||||
function! ale#list#IsQuickfixOpen() abort
|
||||
for l:buf in range(1, bufnr('$'))
|
||||
if getbufvar(l:buf, '&buftype') is# 'quickfix'
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
let l:res = getqflist({ 'winid' : winnr() })
|
||||
|
||||
if has_key(l:res, 'winid') && l:res.winid > 0
|
||||
return 1
|
||||
endif
|
||||
|
||||
let l:res = getloclist(0, { 'winid' : winnr() })
|
||||
|
||||
if has_key(l:res, 'winid') && l:res.winid > 0
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
@@ -44,6 +44,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
|
||||
\ 'definition': 0,
|
||||
\ 'typeDefinition': 0,
|
||||
\ 'symbol_search': 0,
|
||||
\ 'code_actions': 0,
|
||||
\ },
|
||||
\}
|
||||
endif
|
||||
@@ -219,6 +220,14 @@ function! s:UpdateCapabilities(conn, capabilities) abort
|
||||
let a:conn.capabilities.rename = 1
|
||||
endif
|
||||
|
||||
if get(a:capabilities, 'codeActionProvider') is v:true
|
||||
let a:conn.capabilities.code_actions = 1
|
||||
endif
|
||||
|
||||
if type(get(a:capabilities, 'codeActionProvider')) is v:t_dict
|
||||
let a:conn.capabilities.code_actions = 1
|
||||
endif
|
||||
|
||||
if !empty(get(a:capabilities, 'completionProvider'))
|
||||
let a:conn.capabilities.completion = 1
|
||||
endif
|
||||
@@ -350,6 +359,7 @@ function! ale#lsp#MarkConnectionAsTsserver(conn_id) abort
|
||||
let l:conn.capabilities.definition = 1
|
||||
let l:conn.capabilities.symbol_search = 1
|
||||
let l:conn.capabilities.rename = 1
|
||||
let l:conn.capabilities.code_actions = 1
|
||||
endfunction
|
||||
|
||||
function! s:SendInitMessage(conn) abort
|
||||
|
||||
@@ -172,3 +172,25 @@ function! ale#lsp#message#Rename(buffer, line, column, new_name) abort
|
||||
\ 'newName': a:new_name,
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#message#CodeAction(buffer, line, column, end_line, end_column, diagnostics) abort
|
||||
return [0, 'textDocument/codeAction', {
|
||||
\ 'textDocument': {
|
||||
\ 'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')),
|
||||
\ },
|
||||
\ 'range': {
|
||||
\ 'start': {'line': a:line - 1, 'character': a:column - 1},
|
||||
\ 'end': {'line': a:end_line - 1, 'character': a:end_column},
|
||||
\ },
|
||||
\ 'context': {
|
||||
\ 'diagnostics': a:diagnostics
|
||||
\ },
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#message#ExecuteCommand(command, arguments) abort
|
||||
return [0, 'workspace/executeCommand', {
|
||||
\ 'command': a:command,
|
||||
\ 'arguments': a:arguments,
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
@@ -56,6 +56,7 @@ function! ale#lsp#response#ReadDiagnostics(response) abort
|
||||
endif
|
||||
|
||||
if has_key(l:diagnostic, 'relatedInformation')
|
||||
\ && l:diagnostic.relatedInformation isnot v:null
|
||||
let l:related = deepcopy(l:diagnostic.relatedInformation)
|
||||
call map(l:related, {key, val ->
|
||||
\ ale#path#FromURI(val.location.uri) .
|
||||
|
||||
@@ -103,3 +103,39 @@ function! ale#lsp#tsserver_message#OrganizeImports(buffer) abort
|
||||
\ },
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#tsserver_message#GetCodeFixes(buffer, line, column, end_line, end_column, error_codes) abort
|
||||
" The lines and columns are 1-based.
|
||||
" The errors codes must be a list of tsserver error codes to fix.
|
||||
return [0, 'ts@getCodeFixes', {
|
||||
\ 'startLine': a:line,
|
||||
\ 'startOffset': a:column,
|
||||
\ 'endLine': a:end_line,
|
||||
\ 'endOffset': a:end_column + 1,
|
||||
\ 'file': expand('#' . a:buffer . ':p'),
|
||||
\ 'errorCodes': a:error_codes,
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#tsserver_message#GetApplicableRefactors(buffer, line, column, end_line, end_column) abort
|
||||
" The arguments for this request can also be just 'line' and 'offset'
|
||||
return [0, 'ts@getApplicableRefactors', {
|
||||
\ 'startLine': a:line,
|
||||
\ 'startOffset': a:column,
|
||||
\ 'endLine': a:end_line,
|
||||
\ 'endOffset': a:end_column + 1,
|
||||
\ 'file': expand('#' . a:buffer . ':p'),
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#tsserver_message#GetEditsForRefactor(buffer, line, column, end_line, end_column, refactor, action) abort
|
||||
return [0, 'ts@getEditsForRefactor', {
|
||||
\ 'startLine': a:line,
|
||||
\ 'startOffset': a:column,
|
||||
\ 'endLine': a:end_line,
|
||||
\ 'endOffset': a:end_column + 1,
|
||||
\ 'file': expand('#' . a:buffer . ':p'),
|
||||
\ 'refactor': a:refactor,
|
||||
\ 'action': a:action,
|
||||
\}]
|
||||
endfunction
|
||||
|
||||
@@ -85,12 +85,18 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
|
||||
endif
|
||||
|
||||
let l:info.syntax_loclist = l:thislist
|
||||
else
|
||||
elseif a:error_type is# 'semantic'
|
||||
if len(l:thislist) is 0 && len(get(l:info, 'semantic_loclist', [])) is 0
|
||||
let l:no_changes = 1
|
||||
endif
|
||||
|
||||
let l:info.semantic_loclist = l:thislist
|
||||
else
|
||||
if len(l:thislist) is 0 && len(get(l:info, 'suggestion_loclist', [])) is 0
|
||||
let l:no_changes = 1
|
||||
endif
|
||||
|
||||
let l:info.suggestion_loclist = l:thislist
|
||||
endif
|
||||
|
||||
if l:no_changes
|
||||
@@ -98,6 +104,7 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
|
||||
endif
|
||||
|
||||
let l:loclist = get(l:info, 'semantic_loclist', [])
|
||||
\ + get(l:info, 'suggestion_loclist', [])
|
||||
\ + get(l:info, 'syntax_loclist', [])
|
||||
|
||||
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
|
||||
@@ -150,6 +157,10 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'syntaxDiag'
|
||||
call s:HandleTSServerDiagnostics(a:response, 'syntax')
|
||||
elseif get(a:response, 'type', '') is# 'event'
|
||||
\&& get(a:response, 'event', '') is# 'suggestionDiag'
|
||||
\&& get(g:, 'ale_lsp_suggestions', '1') == 1
|
||||
call s:HandleTSServerDiagnostics(a:response, 'suggestion')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
51
autoload/ale/maven.vim
Normal file
51
autoload/ale/maven.vim
Normal file
@@ -0,0 +1,51 @@
|
||||
" Description: Functions for working with Maven projects.
|
||||
"
|
||||
" Given a buffer number, find a Maven project root.
|
||||
function! ale#maven#FindProjectRoot(buffer) abort
|
||||
let l:wrapper_path = ale#path#FindNearestFile(a:buffer, 'mvnw')
|
||||
|
||||
if !empty(l:wrapper_path)
|
||||
return fnamemodify(l:wrapper_path, ':h')
|
||||
endif
|
||||
|
||||
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
|
||||
|
||||
if !empty(l:pom_path)
|
||||
return fnamemodify(l:pom_path, ':h')
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
|
||||
" Given a buffer number, find the path to the executable.
|
||||
" First search on the path for 'mvnw' (mvnw.cmd on Windows), if nothing is found,
|
||||
" try the global command. Returns an empty string if cannot find the executable.
|
||||
function! ale#maven#FindExecutable(buffer) abort
|
||||
let l:wrapper_cmd = has('unix') ? 'mvnw' : 'mvnw.cmd'
|
||||
let l:wrapper_path = ale#path#FindNearestFile(a:buffer, l:wrapper_cmd)
|
||||
|
||||
if !empty(l:wrapper_path) && executable(l:wrapper_path)
|
||||
return l:wrapper_path
|
||||
endif
|
||||
|
||||
if executable('mvn')
|
||||
return 'mvn'
|
||||
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#maven#BuildClasspathCommand(buffer) abort
|
||||
let l:executable = ale#maven#FindExecutable(a:buffer)
|
||||
let l:project_root = ale#maven#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:executable) && !empty(l:project_root)
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . l:executable . ' dependency:build-classpath'
|
||||
endif
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
@@ -12,10 +12,13 @@ function! ale#organize_imports#HandleTSServerResponse(conn_id, response) abort
|
||||
|
||||
let l:file_code_edits = a:response.body
|
||||
|
||||
call ale#code_action#HandleCodeAction({
|
||||
\ 'description': 'Organize Imports',
|
||||
\ 'changes': l:file_code_edits,
|
||||
\}, v:false)
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'Organize Imports',
|
||||
\ 'changes': l:file_code_edits,
|
||||
\ },
|
||||
\ {}
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! s:OnReady(linter, lsp_details) abort
|
||||
|
||||
@@ -32,6 +32,8 @@ function! ale#python#FindProjectRootIni(buffer) abort
|
||||
\|| filereadable(l:path . '/.pylintrc')
|
||||
\|| filereadable(l:path . '/Pipfile')
|
||||
\|| filereadable(l:path . '/Pipfile.lock')
|
||||
\|| filereadable(l:path . '/poetry.lock')
|
||||
\|| filereadable(l:path . '/pyproject.toml')
|
||||
return l:path
|
||||
endif
|
||||
endfor
|
||||
|
||||
@@ -33,9 +33,10 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:old_name = s:rename_map[a:response.request_seq].old_name
|
||||
let l:new_name = s:rename_map[a:response.request_seq].new_name
|
||||
call remove(s:rename_map, a:response.request_seq)
|
||||
let l:options = remove(s:rename_map, a:response.request_seq)
|
||||
|
||||
let l:old_name = l:options.old_name
|
||||
let l:new_name = l:options.new_name
|
||||
|
||||
if get(a:response, 'success', v:false) is v:false
|
||||
let l:message = get(a:response, 'message', 'unknown')
|
||||
@@ -77,41 +78,21 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
|
||||
return
|
||||
endif
|
||||
|
||||
call ale#code_action#HandleCodeAction({
|
||||
\ 'description': 'rename',
|
||||
\ 'changes': l:changes,
|
||||
\}, v:true)
|
||||
endfunction
|
||||
|
||||
function! s:getChanges(workspace_edit) abort
|
||||
let l:changes = {}
|
||||
|
||||
if has_key(a:workspace_edit, 'changes') && !empty(a:workspace_edit.changes)
|
||||
return a:workspace_edit.changes
|
||||
elseif has_key(a:workspace_edit, 'documentChanges')
|
||||
let l:document_changes = []
|
||||
|
||||
if type(a:workspace_edit.documentChanges) is v:t_dict
|
||||
\ && has_key(a:workspace_edit.documentChanges, 'edits')
|
||||
call add(l:document_changes, a:workspace_edit.documentChanges)
|
||||
elseif type(a:workspace_edit.documentChanges) is v:t_list
|
||||
let l:document_changes = a:workspace_edit.documentChanges
|
||||
endif
|
||||
|
||||
for l:text_document_edit in l:document_changes
|
||||
let l:filename = l:text_document_edit.textDocument.uri
|
||||
let l:edits = l:text_document_edit.edits
|
||||
let l:changes[l:filename] = l:edits
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:changes
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'rename',
|
||||
\ 'changes': l:changes,
|
||||
\ },
|
||||
\ {
|
||||
\ 'should_save': 1,
|
||||
\ },
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! ale#rename#HandleLSPResponse(conn_id, response) abort
|
||||
if has_key(a:response, 'id')
|
||||
\&& has_key(s:rename_map, a:response.id)
|
||||
call remove(s:rename_map, a:response.id)
|
||||
let l:options = remove(s:rename_map, a:response.id)
|
||||
|
||||
if !has_key(a:response, 'result')
|
||||
call s:message('No rename result received from server')
|
||||
@@ -119,7 +100,7 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:changes_map = s:getChanges(a:response.result)
|
||||
let l:changes_map = ale#code_action#GetChanges(a:response.result)
|
||||
|
||||
if empty(l:changes_map)
|
||||
call s:message('No changes received from server')
|
||||
@@ -127,43 +108,21 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:changes = []
|
||||
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
|
||||
|
||||
for l:file_name in keys(l:changes_map)
|
||||
let l:text_edits = l:changes_map[l:file_name]
|
||||
let l:text_changes = []
|
||||
|
||||
for l:edit in l:text_edits
|
||||
let l:range = l:edit.range
|
||||
let l:new_text = l:edit.newText
|
||||
|
||||
call add(l:text_changes, {
|
||||
\ 'start': {
|
||||
\ 'line': l:range.start.line + 1,
|
||||
\ 'offset': l:range.start.character + 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:range.end.line + 1,
|
||||
\ 'offset': l:range.end.character + 1,
|
||||
\ },
|
||||
\ 'newText': l:new_text,
|
||||
\})
|
||||
endfor
|
||||
|
||||
call add(l:changes, {
|
||||
\ 'fileName': ale#path#FromURI(l:file_name),
|
||||
\ 'textChanges': l:text_changes,
|
||||
\})
|
||||
endfor
|
||||
|
||||
call ale#code_action#HandleCodeAction({
|
||||
\ 'description': 'rename',
|
||||
\ 'changes': l:changes,
|
||||
\}, v:true)
|
||||
call ale#code_action#HandleCodeAction(
|
||||
\ {
|
||||
\ 'description': 'rename',
|
||||
\ 'changes': l:changes,
|
||||
\ },
|
||||
\ {
|
||||
\ 'should_save': 1,
|
||||
\ },
|
||||
\)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:OnReady(line, column, old_name, new_name, linter, lsp_details) abort
|
||||
function! s:OnReady(line, column, options, linter, lsp_details) abort
|
||||
let l:id = a:lsp_details.connection_id
|
||||
|
||||
if !ale#lsp#HasCapability(l:id, 'rename')
|
||||
@@ -195,19 +154,16 @@ function! s:OnReady(line, column, old_name, new_name, linter, lsp_details) abort
|
||||
\ l:buffer,
|
||||
\ a:line,
|
||||
\ a:column,
|
||||
\ a:new_name
|
||||
\ a:options.new_name
|
||||
\)
|
||||
endif
|
||||
|
||||
let l:request_id = ale#lsp#Send(l:id, l:message)
|
||||
|
||||
let s:rename_map[l:request_id] = {
|
||||
\ 'new_name': a:new_name,
|
||||
\ 'old_name': a:old_name,
|
||||
\}
|
||||
let s:rename_map[l:request_id] = a:options
|
||||
endfunction
|
||||
|
||||
function! s:ExecuteRename(linter, old_name, new_name) abort
|
||||
function! s:ExecuteRename(linter, options) abort
|
||||
let l:buffer = bufnr('')
|
||||
let [l:line, l:column] = getpos('.')[1:2]
|
||||
|
||||
@@ -215,8 +171,7 @@ function! s:ExecuteRename(linter, old_name, new_name) abort
|
||||
let l:column = min([l:column, len(getline(l:line))])
|
||||
endif
|
||||
|
||||
let l:Callback = function(
|
||||
\ 's:OnReady', [l:line, l:column, a:old_name, a:new_name])
|
||||
let l:Callback = function('s:OnReady', [l:line, l:column, a:options])
|
||||
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
|
||||
endfunction
|
||||
|
||||
@@ -245,6 +200,9 @@ function! ale#rename#Execute() abort
|
||||
endif
|
||||
|
||||
for l:lsp_linter in l:lsp_linters
|
||||
call s:ExecuteRename(l:lsp_linter, l:old_name, l:new_name)
|
||||
call s:ExecuteRename(l:lsp_linter, {
|
||||
\ 'old_name': l:old_name,
|
||||
\ 'new_name': l:new_name,
|
||||
\})
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user