Compare commits

..

9 Commits

Author SHA1 Message Date
w0rp
d837169f1d Ignore compiled files from newer versions 2019-05-08 09:52:43 +01:00
w0rp
9778a6e5b5 Merge pull request #2134 from oaue/master
javac linter: fix handling of error messages containing ':' character
2019-05-08 09:51:46 +01:00
w0rp
0927634916 Fix #2452 - Strip trailing spaces off sign text automatically 2019-04-23 15:59:05 +01:00
w0rp
711de2c1be Fix #2415 - Mark tsserver and LSP linters inactive again 2019-04-17 18:13:22 +01:00
w0rp
fa18195e34 Fix #2440 - Fix the kotlinc command when Maven and Gradle are missing 2019-04-15 13:36:28 +01:00
w0rp
0059bcd1d0 Merge pull request #2433 from belka-ew/bugfix/remove-otherproject-util-double
Remove otherproject#util#Double from d.vim
2019-04-13 12:30:04 +01:00
w0rp
9d0a55edec Do not complain about generated _callback settings 2019-04-10 19:53:22 +01:00
w0rp
950204b133 Fix #2399 - Do not check buffers used for displaying diffs 2019-04-10 18:43:21 +01:00
w0rp
bbb6e70377 #2417 - Silence errors for shortmess+=T 2019-04-10 15:40:16 +01:00
384 changed files with 1166 additions and 11709 deletions

View File

@@ -5,11 +5,6 @@ clone_depth: 10
# Use the directory C:\testplugin so test directories will mostly work.
clone_folder: C:\testplugin
branches:
only:
- master
- /v\d+\.\d+\.(x|\d+)/
# Cache the vim and vader directories between builds.
cache:
- C:\vim -> .appveyor.yml

View File

@@ -3,10 +3,6 @@ sudo: required
services:
- docker
language: generic
branches:
only:
- master
- /^v\d+\.\d+\.(x|\d+)$/
env:
- OPTIONS=--vim-80-only
- OPTIONS=--vim-81-only

View File

@@ -1,9 +1,9 @@
FROM tweekmonster/vim-testbed:latest
RUN install_vim -tag v8.0.0027 -build \
-tag v8.1.0519 -build \
-tag v8.1.0204 -build \
-tag neovim:v0.2.0 -build \
-tag neovim:v0.3.5 -build
-tag neovim:v0.3.0 -build
ENV PACKAGES="\
bash \

View File

@@ -1,4 +1,4 @@
Copyright (c) 2016-2019, w0rp <devw0rp@gmail.com>
Copyright (c) 2016-2018, w0rp <devw0rp@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -1,13 +1,13 @@
# 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 [![Travis CI Build Status](https://travis-ci.org/w0rp/ale.svg?branch=master)](https://travis-ci.org/w0rp/ale) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/r0ef1xu8xjmik58d/branch/master?svg=true)](https://ci.appveyor.com/project/w0rp/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)
![ALE Logo by Mark Grealish - https://www.bhalash.com/](img/logo.jpg?raw=true)
ALE (Asynchronous Lint Engine) is a plugin providing linting (syntax checking
and semantic errors) in NeoVim 0.2.0+ and Vim 8 while you edit your text files,
ALE (Asynchronous Lint Engine) is a plugin for providing linting (checking
syntax and semantics) in NeoVim 0.2.0+ and Vim 8 while you edit your text files,
and acts as a Vim [Language Server Protocol](https://langserver.org/) client.
<img src="https://user-images.githubusercontent.com/3518142/59195938-3a81b100-8b85-11e9-8e8d-6a601b1db908.gif" alt="A linting example with the darkspectrum color scheme in GVim." title="A linting example with the darkspectrum color scheme in GVim.">
<img src="img/example.gif?raw=true" alt="A linting example with the darkspectrum color scheme in GVim." title="A linting example with the darkspectrum color scheme in GVim.">
ALE makes use of NeoVim and Vim 8 job control functions and timers to
run linters on the contents of text buffers and return errors as
@@ -26,7 +26,7 @@ features, including:
* Diagnostics (via Language Server Protocol linters)
* Go To Definition (`:ALEGoToDefinition`)
* Completion (Built in completion support, or with Deoplete)
* Completion (`let g:ale_completion_enabled = 1` before ALE is loaded)
* Finding references (`:ALEFindReferences`)
* Hover information (`:ALEHover`)
* Symbol search (`:ALESymbolSearch`)
@@ -159,44 +159,12 @@ ALE offers some support for completion via hijacking of omnicompletion while you
type. All of ALE's completion information must come from Language Server
Protocol linters, or from `tsserver` for TypeScript.
ALE integrates with [Deoplete](https://github.com/Shougo/deoplete.nvim) as a
completion source, named `'ale'`. You can configure Deoplete to only use ALE as
the source of completion information, or mix it with other sources.
```vim
" Use ALE and also some plugin 'foobar' as completion sources for all code.
call deoplete#custom#option('sources', {
\ '_': ['ale', 'foobar'],
\})
```
ALE also offers its own automatic completion support, which does not require any
other plugins, and can be enabled by changing a setting before ALE is loaded.
```vim
" Enable completion where available.
" This setting must be set before ALE is loaded.
"
" You should not turn this setting on if you wish to use ALE as a completion
" source for other completion plugins, like Deoplete.
let g:ale_completion_enabled = 1
```
ALE provides an omni-completion function you can use for triggering
completion manually with `<C-x><C-o>`.
```vim
set omnifunc=ale#completion#OmniFunc
```
When working with TypeScript files, ALE supports automatic imports from
external modules. This behavior is disabled by default and can be enabled by
setting:
```vim
let g:ale_completion_tsserver_autoimport = 1
```
See `:help ale-completion` for more information.
<a name="usage-go-to-definition"></a>
@@ -266,14 +234,14 @@ any other tools. Simply clone the plugin into your `pack` directory.
```bash
mkdir -p ~/.vim/pack/git-plugins/start
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.vim/pack/git-plugins/start/ale
git clone https://github.com/w0rp/ale.git ~/.vim/pack/git-plugins/start/ale
```
#### NeoVim on Unix
```bash
mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
git clone https://github.com/w0rp/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale
```
#### Vim 8 on Windows
@@ -281,7 +249,7 @@ git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.local/share/nvi
```bash
# Run these commands in the "Git for Windows" Bash terminal
mkdir -p ~/vimfiles/pack/git-plugins/start
git clone --depth 1 https://github.com/dense-analysis/ale.git ~/vimfiles/pack/git-plugins/start/ale
git clone https://github.com/w0rp/ale.git ~/vimfiles/pack/git-plugins/start/ale
```
#### Generating Vim help files
@@ -312,7 +280,7 @@ You can run the following commands in your terminal to do so:
```bash
cd ~/.vim/bundle
git clone https://github.com/dense-analysis/ale.git
git clone https://github.com/w0rp/ale.git
```
<a name="installation-with-vundle"></a>
@@ -323,7 +291,7 @@ You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.v
by using the path on GitHub for this repository.
```vim
Plugin 'dense-analysis/ale'
Plugin 'w0rp/ale'
```
See the Vundle documentation for more information.
@@ -337,7 +305,7 @@ by adding the GitHub path for this repository to your `~/.vimrc`
and running `:PlugInstall`.
```vim
Plug 'dense-analysis/ale'
Plug 'w0rp/ale'
```
<a name="contributing"></a>
@@ -345,14 +313,14 @@ Plug 'dense-analysis/ale'
## 4. Contributing
If you would like to see support for more languages and tools, please
[create an issue](https://github.com/dense-analysis/ale/issues)
or [create a pull request](https://github.com/dense-analysis/ale/pulls).
[create an issue](https://github.com/w0rp/ale/issues)
or [create a pull request](https://github.com/w0rp/ale/pulls).
If your tool can read from stdin or you have code to suggest which is good,
support can be happily added for it.
If you are interested in the general direction of the project, check out the
[wiki home page](https://github.com/dense-analysis/ale/wiki). The wiki includes
a Roadmap for the future, and more.
[wiki home page](https://github.com/w0rp/ale/wiki). The wiki includes a
Roadmap for the future, and more.
If you'd liked to discuss the project more directly, check out the `#vim-ale` channel
on Freenode. Web chat is available [here](https://webchat.freenode.net/?channels=vim-ale).
@@ -549,7 +517,7 @@ let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
Will give you:
![Echoed message](https://user-images.githubusercontent.com/3518142/59195927-348bd000-8b85-11e9-88b6-508a094f1548.png)
![Echoed message](img/echo.png)
See `:help g:ale_echo_msg_format` for more information.
@@ -604,7 +572,6 @@ options off.
```vim
" Write this in your vimrc file
let g:ale_lint_on_text_changed = 'never'
let g:ale_lint_on_insert_leave = 0
" You can disable this option too
" if you don't want linters to run on opening a file
let g:ale_lint_on_enter = 0
@@ -731,10 +698,11 @@ while you type. ALE uses a timeout which is cancelled and reset every time you
type, and this delay can be increased so linters are run less often. See
`:help g:ale_lint_delay` for more information.
If you don't wish to run linters while you type, you can disable that behaviour.
Set `g:ale_lint_on_text_changed` to `never`. You won't get as frequent error
checking, but ALE shouldn't block your ability to edit a document after you save
a file, so the asynchronous nature of the plugin will still be an advantage.
If you don't wish to run linters while you type, you can disable that
behaviour. Set `g:ale_lint_on_text_changed` to `never` or `normal`. You won't
get as frequent error checking, but ALE shouldn't block your ability to edit a
document after you save a file, so the asynchronous nature of the plugin will
still be an advantage.
If you are still concerned, you can turn the automatic linting off altogether,
including the option `g:ale_lint_on_enter`, and you can run ALE manually with

View File

@@ -5,10 +5,7 @@ call ale#Set('asm_gcc_executable', 'gcc')
call ale#Set('asm_gcc_options', '-Wall')
function! ale_linters#asm#gcc#GetCommand(buffer) abort
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file
return '%e -x assembler -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction

View File

@@ -4,6 +4,12 @@
call ale#Set('c_clangd_executable', 'clangd')
call ale#Set('c_clangd_options', '')
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
endfunction
@@ -13,5 +19,5 @@ call ale#linter#Define('c', {
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'c_clangd_executable')},
\ 'command': function('ale_linters#c#clangd#GetCommand'),
\ 'project_root': function('ale#c#FindProjectRoot'),
\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'),
\})

View File

@@ -11,32 +11,22 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
" http://clang.llvm.org/extra/clang-tidy/checks/list.html
call ale#Set('c_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy to use as compile
" flags.
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '')
" Set this option to manually set options for clang-tidy directly.
call ale#Set('c_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '')
function! ale_linters#c#clangtidy#GetCommand(buffer, output) abort
function! ale_linters#c#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
let l:options = ''
" Get the extra options if we couldn't find a build directory.
if empty(l:build_dir)
let l:options = ale#Var(a:buffer, 'c_clangtidy_options')
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
endif
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options')
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'c_clangtidy_options')
\ : ''
return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (!empty(l:options) ? ' -- ' . l:options : '')
@@ -46,7 +36,7 @@ call ale#linter#Define('c', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
\ 'executable': {b -> ale#Var(b, 'c_clangtidy_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clangtidy#GetCommand'))},
\ 'command': function('ale_linters#c#clangtidy#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})

View File

@@ -5,17 +5,23 @@ call ale#Set('c_cppcheck_executable', 'cppcheck')
call ale#Set('c_cppcheck_options', '--enable=style')
function! ale_linters#c#cppcheck#GetCommand(buffer) abort
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
" Search upwards from the file for compile_commands.json.
"
" If we find it, we'll `cd` to where the compile_commands.json file is,
" then use the file to set up import paths, etc.
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
let l:cd_command = !empty(l:compile_commmands_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : ''
return l:cd_command
\ . '%e -q --language=c'
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . l:buffer_path_include
\ . '%e -q --language=c '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'c_cppcheck_options')
\ . ' %t'
endfunction

View File

@@ -5,15 +5,13 @@ call ale#Set('c_cquery_executable', 'cquery')
call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
" Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
if empty(l:project_root)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
endif
" Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort

View File

@@ -9,11 +9,7 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
return '%e -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'

View File

@@ -1,54 +0,0 @@
" Author: Raphael Hoegger - https://github.com/pfuender
" Description: Cookstyle (RuboCop based), a code style analyzer for Ruby files
call ale#Set('chef_cookstyle_executable', 'cookstyle')
call ale#Set('chef_cookstyle_options', '')
function! ale_linters#chef#cookstyle#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'chef_cookstyle_options')
return '%e' . ale#Pad(escape(l:options, '~')) . ' --force-exclusion --format json --stdin ' . ' %s'
endfunction
function! ale_linters#chef#cookstyle#Handle(buffer, lines) abort
if len(a:lines) == 0
return []
endif
let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], {})
if !has_key(l:errors, 'summary')
\|| l:errors['summary']['offense_count'] == 0
\|| empty(l:errors['files'])
return []
endif
let l:output = []
for l:error in l:errors['files'][0]['offenses']
let l:start_col = str2nr(l:error['location']['start_column'])
let l:end_col = str2nr(l:error['location']['last_column'])
if !l:end_col
let l:end_col = l:start_col + 1
endif
call add(l:output, {
\ 'lnum': str2nr(l:error['location']['line']),
\ 'col': l:start_col,
\ 'end_col': l:end_col,
\ 'code': l:error['cop_name'],
\ 'text': l:error['message'],
\ 'type': l:error['severity'] is? 'convention' ? 'W' : 'E',
\})
endfor
return l:output
endfunction
call ale#linter#Define('chef', {
\ 'name': 'cookstyle',
\ 'executable': {b -> ale#Var(b, 'chef_cookstyle_executable')},
\ 'command': function('ale_linters#chef#cookstyle#GetCommand'),
\ 'callback': 'ale_linters#chef#cookstyle#Handle',
\})

View File

@@ -1,34 +0,0 @@
" Author: Masashi Iizuka <liquidz.uo@gmail.com>
" Description: linter for clojure using clj-kondo https://github.com/borkdude/clj-kondo
function! ale_linters#clojure#clj_kondo#HandleCljKondoFormat(buffer, lines) abort
" output format
" <filename>:<line>:<column>: <issue type>: <message>
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+):? ((Exception|error|warning): ?(.+))$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:type = 'E'
if l:match[4] is? 'warning'
let l:type = 'W'
endif
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3],
\ 'type': l:type,
\})
endfor
return l:output
endfunction
call ale#linter#Define('clojure', {
\ 'name': 'clj-kondo',
\ 'output_stream': 'stdout',
\ 'executable': 'clj-kondo',
\ 'command': 'clj-kondo --lint %t',
\ 'callback': 'ale_linters#clojure#clj_kondo#HandleCljKondoFormat',
\})

View File

@@ -12,8 +12,7 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir)
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
let l:build_dir = ale#path#Dirname(l:json_file)
let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endif
" The extra arguments in the command are used to prevent .plist files from

View File

@@ -4,6 +4,12 @@
call ale#Set('cpp_clangd_executable', 'clangd')
call ale#Set('cpp_clangd_options', '')
function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
endfunction
@@ -13,5 +19,5 @@ call ale#linter#Define('cpp', {
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')},
\ 'command': function('ale_linters#cpp#clangd#GetCommand'),
\ 'project_root': function('ale#c#FindProjectRoot'),
\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'),
\})

View File

@@ -5,32 +5,22 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply.
call ale#Set('cpp_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy to use as compile
" flags.
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '')
" Set this option to manually set options for clang-tidy directly.
call ale#Set('cpp_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '')
function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
let l:options = ''
" Get the extra options if we couldn't find a build directory.
if empty(l:build_dir)
let l:options = ale#Var(a:buffer, 'cpp_clangtidy_options')
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
endif
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
\ : ''
return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (!empty(l:options) ? ' -- ' . l:options : '')
@@ -40,7 +30,7 @@ call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
\ 'executable': {b -> ale#Var(b, 'cpp_clangtidy_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clangtidy#GetCommand'))},
\ 'command': function('ale_linters#cpp#clangtidy#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})

View File

@@ -5,17 +5,23 @@ call ale#Set('cpp_cppcheck_executable', 'cppcheck')
call ale#Set('cpp_cppcheck_options', '--enable=style')
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
" Search upwards from the file for compile_commands.json.
"
" If we find it, we'll `cd` to where the compile_commands.json file is,
" then use the file to set up import paths, etc.
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
let l:cd_command = !empty(l:compile_commmands_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : ''
return l:cd_command
\ . '%e -q --language=c++'
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . l:buffer_path_include
\ . '%e -q --language=c++ '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'cpp_cppcheck_options')
\ . ' %t'
endfunction

View File

@@ -5,15 +5,13 @@ call ale#Set('cpp_cquery_executable', 'cquery')
call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
" Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
if empty(l:project_root)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
endif
" Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort

View File

@@ -9,11 +9,7 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
return '%e -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'

View File

@@ -1,95 +0,0 @@
call ale#Set('cs_csc_options', '')
call ale#Set('cs_csc_source', '')
call ale#Set('cs_csc_assembly_path', [])
call ale#Set('cs_csc_assemblies', [])
function! s:GetWorkingDirectory(buffer) abort
let l:working_directory = ale#Var(a:buffer, 'cs_csc_source')
if !empty(l:working_directory)
return l:working_directory
endif
return expand('#' . a:buffer . ':p:h')
endfunction
function! ale_linters#cs#csc#GetCommand(buffer) abort
" Pass assembly paths via the -lib: parameter.
let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path')
let l:lib_option = !empty(l:path_list)
\ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',')
\ : ''
" Pass paths to DLL files via the -r: parameter.
let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies')
let l:r_option = !empty(l:assembly_list)
\ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',')
\ : ''
" register temporary module target file with ale
" register temporary module target file with ALE.
let l:out = ale#command#CreateFile(a:buffer)
" The code is compiled as a module and the output is redirected to a
" temporary file.
return ale#path#CdString(s:GetWorkingDirectory(a:buffer))
\ . 'csc /unsafe'
\ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options'))
\ . ale#Pad(l:lib_option)
\ . ale#Pad(l:r_option)
\ . ' /out:' . l:out
\ . ' /t:module'
\ . ' /recurse:' . ale#Escape('*.cs')
endfunction
function! ale_linters#cs#csc#Handle(buffer, lines) abort
" Look for lines like the following.
"
" Tests.cs(12,29): error CSXXXX: ; expected
"
" NOTE: pattern also captures file name as linter compiles all
" files within the source tree rooted at the specified source
" path and not just the file loaded in the buffer
let l:patterns = [
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
\]
let l:output = []
let l:dir = s:GetWorkingDirectory(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'code': l:match[5],
\ 'text': l:match[6] ,
\})
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
call add(l:output, {
\ 'filename':'<csc>',
\ 'lnum': -1,
\ 'col': -1,
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'code': l:match[2],
\ 'text': l:match[3],
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('cs',{
\ 'name': 'csc',
\ 'output_stream': 'stdout',
\ 'executable': 'csc',
\ 'command': function('ale_linters#cs#csc#GetCommand'),
\ 'callback': 'ale_linters#cs#csc#Handle',
\ 'lint_file': 1
\})

View File

@@ -52,34 +52,20 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort
" NOTE: pattern also captures file name as linter compiles all
" files within the source tree rooted at the specified source
" path and not just the file loaded in the buffer
let l:patterns = [
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
\]
let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$'
let l:output = []
let l:dir = s:GetWorkingDirectory(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'code': l:match[5],
\ 'text': l:match[6] ,
\})
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
call add(l:output, {
\ 'filename':'<mcs>',
\ 'lnum': -1,
\ 'col': -1,
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'code': l:match[2],
\ 'text': l:match[3],
\})
endif
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'code': l:match[5],
\ 'text': l:match[6],
\})
endfor
return l:output

View File

@@ -1,9 +0,0 @@
" Author: harttle <yangjvn@126.com>
" Description: fecs for CSS files
call ale#linter#Define('css', {
\ 'name': 'fecs',
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
\ 'command': function('ale#handlers#fecs#GetCommand'),
\ 'callback': 'ale#handlers#fecs#Handle',
\})

View File

@@ -1,40 +0,0 @@
" Author: antew - https://github.com/antew
" Description: elm-language-server integration for elm (diagnostics, formatting, and more)
call ale#Set('elm_ls_executable', 'elm-language-server')
call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1))
" elm-language-server will search for local and global binaries, if empty
call ale#Set('elm_ls_elm_path', '')
call ale#Set('elm_ls_elm_format_path', '')
call ale#Set('elm_ls_elm_test_path', '')
call ale#Set('elm_ls_elm_analyse_trigger', 'change')
function! elm_ls#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction
function! elm_ls#GetOptions(buffer) abort
return {
\ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'),
\ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'),
\ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'),
\ 'elmAnalyseTrigger': ale#Var(a:buffer, 'elm_ls_elm_analyse_trigger'),
\}
endfunction
call ale#linter#Define('elm', {
\ 'name': 'elm_ls',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_ls', [
\ 'node_modules/.bin/elm-language-server',
\ 'node_modules/.bin/elm-lsp',
\ 'elm-lsp'
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('elm_ls#GetRootDir'),
\ 'language': 'elm',
\ 'initialization_options': function('elm_ls#GetOptions')
\})

View File

@@ -0,0 +1,22 @@
" Author: antew - https://github.com/antew
" Description: LSP integration for elm, currently supports diagnostics (linting)
call ale#Set('elm_lsp_executable', 'elm-lsp')
call ale#Set('elm_lsp_use_global', get(g:, 'ale_use_global_executables', 0))
function! elm_lsp#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction
call ale#linter#Define('elm', {
\ 'name': 'elm_lsp',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_lsp', [
\ 'node_modules/.bin/elm-lsp',
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('elm_lsp#GetRootDir'),
\ 'language': 'elm'
\})

View File

@@ -1,93 +0,0 @@
" Author: Autoine Gagne - https://github.com/AntoineGagne
" Description: Define a checker that runs dialyzer on Erlang files.
let g:ale_erlang_dialyzer_executable =
\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer')
let g:ale_erlang_dialyzer_plt_file =
\ get(g:, 'ale_erlang_dialyzer_plt_file', '')
let g:ale_erlang_dialyzer_rebar3_profile =
\ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default')
function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile')
endfunction
function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort
let l:plt_file = ''
let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer)
let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build/' . l:rebar3_profile)
if !empty(l:plt_file_directory)
let l:plt_file = globpath(l:plt_file_directory, '*_plt', 0, 1)
endif
if !empty(l:plt_file)
return l:plt_file[0]
endif
if !empty($REBAR_PLT_DIR)
return expand('$REBAR_PLT_DIR/dialyzer/plt')
endif
return expand('$HOME/.dialyzer_plt')
endfunction
function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort
let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file')
if !empty(l:plt_file)
return l:plt_file
endif
return ale_linters#erlang#dialyzer#FindPlt(a:buffer)
endfunction
function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_executable')
endfunction
function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort
let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer))
\ . ' -n'
\ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer))
\ . ' -Wunmatched_returns'
\ . ' -Werror_handling'
\ . ' -Wrace_conditions'
\ . ' -Wunderspecs'
\ . ' %s'
return l:command
endfunction
function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort
" Match patterns like the following:
"
" erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available
let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) != 0
let l:code = l:match[2]
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'lcol': 0,
\ 'text': l:code,
\ 'type': 'W'
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'dialyzer',
\ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'),
\ 'command': function('ale_linters#erlang#dialyzer#GetCommand'),
\ 'callback': function('ale_linters#erlang#dialyzer#Handle'),
\ 'lint_file': 1
\})

View File

@@ -8,7 +8,7 @@ call ale#Set('eruby_ruumba_options', '')
function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'eruby_ruumba_executable')
return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))

View File

@@ -5,13 +5,11 @@ call ale#Set('go_bingo_executable', 'bingo')
call ale#Set('go_bingo_options', '--mode stdio')
function! ale_linters#go#bingo#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
endfunction
function! ale_linters#go#bingo#FindProjectRoot(buffer) abort
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h'
if empty(l:project_root)

View File

@@ -11,7 +11,6 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
" Run go test in local directory with relative path
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./'

View File

@@ -1,16 +1,10 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: gofmt for Go files
function! ale_linters#go#gofmt#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer)
\ . '%e -e %t'
endfunction
call ale#linter#Define('go', {
\ 'name': 'gofmt',
\ 'output_stream': 'stderr',
\ 'executable': 'gofmt',
\ 'command': function('ale_linters#go#gofmt#GetCommand'),
\ 'command': 'gofmt -e %t',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})

View File

@@ -10,16 +10,13 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run '
\ . l:options
endif
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run '
\ . ale#Escape(l:filename)
\ . ' ' . l:options

View File

@@ -7,7 +7,7 @@ call ale#Set('go_golint_options', '')
function! ale_linters#go#golint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golint_options')
return ale#go#EnvString(a:buffer) . '%e'
return '%e'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %t'
endfunction

View File

@@ -14,13 +14,11 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'

View File

@@ -1,34 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Author: Jerko Steiner <https://github.com/jeremija>
" Description: https://github.com/saibing/gopls
call ale#Set('go_gopls_executable', 'gopls')
call ale#Set('go_gopls_options', '--mode stdio')
function! ale_linters#go#gopls#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer)
\ . '%e'
\ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options'))
endfunction
function! ale_linters#go#gopls#FindProjectRoot(buffer) abort
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h'
if empty(l:project_root)
let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
let l:mods = ':h:h'
endif
return !empty(l:project_root) ? fnamemodify(l:project_root, l:mods) : ''
endfunction
call ale#linter#Define('go', {
\ 'name': 'gopls',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'go_gopls_executable')},
\ 'command': function('ale_linters#go#gopls#GetCommand'),
\ 'project_root': function('ale_linters#go#gopls#FindProjectRoot'),
\})

View File

@@ -2,8 +2,7 @@
" Description: gosimple for Go files
function! ale_linters#go#gosimple#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gosimple .'
return ale#path#BufferCdString(a:buffer) . ' gosimple .'
endfunction
call ale#linter#Define('go', {

View File

@@ -6,8 +6,7 @@ function! ale_linters#go#gotype#GetCommand(buffer) abort
return ''
endif
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gotype -e .'
return ale#path#BufferCdString(a:buffer) . ' gotype -e .'
endfunction
call ale#linter#Define('go', {

View File

@@ -11,7 +11,6 @@ function! ale_linters#go#govet#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_govet_options')
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' .'

View File

@@ -15,9 +15,8 @@ function! ale_linters#go#langserver#GetCommand(buffer) abort
endif
let l:options = uniq(sort(l:options))
let l:env = ale#go#EnvString(a:buffer)
return l:env . join(extend(l:executable, l:options), ' ')
return join(extend(l:executable, l:options), ' ')
endfunction
call ale#linter#Define('go', {

View File

@@ -8,18 +8,17 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort
let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_staticcheck_options')
let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package')
let l:env = ale#go#EnvString(a:buffer)
" BufferCdString is used so that we can be sure the paths output from
" staticcheck can be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . l:env . 'staticcheck'
\ . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
\ . l:env . 'staticcheck'
\ . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' ' . ale#Escape(l:filename)
endfunction

View File

@@ -4,8 +4,7 @@
call ale#Set('haskell_cabal_ghc_options', '-fno-code -v0')
function! ale_linters#haskell#cabal_ghc#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . 'cabal exec -- ghc '
return 'cabal exec -- ghc '
\ . ale#Var(a:buffer, 'haskell_cabal_ghc_options')
\ . ' %t'
endfunction

View File

@@ -4,8 +4,7 @@
call ale#Set('haskell_stack_ghc_options', '-fno-code -v0')
function! ale_linters#haskell#stack_ghc#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . ale#handlers#haskell#GetStackExecutable(a:buffer)
return ale#handlers#haskell#GetStackExecutable(a:buffer)
\ . ' ghc -- '
\ . ale#Var(a:buffer, 'haskell_stack_ghc_options')
\ . ' %t'

View File

@@ -1,9 +0,0 @@
" Author: harttle <yangjvn@126.com>
" Description: fecs for HTMl files
call ale#linter#Define('html', {
\ 'name': 'fecs',
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
\ 'command': function('ale#handlers#fecs#GetCommand'),
\ 'callback': 'ale#handlers#fecs#Handle',
\})

View File

@@ -1,35 +0,0 @@
" Author: Andreww Hayworth <ahayworth@gmail.com>
" Description: Integrate ALE with ink-language-server
call ale#Set('ink_ls_executable', 'ink-language-server')
call ale#Set('ink_ls_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('ink_ls_initialization_options', {})
function! ale_linters#ink#ls#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'ink_ls', [
\ 'ink-language-server',
\ 'node_modules/.bin/ink-language-server',
\])
endfunction
function! ale_linters#ink#ls#GetCommand(buffer) abort
let l:executable = ale_linters#ink#ls#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' --stdio'
endfunction
function! ale_linters#ink#ls#FindProjectRoot(buffer) abort
let l:main_file = get(ale#Var(a:buffer, 'ink_ls_initialization_options'), 'mainStoryPath', 'main.ink')
let l:config = ale#path#ResolveLocalPath(a:buffer, l:main_file, expand('#' . a:buffer . ':p'))
return ale#path#Dirname(l:config)
endfunction
call ale#linter#Define('ink', {
\ 'name': 'ink-language-server',
\ 'lsp': 'stdio',
\ 'executable': function('ale_linters#ink#ls#GetExecutable'),
\ 'command': function('ale_linters#ink#ls#GetCommand'),
\ 'project_root': function('ale_linters#ink#ls#FindProjectRoot'),
\ 'initialization_options': {b -> ale#Var(b, 'ink_ls_initialization_options')},
\})

View File

@@ -1,10 +1,6 @@
" Author: Devon Meunier <devon.meunier@gmail.com>
" Description: checkstyle for Java files
call ale#Set('java_checkstyle_executable', 'checkstyle')
call ale#Set('java_checkstyle_config', '/google_checks.xml')
call ale#Set('java_checkstyle_options', '')
function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
let l:output = []
@@ -21,10 +17,6 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
\})
endfor
if !empty(l:output)
return l:output
endif
" old checkstyle versions
let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'
@@ -39,32 +31,19 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
return l:output
endfunction
function! s:GetConfig(buffer, config) abort
if ale#path#IsAbsolute(a:config)
return a:config
endif
let s:file = ale#path#FindNearestFile(a:buffer, a:config)
return !empty(s:file) ? s:file : a:config
endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config')
let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option)
\ ? s:GetConfig(a:buffer, l:config_option)
\ : ''
return '%e'
\ . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
return 'checkstyle '
\ . ale#Var(a:buffer, 'java_checkstyle_options')
\ . ' %s'
endfunction
if !exists('g:ale_java_checkstyle_options')
let g:ale_java_checkstyle_options = '-c /google_checks.xml'
endif
call ale#linter#Define('java', {
\ 'name': 'checkstyle',
\ 'executable': {b -> ale#Var(b, 'java_checkstyle_executable')},
\ 'executable': 'checkstyle',
\ 'command': function('ale_linters#java#checkstyle#GetCommand'),
\ 'callback': 'ale_linters#java#checkstyle#Handle',
\ 'lint_file': 1,

View File

@@ -1,161 +0,0 @@
" Author: Horacio Sanson <https://github.com/hsanson>
" Description: Support for the Eclipse language server https://github.com/eclipse/eclipse.jdt.ls
let s:version_cache = {}
call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls'))
call ale#Set('java_eclipselsp_config_path', '')
call ale#Set('java_eclipselsp_workspace_path', '')
call ale#Set('java_eclipselsp_executable', 'java')
function! ale_linters#java#eclipselsp#Executable(buffer) abort
return ale#Var(a:buffer, 'java_eclipselsp_executable')
endfunction
function! ale_linters#java#eclipselsp#TargetPath(buffer) abort
return ale#Var(a:buffer, 'java_eclipselsp_path')
endfunction
function! ale_linters#java#eclipselsp#JarPath(buffer) abort
let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer)
" Search jar file within repository path when manually built using mvn
let l:repo_path = l:path . '/org.eclipse.jdt.ls.product/target/repository'
let l:files = globpath(l:repo_path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) == 1
return l:files[0]
endif
" Search jar file within VSCode extensions folder.
let l:files = globpath(l:path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) == 1
return l:files[0]
endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) == 1
return l:files[0]
endif
return ''
endfunction
function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort
let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h')
let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path')
if !empty(l:config_path)
return ale#path#Simplify(l:config_path)
endif
if has('win32')
let l:path = l:path . '/config_win'
elseif has('macunix')
let l:path = l:path . '/config_mac'
else
let l:path = l:path . '/config_linux'
endif
return ale#path#Simplify(l:path)
endfunction
function! ale_linters#java#eclipselsp#VersionCheck(version_lines) abort
return s:GetVersion('', a:version_lines)
endfunction
function! s:GetVersion(executable, version_lines) abort
let l:version = []
for l:line in a:version_lines
let l:match = matchlist(l:line, '\(\d\+\)\.\(\d\+\)\.\(\d\+\)')
if !empty(l:match)
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0]
let s:version_cache[a:executable] = l:version
break
endif
endfor
return l:version
endfunction
function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines, meta) abort
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
let l:version = s:GetVersion(l:executable, a:version_lines)
return ale_linters#java#eclipselsp#Command(a:buffer, l:version)
endfunction
function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path')
if !empty(l:wspath)
return l:wspath
endif
return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
endfunction
function! ale_linters#java#eclipselsp#Command(buffer, version) abort
let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
let l:cmd = [ ale#Escape(l:executable),
\ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
\ '-Dosgi.bundles.defaultStartLevel=4',
\ '-Declipse.product=org.eclipse.jdt.ls.core.product',
\ '-Dlog.level=ALL',
\ '-noverify',
\ '-Xmx1G',
\ '-jar',
\ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)),
\ '-configuration',
\ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)),
\ '-data',
\ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer))
\ ]
if ale#semver#GTE(a:version, [1, 9])
call add(l:cmd, '--add-modules=ALL-SYSTEM')
call add(l:cmd, '--add-opens java.base/java.util=ALL-UNNAMED')
call add(l:cmd, '--add-opens java.base/java.lang=ALL-UNNAMED')
endif
return join(l:cmd, ' ')
endfunction
function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
if empty(l:executable)
return ''
endif
let l:cache = s:version_cache
if has_key(s:version_cache, l:executable)
return ale_linters#java#eclipselsp#Command(a:buffer, s:version_cache[l:executable])
endif
let l:command = ale#Escape(l:executable) . ' -version'
return ale#command#Run(
\ a:buffer,
\ l:command,
\ function('ale_linters#java#eclipselsp#CommandWithVersion')
\)
endfunction
call ale#linter#Define('java', {
\ 'name': 'eclipselsp',
\ 'lsp': 'stdio',
\ 'executable': function('ale_linters#java#eclipselsp#Executable'),
\ 'command': function('ale_linters#java#eclipselsp#RunWithVersionCheck'),
\ 'language': 'java',
\ 'project_root': function('ale#java#FindProjectRoot'),
\})

View File

@@ -21,11 +21,6 @@ function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
let l:command = ale#gradle#BuildClasspathCommand(a:buffer)
endif
" Try to use Ant if Gradle and Maven aren't available
if empty(l:command)
let l:command = ale#ant#BuildClasspathCommand(a:buffer)
endif
if empty(l:command)
return ale_linters#java#javac#GetCommand(a:buffer, [], {})
endif

View File

@@ -1,47 +1,16 @@
" Author: Horacio Sanson <https://github.com/hsanson>
" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
call ale#Set('java_javalsp_executable', '')
call ale#Set('java_javalsp_config', {})
call ale#Set('java_javalsp_executable', 'java')
function! ale_linters#java#javalsp#Executable(buffer) abort
return ale#Var(a:buffer, 'java_javalsp_executable')
endfunction
function! ale_linters#java#javalsp#Config(buffer) abort
let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } }
let l:config = ale#Var(a:buffer, 'java_javalsp_config')
" Ensure the config dictionary contains both classPath and
" externalDependencies keys to avoid a NPE crash on Java Language Server.
call extend(l:config, l:defaults, 'keep')
call extend(l:config['java'], l:defaults['java'], 'keep')
return l:config
endfunction
function! ale_linters#java#javalsp#Command(buffer) abort
let l:executable = ale_linters#java#javalsp#Executable(a:buffer)
if fnamemodify(l:executable, ':t') is# 'java'
" For backward compatibility.
let l:cmd = [
\ ale#Escape(l:executable),
\ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs',
\ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs',
\ '-m javacs/org.javacs.Main',
\]
return join(l:cmd, ' ')
else
return ale#Escape(l:executable)
endif
return ale#Escape(l:executable) . ' -Xverify:none -m javacs/org.javacs.Main'
endfunction
call ale#linter#Define('java', {
@@ -51,5 +20,4 @@ call ale#linter#Define('java', {
\ 'command': function('ale_linters#java#javalsp#Command'),
\ 'language': 'java',
\ 'project_root': function('ale#java#FindProjectRoot'),
\ 'lsp_config': function('ale_linters#java#javalsp#Config')
\})

View File

@@ -6,5 +6,5 @@ call ale#linter#Define('javascript', {
\ 'output_stream': 'both',
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON',
\ 'callback': 'ale#handlers#eslint#Handle',
\})

View File

@@ -1,10 +0,0 @@
" Author: harttle <yangjvn@126.com>
" Description: fecs for JavaScript files
call ale#linter#Define('javascript', {
\ 'name': 'fecs',
\ 'executable': function('ale#handlers#fecs#GetExecutable'),
\ 'command': function('ale#handlers#fecs#GetCommand'),
\ 'read_buffer': 0,
\ 'callback': 'ale#handlers#fecs#Handle',
\})

0
ale_linters/javascript/flow.vim Normal file → Executable file
View File

View File

@@ -8,7 +8,6 @@ call ale#Set('javascript_standard_options', '')
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
\ 'node_modules/standard/bin/cmd.js',
\ 'node_modules/semistandard/bin/cmd.js',
\ 'node_modules/.bin/standard',
\])
endfunction

View File

@@ -14,7 +14,7 @@ endfunction
function! ale_linters#javascript#xo#GetCommand(buffer) abort
return ale#Escape(ale_linters#javascript#xo#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'javascript_xo_options')
\ . ' --reporter json --stdin --stdin-filename %s'
\ . ' --reporter unix --stdin --stdin-filename %s'
endfunction
" xo uses eslint and the output format is the same
@@ -22,5 +22,5 @@ call ale#linter#Define('javascript', {
\ 'name': 'xo',
\ 'executable': function('ale_linters#javascript#xo#GetExecutable'),
\ 'command': function('ale_linters#javascript#xo#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON',
\ 'callback': 'ale#handlers#eslint#Handle',
\})

0
ale_linters/less/lessc.vim Normal file → Executable file
View File

View File

@@ -17,17 +17,18 @@ function! ale_linters#markdown#mdl#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'markdown_mdl_options')
return ale#Escape(l:executable) . l:exec_args
\ . ' -j' . (!empty(l:options) ? ' ' . l:options : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
endfunction
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
" matches: '(stdin):173: MD004 Unordered list style'
let l:pattern = ':\(\d*\): \(.*\)$'
let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:error['line'],
\ 'code': l:error['rule'] . '/' . join(l:error['aliases'], '/'),
\ 'text': l:error['description'],
\ 'lnum': l:match[1] + 0,
\ 'text': l:match[2],
\ 'type': 'W',
\})
endfor

View File

@@ -4,6 +4,12 @@
call ale#Set('objc_clangd_executable', 'clangd')
call ale#Set('objc_clangd_options', '')
function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objc#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
endfunction
@@ -13,5 +19,5 @@ call ale#linter#Define('objc', {
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')},
\ 'command': function('ale_linters#objc#clangd#GetCommand'),
\ 'project_root': function('ale#c#FindProjectRoot'),
\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'),
\})

View File

@@ -4,6 +4,12 @@
call ale#Set('objcpp_clangd_executable', 'clangd')
call ale#Set('objcpp_clangd_options', '')
function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
endfunction
@@ -13,5 +19,5 @@ call ale#linter#Define('objcpp', {
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')},
\ 'command': function('ale_linters#objcpp#clangd#GetCommand'),
\ 'project_root': function('ale#c#FindProjectRoot'),
\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'),
\})

View File

@@ -10,13 +10,13 @@ call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#phpcs#GetCommand(buffer) abort
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard)
\ ? '--standard=' . ale#Escape(l:standard)
\ ? '--standard=' . l:standard
\ : ''
let l:options = ale#Var(a:buffer, 'php_phpcs_options')
return ale#path#BufferCdString(a:buffer)
\ . '%e -s --report=emacs --stdin-path=%s'
\ . ale#Pad(l:standard_option)
\ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options'))
return '%e -s --report=emacs --stdin-path=%s'
\ . ale#Pad(l:standard_option)
\ . ale#Pad(l:options)
endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
@@ -36,7 +36,6 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
\ 'col': l:match[2] + 0,
\ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W',
\ 'sub_type': 'style',
\})
endfor

View File

@@ -3,42 +3,23 @@
" Set to change the ruleset
let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan')
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '')
let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4')
let g:ale_php_phpstan_configuration = get(g:, 'ale_php_phpstan_configuration', '')
let g:ale_php_phpstan_autoload = get(g:, 'ale_php_phpstan_autoload', '')
function! ale_linters#php#phpstan#GetCommand(buffer, version) abort
let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration')
let l:configuration_option = !empty(l:configuration)
\ ? ' -c ' . ale#Escape(l:configuration)
\ : ''
let l:autoload = ale#Var(a:buffer, 'php_phpstan_autoload')
let l:autoload_option = !empty(l:autoload)
\ ? ' -a ' . ale#Escape(l:autoload)
\ : ''
let l:level = ale#Var(a:buffer, 'php_phpstan_level')
let l:config_file_exists = ale#path#FindNearestFile(a:buffer, 'phpstan.neon')
if empty(l:level) && empty(l:config_file_exists)
" if no configuration file is found, then use 4 as a default level
let l:level = '4'
endif
let l:level_option = !empty(l:level)
\ ? ' -l ' . ale#Escape(l:level)
\ ? ' -c ' . l:configuration
\ : ''
let l:error_format = ale#semver#GTE(a:version, [0, 10, 3])
\ ? ' --error-format raw'
\ : ' --errorFormat raw'
return '%e analyze --no-progress'
return '%e analyze -l'
\ . ale#Var(a:buffer, 'php_phpstan_level')
\ . l:error_format
\ . l:configuration_option
\ . l:autoload_option
\ . l:level_option
\ . ' %s'
endfunction
@@ -54,7 +35,7 @@ function! ale_linters#php#phpstan#Handle(buffer, lines) abort
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'text': l:match[3],
\ 'type': 'E',
\ 'type': 'W',
\})
endfor

View File

@@ -1,7 +1,7 @@
" Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP
call ale#Set('psalm_langserver_executable', 'psalm')
call ale#Set('psalm_langserver_executable', 'psalm-language-server')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
@@ -14,8 +14,8 @@ call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
\ 'vendor/bin/psalm',
\ 'vendor/bin/psalm-language-server',
\ ])},
\ 'command': '%e --language-server',
\ 'command': '%e',
\ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'),
\})

View File

@@ -1,99 +0,0 @@
" Author: Jesse Harris - https://github.com/zigford
" Description: This file adds support for powershell scripts synatax errors
call ale#Set('powershell_powershell_executable', 'pwsh')
function! ale_linters#powershell#powershell#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'powershell_powershell_executable')
endfunction
" Some powershell magic to show syntax errors without executing the script
" thanks to keith hill:
" https://rkeithhill.wordpress.com/2007/10/30/powershell-quicktip-preparsing-scripts-to-check-for-syntax-errors/
function! ale_linters#powershell#powershell#GetCommand(buffer) abort
let l:script = ['Param($Script);
\ trap {$_;continue} & {
\ $Contents = Get-Content -Path $Script;
\ $Contents = [string]::Join([Environment]::NewLine, $Contents);
\ [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Contents);
\ };']
return ale#powershell#RunPowerShell(
\ a:buffer, 'powershell_powershell', l:script)
endfunction
" Parse powershell error output using regex into a list of dicts
function! ale_linters#powershell#powershell#Handle(buffer, lines) abort
let l:output = []
" Our 3 patterns we need to scrape the data for the dicts
let l:patterns = [
\ '\v^At line:(\d+) char:(\d+)',
\ '\v^(At|\+| )@!.*',
\ '\vFullyQualifiedErrorId : (\w+)',
\]
let l:matchcount = 0
for l:match in ale#util#GetMatches(a:lines, l:patterns)
" We want to work with 3 matches per syntax error
let l:matchcount = l:matchcount + 1
if l:matchcount == 1 || str2nr(l:match[1])
" First match consists of 2 capture groups, and
" can capture the line and col
if exists('l:item')
" We may be here because the last syntax
" didn't emit a code, and so only had 2
" matches
call add(l:output, l:item)
let l:matchcount = 1
endif
" If the match is 0, it was a failed match
" probably due to an unexpected token which
" contained a newline. Reset matchcount. to
" continue to the next match
if !empty(l:match[1])
let l:item = {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'type': 'E',
\}
else
let l:matchcount = 0
endif
elseif l:matchcount == 2
" Second match[0] grabs the full line in order
" to handles the text
let l:item['text'] = l:match[0]
else
" Final match handles the code, however
" powershell only emits 1 code for all errors
" so, we get the final code on the last error
" and loop over the previously added items to
" append the code we now know
call add(l:output, l:item)
unlet l:item
if len(l:match[1]) > 0
for l:i in l:output
let l:i['code'] = l:match[1]
endfor
endif
" Reset the matchcount so we can begin gathering
" matches for the next syntax error
let l:matchcount = 0
endif
endfor
return l:output
endfunction
call ale#linter#Define('powershell', {
\ 'name': 'powershell',
\ 'executable': function('ale_linters#powershell#powershell#GetExecutable'),
\ 'command': function('ale_linters#powershell#powershell#GetCommand'),
\ 'output_stream': 'stdout',
\ 'callback': 'ale_linters#powershell#powershell#Handle',
\})

View File

@@ -13,6 +13,37 @@ function! ale_linters#powershell#psscriptanalyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'powershell_psscriptanalyzer_executable')
endfunction
" Write a powershell script to a temp file for execution
" return the command used to execute it
function! s:TemporaryPSScript(buffer, input) abort
let l:filename = 'script.ps1'
" Create a temp dir to house our temp .ps1 script
" a temp dir is needed as powershell needs the .ps1
" extension
let l:tempdir = ale#util#Tempname() . (has('win32') ? '\' : '/')
let l:tempscript = l:tempdir . l:filename
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:tempdir, '', 0750)
" Automatically delete the directory later.
call ale#command#ManageDirectory(a:buffer, l:tempdir)
" Write the script input out to a file.
call ale#util#Writefile(a:buffer, a:input, l:tempscript)
return l:tempscript
endfunction
function! ale_linters#powershell#psscriptanalyzer#RunPowerShell(buffer, command) abort
let l:executable = ale_linters#powershell#psscriptanalyzer#GetExecutable(
\ a:buffer)
let l:tempscript = s:TemporaryPSScript(a:buffer, a:command)
return ale#Escape(l:executable)
\ . ' -Exe Bypass -NoProfile -File '
\ . ale#Escape(l:tempscript)
\ . ' %t'
endfunction
" Run Invoke-ScriptAnalyzer and output each linting message as 4 seperate lines
" for each parsing
function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
@@ -29,10 +60,8 @@ function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
\ $_.Message;
\ $_.RuleName}']
return ale#powershell#RunPowerShell(
\ a:buffer,
\ 'powershell_psscriptanalyzer',
\ l:script)
return ale_linters#powershell#psscriptanalyzer#RunPowerShell(
\ a:buffer, l:script)
endfunction
" add every 4 lines to an item(Dict) and every item to a list
@@ -69,8 +98,8 @@ endfunction
call ale#linter#Define('powershell', {
\ 'name': 'psscriptanalyzer',
\ 'executable': function('ale_linters#powershell#psscriptanalyzer#GetExecutable'),
\ 'command': function('ale_linters#powershell#psscriptanalyzer#GetCommand'),
\ 'executable_callback': 'ale_linters#powershell#psscriptanalyzer#GetExecutable',
\ 'command_callback': 'ale_linters#powershell#psscriptanalyzer#GetCommand',
\ 'output_stream': 'stdout',
\ 'callback': 'ale_linters#powershell#psscriptanalyzer#Handle',
\})

View File

@@ -31,20 +31,6 @@ function! ale_linters#pug#puglint#GetCommand(buffer) abort
\ . ' -r inline %t'
endfunction
function! ale_linters#pug#puglint#Handle(buffer, lines) abort
for l:line in a:lines[:10]
if l:line =~# '^SyntaxError: '
return [{
\ 'lnum': 1,
\ 'text': 'puglint configuration error (type :ALEDetail for more information)',
\ 'detail': join(a:lines, "\n"),
\}]
endif
endfor
return ale#handlers#unix#HandleAsError(a:buffer, a:lines)
endfunction
call ale#linter#Define('pug', {
\ 'name': 'puglint',
\ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [
@@ -52,5 +38,5 @@ call ale#linter#Define('pug', {
\ ])},
\ 'output_stream': 'stderr',
\ 'command': function('ale_linters#pug#puglint#GetCommand'),
\ 'callback': 'ale_linters#pug#puglint#Handle',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})

View File

@@ -1,49 +0,0 @@
" Author: Drew Olson <drew@drewolson.org>
" Description: Integrate ALE with purescript-language-server.
call ale#Set('purescript_ls_executable', 'purescript-language-server')
call ale#Set('purescript_ls_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('purescript_ls_config', {})
function! ale_linters#purescript#ls#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'purescript_ls', [
\ 'node_modules/.bin/purescript-language-server',
\])
endfunction
function! ale_linters#purescript#ls#GetCommand(buffer) abort
let l:executable = ale_linters#purescript#ls#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' --stdio'
endfunction
function! ale_linters#purescript#ls#FindProjectRoot(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, 'bower.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
let l:config = ale#path#FindNearestFile(a:buffer, 'psc-package.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
let l:config = ale#path#FindNearestFile(a:buffer, 'spago.dhall')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
return ''
endfunction
call ale#linter#Define('purescript', {
\ 'name': 'purescript-language-server',
\ 'lsp': 'stdio',
\ 'executable': function('ale_linters#purescript#ls#GetExecutable'),
\ 'command': function('ale_linters#purescript#ls#GetCommand'),
\ 'project_root': function('ale_linters#purescript#ls#FindProjectRoot'),
\ 'lsp_config': {b -> ale#Var(b, 'purescript_ls_config')},
\})

View File

@@ -78,5 +78,4 @@ call ale#linter#Define('python', {
\ 'executable': function('ale_linters#python#mypy#GetExecutable'),
\ 'command': function('ale_linters#python#mypy#GetCommand'),
\ 'callback': 'ale_linters#python#mypy#Handle',
\ 'output_stream': 'both'
\})

View File

@@ -6,7 +6,6 @@ call ale#Set('python_pylint_options', '')
call ale#Set('python_pylint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pylint_change_directory', 1)
call ale#Set('python_pylint_auto_pipenv', 0)
call ale#Set('python_pylint_use_msg_id', 0)
function! ale_linters#python#pylint#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylint_auto_pipenv'))
@@ -65,17 +64,11 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
continue
endif
if ale#Var(a:buffer, 'python_pylint_use_msg_id') is# 1
let l:code_out = l:code
else
let l:code_out = l:match[4]
endif
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 1,
\ 'text': l:match[5],
\ 'code': l:code_out,
\ 'code': l:match[4],
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
\})
endfor

View File

@@ -1,23 +0,0 @@
" Author: David Buchan-Swanson <github@deecewan.com>
" Description: Integrate ALE with reason-language-server.
call ale#Set('reason_ls_executable', '')
function! ale_linters#reason#ls#FindProjectRoot(buffer) abort
let l:reason_config = ale#path#FindNearestFile(a:buffer, 'bsconfig.json')
if !empty(l:reason_config)
return fnamemodify(l:reason_config, ':h')
endif
return ''
endfunction
call ale#linter#Define('reason', {
\ 'name': 'reason-language-server',
\ 'lsp': 'stdio',
\ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale_linters#reason#ls#FindProjectRoot'),
\ 'language': 'reason',
\})

View File

@@ -36,7 +36,7 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
return ale#ruby#EscapeExecutable(l:executable, 'brakeman')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
\ . ' -f json -q '
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
\ . ' -p ' . ale#Escape(l:rails_root)

View File

@@ -1,42 +0,0 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: debride, a dead method detector for Ruby files
call ale#Set('ruby_debride_executable', 'debride')
call ale#Set('ruby_debride_options', '')
function! ale_linters#ruby#debride#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_debride_executable')
return ale#ruby#EscapeExecutable(l:executable, 'debride')
\ . ale#Var(a:buffer, 'ruby_debride_options')
\ . ' %s'
endfunction
function! ale_linters#ruby#debride#HandleOutput(buffer, lines) abort
let l:output = []
for l:line in a:lines
if l:line !~# '^ '
continue
endif
let l:elements = split(l:line)
let l:method_name = l:elements[0]
let l:lnum = split(l:elements[1], ':')[1]
call add(l:output, {
\ 'lnum': 0 + l:lnum,
\ 'text': 'Possible unused method: ' . l:method_name,
\ 'type': 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'debride',
\ 'executable': {b -> ale#Var(b, 'ruby_debride_executable')},
\ 'command': function('ale_linters#ruby#debride#GetCommand'),
\ 'callback': 'ale_linters#ruby#debride#HandleOutput',
\})

View File

@@ -33,7 +33,7 @@ function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
let l:output_file = has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = has('win32') ? '; type %t' : ''
return ale#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
\ . ' --silent -f json --output-file ' . l:output_file
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
\ . ale#Escape(l:rails_root)

View File

@@ -14,7 +14,7 @@ function! ale_linters#ruby#reek#GetCommand(buffer, version) abort
\ ? ' --stdin-filename %s'
\ : ''
return ale#ruby#EscapeExecutable(l:executable, 'reek')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
\ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args
endfunction

View File

@@ -7,7 +7,7 @@ call ale#Set('ruby_rubocop_options', '')
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))

View File

@@ -1,23 +0,0 @@
call ale#Set('ruby_sorbet_executable', 'srb')
call ale#Set('ruby_sorbet_options', '')
function! ale_linters#ruby#sorbet#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable')
let l:options = ale#Var(a:buffer, 'ruby_sorbet_options')
return ale#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --lsp --disable-watchman'
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'sorbet',
\ 'aliases': ['srb'],
\ 'lsp': 'stdio',
\ 'language': 'ruby',
\ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')},
\ 'command': function('ale_linters#ruby#sorbet#GetCommand'),
\ 'project_root': function('ale#ruby#FindProjectRoot')
\})

View File

@@ -8,7 +8,7 @@ call ale#Set('ruby_standardrb_options', '')
function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_standardrb_executable')
return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))

View File

@@ -25,11 +25,14 @@ endfunction
function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check')
\ && ale#semver#GTE(a:version, [0, 17, 0])
let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets')
let l:use_all_targets = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_all_targets')
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples')
let l:use_examples = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_examples')
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
let l:use_tests = l:use_check
\ && ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
@@ -66,15 +69,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
if ale#Var(a:buffer, 'rust_cargo_use_clippy')
let l:subcommand = 'clippy'
let l:clippy_options = ale#Var(a:buffer, 'rust_cargo_clippy_options')
if l:clippy_options =~# '^-- '
let l:clippy_options = join(split(l:clippy_options, '-- '))
endif
if l:clippy_options isnot# ''
let l:clippy_options = ' -- ' . l:clippy_options
endif
let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options')
endif
return l:nearest_cargo_prefix . 'cargo '

View File

@@ -2,7 +2,7 @@
" Description: A language server for Rust
call ale#Set('rust_rls_executable', 'rls')
call ale#Set('rust_rls_toolchain', '')
call ale#Set('rust_rls_toolchain', 'nightly')
call ale#Set('rust_rls_config', {})
function! ale_linters#rust#rls#GetCommand(buffer) abort

View File

@@ -1,48 +0,0 @@
" Author: Jeffrey Lau - https://github.com/zoonfafer
" Description: Metals Language Server for Scala https://scalameta.org/metals/
call ale#Set('scala_metals_executable', 'metals-vim')
call ale#Set('scala_metals_project_root', '')
function! ale_linters#scala#metals#GetProjectRoot(buffer) abort
let l:project_root = ale#Var(a:buffer, 'scala_metals_project_root')
if !empty(l:project_root)
return l:project_root
endif
let l:potential_roots = [
\ 'build.sc',
\ 'build.sbt',
\ '.bloop',
\ '.metals',
\]
for l:root in l:potential_roots
let l:project_root = ale#path#ResolveLocalPath(
\ a:buffer,
\ l:root,
\ ''
\)
if !empty(l:project_root)
return fnamemodify(
\ l:project_root,
\ ':h',
\)
endif
endfor
endfunction
function! ale_linters#scala#metals#GetCommand(buffer) abort
return '%e' . ale#Pad('stdio')
endfunction
call ale#linter#Define('scala', {
\ 'name': 'metals',
\ 'lsp': 'stdio',
\ 'language': 'scala',
\ 'executable': {b -> ale#Var(b, 'scala_metals_executable')},
\ 'command': function('ale_linters#scala#metals#GetCommand'),
\ 'project_root': function('ale_linters#scala#metals#GetProjectRoot'),
\})

View File

@@ -34,10 +34,8 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" bash: line 13: syntax error near unexpected token `d'
" bash:行0: 未预期的符号“done”附近有语法错误
" bash: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符
" sh: 11: Syntax error: "(" unexpected
let l:pattern = '\v([^:]+:\D*)(\d+): (.+)$'
let l:pattern = '\v(line |: ?)(\d+): (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)

View File

@@ -10,7 +10,6 @@ call ale#Set('sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_excl
call ale#Set('sh_shellcheck_executable', 'shellcheck')
call ale#Set('sh_shellcheck_dialect', 'auto')
call ale#Set('sh_shellcheck_options', '')
call ale#Set('sh_shellcheck_change_directory', 1)
function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
@@ -41,15 +40,12 @@ function! ale_linters#sh#shellcheck#GetCommand(buffer, version) abort
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect')
let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : ''
let l:cd_string = ale#Var(a:buffer, 'sh_shellcheck_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
if l:dialect is# 'auto'
let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer)
endif
return l:cd_string
return ale#path#BufferCdString(a:buffer)
\ . '%e'
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
\ . (!empty(l:options) ? ' ' . l:options : '')

View File

@@ -1,35 +0,0 @@
" Author: Karl Bartel <karl42@gmail.com> - http://karl.berlin/
" Description: Report solc compiler errors in Solidity code
call ale#Set('solidity_solc_options', '')
function! ale_linters#solidity#solc#Handle(buffer, lines) abort
" Matches patterns like the following:
" /path/to/file/file.sol:1:10: Error: Identifier not found or not unique.
let l:pattern = '\v^[^:]+:(\d+):(\d+): (Error|Warning): (.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:isError = l:match[3] is? 'error'
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4],
\ 'type': l:isError ? 'E' : 'W',
\})
endfor
return l:output
endfunction
function! ale_linters#solidity#solc#GetCommand(buffer) abort
return 'solc' . ale#Pad(ale#Var(a:buffer, 'solidity_solc_options')) . ' %s'
endfunction
call ale#linter#Define('solidity', {
\ 'name': 'solc',
\ 'executable': 'solc',
\ 'command': function('ale_linters#solidity#solc#GetCommand'),
\ 'callback': 'ale_linters#solidity#solc#Handle',
\ 'output_stream': 'stderr',
\})

View File

@@ -1,13 +0,0 @@
" Author: Dan Loman <https://github.com/namolnad>
" Description: Support for sourcekit-lsp https://github.com/apple/sourcekit-lsp
call ale#Set('sourcekit_lsp_executable', 'sourcekit-lsp')
call ale#linter#Define('swift', {
\ 'name': 'sourcekitlsp',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'sourcekit_lsp_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#swift#FindProjectRoot'),
\ 'language': 'swift',
\})

View File

@@ -1,49 +0,0 @@
" Author: Keith Maxwell <keith.maxwell@gmail.com>
" Description: terraform fmt to check for errors
call ale#Set('terraform_terraform_executable', 'terraform')
function! ale_linters#terraform#terraform#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'terraform_terraform_executable')
endfunction
function! ale_linters#terraform#terraform#GetCommand(buffer) abort
return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer))
\ . ' fmt -no-color --check=true -'
endfunction
function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
let l:head = '^Error running fmt: In <standard input>: '
let l:output = []
let l:patterns = [
\ l:head.'At \(\d\+\):\(\d\+\): \(.*\)$',
\ l:head.'\(.*\)$'
\]
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match[2]) > 0
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'text': l:match[3],
\ 'type': 'E',
\})
else
call add(l:output, {
\ 'lnum': line('$'),
\ 'text': l:match[1],
\ 'type': 'E',
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('terraform', {
\ 'name': 'terraform',
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'),
\ 'command': function('ale_linters#terraform#terraform#GetCommand'),
\ 'callback': 'ale_linters#terraform#terraform#Handle',
\})

View File

@@ -9,69 +9,23 @@ call ale#Set('terraform_tflint_executable', 'tflint')
function! ale_linters#terraform#tflint#Handle(buffer, lines) abort
let l:output = []
let l:pattern = '\v^(.*):(\d+),(\d+)-(\d+)?,?(\d+): (.{-1,}); (.+)$'
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
" This is a rough test for tflint's output format
" On versions prior to 0.11 it outputs all errors as a single level list
if type(l:json) is v:t_list
for l:error in l:json
if l:error.type is# 'ERROR'
let l:type = 'E'
elseif l:error.type is# 'NOTICE'
let l:type = 'I'
else
let l:type = 'W'
endif
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
if l:error.type is# 'ERROR'
let l:type = 'E'
elseif l:error.type is# 'NOTICE'
let l:type = 'I'
else
let l:type = 'W'
endif
call add(l:output, {
\ 'lnum': l:error.line,
\ 'text': l:error.message,
\ 'type': l:type,
\ 'code': l:error.detector,
\})
endfor
else
for l:error in get(l:json, 'errors', [])
for l:match in ale#util#GetMatches(l:error.message, [l:pattern])
if l:match[4] is# ''
let l:match[4] = l:match[2]
endif
call add(l:output, {
\ 'filename': l:match[1],
\ 'lnum': str2nr(l:match[2]),
\ 'col': str2nr(l:match[3]),
\ 'end_lnum': str2nr(l:match[4]),
\ 'end_col': str2nr(l:match[5]),
\ 'text': l:match[7],
\ 'code': l:match[6],
\ 'type': 'E',
\})
endfor
endfor
for l:error in get(l:json, 'issues', [])
if l:error.rule.severity is# 'ERROR'
let l:type = 'E'
elseif l:error.rule.severity is# 'NOTICE'
let l:type = 'I'
else
let l:type = 'W'
endif
call add(l:output, {
\ 'filename': l:error.range.filename,
\ 'lnum': l:error.range.start.line,
\ 'col': l:error.range.start.column,
\ 'end_lnum': l:error.range.end.line,
\ 'end_col': l:error.range.end.column,
\ 'text': l:error.message,
\ 'code': l:error.rule.name,
\ 'type': l:type,
\})
endfor
endif
call add(l:output, {
\ 'lnum': l:error.line,
\ 'text': l:error.message,
\ 'type': l:type,
\ 'code': l:error.detector,
\})
endfor
return l:output
endfunction

View File

@@ -1,21 +0,0 @@
" Author: Ricardo Liang <ricardoliang@gmail.com>
" Description: Texlab language server (Rust rewrite)
call ale#Set('tex_texlab_executable', 'texlab')
call ale#Set('tex_texlab_options', '')
function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort
return ''
endfunction
function! ale_linters#tex#texlab#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'tex_texlab_options'))
endfunction
call ale#linter#Define('tex', {
\ 'name': 'texlab',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'tex_texlab_executable')},
\ 'command': function('ale_linters#tex#texlab#GetCommand'),
\ 'project_root': function('ale_linters#tex#texlab#GetProjectRoot'),
\})

View File

@@ -5,5 +5,5 @@ call ale#linter#Define('typescript', {
\ 'name': 'eslint',
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON',
\ 'callback': 'ale#handlers#eslint#Handle',
\})

View File

@@ -1,23 +0,0 @@
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',
\})

View File

@@ -24,20 +24,6 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
\})
endfor
"Matches patterns like the following:
"** Warning: (vlog-2623) add.v(7): Undefined variable: C.
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.
" let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
let l:pattern = '^**\s\(\w*\):\s\([^)]*)\)[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[2] . ' ' . l:match[4],
\})
endfor
return l:output
endfunction

View File

@@ -97,7 +97,7 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
let l:linters = !empty(l:ignore_config) || l:disable_lsp
let l:linters = !empty(l:ignore_config)
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config, l:disable_lsp)
\ : l:linters
@@ -156,7 +156,7 @@ function! ale#Queue(delay, ...) abort
endif
endfunction
let s:current_ale_version = [2, 6, 0]
let s:current_ale_version = [2, 4, 0]
" A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort

View File

@@ -1,41 +0,0 @@
" Author: Andrew Lee <andrewl@mbda.fun>.
" Inspired by ale/gradle.vim by Michael Pardo <michael@michaelpardo.com>
" Description: Functions for working with Ant projects.
" Given a buffer number, find an Ant project root
function! ale#ant#FindProjectRoot(buffer) abort
let l:build_xml_path = ale#path#FindNearestFile(a:buffer, 'build.xml')
if !empty(l:build_xml_path)
return fnamemodify(l:build_xml_path, ':h')
endif
return ''
endfunction
" Given a buffer number, find the path to the `ant` executable. Returns an empty
" string if cannot find the executable.
function! ale#ant#FindExecutable(buffer) abort
if executable('ant')
return 'ant'
endif
return ''
endfunction
" Given a buffer number, build a command to print the classpath of the root
" project. Returns an empty string if cannot build the command.
function! ale#ant#BuildClasspathCommand(buffer) abort
let l:executable = ale#ant#FindExecutable(a:buffer)
let l:project_root = ale#ant#FindProjectRoot(a:buffer)
if !empty(l:executable) && !empty(l:project_root)
return ale#path#CdString(l:project_root)
\ . ale#Escape(l:executable)
\ . ' classpath'
\ . ' -S'
\ . ' -q'
endif
return ''
endfunction

View File

@@ -96,13 +96,6 @@ function! ale#assert#Fixer(expected_result) abort
AssertEqual a:expected_result, l:result
endfunction
function! ale#assert#FixerNotExecuted() abort
let l:buffer = bufnr('')
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1]
Assert empty(l:result), "The fixer will be executed when it shouldn't be"
endfunction
function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
@@ -165,7 +158,6 @@ endfunction
function! ale#assert#SetUpFixerTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
endfunction
" A dummy function for making sure this module is loaded.
@@ -324,8 +316,4 @@ function! ale#assert#TearDownFixerTest() abort
if exists(':AssertFixer')
delcommand AssertFixer
endif
if exists(':AssertFixerNotExecuted')
delcommand AssertFixerNotExecuted
endif
endfunction

View File

@@ -23,117 +23,104 @@ function! ale#c#GetBuildDirectory(buffer) abort
return l:build_dir
endif
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
return ale#path#Dirname(l:json_file)
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endfunction
function! ale#c#ShellSplit(line) abort
let l:stack = []
let l:args = ['']
let l:prev = ''
for l:char in split(a:line, '\zs')
if l:char is# ''''
if len(l:stack) > 0 && get(l:stack, -1) is# ''''
call remove(l:stack, -1)
elseif (len(l:stack) == 0 || get(l:stack, -1) isnot# '"') && l:prev isnot# '\'
call add(l:stack, l:char)
endif
elseif (l:char is# '"' || l:char is# '`') && l:prev isnot# '\'
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
call remove(l:stack, -1)
elseif len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
call add(l:stack, l:char)
endif
elseif (l:char is# '(' || l:char is# '[' || l:char is# '{') && l:prev isnot# '\'
if len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
call add(l:stack, l:char)
endif
elseif (l:char is# ')' || l:char is# ']' || l:char is# '}') && l:prev isnot# '\'
if len(l:stack) > 0 && get(l:stack, -1) is# {')': '(', ']': '[', '}': '{'}[l:char]
call remove(l:stack, -1)
endif
elseif l:char is# ' ' && len(l:stack) == 0
if len(get(l:args, -1)) > 0
call add(l:args, '')
function! ale#c#FindProjectRoot(buffer) abort
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
continue
return l:path
endif
let l:args[-1] = get(l:args, -1) . l:char
endfor
return l:args
return ''
endfunction
function! ale#c#AreSpecialCharsBalanced(option) abort
" Escape \"
let l:option_escaped = substitute(a:option, '\\"', '', 'g')
" Retain special chars only
let l:special_chars = substitute(l:option_escaped, '[^"''()`]', '', 'g')
let l:special_chars = split(l:special_chars, '\zs')
" Check if they are balanced
let l:stack = []
for l:char in l:special_chars
if l:char is# ')'
if len(l:stack) == 0 || get(l:stack, -1) isnot# '('
return 0
endif
call remove(l:stack, -1)
elseif l:char is# '('
call add(l:stack, l:char)
else
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
call remove(l:stack, -1)
else
call add(l:stack, l:char)
endif
endif
endfor
return len(l:stack) == 0
endfunction
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:cflags_list = []
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
let l:split_lines = split(a:cflag_line)
let l:option_index = 0
while l:option_index < len(l:split_lines)
let l:option = l:split_lines[l:option_index]
let l:option_index = l:option_index + 1
let l:next_option_index = l:option_index + 1
" Include options, that may need relative path fix
if stridx(l:option, '-I') == 0
\ || stridx(l:option, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I'
else
let l:arg = l:split_lines[l:option_index]
let l:option_index = l:option_index + 1
" Join space-separated option
while l:next_option_index < len(l:split_lines)
\&& stridx(l:split_lines[l:next_option_index], '-') != 0
let l:next_option_index += 1
endwhile
let l:option = join(l:split_lines[l:option_index : l:next_option_index-1], ' ')
call remove(l:split_lines, l:option_index, l:next_option_index-1)
call insert(l:split_lines, l:option, l:option_index)
" Ignore invalid or conflicting options
if stridx(l:option, '-') != 0
\|| stridx(l:option, '-o') == 0
\|| stridx(l:option, '-c') == 0
call remove(l:split_lines, l:option_index)
let l:option_index = l:option_index - 1
" Fix relative path
elseif stridx(l:option, '-I') == 0
if !(stridx(l:option, ':') == 2+1 || stridx(l:option, '/') == 2+0)
let l:option = '-I' . a:path_prefix . s:sep . l:option[2:]
call remove(l:split_lines, l:option_index)
call insert(l:split_lines, l:option, l:option_index)
endif
" Fix relative paths if needed
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0
let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path)
endif
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:arg)
" Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
call add(l:cflags_list, l:option)
if l:option is# '-D' || l:option is# '-B'
call add(l:cflags_list, l:split_lines[l:option_index])
let l:option_index = l:option_index + 1
endif
" Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:split_lines[l:option_index])
let l:option_index = l:option_index + 1
" Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
\ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0
\ || (stridx(l:option, '-f') == 0 && stridx(l:option, '-fdump') != 0 && stridx(l:option, '-fdiagnostics') != 0 && stridx(l:option, '-fno-show-column') != 0)
\ || stridx(l:option, '-O') == 0
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs'
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0
call add(l:cflags_list, l:option)
endif
let l:option_index = l:option_index + 1
endwhile
return join(l:cflags_list, ' ')
call uniq(l:split_lines)
return join(l:split_lines, ' ')
endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile
return v:null
return ''
endif
let l:buffer_filename = expand('#' . a:buffer . ':t')
@@ -153,17 +140,14 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
endfunction
" Given a buffer number, find the project directory containing
" compile_commands.json, and the path to the compile_commands.json file.
"
" If compile_commands.json cannot be found, two empty strings will be
" returned.
" Given a buffer number, find the build subdirectory with compile commands
" The subdirectory is returned without the trailing /
function! ale#c#FindCompileCommands(buffer) abort
" Look above the current source file to find compile_commands.json
let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:json_file)
return [fnamemodify(l:json_file, ':h'), l:json_file]
return l:json_file
endif
" Search in build directories if we can't find it in the project.
@@ -173,42 +157,12 @@ function! ale#c#FindCompileCommands(buffer) abort
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
if filereadable(l:json_file)
return [l:path, l:json_file]
return l:json_file
endif
endfor
endfor
return ['', '']
endfunction
" Find the project root for C/C++ projects.
"
" The location of compile_commands.json will be used to find project roots.
"
" If compile_commands.json cannot be found, other common configuration files
" will be used to detect the project root.
function! ale#c#FindProjectRoot(buffer) abort
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
" Fall back on detecting the project root based on other filenames.
if empty(l:root)
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
return l:path
endif
endfor
endif
return l:root
return ''
endfunction
" Cache compile_commands.json data in a Dictionary, so we don't need to read
@@ -240,14 +194,10 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:raw_data = []
silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), ''))
if type(l:raw_data) isnot v:t_list
let l:raw_data = []
endif
let l:file_lookup = {}
let l:dir_lookup = {}
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
for l:entry in l:raw_data
let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
@@ -265,46 +215,14 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty
endfunction
function! ale#c#GetCompileCommand(json_item) abort
if has_key(a:json_item, 'command')
return a:json_item.command
elseif has_key(a:json_item, 'arguments')
return join(a:json_item.arguments, ' ')
endif
return ''
endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
" Search for an exact file match first.
let l:basename = tolower(expand('#' . a:buffer . ':t'))
let l:file_list = get(a:file_lookup, l:basename, [])
" A source file matching the header filename.
let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
for l:suffix in ['.c', '.cpp']
let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, [])
if !empty(l:file_list)
let l:source_file = l:key
break
endif
endfor
endif
for l:item in l:file_list
" Load the flags for this file, or for a source file matching the
" header file.
if (
\ bufnr(l:item.file) is a:buffer
\ || (
\ !empty(l:source_file)
\ && l:item.file[-len(l:source_file):] is? l:source_file
\ )
\)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
if bufnr(l:item.file) is a:buffer && has_key(l:item, 'command')
return ale#c#ParseCFlags(l:item.directory, l:item.command)
endif
endfor
@@ -316,7 +234,8 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
for l:item in l:dir_list
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
\&& has_key(l:item, 'command')
return ale#c#ParseCFlags(l:item.directory, l:item.command)
endif
endfor
@@ -332,25 +251,25 @@ function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
endfunction
function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = v:null
let l:cflags = ' '
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif
if ale#Var(a:buffer, 'c_parse_compile_commands')
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
let l:json_file = ale#c#FindCompileCommands(a:buffer)
if !empty(l:json_file)
let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
endif
endif
if l:cflags is v:null
if l:cflags is# ' '
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif
return l:cflags isnot v:null ? l:cflags : ''
return l:cflags
endfunction
function! ale#c#GetMakeCommand(buffer) abort

View File

@@ -1,163 +0,0 @@
" Author: Jerko Steiner <jerko.steiner@gmail.com>
" Description: Code action support for LSP / tsserver
function! ale#code_action#HandleCodeAction(code_action) abort
let l:current_buffer = bufnr('')
let l:changes = a:code_action.changes
for l:file_code_edit in l:changes
let l:buf = bufnr(l:file_code_edit.fileName)
if l:buf != -1 && l:buf != l:current_buffer && getbufvar(l:buf, '&mod')
call ale#util#Execute('echom ''Aborting action, file is unsaved''')
return
endif
endfor
for l:file_code_edit in l:changes
call ale#code_action#ApplyChanges(
\ l:file_code_edit.fileName, l:file_code_edit.textChanges)
endfor
endfunction
function! ale#code_action#ApplyChanges(filename, changes) abort
let l:current_buffer = bufnr('')
" The buffer is used to determine the fileformat, if available.
let l:buffer = bufnr(a:filename)
let l:is_current_buffer = l:buffer > 0 && l:buffer == l:current_buffer
if l:buffer > 0
let l:lines = getbufline(l:buffer, 1, '$')
else
let l:lines = readfile(a:filename, 'b')
endif
if l:is_current_buffer
let l:pos = getpos('.')[1:2]
else
let l:pos = [1, 1]
endif
" We have to keep track of how many lines we have added, and offset
" changes accordingly.
let l:line_offset = 0
let l:column_offset = 0
let l:last_end_line = 0
for l:code_edit in a:changes
if l:code_edit.start.line isnot l:last_end_line
let l:column_offset = 0
endif
let l:line = l:code_edit.start.line + l:line_offset
let l:column = l:code_edit.start.offset + l:column_offset
let l:end_line = l:code_edit.end.line + l:line_offset
let l:end_column = l:code_edit.end.offset + l:column_offset
let l:text = l:code_edit.newText
let l:cur_line = l:pos[0]
let l:cur_column = l:pos[1]
let l:last_end_line = l:end_line
" Adjust the ends according to previous edits.
if l:end_line > len(l:lines)
let l:end_line_len = 0
else
let l:end_line_len = len(l:lines[l:end_line - 1])
endif
let l:insertions = split(l:text, '\n', 1)
if l:line is 1
" Same logic as for column below. Vimscript's slice [:-1] will not
" be an empty list.
let l:start = []
else
let l:start = l:lines[: l:line - 2]
endif
if l:column is 1
" We need to handle column 1 specially, because we can't slice an
" empty string ending on index 0.
let l:middle = [l:insertions[0]]
else
let l:middle = [l:lines[l:line - 1][: l:column - 2] . l:insertions[0]]
endif
call extend(l:middle, l:insertions[1:])
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
let l:lines_before_change = len(l:lines)
let l:lines = l:start + l:middle + l:lines[l:end_line :]
let l:current_line_offset = len(l:lines) - l:lines_before_change
let l:line_offset += l:current_line_offset
let l:column_offset = len(l:middle[-1]) - l:end_line_len
let l:pos = s:UpdateCursor(l:pos,
\ [l:line, l:column],
\ [l:end_line, l:end_column],
\ [l:current_line_offset, l:column_offset])
endfor
if l:lines[-1] is# ''
call remove(l:lines, -1)
endif
call ale#util#Writefile(l:buffer, l:lines, a:filename)
if l:is_current_buffer
call ale#util#Execute(':e!')
call setpos('.', [0, l:pos[0], l:pos[1], 0])
endif
endfunction
function! s:UpdateCursor(cursor, start, end, offset) abort
let l:cur_line = a:cursor[0]
let l:cur_column = a:cursor[1]
let l:line = a:start[0]
let l:column = a:start[1]
let l:end_line = a:end[0]
let l:end_column = a:end[1]
let l:line_offset = a:offset[0]
let l:column_offset = a:offset[1]
if l:end_line < l:cur_line
" both start and end lines are before the cursor. only line offset
" needs to be updated
let l:cur_line += l:line_offset
elseif l:end_line == l:cur_line
" end line is at the same location as cursor, which means
" l:line <= l:cur_line
if l:line < l:cur_line || l:column <= l:cur_column
" updates are happening either before or around the cursor
if l:end_column < l:cur_column
" updates are happening before the cursor, update the
" column offset for cursor
let l:cur_line += l:line_offset
let l:cur_column += l:column_offset
else
" updates are happening around the cursor, move the cursor
" to the end of the changes
let l:cur_line += l:line_offset
let l:cur_column = l:end_column + l:column_offset
endif
" else is not necessary, it means modifications are happening
" after the cursor so no cursor updates need to be done
endif
else
" end line is after the cursor
if l:line < l:cur_line || l:line == l:cur_line && l:column <= l:cur_column
" changes are happening around the cursor, move the cursor
" to the end of the changes
let l:cur_line = l:end_line + l:line_offset
let l:cur_column = l:end_column + l:column_offset
" else is not necesary, it means modifications are happening
" after the cursor so no cursor updates need to be done
endif
endif
return [l:cur_line, l:cur_column]
endfunction

View File

@@ -15,7 +15,6 @@ onoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
let g:ale_completion_tsserver_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0)
let s:timer_id = -1
let s:last_done_pos = []
@@ -53,7 +52,6 @@ let s:should_complete_map = {
\ 'lisp': s:lisp_regex,
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$',
\ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$',
\ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$',
\}
" Regular expressions for finding the start column to replace with completion.
@@ -61,13 +59,11 @@ let s:omni_start_map = {
\ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
\}
" A map of exact characters for triggering LSP completions. Do not forget to
" update self.input_patterns in ale.py in updating entries in this map.
" A map of exact characters for triggering LSP completions.
let s:trigger_character_map = {
\ '<default>': ['.'],
\ 'typescript': ['.', '''', '"'],
\ 'rust': ['.', '::'],
\ 'cpp': ['.', '::', '->'],
\}
function! s:GetFiletypeValue(map, filetype) abort
@@ -163,20 +159,18 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
endfunction
function! s:ReplaceCompletionOptions() abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
if l:source is# 'ale-automatic'
let &l:omnifunc = 'ale#completion#OmniFunc'
let l:info = get(b:, 'ale_completion_info', {})
if !get(l:info, 'manual')
if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt
endif
@@ -205,77 +199,47 @@ function! ale#completion#RestoreCompletionOptions() abort
endif
endfunction
function! ale#completion#GetCompletionPosition() abort
if !exists('b:ale_completion_info')
return 0
endif
let l:line = b:ale_completion_info.line
let l:column = b:ale_completion_info.column
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
let l:up_to_column = getline(l:line)[: l:column - 2]
let l:match = matchstr(l:up_to_column, l:regex)
return l:column - len(l:match) - 1
endfunction
function! ale#completion#GetCompletionPositionForDeoplete(input) abort
return match(a:input, '\k*$')
endfunction
function! ale#completion#GetCompletionResult() abort
if exists('b:ale_completion_result')
return b:ale_completion_result
endif
return v:null
endfunction
function! ale#completion#AutomaticOmniFunc(findstart, base) abort
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
return ale#completion#GetCompletionPosition()
let l:line = b:ale_completion_info.line
let l:column = b:ale_completion_info.column
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
let l:up_to_column = getline(l:line)[: l:column - 2]
let l:match = matchstr(l:up_to_column, l:regex)
return l:column - len(l:match) - 1
else
let l:result = ale#completion#GetCompletionResult()
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
call s:ReplaceCompletionOptions()
return l:result isnot v:null ? l:result : []
return get(b:, 'ale_completion_result', [])
endif
endfunction
function! ale#completion#Show(result) abort
function! ale#completion#Show(response, completion_parser) abort
if ale#util#Mode() isnot# 'i'
return
endif
" Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion.
let b:ale_completion_result = a:result
" Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result)
return
endif
let b:ale_completion_response = a:response
let b:ale_completion_parser = a:completion_parser
" Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions()
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call timer_start(
\ 0,
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}
\)
endif
if l:source is# 'ale-callback'
call b:CompleteCallback(b:ale_completion_result)
endif
endfunction
function! ale#completion#GetAllTriggers() abort
return deepcopy(s:trigger_character_map)
call timer_start(0, {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")})
endfunction
function! s:CompletionStillValid(request_id) abort
@@ -285,22 +249,14 @@ function! s:CompletionStillValid(request_id) abort
\&& has_key(b:, 'ale_completion_info')
\&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line
\&& (
\ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'deoplete'
\ || b:ale_completion_info.source is# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback'
\)
\&& b:ale_completion_info.column == l:column
endfunction
function! ale#completion#ParseTSServerCompletions(response) abort
let l:names = []
for l:suggestion in a:response.body
call add(l:names, {
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''),
\})
call add(l:names, l:suggestion.name)
endfor
return l:names
@@ -314,10 +270,6 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
for l:suggestion in a:response.body
let l:displayParts = []
for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ')
endfor
for l:part in l:suggestion.displayParts
call add(l:displayParts, l:part.text)
endfor
@@ -338,22 +290,13 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
endif
" See :help complete-items
let l:result = {
call add(l:results, {
\ 'word': l:suggestion.name,
\ 'kind': l:kind,
\ 'icase': 1,
\ 'menu': join(l:displayParts, ''),
\ 'dup': g:ale_completion_tsserver_autoimport,
\ 'info': join(l:documentationParts, ''),
\}
if has_key(l:suggestion, 'codeActions')
let l:result.user_data = json_encode({
\ 'codeActions': l:suggestion.codeActions,
\ })
endif
call add(l:results, l:result)
\})
endfor
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
@@ -362,12 +305,12 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:names_with_details = map(copy(l:results), 'v:val.word')
let l:missing_names = filter(
\ copy(l:names),
\ 'index(l:names_with_details, v:val.word) < 0',
\ 'index(l:names_with_details, v:val) < 0',
\)
for l:name in l:missing_names
call add(l:results, {
\ 'word': l:name.word,
\ 'word': l:name,
\ 'kind': 'v',
\ 'icase': 1,
\ 'menu': '',
@@ -413,8 +356,6 @@ function! ale#completion#ParseLSPCompletions(response) abort
if get(l:item, 'insertTextFormat') is s:LSP_INSERT_TEXT_FORMAT_PLAIN
\&& type(get(l:item, 'textEdit')) is v:t_dict
let l:text = l:item.textEdit.newText
elseif type(get(l:item, 'insertText')) is v:t_string
let l:text = l:item.insertText
else
let l:text = l:item.label
endif
@@ -489,28 +430,20 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
if !empty(l:names)
let l:identifiers = []
for l:name in l:names
call add(l:identifiers, {
\ 'name': l:name.word,
\ 'source': get(l:name, 'source', ''),
\})
endfor
let b:ale_completion_info.request_id = ale#lsp#Send(
\ b:ale_completion_info.conn_id,
\ ale#lsp#tsserver_message#CompletionEntryDetails(
\ l:buffer,
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ l:identifiers,
\ l:names,
\ ),
\)
endif
elseif l:command is# 'completionEntryDetails'
call ale#completion#Show(
\ ale#completion#ParseTSServerCompletionEntryDetails(a:response),
\ a:response,
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
\)
endif
endfunction
@@ -522,7 +455,8 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
endif
call ale#completion#Show(
\ ale#completion#ParseLSPCompletions(a:response),
\ a:response,
\ 'ale#completion#ParseLSPCompletions',
\)
endfunction
@@ -551,7 +485,6 @@ function! s:OnReady(linter, lsp_details) abort
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ b:ale_completion_info.prefix,
\ g:ale_completion_tsserver_autoimport,
\)
else
" Send a message saying the buffer has changed first, otherwise
@@ -564,7 +497,10 @@ function! s:OnReady(linter, lsp_details) abort
let l:message = ale#lsp#message#Completion(
\ l:buffer,
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ min([
\ b:ale_completion_info.line_length,
\ b:ale_completion_info.column,
\ ]) + 1,
\ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
\)
endif
@@ -581,41 +517,15 @@ function! s:OnReady(linter, lsp_details) abort
endif
endfunction
" This function can be called to check if ALE can provide completion data for
" the current buffer. 1 will be returned if there's a potential source of
" completion data ALE can use, and 0 will be returned otherwise.
function! ale#completion#CanProvideCompletions() abort
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
return 1
endif
endfor
return 0
endfunction
" This function can be used to manually trigger autocomplete, even when
" g:ale_completion_enabled is set to false
function! ale#completion#GetCompletions(...) abort
let l:source = get(a:000, 0, '')
let l:options = get(a:000, 1, {})
if len(a:000) > 2
throw 'Too many arguments!'
endif
let l:CompleteCallback = get(l:options, 'callback', v:null)
if l:CompleteCallback isnot v:null
let b:CompleteCallback = l:CompleteCallback
endif
function! ale#completion#GetCompletions(manual) abort
let [l:line, l:column] = getpos('.')[1:2]
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if l:source is# 'ale-automatic' && empty(l:prefix)
return 0
if !a:manual && empty(l:prefix)
return
endif
let l:line_length = len(getline('.'))
@@ -627,51 +537,21 @@ function! ale#completion#GetCompletions(...) abort
\ 'prefix': l:prefix,
\ 'conn_id': 0,
\ 'request_id': 0,
\ 'source': l:source,
\ 'manual': a:manual,
\}
unlet! b:ale_completion_result
let l:buffer = bufnr('')
let l:Callback = function('s:OnReady')
let l:started = 0
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
let l:started = 1
endif
call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif
endfor
return l:started
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc')
if !l:started
" This is the special value for cancelling completions silently.
" See :help complete-functions
return -3
endif
return ale#completion#GetCompletionPosition()
else
let l:result = ale#completion#GetCompletionResult()
while l:result is v:null && !complete_check()
sleep 2ms
let l:result = ale#completion#GetCompletionResult()
endwhile
return l:result isnot v:null ? l:result : []
endif
endfunction
function! s:TimerHandler(...) abort
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
if !g:ale_completion_enabled
return
endif
@@ -682,7 +562,7 @@ function! s:TimerHandler(...) abort
" When running the timer callback, we have to be sure that the cursor
" hasn't moved from where it was when we requested completions by typing.
if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i'
call ale#completion#GetCompletions('ale-automatic')
call ale#completion#GetCompletions(0)
endif
endfunction
@@ -696,7 +576,7 @@ function! ale#completion#StopTimer() abort
endfunction
function! ale#completion#Queue() abort
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
if !g:ale_completion_enabled
return
endif
@@ -719,30 +599,6 @@ function! ale#completion#Queue() abort
let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler'))
endfunction
function! ale#completion#HandleUserData(completed_item) abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source isnot# 'ale-automatic' && l:source isnot# 'ale-manual'
return
endif
let l:user_data_json = get(a:completed_item, 'user_data', '')
if empty(l:user_data_json)
return
endif
let l:user_data = json_decode(l:user_data_json)
if type(l:user_data) isnot v:t_dict
return
endif
for l:code_action in get(l:user_data, 'codeActions', [])
call ale#code_action#HandleCodeAction(l:code_action)
endfor
endfunction
function! ale#completion#Done() abort
silent! pclose
@@ -751,10 +607,6 @@ function! ale#completion#Done() abort
let s:last_done_pos = getpos('.')[1:2]
endfunction
augroup ALECompletionActions
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END
function! s:Setup(enabled) abort
augroup ALECompletionGroup
autocmd!

View File

@@ -50,7 +50,6 @@ let s:global_variable_list = [
\ 'ale_sign_style_error',
\ 'ale_sign_style_warning',
\ 'ale_sign_warning',
\ 'ale_sign_highlight_linenrs',
\ 'ale_statusline_format',
\ 'ale_type_map',
\ 'ale_use_global_executables',
@@ -63,7 +62,7 @@ function! s:Echo(message) abort
execute 'echo a:message'
endfunction
function! s:GetLinterVariables(filetype, exclude_linter_names) abort
function! s:GetLinterVariables(filetype, linter_names) abort
let l:variable_list = []
let l:filetype_parts = split(a:filetype, '\.')
@@ -74,7 +73,7 @@ function! s:GetLinterVariables(filetype, exclude_linter_names) abort
" Include matching variables.
if !empty(l:match)
\&& index(l:filetype_parts, l:match[1]) >= 0
\&& index(a:exclude_linter_names, l:match[2]) == -1
\&& index(a:linter_names, l:match[2]) >= 0
call add(l:variable_list, l:key)
endif
endfor
@@ -212,11 +211,10 @@ function! ale#debugging#Info() abort
let l:all_names = map(copy(l:all_linters), 'v:val[''name'']')
let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']')
let l:exclude_names = filter(copy(l:all_names), 'index(l:enabled_names, v:val) == -1')
" Load linter variables to display
" This must be done after linters are loaded.
let l:variable_list = s:GetLinterVariables(l:filetype, l:exclude_names)
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names)
let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype)
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
@@ -240,12 +238,6 @@ function! ale#debugging#Info() abort
endfunction
function! ale#debugging#InfoToClipboard() abort
if !has('clipboard')
call s:Echo('clipboard not available. Try :ALEInfoToFile instead.')
return
endif
redir => l:output
silent call ale#debugging#Info()
redir END

View File

@@ -3,9 +3,6 @@
let s:go_to_definition_map = {}
" Enable automatic updates of the tagstack
let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', 1)
" Used to get the definition map in tests.
function! ale#definition#GetMap() abort
return deepcopy(s:go_to_definition_map)
@@ -20,20 +17,6 @@ function! ale#definition#ClearLSPData() abort
let s:go_to_definition_map = {}
endfunction
function! ale#definition#UpdateTagStack() abort
let l:should_update_tagstack = exists('*gettagstack') && exists('*settagstack') && g:ale_update_tagstack
if l:should_update_tagstack
" Grab the old location (to jump back to) and the word under the
" cursor (as a label for the tagstack)
let l:old_location = [bufnr('%'), line('.'), col('.'), 0]
let l:tagname = expand('<cword>')
let l:winid = win_getid()
call settagstack(l:winid, {'items': [{'from': l:old_location, 'tagname': l:tagname}]}, 'a')
call settagstack(l:winid, {'curidx': len(gettagstack(l:winid)['items']) + 1})
endif
endfunction
function! ale#definition#HandleTSServerResponse(conn_id, response) abort
if get(a:response, 'command', '') is# 'definition'
\&& has_key(s:go_to_definition_map, a:response.request_seq)
@@ -44,7 +27,6 @@ function! ale#definition#HandleTSServerResponse(conn_id, response) abort
let l:line = a:response.body[0].start.line
let l:column = a:response.body[0].start.offset
call ale#definition#UpdateTagStack()
call ale#util#Open(l:filename, l:line, l:column, l:options)
endif
endif
@@ -69,7 +51,6 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
let l:line = l:item.range.start.line + 1
let l:column = l:item.range.start.character + 1
call ale#definition#UpdateTagStack()
call ale#util#Open(l:filename, l:line, l:column, l:options)
break
endfor

View File

@@ -710,10 +710,6 @@ function! ale#engine#Cleanup(buffer) abort
return
endif
if exists('*ale#lsp#CloseDocument')
call ale#lsp#CloseDocument(a:buffer)
endif
if !has_key(g:ale_buffer_info, a:buffer)
return
endif

View File

@@ -128,7 +128,7 @@ function! ale#events#Init() abort
endif
if g:ale_lint_on_insert_leave
autocmd InsertLeave * if ale#Var(str2nr(expand('<abuf>')), 'lint_on_insert_leave') | call ale#Queue(0) | endif
autocmd InsertLeave * call ale#Queue(0)
endif
if g:ale_echo_cursor || g:ale_cursor_detail

View File

@@ -1,61 +1,45 @@
call ale#Set('fix_on_save_ignore', {})
" Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers.
function! ale#fix#ApplyQueuedFixes(buffer) abort
let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0})
let l:has_bufline_api = exists('*deletebufline') && exists('*setbufline')
function! ale#fix#ApplyQueuedFixes() abort
let l:buffer = bufnr('')
let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0})
if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr(''))
if !l:data.done
return
endif
call remove(g:ale_fix_buffer_data, a:buffer)
call remove(g:ale_fix_buffer_data, l:buffer)
if l:data.changes_made
let l:start_line = len(l:data.output) + 1
let l:end_line = len(l:data.lines_before)
if l:end_line >= l:start_line
let l:save = winsaveview()
silent execute l:start_line . ',' . l:end_line . 'd_'
call winrestview(l:save)
endif
" If the file is in DOS mode, we have to remove carriage returns from
" the ends of lines before calling setline(), or we will see them
" twice.
let l:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos'
\ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
\ : l:data.output
let l:first_line_to_remove = len(l:new_lines) + 1
" Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines)
call deletebufline(a:buffer, l:first_line_to_remove, '$')
" Fall back on setting lines the old way, for the current buffer.
else
let l:old_line_length = len(l:data.lines_before)
if l:old_line_length >= l:first_line_to_remove
let l:save = winsaveview()
silent execute
\ l:first_line_to_remove . ',' . l:old_line_length . 'd_'
call winrestview(l:save)
endif
call setline(1, l:new_lines)
endif
call setline(1, l:lines_to_set)
if l:data.should_save
if a:buffer is bufnr('')
if empty(&buftype)
noautocmd :w!
else
set nomodified
endif
if empty(&buftype)
noautocmd :w!
else
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
set nomodified
endif
endif
endif
if l:data.should_save
let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
\ && ale#Var(a:buffer, 'lint_on_save')
let l:should_lint = g:ale_fix_on_save
else
let l:should_lint = l:data.changes_made
endif
@@ -66,7 +50,7 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort
" fixing problems.
if g:ale_enabled
\&& l:should_lint
\&& !ale#events#QuitRecently(a:buffer)
\&& !ale#events#QuitRecently(l:buffer)
call ale#Queue(0, l:data.should_save ? 'lint_file' : '')
endif
endfunction
@@ -74,7 +58,7 @@ endfunction
function! ale#fix#ApplyFixes(buffer, output) abort
let l:data = g:ale_fix_buffer_data[a:buffer]
let l:data.output = a:output
let l:data.changes_made = l:data.lines_before !=# l:data.output " no-custom-checks
let l:data.changes_made = l:data.lines_before != l:data.output
let l:data.done = 1
call ale#command#RemoveManagedFiles(a:buffer)
@@ -97,7 +81,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
" We can only change the lines of a buffer which is currently open,
" so try and apply the fixes to the current buffer.
call ale#fix#ApplyQueuedFixes(a:buffer)
call ale#fix#ApplyQueuedFixes()
endfunction
function! s:HandleExit(job_info, buffer, job_output, data) abort
@@ -281,21 +265,7 @@ function! s:AddSubCallbacks(full_list, callbacks) abort
return 1
endfunction
function! s:IgnoreFixers(callback_list, filetype, config) abort
if type(a:config) is v:t_list
let l:ignore_list = a:config
else
let l:ignore_list = []
for l:part in split(a:filetype , '\.')
call extend(l:ignore_list, get(a:config, l:part, []))
endfor
endif
call filter(a:callback_list, 'index(l:ignore_list, v:val) < 0')
endfunction
function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
function! s:GetCallbacks(buffer, fixers) abort
if len(a:fixers)
let l:callback_list = a:fixers
elseif type(get(b:, 'ale_fixers')) is v:t_list
@@ -320,12 +290,8 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
endif
endif
if a:fixing_flag is# 'save_file'
let l:config = ale#Var(a:buffer, 'fix_on_save_ignore')
if !empty(l:config)
call s:IgnoreFixers(l:callback_list, &filetype, l:config)
endif
if empty(l:callback_list)
return []
endif
let l:corrected_list = []
@@ -373,7 +339,7 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort
endif
try
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
let l:callback_list = s:GetCallbacks(a:buffer, a:000)
catch /E700\|BADNAME/
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(
@@ -413,4 +379,5 @@ endfunction
" Set up an autocmd command to try and apply buffer fixes when available.
augroup ALEBufferFixGroup
autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
autocmd BufEnter * call ale#fix#ApplyQueuedFixes()
augroup END

View File

@@ -27,16 +27,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with black.',
\ },
\ 'dfmt': {
\ 'function': 'ale#fixers#dfmt#Fix',
\ 'suggested_filetypes': ['d'],
\ 'description': 'Fix D files with dfmt.',
\ },
\ 'fecs': {
\ 'function': 'ale#fixers#fecs#Fix',
\ 'suggested_filetypes': ['javascript', 'css', 'html'],
\ 'description': 'Apply fecs format to a file.',
\ },
\ 'tidy': {
\ 'function': 'ale#fixers#tidy#Fix',
\ 'suggested_filetypes': ['html'],
@@ -120,11 +110,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['scala'],
\ 'description': 'Fix Scala files using scalafmt',
\ },
\ 'sorbet': {
\ 'function': 'ale#fixers#sorbet#Fix',
\ 'suggested_filetypes': ['ruby'],
\ 'description': 'Fix ruby files with srb tc --autocorrect.',
\ },
\ 'standard': {
\ 'function': 'ale#fixers#standard#Fix',
\ 'suggested_filetypes': ['javascript'],
@@ -155,11 +140,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with php-cs-fixer.',
\ },
\ 'clangtidy': {
\ 'function': 'ale#fixers#clangtidy#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'objc'],
\ 'description': 'Fix C/C++ and ObjectiveC files with clang-tidy.',
\ },
\ 'clang-format': {
\ 'function': 'ale#fixers#clangformat#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'cuda'],
@@ -205,11 +185,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['hack'],
\ 'description': 'Fix Hack files with hackfmt.',
\ },
\ 'floskell': {
\ 'function': 'ale#fixers#floskell#Fix',
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with floskell.',
\ },
\ 'hfmt': {
\ 'function': 'ale#fixers#hfmt#Fix',
\ 'suggested_filetypes': ['haskell'],
@@ -220,11 +195,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with brittany.',
\ },
\ 'hindent': {
\ 'function': 'ale#fixers#hindent#Fix',
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with hindent.',
\ },
\ 'hlint': {
\ 'function': 'ale#fixers#hlint#Fix',
\ 'suggested_filetypes': ['haskell'],
@@ -240,11 +210,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['ocaml'],
\ 'description': 'Fix OCaml files with ocamlformat.',
\ },
\ 'ocp-indent': {
\ 'function': 'ale#fixers#ocp_indent#Fix',
\ 'suggested_filetypes': ['ocaml'],
\ 'description': 'Fix OCaml files with ocp-indent.',
\ },
\ 'refmt': {
\ 'function': 'ale#fixers#refmt#Fix',
\ 'suggested_filetypes': ['reason'],
@@ -260,11 +225,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['sql'],
\ 'description': 'Fix SQL files with sqlfmt.',
\ },
\ 'sqlformat': {
\ 'function': 'ale#fixers#sqlformat#Fix',
\ 'suggested_filetypes': ['sql'],
\ 'description': 'Fix SQL files with sqlformat.',
\ },
\ 'google_java_format': {
\ 'function': 'ale#fixers#google_java_format#Fix',
\ 'suggested_filetypes': ['java'],
@@ -287,8 +247,8 @@ let s:default_registry = {
\ },
\ 'xo': {
\ 'function': 'ale#fixers#xo#Fix',
\ 'suggested_filetypes': ['javascript', 'typescript'],
\ 'description': 'Fix JavaScript/TypeScript files using xo --fix.',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Fix JavaScript files using xo --fix.',
\ },
\ 'qmlfmt': {
\ 'function': 'ale#fixers#qmlfmt#Fix',
@@ -320,36 +280,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['kt'],
\ 'description': 'Fix Kotlin files with ktlint.',
\ },
\ 'styler': {
\ 'function': 'ale#fixers#styler#Fix',
\ 'suggested_filetypes': ['r', 'rmarkdown', 'rmd'],
\ 'description': 'Fix R files with styler.',
\ },
\ 'latexindent': {
\ 'function': 'ale#fixers#latexindent#Fix',
\ 'suggested_filetypes': ['tex'],
\ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.',
\ },
\ 'pgformatter': {
\ 'function': 'ale#fixers#pgformatter#Fix',
\ 'suggested_filetypes': ['sql'],
\ 'description': 'A PostgreSQL SQL syntax beautifier',
\ },
\ 'reorder-python-imports': {
\ 'function': 'ale#fixers#reorder_python_imports#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Sort Python imports with reorder-python-imports.',
\ },
\ 'gnatpp': {
\ 'function': 'ale#fixers#gnatpp#Fix',
\ 'suggested_filetypes': ['ada'],
\ 'description': 'Format Ada files with gnatpp.',
\ },
\ 'nixpkgs-fmt': {
\ 'function': 'ale#fixers#nixpkgsfmt#Fix',
\ 'suggested_filetypes': ['nix'],
\ 'description': 'A formatter for Nix code',
\ },
\}
" Reset the function registry to the default entries.

View File

@@ -29,10 +29,6 @@ function! ale#fixers#black#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_black_options')
if expand('#' . a:buffer . ':e') is? 'pyi'
let l:options .= '--pyi'
endif
return {
\ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '')

View File

@@ -13,15 +13,10 @@ function! ale#fixers#clangformat#GetExecutable(buffer) abort
endfunction
function! ale#fixers#clangformat#Fix(buffer) abort
let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
let l:filename = ale#Escape(bufname(a:buffer))
let l:options = ale#Var(a:buffer, 'c_clangformat_options')
let l:command = l:executable . ' --assume-filename=' . l:filename
if l:options isnot# ''
let l:command .= ' ' . l:options
endif
return {'command': l:command}
return {
\ 'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
\ . ' ' . l:options,
\}
endfunction

View File

@@ -1,52 +0,0 @@
scriptencoding utf-8
" Author: ObserverOfTime <chronobserver@disroot.org>
" Description: Fixing C/C++ files with clang-tidy.
function! s:set_variables() abort
let l:use_global = get(g:, 'ale_use_global_executables', 0)
for l:ft in ['c', 'cpp']
call ale#Set(l:ft . '_clangtidy_executable', 'clang-tidy')
call ale#Set(l:ft . '_clangtidy_use_global', l:use_global)
call ale#Set(l:ft . '_clangtidy_checks', [])
call ale#Set(l:ft . '_clangtidy_options', '')
call ale#Set(l:ft . '_clangtidy_extra_options', '')
call ale#Set(l:ft . '_clangtidy_fix_errors', 1)
endfor
call ale#Set('c_build_dir', '')
endfunction
call s:set_variables()
function! ale#fixers#clangtidy#Var(buffer, name) abort
let l:ft = getbufvar(str2nr(a:buffer), '&filetype')
let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c'
return ale#Var(a:buffer, l:ft . '_clangtidy_' . a:name)
endfunction
function! ale#fixers#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#fixers#clangtidy#Var(a:buffer, 'checks'), ',')
let l:extra_options = ale#fixers#clangtidy#Var(a:buffer, 'extra_options')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
let l:options = empty(l:build_dir)
\ ? ale#fixers#clangtidy#Var(a:buffer, 'options') : ''
let l:fix_errors = ale#fixers#clangtidy#Var(a:buffer, 'fix_errors')
return ' -fix' . (l:fix_errors ? ' -fix-errors' : '')
\ . (empty(l:checks) ? '' : ' -checks=' . ale#Escape(l:checks))
\ . (empty(l:extra_options) ? '' : ' ' . l:extra_options)
\ . (empty(l:build_dir) ? '' : ' -p ' . ale#Escape(l:build_dir))
\ . ' %t' . (empty(l:options) ? '' : ' -- ' . l:options)
endfunction
function! ale#fixers#clangtidy#Fix(buffer) abort
let l:executable = ale#fixers#clangtidy#Var(a:buffer, 'executable')
let l:command = ale#fixers#clangtidy#GetCommand(a:buffer)
return {
\ 'command': ale#Escape(l:executable) . l:command,
\ 'read_temporary_file': 1,
\}
endfunction

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