summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml36
-rw-r--r--.travis.yml16
-rw-r--r--Dockerfile10
-rw-r--r--README.md26
-rw-r--r--ale_linters/ada/adals.vim26
-rw-r--r--ale_linters/apkbuild/apkbuild_lint.vim12
-rw-r--r--ale_linters/apkbuild/secfixes_check.vim12
-rw-r--r--ale_linters/cloudformation/cfn_python_lint.vim1
-rw-r--r--ale_linters/cpp/clangtidy.vim10
-rw-r--r--ale_linters/dafny/dafny.vim19
-rw-r--r--ale_linters/dart/analysis_server.vim29
-rw-r--r--ale_linters/dockerfile/hadolint.vim18
-rw-r--r--ale_linters/elixir/credo.vim11
-rw-r--r--ale_linters/erlang/dialyzer.vim12
-rw-r--r--ale_linters/erlang/elvis.vim39
-rw-r--r--ale_linters/erlang/erlc.vim16
-rw-r--r--ale_linters/haskell/hls.vim63
-rw-r--r--ale_linters/inko/inko.vim33
-rw-r--r--ale_linters/java/checkstyle.vim2
-rw-r--r--ale_linters/java/eclipselsp.vim8
-rw-r--r--ale_linters/javascript/xo.vim23
-rw-r--r--ale_linters/json/spectral.vim14
-rw-r--r--ale_linters/julia/languageserver.vim4
-rw-r--r--ale_linters/nix/nix.vim57
-rw-r--r--ale_linters/nix/rnix_lsp.vim16
-rw-r--r--ale_linters/openapi/ibm_validator.vim58
-rw-r--r--ale_linters/openapi/yamllint.vim9
-rw-r--r--ale_linters/perl6/perl6.vim2
-rwxr-xr-xale_linters/php/intelephense.vim32
-rw-r--r--ale_linters/php/phpcs.vim2
-rw-r--r--ale_linters/php/tlint.vim80
-rw-r--r--ale_linters/prolog/swipl.vim16
-rw-r--r--ale_linters/python/jedils.vim34
-rw-r--r--ale_linters/r/languageserver.vim26
-rw-r--r--ale_linters/ruby/sorbet.vim5
-rw-r--r--ale_linters/rust/analyzer.vim2
-rw-r--r--ale_linters/salt/salt_lint.vim33
-rw-r--r--ale_linters/terraform/terraform.vim42
-rw-r--r--ale_linters/terraform/terraform_ls.vim38
-rw-r--r--ale_linters/typescript/deno.vim25
-rw-r--r--ale_linters/typescript/tsserver.vim1
-rw-r--r--ale_linters/typescript/xo.vim23
-rw-r--r--ale_linters/vala/vala_lint.vim66
-rw-r--r--ale_linters/yaml/spectral.vim14
-rw-r--r--ale_linters/yaml/yamllint.vim43
-rw-r--r--autoload/ale/balloon.vim32
-rw-r--r--autoload/ale/c.vim1
-rw-r--r--autoload/ale/code_action.vim243
-rw-r--r--autoload/ale/codefix.vim487
-rw-r--r--autoload/ale/completion.vim8
-rw-r--r--autoload/ale/cursor.vim22
-rw-r--r--autoload/ale/dhall.vim24
-rw-r--r--autoload/ale/fix/registry.vim55
-rw-r--r--autoload/ale/fixers/autoimport.vim25
-rw-r--r--autoload/ale/fixers/deno.vim17
-rw-r--r--autoload/ale/fixers/dhall.vim23
-rw-r--r--autoload/ale/fixers/dhall_format.vim14
-rw-r--r--autoload/ale/fixers/dhall_freeze.vim18
-rw-r--r--autoload/ale/fixers/dhall_lint.vim14
-rw-r--r--autoload/ale/fixers/gofmt.vim3
-rw-r--r--autoload/ale/fixers/isort.vim27
-rw-r--r--autoload/ale/fixers/luafmt.vim13
-rw-r--r--autoload/ale/fixers/ormolu.vim12
-rw-r--r--autoload/ale/fixers/phpcbf.vim3
-rw-r--r--autoload/ale/fixers/prettier.vim1
-rw-r--r--autoload/ale/fixers/standardrb.vim4
-rw-r--r--autoload/ale/fixers/xo.vim37
-rw-r--r--autoload/ale/fixers/yamlfix.vim25
-rw-r--r--autoload/ale/floating_preview.vim91
-rw-r--r--autoload/ale/handlers/atools.vim41
-rw-r--r--autoload/ale/handlers/deno.vim52
-rw-r--r--autoload/ale/handlers/eslint.vim1
-rw-r--r--autoload/ale/handlers/hdl_checker.vim2
-rw-r--r--autoload/ale/handlers/inko.vim37
-rw-r--r--autoload/ale/handlers/sh.vim22
-rw-r--r--autoload/ale/handlers/shellcheck.vim35
-rw-r--r--autoload/ale/handlers/spectral.vim31
-rw-r--r--autoload/ale/handlers/xo.vim44
-rw-r--r--autoload/ale/handlers/yamllint.vim39
-rw-r--r--autoload/ale/hover.vim17
-rw-r--r--autoload/ale/linter.vim2
-rw-r--r--autoload/ale/list.vim16
-rw-r--r--autoload/ale/lsp.vim10
-rw-r--r--autoload/ale/lsp/message.vim22
-rw-r--r--autoload/ale/lsp/response.vim1
-rw-r--r--autoload/ale/lsp/tsserver_message.vim36
-rw-r--r--autoload/ale/lsp_linter.vim13
-rw-r--r--autoload/ale/maven.vim2
-rw-r--r--autoload/ale/python.vim2
-rw-r--r--autoload/ale/rename.vim61
-rw-r--r--autoload/ale/sign.vim3
-rw-r--r--autoload/ale/socket.vim5
-rw-r--r--autoload/ale/util.vim2
-rw-r--r--doc/ale-ada.txt30
-rw-r--r--doc/ale-apkbuild.txt30
-rw-r--r--doc/ale-dafny.txt16
-rw-r--r--doc/ale-dart.txt25
-rw-r--r--doc/ale-development.txt18
-rw-r--r--doc/ale-dhall.txt52
-rw-r--r--doc/ale-elixir.txt7
-rw-r--r--doc/ale-erlang.txt28
-rw-r--r--doc/ale-haskell.txt32
-rw-r--r--doc/ale-inko.txt22
-rw-r--r--doc/ale-json.txt32
-rw-r--r--doc/ale-lua.txt16
-rw-r--r--doc/ale-openapi.txt74
-rw-r--r--doc/ale-php.txt73
-rw-r--r--doc/ale-python.txt39
-rw-r--r--doc/ale-r.txt29
-rw-r--r--doc/ale-ruby.txt10
-rw-r--r--doc/ale-rust.txt4
-rw-r--r--doc/ale-salt.tmt43
-rw-r--r--doc/ale-supported-languages-and-tools.txt58
-rw-r--r--doc/ale-terraform.txt22
-rw-r--r--doc/ale-typescript.txt60
-rw-r--r--doc/ale-vala.txt21
-rw-r--r--doc/ale-yaml.txt70
-rw-r--r--doc/ale.txt159
-rw-r--r--plugin/ale.vim24
-rwxr-xr-xrun-tests92
-rw-r--r--supported-tools.md58
-rw-r--r--test/command_callback/inko_paths/test.inko0
-rw-r--r--test/command_callback/inko_paths/tests/test/test_foo.inko0
-rw-r--r--test/command_callback/php-intelephense-project/with-composer/composer.json0
-rwxr-xr-xtest/command_callback/python_paths/with_virtualenv/env/Scripts/autoimport.exe0
-rw-r--r--test/command_callback/python_paths/with_virtualenv/env/Scripts/yamlfix.exe0
-rwxr-xr-xtest/command_callback/python_paths/with_virtualenv/env/bin/autoimport0
-rwxr-xr-xtest/command_callback/python_paths/with_virtualenv/env/bin/yamlfix0
-rw-r--r--test/command_callback/r_paths/.Rprofile0
-rw-r--r--test/command_callback/spectral_paths/node_modules/.bin/spectral0
-rw-r--r--test/command_callback/spectral_paths/openapi.yaml0
-rw-r--r--test/command_callback/test_adals_command_callbacks.vader17
-rw-r--r--test/command_callback/test_clang_tidy_command_callback.vader1
-rw-r--r--test/command_callback/test_dart_analysis_server_command_callback.vader15
-rw-r--r--test/command_callback/test_elixir_credo.vader7
-rw-r--r--test/command_callback/test_erlang_dialyzer_command_callback.vader8
-rw-r--r--test/command_callback/test_erlang_elvis_command_callback.vader16
-rw-r--r--test/command_callback/test_erlang_erlc_command_callback.vader40
-rw-r--r--test/command_callback/test_fecs_command_callback.vader1
-rw-r--r--test/command_callback/test_haskell_hls_callbacks.vader27
-rw-r--r--test/command_callback/test_ibm_openapi_validator_command_callback.vader15
-rw-r--r--test/command_callback/test_inko_inko_callbacks.vader20
-rw-r--r--test/command_callback/test_julia_languageserver_callbacks.vader8
-rw-r--r--test/command_callback/test_php_intelephense_command_callback.vader26
-rw-r--r--test/command_callback/test_r_languageserver_callbacks.vader22
-rw-r--r--test/command_callback/test_rust_analyzer_callbacks.vader4
-rw-r--r--test/command_callback/test_sorbet_command_callback.vader7
-rw-r--r--test/command_callback/test_spectral_command_callback.vader31
-rw-r--r--test/command_callback/test_terraform_ls_command_callback.vader61
-rw-r--r--test/command_callback/test_terraform_terraform_command_callback.vader8
-rw-r--r--test/command_callback/test_typescript_deno_lsp.vader60
-rw-r--r--test/command_callback/test_xo_command_callback.vader11
-rw-r--r--test/command_callback/test_xots_command_callback.vader23
-rw-r--r--test/completion/test_lsp_completion_parsing.vader91
-rw-r--r--test/completion/test_omnifunc_completion.vader6
-rw-r--r--test/dumb_named_pipe_server.py42
-rw-r--r--test/eslint-test-files/react-app/node_modules/xo/cli.js0
-rw-r--r--test/eslint-test-files/react-app/subdir/testfile.ts0
-rw-r--r--test/fixers/test_autoimport_fixer_callback.vader50
-rw-r--r--test/fixers/test_dhall_fixer_callback.vader11
-rw-r--r--test/fixers/test_dhall_format_fixer_callback.vader24
-rw-r--r--test/fixers/test_dhall_freeze_fixer_callback.vader24
-rw-r--r--test/fixers/test_dhall_lint_fixer_callback.vader22
-rw-r--r--test/fixers/test_gofmt_fixer_callback.vader14
-rw-r--r--test/fixers/test_isort_fixer_callback.vader10
-rw-r--r--test/fixers/test_luafmt_fixer_callback.vader35
-rw-r--r--test/fixers/test_ormolu_fixer_callback.vader24
-rw-r--r--test/fixers/test_phpcbf_fixer_callback.vader11
-rw-r--r--test/fixers/test_standardrb_fixer_callback.vader12
-rw-r--r--test/fixers/test_xo_fixer_callback.vader45
-rw-r--r--test/fixers/test_xots_fixer_callback.vader45
-rw-r--r--test/fixers/test_yamlfix_fixer_callback.vader50
-rw-r--r--test/handler/test_atools_handler.vader85
-rw-r--r--test/handler/test_dafny_handler.vader16
-rw-r--r--test/handler/test_erlang_elvis_handler.vader37
-rw-r--r--test/handler/test_hadolint.vader49
-rw-r--r--test/handler/test_ibm_openapi_validator_handler.vader49
-rw-r--r--test/handler/test_inko_handler.vader54
-rw-r--r--test/handler/test_nix_handler.vader23
-rw-r--r--test/handler/test_phpcs_handler.vader11
-rw-r--r--test/handler/test_salt_salt_lint.vader34
-rw-r--r--test/handler/test_spectral_handler.vader52
-rw-r--r--test/handler/test_swipl_handler.vader60
-rw-r--r--test/handler/test_terraform_handler.vader59
-rw-r--r--test/handler/test_tlint_handler.vader34
-rw-r--r--test/handler/test_vala_lint_handler.vader54
-rw-r--r--test/handler/test_yamllint_handler.vader8
-rw-r--r--test/lsp/test_other_initialize_message_handling.vader6
-rw-r--r--test/lua_files/testfile.lua0
-rw-r--r--test/nix/test.nix0
-rw-r--r--test/nix/test_rnix_lsp.vader14
-rwxr-xr-xtest/script/check-duplicate-tags5
-rwxr-xr-xtest/script/check-supported-tools-tables6
-rwxr-xr-xtest/script/check-tag-alignment11
-rwxr-xr-xtest/script/check-tag-references22
-rwxr-xr-xtest/script/check-toc2
-rwxr-xr-xtest/script/custom-checks34
-rwxr-xr-xtest/script/custom-linting-rules25
-rw-r--r--test/smoke_test.vader8
-rw-r--r--test/test_c_flag_parsing.vader6
-rw-r--r--test/test_code_action.vader4
-rw-r--r--test/test_code_action_python.vader59
-rw-r--r--test/test_codefix.vader549
-rw-r--r--test/test_deno_executable_detection.vader19
-rw-r--r--test/test_dockerfile_hadolint_linter.vader4
-rw-r--r--test/test_filetype_linter_defaults.vader7
-rw-r--r--test/test_floating_preview.vader92
-rw-r--r--test/test_hover.vader87
-rw-r--r--test/test_lint_on_enter_when_file_changed.vader2
-rw-r--r--test/test_linting_updates_loclist.vader6
-rw-r--r--test/test_redundant_tsserver_rendering_avoided.vader30
-rw-r--r--test/test_rename.vader6
-rw-r--r--test/test_shell_detection.vader48
-rw-r--r--test/test_socket_connections.vader57
-rw-r--r--test/typescript/test.ts0
-rw-r--r--test/typescript/tsconfig.json0
-rw-r--r--test/xo-test-files/monorepo/node_modules/xo/cli.js0
-rw-r--r--test/xo-test-files/monorepo/package.json0
-rw-r--r--test/xo-test-files/monorepo/packages/a/index.js0
-rw-r--r--test/xo-test-files/monorepo/packages/a/index.ts0
-rw-r--r--test/xo-test-files/monorepo/packages/a/package.json0
221 files changed, 5990 insertions, 591 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..42add447
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -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 }}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 00baff1c..00000000
--- a/.travis.yml
+++ /dev/null
@@ -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
diff --git a/Dockerfile b/Dockerfile
index a21299e6..b685a7a2 100644
--- a/Dockerfile
+++ b/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
diff --git a/README.md b/README.md
index 0f1c613b..c008aa87 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Asynchronous Lint Engine [![Travis CI Build Status](https://travis-ci.com/dense-analysis/ale.svg?branch=master)](https://travis-ci.com/dense-analysis/ale) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/r0ef1xu8xjmik58d/branch/master?svg=true)](https://ci.appveyor.com/project/dense-analysis/ale) [![Join the chat at https://gitter.im/vim-ale/Lobby](https://badges.gitter.im/vim-ale/Lobby.svg)](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# Asynchronous Lint Engine [![GitHub Build Status](https://github.com/dense-analysis/ale/workflows/CI/badge.svg)](https://github.com/dense-analysis/ale/actions?query=event%3Apush+workflow%3ACI+branch%3Amaster++) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/r0ef1xu8xjmik58d/branch/master?svg=true)](https://ci.appveyor.com/project/dense-analysis/ale) [![Join the chat at https://gitter.im/vim-ale/Lobby](https://badges.gitter.im/vim-ale/Lobby.svg)](https://gitter.im/vim-ale/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![ALE Logo by Mark Grealish - https://www.bhalash.com/](https://user-images.githubusercontent.com/3518142/59195920-2c339500-8b85-11e9-9c22-f6b7f69637b8.jpg)
@@ -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
diff --git a/ale_linters/ada/adals.vim b/ale_linters/ada/adals.vim
new file mode 100644
index 00000000..9a41e1df
--- /dev/null
+++ b/ale_linters/ada/adals.vim
@@ -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')
+\})
diff --git a/ale_linters/apkbuild/apkbuild_lint.vim b/ale_linters/apkbuild/apkbuild_lint.vim
new file mode 100644
index 00000000..285f5534
--- /dev/null
+++ b/ale_linters/apkbuild/apkbuild_lint.vim
@@ -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',
+\})
diff --git a/ale_linters/apkbuild/secfixes_check.vim b/ale_linters/apkbuild/secfixes_check.vim
new file mode 100644
index 00000000..c65267fd
--- /dev/null
+++ b/ale_linters/apkbuild/secfixes_check.vim
@@ -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',
+\})
diff --git a/ale_linters/cloudformation/cfn_python_lint.vim b/ale_linters/cloudformation/cfn_python_lint.vim
index d0ac7b28..16841431 100644
--- a/ale_linters/cloudformation/cfn_python_lint.vim
+++ b/ale_linters/cloudformation/cfn_python_lint.vim
@@ -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',
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 5e062d86..d6944aae 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -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
diff --git a/ale_linters/dafny/dafny.vim b/ale_linters/dafny/dafny.vim
index b5b90675..2a9f761a 100644
--- a/ale_linters/dafny/dafny.vim
+++ b/ale_linters/dafny/dafny.vim
@@ -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,
\ })
diff --git a/ale_linters/dart/analysis_server.vim b/ale_linters/dart/analysis_server.vim
new file mode 100644
index 00000000..a6870da9
--- /dev/null
+++ b/ale_linters/dart/analysis_server.vim
@@ -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'),
+\})
diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim
index e57cd76d..bed87642 100644
--- a/ale_linters/dockerfile/hadolint.vim
+++ b/ale_linters/dockerfile/hadolint.vim
@@ -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'
diff --git a/ale_linters/elixir/credo.vim b/ale_linters/elixir/credo.vim
index 7c298502..892d47b9 100644
--- a/ale_linters/elixir/credo.vim
+++ b/ale_linters/elixir/credo.vim
@@ -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
diff --git a/ale_linters/erlang/dialyzer.vim b/ale_linters/erlang/dialyzer.vim
index 395647a0..a97c9520 100644
--- a/ale_linters/erlang/dialyzer.vim
+++ b/ale_linters/erlang/dialyzer.vim
@@ -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
diff --git a/ale_linters/erlang/elvis.vim b/ale_linters/erlang/elvis.vim
new file mode 100644
index 00000000..31dea3dd
--- /dev/null
+++ b/ale_linters/erlang/elvis.vim
@@ -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,
+\})
diff --git a/ale_linters/erlang/erlc.vim b/ale_linters/erlang/erlc.vim
index a83bacc3..e78dc341 100644
--- a/ale_linters/erlang/erlc.vim
+++ b/ale_linters/erlang/erlc.vim
@@ -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',
\})
diff --git a/ale_linters/haskell/hls.vim b/ale_linters/haskell/hls.vim
new file mode 100644
index 00000000..ae0556a4
--- /dev/null
+++ b/ale_linters/haskell/hls.vim
@@ -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'),
+\})
diff --git a/ale_linters/inko/inko.vim b/ale_linters/inko/inko.vim
new file mode 100644
index 00000000..11558897
--- /dev/null
+++ b/ale_linters/inko/inko.vim
@@ -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
+\})
diff --git a/ale_linters/java/checkstyle.vim b/ale_linters/java/checkstyle.vim
index ec7339d1..f00734e0 100644
--- a/ale_linters/java/checkstyle.vim
+++ b/ale_linters/java/checkstyle.vim
@@ -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, {
diff --git a/ale_linters/java/eclipselsp.vim b/ale_linters/java/eclipselsp.vim
index 8bc09039..adfd1b09 100644
--- a/ale_linters/java/eclipselsp.vim
+++ b/ale_linters/java/eclipselsp.vim
@@ -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]
diff --git a/ale_linters/javascript/xo.vim b/ale_linters/javascript/xo.vim
index e24f4a82..5e04ad5c 100644
--- a/ale_linters/javascript/xo.vim
+++ b/ale_linters/javascript/xo.vim
@@ -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',
\})
diff --git a/ale_linters/json/spectral.vim b/ale_linters/json/spectral.vim
new file mode 100644
index 00000000..c7d56234
--- /dev/null
+++ b/ale_linters/json/spectral.vim
@@ -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'
+\})
diff --git a/ale_linters/julia/languageserver.vim b/ale_linters/julia/languageserver.vim
index 564bec39..999ad815 100644
--- a/ale_linters/julia/languageserver.vim
+++ b/ale_linters/julia/languageserver.vim
@@ -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', {
diff --git a/ale_linters/nix/nix.vim b/ale_linters/nix/nix.vim
index 0a0c5c3e..3d91a9ec 100644
--- a/ale_linters/nix/nix.vim
+++ b/ale_linters/nix/nix.vim
@@ -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',
\})
diff --git a/ale_linters/nix/rnix_lsp.vim b/ale_linters/nix/rnix_lsp.vim
new file mode 100644
index 00000000..949bed1c
--- /dev/null
+++ b/ale_linters/nix/rnix_lsp.vim
@@ -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'),
+\})
diff --git a/ale_linters/openapi/ibm_validator.vim b/ale_linters/openapi/ibm_validator.vim
new file mode 100644
index 00000000..446931a2
--- /dev/null
+++ b/ale_linters/openapi/ibm_validator.vim
@@ -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',
+\})
diff --git a/ale_linters/openapi/yamllint.vim b/ale_linters/openapi/yamllint.vim
new file mode 100644
index 00000000..2b8952cc
--- /dev/null
+++ b/ale_linters/openapi/yamllint.vim
@@ -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',
+\})
diff --git a/ale_linters/perl6/perl6.vim b/ale_linters/perl6/perl6.vim
index 68ef4769..444ae4d7 100644
--- a/ale_linters/perl6/perl6.vim
+++ b/ale_linters/perl6/perl6.vim
@@ -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',
diff --git a/ale_linters/php/intelephense.vim b/ale_linters/php/intelephense.vim
new file mode 100755
index 00000000..aca619e3
--- /dev/null
+++ b/ale_linters/php/intelephense.vim
@@ -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'),
+\})
diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim
index 11b81e84..c5a3faa9 100644
--- a/ale_linters/php/phpcs.vim
+++ b/ale_linters/php/phpcs.vim
@@ -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)
diff --git a/ale_linters/php/tlint.vim b/ale_linters/php/tlint.vim
new file mode 100644
index 00000000..6bba8def
--- /dev/null
+++ b/ale_linters/php/tlint.vim
@@ -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'),
+\})
diff --git a/ale_linters/prolog/swipl.vim b/ale_linters/prolog/swipl.vim
index 5c601c40..82859eb0 100644
--- a/ale_linters/prolog/swipl.vim
+++ b/ale_linters/prolog/swipl.vim
@@ -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
diff --git a/ale_linters/python/jedils.vim b/ale_linters/python/jedils.vim
new file mode 100644
index 00000000..eae5fb07
--- /dev/null
+++ b/ale_linters/python/jedils.vim
@@ -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',
+\})
diff --git a/ale_linters/r/languageserver.vim b/ale_linters/r/languageserver.vim
new file mode 100644
index 00000000..febe66bd
--- /dev/null
+++ b/ale_linters/r/languageserver.vim
@@ -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')
+\})
diff --git a/ale_linters/ruby/sorbet.vim b/ale_linters/ruby/sorbet.vim
index cae0683c..c67e20cc 100644
--- a/ale_linters/ruby/sorbet.vim
+++ b/ale_linters/ruby/sorbet.vim
@@ -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', {
diff --git a/ale_linters/rust/analyzer.vim b/ale_linters/rust/analyzer.vim
index 3666ec03..77d946f7 100644
--- a/ale_linters/rust/analyzer.vim
+++ b/ale_linters/rust/analyzer.vim
@@ -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'),
diff --git a/ale_linters/salt/salt_lint.vim b/ale_linters/salt/salt_lint.vim
new file mode 100644
index 00000000..47f66d83
--- /dev/null
+++ b/ale_linters/salt/salt_lint.vim
@@ -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'
+\})
diff --git a/ale_linters/terraform/terraform.vim b/ale_linters/terraform/terraform.vim
index 0429cb7a..623fc2fd 100644
--- a/ale_linters/terraform/terraform.vim
+++ b/ale_linters/terraform/terraform.vim
@@ -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',
diff --git a/ale_linters/terraform/terraform_ls.vim b/ale_linters/terraform/terraform_ls.vim
new file mode 100644
index 00000000..ab35126e
--- /dev/null
+++ b/ale_linters/terraform/terraform_ls.vim
@@ -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',
+\})
diff --git a/ale_linters/typescript/deno.vim b/ale_linters/typescript/deno.vim
new file mode 100644
index 00000000..051cb208
--- /dev/null
+++ b/ale_linters/typescript/deno.vim
@@ -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
diff --git a/ale_linters/typescript/tsserver.vim b/ale_linters/typescript/tsserver.vim
index 840889f3..4726e40d 100644
--- a/ale_linters/typescript/tsserver.vim
+++ b/ale_linters/typescript/tsserver.vim
@@ -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',
diff --git a/ale_linters/typescript/xo.vim b/ale_linters/typescript/xo.vim
index 0a3a717b..6f4ee50c 100644
--- a/ale_linters/typescript/xo.vim
+++ b/ale_linters/typescript/xo.vim
@@ -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',
\})
diff --git a/ale_linters/vala/vala_lint.vim b/ale_linters/vala/vala_lint.vim
new file mode 100644
index 00000000..7f8a566a
--- /dev/null
+++ b/ale_linters/vala/vala_lint.vim
@@ -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,
+\})
diff --git a/ale_linters/yaml/spectral.vim b/ale_linters/yaml/spectral.vim
new file mode 100644
index 00000000..bd4623a5
--- /dev/null
+++ b/ale_linters/yaml/spectral.vim
@@ -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'
+\})
diff --git a/ale_linters/yaml/yamllint.vim b/ale_linters/yaml/yamllint.vim
index bedb7bf1..39011df1 100644
--- a/ale_linters/yaml/yamllint.vim
+++ b/ale_linters/yaml/yamllint.vim
@@ -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',
\})
diff --git a/autoload/ale/balloon.vim b/autoload/ale/balloon.vim
index 72f6b91c..8678376f 100644
--- a/autoload/ale/balloon.vim
+++ b/autoload/ale/balloon.vim
@@ -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
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim
index cff53125..c7b1e20a 100644
--- a/autoload/ale/c.vim
+++ b/autoload/ale/c.vim
@@ -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'
diff --git a/autoload/ale/code_action.vim b/autoload/ale/code_action.vim
index 42f4f265..69d40933 100644
--- a/autoload/ale/code_action.vim
+++ b/autoload/ale/code_action.vim
@@ -1,28 +1,24 @@
" Author: Jerko Steiner <jerko.steiner@gmail.com>
" Description: Code action support for LSP / tsserver
+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
let l:should_save = get(a:options, 'should_save')
- let l:force_save = get(a:options, 'force_save')
- let l:safe_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')
- if !l:force_save
- call ale#util#Execute('echom ''Aborting action, file is unsaved''')
-
- return
- endif
- else
- call add(l:safe_changes, l:file_code_edit)
- endif
- endfor
-
- for l:file_code_edit in l:safe_changes
call ale#code_action#ApplyChanges(
\ l:file_code_edit.fileName,
\ l:file_code_edit.textChanges,
@@ -85,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
@@ -125,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.
@@ -134,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,
@@ -166,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
@@ -215,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
diff --git a/autoload/ale/codefix.vim b/autoload/ale/codefix.vim
new file mode 100644
index 00000000..4a78063b
--- /dev/null
+++ b/autoload/ale/codefix.vim
@@ -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
diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim
index efbf0fd5..332d0734 100644
--- a/autoload/ale/completion.vim
+++ b/autoload/ale/completion.vim
@@ -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
diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim
index 9ca6fb15..e8478e93 100644
--- a/autoload/ale/cursor.vim
+++ b/autoload/ale/cursor.vim
@@ -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
diff --git a/autoload/ale/dhall.vim b/autoload/ale/dhall.vim
new file mode 100644
index 00000000..cc54418f
--- /dev/null
+++ b/autoload/ale/dhall.vim
@@ -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
diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim
index f8c04aef..23441ca5 100644
--- a/autoload/ale/fix/registry.vim
+++ b/autoload/ale/fix/registry.vim
@@ -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': {
@@ -337,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': {
@@ -380,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.
diff --git a/autoload/ale/fixers/autoimport.vim b/autoload/ale/fixers/autoimport.vim
new file mode 100644
index 00000000..37a52db8
--- /dev/null
+++ b/autoload/ale/fixers/autoimport.vim
@@ -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
diff --git a/autoload/ale/fixers/deno.vim b/autoload/ale/fixers/deno.vim
new file mode 100644
index 00000000..7154c6ee
--- /dev/null
+++ b/autoload/ale/fixers/deno.vim
@@ -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
diff --git a/autoload/ale/fixers/dhall.vim b/autoload/ale/fixers/dhall.vim
deleted file mode 100644
index 18f6006c..00000000
--- a/autoload/ale/fixers/dhall.vim
+++ /dev/null
@@ -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
diff --git a/autoload/ale/fixers/dhall_format.vim b/autoload/ale/fixers/dhall_format.vim
new file mode 100644
index 00000000..d4021983
--- /dev/null
+++ b/autoload/ale/fixers/dhall_format.vim
@@ -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
diff --git a/autoload/ale/fixers/dhall_freeze.vim b/autoload/ale/fixers/dhall_freeze.vim
new file mode 100644
index 00000000..74ae7530
--- /dev/null
+++ b/autoload/ale/fixers/dhall_freeze.vim
@@ -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
diff --git a/autoload/ale/fixers/dhall_lint.vim b/autoload/ale/fixers/dhall_lint.vim
new file mode 100644
index 00000000..2abbe6f7
--- /dev/null
+++ b/autoload/ale/fixers/dhall_lint.vim
@@ -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
diff --git a/autoload/ale/fixers/gofmt.vim b/autoload/ale/fixers/gofmt.vim
index d5a539b9..b9cfbb58 100644
--- a/autoload/ale/fixers/gofmt.vim
+++ b/autoload/ale/fixers/gofmt.vim
@@ -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
diff --git a/autoload/ale/fixers/isort.vim b/autoload/ale/fixers/isort.vim
index 9070fb27..55bb550e 100644
--- a/autoload/ale/fixers/isort.vim
+++ b/autoload/ale/fixers/isort.vim
@@ -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)
+
+ let l:exec_args = l:executable =~? 'pipenv$'
+ \ ? ' run isort'
+ \ : ''
- if !executable(l:executable)
+ 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
diff --git a/autoload/ale/fixers/luafmt.vim b/autoload/ale/fixers/luafmt.vim
new file mode 100644
index 00000000..6cb9ef4a
--- /dev/null
+++ b/autoload/ale/fixers/luafmt.vim
@@ -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
diff --git a/autoload/ale/fixers/ormolu.vim b/autoload/ale/fixers/ormolu.vim
new file mode 100644
index 00000000..69b55c1f
--- /dev/null
+++ b/autoload/ale/fixers/ormolu.vim
@@ -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
diff --git a/autoload/ale/fixers/phpcbf.vim b/autoload/ale/fixers/phpcbf.vim
index f14b8406..0a61c657 100644
--- a/autoload/ale/fixers/phpcbf.vim
+++ b/autoload/ale/fixers/phpcbf.vim
@@ -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
diff --git a/autoload/ale/fixers/prettier.vim b/autoload/ale/fixers/prettier.vim
index e0f4972e..12c018af 100644
--- a/autoload/ale/fixers/prettier.vim
+++ b/autoload/ale/fixers/prettier.vim
@@ -83,6 +83,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
\ 'markdown': 'markdown',
\ 'vue': 'vue',
\ 'yaml': 'yaml',
+ \ 'openapi': 'yaml',
\ 'html': 'html',
\}
diff --git a/autoload/ale/fixers/standardrb.vim b/autoload/ale/fixers/standardrb.vim
index 54330a37..acb310c6 100644
--- a/autoload/ale/fixers/standardrb.vim
+++ b/autoload/ale/fixers/standardrb.vim
@@ -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
diff --git a/autoload/ale/fixers/xo.vim b/autoload/ale/fixers/xo.vim
index 882350be..dcf4c737 100644
--- a/autoload/ale/fixers/xo.vim
+++ b/autoload/ale/fixers/xo.vim
@@ -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
diff --git a/autoload/ale/fixers/yamlfix.vim b/autoload/ale/fixers/yamlfix.vim
new file mode 100644
index 00000000..966556c9
--- /dev/null
+++ b/autoload/ale/fixers/yamlfix.vim
@@ -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
diff --git a/autoload/ale/floating_preview.vim b/autoload/ale/floating_preview.vim
new file mode 100644
index 00000000..e6a75689
--- /dev/null
+++ b/autoload/ale/floating_preview.vim
@@ -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
+
diff --git a/autoload/ale/handlers/atools.vim b/autoload/ale/handlers/atools.vim
new file mode 100644
index 00000000..c273fc40
--- /dev/null
+++ b/autoload/ale/handlers/atools.vim
@@ -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
diff --git a/autoload/ale/handlers/deno.vim b/autoload/ale/handlers/deno.vim
new file mode 100644
index 00000000..4bf4546a
--- /dev/null
+++ b/autoload/ale/handlers/deno.vim
@@ -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
diff --git a/autoload/ale/handlers/eslint.vim b/autoload/ale/handlers/eslint.vim
index e37d6902..b8610612 100644
--- a/autoload/ale/handlers/eslint.vim
+++ b/autoload/ale/handlers/eslint.vim
@@ -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') ? '\' : '/'
diff --git a/autoload/ale/handlers/hdl_checker.vim b/autoload/ale/handlers/hdl_checker.vim
index 36dbd259..e11c5377 100644
--- a/autoload/ale/handlers/hdl_checker.vim
+++ b/autoload/ale/handlers/hdl_checker.vim
@@ -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
diff --git a/autoload/ale/handlers/inko.vim b/autoload/ale/handlers/inko.vim
new file mode 100644
index 00000000..73f06871
--- /dev/null
+++ b/autoload/ale/handlers/inko.vim
@@ -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
diff --git a/autoload/ale/handlers/sh.vim b/autoload/ale/handlers/sh.vim
index 1e50cb89..6ed9fea3 100644
--- a/autoload/ale/handlers/sh.vim
+++ b/autoload/ale/handlers/sh.vim
@@ -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
diff --git a/autoload/ale/handlers/shellcheck.vim b/autoload/ale/handlers/shellcheck.vim
index b16280f0..701c43b2 100644
--- a/autoload/ale/handlers/shellcheck.vim
+++ b/autoload/ale/handlers/shellcheck.vim
@@ -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
diff --git a/autoload/ale/handlers/spectral.vim b/autoload/ale/handlers/spectral.vim
new file mode 100644
index 00000000..1eb4a5de
--- /dev/null
+++ b/autoload/ale/handlers/spectral.vim
@@ -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
+
diff --git a/autoload/ale/handlers/xo.vim b/autoload/ale/handlers/xo.vim
new file mode 100644
index 00000000..c63278c0
--- /dev/null
+++ b/autoload/ale/handlers/xo.vim
@@ -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
diff --git a/autoload/ale/handlers/yamllint.vim b/autoload/ale/handlers/yamllint.vim
new file mode 100644
index 00000000..5e04577d
--- /dev/null
+++ b/autoload/ale/handlers/yamllint.vim
@@ -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
+
diff --git a/autoload/ale/hover.vim b/autoload/ale/hover.vim
index 38b4b866..cb0379fd 100644
--- a/autoload/ale/hover.vim
+++ b/autoload/ale/hover.vim
@@ -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',
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index 645c25f9..f9ec48d7 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -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'],
diff --git a/autoload/ale/list.vim b/autoload/ale/list.vim
index 4bfe2a7b..c2ae5cc5 100644
--- a/autoload/ale/list.vim
+++ b/autoload/ale/list.vim
@@ -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
diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim
index 7d99e9d2..cb0573aa 100644
--- a/autoload/ale/lsp.vim
+++ b/autoload/ale/lsp.vim
@@ -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
diff --git a/autoload/ale/lsp/message.vim b/autoload/ale/lsp/message.vim
index 5b0cb8b7..38be4da6 100644
--- a/autoload/ale/lsp/message.vim
+++ b/autoload/ale/lsp/message.vim
@@ -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
diff --git a/autoload/ale/lsp/response.vim b/autoload/ale/lsp/response.vim
index 30da77e1..a4f80980 100644
--- a/autoload/ale/lsp/response.vim
+++ b/autoload/ale/lsp/response.vim
@@ -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) .
diff --git a/autoload/ale/lsp/tsserver_message.vim b/autoload/ale/lsp/tsserver_message.vim
index b9fafaa0..3c1b47ed 100644
--- a/autoload/ale/lsp/tsserver_message.vim
+++ b/autoload/ale/lsp/tsserver_message.vim
@@ -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
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index dcd76e8f..628dde78 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -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
diff --git a/autoload/ale/maven.vim b/autoload/ale/maven.vim
index 745f8c93..42735286 100644
--- a/autoload/ale/maven.vim
+++ b/autoload/ale/maven.vim
@@ -25,7 +25,7 @@ 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 executable(l:wrapper_path)
+ if !empty(l:wrapper_path) && executable(l:wrapper_path)
return l:wrapper_path
endif
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index 7ed22367..fc6c1130 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -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
diff --git a/autoload/ale/rename.vim b/autoload/ale/rename.vim
index 8190411d..9030618e 100644
--- a/autoload/ale/rename.vim
+++ b/autoload/ale/rename.vim
@@ -85,36 +85,10 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
\ },
\ {
\ 'should_save': 1,
- \ 'force_save': get(l:options, 'force_save'),
\ },
\)
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
-endfunction
-
function! ale#rename#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:rename_map, a:response.id)
@@ -126,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')
@@ -134,34 +108,7 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
return
endif
- let l:changes = []
-
- 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
+ let l:changes = ale#code_action#BuildChangesList(l:changes_map)
call ale#code_action#HandleCodeAction(
\ {
@@ -170,7 +117,6 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
\ },
\ {
\ 'should_save': 1,
- \ 'force_save': get(l:options, 'force_save'),
\ },
\)
endif
@@ -229,7 +175,7 @@ function! s:ExecuteRename(linter, options) abort
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction
-function! ale#rename#Execute(options) abort
+function! ale#rename#Execute() abort
let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype)
@@ -257,7 +203,6 @@ function! ale#rename#Execute(options) abort
call s:ExecuteRename(l:lsp_linter, {
\ 'old_name': l:old_name,
\ 'new_name': l:new_name,
- \ 'force_save': get(a:options, 'force_save') is 1,
\})
endfor
endfunction
diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim
index 8109c60e..2864f39b 100644
--- a/autoload/ale/sign.vim
+++ b/autoload/ale/sign.vim
@@ -50,9 +50,12 @@ if !hlexists('ALESignColumnWithErrors')
endif
function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort
+ let l:verbose = &verbose
+ set verbose=0
redir => l:output
0verbose silent highlight SignColumn
redir end
+ let &verbose = l:verbose
let l:highlight_syntax = join(split(l:output)[2:])
let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
diff --git a/autoload/ale/socket.vim b/autoload/ale/socket.vim
index 7e069fb5..61f11e70 100644
--- a/autoload/ale/socket.vim
+++ b/autoload/ale/socket.vim
@@ -72,9 +72,8 @@ function! ale#socket#Open(address, options) abort
elseif exists('*chansend') && exists('*sockconnect')
" NeoVim 0.3+
try
- let l:channel_id = sockconnect('tcp', a:address, {
- \ 'on_data': function('s:NeoVimOutputCallback'),
- \})
+ let l:channel_id = sockconnect(stridx(a:address, ':') != -1 ? 'tcp' : 'pipe',
+ \ a:address, {'on_data': function('s:NeoVimOutputCallback')})
let l:channel_info.last_line = ''
catch /connection failed/
let l:channel_id = -1
diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim
index 1f396377..5c41ab83 100644
--- a/autoload/ale/util.vim
+++ b/autoload/ale/util.vim
@@ -409,7 +409,7 @@ function! ale#util#FuzzyJSONDecode(data, default) abort
endif
return l:result
- catch /E474/
+ catch /E474\|E491/
return a:default
endtry
endfunction
diff --git a/doc/ale-ada.txt b/doc/ale-ada.txt
index 2ac30c0a..0fc55a9c 100644
--- a/doc/ale-ada.txt
+++ b/doc/ale-ada.txt
@@ -33,4 +33,34 @@ g:ale_ada_gnatpp_options *g:ale_ada_gnatpp_options*
===============================================================================
+ada-language-server *ale-ada-language-server*
+
+g:ale_ada_adals_executable *g:ale_ada_adals_executable*
+ *b:ale_ada_adals_executable*
+ Type: |String|
+ Default: `'ada_language_server'`
+
+ This variable can be changed to use a different executable for Ada Language
+ Server.
+
+
+g:ale_ada_adals_project *g:ale_ada_adals_project*
+ *b:ale_ada_adals_project*
+ Type: |String|
+ Default: `'default.gpr'`
+
+This variable can be changed to use a different GPR file for
+Ada Language Server.
+
+
+g:ale_ada_adals_encoding *g:ale_ada_adals_encoding*
+ *b:ale_ada_adals_encoding*
+ Type: |String|
+ Default: `'utf-8'`
+
+This variable can be changed to use a different file encoding for
+Ada Language Server.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-apkbuild.txt b/doc/ale-apkbuild.txt
new file mode 100644
index 00000000..05261400
--- /dev/null
+++ b/doc/ale-apkbuild.txt
@@ -0,0 +1,30 @@
+===============================================================================
+ALE APKBUILD Integration *ale-apkbuild-options*
+
+
+===============================================================================
+apkbuild-lint *ale-apkbuild-apkbuild-lint*
+
+g:ale_apkbuild_apkbuild_lint_executable
+ *g:ale_apkbuild_apkbuild_lint_executable*
+ *b:ale_apkbuild_apkbuild_lint_executable*
+
+ Type: |String|
+ Default: `'apkbuild-lint'`
+
+ This variable can be set to change the path to apkbuild-lint
+
+===============================================================================
+secfixes-check *ale-apkbuild-secfixes-check*
+
+g:ale_apkbuild_secfixes_check_executable
+ *g:ale_apkbuild_secfixes_check_executable*
+ *b:ale_apkbuild_secfixes_check_executable*
+
+ Type: |String|
+ Default: `'secfixes-check'`
+
+ This variable can be set to change the path to secfixes-check
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-dafny.txt b/doc/ale-dafny.txt
new file mode 100644
index 00000000..005170ad
--- /dev/null
+++ b/doc/ale-dafny.txt
@@ -0,0 +1,16 @@
+===============================================================================
+ALE Dafny Integration *ale-dafny-options*
+
+
+===============================================================================
+dafny *ale-dafny-dafny*
+
+g:ale_dafny_dafny_timelimit *g:ale_dafny_dafny_timelimit*
+ *b:ale_dafny_dafny_timelimit*
+ Type: |Number|
+ Default: `10`
+
+ This variable sets the `/timeLimit` used for dafny.
+
+
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-dart.txt b/doc/ale-dart.txt
index a6d88dd8..01089252 100644
--- a/doc/ale-dart.txt
+++ b/doc/ale-dart.txt
@@ -3,6 +3,31 @@ ALE Dart Integration *ale-dart-options*
===============================================================================
+analysis_server *ale-dart-analysis_server*
+
+Installation
+-------------------------------------------------------------------------------
+
+Install Dart via whatever means. `analysis_server` will be included in the SDK.
+
+In case that `dart` is not in your path, try to set the executable option to
+its absolute path. : >
+ " Set the executable path for dart to the absolute path to it.
+ let g:ale_dart_analysis_server_executable = '/usr/local/bin/dart'
+<
+
+Options
+-------------------------------------------------------------------------------
+
+g:ale_dart_analysis_server_executable *g:ale_dart_analysis_server_executable*
+ *b:ale_dart_analysis_server_executable*
+ Type: |String|
+ Default: `'dart'`
+
+ This variable can be set to change the path of dart.
+
+
+===============================================================================
dartanalyzer *ale-dart-dartanalyzer*
Installation
diff --git a/doc/ale-development.txt b/doc/ale-development.txt
index afd9798f..dbbeb2da 100644
--- a/doc/ale-development.txt
+++ b/doc/ale-development.txt
@@ -148,13 +148,14 @@ Apply the following rules when writing Bash scripts.
===============================================================================
4. Testing ALE *ale-development-tests* *ale-dev-tests* *ale-tests*
-ALE is tested with a suite of tests executed in Travis CI and AppVeyor. ALE
-runs tests with the following versions of Vim in the following environments.
-
-1. Vim 8.0.0027 on Linux via Travis CI.
-2. Vim 8.1.0519 on Linux via Travis CI.
-3. NeoVim 0.2.0 on Linux via Travis CI.
-4. NeoVim 0.3.5 on Linux via Travis CI.
+ALE is tested with a suite of tests executed via GitHub Actions and AppVeyor.
+ALE runs tests with the following versions of Vim in the following
+environments.
+
+1. Vim 8.0.0027 on Linux via GitHub Actions.
+2. Vim 8.2.2401 on Linux via GitHub Actions.
+3. NeoVim 0.2.0 on Linux via GitHub Actions.
+4. NeoVim 0.4.4 on Linux via GitHub Actions.
5. Vim 8 (stable builds) on Windows via AppVeyor.
If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
@@ -192,7 +193,8 @@ tests.
When you add new linters or fixers, make sure to add them into the tables in
supported-tools.md and |ale-supported-languages-and-tools.txt|. If you forget to
-keep them both in sync, you should see an error like the following in Travis CI.
+keep them both in sync, you should see an error like the following in the
+builds run for GitHub Actions.
>
========================================
diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables
diff --git a/doc/ale-dhall.txt b/doc/ale-dhall.txt
new file mode 100644
index 00000000..44b0bf32
--- /dev/null
+++ b/doc/ale-dhall.txt
@@ -0,0 +1,52 @@
+===============================================================================
+ALE Dhall Integration *ale-dhall-options*
+
+g:ale_dhall_executable *g:ale_dhall_executable*
+ *b:ale_dhall_executable*
+ Type: |String|
+ Default: `'dhall'`
+
+g:ale_dhall_options g:ale_dhall_options
+ b:ale_dhall_options
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the 'dhall` executable.
+ This is shared with `dhall-freeze` and `dhall-lint`.
+>
+ let g:dhall_options = '--ascii'
+<
+
+===============================================================================
+dhall-format *ale-dhall-format*
+
+Dhall
+ (https://dhall-lang.org/)
+
+
+===============================================================================
+dhall-freeze *ale-dhall-freeze*
+
+Dhall
+ (https://dhall-lang.org/)
+
+g:ale_dhall_freeze_options g:ale_dhall_freeze_options
+ b:ale_dhall_freeze_options
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the 'dhall freeze`
+ executable.
+>
+ let g:dhall_freeze_options = '--all'
+<
+
+===============================================================================
+dhall-lint *ale-dhall-lint*
+
+Dhall
+ (https://dhall-lang.org/)
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-elixir.txt b/doc/ale-elixir.txt
index de9daacf..a4e5c2c6 100644
--- a/doc/ale-elixir.txt
+++ b/doc/ale-elixir.txt
@@ -85,5 +85,12 @@ g:ale_elixir_credo_strict *g:ale_elixir_credo_strict*
Tells credo to run in strict mode or suggest mode. Set variable to 1 to
enable --strict mode.
+g:ale_elixir_credo_config_file g:ale_elixir_credo_config_file
+
+ Type: String
+ Default: ''
+
+ Tells credo to use a custom configuration file.
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-erlang.txt b/doc/ale-erlang.txt
index 59993a99..93ac7915 100644
--- a/doc/ale-erlang.txt
+++ b/doc/ale-erlang.txt
@@ -13,6 +13,14 @@ g:ale_erlang_dialyzer_executable *g:ale_erlang_dialyzer_executable*
This variable can be changed to specify the dialyzer executable.
+g:ale_erlang_dialyzer_options *g:ale_erlang_dialyzer_options*
+ *b:ale_erlang_dialyzer_options*
+ Type: |String|
+ Default: `'-Wunmatched_returns -Werror_handling -Wrace_conditions -Wunderspec'`
+
+ This variable can be changed to specify the options to pass to the dialyzer
+ executable.
+
g:ale_erlang_dialyzer_plt_file *g:ale_erlang_dialyzer_plt_file*
*b:ale_erlang_dialyzer_plt_file*
Type: |String|
@@ -31,9 +39,29 @@ g:ale_erlang_dialyzer_rebar3_profile *g:ale_erlang_dialyzer_rebar3_profile*
This variable can be changed to specify the profile that is used to
run dialyzer with rebar3.
+
+-------------------------------------------------------------------------------
+elvis *ale-erlang-elvis*
+
+g:ale_erlang_elvis_executable *g:ale_erlang_elvis_executable*
+ *b:ale_erlang_elvis_executable*
+ Type: |String|
+ Default: `'elvis'`
+
+ This variable can be changed to specify the elvis executable.
+
+
-------------------------------------------------------------------------------
erlc *ale-erlang-erlc*
+g:ale_erlang_erlc_executable *g:ale_erlang_erlc_executable*
+ *b:ale_erlang_erlc_executable*
+ Type: |String|
+ Default: `'erlc'`
+
+ This variable can be changed to specify the erlc executable.
+
+
g:ale_erlang_erlc_options *g:ale_erlang_erlc_options*
*b:ale_erlang_erlc_options*
Type: |String|
diff --git a/doc/ale-haskell.txt b/doc/ale-haskell.txt
index 5dd3ec15..09894340 100644
--- a/doc/ale-haskell.txt
+++ b/doc/ale-haskell.txt
@@ -125,6 +125,18 @@ g:ale_haskell_hlint_options g:ale_haskell_hlint_options
===============================================================================
+hls *ale-haskell-hls*
+
+g:ale_haskell_hls_executable *g:ale_haskell_hls_executable*
+ *b:ale_haskell_his_executable*
+ Type: |String|
+ Default: `'haskell-language-server-wrapper'`
+
+ This variable can be changed to use a different executable for the haskell
+ language server.
+
+
+===============================================================================
stack-build *ale-haskell-stack-build*
g:ale_haskell_stack_build_options *g:ale_haskell_stack_build_options*
@@ -173,4 +185,24 @@ g:ale_haskell_hie_executable *g:ale_haskell_hie_executable*
===============================================================================
+ormolu *ale-haskell-ormolu*
+
+g:ale_haskell_ormolu_executable *g:ale_haskell_ormolu_executable*
+ *b:ale_haskell_ormolu_executable*
+ Type: |String|
+ Default: `'ormolu'`
+
+ This variable can be changed to use a different executable for ormolu.
+
+
+g:ale_haskell_ormolu_options *g:ale_haskell_ormolu_options*
+ *b:ale_haskell_ormolu_options*
+ Type: String
+ Default: ''
+
+ This variable can be used to pass extra options to the underlying ormolu
+ executable.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-inko.txt b/doc/ale-inko.txt
new file mode 100644
index 00000000..5ca14af6
--- /dev/null
+++ b/doc/ale-inko.txt
@@ -0,0 +1,22 @@
+===============================================================================
+ALE Inko Integration *ale-inko-options*
+ *ale-integration-inko*
+
+===============================================================================
+Integration Information
+
+ Currently, the only supported linter for Inko is the Inko compiler itself.
+
+===============================================================================
+inko *ale-inko-inko*
+
+g:ale_inko_inko_executable *g:ale_inko_inko_executable*
+ *b:ale_inko_inko_executable*
+ Type: |String|
+ Default: `'inko'`
+
+ This variable can be modified to change the executable path for `inko`.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-json.txt b/doc/ale-json.txt
index 96499a04..dc91e14c 100644
--- a/doc/ale-json.txt
+++ b/doc/ale-json.txt
@@ -102,4 +102,36 @@ See |ale-javascript-prettier| for information about the available options.
===============================================================================
+spectral *ale-json-spectral*
+
+Website: https://github.com/stoplightio/spectral
+
+Installation
+-------------------------------------------------------------------------------
+
+Install spectral either globally or locally: >
+
+ npm install @stoplight/spectral -g # global
+ npm install @stoplight/spectral # local
+<
+
+Options
+-------------------------------------------------------------------------------
+
+g:ale_json_spectral_executable *g:ale_json_spectral_executable*
+ *b:ale_json_spectral_executable*
+ Type: |String|
+ Default: `'spectral'`
+
+ This variable can be set to change the path to spectral.
+
+g:ale_json_spectral_use_global *g:ale_json_spectral_use_global*
+ *b:ale_json_spectral_use_global*
+ Type: |String|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-lua.txt b/doc/ale-lua.txt
index f1286f89..408f0c3c 100644
--- a/doc/ale-lua.txt
+++ b/doc/ale-lua.txt
@@ -31,4 +31,20 @@ g:ale_lua_luacheck_options *g:ale_lua_luacheck_options*
===============================================================================
+luafmt *ale-lua-luafmt*
+
+g:ale_lua_luafmt_executable *g:ale_lua_luafmt_executable*
+ *b:ale_lua_luafmt_executable*
+ Type: |String|
+ Default: `'luafmt'`
+
+ This variable can be set to use a different executable for luafmt.
+
+g:ale_lua_luafmt_options *g:ale_lua_luafmt_options*
+ *b:ale_lua_luafmt_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the luafmt fixer.
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-openapi.txt b/doc/ale-openapi.txt
new file mode 100644
index 00000000..1fc41add
--- /dev/null
+++ b/doc/ale-openapi.txt
@@ -0,0 +1,74 @@
+===============================================================================
+ALE OpenApi Integration *ale-openapi-options*
+
+===============================================================================
+ibm_validator *ale-openapi-ibm-validator*
+
+Website: https://github.com/IBM/openapi-validator
+
+
+Installation
+-------------------------------------------------------------------------------
+
+Install ibm-openapi-validator either globally or locally: >
+
+ npm install ibm-openapi-validator -g # global
+ npm install ibm-openapi-validator # local
+<
+Configuration
+-------------------------------------------------------------------------------
+
+OpenAPI files can be written in YAML or JSON so in order for ALE plugins to
+work with these files we must set the buffer |filetype| to either |openapi.yaml|
+or |openapi.json| respectively. This causes ALE to lint the file with linters
+configured for openapi and yaml files or openapi and json files respectively.
+
+For example setting filetype to |openapi.yaml| on a buffer and the following
+|g:ale_linters| configuration will enable linting of openapi files using both
+|ibm_validator| and |yamlint|:
+
+>
+ let g:ale_linters = {
+ \ 'yaml': ['yamllint'],
+ \ 'openapi': ['ibm_validator']
+ \}
+<
+
+The following plugin will detect openapi files automatically and set the
+filetype to |openapi.yaml| or |openapi.json|:
+
+ https://github.com/hsanson/vim-openapi
+
+Options
+-------------------------------------------------------------------------------
+
+g:ale_openapi_ibm_validator_executable *g:ale_openapi_ibm_validator_executable*
+ *b:ale_openapi_ibm_validator_executable*
+ Type: |String|
+ Default: `'lint-openapi'`
+
+ This variable can be set to change the path to lint-openapi.
+
+
+g:ale_openapi_ibm_validator_options *g:ale_openapi_ibm_validator_options*
+ *b:ale_openapi_ibm_validator_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to lint-openapi.
+
+
+===============================================================================
+prettier *ale-openapi-prettier*
+
+See |ale-javascript-prettier| for information about the available options.
+
+
+===============================================================================
+yamllint *ale-openapi-yamllint*
+
+See |ale-yaml-yamllint| for information about the available options.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-php.txt b/doc/ale-php.txt
index 9fe868f8..4ee016fb 100644
--- a/doc/ale-php.txt
+++ b/doc/ale-php.txt
@@ -85,6 +85,14 @@ g:ale_php_phpcbf_use_global *g:ale_php_phpcbf_use_global*
See |ale-integrations-local-executables|
+g:ale_php_phpcbf_options *g:ale_php_phpcbf_options*
+ *b:ale_php_phpcbf_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to php-cbf
+
+
===============================================================================
phpcs *ale-php-phpcs*
@@ -243,5 +251,70 @@ g:ale_php_php_executable *g:ale_php_php_executable*
This variable sets the executable used for php.
+
+===============================================================================
+tlint *ale-php-tlint*
+
+g:ale_php_tlint_executable *g:ale_php_tlint_executable*
+ *b:ale_php_tlint_executable*
+ Type: |String|
+ Default: `'tlint'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_php_tlint_use_global *g:ale_php_tlint_use_global*
+ *b:ale_php_tlint_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_php_tlint_options *g:ale_php_tlint_options*
+ *b:ale_php_tlint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to tlint
+
+
+===============================================================================
+intelephense *ale-php-intelephense*
+
+g:ale_php_intelephense_executable *g:ale_php_intelephense_executable*
+ *b:ale_php_intelephense_executable*
+ Type: |String|
+ Default: `'intelephense'`
+
+ The variable can be set to configure the executable that will be used for
+ running the intelephense language server. `node_modules` directory
+ executable will be preferred instead of this setting if
+ |g:ale_php_intelephense_use_global| is `0`.
+
+ See: |ale-integrations-local-executables|
+
+
+g:ale_php_intelephense_use_global *g:ale_php_intelephense_use_global*
+ *b:ale_php_intelephense_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ This variable can be set to `1` to force the language server to be run with
+ the executable set for |g:ale_php_intelephense_executable|.
+
+ See: |ale-integrations-local-executables|
+
+
+g:ale_php_intelephense_config *g:ale_php_intelephense_config*
+ *b:ale_php_intelephense_config*
+ Type: |Dictionary|
+ Default: `{}`
+
+ The initialization options config specified by Intelephense. Refer to the
+ installation docs provided by intelephense (github.com/bmewburn/intelephense
+ -docs).
+
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index 6b1a6d33..1f263e84 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -36,12 +36,40 @@ ALE will look for configuration files with the following filenames. >
.pylintrc
Pipfile
Pipfile.lock
+ poetry.lock
+ pyproject.toml
<
The first directory containing any of the files named above will be used.
===============================================================================
+autoimport *ale-python-autoimport*
+
+g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
+ *b:ale_python_autoimport_executable*
+ Type: |String|
+ Default: `'autoimport'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_python_autoimport_options *g:ale_python_autoimport_options*
+ *b:ale_python_autoimport_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass extra options to autoimport.
+
+
+g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
+ *b:ale_python_autoimport_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+===============================================================================
autopep8 *ale-python-autopep8*
g:ale_python_autopep8_executable *g:ale_python_autopep8_executable*
@@ -254,6 +282,15 @@ g:ale_python_isort_use_global *g:ale_python_isort_use_global*
See |ale-integrations-local-executables|
+g:ale_python_isort_auto_pipenv *g:ale_python_isort_auto_pipenv*
+ *b:ale_python_isort_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
mypy *ale-python-mypy*
@@ -687,7 +724,7 @@ g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv*
===============================================================================
pyright *ale-python-pyright*
-The `pyrlight` linter requires a recent version of `pyright` which includes
+The `pyright` linter requires a recent version of `pyright` which includes
the `pyright-langserver` executable. You can install `pyright` on your system
through `npm` with `sudo npm install -g pyright` or similar.
diff --git a/doc/ale-r.txt b/doc/ale-r.txt
index b5ccebe5..3fabf702 100644
--- a/doc/ale-r.txt
+++ b/doc/ale-r.txt
@@ -3,6 +3,29 @@ ALE R Integration *ale-r-options*
===============================================================================
+languageserver *ale-r-languageserver*
+
+g:ale_r_languageserver_cmd *g:ale_r_languageserver_cmd*
+ *b:ale_r_languageserver_cmd*
+ Type: |String|
+ Default: `'languageserver::run()'`
+
+ This option can be configured to change the execution command for
+ languageserver.
+
+ See the languageserver documentation for more options.
+
+
+g:ale_r_languageserver_config *g:ale_r_languageserver_config*
+ *b:ale_r_languageserver_config*
+ Type: |Dictionary|
+ Default: `{}`
+
+ This option can be configured to change settings for languageserver. See the
+ languageserver documentation for more information.
+
+
+===============================================================================
lintr *ale-r-lintr*
g:ale_r_lintr_options *g:ale_r_lintr_options*
@@ -22,7 +45,7 @@ g:ale_r_lintr_lint_package *g:ale_r_lintr_lint_package*
Default: `0`
When set to `1`, the file will be checked with `lintr::lint_package` instead
- of `lintr::lint`. This prevents erroneous namespace warnings when linting
+ of `lintr::lint`. This prevents erroneous namespace warnings when linting
package files.
@@ -36,8 +59,8 @@ g:ale_r_styler_options *g:ale_r_styler_options*
This option can be configured to change the options for styler.
- The value of this option will be used as the `style` argument for the
- `styler::style_file` options. Consult the styler documentation
+ The value of this option will be used as the `style` argument for the
+ `styler::style_file` options. Consult the styler documentation
for more information.
diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt
index 8815404a..edc6144a 100644
--- a/doc/ale-ruby.txt
+++ b/doc/ale-ruby.txt
@@ -177,6 +177,16 @@ g:ale_ruby_sorbet_options *g:ale_ruby_sorbet_options*
This variable can be changed to modify flags given to sorbet.
+g:ale_ruby_sorbet_enable_watchman *g:ale_ruby_sorbet_enable_watchman*
+ *b:ale_ruby_sorbet_enable_watchman*
+ Type: |Number|
+ Default: `0`
+
+ Whether or not to use watchman to let the LSP server to know about changes
+ to files from outside of vim. Defaults to disable watchman because it
+ requires watchman to be installed separately from sorbet.
+
+
===============================================================================
standardrb *ale-ruby-standardrb*
diff --git a/doc/ale-rust.txt b/doc/ale-rust.txt
index f4b4e7b7..3aa63673 100644
--- a/doc/ale-rust.txt
+++ b/doc/ale-rust.txt
@@ -22,12 +22,12 @@ Integration Information
3. rls -- If you have `rls` installed, you might prefer using this linter
over cargo. rls implements the Language Server Protocol for incremental
compilation of Rust code, and can check Rust files while you type. `rls`
- requires Rust files to contained in Cargo projects.
+ requires Rust files to be contained in Cargo projects.
4. analyzer -- If you have rust-analyzer installed, you might prefer using
this linter over cargo and rls. rust-analyzer also implements the
Language Server Protocol for incremental compilation of Rust code, and is
the next iteration of rls. rust-analyzer, like rls, requires Rust files
- to contained in Cargo projects.
+ to be contained in Cargo projects.
5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to
consistently reformat your Rust code.
diff --git a/doc/ale-salt.tmt b/doc/ale-salt.tmt
new file mode 100644
index 00000000..ac500d37
--- /dev/null
+++ b/doc/ale-salt.tmt
@@ -0,0 +1,43 @@
+===============================================================================
+ALE SALT Integration *ale-salt-options*
+
+===============================================================================
+salt-lint *ale-salt-salt-lint*
+
+Website: https://github.com/warpnet/salt-lint
+
+
+Installation
+-------------------------------------------------------------------------------
+
+Install salt-lint in your a virtualenv directory, locally, or globally: >
+
+ pip install salt-lint # After activating virtualenv
+ pip install --user salt-lint # Install to ~/.local/bin
+ sudo pip install salt-lint # Install globally
+
+See |g:ale_virtualenv_dir_names| for configuring how ALE searches for
+virtualenv directories.
+
+
+Options
+-------------------------------------------------------------------------------
+
+g:ale_salt_salt-lint_executable *g:ale_salt_salt_lint_executable*
+ *b:ale_salt_salt_lint_executable*
+ Type: |String|
+ Default: `'salt-lint'`
+
+ This variable can be set to change the path to salt-lint.
+
+
+g:ale_salt_salt-lint_options *g:ale_salt_salt-lint_options*
+ *b:ale_salt_salt-lint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to salt-lint.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt
index ffd53c2a..33771e49 100644
--- a/doc/ale-supported-languages-and-tools.txt
+++ b/doc/ale-supported-languages-and-tools.txt
@@ -13,12 +13,16 @@ Notes:
`!!` These linters check only files on disk. See |ale-lint-file-linters|
* Ada
+ * `ada_language_server`
* `gcc`
* `gnatpp`
* Ansible
* `ansible-lint`
* API Blueprint
* `drafter`
+* APKBUILD
+ * `apkbuild-lint`
+ * `secfixes-check`
* AsciiDoc
* `alex`!!
* `languagetool`!!
@@ -49,8 +53,8 @@ Notes:
* `astyle`
* `ccls`
* `clang` (`cc`)
- * `clangd`
* `clang-format`
+ * `clangd`
* `clangtidy`!!
* `cppcheck`
* `cpplint`!!
@@ -67,9 +71,9 @@ Notes:
* `astyle`
* `ccls`
* `clang` (`cc`)
+ * `clang-format`
* `clangcheck`!!
* `clangd`
- * `clang-format`
* `clangtidy`!!
* `clazy`!!
* `cppcheck`
@@ -116,11 +120,14 @@ Notes:
* Dafny
* `dafny`!!
* Dart
+ * `analysis_server`
* `dartanalyzer`!!
* `dartfmt`!!
* `language_server`
* Dhall
* `dhall-format`
+ * `dhall-freeze`
+ * `dhall-lint`
* Dockerfile
* `dockerfile_lint`
* `hadolint`
@@ -140,8 +147,9 @@ Notes:
* `erubis`
* `ruumba`
* Erlang
- * `erlc`
* `SyntaxErl`
+ * `elvis`!!
+ * `erlc`
* Fish
* `fish` (-n flag)
* `fish_indent`
@@ -160,17 +168,17 @@ Notes:
* Go
* `bingo`
* `go build`!!
+ * `go mod`!!
+ * `go vet`!!
* `gofmt`
* `goimports`
* `golangci-lint`!!
* `golangserver`
* `golint`
* `gometalinter`!!
- * `go mod`!!
* `gopls`
* `gosimple`!!
* `gotype`!!
- * `go vet`!!
* `revive`!!
* `staticcheck`!!
* GraphQL
@@ -196,16 +204,18 @@ Notes:
* `hie`
* `hindent`
* `hlint`
+ * `hls`
+ * `ormolu`
* `stack-build`!!
* `stack-ghc`
* `stylish-haskell`
* HCL
* `terraform-fmt`
* HTML
+ * `HTMLHint`
* `alex`!!
* `fecs`
* `html-beautify`
- * `HTMLHint`
* `prettier`
* `proselint`
* `tidy`
@@ -214,15 +224,17 @@ Notes:
* `idris`
* Ink
* `ink-language-server`
+* Inko
+ * `inko` !!
* ISPC
* `ispc`!!
* Java
+ * `PMD`
* `checkstyle`
* `eclipselsp`
* `google-java-format`
* `javac`
* `javalsp`
- * `PMD`
* `uncrustify`
* JavaScript
* `eslint`
@@ -241,6 +253,7 @@ Notes:
* `jq`
* `jsonlint`
* `prettier`
+ * `spectral`
* Julia
* `languageserver`
* Kotlin
@@ -266,6 +279,7 @@ Notes:
* Lua
* `luac`
* `luacheck`
+ * `luafmt`
* Mail
* `alex`!!
* `languagetool`!!
@@ -298,6 +312,7 @@ Notes:
* nix
* `nix-instantiate`
* `nixpkgs-fmt`
+ * `rnix-lsp`
* nroff
* `alex`!!
* `proselint`
@@ -316,6 +331,10 @@ Notes:
* `ocamlformat`
* `ocp-indent`
* `ols`
+* OpenApi
+ * `ibm_validator`
+ * `prettier`
+ * `yamllint`
* Pawn
* `uncrustify`
* Perl
@@ -325,15 +344,17 @@ Notes:
* Perl6
* `perl6 -c`
* PHP
+ * `intelephense`
* `langserver`
* `phan`
+ * `php -l`
+ * `php-cs-fixer`
* `phpcbf`
* `phpcs`
- * `php-cs-fixer`
- * `php -l`
* `phpmd`
* `phpstan`
* `psalm`!!
+ * `tlint`
* PO
* `alex`!!
* `msgfmt`
@@ -362,6 +383,7 @@ Notes:
* `purescript-language-server`
* `purty`
* Python
+ * `autoimport`
* `autopep8`
* `bandit`
* `black`
@@ -384,10 +406,13 @@ Notes:
* `qmlfmt`
* `qmllint`
* R
+ * `languageserver`
* `lintr`
* `styler`
* Racket
* `raco`
+* Re:VIEW
+ * `redpen`
* ReasonML
* `merlin`
* `ols`
@@ -401,8 +426,6 @@ Notes:
* `textlint`
* `vale`
* `write-good`
-* Re:VIEW
- * `redpen`
* RPM spec
* `rpmlint`
* Ruby
@@ -422,6 +445,8 @@ Notes:
* `rust-analyzer`
* `rustc` (see |ale-integration-rust|)
* `rustfmt`
+* Salt
+ * `salt-lint`
* Sass
* `sass-lint`
* `stylelint`
@@ -447,10 +472,10 @@ Notes:
* `solium`
* SQL
* `pgformatter`
+ * `sql-lint`
* `sqlfmt`
* `sqlformat`
* `sqlint`
- * `sql-lint`
* Stylus
* `stylelint`
* SugarSS
@@ -463,7 +488,10 @@ Notes:
* Tcl
* `nagelfar`!!
* Terraform
- * `fmt`
+ * `terraform`
+ * `terraform-fmt-fixer`
+ * `terraform-ls`
+ * `terraform-lsp`
* `tflint`
* Texinfo
* `alex`!!
@@ -480,6 +508,7 @@ Notes:
* Thrift
* `thrift`
* TypeScript
+ * `deno`
* `eslint`
* `fecs`
* `prettier`
@@ -489,6 +518,7 @@ Notes:
* `typecheck`
* VALA
* `uncrustify`
+ * `vala_lint`!!
* Verilog
* `hdl-checker`
* `iverilog`
@@ -517,7 +547,9 @@ Notes:
* `xmllint`
* YAML
* `prettier`
+ * `spectral`
* `swaglint`
+ * `yamlfix`
* `yamllint`
* YANG
* `yang-lsp`
diff --git a/doc/ale-terraform.txt b/doc/ale-terraform.txt
index f62db190..175bdf5c 100644
--- a/doc/ale-terraform.txt
+++ b/doc/ale-terraform.txt
@@ -33,6 +33,28 @@ g:ale_terraform_terraform_executable *g:ale_terraform_terraform_executable*
===============================================================================
+terraform-ls *ale-terraform-terraform-ls*
+
+Official terraform language server. More stable than *terraform-lsp* but
+currently has less features.
+
+g:ale_terraform_ls_executable *g:ale_terraform_ls_executable*
+ *b:ale_terraform_ls_executable*
+ Type: |String|
+ Default: `'terraform-ls'`
+
+ This variable can be changed to use a different executable for terraform-ls.
+
+
+g:ale_terraform_ls_options *g:ale_terraform_ls_options*
+ *b:ale_terraform_ls_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to pass custom CLI flags to terraform-ls.
+
+
+===============================================================================
terraform-lsp *ale-terraform-terraform-lsp*
g:ale_terraform_langserver_executable *g:ale_terraform_langserver_executable*
diff --git a/doc/ale-typescript.txt b/doc/ale-typescript.txt
index 2c50d119..a2446c2c 100644
--- a/doc/ale-typescript.txt
+++ b/doc/ale-typescript.txt
@@ -3,6 +3,39 @@ ALE TypeScript Integration *ale-typescript-options*
===============================================================================
+deno *ale-typescript-deno*
+
+Starting from version 1.6.0, Deno comes with its own language server. Earlier
+versions are not supported.
+
+g:ale_deno_executable *g:ale_deno_executable*
+ *b:ale_deno_executable*
+ Type: |String|
+ Default: `'deno'`
+
+
+g:ale_deno_lsp_project_root *g:ale_deno_lsp_project_root*
+ *b:ale_deno_lsp_project_root*
+ Type: |String|
+ Default: `''`
+
+ If this variable is left unset, ALE will try to find the project root by
+ executing the following steps in the given order:
+
+ 1. Find an ancestor directory containing a tsconfig.json.
+ 2. Find an ancestory irectory containing a .git folder.
+ 3. Use the directory of the current buffer (if the buffer was opened from
+ a file).
+
+g:ale_deno_unstable *g:ale_deno_unstable*
+ *b:ale_deno_unstable*
+ Type: |Number|
+ Default: `0`
+
+ Enable or disable unstable Deno features and APIs.
+
+
+===============================================================================
eslint *ale-typescript-eslint*
Because of how TypeScript compiles code to JavaScript and how interrelated
@@ -139,4 +172,31 @@ g:ale_typescript_tsserver_use_global *g:ale_typescript_tsserver_use_global*
===============================================================================
+xo *ale-typescript-xo*
+
+g:ale_typescript_xo_executable *g:ale_typescript_xo_executable*
+ *b:ale_typescript_xo_executable*
+ Type: |String|
+ Default: `'xo'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_typescript_xo_options *g:ale_typescript_xo_options*
+ *b:ale_typescript_xo_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to xo.
+
+
+g:ale_typescript_xo_use_global *g:ale_typescript_xo_use_global*
+ *b:ale_typescript_xo_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-vala.txt b/doc/ale-vala.txt
index ca24bcf4..d48f68bb 100644
--- a/doc/ale-vala.txt
+++ b/doc/ale-vala.txt
@@ -9,4 +9,25 @@ See |ale-c-uncrustify| for information about the available options.
===============================================================================
+Vala-Lint *ale-vala-vala-lint*
+
+g:vala_vala_lint_executable *g:vala_vala_lint_executable*
+ *b:vala_vala_lint_executable*
+ Type: |String|
+ Default: `'io.elementary.vala-lint'`
+
+ This variable can be set to specify a Vala-Lint executable file.
+
+
+g:vala_vala_lint_config_filename *g:vala_vala_lint_config_filename*
+ *b:vala_vala_lint_config_filename*
+ Type: |String|
+ Default: `'vala-lint.conf'`
+
+ This variable can be set to specify a Vala-Lint config filename. When a file
+ with the specified name was not found or this variable was set to empty,
+ Vala-Lint will be executed without specifying a config filename.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-yaml.txt b/doc/ale-yaml.txt
index c9a12ea1..04871403 100644
--- a/doc/ale-yaml.txt
+++ b/doc/ale-yaml.txt
@@ -15,7 +15,38 @@ Install prettier either globally or locally: >
npm install prettier -g # global
npm install prettier # local
<
-
+===============================================================================
+spectral *ale-yaml-spectral*
+
+Website: https://github.com/stoplightio/spectral
+
+Installation
+-------------------------------------------------------------------------------
+
+Install spectral either globally or locally: >
+
+ npm install @stoplight/spectral -g # global
+ npm install @stoplight/spectral # local
+<
+
+Options
+-------------------------------------------------------------------------------
+
+g:ale_yaml_spectral_executable *g:ale_yaml_spectral_executable*
+ *b:ale_yaml_spectral_executable*
+ Type: |String|
+ Default: `'spectral'`
+
+ This variable can be set to change the path to spectral.
+
+g:ale_yaml_spectral_use_global *g:ale_yaml_spectral_use_global*
+ *b:ale_yaml_spectral_use_global*
+ Type: |String|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+
===============================================================================
swaglint *ale-yaml-swaglint*
@@ -49,6 +80,43 @@ g:ale_yaml_swaglint_use_global *g:ale_yaml_swaglint_use_global*
See |ale-integrations-local-executables|
+===============================================================================
+yamlfix *ale-yaml-yamlfix*
+
+Website: https://lyz-code.github.io/yamlfix
+
+
+Installation
+-------------------------------------------------------------------------------
+
+Install yamlfix: >
+
+ pip install yamlfix
+<
+
+Options
+-------------------------------------------------------------------------------
+g:ale_yaml_yamlfix_executable *g:ale_yaml_yamlfix_executable*
+ *b:ale_yaml_yamlfix_executable*
+ Type: |String|
+ Default: `'yamlfix'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_yaml_yamlfix_options *g:ale_yaml_yamlfix_options*
+ *b:ale_yaml_yamlfix_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass extra options to yamlfix.
+
+g:ale_yaml_yamlfix_use_global *g:ale_yaml_yamlfix_use_global*
+ *b:ale_yaml_yamlfix_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
===============================================================================
yamllint *ale-yaml-yamllint*
diff --git a/doc/ale.txt b/doc/ale.txt
index e7f69011..034d62b8 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -20,6 +20,7 @@ CONTENTS *ale-contents*
5.4 Find References...................|ale-find-references|
5.5 Hovering..........................|ale-hover|
5.6 Symbol Search.....................|ale-symbol-search|
+ 5.7 Refactoring: Rename, Actions......|ale-refactor|
6. Global Options.......................|ale-options|
6.1 Highlights........................|ale-highlights|
7. Linter/Fixer Options.................|ale-integration-options|
@@ -227,8 +228,8 @@ A minimal configuration for a language server linter might look so. >
\ 'project_root': '/path/to/root_of_project',
\})
<
-For language servers that use a TCP socket connection, you should define the
-address to connect to instead. >
+For language servers that use a TCP or named pipe socket connection, you
+should define the address to connect to instead. >
call ale#linter#Define('filetype_here', {
\ 'name': 'any_name_you_want',
@@ -645,6 +646,9 @@ problem will be displayed in a balloon instead of hover information.
Hover information can be displayed in the preview window instead by setting
|g:ale_hover_to_preview| to `1`.
+When using Neovim, if |g:ale_hover_to_floating_preview| or |g:ale_floating_preview|
+is set to 1, the hover information will show in a floating window.
+
For Vim 8.1+ terminals, mouse hovering is disabled by default. Enabling
|balloonexpr| commands in terminals can cause scrolling issues in terminals,
so ALE will not attempt to show balloons unless |g:ale_set_balloons| is set to
@@ -669,6 +673,34 @@ ALE supports searching for workspace symbols via LSP linters with the
|ALESymbolSearch| command. See the documentation for the command
for a full list of options.
+-------------------------------------------------------------------------------
+5.7 Refactoring: Rename, Actions *ale-refactor*
+
+ALE supports renaming 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.
+
+Actions will appear in the right click mouse menu by default for GUI versions
+of Vim, unless disabled by setting |g:ale_popup_menu_enabled| to `0`.
+
+Make sure to set your Vim to move the cursor position whenever you right
+click, and enable the mouse menu: >
+
+ set mouse=a
+ set mousemodel=popup_setpos
+<
+You may wish to remove some other menu items you don't want to see: >
+
+ silent! aunmenu PopUp.Select\ Word
+ silent! aunmenu PopUp.Select\ Sentence
+ silent! aunmenu PopUp.Select\ Paragraph
+ silent! aunmenu PopUp.Select\ Line
+ silent! aunmenu PopUp.Select\ Block
+ silent! aunmenu PopUp.Select\ Blockwise
+ silent! aunmenu PopUp.Select\ All
+<
===============================================================================
6. Global Options *ale-options*
@@ -925,6 +957,15 @@ g:ale_default_navigation *g:ale_default_navigation*
buffer, such as for |ALEFindReferences|, or |ALEGoToDefinition|.
+g:ale_detail_to_floating_preview *g:ale_detail_to_floating_preview*
+ *b:ale_detail_to_floating_preview*
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, Neovim will use a floating window for
+ ALEDetail output.
+
+
g:ale_disable_lsp *g:ale_disable_lsp*
*b:ale_disable_lsp*
@@ -1148,6 +1189,16 @@ g:ale_fix_on_save_ignore *g:ale_fix_on_save_ignore*
let g:ale_fix_on_save_ignore = [g:AddBar]
<
+g:ale_floating_preview *g:ale_floating_preview*
+
+ Type: |Number|
+ Default: `0`
+
+ When set to `1`, Neovim will use a floating window for ale's preview window.
+ This is equivalent to setting |g:ale_hover_to_floating_preview| and
+ |g:ale_detail_to_floating_preview| to `1`.
+
+
g:ale_history_enabled *g:ale_history_enabled*
Type: |Number|
@@ -1206,6 +1257,14 @@ g:ale_hover_to_preview *g:ale_hover_to_preview*
instead of in balloons or the message line.
+g:ale_hover_to_floating_preview *g:ale_hover_to_floating_preview*
+ *b:ale_hover_to_floating_preview*
+ Type: |Number|
+ Default: `0`
+
+ If set to `1`, Neovim will use floating windows for hover messages.
+
+
g:ale_keep_list_window_open *g:ale_keep_list_window_open*
*b:ale_keep_list_window_open*
Type: |Number|
@@ -1497,11 +1556,13 @@ g:ale_linters *g:ale_linters*
following values: >
{
+ \ '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'],
@@ -1648,6 +1709,15 @@ g:ale_lsp_show_message_severity *g:ale_lsp_show_message_severity*
`'disabled'` - Doesn't display any information at all.
+g:ale_lsp_suggestions *g:ale_lsp_suggestions*
+
+ Type: |Number|
+ Default: 1
+
+ This variable defines if suggestions must be collected from LSP or tsserver
+ and shown.
+
+
g:ale_lsp_root *g:ale_lsp_root*
*b:ale_lsp_root*
@@ -1665,6 +1735,7 @@ g:ale_lsp_root *g:ale_lsp_root*
If neither variable yields a result, a linter-specific function is invoked to
detect a project root. If this, too, yields no result, the linter is disabled.
+
g:ale_max_buffer_history_size *g:ale_max_buffer_history_size*
Type: |Number|
@@ -1773,6 +1844,21 @@ g:ale_pattern_options_enabled *g:ale_pattern_options_enabled*
will not set buffer variables per |g:ale_pattern_options|.
+g:ale_popup_menu_enabled *g:ale_popup_menu_enabled*
+
+ Type: |Number|
+ Default: `has('gui_running')`
+
+ When this option is set to `1`, ALE will show code actions and rename
+ capabilities in the right click mouse menu when there's a LSP server or
+ tsserver available. See |ale-refactor|.
+
+ This feature is only supported in GUI versions of Vim.
+
+ This setting must be set to `1` before ALE is loaded for this behavior
+ to be enabled. See |ale-lint-settings-on-startup|.
+
+
g:ale_rename_tsserver_find_in_comments *g:ale_rename_tsserver_find_in_comments*
Type: |Number|
@@ -1797,7 +1883,7 @@ g:ale_rename_tsserver_find_in_strings *g:ale_rename_tsserver_find_in_strings*
g:ale_set_balloons *g:ale_set_balloons*
*b:ale_set_balloons*
- Type: |Number|
+ Type: |Number| or |String|
Default: `has('balloon_eval') && has('gui_running')`
When this option is set to `1`, balloon messages will be displayed for
@@ -1808,6 +1894,13 @@ g:ale_set_balloons *g:ale_set_balloons*
supporting "Hover" information, per |ale-hover|, then brief information
about the symbol under the cursor will be displayed in a balloon.
+ This option can be set to `'hover'` to only enable balloons for hover
+ message, so diagnostics are never shown in balloons. You may wish to
+ configure use this setting only in GUI Vim like so: >
+
+ let g:ale_set_balloons = has('gui_running') ? 'hover' : 0
+<
+
Balloons can be enabled for terminal versions of Vim that support balloons,
but some versions of Vim will produce strange mouse behavior when balloons
are enabled. To configure balloons for your terminal, you should first
@@ -2506,8 +2599,12 @@ documented in additional help files.
ada.....................................|ale-ada-options|
gcc...................................|ale-ada-gcc|
gnatpp................................|ale-ada-gnatpp|
+ ada-language-server...................|ale-ada-language-server|
ansible.................................|ale-ansible-options|
ansible-lint..........................|ale-ansible-ansible-lint|
+ apkbuild................................|ale-apkbuild-options|
+ apkbuild-lint.........................|ale-apkbuild-apkbuild-lint|
+ secfixes-check........................|ale-apkbuild-secfixes-check|
asciidoc................................|ale-asciidoc-options|
write-good............................|ale-asciidoc-write-good|
textlint..............................|ale-asciidoc-textlint|
@@ -2571,9 +2668,16 @@ documented in additional help files.
dfmt..................................|ale-d-dfmt|
dls...................................|ale-d-dls|
uncrustify............................|ale-d-uncrustify|
+ dafny...................................|ale-dafny-options|
+ dafny.................................|ale-dafny-dafny|
dart....................................|ale-dart-options|
+ analysis_server.......................|ale-dart-analysis_server|
dartanalyzer..........................|ale-dart-dartanalyzer|
dartfmt...............................|ale-dart-dartfmt|
+ dhall...................................|ale-dhall-options|
+ dhall-format..........................|ale-dhall-format|
+ dhall-freeze..........................|ale-dhall-freeze|
+ dhall-lint............................|ale-dhall-lint|
dockerfile..............................|ale-dockerfile-options|
dockerfile_lint.......................|ale-dockerfile-dockerfile_lint|
hadolint..............................|ale-dockerfile-hadolint|
@@ -2589,6 +2693,7 @@ documented in additional help files.
elm-make..............................|ale-elm-elm-make|
erlang..................................|ale-erlang-options|
dialyzer..............................|ale-erlang-dialyzer|
+ elvis.................................|ale-erlang-elvis|
erlc..................................|ale-erlang-erlc|
syntaxerl.............................|ale-erlang-syntaxerl|
eruby...................................|ale-eruby-options|
@@ -2639,10 +2744,12 @@ documented in additional help files.
hfmt..................................|ale-haskell-hfmt|
hindent...............................|ale-haskell-hindent|
hlint.................................|ale-haskell-hlint|
+ hls...................................|ale-haskell-hls|
stack-build...........................|ale-haskell-stack-build|
stack-ghc.............................|ale-haskell-stack-ghc|
stylish-haskell.......................|ale-haskell-stylish-haskell|
hie...................................|ale-haskell-hie|
+ ormolu................................|ale-haskell-ormolu|
hcl.....................................|ale-hcl-options|
terraform-fmt.........................|ale-hcl-terraform-fmt|
html....................................|ale-html-options|
@@ -2657,6 +2764,8 @@ documented in additional help files.
idris.................................|ale-idris-idris|
ink.....................................|ale-ink-options|
ink-language-server...................|ale-ink-language-server|
+ inko....................................|ale-inko-options|
+ inko..................................|ale-inko-inko|
ispc....................................|ale-ispc-options|
ispc..................................|ale-ispc-ispc|
java....................................|ale-java-options|
@@ -2684,6 +2793,7 @@ documented in additional help files.
jsonlint..............................|ale-json-jsonlint|
jq....................................|ale-json-jq|
prettier..............................|ale-json-prettier|
+ spectral..............................|ale-json-spectral|
julia...................................|ale-julia-options|
languageserver........................|ale-julia-languageserver|
kotlin..................................|ale-kotlin-options|
@@ -2702,6 +2812,7 @@ documented in additional help files.
lua.....................................|ale-lua-options|
luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck|
+ luafmt................................|ale-lua-luafmt|
markdown................................|ale-markdown-options|
markdownlint..........................|ale-markdown-markdownlint|
mdl...................................|ale-markdown-mdl|
@@ -2735,6 +2846,10 @@ documented in additional help files.
ols...................................|ale-ocaml-ols|
ocamlformat...........................|ale-ocaml-ocamlformat|
ocp-indent............................|ale-ocaml-ocp-indent|
+ openapi.................................|ale-openapi-options|
+ ibm_validator.........................|ale-openapi-ibm-validator|
+ prettier..............................|ale-openapi-prettier|
+ yamllint..............................|ale-openapi-yamllint|
pawn....................................|ale-pawn-options|
uncrustify............................|ale-pawn-uncrustify|
perl....................................|ale-perl-options|
@@ -2753,6 +2868,8 @@ documented in additional help files.
psalm.................................|ale-php-psalm|
php-cs-fixer..........................|ale-php-php-cs-fixer|
php...................................|ale-php-php|
+ tlint.................................|ale-php-tlint|
+ intelephense..........................|ale-php-intelephense|
po......................................|ale-po-options|
write-good............................|ale-po-write-good|
pod.....................................|ale-pod-options|
@@ -2778,6 +2895,7 @@ documented in additional help files.
pyrex (cython)..........................|ale-pyrex-options|
cython................................|ale-pyrex-cython|
python..................................|ale-python-options|
+ autoimport............................|ale-python-autoimport|
autopep8..............................|ale-python-autopep8|
bandit................................|ale-python-bandit|
black.................................|ale-python-black|
@@ -2799,6 +2917,7 @@ documented in additional help files.
qml.....................................|ale-qml-options|
qmlfmt................................|ale-qml-qmlfmt|
r.......................................|ale-r-options|
+ languageserver........................|ale-r-languageserver|
lintr.................................|ale-r-lintr|
styler................................|ale-r-styler|
reasonml................................|ale-reasonml-options|
@@ -2826,6 +2945,8 @@ documented in additional help files.
rls...................................|ale-rust-rls|
rustc.................................|ale-rust-rustc|
rustfmt...............................|ale-rust-rustfmt|
+ salt....................................|ale-salt-options|
+ salt-lint.............................|ale-salt-salt-lint|
sass....................................|ale-sass-options|
sasslint..............................|ale-sass-sasslint|
stylelint.............................|ale-sass-stylelint|
@@ -2867,6 +2988,7 @@ documented in additional help files.
terraform...............................|ale-terraform-options|
terraform-fmt-fixer...................|ale-terraform-fmt-fixer|
terraform.............................|ale-terraform-terraform|
+ terraform-ls..........................|ale-terraform-terraform-ls|
terraform-lsp.........................|ale-terraform-terraform-lsp|
tflint................................|ale-terraform-tflint|
tex.....................................|ale-tex-options|
@@ -2882,11 +3004,13 @@ documented in additional help files.
thrift..................................|ale-thrift-options|
thrift................................|ale-thrift-thrift|
typescript..............................|ale-typescript-options|
+ deno..................................|ale-typescript-deno|
eslint................................|ale-typescript-eslint|
prettier..............................|ale-typescript-prettier|
standard..............................|ale-typescript-standard|
tslint................................|ale-typescript-tslint|
tsserver..............................|ale-typescript-tsserver|
+ xo....................................|ale-typescript-xo|
vala....................................|ale-vala-options|
uncrustify............................|ale-vala-uncrustify|
verilog/systemverilog...................|ale-verilog-options|
@@ -2900,11 +3024,11 @@ documented in additional help files.
hdl-checker...........................|ale-vhdl-hdl-checker|
vcom..................................|ale-vhdl-vcom|
xvhdl.................................|ale-vhdl-xvhdl|
+ vim help................................|ale-vim-help-options|
+ write-good............................|ale-vim-help-write-good|
vim.....................................|ale-vim-options|
vimls.................................|ale-vim-vimls|
vint..................................|ale-vim-vint|
- vim help................................|ale-vim-help-options|
- write-good............................|ale-vim-help-write-good|
vue.....................................|ale-vue-options|
prettier..............................|ale-vue-prettier|
vls...................................|ale-vue-vls|
@@ -2914,7 +3038,9 @@ documented in additional help files.
xmllint...............................|ale-xml-xmllint|
yaml....................................|ale-yaml-options|
prettier..............................|ale-yaml-prettier|
+ spectral..............................|ale-yaml-spectral|
swaglint..............................|ale-yaml-swaglint|
+ yamlfix...............................|ale-yaml-yamlfix|
yamllint..............................|ale-yaml-yamllint|
yang....................................|ale-yang-options|
yang-lsp..............................|ale-yang-lsp|
@@ -3100,11 +3226,17 @@ ALERename *ALERename*
The symbol where the cursor is resting will be the symbol renamed, and a
prompt will open to request a new name.
- ALE will refuse to complete a rename operation if there are files to modify
- which have not yet been saved in Vim. If the command is run with a bang
- (`:ALERename!`), all warnings will be suppressed, and files that are still
- open in Vim and not saved will be ignored and left in a state where symbols
- in those files will not be updated.
+
+ALECodeAction *ALECodeAction*
+
+ Apply a code action via LSP servers or `tsserver`.
+
+ If there is an error present on a line that can be fixed, ALE will
+ automatically fix a line, unless there are multiple possible code fixes to
+ apply.
+
+ This command can be run in visual mode apply actions, such as applicable
+ refactors. A menu will be shown to select code action to apply.
ALERepeatSelection *ALERepeatSelection*
@@ -3725,7 +3857,7 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
When this argument is set to `'socket'`, then the
linter will be defined as an LSP linter via a TCP
- socket connection. `address` must be set.
+ or named pipe socket connection. `address` must be set.
ALE will not start a server automatically.
@@ -3750,7 +3882,10 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`address` A |String| representing an address to connect to,
or a |Funcref| accepting a buffer number and
- returning the |String|.
+ returning the |String|. If the value contains a
+ colon, it is interpreted as referring to a TCP
+ socket; otherwise it is interpreted as the path of a
+ named pipe.
The result can be computed with |ale#command#Run()|.
diff --git a/plugin/ale.vim b/plugin/ale.vim
index 32ec14ac..1735715d 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -138,6 +138,15 @@ let g:ale_set_balloons = get(g:, 'ale_set_balloons', has('balloon_eval') && has(
" Use preview window for hover messages.
let g:ale_hover_to_preview = get(g:, 'ale_hover_to_preview', 0)
+" Float preview windows in Neovim
+let g:ale_floating_preview = get(g:, 'ale_floating_preview', 0)
+
+" Hovers use floating windows in Neovim
+let g:ale_hover_to_floating_preview = get(g:, 'ale_hover_to_floating_preview', 0)
+
+" Detail uses floating windows in Neovim
+let g:ale_detail_to_floating_preview = get(g:, 'ale_detail_to_floating_preview', 0)
+
" This flag can be set to 0 to disable warnings for trailing whitespace
let g:ale_warn_about_trailing_whitespace = get(g:, 'ale_warn_about_trailing_whitespace', 1)
" This flag can be set to 0 to disable warnings for trailing blank lines
@@ -158,7 +167,10 @@ let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
" This variable can be overridden to set the GO111MODULE environment variable.
let g:ale_go_go111module = get(g:, 'ale_go_go111module', '')
-if g:ale_set_balloons
+" If 1, enable a popup menu for commands.
+let g:ale_popup_menu_enabled = get(g:, 'ale_popup_menu_enabled', has('gui_running'))
+
+if g:ale_set_balloons is 1 || g:ale_set_balloons is# 'hover'
call ale#balloon#Enable()
endif
@@ -166,6 +178,10 @@ if g:ale_completion_enabled
call ale#completion#Enable()
endif
+if g:ale_popup_menu_enabled
+ call ale#code_action#EnablePopUpMenu()
+endif
+
" Define commands for moving through warnings and errors.
command! -bar -nargs=* ALEPrevious
\ :call ale#loclist_jumping#WrapJump('before', <q-args>)
@@ -238,7 +254,10 @@ command! -bar ALEComplete :call ale#completion#GetCompletions('ale-manual')
command! -bar ALEImport :call ale#completion#Import()
" Rename symbols using tsserver and LSP
-command! -bar -bang ALERename :call ale#rename#Execute({'force_save': '<bang>' is# '!'})
+command! -bar -bang ALERename :call ale#rename#Execute()
+
+" Apply code actions to a range.
+command! -bar -range ALECodeAction :call ale#codefix#Execute(<range>)
" Organize import statements using tsserver
command! -bar ALEOrganizeImports :call ale#organize_imports#Execute()
@@ -283,6 +302,7 @@ nnoremap <silent> <Plug>(ale_documentation) :ALEDocumentation<Return>
inoremap <silent> <Plug>(ale_complete) <C-\><C-O>:ALEComplete<Return>
nnoremap <silent> <Plug>(ale_import) :ALEImport<Return>
nnoremap <silent> <Plug>(ale_rename) :ALERename<Return>
+nnoremap <silent> <Plug>(ale_code_action) :ALECodeAction<Return>
nnoremap <silent> <Plug>(ale_repeat_selection) :ALERepeatSelection<Return>
" Set up autocmd groups now.
diff --git a/run-tests b/run-tests
index 1d452a72..ee2b10cd 100755
--- a/run-tests
+++ b/run-tests
@@ -9,8 +9,11 @@ set -u
# options, or read the output below.
#
-image=w0rp/ale
-current_image_id=f58c7bf8900f
+image=denseanalysis/ale
+
+# Create docker image tag based on Dockerfile contents
+image_tag=$(md5sum Dockerfile | cut -d' ' -f1)
+git_version=$(git describe --always --tags)
# Used in all test scripts for running the selected Docker image.
DOCKER_RUN_IMAGE="$image"
@@ -21,9 +24,9 @@ tests='test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*.vader'
verbose_flag=''
quiet_flag=''
run_neovim_02_tests=1
-run_neovim_03_tests=1
+run_neovim_04_tests=1
run_vim_80_tests=1
-run_vim_81_tests=1
+run_vim_82_tests=1
run_linters=1
while [ $# -ne 0 ]; do
@@ -36,58 +39,66 @@ while [ $# -ne 0 ]; do
quiet_flag='-q'
shift
;;
+ --build-image)
+ run_vim_80_tests=0
+ run_vim_82_tests=0
+ run_neovim_02_tests=0
+ run_neovim_04_tests=0
+ run_linters=0
+ shift
+ ;;
--neovim-only)
run_vim_80_tests=0
- run_vim_81_tests=0
+ run_vim_82_tests=0
run_linters=0
shift
;;
--neovim-02-only)
- run_neovim_03_tests=0
+ run_neovim_04_tests=0
run_vim_80_tests=0
- run_vim_81_tests=0
+ run_vim_82_tests=0
run_linters=0
shift
;;
- --neovim-03-only)
+ --neovim-04-only)
run_neovim_02_tests=0
run_vim_80_tests=0
- run_vim_81_tests=0
+ run_vim_82_tests=0
run_linters=0
shift
;;
--vim-only)
run_neovim_02_tests=0
- run_neovim_03_tests=0
+ run_neovim_04_tests=0
run_linters=0
shift
;;
--vim-80-only)
run_neovim_02_tests=0
- run_neovim_03_tests=0
- run_vim_81_tests=0
+ run_neovim_04_tests=0
+ run_vim_82_tests=0
run_linters=0
shift
;;
- --vim-81-only)
+ --vim-82-only)
run_neovim_02_tests=0
- run_neovim_03_tests=0
+ run_neovim_04_tests=0
run_vim_80_tests=0
run_linters=0
shift
;;
--linters-only)
run_vim_80_tests=0
- run_vim_81_tests=0
+ run_vim_82_tests=0
run_neovim_02_tests=0
- run_neovim_03_tests=0
+ run_neovim_04_tests=0
shift
;;
--fast)
run_vim_80_tests=0
- run_vim_81_tests=0
+ run_vim_82_tests=0
run_neovim_02_tests=0
- run_neovim_03_tests=1
+ run_neovim_04_tests=1
shift
;;
--help)
@@ -99,12 +110,13 @@ while [ $# -ne 0 ]; do
echo 'Options:'
echo ' -v Enable verbose output'
echo ' -q Hide output for successful tests'
- echo ' --neovim-only Run tests only for NeoVim 0.2 and 0.3'
+ echo ' --build-image Run docker image build only.'
+ echo ' --neovim-only Run tests only for NeoVim'
echo ' --neovim-02-only Run tests only for NeoVim 0.2'
- echo ' --neovim-03-only Run tests only for NeoVim 0.3'
- echo ' --vim-only Run tests only for Vim 8.0 and 8.1'
+ echo ' --neovim-04-only Run tests only for NeoVim 0.4'
+ echo ' --vim-only Run tests only for Vim'
echo ' --vim-80-only Run tests only for Vim 8.0'
- echo ' --vim-81-only Run tests only for Vim 8.1'
+ echo ' --vim-82-only Run tests only for Vim 8.2'
echo ' --linters-only Run only Vint and custom checks'
echo ' --fast Run only the fastest Vim and custom checks'
echo ' --help Show this help text'
@@ -138,8 +150,36 @@ fi
# Delete .swp files in the test directory, which cause Vim 8 to hang.
find test -name '*.swp' -delete
-docker images -q w0rp/ale | grep "^$current_image_id" > /dev/null \
- || docker pull "$image"
+# Check if docker un image is available locally
+has_image=$(docker images ls --filter reference="${image}:${image_tag}" --quiet | wc -l)
+
+if [ "$has_image" -eq 0 ]
+then
+
+ echo "Downloading run image ${image}:${image_tag}"
+ docker pull "${image}:${image_tag}" &> /dev/null
+
+ if [ $? -eq 1 ]
+ then
+ echo "Could not pull image ${image}:${image_tag}"
+ echo "Building run image ${image}:${image_tag}"
+ docker build --build-arg GIT_VERSION="$git_version" -t "${image}:${image_tag}" .
+ docker tag "${image}:${image_tag}" "${image}:latest"
+
+ if [[ -z "${DOCKER_HUB_USER:-}" || -z "${DOCKER_HUB_PASS:-}" ]]
+ then
+ echo "Docker Hub credentials not set, skip push"
+ else
+ echo "Push ${image}:${image_tag} to Docker Hub"
+ echo "$DOCKER_HUB_PASS" | docker login -u "$DOCKER_HUB_USER" --password-stdin
+ docker push "${image}:${image_tag}"
+ fi
+ fi
+else
+ echo "Docker run image ${image}:${image_tag} ready"
+fi
+
+docker tag "${image}:${image_tag}" "${image}:latest"
output_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
@@ -174,9 +214,9 @@ trap cancel_tests INT TERM
for vim in $(docker run --rm "$DOCKER_RUN_IMAGE" ls /vim-build/bin | grep '^neovim\|^vim' ); do
if ( [[ $vim =~ ^vim-v8.0 ]] && ((run_vim_80_tests)) ) \
- || ( [[ $vim =~ ^vim-v8.1 ]] && ((run_vim_81_tests)) ) \
+ || ( [[ $vim =~ ^vim-v8.2 ]] && ((run_vim_82_tests)) ) \
|| ( [[ $vim =~ ^neovim-v0.2 ]] && ((run_neovim_02_tests)) ) \
- || ( [[ $vim =~ ^neovim-v0.3 ]] && ((run_neovim_03_tests)) ); then
+ || ( [[ $vim =~ ^neovim-v0.4 ]] && ((run_neovim_04_tests)) ); then
echo "Starting Vim: $vim..."
file_number=$((file_number+1))
test/script/run-vader-tests $quiet_flag $verbose_flag "$vim" "$tests" \
diff --git a/supported-tools.md b/supported-tools.md
index f93f2ad1..b649ec22 100644
--- a/supported-tools.md
+++ b/supported-tools.md
@@ -22,12 +22,16 @@ formatting.
---
* Ada
+ * [ada_language_server](https://github.com/AdaCore/ada_language_server)
* [gcc](https://gcc.gnu.org)
* [gnatpp](https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/gnat_utility_programs.html#the-gnat-pretty-printer-gnatpp) :floppy_disk:
* Ansible
* [ansible-lint](https://github.com/willthames/ansible-lint)
* API Blueprint
* [drafter](https://github.com/apiaryio/drafter)
+* APKBUILD
+ * [apkbuild-lint](https://gitlab.alpinelinux.org/Leo/atools)
+ * [secfixes-check](https://gitlab.alpinelinux.org/Leo/atools)
* AsciiDoc
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
@@ -58,8 +62,8 @@ formatting.
* [astyle](http://astyle.sourceforge.net/)
* [ccls](https://github.com/MaskRay/ccls)
* [clang](http://clang.llvm.org/)
- * [clangd](https://clang.llvm.org/extra/clangd.html)
* [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
+ * [clangd](https://clang.llvm.org/extra/clangd.html)
* [clangtidy](http://clang.llvm.org/extra/clang-tidy/) :floppy_disk:
* [cppcheck](http://cppcheck.sourceforge.net)
* [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint)
@@ -76,9 +80,9 @@ formatting.
* [astyle](http://astyle.sourceforge.net/)
* [ccls](https://github.com/MaskRay/ccls)
* [clang](http://clang.llvm.org/)
+ * [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
* [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) :floppy_disk:
* [clangd](https://clang.llvm.org/extra/clangd.html)
- * [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
* [clangtidy](http://clang.llvm.org/extra/clang-tidy/) :floppy_disk:
* [clazy](https://github.com/KDE/clazy) :floppy_disk:
* [cppcheck](http://cppcheck.sourceforge.net)
@@ -125,11 +129,14 @@ formatting.
* Dafny
* [dafny](https://rise4fun.com/Dafny) :floppy_disk:
* Dart
+ * [analysis_server](https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server)
* [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) :floppy_disk:
* [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt)
* [language_server](https://github.com/natebosch/dart_language_server)
* Dhall
* [dhall-format](https://github.com/dhall-lang/dhall-lang)
+ * [dhall-freeze](https://github.com/dhall-lang/dhall-lang)
+ * [dhall-lint](https://github.com/dhall-lang/dhall-lang)
* Dockerfile
* [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint)
* [hadolint](https://github.com/hadolint/hadolint)
@@ -149,8 +156,9 @@ formatting.
* [erubis](https://github.com/kwatch/erubis)
* [ruumba](https://github.com/ericqweinstein/ruumba)
* Erlang
- * [erlc](http://erlang.org/doc/man/erlc.html)
* [SyntaxErl](https://github.com/ten0s/syntaxerl)
+ * [elvis](https://github.com/inaka/elvis) :floppy_disk:
+ * [erlc](http://erlang.org/doc/man/erlc.html)
* Fish
* fish [-n flag](https://linux.die.net/man/1/fish)
* [fish_indent](https://fishshell.com/docs/current/cmds/fish_indent.html)
@@ -169,17 +177,17 @@ formatting.
* Go
* [bingo](https://github.com/saibing/bingo) :warning:
* [go build](https://golang.org/cmd/go/) :warning: :floppy_disk:
+ * [go mod](https://golang.org/cmd/go/) :warning: :floppy_disk:
+ * [go vet](https://golang.org/cmd/vet/) :floppy_disk:
* [gofmt](https://golang.org/cmd/gofmt/)
* [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) :warning:
* [golangci-lint](https://github.com/golangci/golangci-lint) :warning: :floppy_disk:
* [golangserver](https://github.com/sourcegraph/go-langserver) :warning:
* [golint](https://godoc.org/github.com/golang/lint)
* [gometalinter](https://github.com/alecthomas/gometalinter) :warning: :floppy_disk:
- * [go mod](https://golang.org/cmd/go/) :warning: :floppy_disk:
* [gopls](https://github.com/golang/go/wiki/gopls) :warning:
* [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) :warning: :floppy_disk:
* [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) :warning: :floppy_disk:
- * [go vet](https://golang.org/cmd/vet/) :floppy_disk:
* [revive](https://github.com/mgechev/revive) :warning: :floppy_disk:
* [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) :warning: :floppy_disk:
* GraphQL
@@ -205,16 +213,18 @@ formatting.
* [hie](https://github.com/haskell/haskell-ide-engine)
* [hindent](https://hackage.haskell.org/package/hindent)
* [hlint](https://hackage.haskell.org/package/hlint)
+ * [hls](https://github.com/haskell/haskell-language-server)
+ * [ormolu](https://github.com/tweag/ormolu)
* [stack-build](https://haskellstack.org/) :floppy_disk:
* [stack-ghc](https://haskellstack.org/)
* [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
* HCL
* [terraform-fmt](https://github.com/hashicorp/terraform)
* HTML
+ * [HTMLHint](http://htmlhint.com/)
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [fecs](http://fecs.baidu.com/)
* [html-beautify](https://beautifier.io/)
- * [HTMLHint](http://htmlhint.com/)
* [prettier](https://github.com/prettier/prettier)
* [proselint](http://proselint.com/)
* [tidy](http://www.html-tidy.org/)
@@ -223,15 +233,17 @@ formatting.
* [idris](http://www.idris-lang.org/)
* Ink
* [ink-language-server](https://github.com/ephread/ink-language-server)
+* Inko
+ * [inko](https://inko-lang.org/) :floppy_disk:
* ISPC
* [ispc](https://ispc.github.io/) :floppy_disk:
* Java
+ * [PMD](https://pmd.github.io/)
* [checkstyle](http://checkstyle.sourceforge.net)
* [eclipselsp](https://github.com/eclipse/eclipse.jdt.ls)
* [google-java-format](https://github.com/google/google-java-format)
* [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
* [javalsp](https://github.com/georgewfraser/vscode-javac)
- * [PMD](https://pmd.github.io/)
* [uncrustify](https://github.com/uncrustify/uncrustify)
* JavaScript
* [eslint](http://eslint.org/)
@@ -250,6 +262,7 @@ formatting.
* [jq](https://stedolan.github.io/jq/)
* [jsonlint](http://zaa.ch/jsonlint/)
* [prettier](https://github.com/prettier/prettier)
+ * [spectral](https://github.com/stoplightio/spectral)
* Julia
* [languageserver](https://github.com/JuliaEditorSupport/LanguageServer.jl)
* Kotlin
@@ -275,6 +288,7 @@ formatting.
* Lua
* [luac](https://www.lua.org/manual/5.1/luac.html)
* [luacheck](https://github.com/mpeterv/luacheck)
+ * [luafmt](https://github.com/trixnz/lua-fmt)
* Mail
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
@@ -307,6 +321,7 @@ formatting.
* nix
* [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate)
* [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt)
+ * [rnix-lsp](https://github.com/nix-community/rnix-lsp)
* nroff
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [proselint](http://proselint.com/)
@@ -325,6 +340,10 @@ formatting.
* [ocamlformat](https://github.com/ocaml-ppx/ocamlformat)
* [ocp-indent](https://github.com/OCamlPro/ocp-indent)
* [ols](https://github.com/freebroccolo/ocaml-language-server)
+* OpenApi
+ * [ibm_validator](https://github.com/IBM/openapi-validator)
+ * [prettier](https://github.com/prettier/prettier)
+ * [yamllint](https://yamllint.readthedocs.io/)
* Pawn
* [uncrustify](https://github.com/uncrustify/uncrustify)
* Perl
@@ -334,15 +353,17 @@ formatting.
* Perl6
* [perl6 -c](https://perl6.org) :warning:
* PHP
+ * [intelephense](https://github.com/bmewburn/intelephense-docs)
* [langserver](https://github.com/felixfbecker/php-language-server)
* [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions
+ * [php -l](https://secure.php.net/)
+ * [php-cs-fixer](http://cs.sensiolabs.org/)
* [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer)
* [phpcs](https://github.com/squizlabs/PHP_CodeSniffer)
- * [php-cs-fixer](http://cs.sensiolabs.org/)
- * [php -l](https://secure.php.net/)
* [phpmd](https://phpmd.org)
* [phpstan](https://github.com/phpstan/phpstan)
* [psalm](https://getpsalm.org) :floppy_disk:
+ * [tlint](https://github.com/tightenco/tlint)
* PO
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [msgfmt](https://www.gnu.org/software/gettext/manual/html_node/msgfmt-Invocation.html)
@@ -371,6 +392,7 @@ formatting.
* [purescript-language-server](https://github.com/nwolverson/purescript-language-server)
* [purty](https://gitlab.com/joneshf/purty)
* Python
+ * [autoimport](https://lyz-code.github.io/autoimport/)
* [autopep8](https://github.com/hhatto/autopep8)
* [bandit](https://github.com/PyCQA/bandit) :warning:
* [black](https://github.com/ambv/black)
@@ -393,10 +415,13 @@ formatting.
* [qmlfmt](https://github.com/jesperhh/qmlfmt)
* [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint)
* R
+ * [languageserver](https://github.com/REditorSupport/languageserver)
* [lintr](https://github.com/jimhester/lintr)
* [styler](https://github.com/r-lib/styler)
* Racket
* [raco](https://docs.racket-lang.org/raco/)
+* Re:VIEW
+ * [redpen](http://redpen.cc/)
* ReasonML
* [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-reasonml-ols` for configuration instructions
* [ols](https://github.com/freebroccolo/ocaml-language-server)
@@ -410,8 +435,6 @@ formatting.
* [textlint](https://textlint.github.io/)
* [vale](https://github.com/ValeLint/vale)
* [write-good](https://github.com/btford/write-good)
-* Re:VIEW
- * [redpen](http://redpen.cc/)
* RPM spec
* [rpmlint](https://github.com/rpm-software-management/rpmlint) :warning: (see `:help ale-integration-spec`)
* Ruby
@@ -431,6 +454,8 @@ formatting.
* [rust-analyzer](https://github.com/rust-analyzer/rust-analyzer) :warning:
* [rustc](https://www.rust-lang.org/) :warning:
* [rustfmt](https://github.com/rust-lang-nursery/rustfmt)
+* Salt
+ * [salt-lint](https://github.com/warpnet/salt-lint)
* Sass
* [sass-lint](https://www.npmjs.com/package/sass-lint)
* [stylelint](https://github.com/stylelint/stylelint)
@@ -456,10 +481,10 @@ formatting.
* [solium](https://github.com/duaraghav8/Solium)
* SQL
* [pgformatter](https://github.com/darold/pgFormatter)
+ * [sql-lint](https://github.com/joereynolds/sql-lint)
* [sqlfmt](https://github.com/jackc/sqlfmt)
* [sqlformat](https://github.com/andialbrecht/sqlparse)
* [sqlint](https://github.com/purcell/sqlint)
- * [sql-lint](https://github.com/joereynolds/sql-lint)
* Stylus
* [stylelint](https://github.com/stylelint/stylelint)
* SugarSS
@@ -472,7 +497,10 @@ formatting.
* Tcl
* [nagelfar](http://nagelfar.sourceforge.net) :floppy_disk:
* Terraform
- * [fmt](https://github.com/hashicorp/terraform)
+ * [terraform](https://github.com/hashicorp/terraform)
+ * [terraform-fmt-fixer](https://github.com/hashicorp/terraform)
+ * [terraform-ls](https://github.com/hashicorp/terraform-ls)
+ * [terraform-lsp](https://github.com/juliosueiras/terraform-lsp)
* [tflint](https://github.com/wata727/tflint)
* Texinfo
* [alex](https://github.com/wooorm/alex) :floppy_disk:
@@ -489,6 +517,7 @@ formatting.
* Thrift
* [thrift](http://thrift.apache.org/)
* TypeScript
+ * [deno](https://deno.land/)
* [eslint](http://eslint.org/)
* [fecs](http://fecs.baidu.com/)
* [prettier](https://github.com/prettier/prettier)
@@ -498,6 +527,7 @@ formatting.
* typecheck
* VALA
* [uncrustify](https://github.com/uncrustify/uncrustify)
+ * [vala_lint](https://github.com/vala-lang/vala-lint) :floppy_disk:
* Verilog
* [hdl-checker](https://pypi.org/project/hdl-checker)
* [iverilog](https://github.com/steveicarus/iverilog)
@@ -526,7 +556,9 @@ formatting.
* [xmllint](http://xmlsoft.org/xmllint.html)
* YAML
* [prettier](https://github.com/prettier/prettier)
+ * [spectral](https://github.com/stoplightio/spectral)
* [swaglint](https://github.com/byCedric/swaglint)
+ * [yamlfix](https://lyz-code.github.io/yamlfix)
* [yamllint](https://yamllint.readthedocs.io/)
* YANG
* [yang-lsp](https://github.com/theia-ide/yang-lsp)
diff --git a/test/command_callback/inko_paths/test.inko b/test/command_callback/inko_paths/test.inko
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/inko_paths/test.inko
diff --git a/test/command_callback/inko_paths/tests/test/test_foo.inko b/test/command_callback/inko_paths/tests/test/test_foo.inko
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/inko_paths/tests/test/test_foo.inko
diff --git a/test/command_callback/php-intelephense-project/with-composer/composer.json b/test/command_callback/php-intelephense-project/with-composer/composer.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/php-intelephense-project/with-composer/composer.json
diff --git a/test/command_callback/python_paths/with_virtualenv/env/Scripts/autoimport.exe b/test/command_callback/python_paths/with_virtualenv/env/Scripts/autoimport.exe
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_virtualenv/env/Scripts/autoimport.exe
diff --git a/test/command_callback/python_paths/with_virtualenv/env/Scripts/yamlfix.exe b/test/command_callback/python_paths/with_virtualenv/env/Scripts/yamlfix.exe
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_virtualenv/env/Scripts/yamlfix.exe
diff --git a/test/command_callback/python_paths/with_virtualenv/env/bin/autoimport b/test/command_callback/python_paths/with_virtualenv/env/bin/autoimport
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_virtualenv/env/bin/autoimport
diff --git a/test/command_callback/python_paths/with_virtualenv/env/bin/yamlfix b/test/command_callback/python_paths/with_virtualenv/env/bin/yamlfix
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_virtualenv/env/bin/yamlfix
diff --git a/test/command_callback/r_paths/.Rprofile b/test/command_callback/r_paths/.Rprofile
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/r_paths/.Rprofile
diff --git a/test/command_callback/spectral_paths/node_modules/.bin/spectral b/test/command_callback/spectral_paths/node_modules/.bin/spectral
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/spectral_paths/node_modules/.bin/spectral
diff --git a/test/command_callback/spectral_paths/openapi.yaml b/test/command_callback/spectral_paths/openapi.yaml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/spectral_paths/openapi.yaml
diff --git a/test/command_callback/test_adals_command_callbacks.vader b/test/command_callback/test_adals_command_callbacks.vader
new file mode 100644
index 00000000..5a04594e
--- /dev/null
+++ b/test/command_callback/test_adals_command_callbacks.vader
@@ -0,0 +1,17 @@
+Before:
+ call ale#assert#SetUpLinterTest('ada', 'adals')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Sets adals executable):
+ let g:ale_ada_adals_executable = '/path/to /Ada'
+ AssertLinter '/path/to /Ada', ale#Escape('/path/to /Ada')
+
+Execute(Sets adals encoding):
+ let b:ale_ada_adals_encoding = 'iso-8859-1'
+ AssertLSPConfig {'ada.defaultCharset': 'iso-8859-1', 'ada.projectFile': 'default.gpr'}
+
+Execute(Sets adals project):
+ let g:ale_ada_adals_project = 'myproject.gpr'
+ AssertLSPConfig {'ada.defaultCharset': 'utf-8', 'ada.projectFile': 'myproject.gpr'}
diff --git a/test/command_callback/test_clang_tidy_command_callback.vader b/test/command_callback/test_clang_tidy_command_callback.vader
index f0a07e8c..eb1220be 100644
--- a/test/command_callback/test_clang_tidy_command_callback.vader
+++ b/test/command_callback/test_clang_tidy_command_callback.vader
@@ -68,7 +68,6 @@ Execute(The build directory should be used for header files):
\ ale#Escape('clang-tidy')
\ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar')
- \ . ' -- -x c++'
call ale#test#SetFilename('test.hpp')
diff --git a/test/command_callback/test_dart_analysis_server_command_callback.vader b/test/command_callback/test_dart_analysis_server_command_callback.vader
new file mode 100644
index 00000000..1754109a
--- /dev/null
+++ b/test/command_callback/test_dart_analysis_server_command_callback.vader
@@ -0,0 +1,15 @@
+Before:
+ call ale#assert#SetUpLinterTest('dart', 'analysis_server')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'dart', ale#Escape('dart')
+ \ . ' ./snapshots/analysis_server.dart.snapshot --lsp'
+
+Execute(The executable should be configurable):
+ let g:ale_dart_analysis_server_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
+ \ . ' ./snapshots/analysis_server.dart.snapshot --lsp'
diff --git a/test/command_callback/test_elixir_credo.vader b/test/command_callback/test_elixir_credo.vader
index 3eb88846..b14444c6 100644
--- a/test/command_callback/test_elixir_credo.vader
+++ b/test/command_callback/test_elixir_credo.vader
@@ -38,3 +38,10 @@ Execute(Builds credo command with suggest mode when set to 0):
AssertLinter 'mix',
\ ale#path#CdString(ale#path#Simplify(g:dir . '/elixir_paths/mix_project'))
\ . 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
+
+Execute(Builds credo command with a custom config file):
+ let g:ale_elixir_credo_config_file = '/home/user/custom_credo.exs'
+
+ AssertLinter 'mix',
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/elixir_paths/mix_project'))
+ \ . 'mix help credo && mix credo suggest --config-file /home/user/custom_credo.exs --format=flycheck --read-from-stdin %s'
diff --git a/test/command_callback/test_erlang_dialyzer_command_callback.vader b/test/command_callback/test_erlang_dialyzer_command_callback.vader
index 5e21c053..5e818d7f 100644
--- a/test/command_callback/test_erlang_dialyzer_command_callback.vader
+++ b/test/command_callback/test_erlang_dialyzer_command_callback.vader
@@ -25,6 +25,14 @@ Execute(The command should accept configured executable.):
\ . ' -Wunderspecs'
\ . ' %s'
+Execute(The command should accept configured options.):
+ let b:ale_erlang_dialyzer_options = '-r ' . expand('$HOME')
+ AssertLinter 'dialyzer',
+ \ ale#Escape('dialyzer')
+ \ . ' -n --plt ' . ale#Escape(expand('$HOME/.dialyzer_plt'))
+ \ . ' -r ' . expand('$HOME')
+ \ . ' %s'
+
Execute(The command should accept configured PLT file.):
let b:ale_erlang_dialyzer_plt_file = 'custom-plt'
AssertLinter 'dialyzer',
diff --git a/test/command_callback/test_erlang_elvis_command_callback.vader b/test/command_callback/test_erlang_elvis_command_callback.vader
new file mode 100644
index 00000000..4aab49d6
--- /dev/null
+++ b/test/command_callback/test_erlang_elvis_command_callback.vader
@@ -0,0 +1,16 @@
+Before:
+ let b:file = fnamemodify(bufname(''), ':.')
+ call ale#assert#SetUpLinterTest('erlang', 'elvis')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Default command should be correct):
+ AssertLinter 'elvis',
+ \ ale#Escape('elvis') . ' rock --output-format=parsable ' . ale#Escape(b:file)
+
+Execute(Executable should be configurable):
+ let b:ale_erlang_elvis_executable = '/path/to/elvis'
+
+ AssertLinter '/path/to/elvis',
+ \ ale#Escape('/path/to/elvis') . ' rock --output-format=parsable ' . ale#Escape(b:file)
diff --git a/test/command_callback/test_erlang_erlc_command_callback.vader b/test/command_callback/test_erlang_erlc_command_callback.vader
new file mode 100644
index 00000000..7d659a07
--- /dev/null
+++ b/test/command_callback/test_erlang_erlc_command_callback.vader
@@ -0,0 +1,40 @@
+Before:
+ call ale#assert#SetUpLinterTest('erlang', 'erlc')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct.):
+ let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr(''))
+ let g:regex = 'erlc.\+-o.\+%t'
+ let g:matched = match(g:cmd, g:regex)
+
+ " match returns -1 if not found
+ AssertNotEqual
+ \ g:matched,
+ \ -1,
+ \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']'
+
+Execute(The command should accept configured executable.):
+ let b:ale_erlang_erlc_executable = '/usr/bin/erlc'
+ let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr(''))
+ let g:regex = '/usr/bin/erlc.\+-o.\+%t'
+ let g:matched = match(g:cmd, g:regex)
+
+ " match returns -1 if not found
+ AssertNotEqual
+ \ g:matched,
+ \ -1,
+ \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']'
+
+Execute(The command should accept configured options.):
+ let b:ale_erlang_erlc_options = '-I include'
+ let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr(''))
+ let g:regex = 'erlc.\+-o.\+-I include.\+%t'
+ let g:matched = match(g:cmd, g:regex)
+
+ " match returns -1 if not found
+ AssertNotEqual
+ \ g:matched,
+ \ -1,
+ \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']'
diff --git a/test/command_callback/test_fecs_command_callback.vader b/test/command_callback/test_fecs_command_callback.vader
index f70ad084..4287d324 100644
--- a/test/command_callback/test_fecs_command_callback.vader
+++ b/test/command_callback/test_fecs_command_callback.vader
@@ -1,5 +1,6 @@
Before:
call ale#assert#SetUpLinterTest('javascript', 'fecs')
+ runtime autoload/ale/handlers/fecs.vim
After:
call ale#assert#TearDownLinterTest()
diff --git a/test/command_callback/test_haskell_hls_callbacks.vader b/test/command_callback/test_haskell_hls_callbacks.vader
new file mode 100644
index 00000000..e64aab6f
--- /dev/null
+++ b/test/command_callback/test_haskell_hls_callbacks.vader
@@ -0,0 +1,27 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'hls')
+
+ Save &filetype
+ let &filetype = 'haskell'
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The language string should be correct):
+ AssertLSPLanguage 'haskell'
+
+Execute(The default executable should be correct):
+ AssertLinter 'haskell-language-server-wrapper',
+ \ ale#Escape('haskell-language-server-wrapper') . ' --lsp'
+
+Execute(The project root should be detected correctly):
+ AssertLSPProject g:dir
+
+ call ale#test#SetFilename('hls_paths/file.hs')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/hls_paths')
+
+Execute(The executable should be configurable):
+ let g:ale_haskell_hls_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --lsp'
diff --git a/test/command_callback/test_ibm_openapi_validator_command_callback.vader b/test/command_callback/test_ibm_openapi_validator_command_callback.vader
new file mode 100644
index 00000000..3484cc09
--- /dev/null
+++ b/test/command_callback/test_ibm_openapi_validator_command_callback.vader
@@ -0,0 +1,15 @@
+Before:
+ call ale#assert#SetUpLinterTest('openapi', 'ibm_validator')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The yaml ibm-openapi-validator command callback should return the correct default string):
+ AssertLinter 'lint-openapi', ale#Escape('lint-openapi') . ' %t'
+
+Execute(The yaml ibm-openapi-validator command callback should be configurable):
+ let g:ale_openapi_ibm_validator_executable = '~/.local/bin/lint-openapi'
+ let g:ale_openapi_ibm_validator_options = '-c ~/.config'
+
+ AssertLinter '~/.local/bin/lint-openapi', ale#Escape('~/.local/bin/lint-openapi')
+ \ . ' -c ~/.config %t'
diff --git a/test/command_callback/test_inko_inko_callbacks.vader b/test/command_callback/test_inko_inko_callbacks.vader
new file mode 100644
index 00000000..93295c91
--- /dev/null
+++ b/test/command_callback/test_inko_inko_callbacks.vader
@@ -0,0 +1,20 @@
+Before:
+ call ale#assert#SetUpLinterTest('inko', 'inko')
+ call ale#test#SetFilename('inko_paths/test.inko')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default executable path should be correct):
+ AssertLinter 'inko', ale#Escape('inko') . ' build --check --format=json %s'
+
+Execute(The inko callback should include tests/ for test paths):
+ call ale#engine#Cleanup(bufnr(''))
+ noautocmd e! inko_paths/tests/test/test_foo.inko
+ call ale#engine#InitBufferInfo(bufnr(''))
+
+ AssertLinter 'inko',
+ \ ale#Escape('inko')
+ \ . ' build --check --format=json --include '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/inko_paths/tests/'))
+ \ . ' %s'
diff --git a/test/command_callback/test_julia_languageserver_callbacks.vader b/test/command_callback/test_julia_languageserver_callbacks.vader
index 3bc46e3d..96df81f1 100644
--- a/test/command_callback/test_julia_languageserver_callbacks.vader
+++ b/test/command_callback/test_julia_languageserver_callbacks.vader
@@ -11,16 +11,16 @@ After:
Execute(The default executable path should be correct):
AssertLinter 'julia',
\ ale#Escape('julia') .
- \' --startup-file=no --history-file=no -e ' .
- \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
+ \' --project=@. --startup-file=no --history-file=no -e ' .
+ \ ale#Escape('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);')
Execute(The executable should be configurable):
let g:ale_julia_executable = 'julia-new'
AssertLinter 'julia-new',
\ ale#Escape('julia-new') .
- \' --startup-file=no --history-file=no -e ' .
- \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
+ \' --project=@. --startup-file=no --history-file=no -e ' .
+ \ ale#Escape('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);')
Execute(The project root should be detected correctly):
AssertLSPProject ''
diff --git a/test/command_callback/test_php_intelephense_command_callback.vader b/test/command_callback/test_php_intelephense_command_callback.vader
new file mode 100644
index 00000000..dd6adb3d
--- /dev/null
+++ b/test/command_callback/test_php_intelephense_command_callback.vader
@@ -0,0 +1,26 @@
+Before:
+ call ale#assert#SetUpLinterTest('php', 'intelephense')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default executable path should be correct):
+ AssertLinter 'intelephense',
+ \ ale#Escape('intelephense') . ' --stdio'
+
+Execute(The project path should be correct for .git directories):
+ call ale#test#SetFilename('php-intelephense-project/with-git/test.php')
+ silent! call mkdir('php-intelephense-project/with-git/.git', 'p')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-git')
+
+Execute(The project path should be correct for composer.json file):
+ call ale#test#SetFilename('php-intelephense-project/with-composer/test.php')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-composer')
+
+Execute(The project cache should be saved in a temp dir):
+ call ale#test#SetFilename('php-intelephense-project/with-composer/test.php')
+ let g:ale_php_intelephense_config = { 'storagePath': '/tmp/intelephense' }
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-composer')
diff --git a/test/command_callback/test_r_languageserver_callbacks.vader b/test/command_callback/test_r_languageserver_callbacks.vader
new file mode 100644
index 00000000..9a4a1f87
--- /dev/null
+++ b/test/command_callback/test_r_languageserver_callbacks.vader
@@ -0,0 +1,22 @@
+Before:
+ call ale#assert#SetUpLinterTest('r', 'languageserver')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default executable path should be correct):
+ AssertLinter 'Rscript', 'Rscript --vanilla -e ' . ale#Escape('languageserver::run()')
+
+Execute(The project root should be detected correctly):
+ AssertLSPProject '.'
+
+ call ale#test#SetFilename('r_paths/dummy/test.R')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/r_paths')
+
+Execute(Should accept configuration settings):
+ AssertLSPConfig {}
+
+ let b:ale_r_languageserver_config = {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}}
+
+ AssertLSPConfig {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}}
diff --git a/test/command_callback/test_rust_analyzer_callbacks.vader b/test/command_callback/test_rust_analyzer_callbacks.vader
index 95866076..efab1378 100644
--- a/test/command_callback/test_rust_analyzer_callbacks.vader
+++ b/test/command_callback/test_rust_analyzer_callbacks.vader
@@ -16,5 +16,5 @@ Execute(The project root should be detected correctly):
Execute(Should accept configuration settings):
AssertLSPConfig {}
- let b:ale_rust_analyzer_config = {'rust': {'clippy_preference': 'on'}}
- AssertLSPConfig {'rust': {'clippy_preference': 'on'}}
+ let b:ale_rust_analyzer_config = {'diagnostics': {'disabled': ['unresolved-import']}}
+ AssertLSPOptions {'diagnostics': {'disabled': ['unresolved-import']}}
diff --git a/test/command_callback/test_sorbet_command_callback.vader b/test/command_callback/test_sorbet_command_callback.vader
index b46e90a4..fe758635 100644
--- a/test/command_callback/test_sorbet_command_callback.vader
+++ b/test/command_callback/test_sorbet_command_callback.vader
@@ -5,6 +5,7 @@ Before:
let g:ale_ruby_sorbet_executable = 'srb'
let g:ale_ruby_sorbet_options = ''
+ let g:ale_ruby_sorbet_enable_watchman = 0
After:
call ale#assert#TearDownLinterTest()
@@ -13,6 +14,12 @@ Execute(Executable should default to srb):
AssertLinter 'srb', ale#Escape('srb')
\ . ' tc --lsp --disable-watchman'
+Execute(Able to enable watchman):
+ let g:ale_ruby_sorbet_enable_watchman = 1
+
+ AssertLinter 'srb', ale#Escape('srb')
+ \ . ' tc --lsp'
+
Execute(Should be able to set a custom executable):
let g:ale_ruby_sorbet_executable = 'bin/srb'
diff --git a/test/command_callback/test_spectral_command_callback.vader b/test/command_callback/test_spectral_command_callback.vader
new file mode 100644
index 00000000..ed3795b9
--- /dev/null
+++ b/test/command_callback/test_spectral_command_callback.vader
@@ -0,0 +1,31 @@
+Before:
+ call ale#assert#SetUpLinterTest('yaml', 'spectral')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The yaml spectral command callback should return the correct default string):
+ AssertLinter 'spectral', ale#Escape('spectral') . ' lint --ignore-unknown-format -q -f text %t'
+
+Execute(The yaml spectral command callback should be configurable):
+ let g:ale_yaml_spectral_executable = '~/.local/bin/spectral'
+
+ AssertLinter '~/.local/bin/spectral',
+ \ ale#Escape('~/.local/bin/spectral')
+ \ . ' lint --ignore-unknown-format -q -f text %t'
+
+Execute(The yaml spectral command callback should allow a global installation to be used):
+ let g:ale_yaml_spectral_executable = '/usr/local/bin/spectral'
+ let g:ale_yaml_spectral_use_global = 1
+
+ AssertLinter '/usr/local/bin/spectral',
+ \ ale#Escape('/usr/local/bin/spectral')
+ \ . ' lint --ignore-unknown-format -q -f text %t'
+
+Execute(The yaml spectral command callback should allow a local installation to be used):
+ call ale#test#SetFilename('spectral_paths/openapi.yaml')
+
+ AssertLinter
+ \ ale#path#Simplify(g:dir . '/spectral_paths/node_modules/.bin/spectral'),
+ \ ale#Escape(ale#path#Simplify(g:dir . '/spectral_paths/node_modules/.bin/spectral'))
+ \ . ' lint --ignore-unknown-format -q -f text %t'
diff --git a/test/command_callback/test_terraform_ls_command_callback.vader b/test/command_callback/test_terraform_ls_command_callback.vader
new file mode 100644
index 00000000..d559ba8c
--- /dev/null
+++ b/test/command_callback/test_terraform_ls_command_callback.vader
@@ -0,0 +1,61 @@
+Before:
+ call ale#assert#SetUpLinterTest('terraform', 'terraform_ls')
+
+After:
+ if isdirectory(g:dir . '/.terraform')
+ call delete(g:dir . '/.terraform', 'd')
+ endif
+
+ unlet! b:ale_terraform_terraform_executable
+ unlet! b:ale_terraform_ls_executable
+ unlet! b:ale_terraform_ls_options
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(Should send correct LSP language):
+ AssertLSPLanguage 'terraform'
+
+Execute(Should load default executable):
+ AssertLinter 'terraform-ls',
+ \ ale#Escape('terraform-ls') . ' serve'
+
+Execute(Should configure custom executable):
+ let b:ale_terraform_ls_executable = 'foo'
+ AssertLinter 'foo',
+ \ ale#Escape('foo') . ' serve'
+
+Execute(Should ignore non-absolute custom terraform executable):
+ let b:ale_terraform_terraform_executable = 'terraform'
+ AssertLinter 'terraform-ls',
+ \ ale#Escape('terraform-ls') . ' serve'
+
+Execute(Should set absolute custom terraform executable):
+ let b:ale_terraform_terraform_executable = '/bin/terraform'
+ AssertLinter 'terraform-ls',
+ \ ale#Escape('terraform-ls') . ' serve -tf-exec /bin/terraform'
+
+Execute(Should set custom options):
+ let b:ale_terraform_ls_options = '--bar'
+
+ AssertLinter 'terraform-ls',
+ \ ale#Escape('terraform-ls') . ' serve --bar'
+
+Execute(Should return current directory if it contains .terraform directory):
+ call mkdir(g:dir . '/.terraform')
+ AssertLSPProject g:dir
+
+Execute(Should return nearest directory with .terraform if found in parent directory):
+ call ale#test#SetFilename('../terraform_files/main.tf')
+
+ let b:parent_dir = ale#path#Simplify(g:dir . '/..')
+ let b:tf_dir = b:parent_dir . '/.terraform'
+
+ if !isdirectory(b:tf_dir)
+ call mkdir(b:tf_dir)
+ endif
+
+ AssertLSPProject b:parent_dir
+
+ call delete(b:tf_dir, 'd')
+ unlet!b:parent_dir
+ unlet!b:tf_dir
diff --git a/test/command_callback/test_terraform_terraform_command_callback.vader b/test/command_callback/test_terraform_terraform_command_callback.vader
index fabd902d..25ca652a 100644
--- a/test/command_callback/test_terraform_terraform_command_callback.vader
+++ b/test/command_callback/test_terraform_terraform_command_callback.vader
@@ -6,4 +6,10 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'terraform', ale#Escape('terraform') . ' fmt -no-color --check=true -'
+ AssertLinter 'terraform',
+ \ ale#Escape('terraform') . ' validate -no-color -json '
+
+Execute(The default command should be overriden):
+ let b:ale_terraform_terraform_executable = '/bin/other/terraform'
+ AssertLinter '/bin/other/terraform',
+ \ ale#Escape('/bin/other/terraform') . ' validate -no-color -json '
diff --git a/test/command_callback/test_typescript_deno_lsp.vader b/test/command_callback/test_typescript_deno_lsp.vader
new file mode 100644
index 00000000..01cbc851
--- /dev/null
+++ b/test/command_callback/test_typescript_deno_lsp.vader
@@ -0,0 +1,60 @@
+Before:
+ let g:ale_deno_unstable = 0
+ let g:ale_deno_executable = 'deno'
+ let g:ale_deno_project_root = ''
+
+ runtime autoload/ale/handlers/deno.vim
+ call ale#assert#SetUpLinterTest('typescript', 'deno')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Should set deno lsp for TypeScript projects using stable Deno API):
+ AssertLSPLanguage 'typescript'
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/../..')
+ AssertLSPOptions {
+ \ 'enable': v:true,
+ \ 'lint': v:true,
+ \ 'unstable': v:false
+ \}
+
+Execute(Should set deno lsp using unstable Deno API if enabled by user):
+ let g:ale_deno_unstable = 1
+ AssertLSPLanguage 'typescript'
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/../..')
+ AssertLSPOptions {
+ \ 'enable': v:true,
+ \ 'lint': v:true,
+ \ 'unstable': v:true
+ \}
+
+Execute(Should find project root containing tsconfig.json):
+ call ale#test#SetFilename('../typescript/test.ts')
+ AssertLSPLanguage 'typescript'
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/../typescript')
+ AssertLSPOptions {
+ \ 'enable': v:true,
+ \ 'lint': v:true,
+ \ 'unstable': v:false
+ \}
+
+Execute(Should use user-specified project root):
+ let g:ale_deno_lsp_project_root = '/'
+
+ call ale#test#SetFilename('../typescript/test.ts')
+ AssertLSPLanguage 'typescript'
+ AssertLSPConfig {}
+ AssertLSPProject '/'
+ AssertLSPOptions {
+ \ 'enable': v:true,
+ \ 'lint': v:true,
+ \ 'unstable': v:false
+ \}
+
+Execute(Check Deno LSP command):
+ AssertLinter 'deno', [
+ \ ale#Escape('deno') . ' lsp',
+ \]
diff --git a/test/command_callback/test_xo_command_callback.vader b/test/command_callback/test_xo_command_callback.vader
index 65cb4f8a..1aa4c3f1 100644
--- a/test/command_callback/test_xo_command_callback.vader
+++ b/test/command_callback/test_xo_command_callback.vader
@@ -1,8 +1,11 @@
Before:
- call ale#assert#SetUpLinterTest('typescript', 'xo')
- call ale#test#SetFilename('testfile.ts')
+ call ale#assert#SetUpLinterTest('javascript', 'xo')
+ call ale#test#SetFilename('testfile.jsx')
unlet! b:executable
+ set filetype=javascriptreact
+ runtime autoload/ale/handlers/xo.vim
+
After:
call ale#assert#TearDownLinterTest()
@@ -10,11 +13,11 @@ Execute(The XO executable should be called):
AssertLinter 'xo', ale#Escape('xo') . ' --reporter json --stdin --stdin-filename %s'
Execute(The XO executable should be configurable):
- let b:ale_typescript_xo_executable = 'foobar'
+ let b:ale_javascript_xo_executable = 'foobar'
AssertLinter 'foobar', ale#Escape('foobar') . ' --reporter json --stdin --stdin-filename %s'
Execute(The XO options should be configurable):
- let b:ale_typescript_xo_options = '--wat'
+ let b:ale_javascript_xo_options = '--wat'
AssertLinter 'xo', ale#Escape('xo') . ' --wat --reporter json --stdin --stdin-filename %s'
diff --git a/test/command_callback/test_xots_command_callback.vader b/test/command_callback/test_xots_command_callback.vader
new file mode 100644
index 00000000..cc38ff02
--- /dev/null
+++ b/test/command_callback/test_xots_command_callback.vader
@@ -0,0 +1,23 @@
+Before:
+ call ale#assert#SetUpLinterTest('typescript', 'xo')
+ call ale#test#SetFilename('testfile.tsx')
+ unlet! b:executable
+
+ set filetype=typescriptreact
+ runtime autoload/ale/handlers/xo.vim
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The XO executable should be called):
+ AssertLinter 'xo', ale#Escape('xo') . ' --reporter json --stdin --stdin-filename %s'
+
+Execute(The XO executable should be configurable):
+ let b:ale_typescript_xo_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --reporter json --stdin --stdin-filename %s'
+
+Execute(The XO options should be configurable):
+ let b:ale_typescript_xo_options = '--wat'
+
+ AssertLinter 'xo', ale#Escape('xo') . ' --wat --reporter json --stdin --stdin-filename %s'
diff --git a/test/completion/test_lsp_completion_parsing.vader b/test/completion/test_lsp_completion_parsing.vader
index d989aefe..a334d945 100644
--- a/test/completion/test_lsp_completion_parsing.vader
+++ b/test/completion/test_lsp_completion_parsing.vader
@@ -10,36 +10,39 @@ After:
unlet! b:ale_completion_info
Execute(Should handle Rust completion results correctly):
+ let g:ale_completion_autoimport = 0
+
AssertEqual
\ [
- \ {'word': 'new', 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'with_capacity', 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_utf8', 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_utf8_lossy', 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_utf16', 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_utf16_lossy', 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_raw_parts', 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_utf8_unchecked', 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Searcher', 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'default', 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Target', 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'Err', 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from_str', 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from', 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from', 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'from', 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'new', 'dup': 0, 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'with_capacity', 'dup': 0, 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_utf8', 'dup': 0, 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_utf8_lossy', 'dup': 0, 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_utf16', 'dup': 0, 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_utf16_lossy', 'dup': 0, 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_raw_parts', 'dup': 0, 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_utf8_unchecked', 'dup': 0, 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Searcher', 'dup': 0, 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'default', 'dup': 0, 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Target', 'dup': 0, 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'Err', 'dup': 0, 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from_str', 'dup': 0, 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'to_vec', 'dup': 0, 'menu': 'pub fn to_vec(&self) -> Vec<T> where T: Clone,', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\],
\ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0",
@@ -184,18 +187,24 @@ Execute(Should handle Rust completion results correctly):
\ "label":"from",
\ "kind":3,
\ "detail":"fn from(s: Cow<'a, str>) -> String"
+ \ },
+ \ {
+ \ "label":"to_vec",
+ \ "kind":3,
+ \ "detail":"pub fn to_vec(&self) -> Vec<T>\nwhere\n T: Clone,"
\ }
\ ]
\ })
Execute(Should handle Python completion results correctly):
+ let g:ale_completion_autoimport = 0
let b:ale_completion_info = {
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\}
AssertEqual
\ [
- \ {'word': 'what', 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'what', 'dup': 0, 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0",
@@ -400,6 +409,8 @@ Execute(Should handle Python completion results correctly):
\ })
Execute(Should handle extra Python completion results correctly):
+ let g:ale_completion_autoimport = 0
+
let b:ale_completion_info = {
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\ 'prefix': 'mig',
@@ -407,8 +418,8 @@ Execute(Should handle extra Python completion results correctly):
AssertEqual
\ [
- \ {'word': 'migrations', 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
- \ {'word': 'MigEngine', 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'MigEngine', 'dup': 0, 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@@ -439,9 +450,11 @@ Execute(Should handle extra Python completion results correctly):
\ })
Execute(Should handle missing keys):
+ let g:ale_completion_autoimport = 0
+
AssertEqual
\ [
- \ {'word': 'x', 'menu': '', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'x', 'dup': 0, 'menu': '', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@@ -457,9 +470,11 @@ Execute(Should handle missing keys):
\ })
Execute(Should handle documentation in the markdown format):
+ let g:ale_completion_autoimport = 0
+
AssertEqual
\ [
- \ {'word': 'migrations', 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@@ -481,9 +496,11 @@ Execute(Should handle documentation in the markdown format):
\ })
Execute(Should handle completion messages with textEdit objects):
+ let g:ale_completion_autoimport = 0
+
AssertEqual
\ [
- \ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
@@ -512,9 +529,11 @@ Execute(Should handle completion messages with textEdit objects):
\ })
Execute(Should handle completion messages with the deprecated insertText attribute):
+ let g:ale_completion_autoimport = 0
+
AssertEqual
\ [
- \ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
+ \ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
@@ -542,6 +561,7 @@ Execute(Should handle completion messages with additionalTextEdits when ale_comp
\ [
\ {
\ 'word': 'next_callback',
+ \ 'dup': 1,
\ 'menu': 'PlayTimeCallback',
\ 'info': '',
\ 'kind': 'v',
@@ -655,6 +675,7 @@ Execute(Should still handle completion messages with empty additionalTextEdits w
\ [
\ {
\ 'word': 'next_callback',
+ \ 'dup': 0,
\ 'menu': 'PlayTimeCallback',
\ 'info': '',
\ 'kind': 'v',
diff --git a/test/completion/test_omnifunc_completion.vader b/test/completion/test_omnifunc_completion.vader
index 3711f974..1db64705 100644
--- a/test/completion/test_omnifunc_completion.vader
+++ b/test/completion/test_omnifunc_completion.vader
@@ -45,15 +45,15 @@ Execute(The start position should be returned when results can be requested):
AssertEqual 11, ale#completion#OmniFunc(1, '')
Execute(The omnifunc function should return async results):
- " Neovim 0.2.0 struggles at running these tests.
- if !has('nvim') || has('nvim-0.3.0')
+ " Neovim 0.2.0 and 0.4.4 struggles at running these tests.
+ if !has('nvim')
call timer_start(0, function('SetCompletionResult'))
AssertEqual ['foo'], ale#completion#OmniFunc(0, '')
endif
Execute(The omnifunc function should parse and return async responses):
- if !has('nvim') || has('nvim-0.3.0')
+ if !has('nvim')
call timer_start(0, function('SetCompletionResponse'))
AssertEqual ['foo'], ale#completion#OmniFunc(0, '')
diff --git a/test/dumb_named_pipe_server.py b/test/dumb_named_pipe_server.py
new file mode 100644
index 00000000..a77e538c
--- /dev/null
+++ b/test/dumb_named_pipe_server.py
@@ -0,0 +1,42 @@
+"""
+This Python script creates a named pipe server that does nothing but send its input
+back to the client that connects to it. Only one argument must be given, the path
+of a named pipe to bind to.
+"""
+import os
+import socket
+import sys
+
+
+def main():
+ if len(sys.argv) < 2:
+ sys.exit('You must specify a filepath')
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ if os.path.exists(sys.argv[1]):
+ os.remove(sys.argv[1])
+ sock.bind(sys.argv[1])
+ sock.listen(0)
+
+ pid = os.fork()
+
+ if pid:
+ print(pid)
+ sys.exit()
+
+ while True:
+ connection = sock.accept()[0]
+ connection.settimeout(5)
+
+ while True:
+ try:
+ connection.send(connection.recv(1024))
+ except socket.timeout:
+ break
+
+ connection.close()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/eslint-test-files/react-app/node_modules/xo/cli.js b/test/eslint-test-files/react-app/node_modules/xo/cli.js
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/eslint-test-files/react-app/node_modules/xo/cli.js
diff --git a/test/eslint-test-files/react-app/subdir/testfile.ts b/test/eslint-test-files/react-app/subdir/testfile.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/eslint-test-files/react-app/subdir/testfile.ts
diff --git a/test/fixers/test_autoimport_fixer_callback.vader b/test/fixers/test_autoimport_fixer_callback.vader
new file mode 100644
index 00000000..6952cbb8
--- /dev/null
+++ b/test/fixers/test_autoimport_fixer_callback.vader
@@ -0,0 +1,50 @@
+Before:
+ Save g:ale_python_autoimport_executable
+ Save g:ale_python_autoimport_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_python_autoimport_executable = 'xxxinvalid'
+ let g:ale_python_autoimport_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+ silent cd ..
+ silent cd command_callback
+ let g:dir = getcwd()
+
+ let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
+
+After:
+ Restore
+
+ unlet! b:bin_dir
+
+ call ale#test#RestoreDirectory()
+
+Execute(The autoimport callback should return the correct default values):
+ AssertEqual
+ \ 0,
+ \ ale#fixers#autoimport#Fix(bufnr(''))
+
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
+ AssertEqual
+ \ {
+ \ 'command': ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/autoimport')) . ' -',
+ \ },
+ \ ale#fixers#autoimport#Fix(bufnr(''))
+
+Execute(The autoimport callback should respect custom options):
+ let g:ale_python_autoimport_options = '--multi-line=3 --trailing-comma'
+
+ AssertEqual
+ \ 0,
+ \ ale#fixers#autoimport#Fix(bufnr(''))
+
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
+ AssertEqual
+ \ {
+ \ 'command': ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/autoimport'))
+ \ . ' --multi-line=3 --trailing-comma -',
+ \ },
+ \ ale#fixers#autoimport#Fix(bufnr(''))
diff --git a/test/fixers/test_dhall_fixer_callback.vader b/test/fixers/test_dhall_fixer_callback.vader
deleted file mode 100644
index f27880b7..00000000
--- a/test/fixers/test_dhall_fixer_callback.vader
+++ /dev/null
@@ -1,11 +0,0 @@
-Before:
- call ale#assert#SetUpFixerTest('dhall', 'dhall')
-
-After:
- call ale#assert#TearDownFixerTest()
-
-Execute(The default command should be correct):
- AssertFixer
- \ { 'read_temporary_file': 1,
- \ 'command': ale#Escape('dhall') . ' format --inplace %t'
- \ }
diff --git a/test/fixers/test_dhall_format_fixer_callback.vader b/test/fixers/test_dhall_format_fixer_callback.vader
new file mode 100644
index 00000000..9bc17f7e
--- /dev/null
+++ b/test/fixers/test_dhall_format_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_dhall_executable
+ Save g:ale_dhall_options
+
+ " Use an invalid global executable, so we don’t match it.
+ let g:ale_dhall_executable = 'odd-dhall'
+ let g:ale_dhall_options = '--ascii'
+
+ call ale#assert#SetUpFixerTest('dhall-format', 'dhall-format')
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The dhall-format callback should return the correct options):
+ call ale#test#SetFilename('../dhall_files/testfile.dhall')
+
+ AssertFixer
+ \ {
+ \ 'command': ale#Escape('odd-dhall')
+ \ . ' --ascii'
+ \ . ' format'
+ \ . ' --inplace %t',
+ \ 'read_temporary_file': 1,
+ \ }
diff --git a/test/fixers/test_dhall_freeze_fixer_callback.vader b/test/fixers/test_dhall_freeze_fixer_callback.vader
new file mode 100644
index 00000000..c8f820bb
--- /dev/null
+++ b/test/fixers/test_dhall_freeze_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_dhall_executable
+ Save g:ale_dhall_options
+
+ " Use an invalid global executable, so we don’t match it.
+ let g:ale_dhall_executable = 'odd-dhall'
+ let g:ale_dhall_options = '--ascii'
+ let g:ale_dhall_freeze_options = '--all'
+
+ call ale#assert#SetUpFixerTest('dhall-freeze', 'dhall-freeze')
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The dhall-freeze callback should return the correct options):
+ AssertFixer
+ \ {
+ \ 'command': ale#Escape('odd-dhall')
+ \ . ' --ascii'
+ \ . ' freeze'
+ \ . ' --all'
+ \ . ' --inplace %t',
+ \ 'read_temporary_file': 1,
+ \ }
diff --git a/test/fixers/test_dhall_lint_fixer_callback.vader b/test/fixers/test_dhall_lint_fixer_callback.vader
new file mode 100644
index 00000000..82229363
--- /dev/null
+++ b/test/fixers/test_dhall_lint_fixer_callback.vader
@@ -0,0 +1,22 @@
+Before:
+ Save g:ale_dhall_executable
+ Save g:ale_dhall_options
+
+ " Use an invalid global executable, so we don’t match it.
+ let g:ale_dhall_executable = 'odd-dhall'
+ let g:ale_dhall_options = '--ascii'
+
+ call ale#assert#SetUpFixerTest('dhall-lint', 'dhall-lint')
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The dhall-lint callback should return the correct options):
+ AssertFixer
+ \ {
+ \ 'command': ale#Escape('odd-dhall')
+ \ . ' --ascii'
+ \ . ' lint'
+ \ . ' --inplace %t',
+ \ 'read_temporary_file': 1,
+ \ }
diff --git a/test/fixers/test_gofmt_fixer_callback.vader b/test/fixers/test_gofmt_fixer_callback.vader
index 16659655..99407173 100644
--- a/test/fixers/test_gofmt_fixer_callback.vader
+++ b/test/fixers/test_gofmt_fixer_callback.vader
@@ -21,10 +21,7 @@ Execute(The gofmt callback should return the correct default values):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
- \ 'command': ale#Escape('xxxinvalid')
- \ . ' -l -w'
- \ . ' %t',
+ \ 'command': ale#Escape('xxxinvalid'),
\ },
\ ale#fixers#gofmt#Fix(bufnr(''))
@@ -35,11 +32,8 @@ Execute(The gofmt callback should include custom gofmt options):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
\ 'command': ale#Escape('xxxinvalid')
- \ . ' -l -w'
- \ . ' ' . g:ale_go_gofmt_options
- \ . ' %t',
+ \ . ' ' . g:ale_go_gofmt_options,
\ },
\ ale#fixers#gofmt#Fix(bufnr(''))
@@ -50,9 +44,7 @@ Execute(The gofmt callback should support Go environment variables):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
\ 'command': ale#Env('GO111MODULE', 'off')
- \ . ale#Escape('xxxinvalid') . ' -l -w'
- \ . ' %t',
+ \ . ale#Escape('xxxinvalid')
\ },
\ ale#fixers#gofmt#Fix(bufnr(''))
diff --git a/test/fixers/test_isort_fixer_callback.vader b/test/fixers/test_isort_fixer_callback.vader
index 7f389dcf..3941f6dd 100644
--- a/test/fixers/test_isort_fixer_callback.vader
+++ b/test/fixers/test_isort_fixer_callback.vader
@@ -5,6 +5,7 @@ Before:
" Use an invalid global executable, so we don't match it.
let g:ale_python_isort_executable = 'xxxinvalid'
let g:ale_python_isort_options = ''
+ let g:ale_python_isort_auto_pipenv = 0
call ale#test#SetDirectory('/testplugin/test/fixers')
silent cd ..
@@ -48,3 +49,12 @@ Execute(The isort callback should respect custom options):
\ . ' --multi-line=3 --trailing-comma -',
\ },
\ ale#fixers#isort#Fix(bufnr(''))
+
+Execute(Pipenv is detected when python_isort_auto_pipenv is set):
+ let g:ale_python_isort_auto_pipenv = 1
+
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertEqual
+ \ {'command': ale#path#BufferCdString(bufnr('')) . ale#Escape('pipenv') . ' run isort -'},
+ \ ale#fixers#isort#Fix(bufnr(''))
diff --git a/test/fixers/test_luafmt_fixer_callback.vader b/test/fixers/test_luafmt_fixer_callback.vader
new file mode 100644
index 00000000..362da118
--- /dev/null
+++ b/test/fixers/test_luafmt_fixer_callback.vader
@@ -0,0 +1,35 @@
+Before:
+ Save g:ale_lua_luafmt_executable
+ Save g:ale_lua_luafmt_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_lua_luafmt_executable = 'xxxinvalid'
+ let g:ale_lua_luafmt_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The luafmt callback should return the correct default values):
+ call ale#test#SetFilename('../lua_files/testfile.lua')
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid') . ' --stdin',
+ \ },
+ \ ale#fixers#luafmt#Fix(bufnr(''))
+
+Execute(The luafmt callback should include custom luafmt options):
+ let g:ale_lua_luafmt_options = "--skip-children"
+ call ale#test#SetFilename('../lua_files/testfile.lua')
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' ' . g:ale_lua_luafmt_options
+ \ . ' --stdin',
+ \ },
+ \ ale#fixers#luafmt#Fix(bufnr(''))
diff --git a/test/fixers/test_ormolu_fixer_callback.vader b/test/fixers/test_ormolu_fixer_callback.vader
new file mode 100644
index 00000000..8df3fca9
--- /dev/null
+++ b/test/fixers/test_ormolu_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_haskell_ormolu_executable
+ Save g:ale_haskell_ormolu_options
+
+After:
+ Restore
+
+Execute(The ormolu callback should return the correct default values):
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('ormolu')
+ \ },
+ \ ale#fixers#ormolu#Fix(bufnr(''))
+
+Execute(The ormolu executable and options should be configurable):
+ let g:ale_nix_nixpkgsfmt_executable = '/path/to/ormolu'
+ let g:ale_nix_nixpkgsfmt_options = '-h'
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('/path/to/ormolu')
+ \ . ' -h',
+ \ },
+ \ ale#fixers#nixpkgsfmt#Fix(bufnr(''))
diff --git a/test/fixers/test_phpcbf_fixer_callback.vader b/test/fixers/test_phpcbf_fixer_callback.vader
index 1663c89c..f7bcc2d8 100644
--- a/test/fixers/test_phpcbf_fixer_callback.vader
+++ b/test/fixers/test_phpcbf_fixer_callback.vader
@@ -5,6 +5,7 @@ Before:
let g:ale_php_phpcbf_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = ''
+ let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers')
@@ -54,6 +55,15 @@ Execute(The phpcbf callback should include the phpcbf_standard option):
\ {'command': ale#Escape(ale#path#Simplify(g:dir . '/php_paths/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . '--standard=phpcbf_ruleset.xml' . ' -'},
\ ale#fixers#phpcbf#Fix(bufnr(''))
+Execute(User provided options should be used):
+ let g:ale_php_phpcbf_options = '--my-user-provided-option my-value'
+ call ale#test#SetFilename('php_paths/project-with-phpcbf/foo/test.php')
+
+ AssertEqual
+ \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/php_paths/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . ale#Pad('--my-user-provided-option my-value') . ' -'},
+ \ ale#fixers#phpcbf#Fix(bufnr(''))
+
+
Before:
Save g:ale_php_phpcbf_executable
Save g:ale_php_phpcbf_standard
@@ -61,6 +71,7 @@ Before:
let g:ale_php_phpcbf_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = ''
+ let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers')
diff --git a/test/fixers/test_standardrb_fixer_callback.vader b/test/fixers/test_standardrb_fixer_callback.vader
index 99234b79..d315651f 100644
--- a/test/fixers/test_standardrb_fixer_callback.vader
+++ b/test/fixers/test_standardrb_fixer_callback.vader
@@ -21,9 +21,9 @@ Execute(The standardrb callback should return the correct default values):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_standardrb_executable)
- \ . ' --fix --force-exclusion %t',
+ \ . ' --fix --force-exclusion --stdin %s',
\ },
\ ale#fixers#standardrb#Fix(bufnr(''))
@@ -32,10 +32,10 @@ Execute(The standardrb callback should include configuration files):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_standardrb_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.standard.yml'))
- \ . ' --fix --force-exclusion %t',
+ \ . ' --fix --force-exclusion --stdin %s',
\ },
\ ale#fixers#standardrb#Fix(bufnr(''))
@@ -45,10 +45,10 @@ Execute(The standardrb callback should include custom rubocop options):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_standardrb_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.standard.yml'))
\ . ' --except Lint/Debugger'
- \ . ' --fix --force-exclusion %t',
+ \ . ' --fix --force-exclusion --stdin %s',
\ },
\ ale#fixers#standardrb#Fix(bufnr(''))
diff --git a/test/fixers/test_xo_fixer_callback.vader b/test/fixers/test_xo_fixer_callback.vader
new file mode 100644
index 00000000..a473606e
--- /dev/null
+++ b/test/fixers/test_xo_fixer_callback.vader
@@ -0,0 +1,45 @@
+Before:
+ call ale#assert#SetUpFixerTest('javascript', 'xo')
+ runtime autoload/ale/handlers/xo.vim
+ set filetype=javascript
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The xo callback should return the correct default values):
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.js')
+
+ AssertFixer
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --fix %t',
+ \ }
+
+Execute(The xo callback should include custom xo options):
+ let g:ale_javascript_xo_options = '--space'
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.js')
+
+ AssertFixer
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --fix %t'
+ \ . ' --space',
+ \ }
+
+Execute(--stdin should be used when xo is new enough):
+ let g:ale_javascript_xo_options = '--space'
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.js')
+
+ GivenCommandOutput ['0.30.0']
+ AssertFixer
+ \ {
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --stdin --stdin-filename %s'
+ \ . ' --fix'
+ \ . ' --space',
+ \ }
diff --git a/test/fixers/test_xots_fixer_callback.vader b/test/fixers/test_xots_fixer_callback.vader
new file mode 100644
index 00000000..5c7fa1d1
--- /dev/null
+++ b/test/fixers/test_xots_fixer_callback.vader
@@ -0,0 +1,45 @@
+Before:
+ call ale#assert#SetUpFixerTest('typescript', 'xo')
+ runtime autoload/ale/handlers/xo.vim
+ set filetype=typescript
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The xo callback should return the correct default values):
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.ts')
+
+ AssertFixer
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --fix %t',
+ \ }
+
+Execute(The xo callback should include custom xo options):
+ let g:ale_typescript_xo_options = '--space'
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.ts')
+
+ AssertFixer
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --fix %t'
+ \ . ' --space',
+ \ }
+
+Execute(--stdin should be used when xo is new enough):
+ let g:ale_typescript_xo_options = '--space'
+ call ale#test#SetFilename('../xo-test-files/monorepo/packages/a/index.ts')
+
+ GivenCommandOutput ['0.30.0']
+ AssertFixer
+ \ {
+ \ 'command': (has('win32') ? 'node.exe ' : '')
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../xo-test-files/monorepo/node_modules/xo/cli.js'))
+ \ . ' --stdin --stdin-filename %s'
+ \ . ' --fix'
+ \ . ' --space',
+ \ }
diff --git a/test/fixers/test_yamlfix_fixer_callback.vader b/test/fixers/test_yamlfix_fixer_callback.vader
new file mode 100644
index 00000000..3ffda91e
--- /dev/null
+++ b/test/fixers/test_yamlfix_fixer_callback.vader
@@ -0,0 +1,50 @@
+Before:
+ Save g:ale_python_yamlfix_executable
+ Save g:ale_python_yamlfix_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_python_yamlfix_executable = 'xxxinvalid'
+ let g:ale_python_yamlfix_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+ silent cd ..
+ silent cd command_callback
+ let g:dir = getcwd()
+
+ let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
+
+After:
+ Restore
+
+ unlet! b:bin_dir
+
+ call ale#test#RestoreDirectory()
+
+Execute(The yamlfix callback should return the correct default values):
+ AssertEqual
+ \ 0,
+ \ ale#fixers#yamlfix#Fix(bufnr(''))
+
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.yaml')
+ AssertEqual
+ \ {
+ \ 'command': ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/yamlfix')) . ' -',
+ \ },
+ \ ale#fixers#yamlfix#Fix(bufnr(''))
+
+Execute(The yamlfix callback should respect custom options):
+ let g:ale_yaml_yamlfix_options = '--multi-line=3 --trailing-comma'
+
+ AssertEqual
+ \ 0,
+ \ ale#fixers#yamlfix#Fix(bufnr(''))
+
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.yaml')
+ AssertEqual
+ \ {
+ \ 'command': ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/yamlfix'))
+ \ . ' --multi-line=3 --trailing-comma -',
+ \ },
+ \ ale#fixers#yamlfix#Fix(bufnr(''))
diff --git a/test/handler/test_atools_handler.vader b/test/handler/test_atools_handler.vader
new file mode 100644
index 00000000..1bb9ca00
--- /dev/null
+++ b/test/handler/test_atools_handler.vader
@@ -0,0 +1,85 @@
+Before:
+ runtime autoload/ale/handlers/atools.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The atools handler should handle basic errors or warings):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 2,
+ \ 'text': 'trailing whitespace',
+ \ 'type': 'E',
+ \ 'code': 'AL8',
+ \ },
+ \ {
+ \ 'lnum': 15,
+ \ 'text': '$pkgname should not be used in the source url',
+ \ 'type': 'W',
+ \ 'code': 'AL29',
+ \ },
+ \ ],
+ \ ale#handlers#atools#Handle(bufnr(''), [
+ \ 'IC:[AL8]:APKBUILD:2:trailing whitespace',
+ \ 'MC:[AL29]:APKBUILD:15:$pkgname should not be used in the source url',
+ \ ])
+
+" Regardless of the severity, if the certainty is [P]ossible and not [C]ertain
+" or if regardless of the Certainity the Severity is not [I]mportant or [S]erious
+" then it must be a [W]arning
+Execute(If we are not Certain or Importantly Serious, be a Warning):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 3,
+ \ 'text': 'This violation is Serious but Possible false positive, I am a Warning!',
+ \ 'type': 'W',
+ \ 'code': 'AL',
+ \ },
+ \ {
+ \ 'lnum': 4,
+ \ 'text': 'This violation is Important but Possible false positive, I am a Warning!',
+ \ 'type': 'W',
+ \ 'code': 'AL',
+ \ },
+ \ {
+ \ 'lnum': 5,
+ \ 'text': 'This violation is Minor, I am a Warning!',
+ \ 'type': 'W',
+ \ 'code': 'AL',
+ \ },
+ \ {
+ \ 'lnum': 6,
+ \ 'text': 'This violation is Style, I am a Warning!',
+ \ 'type': 'W',
+ \ 'code': 'AL',
+ \ },
+ \ ],
+ \ ale#handlers#atools#Handle(bufnr(''), [
+ \ 'SP:[AL]:APKBUILD:3:This violation is Serious but Possible false positive, I am a Warning!',
+ \ 'IP:[AL]:APKBUILD:4:This violation is Important but Possible false positive, I am a Warning!',
+ \ 'MC:[AL]:APKBUILD:5:This violation is Minor, I am a Warning!',
+ \ 'TC:[AL]:APKBUILD:6:This violation is Style, I am a Warning!',
+ \ ])
+
+Execute(We should be error if we are Certain it is Serious or Important):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 7,
+ \ 'text': 'This is Certainly Serious, I am an Error!',
+ \ 'type': 'E',
+ \ 'code': 'AL',
+ \ },
+ \ {
+ \ 'lnum': 8,
+ \ 'text': 'This is Certainly Important, I am an Error!',
+ \ 'type': 'E',
+ \ 'code': 'AL',
+ \ },
+ \ ],
+ \ ale#handlers#atools#Handle(bufnr(''), [
+ \ 'SC:[AL]:APKBUILD:7:This is Certainly Serious, I am an Error!',
+ \ 'IC:[AL]:APKBUILD:8:This is Certainly Important, I am an Error!',
+ \ ])
diff --git a/test/handler/test_dafny_handler.vader b/test/handler/test_dafny_handler.vader
index 674f691d..4ca288d2 100644
--- a/test/handler/test_dafny_handler.vader
+++ b/test/handler/test_dafny_handler.vader
@@ -8,21 +8,29 @@ Execute(The Dafny handler should parse output correctly):
AssertEqual
\ [
\ {
- \ 'bufnr': 0,
+ \ 'filename': 'File.dfy',
\ 'col': 45,
\ 'lnum': 123,
\ 'text': 'A precondition for this call might not hold.',
\ 'type': 'E'
\ },
\ {
- \ 'bufnr': 0,
+ \ 'filename': 'File.dfy',
\ 'col': 90,
\ 'lnum': 678,
\ 'text': 'This is the precondition that might not hold.',
\ 'type': 'W'
- \ }
+ \ },
+ \ {
+ \ 'filename': 'File.dfy',
+ \ 'col': 45,
+ \ 'lnum': 123,
+ \ 'text': "Verification of 'Impl$$_22_Proof.__default.PutKeepsMapsFull' timed out after 2 seconds",
+ \ 'type': 'E'
+ \ },
\ ],
\ ale_linters#dafny#dafny#Handle(0, [
\ 'File.dfy(123,45): Error BP5002: A precondition for this call might not hold.',
- \ 'File.dfy(678,90): Related location: This is the precondition that might not hold.'
+ \ 'File.dfy(678,90): Related location: This is the precondition that might not hold.',
+ \ "File.dfy(123,45): Verification of 'Impl$$_22_Proof.__default.PutKeepsMapsFull' timed out after 2 seconds",
\ ])
diff --git a/test/handler/test_erlang_elvis_handler.vader b/test/handler/test_erlang_elvis_handler.vader
new file mode 100644
index 00000000..365376c8
--- /dev/null
+++ b/test/handler/test_erlang_elvis_handler.vader
@@ -0,0 +1,37 @@
+Before:
+ runtime ale_linters/erlang/elvis.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(Warning messages should be handled):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 11,
+ \ 'text': "Replace the 'if' expression on line 11 with a 'case' expression or function clauses.",
+ \ 'type': 'W',
+ \ },
+ \ {
+ \ 'lnum': 20,
+ \ 'text': 'Remove the debug call to io:format/1 on line 20.',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#erlang#elvis#Handle(bufnr(''), [
+ \ "src/foo.erl:11:no_if_expression:Replace the 'if' expression on line 11 with a 'case' expression or function clauses.",
+ \ 'src/foo.erl:20:no_debug_call:Remove the debug call to io:format/1 on line 20.',
+ \ ])
+
+Execute(Line length message shouldn't contain the line itself):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 24,
+ \ 'text': 'Line 24 is too long.',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#erlang#elvis#Handle(bufnr(''), [
+ \ 'src/foo.erl:24:line_length:Line 24 is too long: io:format("Look ma, too long!"),.',
+ \ ])
diff --git a/test/handler/test_hadolint.vader b/test/handler/test_hadolint.vader
new file mode 100644
index 00000000..eec71fbc
--- /dev/null
+++ b/test/handler/test_hadolint.vader
@@ -0,0 +1,49 @@
+Before:
+ runtime ale_linters/dockerfile/hadolint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The hadolint handler should handle an empty string response):
+ AssertEqual
+ \ [],
+ \ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [])
+
+Execute(The hadolint handler should handle a normal example):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 0,
+ \ 'type': 'W',
+ \ 'text': "Always tag the version of an image explicitly",
+ \ 'detail': "DL3006 ( https://github.com/hadolint/hadolint/wiki/DL3006 )\n\nAlways tag the version of an image explicitly",
+ \ },
+# \ {
+# \ 'lnum': 2,
+# \ 'col': 0,
+# \ 'type': 'E',
+# \ 'text': "MAINTAINER is deprecated",
+# \ 'detail': "DL4000 ( https://github.com/hadolint/hadolint/wiki/DL4000 )\n\nMAINTAINER is deprecated",
+# \ },
+# \ {
+# \ 'lnum': 4,
+# \ 'col': 0,
+# \ 'type': 'W',
+# \ 'text': "Specify version with `yum install -y <package>-<version>`.",
+# \ 'detail': "DL3033 ( https://github.com/hadolint/hadolint/wiki/DL3033 )\n\nSpecify version with `yum install -y <package>-<version>`.",
+# \ },
+# \ {
+# \ 'lnum': 12,
+# \ 'col': 0,
+# \ 'type': 'W',
+# \ 'text': "In POSIX sh, brace expansion is undefined.",
+# \ 'detail': "SC2039 ( https://github.com/koalaman/shellcheck/wiki/SC2039 )\n\nIn POSIX sh, brace expansion is undefined.",
+# \ },
+ \ ],
+ \ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [
+ \ '/dev/stdin:1 DL3006 warning: Always tag the version of an image explicitly',
+# \ '/dev/stdin:2 DL4000 error: MAINTAINER is deprecated',
+# \ '/dev/stdin:4 DL3033 warning: Specify version with `yum install -y <package>-<version>`.',
+# \ '/dev/stdin:12 SC2039 warning: In POSIX sh, brace expansion is undefined.'
+ \ ])
diff --git a/test/handler/test_ibm_openapi_validator_handler.vader b/test/handler/test_ibm_openapi_validator_handler.vader
new file mode 100644
index 00000000..e136d5d2
--- /dev/null
+++ b/test/handler/test_ibm_openapi_validator_handler.vader
@@ -0,0 +1,49 @@
+Before:
+ runtime! ale_linters/openapi/ibm_validator.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(Problems should be parsed correctly for openapi-ibm-validator):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 54,
+ \ 'col': 0,
+ \ 'type': 'E',
+ \ 'text': 'Items with a description must have content in it.',
+ \ },
+ \ {
+ \ 'lnum': 24,
+ \ 'col': 0,
+ \ 'type': 'W',
+ \ 'text': 'Operations must have a non-empty `operationId`.',
+ \ },
+ \ {
+ \ 'lnum': 40,
+ \ 'col': 0,
+ \ 'type': 'W',
+ \ 'text': 'operationIds must follow case convention: lower_snake_case',
+ \ },
+ \ ],
+ \ ale_linters#openapi#ibm_validator#Handle(bufnr(''), [
+ \ '',
+ \ '[Warning] No .validaterc file found. The validator will run in default mode.',
+ \ 'To configure the validator, create a .validaterc file.',
+ \ '',
+ \ 'errors',
+ \ '',
+ \ ' Message : Items with a description must have content in it.',
+ \ ' Path : paths./settings.patch.description',
+ \ ' Line : 54',
+ \ '',
+ \ 'warnings',
+ \ '',
+ \ ' Message : Operations must have a non-empty `operationId`.',
+ \ ' Path : paths./stats.get.operationId',
+ \ ' Line : 24',
+ \ '',
+ \ ' Message : operationIds must follow case convention: lower_snake_case',
+ \ ' Path : paths./settings.get.operationId',
+ \ ' Line : 40'
+ \ ])
diff --git a/test/handler/test_inko_handler.vader b/test/handler/test_inko_handler.vader
new file mode 100644
index 00000000..6621d2d6
--- /dev/null
+++ b/test/handler/test_inko_handler.vader
@@ -0,0 +1,54 @@
+Before:
+ runtime ale_linters/inko/inko.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The inko handler should parse errors correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'filename': ale#path#Simplify('/tmp/foo.inko'),
+ \ 'lnum': 4,
+ \ 'col': 5,
+ \ 'text': 'this is an error',
+ \ 'type': 'E',
+ \ }
+ \ ],
+ \ ale#handlers#inko#Handle(bufnr(''), [
+ \ '[',
+ \ ' {',
+ \ ' "file": "/tmp/foo.inko",',
+ \ ' "line": 4,',
+ \ ' "column": 5,',
+ \ ' "message": "this is an error",',
+ \ ' "level": "error"',
+ \ ' }',
+ \ ']'
+ \ ])
+
+Execute(The inko handler should parse warnings correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'filename': ale#path#Simplify('/tmp/foo.inko'),
+ \ 'lnum': 4,
+ \ 'col': 5,
+ \ 'text': 'this is a warning',
+ \ 'type': 'W',
+ \ }
+ \ ],
+ \ ale#handlers#inko#Handle(bufnr(''), [
+ \ '[',
+ \ ' {',
+ \ ' "file": "/tmp/foo.inko",',
+ \ ' "line": 4,',
+ \ ' "column": 5,',
+ \ ' "message": "this is a warning",',
+ \ ' "level": "warning"',
+ \ ' }',
+ \ ']'
+ \ ])
+
+Execute(The inko handler should handle empty output):
+ AssertEqual [], ale#handlers#inko#Handle(bufnr(''), [])
diff --git a/test/handler/test_nix_handler.vader b/test/handler/test_nix_handler.vader
index 398e1ac8..87e8b68f 100644
--- a/test/handler/test_nix_handler.vader
+++ b/test/handler/test_nix_handler.vader
@@ -8,6 +8,29 @@ Execute(The nix handler should parse nix-instantiate error messages correctly):
AssertEqual
\ [
\ {
+ \ 'lnum': 6,
+ \ 'col': 3,
+ \ 'type': 'E',
+ \ 'text': "syntax error, unexpected ']', expecting ';'",
+ \ },
+ \ {
+ \ 'lnum': 3,
+ \ 'col': 5,
+ \ 'type': 'E',
+ \ 'text': "undefined variable 'foo'",
+ \ },
+ \
+ \ ],
+ \ ale_linters#nix#nix#Handle(bufnr(''), [
+ \ "@nix {\"line\":6,\"column\":3,\"raw_msg\":\"syntax error, unexpected ']', expecting ';'\"}",
+ \ "@nix {\"line\":3,\"column\":5,\"raw_msg\":\"undefined variable 'foo'\"}",
+ \ "@nix {\"unrelated\":\"message\"}"
+ \ ])
+
+Execute(The nix handler should parse message from old nix-instantiate correctly):
+ AssertEqual
+ \ [
+ \ {
\ 'lnum': 23,
\ 'col': 14,
\ 'text': 'error: syntax error, unexpected IN',
diff --git a/test/handler/test_phpcs_handler.vader b/test/handler/test_phpcs_handler.vader
index 18accece..26d35cb8 100644
--- a/test/handler/test_phpcs_handler.vader
+++ b/test/handler/test_phpcs_handler.vader
@@ -13,7 +13,16 @@ Execute(phpcs errors should be handled):
\ 'type': 'E',
\ 'sub_type': 'style',
\ 'text': 'Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)',
- \ }],
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'col': 3,
+ \ 'type': 'E',
+ \ 'sub_type': 'style',
+ \ 'text': 'All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks)',
+ \ },
+ \ ],
\ ale_linters#php#phpcs#Handle(bufnr(''), [
\ '/path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)',
+ \ "/path/to/some-filename.php:22:3: error - All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '\"\n'.",
\ ])
diff --git a/test/handler/test_salt_salt_lint.vader b/test/handler/test_salt_salt_lint.vader
new file mode 100644
index 00000000..7e234785
--- /dev/null
+++ b/test/handler/test_salt_salt_lint.vader
@@ -0,0 +1,34 @@
+Before:
+ runtime ale_linters/salt/salt_lint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The salt handler should parse lines correctly and show error in severity HIGH):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 5,
+ \ 'code': 207,
+ \ 'text': 'File modes should always be encapsulated in quotation marks',
+ \ 'type': 'E'
+ \ }
+ \ ],
+ \ ale_linters#salt#salt_lint#Handle(255, [
+ \ '[{"id": "207", "message": "File modes should always be encapsulated in quotation marks", "filename": "test.sls", "linenumber": 5, "line": " - mode: 0755", "severity": "HIGH"}]'
+ \ ])
+
+
+Execute(The salt handler should parse lines correctly and show error in severity not HIGH):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 27,
+ \ 'code': 204,
+ \ 'text': 'Lines should be no longer that 160 chars',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#salt#salt_lint#Handle(255, [
+ \ '[{"id": "204", "message": "Lines should be no longer that 160 chars", "filename": "test2.sls", "linenumber": 27, "line": "this line is definitely longer than 160 chars, this line is definitely longer than 160 chars, this line is definitely longer than 160 chars", "severity": "VERY_LOW"}]'
+ \ ])
diff --git a/test/handler/test_spectral_handler.vader b/test/handler/test_spectral_handler.vader
new file mode 100644
index 00000000..89a3ff1b
--- /dev/null
+++ b/test/handler/test_spectral_handler.vader
@@ -0,0 +1,52 @@
+Before:
+ runtime ale_linters/yaml/spectral.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(spectral handler should parse lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'code': 'oas3-api-servers',
+ \ 'text': 'OpenAPI `servers` must be present and non-empty array.',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'code': 'oas3-schema',
+ \ 'text': 'Object should have required property `paths`.',
+ \ 'type': 'E'
+ \ },
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'code': 'openapi-tags',
+ \ 'text': 'OpenAPI object should have non-empty `tags` array.',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 3,
+ \ 'col': 6,
+ \ 'code': 'info-contact',
+ \ 'text': 'Info object should contain `contact` object.',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 3,
+ \ 'col': 6,
+ \ 'code': 'oas3-schema',
+ \ 'text': '`info` property should have required property `version`.',
+ \ 'type': 'E'
+ \ },
+ \ ],
+ \ ale#handlers#spectral#HandleSpectralOutput(bufnr(''), [
+ \ 'openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array."',
+ \ 'openapi.yml:1:1 error oas3-schema "Object should have required property `paths`."',
+ \ 'openapi.yml:1:1 warning openapi-tags "OpenAPI object should have non-empty `tags` array."',
+ \ 'openapi.yml:3:6 warning info-contact "Info object should contain `contact` object."',
+ \ 'openapi.yml:3:6 error oas3-schema "`info` property should have required property `version`."',
+ \ ])
diff --git a/test/handler/test_swipl_handler.vader b/test/handler/test_swipl_handler.vader
index 9e425cf6..81b8b9e5 100644
--- a/test/handler/test_swipl_handler.vader
+++ b/test/handler/test_swipl_handler.vader
@@ -35,6 +35,22 @@ Execute (The swipl handler should handle a warning / error of two lines):
\ ' Singleton variables: [M]',
\ ])
+Execute (The swipl handler should handle a warning / error of two lines in the new format):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'col': 0,
+ \ 'text': 'Singleton variables: [M]',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'Warning: /path/to/test.pl:9:',
+ \ 'Warning: Singleton variables: [M]',
+ \ ])
+
Execute (The swipl handler should join three or more lines with '. '):
call ale#test#SetFilename('test.pl')
AssertEqual
@@ -79,6 +95,50 @@ Execute (The swipl handler should ignore warnings / errors 'No permission to cal
\ ' vimscript: (multifile A)',
\ ])
+Execute (The swipl handler should join three or more lines with '. ' on latest swipl):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 10,
+ \ 'col': 0,
+ \ 'text': 'Clauses of fib/2 are not together in the source-file. Earlier definition at /path/to/test.pl:7. Current predicate: f/0. Use :- discontiguous fib/2. to suppress this message',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'Warning: /path/to/test.pl:10:',
+ \ 'Warning: Clauses of fib/2 are not together in the source-file',
+ \ 'Warning: Earlier definition at /path/to/test.pl:7',
+ \ 'Warning: Current predicate: f/0',
+ \ 'Warning: Use :- discontiguous fib/2. to suppress this message',
+ \ ])
+
+Execute (The swipl handler should ignore warnings / errors 'No permission to call sandboxed with latest swpl...'):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'ERROR: /path/to/test.pl:11:',
+ \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G3416:_G3417,_G3413,_G3414)''',
+ \ 'ERROR: Reachable from:',
+ \ 'ERROR: system:''$set_pattr''(A,B,C,D)',
+ \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)',
+ \ 'ERROR: vimscript: (multifile A)',
+ \ 'ERROR: /path/to/test.pl:12:',
+ \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G205:_G206,_G202,_G203)''',
+ \ 'ERROR: Reachable from:',
+ \ 'ERROR: system:''$set_pattr''(A,B,C,D)',
+ \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)',
+ \ 'ERROR: vimscript: (multifile A)',
+ \ 'ERROR: /path/to/test.pl:13:',
+ \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G1808:_G1809,_G1805,_G1806)''',
+ \ 'ERROR: Reachable from:',
+ \ 'ERROR: system:''$set_pattr''(A,B,C,D)',
+ \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)',
+ \ 'ERROR: vimscript: (multifile A)',
+ \ ])
+
Execute (The swipl handler should handle a warning / error with no line number):
call ale#test#SetFilename('test.pl')
AssertEqual
diff --git a/test/handler/test_terraform_handler.vader b/test/handler/test_terraform_handler.vader
index 976ce12a..64e2e578 100644
--- a/test/handler/test_terraform_handler.vader
+++ b/test/handler/test_terraform_handler.vader
@@ -1,34 +1,61 @@
Before:
" Load the file which defines the linter.
runtime ale_linters/terraform/terraform.vim
+ call ale#test#SetDirectory('/testplugin/test/terraform_files')
+ call ale#test#SetFilename('providers.tf')
After:
" Unload all linters again.
call ale#linter#Reset()
+ call ale#test#RestoreDirectory()
Execute(The output should be correct):
AssertEqual
\ [
\ {
- \ 'lnum': 1,
- \ 'col': 20,
- \ 'type': 'E',
- \ 'text': 'illegal char',
+ \ 'lnum': 17,
+ \ 'col': 13,
+ \ 'filename': ale#path#Simplify(g:dir . '/providers.tf'),
+ \ 'type': 'W',
+ \ 'text': 'Terraform 0.13 and earlier allowed provider version',
\ },
\ {
- \ 'lnum': 2,
- \ 'col': 14,
+ \ 'lnum': 0,
+ \ 'col': 0,
+ \ 'filename': ale#path#Simplify(g:dir . '/providers.tf'),
\ 'type': 'E',
- \ 'text': 'literal not terminated',
- \ },
- \ {
- \ 'lnum': 1,
- \ 'type': 'E',
- \ 'text': 'object expected closing RBRACE got: EOF',
- \ },
+ \ 'text': 'Plugin reinitialization required. Please run "terraform"',
+ \ }
\ ],
\ ale_linters#terraform#terraform#Handle(bufnr(''), [
- \ 'Error running fmt: In <standard input>: At 1:20: illegal char',
- \ 'Error running fmt: In <standard input>: At 2:14: literal not terminated',
- \ 'Error running fmt: In <standard input>: object expected closing RBRACE got: EOF',
+ \ '{',
+ \ '"valid": false,',
+ \ '"error_count": 1,',
+ \ '"warning_count": 1,',
+ \ '"diagnostics": [',
+ \ ' {',
+ \ ' "severity": "warning",',
+ \ ' "summary": "Version constraints inside provider configuration blocks are deprecated",',
+ \ ' "detail": "Terraform 0.13 and earlier allowed provider version",',
+ \ ' "range": {',
+ \ ' "filename": "providers.tf",',
+ \ ' "start": {',
+ \ ' "line": 17,',
+ \ ' "column": 13,',
+ \ ' "byte": 669',
+ \ ' },',
+ \ ' "end": {',
+ \ ' "line": 17,',
+ \ ' "column": 24,',
+ \ ' "byte": 680',
+ \ ' }',
+ \ ' }',
+ \ ' },',
+ \ ' {',
+ \ ' "severity": "error",',
+ \ ' "summary": "Could not load plugin",',
+ \ ' "detail": "Plugin reinitialization required. Please run \"terraform\""',
+ \ ' }',
+ \ ' ]',
+ \ '}',
\ ])
diff --git a/test/handler/test_tlint_handler.vader b/test/handler/test_tlint_handler.vader
new file mode 100644
index 00000000..e146346c
--- /dev/null
+++ b/test/handler/test_tlint_handler.vader
@@ -0,0 +1,34 @@
+Before:
+ runtime ale_linters/php/tlint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The tlint handler should calculate line numbers):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '5',
+ \ 'col': 0,
+ \ 'sub_type':
+ \ 'style',
+ \ 'type': 'W',
+ \ 'text': ['! There should be no unused imports.', 'There should be no unused imports.', '', '', '', '', '', '', '', '']
+ \ },
+ \ {
+ \ 'lnum': '15',
+ \ 'col': 0,
+ \ 'sub_type':
+ \ 'style',
+ \ 'type': 'W',
+ \ 'text': ['! There should be no method visibility in test methods.', 'There should be no method visibility in test methods.', '', '', '', '', '', '', '', '']
+ \ },
+ \ ],
+ \ ale_linters#php#tlint#Handle(347, [
+ \ "Lints for /Users/jose/Code/Tighten/tester/tests/Unit/ExampleTest.php",
+ \ "============",
+ \ "! There should be no unused imports.",
+ \ "5 : `use Illuminate\Foundation\Testing\RefreshDatabase;`",
+ \ "! There should be no method visibility in test methods.",
+ \ "15 : ` public function testBasicTest()`",
+ \ ])
diff --git a/test/handler/test_vala_lint_handler.vader b/test/handler/test_vala_lint_handler.vader
new file mode 100644
index 00000000..b8a4fbfa
--- /dev/null
+++ b/test/handler/test_vala_lint_handler.vader
@@ -0,0 +1,54 @@
+Before:
+ runtime ale_linters/vala/vala_lint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The Vala-Lint handler should parse lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 18,
+ \ 'col': 18,
+ \ 'text': 'Expected space before paren',
+ \ 'code': 'space-before-paren',
+ \ 'type': 'E',
+ \ },
+ \ {
+ \ 'lnum': 64,
+ \ 'col': 37,
+ \ 'text': 'Expected space before paren',
+ \ 'code': 'space-before-paren',
+ \ 'type': 'W',
+ \ },
+ \ {
+ \ 'lnum': 73,
+ \ 'col': 37,
+ \ 'text': 'Expected space before paren',
+ \ 'code': 'space-before-paren',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale_linters#vala#vala_lint#Handle(bufnr(''), [
+ \ 'Application.vala',
+ \ ' 18.18 error Expected space before paren space-before-paren',
+ \ ' 64.37 warn Expected space before paren space-before-paren',
+ \ ' 73.37 error Expected space before paren space-before-paren',
+ \ ])
+
+Execute(The Vala-Lint handler should ignore unknown error types):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 73,
+ \ 'col': 37,
+ \ 'text': 'Expected space before paren',
+ \ 'code': 'space-before-paren',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale_linters#vala#vala_lint#Handle(bufnr(''), [
+ \ 'Application.vala',
+ \ ' 18.18 test Expected space before paren space-before-paren',
+ \ ' 73.37 error Expected space before paren space-before-paren',
+ \ ])
diff --git a/test/handler/test_yamllint_handler.vader b/test/handler/test_yamllint_handler.vader
index 1aa0b9f5..dd51119c 100644
--- a/test/handler/test_yamllint_handler.vader
+++ b/test/handler/test_yamllint_handler.vader
@@ -3,7 +3,7 @@ Before:
let g:ale_warn_about_trailing_whitespace = 1
- runtime! ale_linters/yaml/yamllint.vim
+ runtime! ale/handlers/yamllint.vim
After:
Restore
@@ -29,7 +29,7 @@ Execute(Problems should be parsed correctly for yamllint):
\ 'text': 'syntax error: expected the node content, but found ''<stream end>''',
\ },
\ ],
- \ ale_linters#yaml#yamllint#Handle(bufnr(''), [
+ \ ale#handlers#yamllint#Handle(bufnr(''), [
\ '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>''',
\ ])
@@ -45,7 +45,7 @@ Execute(The yamllint handler should respect ale_warn_about_trailing_whitespace):
\ 'code': 'trailing-spaces',
\ },
\ ],
- \ ale_linters#yaml#yamllint#Handle(bufnr(''), [
+ \ ale#handlers#yamllint#Handle(bufnr(''), [
\ 'something.yml:5:18: [error] trailing spaces (trailing-spaces)',
\ ])
@@ -54,6 +54,6 @@ Execute(The yamllint handler should respect ale_warn_about_trailing_whitespace):
AssertEqual
\ [
\ ],
- \ ale_linters#yaml#yamllint#Handle(bufnr(''), [
+ \ ale#handlers#yamllint#Handle(bufnr(''), [
\ 'something.yml:5:18: [error] trailing spaces (trailing-spaces)',
\ ])
diff --git a/test/lsp/test_other_initialize_message_handling.vader b/test/lsp/test_other_initialize_message_handling.vader
index b6ef852a..f3b53843 100644
--- a/test/lsp/test_other_initialize_message_handling.vader
+++ b/test/lsp/test_other_initialize_message_handling.vader
@@ -23,6 +23,7 @@ Before:
\ 'completion_trigger_characters': [],
\ 'definition': 0,
\ 'symbol_search': 0,
+ \ 'code_actions': 0,
\ },
\}
@@ -102,6 +103,7 @@ Execute(Capabilities should bet set up correctly):
\ 'definition': 1,
\ 'symbol_search': 1,
\ 'rename': 1,
+ \ 'code_actions': 1,
\ },
\ b:conn.capabilities
AssertEqual [[1, 'initialized', {}]], g:message_list
@@ -125,7 +127,7 @@ Execute(Disabled capabilities should be recognised correctly):
\ 'referencesProvider': v:false,
\ 'textDocumentSync': 2,
\ 'documentFormattingProvider': v:true,
- \ 'codeActionProvider': v:true,
+ \ 'codeActionProvider': v:false,
\ 'signatureHelpProvider': {
\ 'triggerCharacters': ['(', ','],
\ },
@@ -146,6 +148,7 @@ Execute(Disabled capabilities should be recognised correctly):
\ 'definition': 0,
\ 'symbol_search': 0,
\ 'rename': 0,
+ \ 'code_actions': 0,
\ },
\ b:conn.capabilities
AssertEqual [[1, 'initialized', {}]], g:message_list
@@ -197,6 +200,7 @@ Execute(Capabilities should be enabled when send as Dictionaries):
\ 'typeDefinition': 1,
\ 'symbol_search': 1,
\ 'rename': 1,
+ \ 'code_actions': 1,
\ },
\ b:conn.capabilities
AssertEqual [[1, 'initialized', {}]], g:message_list
diff --git a/test/lua_files/testfile.lua b/test/lua_files/testfile.lua
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/lua_files/testfile.lua
diff --git a/test/nix/test.nix b/test/nix/test.nix
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/nix/test.nix
diff --git a/test/nix/test_rnix_lsp.vader b/test/nix/test_rnix_lsp.vader
new file mode 100644
index 00000000..bf62616b
--- /dev/null
+++ b/test/nix/test_rnix_lsp.vader
@@ -0,0 +1,14 @@
+" Author: jD91mZM2 <me@krake.one>
+" Description: Tests for rnix-lsp language client
+
+Before:
+ call ale#assert#SetUpLinterTest('nix', 'rnix_lsp')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(should start rnix-lsp):
+ call ale#test#SetFilename('./test.nix')
+ AssertLSPLanguage 'nix'
+ AssertLSPOptions {}
+ AssertLSPProject ale#path#Simplify('.')
diff --git a/test/script/check-duplicate-tags b/test/script/check-duplicate-tags
new file mode 100755
index 00000000..ec1de788
--- /dev/null
+++ b/test/script/check-duplicate-tags
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -e
+
+grep --exclude=tags -roh '\*.*\*$' doc | sort | uniq -d
diff --git a/test/script/check-supported-tools-tables b/test/script/check-supported-tools-tables
index f4305707..d238e77f 100755
--- a/test/script/check-supported-tools-tables
+++ b/test/script/check-supported-tools-tables
@@ -15,14 +15,13 @@ while read -r; do
if [[ "$REPLY" =~ ^! ]]; then
language="${REPLY/!/}"
else
- # shellcheck disable=SC2001
echo "$language - $REPLY"
fi
done < <(
grep '^\*\|^ *\*' doc/ale-supported-languages-and-tools.txt \
| sed -e '1,2d' \
| sed 's/^\* */!/' \
- | sed 's/^ *\* *\|!!\|\^\|(.*)\|`//g' \
+ | sed -E 's/^ *\* *|!!|\^|\(.*\)|`//g' \
| sed 's/ *$//'
) > "$doc_file"
@@ -30,13 +29,12 @@ while read -r; do
if [[ "$REPLY" =~ ^! ]]; then
language="${REPLY/!/}"
else
- # shellcheck disable=SC2001
echo "$language - $REPLY"
fi
done < <(
grep '^\*\|^ *\*' supported-tools.md \
| sed 's/^\* */!/' \
- | sed 's/^ *\* *\|:floppy_disk:\|:warning:\|(.*)\|\[\|\].*\|-n flag//g' \
+ | sed -E 's/^ *\* *|:floppy_disk:|:warning:|\(.*\)|\[|\].*|-n flag//g' \
| sed 's/ *$//'
) > "$readme_file"
diff --git a/test/script/check-tag-alignment b/test/script/check-tag-alignment
new file mode 100755
index 00000000..d41db160
--- /dev/null
+++ b/test/script/check-tag-alignment
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+exit_code=0
+
+# Documentation tags need to be aligned to the right margin, so look for
+# tags which aren't at the right margin.
+grep ' \*[^*]\+\*$' doc/ -r \
+ | awk '{ sep = index($0, ":"); if (length(substr($0, sep + 1 )) < 79) { print } }' \
+ | grep . && exit_code=1
+
+exit $exit_code
diff --git a/test/script/check-tag-references b/test/script/check-tag-references
new file mode 100755
index 00000000..45e741fb
--- /dev/null
+++ b/test/script/check-tag-references
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+set -e
+
+exit_code=0
+tag_regex='[gb]\?:\?\(ale\|ALE\)[a-zA-Z_\-]\+'
+
+tags="$(mktemp -t tags.XXXXXXXX)"
+refs="$(mktemp -t refs.XXXXXXXX)"
+# Grep for tags and references, and complain if we find a reference without
+# a tag for the reference. Only our tags will be included.
+grep --exclude=tags -roh "\\*$tag_regex\\*" doc | sed 's/*//g' | sort -u > "$tags"
+grep --exclude=tags -roh "|$tag_regex|" doc | sed 's/|//g' | sort -u > "$refs"
+
+exit_code=0
+
+if ! [[ $(comm -23 $refs $tags | wc -l) -eq 0 ]]; then
+ exit_code=1
+fi
+
+rm "$tags"
+rm "$refs"
diff --git a/test/script/check-toc b/test/script/check-toc
index 87a61262..f3f8a9ea 100755
--- a/test/script/check-toc
+++ b/test/script/check-toc
@@ -35,7 +35,7 @@ sed -n "$toc_start_line,$toc_end_line"p doc/ale.txt \
> "$toc_file"
# Get all of the doc files in a natural sorted order.
-doc_files="$(/usr/bin/env ls -1v doc | grep ^ale- | sed 's/^/doc\//' | paste -sd ' ' -)"
+doc_files="$(/usr/bin/env ls -1v doc | grep '^ale-' | sed 's/^/doc\//' | paste -sd ' ' -)"
# shellcheck disable=SC2086
grep -h '\*ale-.*-options\|^[a-z].*\*ale-.*\*$' $doc_files \
diff --git a/test/script/custom-checks b/test/script/custom-checks
index ca9069e4..83afb28c 100755
--- a/test/script/custom-checks
+++ b/test/script/custom-checks
@@ -13,7 +13,7 @@ echo 'Custom warnings/errors follow:'
echo
set -o pipefail
-docker run -a stdout "${docker_flags[@]}" test/script/custom-linting-rules . || exit_code=$?
+docker run "${docker_flags[@]}" test/script/custom-linting-rules . || exit_code=$?
set +o pipefail
echo
@@ -23,7 +23,10 @@ echo '========================================'
echo 'Duplicate tags follow:'
echo
-grep --exclude=tags -roh '\*.*\*$' doc | sort | uniq -d || exit_code=$?
+set -o pipefail
+docker run "${docker_flags[@]}" test/script/check-duplicate-tags . || exit_code=$?
+set +o pipefail
+echo
echo '========================================'
echo 'Checking for invalid tag references'
@@ -31,14 +34,9 @@ echo '========================================'
echo 'Invalid tag references tags follow:'
echo
-tag_regex='[gb]\?:\?\(ale\|ALE\)[a-zA-Z_\-]\+'
-
-# Grep for tags and references, and complain if we find a reference without
-# a tag for the reference. Only our tags will be included.
-diff -u \
- <(grep --exclude=tags -roh "\\*$tag_regex\\*" doc | sort -u | sed 's/*//g') \
- <(grep --exclude=tags -roh "|$tag_regex|" doc | sort -u | sed 's/|//g') \
- | grep '^+[^+]' && exit_code=1
+set -o pipefail
+docker run "${docker_flags[@]}" test/script/check-tag-references || exit_code=$?
+set +o pipefail
echo '========================================'
echo 'diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables'
@@ -46,7 +44,9 @@ echo '========================================'
echo 'Differences follow:'
echo
-test/script/check-supported-tools-tables || exit_code=$?
+set -o pipefail
+docker run "${docker_flags[@]}" test/script/check-supported-tools-tables || exit_code=$?
+set +o pipefail
echo '========================================'
echo 'Look for badly aligned doc tags'
@@ -54,18 +54,18 @@ echo '========================================'
echo 'Badly aligned tags follow:'
echo
-# Documentation tags need to be aligned to the right margin, so look for
-# tags which aren't at the right margin.
-grep ' \*[^*]\+\*$' doc/ -r \
- | awk '{ sep = index($0, ":"); if (length(substr($0, sep + 1 )) < 79) { print } }' \
- | grep . && exit_code=1
+set -o pipefail
+docker run "${docker_flags[@]}" test/script/check-tag-alignment || exit_code=$?
+set +o pipefail
echo '========================================'
echo 'Look for table of contents issues'
echo '========================================'
echo
-test/script/check-toc || exit_code=$?
+set -o pipefail
+docker run "${docker_flags[@]}" test/script/check-toc || exit_code=$?
+set +o pipefail
echo '========================================'
echo 'Check Python code'
diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules
index 981a9459..69ab3cc8 100755
--- a/test/script/custom-linting-rules
+++ b/test/script/custom-linting-rules
@@ -53,17 +53,29 @@ check_errors() {
regex="$1"
message="$2"
include_arg=''
+ exclude_arg=''
if [ $# -gt 2 ]; then
include_arg="--include $3"
fi
+ if [ $# -gt 3 ]; then
+ shift
+ shift
+ shift
+
+ while (( "$#" )); do
+ exclude_arg="$exclude_arg --exclude $1"
+ shift
+ done
+ fi
+
for directory in "${directories[@]}"; do
# shellcheck disable=SC2086
while read -r; do
RETURN_CODE=1
echo "$REPLY $message"
- done < <(grep -H -n "$regex" $include_arg "$directory"/**/*.vim \
+ done < <(grep -H -n "$regex" $include_arg $exclude_arg "$directory"/**/*.vim \
| grep -v 'no-custom-checks' \
| grep -o '^[^:]\+:[0-9]\+' \
| sed 's:^\./::')
@@ -92,7 +104,7 @@ if (( FIX_ERRORS )); then
done
fi
-# The arguments are: regex, explanation, [filename_filter]
+# The arguments are: regex, explanation, [filename_filter], [list, of, exclusions]
check_errors \
'^function.*) *$' \
'Function without abort keyword (See :help except-compat)'
@@ -114,7 +126,10 @@ check_errors '==?' "Use 'is?' instead of '==?'. 0 ==? 'foobar' is true"
check_errors '!=#' "Use 'isnot#' instead of '!=#'. 0 !=# 'foobar' is false"
check_errors '!=?' "Use 'isnot?' instead of '!=?'. 0 !=? 'foobar' is false"
check_errors '^ *:\?echo' "Stray echo line. Use \`execute echo\` if you want to echo something"
-check_errors $'name.:.*\'[a-z_]*[^a-z_0-9][a-z_0-9]*\',$' 'Use snake_case names for linters' '*/ale_linters/*'
+# Exclusions for grandfathered-in exceptions
+exclusions="clojure/clj_kondo.vim elixir/elixir_ls.vim go/golangci_lint.vim swift/swiftformat.vim"
+# shellcheck disable=SC2086
+check_errors $'name.:.*\'[a-z_]*[^a-z_0-9][a-z_0-9]*\',$' 'Use snake_case names for linters' '*/ale_linters/*' $exclusions
# Checks for improving type checks.
check_errors $'\\(==.\\?\\|is\\) type([\'"]\+)' "Use 'is v:t_string' instead"
check_errors '\(==.\?\|is\) type([0-9]\+)' "Use 'is v:t_number' instead"
@@ -128,8 +143,8 @@ check_errors '\(!=.\?\|isnot\) type({})' "Use 'isnot v:t_dict' instead"
check_errors '\(!=.\?\|isnot\) type(function([^)]\+))' "Use 'isnot v:t_func' instead"
# Run a Python script to find lines that require padding around them. For
-# users without Python installed, we'll skip these checks. Travis CI will run
-# the script.
+# users without Python installed, we'll skip these checks. GitHub Actions will
+# run the script.
if command -v python > /dev/null; then
if ! test/script/block-padding-checker "$directory"/**/*.vim; then
RETURN_CODE=1
diff --git a/test/smoke_test.vader b/test/smoke_test.vader
index 0b126cc6..58206049 100644
--- a/test/smoke_test.vader
+++ b/test/smoke_test.vader
@@ -64,9 +64,9 @@ Execute(Linters should run with the default options):
\ 'valid': 1,
\ }]
- " Try the test a few times over in NeoVim 0.3 or Windows,
+ " Try the test a few times over in NeoVim 0.3 or Windows or Vim 8.2,
" where tests fail randomly.
- for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
+ for g:i in range(has('nvim-0.3') || has('win32') || has('patch-8.2.2401') ? 5 : 1)
call ale#Queue(0, '')
call ale#test#WaitForJobs(2000)
@@ -165,9 +165,9 @@ Execute(Previous errors should be removed when linters change):
\ 'valid': 1,
\}]
- " Try the test a few times over in NeoVim 0.3 or Windows,
+ " Try the test a few times over in NeoVim 0.3 or VIm 8.2 or Windows,
" where tests fail randomly.
- for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
+ for g:i in range(has('nvim-0.3') || has('win32') || has('patch-8.2.2401') ? 5 : 1)
call ale#Queue(0, '')
call ale#test#WaitForJobs(2000)
diff --git a/test/test_c_flag_parsing.vader b/test/test_c_flag_parsing.vader
index 99722b17..8b02f2b9 100644
--- a/test/test_c_flag_parsing.vader
+++ b/test/test_c_flag_parsing.vader
@@ -482,6 +482,7 @@ Execute(We should include several important flags):
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
+ \ . ' -imacros ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incmacros'))
\ . ' -Dmacro="value"'
\ . ' -DGoal=9'
\ . ' -D macro2'
@@ -511,6 +512,8 @@ Execute(We should include several important flags):
\ 'incframework',
\ '-include',
\ '''foo bar''',
+ \ '-imacros',
+ \ 'incmacros',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
@@ -559,6 +562,7 @@ Execute(We should quote the flags we need to quote):
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
+ \ . ' -imacros ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incmacros'))
\ . ' ' . ale#Escape('-Dmacro="value"')
\ . ' -DGoal=9'
\ . ' -D macro2'
@@ -591,6 +595,8 @@ Execute(We should quote the flags we need to quote):
\ 'incframework',
\ '-include',
\ '''foo bar''',
+ \ '-imacros',
+ \ 'incmacros',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
diff --git a/test/test_code_action.vader b/test/test_code_action.vader
index 2e5d1381..7eabb759 100644
--- a/test/test_code_action.vader
+++ b/test/test_code_action.vader
@@ -3,6 +3,9 @@ Before:
let g:ale_enabled = 0
+ " Enable fix end-of-line as tests below expect that
+ set fixeol
+
runtime autoload/ale/code_action.vim
runtime autoload/ale/util.vim
@@ -211,6 +214,7 @@ Execute(End of file can be modified):
\)
AssertEqual g:test.text + [
+ \ '',
\ 'type A: string',
\ 'type B: number',
\ '',
diff --git a/test/test_code_action_python.vader b/test/test_code_action_python.vader
new file mode 100644
index 00000000..fd30633d
--- /dev/null
+++ b/test/test_code_action_python.vader
@@ -0,0 +1,59 @@
+Given python(An example Python file):
+ def main():
+ a = 1
+ c = a + 1
+
+Execute():
+ let g:changes = [
+ \ {'end': {'offset': 7, 'line': 1}, 'newText': 'func_qtffgsv', 'start': {'offset': 5, 'line': 1}},
+ \ {'end': {'offset': 9, 'line': 1}, 'newText': '', 'start': {'offset': 8, 'line': 1}},
+ \ {'end': {'offset': 15, 'line': 3}, 'newText': " return c\n\n\ndef main():\n c = func_qtffgsvi()\n", 'start': {'offset': 15, 'line': 3}}
+ \]
+
+ call ale#code_action#ApplyChanges(expand('%:p'), g:changes, 0)
+
+Expect(The changes should be applied correctly):
+ def func_qtffgsvi():
+ a = 1
+ c = a + 1
+ return c
+
+
+ def main():
+ c = func_qtffgsvi()
+
+
+Given python(Second python example):
+ import sys
+ import exifread
+
+ def main():
+ with open(sys.argv[1], 'rb') as f:
+ exif = exifread.process_file(f)
+ dt = str(exif['Image DateTime'])
+ date = dt[:10].replace(':', '-')
+
+Execute():
+ let g:changes = [
+ \ {'end': {'offset': 16, 'line': 2}, 'newText': "\n\ndef func_ivlpdpao(f):\n exif = exifread.process_file(f)\n dt = str(exif['Image DateTime'])\n date = dt[:10].replace(':', '-')\n return date\n", 'start': {'offset': 16, 'line': 2}},
+ \ {'end': {'offset': 32, 'line': 6}, 'newText': 'date = func', 'start': {'offset': 9, 'line': 6}},
+ \ {'end': {'offset': 42, 'line': 8}, 'newText': "ivlpdpao(f)\n", 'start': {'offset': 33, 'line': 6}}
+ \]
+
+ call ale#code_action#ApplyChanges(expand('%:p'), g:changes, 0)
+
+Expect(The changes should be applied correctly):
+ import sys
+ import exifread
+
+
+ def func_ivlpdpao(f):
+ exif = exifread.process_file(f)
+ dt = str(exif['Image DateTime'])
+ date = dt[:10].replace(':', '-')
+ return date
+
+
+ def main():
+ with open(sys.argv[1], 'rb') as f:
+ date = func_ivlpdpao(f)
diff --git a/test/test_codefix.vader b/test/test_codefix.vader
new file mode 100644
index 00000000..fc5470aa
--- /dev/null
+++ b/test/test_codefix.vader
@@ -0,0 +1,549 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('dummy.txt')
+ Save g:ale_buffer_info
+
+ let g:ale_buffer_info = {}
+
+ let g:old_filename = expand('%:p')
+ let g:Callback = ''
+ let g:expr_list = []
+ let g:message_list = []
+ let g:handle_code_action_called = 0
+ let g:code_actions = []
+ let g:options = {}
+ let g:capability_checked = ''
+ let g:conn_id = v:null
+ let g:InitCallback = v:null
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/codefix.vim
+ runtime autoload/ale/code_action.vim
+
+ function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
+
+ if a:linter.lsp is# 'tsserver'
+ call ale#lsp#MarkConnectionAsTsserver(g:conn_id)
+ endif
+
+ let l:details = {
+ \ 'command': 'foobar',
+ \ 'buffer': a:buffer,
+ \ 'connection_id': g:conn_id,
+ \ 'project_root': '/foo/bar',
+ \}
+
+ let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)}
+ endfunction
+
+ function! ale#lsp#HasCapability(conn_id, capability) abort
+ let g:capability_checked = a:capability
+
+ return 1
+ endfunction
+
+ function! ale#lsp#RegisterCallback(conn_id, callback) abort
+ let g:Callback = a:callback
+ endfunction
+
+ function! ale#lsp#Send(conn_id, message) abort
+ call add(g:message_list, a:message)
+
+ return 42
+ endfunction
+
+ function! ale#util#Execute(expr) abort
+ call add(g:expr_list, a:expr)
+ endfunction
+
+ function! ale#code_action#HandleCodeAction(code_action, options) abort
+ let g:handle_code_action_called = 1
+ Assert !get(a:options, 'should_save')
+ call add(g:code_actions, a:code_action)
+ endfunction
+
+ function! ale#util#Input(message, value) abort
+ return '2'
+ endfunction
+
+After:
+ Restore
+
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+ unlet! g:capability_checked
+ unlet! g:InitCallback
+ unlet! g:old_filename
+ unlet! g:conn_id
+ unlet! g:Callback
+ unlet! g:message_list
+ unlet! g:expr_list
+ unlet! b:ale_linters
+ unlet! g:options
+ unlet! g:code_actions
+ unlet! g:handle_code_action_called
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/codefix.vim
+ runtime autoload/ale/code_action.vim
+
+Execute(Failed codefix responses should be handled correctly):
+ call ale#codefix#HandleTSServerResponse(
+ \ 1,
+ \ {'command': 'getCodeFixes', 'request_seq': 3}
+ \)
+ AssertEqual g:handle_code_action_called, 0
+
+Given typescript(Some typescript file):
+ foo
+ somelongerline ()
+ bazxyzxyzxyz
+
+Execute(getCodeFixes from tsserver should be handled):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1, {
+ \ 'command': 'getCodeFixes',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'type': 'response',
+ \ 'body': [
+ \ {
+ \ 'description': 'Import default "x" from module "./z"',
+ \ 'fixName': 'import',
+ \ 'changes': [
+ \ {
+ \ 'fileName': "/foo/bar/file1.ts",
+ \ 'textChanges': [
+ \ {
+ \ 'end': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': 'import x from "./z";^@',
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \})
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [
+ \ {
+ \ 'description': 'codefix',
+ \ 'changes': [
+ \ {
+ \ 'fileName': "/foo/bar/file1.ts",
+ \ 'textChanges': [
+ \ {
+ \ 'end': {
+ \ 'line': 2,
+ \ 'offset': 1
+ \ },
+ \ 'newText': 'import x from "./z";^@',
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \ }
+ \ ],
+ \ g:code_actions
+
+Execute(getCodeFixes from tsserver should be handled with user input if there are more than one action):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1, {
+ \ 'command': 'getCodeFixes',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'type': 'response',
+ \ 'body': [
+ \ {
+ \ 'description': 'Import default "x" from module "./z"',
+ \ 'fixName': 'import',
+ \ 'changes': [
+ \ {
+ \ 'fileName': "/foo/bar/file1.ts",
+ \ 'textChanges': [
+ \ {
+ \ 'end': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': 'import x from "./z";^@',
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \ },
+ \ {
+ \ 'description': 'Import default "x" from module "./y"',
+ \ 'fixName': 'import',
+ \ 'changes': [
+ \ {
+ \ 'fileName': "/foo/bar/file1.ts",
+ \ 'textChanges': [
+ \ {
+ \ 'end': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': 'import x from "./y";^@',
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \})
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [
+ \ {
+ \ 'description': 'codefix',
+ \ 'changes': [
+ \ {
+ \ 'fileName': "/foo/bar/file1.ts",
+ \ 'textChanges': [
+ \ {
+ \ 'end': {
+ \ 'line': 2,
+ \ 'offset': 1
+ \ },
+ \ 'newText': 'import x from "./y";^@',
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ ]
+ \ }
+ \ ],
+ \ g:code_actions
+
+Execute(Prints a tsserver error message when getCodeFixes unsuccessful):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1, {
+ \ 'command': 'getCodeFixes',
+ \ 'request_seq': 3,
+ \ 'success': v:false,
+ \ 'message': 'something is wrong',
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''Error while getting code fixes. Reason: something is wrong'''], g:expr_list
+
+Execute(Does nothing when where are no code fixes):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1, {
+ \ 'command': 'getCodeFixes',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': []
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''No code fixes available.'''], g:expr_list
+
+Execute(tsserver codefix requests should be sent):
+ call ale#linter#Reset()
+
+ runtime ale_linters/typescript/tsserver.vim
+ let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'code': 2304}]}}
+ call setpos('.', [bufnr(''), 2, 16, 0])
+
+ " ALECodeAction
+ call ale#codefix#Execute(0)
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'code_actions', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#codefix#HandleTSServerResponse'')',
+ \ string(g:Callback)
+ AssertEqual
+ \ [
+ \ ale#lsp#tsserver_message#Change(bufnr('')),
+ \ [0, 'ts@getCodeFixes', {
+ \ 'startLine': 2,
+ \ 'startOffset': 16,
+ \ 'endLine': 2,
+ \ 'endOffset': 17,
+ \ 'file': expand('%:p'),
+ \ 'errorCodes': [2304],
+ \ }]
+ \ ],
+ \ g:message_list
+
+Execute(tsserver codefix requests should be sent only for error with code):
+ call ale#linter#Reset()
+
+ runtime ale_linters/typescript/tsserver.vim
+ let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 16}, {'lnum': 2, 'col': 16, 'code': 2304}]}}
+ call setpos('.', [bufnr(''), 2, 16, 0])
+
+ " ALECodeAction
+ call ale#codefix#Execute(0)
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'code_actions', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#codefix#HandleTSServerResponse'')',
+ \ string(g:Callback)
+ AssertEqual
+ \ [
+ \ ale#lsp#tsserver_message#Change(bufnr('')),
+ \ [0, 'ts@getCodeFixes', {
+ \ 'startLine': 2,
+ \ 'startOffset': 16,
+ \ 'endLine': 2,
+ \ 'endOffset': 17,
+ \ 'file': expand('%:p'),
+ \ 'errorCodes': [2304],
+ \ }]
+ \ ],
+ \ g:message_list
+
+Execute(getApplicableRefactors from tsserver should be handled):
+ call ale#codefix#SetMap({3: {
+ \ 'buffer': expand('%:p'),
+ \ 'line': 1,
+ \ 'column': 2,
+ \ 'end_line': 3,
+ \ 'end_column': 4,
+ \ 'connection_id': 0,
+ \}})
+ call ale#codefix#HandleTSServerResponse(1,
+ \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': [{'actions': [{'description': 'Extract to constant in enclosing scope', 'name': 'constant_scope_0'}], 'description': 'Extract constant', 'name': 'Extract Symbol'}, {'actions': [{'description': 'Extract to function in module scope', 'name': 'function_scope_1'}], 'description': 'Extract function', 'name': 'Extract Symbol'}], 'command': 'getApplicableRefactors'})
+
+ AssertEqual
+ \ [
+ \ [0, 'ts@getEditsForRefactor', {
+ \ 'startLine': 1,
+ \ 'startOffset': 2,
+ \ 'endLine': 3,
+ \ 'endOffset': 5,
+ \ 'file': expand('%:p'),
+ \ 'refactor': 'Extract Symbol',
+ \ 'action': 'function_scope_1',
+ \ }]
+ \ ],
+ \ g:message_list
+
+Execute(getApplicableRefactors should print error on failure):
+ call ale#codefix#SetMap({3: {
+ \ 'buffer': expand('%:p'),
+ \ 'line': 1,
+ \ 'column': 2,
+ \ 'end_line': 3,
+ \ 'end_column': 4,
+ \ 'connection_id': 0,
+ \}})
+ call ale#codefix#HandleTSServerResponse(1,
+ \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:false, 'message': 'oops', 'command': 'getApplicableRefactors'})
+
+ AssertEqual ['echom ''Error while getting applicable refactors. Reason: oops'''], g:expr_list
+
+Execute(getApplicableRefactors should do nothing if there are no refactors):
+ call ale#codefix#SetMap({3: {
+ \ 'buffer': expand('%:p'),
+ \ 'line': 1,
+ \ 'column': 2,
+ \ 'end_line': 3,
+ \ 'end_column': 4,
+ \ 'connection_id': 0,
+ \}})
+ call ale#codefix#HandleTSServerResponse(1,
+ \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': [], 'command': 'getApplicableRefactors'})
+
+ AssertEqual ['echom ''No applicable refactors available.'''], g:expr_list
+
+Execute(getEditsForRefactor from tsserver should be handled):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1,
+ \{'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': {'edits': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 35, 'line': 9}, 'newText': 'newFunction(app);', 'start': {'offset': 3, 'line': 8}}, {'end': {'offset': 4, 'line': 19}, 'newText': '^@function newFunction(app: Router) {^@ app.use(booExpressCsrf());^@ app.use(booExpressRequireHttps);^@}^@', 'start': {'offset': 4, 'line': 19}}]}], 'renameLocation': {'offset': 3, 'line': 8}, 'renameFilename': '/foo/bar/file.ts'}, 'command': 'getEditsForRefactor' }
+ \)
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [
+ \ {
+ \ 'description': 'editsForRefactor',
+ \ 'changes': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 35, 'line': 9}, 'newText': 'newFunction(app);', 'start': {'offset': 3, 'line': 8}}, {'end': {'offset': 4, 'line': 19}, 'newText': '^@function newFunction(app: Router) {^@ app.use(booExpressCsrf());^@ app.use(booExpressRequireHttps);^@}^@', 'start': {'offset': 4, 'line': 19}}]}],
+ \ }
+ \ ],
+ \ g:code_actions
+
+Execute(getEditsForRefactor should print error on failure):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleTSServerResponse(1,
+ \{'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:false, 'message': 'oops', 'command': 'getEditsForRefactor' }
+ \)
+
+ AssertEqual ['echom ''Error while getting edits for refactor. Reason: oops'''], g:expr_list
+
+Execute(Failed LSP responses should be handled correctly):
+ call ale#codefix#HandleLSPResponse(
+ \ 1,
+ \ {'method': 'workspace/applyEdit', 'request_seq': 3}
+ \)
+ AssertEqual g:handle_code_action_called, 0
+
+Given python(Some python file):
+ def main():
+ a = 1
+ b = a + 2
+
+Execute("workspace/applyEdit" from LSP should be handled):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleLSPResponse(1,
+ \ {'id': 0, 'jsonrpc': '2.0', 'method': 'workspace/applyEdit', 'params': {'edit': {'changes': {'file:///foo/bar/file.ts': [{'range': {'end': {'character': 27, 'line': 7}, 'start': {'character': 27, 'line': 7}}, 'newText': ', Config'}, {'range': {'end': {'character': 12, 'line': 96}, 'start': {'character': 2, 'line': 94}}, 'newText': 'await newFunction(redis, imageKey, cover, config);'}, {'range': {'end': {'character': 2, 'line': 99}, 'start': {'character': 2, 'line': 99}}, 'newText': '^@async function newFunction(redis: IRedis, imageKey: string, cover: Buffer, config: Config) {^@ try {^@ await redis.set(imageKey, cover, ''ex'', parseInt(config.coverKeyTTL, 10));^@ }^@ catch { }^@}^@'}]}}}})
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [{'description': 'applyEdit', 'changes': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 28, 'line': 8}, 'newText': ', Config', 'start': {'offset': 28, 'line': 8}}, {'end': {'offset': 13, 'line': 97}, 'newText': 'await newFunction(redis, imageKey, cover, config);', 'start': {'offset': 3, 'line': 95}}, {'end': {'offset': 3, 'line': 100}, 'newText': '^@async function newFunction(redis: IRedis, imageKey: string, cover: Buffer, config: Config) {^@ try {^@ await redis.set(imageKey, cover, ''ex'', parseInt(config.coverKeyTTL, 10));^@ }^@ catch { }^@}^@', 'start': {'offset': 3, 'line': 100}}]}]}],
+ \ g:code_actions
+
+Execute(Code Actions from LSP should be handled with user input if there are more than one action):
+ call ale#codefix#SetMap({2: {}})
+ call ale#codefix#HandleLSPResponse(1,
+ \ {'id': 2, 'jsonrpc': '2.0', 'result': [{'title': 'fake for testing'}, {'arguments': [{'documentChanges': [{'edits': [{'range': {'end': {'character': 31, 'line': 2}, 'start': {'character': 31, 'line': 2}}, 'newText': ', createVideo'}], 'textDocument': {'uri': 'file:///foo/bar/file.ts', 'version': 1}}]}], 'title': 'Add ''createVideo'' to existing import declaration from "./video"', 'command': '_typescript.applyWorkspaceEdit'}]})
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [{'description': 'codeaction', 'changes': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 32, 'line': 3}, 'newText': ', createVideo', 'start': {'offset': 32, 'line': 3}}]}]}],
+ \ g:code_actions
+
+Execute(Code Actions from LSP should be handled when returned with documentChanges):
+ call ale#codefix#SetMap({2: {}})
+ call ale#codefix#HandleLSPResponse(1,
+ \ {'id': 2, 'jsonrpc': '2.0', 'result': [{'diagnostics': v:null, 'edit': {'changes': v:null, 'documentChanges': [{'edits': [{'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 4, 'line': 1}}, 'newText': ''}, {'range': {'end': {'character': 9, 'line': 2}, 'start': {'character': 8, 'line': 2}}, 'newText': '(1)'}], 'textDocument': {'uri': 'file:///foo/bar/test.py', 'version': v:null}}]}, 'kind': 'refactor.inline', 'title': 'Inline variable', 'command': v:null}, {'diagnostics': v:null, 'edit': {'changes': v:null, 'documentChanges': [{'edits': [{'range': {'end': {'character': 0, 'line': 0}, 'start': {'character': 0, 'line': 0}}, 'newText': 'def func_bomdjnxh():^@ a = 1return a^@^@^@'}, {'range': {'end': {'character': 9, 'line': 1}, 'start': {'character': 8, 'line': 1}}, 'newText': 'func_bomdjnxh()^@'}], 'textDocument': {'uri': 'file:///foo/bar/test.py', 'version': v:null}}]}, 'kind': 'refactor.extract', 'title': 'Extract expression into function ''func_bomdjnxh''', 'command': v:null}]})
+
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual
+ \ [{'description': 'codeaction', 'changes': [{'fileName': '/foo/bar/test.py', 'textChanges': [{'end': {'offset': 1, 'line': 1}, 'newText': 'def func_bomdjnxh():^@ a = 1return a^@^@^@', 'start': {'offset': 1, 'line': 1}}, {'end': {'offset': 10, 'line': 2}, 'newText': 'func_bomdjnxh()^@', 'start': {'offset': 9, 'line': 2}}]}]}],
+ \ g:code_actions
+
+Execute(LSP Code Actions handles command responses):
+ call ale#codefix#SetMap({3: {
+ \ 'connection_id': 0,
+ \}})
+ call ale#codefix#HandleLSPResponse(1,
+ \ {'id': 3, 'jsonrpc': '2.0', 'result': [{'kind': 'refactor', 'title': 'Extract to inner function in function ''getVideo''', 'command': {'arguments': [{'file': '/foo/bar/file.ts', 'endOffset': 0, 'action': 'function_scope_0', 'startOffset': 1, 'startLine': 65, 'refactor': 'Extract Symbol', 'endLine': 68}], 'title': 'Extract to inner function in function ''getVideo''', 'command': '_typescript.applyRefactoring'}}, {'kind': 'refactor', 'title': 'Extract to function in module scope', 'command': {'arguments': [{'file': '/foo/bar/file.ts', 'endOffset': 0, 'action': 'function_scope_1', 'startOffset': 1, 'startLine': 65, 'refactor': 'Extract Symbol', 'endLine': 68}], 'title': 'Extract to function in module scope', 'command': '_typescript.applyRefactoring'}}]})
+
+ AssertEqual
+ \ [[0, 'workspace/executeCommand', {'arguments': [{'file': '/foo/bar/file.ts', 'action': 'function_scope_1', 'endOffset': 0, 'refactor': 'Extract Symbol', 'endLine': 68, 'startLine': 65, 'startOffset': 1}], 'command': '_typescript.applyRefactoring'}]],
+ \ g:message_list
+
+
+Execute(Prints message when LSP code action returns no results):
+ call ale#codefix#SetMap({3: {}})
+ call ale#codefix#HandleLSPResponse(1,
+ \ {'id': 3, 'jsonrpc': '2.0', 'result': []})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''No code actions received from server'''], g:expr_list
+
+Execute(LSP code action requests should be sent):
+ call ale#linter#Reset()
+
+ runtime ale_linters/python/jedils.vim
+ let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'end_lnum': 2, 'end_col': 6, 'code': 2304, 'text': 'oops'}]}}
+ call setpos('.', [bufnr(''), 2, 5, 0])
+
+ " ALECodeAction
+ call ale#codefix#Execute(0)
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'code_actions', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#codefix#HandleLSPResponse'')',
+ \ string(g:Callback)
+ AssertEqual
+ \ [
+ \ [0, 'textDocument/codeAction', {
+ \ 'context': {
+ \ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
+ \ },
+ \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
+ \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))}
+ \ }]
+ \ ],
+ \ g:message_list[-1:]
+
+Execute(LSP code action requests should be sent only for error with code):
+ call ale#linter#Reset()
+
+ runtime ale_linters/python/jedils.vim
+ let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'end_lnum': 2, 'end_col': 6, 'code': 2304, 'text': 'oops'}]}}
+ call setpos('.', [bufnr(''), 2, 5, 0])
+
+ " ALECodeAction
+ call ale#codefix#Execute(0)
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'code_actions', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#codefix#HandleLSPResponse'')',
+ \ string(g:Callback)
+ AssertEqual
+ \ [
+ \ [0, 'textDocument/codeAction', {
+ \ 'context': {
+ \ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
+ \ },
+ \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
+ \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))}
+ \ }]
+ \ ],
+ \ g:message_list[-1:]
diff --git a/test/test_deno_executable_detection.vader b/test/test_deno_executable_detection.vader
new file mode 100644
index 00000000..edd408b1
--- /dev/null
+++ b/test/test_deno_executable_detection.vader
@@ -0,0 +1,19 @@
+Before:
+ runtime autoload/ale/handlers/deno.vim
+
+After:
+ unlet! g:ale_deno_executable
+
+ call ale#linter#Reset()
+
+Execute(Default executable should be detected correctly):
+ AssertEqual
+ \ 'deno',
+ \ ale#handlers#deno#GetExecutable(bufnr(''))
+
+Execute(User specified executable should override default):
+ let g:ale_deno_executable = '/path/to/deno-bin'
+ AssertEqual
+ \ '/path/to/deno-bin',
+ \ ale#handlers#deno#GetExecutable(bufnr(''))
+
diff --git a/test/test_dockerfile_hadolint_linter.vader b/test/test_dockerfile_hadolint_linter.vader
index 3edbb2b6..882e1a6c 100644
--- a/test/test_dockerfile_hadolint_linter.vader
+++ b/test/test_dockerfile_hadolint_linter.vader
@@ -70,14 +70,14 @@ Execute(test warnings from hadolint):
AssertEqual
\ [{'lnum': 10, 'col': 0, 'type': 'W', 'text': 'Using latest is prone to errors', 'detail': "DL3007 ( https://github.com/hadolint/hadolint/wiki/DL3007 )\n\nUsing latest is prone to errors"}],
\ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [
- \ '/dev/stdin:10 DL3007 Using latest is prone to errors',
+ \ '/dev/stdin:10 DL3007 warning: Using latest is prone to errors',
\ ])
Execute(test warnings from shellcheck):
AssertEqual
\ [{'lnum': 3, 'col': 0, 'type': 'W', 'text': 'bar is referenced but not assigned.', 'detail': "SC2154 ( https://github.com/koalaman/shellcheck/wiki/SC2154 )\n\nbar is referenced but not assigned."}],
\ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [
- \ '/dev/stdin:3 SC2154 bar is referenced but not assigned.',
+ \ '/dev/stdin:3 SC2154 warning: bar is referenced but not assigned.',
\ ])
Execute(test errors from dockerfile parser):
diff --git a/test/test_filetype_linter_defaults.vader b/test/test_filetype_linter_defaults.vader
index e9980536..d4e708ec 100644
--- a/test/test_filetype_linter_defaults.vader
+++ b/test/test_filetype_linter_defaults.vader
@@ -70,3 +70,10 @@ Execute(The defaults for the verilog filetype should be correct):
Execute(Default aliases for React should be defined):
AssertEqual ['javascript', 'jsx'], ale#linter#ResolveFiletype('javascriptreact')
AssertEqual ['typescript', 'tsx'], ale#linter#ResolveFiletype('typescriptreact')
+
+Execute(The defaults for the apkbuild filetype should be correct):
+ AssertEqual ['apkbuild_lint', 'secfixes_check'], GetLinterNames('apkbuild')
+
+ let g:ale_linters_explicit = 1
+
+ AssertEqual [], GetLinterNames('apkbuild')
diff --git a/test/test_floating_preview.vader b/test/test_floating_preview.vader
new file mode 100644
index 00000000..43415556
--- /dev/null
+++ b/test/test_floating_preview.vader
@@ -0,0 +1,92 @@
+Before:
+ let g:ale_floating_preview = 0
+ let g:ale_hover_to_floating_preview = 0
+ let g:ale_detail_to_floating_preview = 0
+
+ runtime autoload/ale/floating_preview.vim
+
+ let g:floated_lines = []
+ let g:floating_preview_show_called = 0
+
+ " Stub out so we can track the call
+ function! ale#floating_preview#Show(lines, ...) abort
+ let g:floating_preview_show_called = 1
+ let g:floated_lines = a:lines
+ endfunction
+
+ let g:ale_buffer_info = {
+ \ bufnr('%'): {
+ \ 'loclist': [
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 10,
+ \ 'bufnr': bufnr('%'),
+ \ 'vcol': 0,
+ \ 'linter_name': 'notalinter',
+ \ 'nr': -1,
+ \ 'type': 'E',
+ \ 'code': 'semi',
+ \ 'text': "Missing semicolon.\r",
+ \ 'detail': "Every statement should end with a semicolon\nsecond line",
+ \ },
+ \ ],
+ \ }
+ \}
+
+ call ale#linter#Reset()
+ call ale#linter#PreventLoading('javascript')
+
+After:
+ Restore
+
+ let g:ale_floating_preview = 0
+ let g:ale_hover_to_floating_preview = 0
+ let g:ale_detail_to_floating_preview = 0
+
+ call cursor(1, 1)
+
+ let g:ale_buffer_info = {}
+
+ " Close the preview window if it's open.
+ if &filetype is# 'ale-preview'
+ noautocmd :q!
+ endif
+
+ call ale#linter#Reset()
+
+
+Given javascript(A file with warnings/errors):
+ var x = 3 + 12345678
+ var x = 5*2 + parseInt("10");
+ // comment
+
+Execute(Floating preview is used with ALEDetail when g:ale_floating_preview set):
+ let g:ale_floating_preview = 1
+
+ call cursor(1, 10)
+
+ ALEDetail
+
+ let expected = ["Every statement should end with a semicolon", "second line"]
+
+ AssertEqual 1, g:floating_preview_show_called
+ AssertEqual expected, g:floated_lines
+
+Execute(Floating preview is used with ALEDetail when g:ale_detail_to_floating_preview set):
+ let g:ale_detail_to_floating_preview = 1
+
+ call cursor(1, 10)
+
+ ALEDetail
+
+ let expected = ["Every statement should end with a semicolon", "second line"]
+
+ AssertEqual 1, g:floating_preview_show_called
+ AssertEqual expected, g:floated_lines
+
+Execute(Floating preview is not used with ALEDetail by default):
+ call cursor(1, 10)
+
+ ALEDetail
+
+ AssertEqual 0, g:floating_preview_show_called
diff --git a/test/test_hover.vader b/test/test_hover.vader
index 9689cda2..7a9c8d91 100644
--- a/test/test_hover.vader
+++ b/test/test_hover.vader
@@ -7,9 +7,25 @@ Before:
let g:item_list = []
let g:show_message_arg_list = []
+ let g:ale_floating_preview = 0
+ let g:ale_hover_to_floating_preview = 0
+ let g:ale_detail_to_floating_preview = 0
+
runtime autoload/ale/linter.vim
runtime autoload/ale/lsp.vim
+ runtime autoload/ale/lsp_linter.vim
runtime autoload/ale/util.vim
+ runtime autoload/ale/floating_preview.vim
+ runtime autoload/ale/hover.vim
+
+ let g:floated_lines = []
+ let g:floating_preview_show_called = 0
+
+ " Stub out so we can track the call
+ function! ale#floating_preview#Show(lines, ...) abort
+ let g:floating_preview_show_called = 1
+ let g:floated_lines = a:lines
+ endfunction
function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
let g:Callback = a:callback
@@ -50,6 +66,7 @@ Before:
\)
endfunction
+
After:
call ale#hover#SetMap({})
call ale#test#RestoreDirectory()
@@ -65,6 +82,7 @@ After:
runtime autoload/ale/lsp_linter.vim
runtime autoload/ale/lsp.vim
runtime autoload/ale/util.vim
+ runtime autoload/ale/floating_preview.vim
Given python(Some Python file):
foo
@@ -101,7 +119,7 @@ Execute(tsserver quickinfo responses will null missing bodies should be handled)
AssertEqual {}, ale#hover#GetMap()
Execute(tsserver quickinfo displayString values should be displayed):
- call ale#hover#SetMap({3: {}})
+ call ale#hover#SetMap({3: {'buffer': bufnr('')}})
call ale#hover#HandleTSServerResponse(
\ 1,
\ {
@@ -168,8 +186,30 @@ Execute(LSP hover response with lists of strings and marked strings should be ha
\], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap()
+Execute(LSP hover with ale_floating_preview should float):
+ let g:ale_floating_preview = 1
+
+ call HandleValidLSPResult({'contents': "the message\ncontinuing"})
+
+ AssertEqual 1, g:floating_preview_show_called
+ AssertEqual ["the message", "continuing"], g:floated_lines
+
+Execute(LSP hover ale_hover_to_floating_preview should float):
+ let g:ale_hover_to_floating_preview = 1
+
+ call HandleValidLSPResult({'contents': "the message\ncontinuing"})
+
+ AssertEqual 1, g:floating_preview_show_called
+ AssertEqual ["the message", "continuing"], g:floated_lines
+
+
+Execute(LSP hover by default should not float):
+ call HandleValidLSPResult({'contents': "the message\ncontinuing"})
+
+ AssertEqual 0, g:floating_preview_show_called
+
Execute(tsserver responses for documentation requests should be handled):
- call ale#hover#SetMap({3: {'show_documentation': 1}})
+ call ale#hover#SetMap({3: {'show_documentation': 1, 'buffer': bufnr('')}})
call ale#hover#HandleTSServerResponse(
\ 1,
@@ -187,3 +227,46 @@ Execute(tsserver responses for documentation requests should be handled):
" The preview window should show the text.
AssertEqual ['foo is a very good method'], ale#test#GetPreviewWindowText()
silent! pclose
+
+Execute(hover with show_documentation should be in the preview window, not floating):
+ let g:ale_hover_to_floating_preview = 1
+ let g:ale_floating_preview = 1
+
+ call ale#hover#SetMap({3: {'show_documentation': 1, 'buffer': bufnr('')}})
+
+ call ale#hover#HandleTSServerResponse(
+ \ 1,
+ \ {
+ \ 'command': 'quickinfo',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': {
+ \ 'documentation': 'foo is a very good method',
+ \ 'displayString': 'foo bar ',
+ \ },
+ \ }
+ \)
+
+ let expected = ["Every statement should end with a semicolon", "second line"]
+
+ AssertEqual 0, g:floating_preview_show_called
+
+Execute(TSServer hover without show_documentation and ale_floating_preview should float):
+ let g:ale_floating_preview = 1
+
+ call ale#hover#SetMap({3: {'buffer': bufnr('')}})
+
+ call ale#hover#HandleTSServerResponse(
+ \ 1,
+ \ {
+ \ 'command': 'quickinfo',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': {
+ \ 'displayString': "the message\ncontinuing",
+ \ },
+ \ }
+ \)
+
+ AssertEqual 1, g:floating_preview_show_called
+ AssertEqual ["the message", "continuing"], g:floated_lines
diff --git a/test/test_lint_on_enter_when_file_changed.vader b/test/test_lint_on_enter_when_file_changed.vader
index 88493005..0d4c4af8 100644
--- a/test/test_lint_on_enter_when_file_changed.vader
+++ b/test/test_lint_on_enter_when_file_changed.vader
@@ -35,7 +35,7 @@ After:
Execute(The file changed event function should set b:ale_file_changed):
let g:ale_lint_on_enter = 0
- if has('gui')
+ if has('gui_running')
new
else
e test
diff --git a/test/test_linting_updates_loclist.vader b/test/test_linting_updates_loclist.vader
index 8a162703..41c86522 100644
--- a/test/test_linting_updates_loclist.vader
+++ b/test/test_linting_updates_loclist.vader
@@ -7,10 +7,12 @@ Before:
Save g:ale_run_synchronously
Save g:ale_set_lists_synchronously
Save g:ale_buffer_info
+ Save g:ale_sign_offset
" We want to check that sign IDs are set for this test.
let g:ale_set_signs = 1
let g:ale_set_loclist = 1
+ let g:ale_sign_offset = 2000000
" Disable features we don't need for these tests.
let g:ale_set_quickfix = 0
let g:ale_set_highlights = 0
@@ -77,7 +79,7 @@ Execute(The loclist should be updated after linting is done):
\ 'type': 'W',
\ 'col': 10,
\ 'text': 'Infix operators must be spaced. [Warning/space-infix-ops]',
- \ 'sign_id': 1000001,
+ \ 'sign_id': 2000001,
\ },
\ {
\ 'lnum': 2,
@@ -88,7 +90,7 @@ Execute(The loclist should be updated after linting is done):
\ 'type': 'E',
\ 'col': 10,
\ 'text': 'Missing semicolon. [Error/semi]',
- \ 'sign_id': 1000002,
+ \ 'sign_id': 2000002,
\ }
\ ],
\ get(get(g:ale_buffer_info, bufnr('%'), {}), 'loclist', [])
diff --git a/test/test_redundant_tsserver_rendering_avoided.vader b/test/test_redundant_tsserver_rendering_avoided.vader
index 6125ebc2..bde5d152 100644
--- a/test/test_redundant_tsserver_rendering_avoided.vader
+++ b/test/test_redundant_tsserver_rendering_avoided.vader
@@ -111,7 +111,7 @@ Execute(An initial list of semantic errors should be handled):
Assert g:ale_handle_loclist_called
-Execute(Subsequent empty lists should be ignored):
+Execute(Subsequent empty lists should be ignored - semantic):
let g:ale_buffer_info[bufnr('')].semantic_loclist = []
call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
@@ -138,3 +138,31 @@ Execute(Non-empty then non-empty semantic errors should be handled):
call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
Assert g:ale_handle_loclist_called
+
+Execute(Subsequent empty lists should be ignored - suggestion):
+ let g:ale_buffer_info[bufnr('')].suggestion_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(Empty then non-empty suggestion messages should be handled):
+ let g:ale_buffer_info[bufnr('')].suggestion_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then empt suggestion messages should be handled):
+ let g:ale_buffer_info[bufnr('')].suggestion_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', ''))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then non-empty suggestion messages should be handled):
+ let g:ale_buffer_info[bufnr('')].suggestion_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
diff --git a/test/test_rename.vader b/test/test_rename.vader
index 2e8b746e..5bc655f4 100644
--- a/test/test_rename.vader
+++ b/test/test_rename.vader
@@ -269,7 +269,7 @@ Execute(tsserver rename requests should be sent):
\ }]
\ ],
\ g:message_list
- AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name', 'force_save': 0}},
+ AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name'}},
\ ale#rename#GetMap()
Given python(Some Python file):
@@ -470,7 +470,7 @@ Execute(LSP rename requests should be sent):
let b:ale_linters = ['pyls']
call setpos('.', [bufnr(''), 1, 5, 0])
- ALERename!
+ ALERename
" We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback)
@@ -500,5 +500,5 @@ Execute(LSP rename requests should be sent):
\ ],
\ g:message_list
- AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name', 'force_save': 1}},
+ AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name'}},
\ ale#rename#GetMap()
diff --git a/test/test_shell_detection.vader b/test/test_shell_detection.vader
index 697054d0..11d801c3 100644
--- a/test/test_shell_detection.vader
+++ b/test/test_shell_detection.vader
@@ -127,3 +127,51 @@ Execute(The dash dialect should be used for the shell and the base function):
Execute(dash should be used for shellcheck):
AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a Bash shellcheck shell directive):
+ # shellcheck shell=bash
+
+Execute(bash dialect should be detected appropriately):
+ AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a sh shellcheck shell directive):
+ #shellcheck shell=sh
+
+Execute(sh dialect should be detected appropriately):
+ AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a tcsh shellcheck shell directive):
+ # shellcheck shell=tcsh
+
+Execute(tcsh dialect should be detected appropriately):
+ AssertEqual 'tcsh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a zsh shellcheck shell directive):
+ # shellcheck shell=zsh
+
+Execute(zsh dialect should be detected appropriately):
+ AssertEqual 'zsh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a csh shellcheck shell directive):
+ # shellcheck shell=csh
+
+Execute(zsh dialect should be detected appropriately):
+ AssertEqual 'csh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a ksh shellcheck shell directive):
+ # shellcheck shell=ksh
+
+Execute(ksh dialect should be detected appropriately):
+ AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a dash shellcheck shell directive):
+ # shellcheck shell=dash
+
+Execute(dash dialect should be detected appropriately):
+ AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
+
+Given(A file with a ash shellcheck shell directive):
+ # shellcheck shell=ash
+
+Execute(dash dialect should be detected for ash that shellcheck does not support):
+ AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
diff --git a/test/test_socket_connections.vader b/test/test_socket_connections.vader
index 6837fe51..9ea5580d 100644
--- a/test/test_socket_connections.vader
+++ b/test/test_socket_connections.vader
@@ -28,11 +28,17 @@ Before:
endfunction
let g:port = 10347
- let g:pid = str2nr(system(
+ let g:pid_tcp = str2nr(system(
\ 'python'
\ . ' ' . ale#Escape(g:dir . '/dumb_tcp_server.py')
\ . ' ' . g:port
\))
+ let g:pipe_path = 'tmp_named_pipe'
+ let g:pid_pipe = str2nr(system(
+ \ 'python'
+ \ . ' ' . ale#Escape(g:dir . '/dumb_named_pipe_server.py')
+ \ . ' ' . g:pipe_path
+ \))
endif
After:
@@ -46,17 +52,23 @@ After:
delfunction WaitForData
delfunction TestCallback
- if has_key(g:, 'pid')
- call system('kill ' . g:pid)
+ if has_key(g:, 'pid_tcp')
+ call system('kill ' . g:pid_tcp)
endif
- unlet! g:pid
+ if has_key(g:, 'pid_pipe')
+ call system('kill ' . g:pid_pipe)
+ endif
+
+ unlet! g:pid_tcp
unlet! g:port
+ unlet! g:pid_pipe
+ unlet! g:pipe_path
endif
unlet! g:can_run_socket_tests
-Execute(Sending and receiving connections to sockets should work):
+Execute(Sending and receiving connections to tcp sockets should work):
if g:can_run_socket_tests
let g:channel_id = ale#socket#Open(
\ '127.0.0.1:' . g:port,
@@ -90,3 +102,38 @@ Execute(Sending and receiving connections to sockets should work):
\ {'callback': function('function')}
\)
endif
+
+Execute(Sending and receiving connections to named pipe sockets should work):
+ if g:can_run_socket_tests && has('nvim')
+ let g:channel_id = ale#socket#Open(
+ \ g:pipe_path,
+ \ {'callback': function('TestCallback')}
+ \)
+
+ Assert g:channel_id >= 0, 'The socket was not opened!'
+
+ call ale#socket#Send(g:channel_id, 'hello')
+ call ale#socket#Send(g:channel_id, ' world')
+
+ AssertEqual 1, ale#socket#IsOpen(g:channel_id)
+
+ " Wait up to 1 second for the expected data to arrive.
+ call WaitForData('hello world', 1000)
+
+ AssertEqual g:channel_id, g:channel_id_received
+ AssertEqual 'hello world', g:data_received
+ AssertEqual g:pipe_path, ale#socket#GetAddress(g:channel_id)
+
+ call ale#socket#Close(g:channel_id)
+
+ AssertEqual 0, ale#socket#IsOpen(g:channel_id)
+ AssertEqual '', ale#socket#GetAddress(g:channel_id)
+ endif
+
+ " NeoVim versions which can't connect to sockets should just fail.
+ if has('nvim') && !exists('*chanclose')
+ AssertEqual -1, ale#socket#Open(
+ \ 'tmp_named_pipe',
+ \ {'callback': function('function')}
+ \)
+ endif
diff --git a/test/typescript/test.ts b/test/typescript/test.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/typescript/test.ts
diff --git a/test/typescript/tsconfig.json b/test/typescript/tsconfig.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/typescript/tsconfig.json
diff --git a/test/xo-test-files/monorepo/node_modules/xo/cli.js b/test/xo-test-files/monorepo/node_modules/xo/cli.js
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/xo-test-files/monorepo/node_modules/xo/cli.js
diff --git a/test/xo-test-files/monorepo/package.json b/test/xo-test-files/monorepo/package.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/xo-test-files/monorepo/package.json
diff --git a/test/xo-test-files/monorepo/packages/a/index.js b/test/xo-test-files/monorepo/packages/a/index.js
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/xo-test-files/monorepo/packages/a/index.js
diff --git a/test/xo-test-files/monorepo/packages/a/index.ts b/test/xo-test-files/monorepo/packages/a/index.ts
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/xo-test-files/monorepo/packages/a/index.ts
diff --git a/test/xo-test-files/monorepo/packages/a/package.json b/test/xo-test-files/monorepo/packages/a/package.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/xo-test-files/monorepo/packages/a/package.json