Compare commits

..

2 Commits

Author SHA1 Message Date
Kevin Locke
26e61fad69 eslint: Use cwd from executable location to fix nested projects (#3222)
* Split FindNearestExecutable from FindExecutable

The path searching in ale#node#FindExecutable() will be useful for
eslint.  Refactor it into a separate function so it can be used without
regard for the state of the _use_global and _executable variables.

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>

* eslint: Set project root from local executable

Using the nearest directory with node_modules does not work correctly
for nested projects where the eslint dependencies are in the outer
project.  For example:
https://github.com/dense-analysis/ale/issues/3143#issuecomment-652452362

Adopt the behavior of SublimeLinter, which runs from project_root
determined by the presence of the eslint executable in node_modules/.bin
(or eslint in dependencies/devDependencies of package.json, which we can
add later as necessary).  See [NodeLinter#find_local_executable].

[NodeLinter#find_local_executable]: https://github.com/SublimeLinter/SublimeLinter/blob/056e6f6/lint/base_linter/node_linter.py#L109

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
2020-07-08 14:49:29 +01:00
Kevin Locke
d8143885a4 Run ESLint fixer from project root, where possible (#3096)
* Split eslint#GetCdString from eslint#GetCommand

Move the code for finding the project root and building the cd string
into a separate function so that it can be reused in the eslint fixer.

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>

* Run ESLint fixer from project root dir

To match the ESLint linter, as changed in 9ee57d43 (which I forgot to
apply to the fixer, whoops).

Fixes: #3094
Closes: #3095

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
2020-07-01 17:53:33 +01:00
267 changed files with 2454 additions and 7048 deletions

View File

@@ -19,9 +19,6 @@ init:
# Stop git from changing newlines
- git config --global core.autocrlf input
# NOTE: If you change the Vim or Vader versions here, please also update the
# instructions for running tests on Windows in ale-development.txt
install:
# Download and unpack Vim
- ps: >-

17
.github/stale.yml vendored
View File

@@ -1,17 +0,0 @@
---
# This configuration closes stale PRs after 28 + 7 days.
# That's 4 weeks until stale bot complains, and a week until it closes a PR.
# Issues in ALE are never, ever stale. They are either resolved or not.
only: pulls
daysUntilStale: 28
daysUntilClose: 7
exemptLabels: []
staleLabel: stale
markComment: >
This pull request has been automatically marked as stale because it has not
been updated recently. Make sure to write tests and document your changes.
See `:help ale-dev` for information on writing tests.
If your pull request is good to merge, bother w0rp or another maintainer
again, and get them to merge it.
closeComment: false

5
.gitignore vendored
View File

@@ -1,12 +1,11 @@
!.editorconfig
*.obj
*.pyc
# Ignore all hidden files everywhere.
# Use `git add -f` to add hidden files.
.*
__pycache__
*.pyc
/doc/tags
/init.vim
/test/ale-info-test-file
/vader_output
__pycache__
tags

View File

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

155
README.md
View File

@@ -61,25 +61,23 @@ other content at [w0rp.com](https://w0rp.com).
4. [Contributing](#contributing)
5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters)
2. [How can I see what ALE has configured for the current file?](#faq-get-info)
3. [How can I use ALE and coc.nvim together?](#faq-coc-nvim)
4. [How can I keep the sign gutter open?](#faq-keep-signs)
5. [How can I change the signs ALE uses?](#faq-change-signs)
6. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
7. [How can I show errors or warnings in my statusline?](#faq-statusline)
8. [How can I show errors or warnings in my lightline?](#faq-lightline)
9. [How can I change the format for echo messages?](#faq-echo-format)
10. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
11. [How can I navigate between errors quickly?](#faq-navigation)
12. [How can I run linters only when I save files?](#faq-lint-on-save)
13. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
14. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
15. [How can I check Vue files with ESLint?](#faq-vue-eslint)
16. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
17. [How can I configure my C or C++ project?](#faq-c-configuration)
18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
2. [How can I keep the sign gutter open?](#faq-keep-signs)
3. [How can I change the signs ALE uses?](#faq-change-signs)
4. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
5. [How can I show errors or warnings in my statusline?](#faq-statusline)
6. [How can I show errors or warnings in my lightline?](#faq-lightline)
7. [How can I change the format for echo messages?](#faq-echo-format)
8. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
9. [How can I navigate between errors quickly?](#faq-navigation)
10. [How can I run linters only when I save files?](#faq-lint-on-save)
11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
13. [How can I check Vue files with ESLint?](#faq-vue-eslint)
14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
15. [How can I configure my C or C++ project?](#faq-c-configuration)
16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
18. [How can I see what ALE has configured for the current file?](#faq-get-info)
<a name="supported-languages"></a>
@@ -104,7 +102,7 @@ programs for checking the syntax and semantics of your programs. By default,
linters will be re-run in the background to check your syntax when you open
new buffers or as you make edits to your files.
The behavior of linting can be configured with a variety of options,
The behaviour of linting can be configured with a variety of options,
documented in [the Vim help file](doc/ale.txt). For more information on the
options ALE offers, consult `:help ale-options` for global options and `:help
ale-integration-options` for options specified to particular linters.
@@ -195,11 +193,12 @@ completion manually with `<C-x><C-o>`.
set omnifunc=ale#completion#OmniFunc
```
ALE supports automatic imports from external modules. This behavior is disabled
by default and can be enabled by setting:
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_autoimport = 1
let g:ale_completion_tsserver_autoimport = 1
```
See `:help ale-completion` for more information.
@@ -232,9 +231,6 @@ ALE supports "hover" information for printing brief information about symbols at
the cursor taken from Language Server Protocol linters and `tsserver` with the
`ALEHover` command.
Truncated information will be displayed when the cursor rests on a symbol by
default, as long as there are no problems on the same line.
The information can be displayed in a `balloon` tooltip in Vim or GVim by
hovering your mouse over symbols. Mouse hovering is enabled by default in GVim,
and needs to be configured for Vim 8.1+ in terminals.
@@ -417,56 +413,9 @@ This plugin will look for linters in the [`ale_linters`](ale_linters) directory.
Each directory within corresponds to a particular filetype in Vim, and each file
in each directory corresponds to the name of a particular linter.
<a name="faq-get-info"></a>
### 5.ii. How can I see what ALE has configured for the current file?
Run the following to see what is currently configured:
```vim
:ALEInfo
```
<a name="faq-coc-nvim"></a>
### 5.iii. How can I use ALE and coc.nvim together?
[coc.nvim](https://github.com/neoclide/coc.nvim) is a popular Vim plugin written
in TypeScript and dependent on the [npm](https://www.npmjs.com/) ecosystem for
providing full IDE features to Vim. Both ALE and coc.nvim implement
[Language Server Protocol](https://microsoft.github.io/language-server-protocol/)
(LSP) clients for supporting diagnostics (linting with a live server), and other
features like auto-completion, and others listed above.
ALE is primarily focused on integrating with external programs through virtually
any means, provided the plugin remains almost entirely written in Vim script.
coc.nvim is primarily focused on bringing IDE features to Vim. If you want to
run external programs on your files to check for errors, and also use the most
advanced IDE features, you might want to use both plugins at the same time.
The easiest way to get both plugins to work together is to configure coc.nvim to
send diagnostics to ALE, so ALE controls how all problems are presented to you,
and to disable all LSP features in ALE, so ALE doesn't try to provide LSP
features already provided by coc.nvim, such as auto-completion.
1. Open your coc.nvim configuration file with `:CocConfig` and add
`"diagnostic.displayByAle": true` to your settings.
2. Add `let g:ale_disable_lsp = 1` to your vimrc file, before plugins are
loaded.
You can also use `b:ale_disable_lsp` in your ftplugin files to enable or disable
LSP features in ALE for different filetypes. After you configure coc.nvim and
ALE this way, you can further configure how problems appear to you by using all
of the settings mentioned in ALE's help file, including how often diagnostics
are requested. See `:help ale-lint`.
The integration between ALE and coc.nvim works using an API ALE offers for
letting any other plugin integrate with ALE. If you are interested in writing a
similar integration, see `:help ale-lint-other-sources`.
<a name="faq-keep-signs"></a>
### 5.iv. How can I keep the sign gutter open?
### 5.ii. How can I keep the sign gutter open?
You can keep the sign gutter open at all times by setting the
`g:ale_sign_column_always` to 1
@@ -477,7 +426,7 @@ let g:ale_sign_column_always = 1
<a name="faq-change-signs"></a>
### 5.v. How can I change the signs ALE uses?
### 5.iii. How can I change the signs ALE uses?
Use these options to specify what text should be used for signs:
@@ -497,7 +446,7 @@ highlight clear ALEWarningSign
<a name="faq-change-highlights"></a>
### 5.vi. How can I change or disable the highlights ALE uses?
### 5.iv. How can I change or disable the highlights ALE uses?
ALE's highlights problems with highlight groups which link to `SpellBad`,
`SpellCap`, `error`, and `todo` groups by default. The characters that are
@@ -523,7 +472,7 @@ See `:help ale-highlights` for more information.
<a name="faq-statusline"></a>
### 5.vii. How can I show errors or warnings in my statusline?
### 5.v. How can I show errors or warnings in my statusline?
[vim-airline](https://github.com/vim-airline/vim-airline) integrates with ALE
for displaying error information in the status bar. If you want to see the
@@ -572,7 +521,7 @@ for more information.
<a name="faq-lightline"></a>
### 5.viii. How can I show errors or warnings in my lightline?
### 5.vi. How can I show errors or warnings in my lightline?
[lightline](https://github.com/itchyny/lightline.vim) does not have built-in
support for ALE, nevertheless there is a plugin that adds this functionality: [maximbaz/lightline-ale](https://github.com/maximbaz/lightline-ale).
@@ -581,7 +530,7 @@ For more information, check out the sources of that plugin, `:help ale#statuslin
<a name="faq-echo-format"></a>
### 5.ix. How can I change the format for echo messages?
### 5.vii. How can I change the format for echo messages?
There are 3 global options that allow customizing the echoed message.
@@ -610,7 +559,7 @@ See `:help g:ale_echo_msg_format` for more information.
<a name="faq-autocmd"></a>
### 5.x. How can I execute some code when ALE starts or stops linting?
### 5.viii. How can I execute some code when ALE starts or stops linting?
ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html)
events when a lint or fix cycle are started and stopped. There is also an event
@@ -633,7 +582,7 @@ augroup END
<a name="faq-navigation"></a>
### 5.xi. How can I navigate between errors quickly?
### 5.ix. How can I navigate between errors quickly?
ALE offers some commands with `<Plug>` keybinds for moving between warnings and
errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
@@ -649,7 +598,7 @@ For more information, consult the online documentation with
<a name="faq-lint-on-save"></a>
### 5.xii. How can I run linters only when I save files?
### 5.x. How can I run linters only when I save files?
ALE offers an option `g:ale_lint_on_save` for enabling running the linters
when files are saved. This option is enabled by default. If you only
@@ -670,7 +619,7 @@ files, you can set `g:ale_lint_on_save` to `0`.
<a name="faq-quickfix"></a>
### 5.xiii. How can I use the quickfix list instead of the loclist?
### 5.xi. How can I use the quickfix list instead of the loclist?
The quickfix list can be enabled by turning the `g:ale_set_quickfix`
option on. If you wish to also disable the loclist, you can disable
@@ -700,7 +649,7 @@ instead of the default horizontally.
<a name="faq-jsx-stylelint-eslint"></a>
### 5.xiv. How can I check JSX files with both stylelint and eslint?
### 5.xii. How can I check JSX files with both stylelint and eslint?
If you configure ALE options correctly in your vimrc file, and install
the right tools, you can check JSX files with stylelint and eslint.
@@ -742,7 +691,7 @@ no linter will be run twice for the same file.
<a name="faq-vue-eslint"></a>
### 5.xv. How can I check Vue files with ESLint?
### 5.xiii. How can I check Vue files with ESLint?
To check Vue files with ESLint, your ESLint project configuration file must be
configured to use the [Vue plugin](https://github.com/vuejs/eslint-plugin-vue).
@@ -773,7 +722,7 @@ let g:ale_linters = {'vue': ['eslint', 'vls']}
<a name="faq-my-battery-is-sad"></a>
### 5.xvi. Will this plugin eat all of my laptop battery power?
### 5.xiv. Will this plugin eat all of my laptop battery power?
ALE takes advantage of the power of various tools to check your code. This of
course means that CPU time will be used to continuously check your code. If you
@@ -786,7 +735,7 @@ while you type. ALE uses a timeout which is cancelled and reset every time you
type, and this delay can be increased so linters are run less often. See
`:help g:ale_lint_delay` for more information.
If you don't wish to run linters while you type, you can disable that behavior.
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.
@@ -797,7 +746,7 @@ including the option `g:ale_lint_on_enter`, and you can run ALE manually with
<a name="faq-c-configuration"></a>
### 5.xvii. How can I configure my C or C++ project?
### 5.xv. How can I configure my C or C++ project?
The structure of C and C++ projects varies wildly from project to project, with
many different build tools being used for building them, and many different
@@ -817,24 +766,13 @@ setting. Consult the documentation for that setting for more information.
`b:ale_linters` can be used to select which tools you want to run, say if you
want to use only `gcc` for one project, and only `clang` for another.
ALE will attempt to parse `compile_commands.json` files to discover compiler
flags to use when linting code. See `:help g:ale_c_parse_compile_commands` for
more information. See Clang's documentation for
[compile_commands.json files](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
You should strongly consider generating them in your builds, which is easy to do
with CMake.
You can also configure ALE to automatically run `make -n` to run dry runs on
`Makefile`s to discover compiler flags. This can execute arbitrary code, so the
option is disabled by default. See `:help g:ale_c_parse_makefile`.
You may also configure buffer-local settings for linters with project-specific
vimrc files. [local_vimrc](https://github.com/LucHermitte/local_vimrc) can be
used for executing local vimrc files which can be shared in your project.
<a name="faq-buffer-configuration"></a>
### 5.xviii. How can I configure ALE differently for different buffers?
### 5.xvi. How can I configure ALE differently for different buffers?
ALE offers various ways to configure which linters or fixers are run, and
other settings. For the majority of ALE's settings, they can either be
@@ -870,7 +808,7 @@ Buffer-local variables for settings always override the global settings.
<a name="faq-list-window-height"></a>
### 5.xix. How can I configure the height of the list in which ALE displays errors?
### 5.xvii. How can I configure the height of the list in which ALE displays errors?
To set a default height for the error list, use the `g:ale_list_window_size` variable.
@@ -879,13 +817,12 @@ To set a default height for the error list, use the `g:ale_list_window_size` var
let g:ale_list_window_size = 5
```
<a name="faq-vm"></a>
<a name="faq-get-info"></a>
### 5.xx. How can I run linters or fixers via Docker or a VM?
### 5.xviii. How can I see what ALE has configured for the current file?
ALE supports running linters or fixers via Docker, virtual machines, or in
combination with any remote machine with a different file system, so long as the
tools are well-integrated with ALE, and ALE is properly configured to run the
correct commands and map filename paths between different file systems. See
`:help ale-lint-other-machines` for the full documentation on how to configure
ALE to support this.
Run the following to see what is currently configured:
```vim
:ALEInfo
```

View File

@@ -18,7 +18,7 @@ function! ale_linters#ada#gcc#GetCommand(buffer) abort
" -gnatc: Check syntax and semantics only (no code generation attempted)
return '%e -x ada -c -gnatc'
\ . ' -o ' . ale#Escape(l:out_file)
\ . ' -I %s:h'
\ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
\ . ' %t'
endfunction

View File

@@ -1,5 +0,0 @@
" Author: Horacio Sanson (hsanson [ät] gmail.com)
" Description: languagetool for asciidoc files, copied from markdown.
call ale#handlers#languagetool#DefineLinter('asciidoc')

View File

@@ -9,7 +9,7 @@ function! ale_linters#asm#gcc#GetCommand(buffer) abort
" -fsyntax-only doesn't catch everything.
return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file
\ . '-iquote %s:h'
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction

View File

@@ -1,53 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A C compiler linter for C files with gcc/clang, etc.
call ale#Set('c_cc_executable', '<auto>')
call ale#Set('c_cc_options', '-std=c11 -Wall')
function! ale_linters#c#cc#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'c_cc_executable')
" Default to either clang or gcc.
if l:executable is# '<auto>'
if ale#engine#IsExecutable(a:buffer, 'clang')
let l:executable = 'clang'
else
let l:executable = 'gcc'
endif
endif
return l:executable
endfunction
function! ale_linters#c#cc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:ale_flags = ale#Var(a:buffer, 'c_cc_options')
if l:cflags =~# '-std='
let l:ale_flags = substitute(
\ l:ale_flags,
\ '-std=\(c\|gnu\)[0-9]\{2\}',
\ '',
\ 'g')
endif
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote %s:h'
\ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'cc',
\ 'aliases': ['gcc', 'clang'],
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#c#cc#GetExecutable'),
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#cc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -3,7 +3,6 @@
call ale#Set('c_ccls_executable', 'ccls')
call ale#Set('c_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('c', {
\ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('c', {
\ 'executable': {b -> ale#Var(b, 'c_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'c_ccls_init_options')},
\ 'initialization_options': {b -> ale#Var(b, 'c_ccls_init_options')},
\})

24
ale_linters/c/clang.vim Normal file
View File

@@ -0,0 +1,24 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: clang linter for c files
call ale#Set('c_clang_executable', 'clang')
call ale#Set('c_clang_options', '-std=c11 -Wall')
function! ale_linters#c#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return '%e -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'c_clang_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clang#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -10,11 +10,9 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : ''
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command
\ . '%e -q --language=c'
\ . l:template
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . l:buffer_path_include

28
ale_linters/c/gcc.vim Normal file
View File

@@ -0,0 +1,28 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: gcc linter for c files
call ale#Set('c_gcc_executable', 'gcc')
call ale#Set('c_gcc_options', '-std=c11 -Wall')
function! ale_linters#c#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'c_gcc_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#gcc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -1,53 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A C++ compiler linter for C++ files with gcc/clang, etc.
call ale#Set('cpp_cc_executable', '<auto>')
call ale#Set('cpp_cc_options', '-std=c++14 -Wall')
function! ale_linters#cpp#cc#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'cpp_cc_executable')
" Default to either clang++ or gcc.
if l:executable is# '<auto>'
if ale#engine#IsExecutable(a:buffer, 'clang++')
let l:executable = 'clang++'
else
let l:executable = 'gcc'
endif
endif
return l:executable
endfunction
function! ale_linters#cpp#cc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:ale_flags = ale#Var(a:buffer, 'cpp_cc_options')
if l:cflags =~# '-std='
let l:ale_flags = substitute(
\ l:ale_flags,
\ '-std=\(c\|gnu\)++[0-9]\{2\}',
\ '',
\ 'g')
endif
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote %s:h'
\ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cc',
\ 'aliases': ['gcc', 'clang', 'g++', 'clang++'],
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#cpp#cc#GetExecutable'),
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#cc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -3,7 +3,6 @@
call ale#Set('cpp_ccls_executable', 'ccls')
call ale#Set('cpp_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('cpp', {
\ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('cpp', {
\ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'cpp_ccls_init_options')},
\ 'initialization_options': {b -> ale#Var(b, 'cpp_ccls_init_options')},
\})

24
ale_linters/cpp/clang.vim Normal file
View File

@@ -0,0 +1,24 @@
" Author: Tomota Nakamura <https://github.com/tomotanakamura>
" Description: clang linter for cpp files
call ale#Set('cpp_clang_executable', 'clang++')
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return '%e -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clang#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -25,11 +25,6 @@ function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
endif
" Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file.
if expand('#' . a:buffer) =~# '\.h$'
let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
endif
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')

View File

@@ -10,11 +10,9 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : ''
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command
\ . '%e -q --language=c++'
\ . l:template
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . l:buffer_path_include

29
ale_linters/cpp/gcc.vim Normal file
View File

@@ -0,0 +1,29 @@
" Author: geam <mdelage@student.42.fr>
" Description: gcc linter for cpp files
"
call ale#Set('cpp_gcc_executable', 'gcc')
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'aliases': ['g++'],
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#gcc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View File

@@ -5,6 +5,9 @@ call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11')
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#command#ManageFile(a:buffer, l:output_file)
return '%e -cuda'
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))

View File

@@ -32,29 +32,14 @@ function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
let l:line = get(l:object, 'line', -1)
let l:message = l:object['message']
let l:link = get(l:object, 'reference_url', '')
if type(l:link) == v:t_list
" Somehow, reference_url is returned as two-part list.
" Anchor markers in that list are sometimes duplicated.
" See https://github.com/projectatomic/dockerfile_lint/issues/134
let l:link = join(l:link, '')
let l:link = substitute(l:link, '##', '#', '')
endif
let l:detail = l:message
if get(l:object, 'description', 'None') isnot# 'None'
let l:detail .= "\n\n" . l:object['description']
let l:message = l:message . '. ' . l:object['description']
endif
let l:detail .= "\n\n" . l:link
call add(l:messages, {
\ 'lnum': l:line,
\ 'text': l:message,
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
\ 'detail': l:detail,
\})
endfor
endfor

View File

@@ -46,7 +46,7 @@ function! ale_linters#elixir#credo#GetMode() abort
endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixUmbrellaRoot(a:buffer)
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root)

View File

@@ -11,7 +11,7 @@ function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin %s'
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction
function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort

View File

@@ -6,6 +6,7 @@ function! ale_linters#go#gofmt#GetCommand(buffer) abort
\ . '%e -e %t'
endfunction
call ale#linter#Define('go', {
\ 'name': 'gofmt',
\ 'output_stream': 'stderr',

View File

@@ -4,28 +4,6 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [
\ 'node_modules/.bin/ember-template-lint',
\])
endfunction
function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer, version) abort
" Reading from stdin was introduced in ember-template-lint@1.6.0
return ale#semver#GTE(a:version, [1, 6, 0])
\ ? '%e --json --filename %s'
\ : '%e --json %t'
endfunction
function! ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer),
\ '%e --version',
\ function('ale_linters#handlebars#embertemplatelint#GetCommand'),
\)
endfunction
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@@ -52,9 +30,10 @@ function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
endfunction
call ale#linter#Define('handlebars', {
\ 'name': 'embertemplatelint',
\ 'aliases': ['ember-template-lint'],
\ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'),
\ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'),
\ 'name': 'ember-template-lint',
\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [
\ 'node_modules/.bin/ember-template-lint',
\ ])},
\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\})

View File

@@ -52,7 +52,7 @@ endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config')
let l:config = l:options !~# '\v(^| )-c ' && !empty(l:config_option)
let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option)
\ ? s:GetConfig(a:buffer, l:config_option)
\ : ''

View File

@@ -20,39 +20,25 @@ endfunction
function! ale_linters#java#eclipselsp#JarPath(buffer) abort
let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer)
if has('win32')
let l:platform = 'win32'
elseif has('macunix')
let l:platform = 'macosx'
else
let l:platform = 'linux'
endif
" Search jar file within repository path when manually built using mvn
let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
let l: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
if len(l:files) == 1
return l:files[0]
endif
" Search jar file within VSCode extensions folder.
let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
let l:files = globpath(l:path, '**/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 unzipped tar.gz file
let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) >= 1
if len(l:files) == 1
return l:files[0]
endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) >= 1
if len(l:files) == 1
return l:files[0]
endif
@@ -180,8 +166,7 @@ function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
return ale#command#Run(
\ a:buffer,
\ l:command,
\ function('ale_linters#java#eclipselsp#CommandWithVersion'),
\ { 'output_stream': 'both' }
\ function('ale_linters#java#eclipselsp#CommandWithVersion')
\)
endfunction

View File

@@ -6,5 +6,5 @@ call ale#linter#Define('kotlin', {
\ 'executable': 'ktlint',
\ 'command': function('ale#handlers#ktlint#GetCommand'),
\ 'callback': 'ale#handlers#ktlint#Handle',
\ 'output_stream': 'stderr'
\ 'lint_file': 1
\})

View File

@@ -1,22 +1,11 @@
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
" Description: Adds support for markdownlint
call ale#Set('markdown_markdownlint_options', '')
function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort
let l:executable = 'markdownlint'
let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options')
return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s'
endfunction
call ale#linter#Define('markdown', {
\ 'name': 'markdownlint',
\ 'executable': 'markdownlint',
\ 'lint_file': 1,
\ 'output_stream': 'both',
\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'),
\ 'command': 'markdownlint %s',
\ 'callback': 'ale#handlers#markdownlint#Handle'
\})

View File

@@ -7,9 +7,10 @@ call ale#Set('nasm_nasm_options', '')
function! ale_linters#nasm#nasm#GetCommand(buffer) abort
" Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/'
let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
let l:output_null = has('win32') ? 'NUL' : '/dev/null'
return '%e -X gnu -I %s:h' . l:separator
return '%e -X gnu -I ' . ale#Escape(l:path)
\ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s'
\ . ' -o ' . l:output_null

View File

@@ -3,7 +3,6 @@
call ale#Set('objc_ccls_executable', 'ccls')
call ale#Set('objc_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('objc', {
\ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('objc', {
\ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'objc_ccls_init_options')},
\ 'initialization_options': {b -> ale#Var(b, 'objc_ccls_init_options')},
\})

View File

@@ -10,7 +10,7 @@ function! ale_linters#objc#clang#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return 'clang -S -x objective-c -fsyntax-only '
\ . '-iquote %s:h'
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -'
endfunction

View File

@@ -10,7 +10,7 @@ function! ale_linters#objcpp#clang#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return 'clang++ -S -x objective-c++ -fsyntax-only '
\ . '-iquote %s:h'
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -'
endfunction

View File

@@ -9,6 +9,6 @@ call ale#linter#Define('ocaml', {
\ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})

View File

@@ -1,9 +1,9 @@
" Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP
call ale#Set('php_psalm_executable', 'psalm')
call ale#Set('php_psalm_options', '')
call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('psalm_langserver_executable', 'psalm')
call ale#Set('psalm_langserver_options', '')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@@ -12,13 +12,13 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
endfunction
function! ale_linters#php#psalm#GetCommand(buffer) abort
return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'php_psalm_options'))
return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'psalm_langserver_options'))
endfunction
call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
\ 'vendor/bin/psalm',
\ ])},
\ 'command': function('ale_linters#php#psalm#GetCommand'),

View File

@@ -8,15 +8,13 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
" Error: Could not parse for environment production: Syntax error at '='; expected '}' at /root/puppetcode/modules/pancakes/manifests/init.pp:5"
" Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 4, column: 5)
" Error: Illegal attempt to assign to 'a Name'. Not an assignable reference (file: /tmp/modules/waffles/manifests/syrup.pp, line: 5, column: 11)
" Error: Could not parse for environment production: Syntax error at end of input (file: /tmp/modules/bob/manifests/init.pp)
let l:pattern = '^Error:\%(.*:\)\? \(.\+\) \((file:\|at\) .\+\.pp\(\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)\|)$\)'
let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[5] + 0,
\ 'col': l:match[7] + 0,
\ 'lnum': l:match[4] + 0,
\ 'col': l:match[6] + 0,
\ 'text': l:match[1],
\})
endfor

View File

@@ -6,7 +6,9 @@ call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra')
function! ale_linters#pyrex#cython#GetCommand(buffer) abort
return '%e --working %s:h --include-dir %s:h'
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
\ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction

View File

@@ -4,7 +4,7 @@
call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 'project')
call ale#Set('python_flake8_change_directory', 1)
call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort
@@ -38,30 +38,10 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
\)
endfunction
function! ale_linters#python#flake8#GetCdString(buffer) abort
let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory')
let l:cd_string = ''
if l:change_directory is# 'project'
let l:project_root = ale#python#FindProjectRootIni(a:buffer)
if !empty(l:project_root)
let l:cd_string = ale#path#CdString(l:project_root)
endif
endif
if (l:change_directory is# 'project' && empty(l:cd_string))
\|| l:change_directory is# 1
\|| l:change_directory is# 'file'
let l:cd_string = ale#path#BufferCdString(a:buffer)
endif
return l:cd_string
endfunction
function! ale_linters#python#flake8#GetCommand(buffer, version) abort
let l:cd_string = ale_linters#python#flake8#GetCdString(a:buffer)
let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'

View File

@@ -16,15 +16,17 @@ function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort
endfunction
function! ale_linters#python#pydocstyle#GetCommand(buffer) abort
let l:dir = fnamemodify(bufname(a:buffer), ':p:h')
let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pydocstyle'
\ : ''
return ale#path#BufferCdString(a:buffer)
return ale#path#CdString(l:dir)
\ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options'))
\ . ' %s:t'
\ . ' ' . ale#Var(a:buffer, 'python_pydocstyle_options')
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:t'))
endfunction
function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort

View File

@@ -17,7 +17,7 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction
function! ale_linters#python#pylint#GetCommand(buffer, version) abort
function! ale_linters#python#pylint#GetCommand(buffer) abort
let l:cd_string = ''
if ale#Var(a:buffer, 'python_pylint_change_directory')
@@ -38,23 +38,17 @@ function! ale_linters#python#pylint#GetCommand(buffer, version) abort
return l:cd_string
\ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pylint_options'))
\ . ' ' . ale#Var(a:buffer, 'python_pylint_options')
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n'
\ . (ale#semver#GTE(a:version, [2, 4, 0]) ? ' --from-stdin' : '')
\ . ' %s'
endfunction
function! ale_linters#python#pylint#Handle(buffer, lines) abort
let l:output = ale#python#HandleTraceback(a:lines, 10)
if !empty(l:output)
return l:output
endif
" Matches patterns like the following:
"
" test.py:4:4: W0101 (unreachable) Unreachable code
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ([[:alnum:]]+) \(([^(]*)\) (.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
"let l:failed = append(0, l:match)
@@ -77,19 +71,13 @@ function! ale_linters#python#pylint#Handle(buffer, lines) abort
let l:code_out = l:match[4]
endif
let l:item = {
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 1,
\ 'text': l:match[5],
\ 'code': l:code_out,
\ 'type': 'W',
\}
if l:code[:0] is# 'E'
let l:item.type = 'E'
endif
call add(l:output, l:item)
\ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
\})
endfor
return l:output
@@ -98,17 +86,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pylint',
\ 'executable': function('ale_linters#python#pylint#GetExecutable'),
\ 'lint_file': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer,
\ ale#Var(buffer, 'python_pylint_executable'),
\ '%e --version',
\ {buffer, version -> !ale#semver#GTE(version, [2, 4, 0])},
\ )},
\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer,
\ ale#Var(buffer, 'python_pylint_executable'),
\ '%e --version',
\ function('ale_linters#python#pylint#GetCommand'),
\ )},
\ 'command': function('ale_linters#python#pylint#GetCommand'),
\ 'callback': 'ale_linters#python#pylint#Handle',
\ 'lint_file': 1,
\})

View File

@@ -1,43 +0,0 @@
call ale#Set('python_pyright_executable', 'pyright-langserver')
call ale#Set('python_pyright_config', {})
function! ale_linters#python#pyright#GetConfig(buffer) abort
let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config'))
if !has_key(l:config, 'python')
let l:config.python = {}
endif
if type(l:config.python) is v:t_dict
" Automatically detect the virtualenv path and use it.
if !has_key(l:config.python, 'venvPath')
let l:venv = ale#python#FindVirtualenv(a:buffer)
if !empty(l:venv)
let l:config.python.venvPath = l:venv
endif
endif
" Automatically use the version of Python in virtualenv.
if type(get(l:config.python, 'venvPath')) is v:t_string
\&& !empty(l:config.python.venvPath)
\&& !has_key(l:config.python, 'pythonPath')
let l:config.python.pythonPath = ale#path#Simplify(
\ l:config.python.venvPath
\ . (has('win32') ? '/Scripts/python' : '/bin/python')
\)
endif
endif
return l:config
endfunction
call ale#linter#Define('python', {
\ 'name': 'pyright',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')},
\ 'command': '%e --stdio',
\ 'project_root': function('ale#python#FindProjectRoot'),
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'),
\})

View File

@@ -9,6 +9,6 @@ call ale#linter#Define('reason', {
\ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})

View File

@@ -10,7 +10,7 @@ function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin %s'
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction
function! ale_linters#ruby#rubocop#GetType(severity) abort

View File

@@ -11,7 +11,7 @@ function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin %s'
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction
" standardrb is based on RuboCop so the callback is the same

View File

@@ -11,7 +11,6 @@ call ale#Set('rust_cargo_default_feature_behavior', 'default')
call ale#Set('rust_cargo_include_features', '')
call ale#Set('rust_cargo_use_clippy', 0)
call ale#Set('rust_cargo_clippy_options', '')
call ale#Set('rust_cargo_target_dir', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@@ -32,9 +31,6 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:target_dir = ale#Var(a:buffer, 'rust_cargo_target_dir')
let l:use_target_dir = !empty(l:target_dir)
\ && ale#semver#GTE(a:version, [0, 17, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
@@ -86,7 +82,6 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
\ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features

View File

@@ -1,43 +0,0 @@
" Author: hsanson <hsanson@gmail.com>
" Description: Lints sh files using bashate
" URL: https://github.com/openstack/bashate
call ale#Set('sh_bashate_executable', 'bashate')
call ale#Set('sh_bashate_options', '')
function! ale_linters#sh#bashate#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'sh_bashate_executable')
endfunction
function! ale_linters#sh#bashate#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'sh_bashate_options')
let l:executable = ale_linters#sh#bashate#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' ' . l:options . ' ' . '%t'
endfunction
function! ale_linters#sh#bashate#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" /path/to/script/file:694:1: E003 Indent not multiple of 4
let l:pattern = ':\(\d\+\):\(\d\+\): \(.*\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'text': l:match[3],
\})
endfor
return l:output
endfunction
call ale#linter#Define('sh', {
\ 'name': 'bashate',
\ 'output_stream': 'stdout',
\ 'executable': function('ale_linters#sh#bashate#GetExecutable'),
\ 'command': function('ale_linters#sh#bashate#GetCommand'),
\ 'callback': 'ale_linters#sh#bashate#Handle',
\})

View File

@@ -1,5 +1,5 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Lints shell files by invoking the shell with -n
" Description: Lints sh files using bash -n
" Backwards compatibility
if exists('g:ale_linters_sh_shell_default_shell')

View File

@@ -1,33 +0,0 @@
" ale_linters/sql/sqllint.vim
" Author: Joe Reynolds <joereynolds952@gmail.co>
" Description: sql-lint for SQL files.
" sql-lint can be found at
" https://www.npmjs.com/package/sql-lint
" https://github.com/joereynolds/sql-lint
function! ale_linters#sql#sqllint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" stdin:1 [ER_NO_DB_ERROR] No database selected
let l:pattern = '\v^[^:]+:(\d+) (.*)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'type': l:match[3][0],
\ 'text': l:match[0],
\})
endfor
return l:output
endfunction
call ale#linter#Define('sql', {
\ 'name': 'sqllint',
\ 'aliases': ['sql-lint'],
\ 'executable': 'sql-lint',
\ 'command': 'sql-lint',
\ 'callback': 'ale_linters#sql#sqllint#Handle',
\})

View File

@@ -1,62 +0,0 @@
" Author: Klaas Pieter Annema <https://github.com/klaaspieter>
" Description: Support for swift-format https://github.com/apple/swift-format
let s:default_executable = 'swift-format'
call ale#Set('swift_swiftformat_executable', s:default_executable)
function! ale_linters#swift#swiftformat#UseSwift(buffer) abort
let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift')
let l:executable = ale#Var(a:buffer, 'swift_swiftformat_executable')
return !empty(l:swift_config) && l:executable is# s:default_executable
endfunction
function! ale_linters#swift#swiftformat#GetExecutable(buffer) abort
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
return 'swift'
endif
return ale#Var(a:buffer, 'swift_swiftformat_executable')
endfunction
function! ale_linters#swift#swiftformat#GetCommand(buffer) abort
let l:executable = ale_linters#swift#swiftformat#GetExecutable(a:buffer)
let l:args = '--mode lint %t'
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
let l:args = 'run swift-format' . ' ' . l:args
endif
return ale#Escape(l:executable) . ' ' . l:args
endfunction
function! ale_linters#swift#swiftformat#Handle(buffer, lines) abort
" Matches lines of the following pattern:
"
" Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove ';' and move the next statement to the new line
" Sources/main.swift:3:12: warning: [Spacing]: remove 1 space
let l:pattern = '\v^.*:(\d+):(\d+): (\S+) \[(\S+)\]: (.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
\ 'code': l:match[4],
\ 'text': l:match[5],
\})
endfor
return l:output
endfunction
call ale#linter#Define('swift', {
\ 'name': 'swift-format',
\ 'executable': function('ale_linters#swift#swiftformat#GetExecutable'),
\ 'command': function('ale_linters#swift#swiftformat#GetCommand'),
\ 'output_stream': 'stderr',
\ 'language': 'swift',
\ 'callback': 'ale_linters#swift#swiftformat#Handle'
\})

View File

@@ -1,5 +0,0 @@
" Author: suoto <andre820@gmail.com>
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
" or xvhdl. More info on https://github.com/suoto/hdl_checker
call ale#handlers#hdl_checker#DefineLinter('verilog')

View File

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

View File

@@ -1,5 +0,0 @@
" Author: suoto <andre820@gmail.com>
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
" or xvhdl. More info on https://github.com/suoto/hdl_checker
call ale#handlers#hdl_checker#DefineLinter('vhdl')

View File

@@ -5,7 +5,7 @@
call ale#Set('vim_vint_show_style_issues', 1)
call ale#Set('vim_vint_executable', 'vint')
let s:enable_neovim = has('nvim') ? ' --enable-neovim' : ''
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"'
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:can_use_no_color_flag = empty(a:version)
@@ -13,17 +13,12 @@ function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:warning_flag = ale#Var(a:buffer, 'vim_vint_show_style_issues') ? '-s' : '-w'
" Use the --stdin-display-name argument if supported, temp file otherwise.
let l:stdin_or_temp = ale#semver#GTE(a:version, [0, 4, 0])
\ ? ' --stdin-display-name %s -'
\ : ' %t'
return '%e'
\ . ' ' . l:warning_flag
\ . (l:can_use_no_color_flag ? ' --no-color' : '')
\ . s:enable_neovim
\ . ' ' . s:format
\ . l:stdin_or_temp
\ . ' %t'
endfunction
let s:word_regex_list = [

View File

@@ -1,20 +0,0 @@
" Author: CherryMan <skipper308@hotmail.ca>
" Description: A language server for Zig
call ale#Set('zig_zls_executable', 'zls')
call ale#Set('zig_zls_config', {})
function! ale_linters#zig#zls#GetProjectRoot(buffer) abort
let l:build_rs = ale#path#FindNearestFile(a:buffer, 'build.zig')
return !empty(l:build_rs) ? fnamemodify(l:build_rs, ':h') : ''
endfunction
call ale#linter#Define('zig', {
\ 'name': 'zls',
\ 'lsp': 'stdio',
\ 'lsp_config': {b -> ale#Var(b, 'zig_zls_config')},
\ 'executable': {b -> ale#Var(b, 'zig_zls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale_linters#zig#zls#GetProjectRoot'),
\})

View File

@@ -100,7 +100,13 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
" Use the filetype from the buffer
let l:filetype = getbufvar(a:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype)
let l:linters = ale#linter#RemoveIgnored(a:buffer, l:filetype, l:linters)
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
let l:linters = !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config, l:disable_lsp)
\ : l:linters
" Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer
@@ -157,7 +163,7 @@ function! ale#Queue(delay, ...) abort
endif
endfunction
let s:current_ale_version = [3, 0, 0]
let s:current_ale_version = [2, 7, 0]
" A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort
@@ -257,28 +263,6 @@ function! ale#GetLocItemMessage(item, format_string) abort
let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
" Replace %s with the text.
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g')
" Windows may insert carriage return line endings (^M), strip these characters.
let l:msg = substitute(l:msg, '\r', '', 'g')
return l:msg
endfunction
" Given a buffer and a linter or fixer name, return an Array of two-item
" Arrays describing how to map filenames to and from the local to foreign file
" systems.
function! ale#GetFilenameMappings(buffer, name) abort
let l:linter_mappings = ale#Var(a:buffer, 'filename_mappings')
if type(l:linter_mappings) is v:t_list
return l:linter_mappings
endif
let l:name = a:name
if !has_key(l:linter_mappings, l:name)
" Use * as a default setting for all tools.
let l:name = '*'
endif
return get(l:linter_mappings, l:name, [])
endfunction

View File

@@ -130,7 +130,7 @@ endfunction
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:language = ale#linter#GetLanguage(l:buffer, l:linter)
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
AssertEqual a:expected_language, l:language
endfunction

View File

@@ -2,28 +2,20 @@
" Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0)
call ale#Set('c_always_make', has('unix') && !has('macunix'))
call ale#Set('c_parse_compile_commands', 1)
call ale#Set('c_parse_compile_commands', 0)
let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
function! s:CanParseMakefile(buffer) abort
" Something somewhere seems to delete this setting in tests, so ensure we
" always have a default value.
call ale#Set('c_parse_makefile', 0)
return ale#Var(a:buffer, 'c_parse_makefile')
endfunction
function! ale#c#GetBuildDirectory(buffer) abort
" Don't include build directory for header files, as compile_commands.json
" files don't consider headers to be translation units, and provide no
" commands for compiling header files.
if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
return ''
endif
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
" c_build_dir has the priority if defined
@@ -76,73 +68,14 @@ function! ale#c#ShellSplit(line) abort
return l:args
endfunction
" Takes the path prefix and a list of cflags and expands @file arguments to
" the contents of the file.
"
" @file arguments are command line arguments recognised by gcc and clang. For
" instance, if @./path/to/file was given to gcc, it would load .path/to/file
" and use the contents of that file as arguments.
function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
let l:out_lines = []
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:cflags_list = []
for l:option in a:raw_split_lines
if stridx(l:option, '@') == 0
" This is an argument specifying a location of a file containing other arguments
let l:path = join(split(l:option, '\zs')[1:], '')
" Make path absolute
if !ale#path#IsAbsolute(l:path)
let l:rel_path = substitute(l:path, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:path = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif
" Read the file and add all the arguments
try
let l:additional_args = readfile(l:path)
catch
continue " All we can really do is skip this argument
endtry
let l:file_lines = []
for l:line in l:additional_args
let l:file_lines += ale#c#ShellSplit(l:line)
endfor
" @file arguments can include other @file arguments, so we must
" recurse.
let l:out_lines += ale#c#ExpandAtArgs(a:path_prefix, l:file_lines)
else
" This is not an @file argument, so don't touch it.
let l:out_lines += [l:option]
endif
endfor
return l:out_lines
endfunction
" Quote C/C++ a compiler argument, if needed.
"
" Quoting arguments might cause issues with some systems/compilers, so we only
" quote them if we need to.
function! ale#c#QuoteArg(arg) abort
if a:arg !~# '\v[#$&*()\\|[\]{};''"<>/?! ^%]'
return a:arg
endif
return ale#Escape(a:arg)
endfunction
function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
" Expand @file arguments now before parsing
let l:arguments = ale#c#ExpandAtArgs(a:path_prefix, a:raw_arguments)
" A list of [already_quoted, argument]
let l:items = []
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
let l:option_index = 0
while l:option_index < len(l:arguments)
let l:option = l:arguments[l:option_index]
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
" Include options, that may need relative path fix
@@ -150,67 +83,56 @@ function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
\ || stridx(l:option, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0
\ || stridx(l:option, '-iframework') == 0
\ || stridx(l:option, '-include') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I'
else
let l:arg = l:arguments[l:option_index]
let l:arg = l:split_lines[l:option_index]
let l:option_index = l:option_index + 1
endif
" Fix relative paths if needed
if !ale#path#IsAbsolute(l:arg)
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#path#GetAbsPath(a:path_prefix, l:rel_path)
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path)
endif
call add(l:items, [1, l:option])
call add(l:items, [1, ale#Escape(l:arg)])
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:items, [1, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
call add(l:cflags_list, l:split_lines[l:option_index])
let l:option_index = l:option_index + 1
else
call add(l:items, [0, l:option])
endif
" Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:items, [0, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
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 && l:option !~# '\v^-f(dump|diagnostics|no-show-column|stack-usage)'
\ || (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:items, [0, l:option])
call add(l:cflags_list, l:option)
endif
endwhile
if a:should_quote
" Quote C arguments that haven't already been quoted above.
" If and only if we've been asked to quote them.
call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])')
else
call map(l:items, 'v:val[1]')
endif
return join(l:items, ' ')
return join(l:cflags_list, ' ')
endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !s:CanParseMakefile(a:buffer)
if !g:ale_c_parse_makefile
return v:null
endif
@@ -228,7 +150,7 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
return ale#c#ParseCFlags(l:makefile_dir, 0, ale#c#ShellSplit(l:cflag_line))
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
endfunction
" Given a buffer number, find the project directory containing
@@ -296,10 +218,6 @@ if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {}
endif
function! ale#c#ResetCompileCommandsCache() abort
let s:compile_commands_cache = {}
endfunction
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:empty = [{}, {}]
@@ -330,20 +248,9 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:dir_lookup = {}
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
let l:filename = ale#path#GetAbsPath(l:entry.directory, l:entry.file)
" Store a key for lookups by the absolute path to the filename.
let l:file_lookup[l:filename] = get(l:file_lookup, l:filename, []) + [l:entry]
" Store a key for fuzzy lookups by the absolute path to the directory.
let l:dirname = fnamemodify(l:filename, ':h')
let l:dir_lookup[l:dirname] = get(l:dir_lookup, l:dirname, []) + [l:entry]
" Store a key for fuzzy lookups by just the basename of the file.
let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
" Store a key for fuzzy lookups by just the basename of the directory.
let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t'))
let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
endfor
@@ -358,80 +265,28 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty
endfunction
" Get [should_quote, arguments] from either 'command' or 'arguments'
" 'arguments' should be quoted later, the split 'command' strings should not.
function! s:GetArguments(json_item) abort
if has_key(a:json_item, 'arguments')
return [1, a:json_item.arguments]
elseif has_key(a:json_item, 'command')
return [0, ale#c#ShellSplit(a:json_item.command)]
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 [0, []]
return ''
endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
let l:buffer_filename = ale#path#Simplify(expand('#' . a:buffer . ':p'))
let l:basename = tolower(fnamemodify(l:buffer_filename, ':t'))
" Look for any file in the same directory if we can't find an exact match.
let l:dir = fnamemodify(l:buffer_filename, ':h')
" Search for an exact file match first.
let l:file_list = get(a:file_lookup, l:buffer_filename, [])
" We may have to look for /foo/bar instead of C:\foo\bar
if empty(l:file_list) && has('win32')
let l:file_list = get(
\ a:file_lookup,
\ ale#path#RemoveDriveLetter(l:buffer_filename),
\ []
\)
endif
" Try the absolute path to the directory second.
let l:dir_list = get(a:dir_lookup, l:dir, [])
if empty(l:dir_list) && has('win32')
let l:dir_list = get(
\ a:dir_lookup,
\ ale#path#RemoveDriveLetter(l:dir),
\ []
\)
endif
if empty(l:file_list) && empty(l:dir_list)
" If we can't find matches with the path to the file, try a
" case-insensitive match for any similarly-named file.
let l:file_list = get(a:file_lookup, l:basename, [])
" If we can't find matches with the path to the directory, try a
" case-insensitive match for anything in similarly-named directory.
let l:dir_list = get(a:dir_lookup, tolower(fnamemodify(l:dir, ':t')), [])
endif
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']
" Try to find a source file by an absolute path first.
let l:key = fnamemodify(l:buffer_filename, ':r') . l:suffix
let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, [])
if empty(l:file_list) && has('win32')
let l:file_list = get(
\ a:file_lookup,
\ ale#path#RemoveDriveLetter(l:key),
\ []
\)
endif
if empty(l:file_list)
" Look fuzzy matches on the basename second.
let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, [])
endif
if !empty(l:file_list)
let l:source_file = l:key
break
@@ -440,31 +295,28 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
endif
for l:item in l:file_list
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
" Load the flags for this file, or for a source file matching the
" header file.
if (
\ bufnr(l:filename) is a:buffer
\ bufnr(l:item.file) is a:buffer
\ || (
\ !empty(l:source_file)
\ && l:filename[-len(l:source_file):] is? l:source_file
\ && l:item.file[-len(l:source_file):] is? l:source_file
\ )
\)
let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
endif
endfor
" Look for any file in the same directory if we can't find an exact match.
let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h'))
let l:dirbasename = tolower(expand('#' . a:buffer . ':p:h:t'))
let l:dir_list = get(a:dir_lookup, l:dirbasename, [])
for l:item in l:dir_list
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
if ale#path#RemoveDriveLetter(fnamemodify(l:filename, ':h'))
\ is? ale#path#RemoveDriveLetter(l:dir)
let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
endif
endfor
@@ -482,6 +334,10 @@ endfunction
function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = v:null
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif
if ale#Var(a:buffer, 'c_parse_compile_commands')
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
@@ -490,10 +346,6 @@ function! ale#c#GetCFlags(buffer, output) abort
endif
endif
if s:CanParseMakefile(a:buffer) && !empty(a:output) && !empty(l:cflags)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif
if l:cflags is v:null
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif
@@ -502,14 +354,11 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction
function! ale#c#GetMakeCommand(buffer) abort
if s:CanParseMakefile(a:buffer)
let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if ale#Var(a:buffer, 'c_parse_makefile')
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:path)
let l:always_make = ale#Var(a:buffer, 'c_always_make')
return ale#path#CdString(fnamemodify(l:path, ':h'))
\ . 'make -n' . (l:always_make ? ' --always-make' : '')
if !empty(l:makefile_path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
endif
endif
@@ -578,3 +427,8 @@ function! ale#c#IncludeOptions(include_paths) abort
return join(l:option_list)
endfunction
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])

View File

@@ -24,42 +24,6 @@ function! ale#code_action#HandleCodeAction(code_action, should_save) abort
endfor
endfunction
function! s:ChangeCmp(left, right) abort
if a:left.start.line < a:right.start.line
return -1
endif
if a:left.start.line > a:right.start.line
return 1
endif
if a:left.start.offset < a:right.start.offset
return -1
endif
if a:left.start.offset > a:right.start.offset
return 1
endif
if a:left.end.line < a:right.end.line
return -1
endif
if a:left.end.line > a:right.end.line
return 1
endif
if a:left.end.offset < a:right.end.offset
return -1
endif
if a:left.end.offset > a:right.end.offset
return 1
endif
return 0
endfunction
function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:current_buffer = bufnr('')
" The buffer is used to determine the fileformat, if available.
@@ -84,8 +48,7 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:column_offset = 0
let l:last_end_line = 0
" Changes have to be sorted so we apply them from top-to-bottom.
for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp'))
for l:code_edit in a:changes
if l:code_edit.start.line isnot l:last_end_line
let l:column_offset = 0
endif

View File

@@ -133,36 +133,11 @@ function! ale#command#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g')
endfunction
" Format a filename, converting it with filename mappings, if non-empty,
" and escaping it for putting into a command string.
"
" The filename can be modified.
function! s:FormatFilename(filename, mappings, modifiers) abort
let l:filename = a:filename
if !empty(a:mappings)
let l:filename = ale#filename_mapping#Map(l:filename, a:mappings)
endif
if !empty(a:modifiers)
let l:filename = fnamemodify(l:filename, a:modifiers)
endif
return ale#Escape(l:filename)
endfunction
" Given a command string, replace every...
" %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory
" %% -> with a literal %
function! ale#command#FormatCommand(
\ buffer,
\ executable,
\ command,
\ pipe_file_if_needed,
\ input,
\ mappings,
\) abort
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed, input) abort
let l:temporary_file = ''
let l:command = a:command
@@ -179,24 +154,14 @@ function! ale#command#FormatCommand(
" file.
if l:command =~# '%s'
let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute(
\ l:command,
\ '\v\%s(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
\ 'g'
\)
let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g')
endif
if a:input isnot v:false && l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
let l:temporary_file = s:TemporaryFilename(a:buffer)
let l:command = substitute(
\ l:command,
\ '\v\%t(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))',
\ 'g'
\)
let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g')
endif
" Finish formatting so %% becomes %.
@@ -300,7 +265,6 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
\ a:command,
\ get(l:options, 'read_buffer', 0),
\ get(l:options, 'input', v:null),
\ get(l:options, 'filename_mappings', []),
\)
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:job_options = {

View File

@@ -5,7 +5,7 @@ scriptencoding utf-8
" The omnicompletion menu is shown through a special Plug mapping which is
" only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough.
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o><C-p>
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o>
" If we hit the key sequence in normal mode, then we won't show the menu, so
" we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
@@ -16,8 +16,7 @@ onoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
let g:ale_completion_autoimport = get(g:, 'ale_completion_autoimport', 0)
let g:ale_completion_tsserver_remove_warnings = get(g:, 'ale_completion_tsserver_remove_warnings', 0)
let g:ale_completion_tsserver_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0)
let s:timer_id = -1
let s:last_done_pos = []
@@ -188,13 +187,7 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return ''
endfunction
function! ale#completion#Filter(
\ buffer,
\ filetype,
\ suggestions,
\ prefix,
\ exact_prefix_match,
\) abort
function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
if empty(a:prefix)
@@ -221,17 +214,10 @@ function! ale#completion#Filter(
" Dictionaries is accepted here.
let l:word = type(l:item) is v:t_string ? l:item : l:item.word
if a:exact_prefix_match
" Add suggestions if the word is an exact match.
if l:word is# a:prefix
call add(l:filtered_suggestions, l:item)
endif
else
" Add suggestions if the suggestion starts with a
" case-insensitive match for the prefix.
if l:word[: len(a:prefix) - 1] is? a:prefix
call add(l:filtered_suggestions, l:item)
endif
" Add suggestions if the suggestion starts with a
" case-insensitive match for the prefix.
if l:word[: len(a:prefix) - 1] is? a:prefix
call add(l:filtered_suggestions, l:item)
endif
endfor
endif
@@ -254,17 +240,21 @@ function! ale#completion#Filter(
return l:filtered_suggestions
endfunction
function! s:ReplaceCompletionOptions(source) abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
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'
endif
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
if a:source is# 'ale-automatic'
if l:source is# 'ale-automatic'
if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt
endif
@@ -327,70 +317,41 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort
else
let l:result = ale#completion#GetCompletionResult()
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call s:ReplaceCompletionOptions(l:source)
endif
call s:ReplaceCompletionOptions()
return l:result isnot v:null ? l:result : []
endif
endfunction
function! s:OpenCompletionMenu(...) abort
if !&l:paste
call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
endif
endfunction
function! ale#completion#Show(result) abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if ale#util#Mode() isnot# 'i' && l:source isnot# 'ale-import'
if ale#util#Mode() isnot# 'i'
return
endif
" Set the list in the buffer.
" 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)
if l:source is# 'ale-import'
" If we ran completion from :ALEImport,
" tell the user that nothing is going to happen.
call s:message('No possible imports found.')
endif
return
endif
" Replace completion options shortly before opening the menu.
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call s:ReplaceCompletionOptions(l:source)
call s:ReplaceCompletionOptions()
call timer_start(0, function('s:OpenCompletionMenu'))
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
if l:source is# 'ale-import'
call ale#completion#HandleUserData(b:ale_completion_result[0])
let l:text_changed = '' . g:ale_lint_on_text_changed
" Check the buffer again right away, if linting is enabled.
if g:ale_enabled
\&& (
\ l:text_changed is# '1'
\ || l:text_changed is# 'always'
\ || l:text_changed is# 'normal'
\ || l:text_changed is# 'insert'
\)
call ale#Queue(0, '')
endif
endif
endfunction
function! ale#completion#GetAllTriggers() abort
@@ -421,18 +382,14 @@ endfunction
function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getpos('.')[1:2]
return has_key(b:, 'ale_completion_info')
\&& (
\ ale#util#Mode() is# 'i'
\ || b:ale_completion_info.source is# 'ale-import'
\)
return ale#util#Mode() is# 'i'
\&& 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# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback'
\ || b:ale_completion_info.source is# 'ale-import'
\)
endfunction
@@ -440,14 +397,10 @@ function! ale#completion#ParseTSServerCompletions(response) abort
let l:names = []
for l:suggestion in a:response.body
let l:kind = get(l:suggestion, 'kind', '')
if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning'
call add(l:names, {
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''),
\})
endif
call add(l:names, {
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''),
\})
endfor
return l:names
@@ -457,26 +410,15 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:buffer = bufnr('')
let l:results = []
let l:names_with_details = []
let l:info = get(b:, 'ale_completion_info', {})
for l:suggestion in a:response.body
let l:displayParts = []
let l:local_name = v:null
for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ')
endfor
for l:part in l:suggestion.displayParts
" Stop on stop on line breaks for the menu.
if get(l:part, 'kind') is# 'lineBreak'
break
endif
if get(l:part, 'kind') is# 'localName'
let l:local_name = l:part.text
endif
call add(l:displayParts, l:part.text)
endfor
@@ -489,35 +431,21 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items
let l:result = {
\ 'word': (
\ l:suggestion.name is# 'default'
\ && l:suggestion.kind is# 'alias'
\ && !empty(l:local_name)
\ ? l:local_name
\ : l:suggestion.name
\ ),
\ 'word': l:suggestion.name,
\ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind),
\ 'icase': 1,
\ 'menu': join(l:displayParts, ''),
\ 'dup': get(l:info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport,
\ 'dup': g:ale_completion_tsserver_autoimport,
\ 'info': join(l:documentationParts, ''),
\}
" This flag is used to tell if this completion came from ALE or not.
let l:user_data = {'_ale_completion_item': 1}
if has_key(l:suggestion, 'codeActions')
let l:user_data.code_actions = l:suggestion.codeActions
let l:result.user_data = json_encode({
\ 'codeActions': l:suggestion.codeActions,
\ })
endif
let l:result.user_data = json_encode(l:user_data)
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:user_data, 'code_actions')
call add(l:results, l:result)
endif
call add(l:results, l:result)
endfor
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
@@ -536,7 +464,6 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ 'icase': 1,
\ 'menu': '',
\ 'info': '',
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\})
endfor
endif
@@ -590,80 +517,23 @@ function! ale#completion#ParseLSPCompletions(response) abort
continue
endif
" Don't use LSP items with additional text edits when autoimport for
" completions is turned off.
if !empty(get(l:item, 'additionalTextEdits'))
\&& !(
\ get(l:info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport
\)
continue
endif
let l:doc = get(l:item, 'documentation', '')
if type(l:doc) is v:t_dict && has_key(l:doc, 'value')
let l:doc = l:doc.value
endif
let l:result = {
call add(l:results, {
\ 'word': l:word,
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
\ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''),
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\}
" This flag is used to tell if this completion came from ALE or not.
let l:user_data = {'_ale_completion_item': 1}
if has_key(l:item, 'additionalTextEdits')
let l:text_changes = []
for l:edit in l:item.additionalTextEdits
call add(l:text_changes, {
\ 'start': {
\ 'line': l:edit.range.start.line + 1,
\ 'offset': l:edit.range.start.character + 1,
\ },
\ 'end': {
\ 'line': l:edit.range.end.line + 1,
\ 'offset': l:edit.range.end.character + 1,
\ },
\ 'newText': l:edit.newText,
\})
endfor
if !empty(l:text_changes)
let l:user_data.code_actions = [{
\ 'description': 'completion',
\ 'changes': [
\ {
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\ },
\ ],
\}]
endif
endif
let l:result.user_data = json_encode(l:user_data)
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:user_data, 'code_actions')
call add(l:results, l:result)
endif
\})
endfor
if has_key(l:info, 'prefix')
let l:results = ale#completion#Filter(
\ l:buffer,
\ &filetype,
\ l:results,
\ l:info.prefix,
\ get(l:info, 'additional_edits_only', 0),
\)
let l:results = ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
endif
return l:results[: g:ale_completion_max_suggestions - 1]
@@ -687,18 +557,13 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
\ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0),
\)[: g:ale_completion_max_suggestions - 1]
" We need to remember some names for tsserver, as it doesn't send
" details back for everything we send.
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
if empty(l:names)
" Response with no results now and skip making a redundant request
" for nothing.
call ale#completion#Show([])
else
if !empty(l:names)
let l:identifiers = []
for l:name in l:names
@@ -763,17 +628,12 @@ function! s:OnReady(linter, lsp_details) abort
call ale#lsp#RegisterCallback(l:id, l:Callback)
if a:linter.lsp is# 'tsserver'
if get(g:, 'ale_completion_tsserver_autoimport') is 1
execute 'echom `g:ale_completion_tsserver_autoimport` is deprecated. Use `g:ale_completion_autoimport` instead.'''
endif
let l:message = ale#lsp#tsserver_message#Completions(
\ l:buffer,
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport,
\ g:ale_completion_tsserver_autoimport,
\)
else
" Send a message saying the buffer has changed first, otherwise
@@ -832,19 +692,9 @@ function! ale#completion#GetCompletions(...) abort
let b:CompleteCallback = l:CompleteCallback
endif
if has_key(l:options, 'line') && has_key(l:options, 'column')
" Use a provided line and column, if given.
let l:line = l:options.line
let l:column = l:options.column
else
let [l:line, l:column] = getpos('.')[1:2]
endif
let [l:line, l:column] = getpos('.')[1:2]
if has_key(l:options, 'prefix')
let l:prefix = l:options.prefix
else
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
endif
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if l:source is# 'ale-automatic' && empty(l:prefix)
return 0
@@ -863,11 +713,6 @@ function! ale#completion#GetCompletions(...) abort
\}
unlet! b:ale_completion_result
if has_key(l:options, 'additional_edits_only')
let b:ale_completion_info.additional_edits_only =
\ l:options.additional_edits_only
endif
let l:buffer = bufnr('')
let l:Callback = function('s:OnReady')
@@ -884,37 +729,6 @@ function! ale#completion#GetCompletions(...) abort
return l:started
endfunction
function! s:message(message) abort
call ale#util#Execute('echom ' . string(a:message))
endfunction
" This function implements the :ALEImport command.
function! ale#completion#Import() abort
let l:word = expand('<cword>')
if empty(l:word)
call s:message('Nothing to complete at cursor!')
return
endif
let [l:line, l:column] = getpos('.')[1:2]
let l:column = searchpos('\V' . escape(l:word, '/\'), 'bn', l:line)[1]
if l:column isnot 0
let l:started = ale#completion#GetCompletions('ale-import', {
\ 'line': l:line,
\ 'column': l:column,
\ 'prefix': l:word,
\ 'additional_edits_only': 1,
\})
if !l:started
call s:message('No completion providers are available.')
endif
endif
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc')
@@ -988,29 +802,29 @@ function! ale#completion#Queue() abort
endfunction
function! ale#completion#HandleUserData(completed_item) abort
let l:user_data_json = get(a:completed_item, 'user_data', '')
let l:user_data = !empty(l:user_data_json)
\ ? json_decode(l:user_data_json)
\ : v:null
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if type(l:user_data) isnot v:t_dict
\|| get(l:user_data, '_ale_completion_item', 0) isnot 1
if l:source isnot# 'ale-automatic'
\&& l:source isnot# 'ale-manual'
\&& l:source isnot# 'ale-callback'
return
endif
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
let l:user_data_json = get(a:completed_item, 'user_data', '')
if l:source is# 'ale-automatic'
\|| l:source is# 'ale-manual'
\|| l:source is# 'ale-callback'
\|| l:source is# 'ale-import'
\|| l:source is# 'ale-omnifunc'
for l:code_action in get(l:user_data, 'code_actions', [])
call ale#code_action#HandleCodeAction(l:code_action, v:false)
endfor
if empty(l:user_data_json)
return
endif
silent doautocmd <nomodeline> User ALECompletePost
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, v:false)
endfor
endfunction
function! ale#completion#Done() abort
@@ -1022,8 +836,6 @@ function! ale#completion#Done() abort
endfunction
augroup ALECompletionActions
autocmd!
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END

View File

@@ -39,8 +39,6 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endif
exec 'echomsg l:message'
catch /E481/
" Do nothing if running from a visual selection.
endtry
" Reset the cursor position if we moved off the end of the line.

View File

@@ -8,7 +8,6 @@ let s:global_variable_list = [
\ 'ale_completion_delay',
\ 'ale_completion_enabled',
\ 'ale_completion_max_suggestions',
\ 'ale_disable_lsp',
\ 'ale_echo_cursor',
\ 'ale_echo_msg_error_str',
\ 'ale_echo_msg_format',
@@ -29,7 +28,6 @@ let s:global_variable_list = [
\ 'ale_linter_aliases',
\ 'ale_linters',
\ 'ale_linters_explicit',
\ 'ale_linters_ignore',
\ 'ale_list_vertical',
\ 'ale_list_window_size',
\ 'ale_loclist_msg_format',
@@ -198,7 +196,6 @@ function! s:EchoLSPErrorMessages(all_linter_names) abort
endfunction
function! ale#debugging#Info() abort
let l:buffer = bufnr('')
let l:filetype = &filetype
" We get the list of enabled linters for free by the above function.
@@ -225,20 +222,10 @@ function! ale#debugging#Info() abort
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '')
let l:non_ignored_names = map(
\ copy(ale#linter#RemoveIgnored(l:buffer, l:filetype, l:enabled_linters)),
\ 'v:val[''name'']',
\)
let l:ignored_names = filter(
\ copy(l:enabled_names),
\ 'index(l:non_ignored_names, v:val) < 0'
\)
call s:Echo(' Current Filetype: ' . l:filetype)
call s:Echo('Available Linters: ' . string(l:all_names))
call s:EchoLinterAliases(l:all_linters)
call s:Echo(' Enabled Linters: ' . string(l:enabled_names))
call s:Echo(' Ignored Linters: ' . string(l:ignored_names))
call s:Echo(' Suggested Fixers: ' . l:fixers_string)
call s:Echo(' Linter Variables:')
call s:Echo('')

View File

@@ -135,6 +135,10 @@ function! s:GoToLSPDefinition(linter, options, capability) abort
endfunction
function! ale#definition#GoTo(options) abort
if !get(g:, 'ale_ignore_2_7_warnings') && has_key(a:options, 'deprecated_command')
execute 'echom '':' . a:options.deprecated_command . ' is deprecated. Use `let g:ale_ignore_2_7_warnings = 1` to disable this message.'''
endif
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
call s:GoToLSPDefinition(l:linter, a:options, 'definition')
@@ -143,6 +147,10 @@ function! ale#definition#GoTo(options) abort
endfunction
function! ale#definition#GoToType(options) abort
if !get(g:, 'ale_ignore_2_7_warnings') && has_key(a:options, 'deprecated_command')
execute 'echom '':' . a:options.deprecated_command . ' is deprecated. Use `let g:ale_ignore_2_7_warnings = 1` to disable this message.'''
endif
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
" TODO: handle typeDefinition for tsserver if supported by the

View File

@@ -4,7 +4,6 @@
" Remapping of linter problems.
let g:ale_type_map = get(g:, 'ale_type_map', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {}
@@ -105,6 +104,42 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
\ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction
" Register a temporary file to be managed with the ALE engine for
" a current job run.
function! ale#engine#ManageFile(buffer, filename) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageFile(a:buffer, a:filename)
endfunction
" Same as the above, but manage an entire directory.
function! ale#engine#ManageDirectory(buffer, directory) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageDirectory(a:buffer, a:directory)
endfunction
function! ale#engine#CreateFile(buffer) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateFile(a:buffer)
endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateDirectory(a:buffer)
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
@@ -157,6 +192,7 @@ function! s:HandleExit(job_info, buffer, output, data) abort
let l:linter = a:job_info.linter
let l:executable = a:job_info.executable
let l:next_chain_index = a:job_info.next_chain_index
" Remove this job from the list.
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
@@ -171,6 +207,20 @@ function! s:HandleExit(job_info, buffer, output, data) abort
call remove(a:output, -1)
endif
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
let [l:command, l:options] = ale#engine#ProcessChain(
\ a:buffer,
\ l:executable,
\ l:linter,
\ l:next_chain_index,
\ a:output,
\)
call s:RunJob(l:command, l:options)
return
endif
try
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
" Handle the function being unknown, or being deleted.
@@ -257,13 +307,6 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfunction
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name)
if !empty(l:mappings)
" We need to apply reverse filename mapping here.
let l:mappings = ale#filename_mapping#Invert(l:mappings)
endif
let l:bufnr_map = {}
let l:new_loclist = []
@@ -304,19 +347,13 @@ function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist)
let l:item.code = l:old_item.code
endif
let l:old_name = get(l:old_item, 'filename', '')
" Map parsed from output to local filesystem files.
if !empty(l:old_name) && !empty(l:mappings)
let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings)
endif
if !empty(l:old_name) && !ale#path#IsTempName(l:old_name)
if has_key(l:old_item, 'filename')
\&& !ale#path#IsTempName(l:old_item.filename)
" Use the filename given.
" Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad
" in the loclist window.
let l:filename = l:old_name
let l:filename = l:old_item.filename
let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr')
@@ -417,19 +454,20 @@ function! s:RunJob(command, options) abort
let l:buffer = a:options.buffer
let l:linter = a:options.linter
let l:output_stream = a:options.output_stream
let l:read_buffer = a:options.read_buffer && !a:options.lint_file
let l:next_chain_index = a:options.next_chain_index
let l:read_buffer = a:options.read_buffer
let l:info = g:ale_buffer_info[l:buffer]
let l:Callback = function('s:HandleExit', [{
\ 'linter': l:linter,
\ 'executable': l:executable,
\ 'next_chain_index': l:next_chain_index,
\}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream,
\ 'executable': l:executable,
\ 'read_buffer': l:read_buffer,
\ 'log_output': 1,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
\ 'log_output': l:next_chain_index >= len(get(l:linter, 'command_chain', [])),
\})
" Only proceed if the job is being run.
@@ -444,7 +482,69 @@ function! s:RunJob(command, options) abort
return 1
endfunction
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort
" Determine which commands to run for a link in a command chain, or
" just a regular command.
function! ale#engine#ProcessChain(buffer, executable, linter, chain_index, input) abort
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
let l:read_buffer = a:linter.read_buffer
let l:chain_index = a:chain_index
let l:input = a:input
while l:chain_index < len(a:linter.command_chain)
" Run a chain of commands, one asynchronous command after the other,
" so that many programs can be run in a sequence.
let l:chain_item = a:linter.command_chain[l:chain_index]
if l:chain_index == 0
" The first callback in the chain takes only a buffer number.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer
\)
else
" The second callback in the chain takes some input too.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer,
\ l:input
\)
endif
" If we have a command to run, execute that.
if !empty(l:command)
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
endif
" The chain item can override the read_buffer option.
if has_key(l:chain_item, 'read_buffer')
let l:read_buffer = l:chain_item.read_buffer
elseif l:chain_index != len(a:linter.command_chain) - 1
" Don't read the buffer for commands besides the last one
" in the chain by default.
let l:read_buffer = 0
endif
break
endif
" Command chain items can return an empty string to indicate that
" a command should be skipped, so we should try the next item
" with no input.
let l:input = []
let l:chain_index += 1
endwhile
return [l:command, {
\ 'executable': a:executable,
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': l:output_stream,
\ 'next_chain_index': l:chain_index + 1,
\ 'read_buffer': l:read_buffer,
\}]
endfunction
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
call ale#command#StopJobs(a:buffer, 'linter')
@@ -453,25 +553,11 @@ function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort
call ale#command#StopJobs(a:buffer, 'file_linter')
let l:info.active_linter_list = []
else
let l:lint_file_map = {}
" Use a previously computed map of `lint_file` values to find
" linters that are used for linting files.
for [l:lint_file, l:linter] in a:linter_slots
if l:lint_file is 1
let l:lint_file_map[l:linter.name] = 1
endif
endfor
" Keep jobs for linting files when we're only linting buffers.
call filter(l:info.active_linter_list, 'get(l:lint_file_map, v:val.name)')
call filter(l:info.active_linter_list, 'get(v:val, ''lint_file'')')
endif
endfunction
function! ale#engine#Stop(buffer) abort
call s:StopCurrentJobs(a:buffer, 1, [])
endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
@@ -522,15 +608,10 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
endif
endfunction
function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
function! s:RunIfExecutable(buffer, linter, executable) abort
if ale#command#IsDeferred(a:executable)
let a:executable.result_callback = {
\ executable -> s:RunIfExecutable(
\ a:buffer,
\ a:linter,
\ a:lint_file,
\ executable
\ )
\ executable -> s:RunIfExecutable(a:buffer, a:linter, executable)
\}
return 1
@@ -538,17 +619,29 @@ function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
if ale#engine#IsExecutable(a:buffer, a:executable)
" Use different job types for file or linter jobs.
let l:job_type = a:lint_file ? 'file_linter' : 'linter'
let l:job_type = a:linter.lint_file ? 'file_linter' : 'linter'
call setbufvar(a:buffer, 'ale_job_type', l:job_type)
if has_key(a:linter, 'command_chain')
let [l:command, l:options] = ale#engine#ProcessChain(
\ a:buffer,
\ a:executable,
\ a:linter,
\ 0,
\ []
\)
return s:RunJob(l:command, l:options)
endif
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
let l:options = {
\ 'executable': a:executable,
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
\ 'next_chain_index': 1,
\ 'read_buffer': a:linter.read_buffer,
\ 'lint_file': a:lint_file,
\}
return s:RunJob(l:command, l:options)
@@ -560,73 +653,22 @@ endfunction
" Run a linter for a buffer.
"
" Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter, lint_file) abort
function! s:RunLinter(buffer, linter) abort
if !empty(a:linter.lsp)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable)
return s:RunIfExecutable(a:buffer, a:linter, l:executable)
endif
return 0
endfunction
function! s:GetLintFileSlots(buffer, linters) abort
let l:linter_slots = []
for l:linter in a:linters
let l:LintFile = l:linter.lint_file
if type(l:LintFile) is v:t_func
let l:LintFile = l:LintFile(a:buffer)
endif
call add(l:linter_slots, [l:LintFile, l:linter])
endfor
return l:linter_slots
endfunction
function! s:GetLintFileValues(slots, Callback) abort
let l:deferred_list = []
let l:new_slots = []
for [l:lint_file, l:linter] in a:slots
while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value')
" If we've already computed the return value, use it.
let l:lint_file = l:lint_file.value
endwhile
if ale#command#IsDeferred(l:lint_file)
" If we are going to return the result later, wait for it.
call add(l:deferred_list, l:lint_file)
else
" If we have the value now, coerce it to 0 or 1.
let l:lint_file = l:lint_file is 1
endif
call add(l:new_slots, [l:lint_file, l:linter])
endfor
if !empty(l:deferred_list)
for l:deferred in l:deferred_list
let l:deferred.result_callback =
\ {-> s:GetLintFileValues(l:new_slots, a:Callback)}
endfor
else
call a:Callback(l:new_slots)
endif
endfunction
function! s:RunLinters(
\ buffer,
\ linters,
\ slots,
\ should_lint_file,
\ new_buffer,
\) abort
call s:StopCurrentJobs(a:buffer, a:should_lint_file, a:slots)
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
@@ -634,10 +676,10 @@ function! s:RunLinters(
silent doautocmd <nomodeline> User ALELintPre
for [l:lint_file, l:linter] in a:slots
for l:linter in a:linters
" Only run lint_file linters if we should.
if !l:lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter, l:lint_file)
if !l:linter.lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter)
" If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0
endif
@@ -652,32 +694,11 @@ function! s:RunLinters(
" disabled, or ALE itself is disabled.
if l:can_clear_results
call ale#engine#SetResults(a:buffer, [])
elseif a:new_buffer
call s:AddProblemsFromOtherBuffers(
\ a:buffer,
\ map(copy(a:slots), 'v:val[1]')
\)
elseif l:new_buffer
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
endif
endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:GetLintFileValues(
\ s:GetLintFileSlots(a:buffer, a:linters),
\ {
\ slots -> s:RunLinters(
\ a:buffer,
\ a:linters,
\ slots,
\ a:should_lint_file,
\ l:new_buffer,
\ )
\ }
\)
endfunction
" Clean up a buffer.
"
" This function will stop all current jobs for the buffer,

View File

@@ -105,11 +105,11 @@ function! ale#events#Init() abort
if g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1'
autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'normal'
autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
autocmd TextChanged * call ale#Queue(g:ale_lint_delay)
elseif l:text_changed is? 'insert'
autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
endif
if g:ale_lint_on_enter
@@ -147,10 +147,6 @@ function! ale#events#Init() abort
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif
endif
if g:ale_hover_cursor
autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif
endif
if g:ale_close_preview_on_insert
autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
endif

View File

@@ -1,22 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Logic for handling mappings between files
" Invert filesystem mappings so they can be mapped in reverse.
function! ale#filename_mapping#Invert(filename_mappings) abort
return map(copy(a:filename_mappings), '[v:val[1], v:val[0]]')
endfunction
" Given a filename and some filename_mappings, map a filename.
function! ale#filename_mapping#Map(filename, filename_mappings) abort
let l:simplified_filename = ale#path#Simplify(a:filename)
for [l:mapping_from, l:mapping_to] in a:filename_mappings
let l:mapping_from = ale#path#Simplify(l:mapping_from)
if l:simplified_filename[:len(l:mapping_from) - 1] is# l:mapping_from
return l:mapping_to . l:simplified_filename[len(l:mapping_from):]
endif
endfor
return a:filename
endfunction

View File

@@ -1,8 +1,4 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Functions for fixing code with programs, or other means.
let g:ale_fix_on_save_ignore = get(g:, 'ale_fix_on_save_ignore', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
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.
@@ -15,29 +11,22 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort
call remove(g:ale_fix_buffer_data, a:buffer)
try
if l:data.changes_made
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
if l:data.changes_made
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
if l:data.should_save
if a:buffer is bufnr('')
if empty(&buftype)
noautocmd :w!
else
set nomodified
endif
if l:data.should_save
if a:buffer is bufnr('')
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
else
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif
endif
catch /E21/
" If we cannot modify the buffer now, try again later.
let g:ale_fix_buffer_data[a:buffer] = l:data
return
endtry
endif
if l:data.should_save
let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
@@ -75,10 +64,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
if l:data.lines_before != l:lines
call remove(g:ale_fix_buffer_data, a:buffer)
if !l:data.ignore_file_changed_errors
execute 'echoerr ''The file was changed before fixing finished'''
endif
execute 'echoerr ''The file was changed before fixing finished'''
return
endif
@@ -104,6 +90,7 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
let l:output = a:job_output
endif
let l:ChainCallback = get(a:job_info, 'chain_with', v:null)
let l:ProcessWith = get(a:job_info, 'process_with', v:null)
" Post-process the output with a function if we have one.
@@ -115,17 +102,27 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
" otherwise skip this job and use the input from before.
"
" We'll use the input from before for chained commands.
if !empty(split(join(l:output)))
if l:ChainCallback is v:null && !empty(split(join(l:output)))
let l:input = l:output
else
let l:input = a:job_info.input
endif
if l:ChainCallback isnot v:null && !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''chain_with is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
let l:next_index = l:ChainCallback is v:null
\ ? a:job_info.callback_index + 1
\ : a:job_info.callback_index
call s:RunFixer({
\ 'buffer': a:buffer,
\ 'input': l:input,
\ 'output': l:output,
\ 'callback_list': a:job_info.callback_list,
\ 'callback_index': a:job_info.callback_index + 1,
\ 'callback_index': l:next_index,
\ 'chain_callback': l:ChainCallback,
\})
endfunction
@@ -138,7 +135,6 @@ function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer
let l:input = a:options.input
let l:fixer_name = a:options.fixer_name
if a:result is 0 || type(a:result) is v:t_list
if type(a:result) is v:t_list
@@ -156,21 +152,26 @@ function! s:RunJob(result, options) abort
endif
let l:command = get(a:result, 'command', '')
let l:ChainWith = get(a:result, 'chain_with', v:null)
if empty(l:command)
" If the command is empty, skip to the next item.
" If the command is empty, skip to the next item, or call the
" chain_with function.
call s:RunFixer({
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_index': a:options.callback_index,
\ 'callback_index': a:options.callback_index + (l:ChainWith is v:null),
\ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith,
\ 'output': [],
\})
return
endif
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
let l:read_buffer = get(a:result, 'read_buffer', 1)
" Default to piping the buffer for the last fixer in the chain.
let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
let l:output_stream = get(a:result, 'output_stream', 'stdout')
if l:read_temporary_file
@@ -179,6 +180,7 @@ function! s:RunJob(result, options) abort
let l:Callback = function('s:HandleExit', [{
\ 'input': l:input,
\ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list,
\ 'process_with': get(a:result, 'process_with', v:null),
@@ -190,7 +192,6 @@ function! s:RunJob(result, options) abort
\ 'read_buffer': l:read_buffer,
\ 'input': l:input,
\ 'log_output': 0,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\})
if empty(l:run_result)
@@ -214,22 +215,32 @@ function! s:RunFixer(options) abort
return
endif
let [l:fixer_name, l:Function] = a:options.callback_list[l:index]
let l:ChainCallback = get(a:options, 'chain_callback', v:null)
let l:Function = l:ChainCallback isnot v:null
\ ? ale#util#GetFunction(l:ChainCallback)
\ : a:options.callback_list[l:index]
" Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer')
" Regular fixer commands accept (buffer, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)])
if l:ChainCallback isnot v:null
" Chained commands accept (buffer, output, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 2
\ ? call(l:Function, [l:buffer, a:options.output])
\ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
else
" Regular fixer commands accept (buffer, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)])
endif
call s:RunJob(l:result, {
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index,
\ 'fixer_name': l:fixer_name,
\})
endfunction
@@ -297,24 +308,16 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
" Variables with capital characters are needed, or Vim will complain about
" funcref variables.
for l:Item in l:callback_list
" Try to capture the names of registered fixer names, so we can use
" them for filename mapping or other purposes later.
let l:fixer_name = v:null
if type(l:Item) is v:t_string
let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func)
let l:fixer_name = l:Item
let l:Item = l:Func
endif
endif
try
call add(l:corrected_list, [
\ l:fixer_name,
\ ale#util#GetFunction(l:Item)
\])
call add(l:corrected_list, ale#util#GetFunction(l:Item))
catch /E475/
" Rethrow exceptions for failing to get a function so we can print
" a friendly message about it.
@@ -332,7 +335,6 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
\ 'lines_before': getbufline(a:buffer, 1, '$'),
\ 'done': 0,
\ 'should_save': a:fixing_flag is# 'save_file',
\ 'ignore_file_changed_errors': a:fixing_flag is# '!',
\ 'temporary_directory_list': [],
\}
endfunction
@@ -341,23 +343,19 @@ endfunction
"
" Returns 0 if no fixes can be applied, and 1 if fixing can be done.
function! ale#fix#Fix(buffer, fixing_flag, ...) abort
if a:fixing_flag isnot# ''
\&& a:fixing_flag isnot# '!'
\&& a:fixing_flag isnot# 'save_file'
throw "fixing_flag must be '', '!', or 'save_file'"
if a:fixing_flag isnot# '' && a:fixing_flag isnot# 'save_file'
throw "fixing_flag must be either '' or 'save_file'"
endif
try
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
catch /E700\|BADNAME/
if a:fixing_flag isnot# '!'
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
\ l:function_name,
\)
execute 'echom l:echo_message'
endif
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
\ l:function_name,
\)
execute 'echom l:echo_message'
return 0
endtry
@@ -391,4 +389,3 @@ endfunction
augroup ALEBufferFixGroup
autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END

View File

@@ -160,11 +160,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with php-cs-fixer.',
\ },
\ 'astyle': {
\ 'function': 'ale#fixers#astyle#Fix',
\ 'suggested_filetypes': ['c', 'cpp'],
\ 'description': 'Fix C/C++ with astyle.',
\ },
\ 'clangtidy': {
\ 'function': 'ale#fixers#clangtidy#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'objc'],
@@ -365,21 +360,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['nix'],
\ 'description': 'A formatter for Nix code',
\ },
\ 'remark-lint': {
\ 'function': 'ale#fixers#remark_lint#Fix',
\ 'suggested_filetypes': ['markdown'],
\ 'description': 'Fix markdown files with remark-lint',
\ },
\ 'html-beautify': {
\ 'function': 'ale#fixers#html_beautify#Fix',
\ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.',
\ },
\ 'dhall': {
\ 'function': 'ale#fixers#dhall#Fix',
\ 'suggested_filetypes': ['dhall'],
\ 'description': 'Fix Dhall files with dhall-format.',
\ },
\}
" Reset the function registry to the default entries.

View File

@@ -1,59 +0,0 @@
" Author: James Kim <jhlink@users.noreply.github.com>
" Description: Fix C/C++ files with astyle.
function! s:set_variables() abort
for l:ft in ['c', 'cpp']
call ale#Set(l:ft . '_astyle_executable', 'astyle')
call ale#Set(l:ft . '_astyle_project_options', '')
endfor
endfunction
call s:set_variables()
function! ale#fixers#astyle#Var(buffer, name) abort
let l:ft = getbufvar(str2nr(a:buffer), '&filetype')
let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c'
return ale#Var(a:buffer, l:ft . '_astyle_' . a:name)
endfunction
" Try to find a project options file.
function! ale#fixers#astyle#FindProjectOptions(buffer) abort
let l:proj_options = ale#fixers#astyle#Var(a:buffer, 'project_options')
" If user has set project options variable then use it and skip any searching.
" This would allow users to use project files named differently than .astylerc.
if !empty(l:proj_options)
return l:proj_options
endif
" Try to find nearest .astylerc file.
let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '.astylerc'), ':t')
if !empty(l:proj_options)
return l:proj_options
endif
" Try to find nearest _astylerc file.
let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '_astylerc'), ':t')
if !empty(l:proj_options)
return l:proj_options
endif
" If no project options file is found return an empty string.
return ''
endfunction
function! ale#fixers#astyle#Fix(buffer) abort
let l:executable = ale#fixers#astyle#Var(a:buffer, 'executable')
let l:proj_options = ale#fixers#astyle#FindProjectOptions(a:buffer)
let l:command = ' --stdin=' . ale#Escape(expand('#' . a:buffer))
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:proj_options) ? '' : ' --project=' . l:proj_options)
\ . l:command
\}
endfunction

View File

@@ -1,23 +0,0 @@
" Author: Pat Brisbin <pbrisbin@gmail.com>
" Description: Integration of dhall-format with ALE.
call ale#Set('dhall_format_executable', 'dhall')
function! ale#fixers#dhall#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'dhall_format_executable')
" Dhall is written in Haskell and commonly installed with Stack
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall')
endfunction
function! ale#fixers#dhall#Fix(buffer) abort
let l:executable = ale#fixers#dhall#GetExecutable(a:buffer)
return {
\ 'command': l:executable
\ . ' format'
\ . ' --inplace'
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -3,6 +3,7 @@
function! ale#fixers#ktlint#Fix(buffer) abort
return {
\ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format'
\ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -10,7 +10,9 @@ function! ale#fixers#latexindent#Fix(buffer) abort
return {
\ 'command': ale#Escape(l:executable)
\ . ' -l'
\ . ' -l -w'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -5,13 +5,14 @@ call ale#Set('ocaml_ocamlformat_executable', 'ocamlformat')
call ale#Set('ocaml_ocamlformat_options', '')
function! ale#fixers#ocamlformat#Fix(buffer) abort
let l:filename = expand('#' . a:buffer . ':p')
let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable')
let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --name=%s'
\ . ' --name=' . ale#Escape(l:filename)
\ . ' -'
\}
endfunction

View File

@@ -34,21 +34,6 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output
endfunction
function! ale#fixers#prettier#GetProjectRoot(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
" Fall back to the directory of the buffer
return fnamemodify(bufname(a:buffer), ':p:h')
endfunction
function! ale#fixers#prettier#CdProjectRoot(buffer) abort
return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
@@ -112,7 +97,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
" 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(a:version, [1, 4, 0])
return {
\ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin',

View File

@@ -17,8 +17,8 @@ function! ale#fixers#prettier_standard#Fix(buffer) abort
return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
\ . ' --stdin'
\ . ' --stdin-filepath=%s'
\ . ' %t'
\ . ' ' . l:options,
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -1,24 +0,0 @@
" Author: blyoa <blyoa110@gmail.com>
" Description: Fixing files with remark-lint.
call ale#Set('markdown_remark_lint_executable', 'remark')
call ale#Set('markdown_remark_lint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_remark_lint_options', '')
function! ale#fixers#remark_lint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'markdown_remark_lint', [
\ 'node_modules/remark-cli/cli.js',
\ 'node_modules/.bin/remark',
\])
endfunction
function! ale#fixers#remark_lint#Fix(buffer) abort
let l:executable = ale#fixers#remark_lint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : ''),
\}
endfunction

View File

@@ -1,40 +1,20 @@
call ale#Set('ruby_rubocop_options', '')
call ale#Set('ruby_rubocop_auto_correct_all', 0)
call ale#Set('ruby_rubocop_executable', 'rubocop')
" Rubocop fixer outputs diagnostics first and then the fixed
" output. These are delimited by a "=======" string that we
" look for to remove everything before it.
function! ale#fixers#rubocop#PostProcess(buffer, output) abort
let l:line = 0
for l:output in a:output
let l:line = l:line + 1
if l:output =~# "^=\\+$"
break
endif
endfor
return a:output[l:line :]
endfunction
function! ale#fixers#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options')
let l:auto_correct_all = ale#Var(a:buffer, 'ruby_rubocop_auto_correct_all')
return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
\ . ' --force-exclusion --stdin %s'
\ . ' --auto-correct --force-exclusion %t'
endfunction
function! ale#fixers#rubocop#Fix(buffer) abort
return {
\ 'command': ale#fixers#rubocop#GetCommand(a:buffer),
\ 'process_with': 'ale#fixers#rubocop#PostProcess'
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -27,7 +27,7 @@ function! ale#fixers#standard#Fix(buffer) abort
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --fix --stdin < %s > %t',
\ . ' --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -16,7 +16,7 @@ function! ale#fixers#tslint#Fix(buffer) abort
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . l:tslint_config_option
\ . ' --outputAbsolutePaths --fix %t',
\ . ' --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -17,10 +17,3 @@ function! ale#handlers#ccls#GetProjectRoot(buffer) abort
" Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction
function! ale#handlers#ccls#GetInitOpts(buffer, init_options_var) abort
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
let l:init_options = empty(l:build_dir) ? {} : {'compilationDatabaseDirectory': l:build_dir}
return extend(l:init_options, ale#Var(a:buffer, a:init_options_var))
endfunction

View File

@@ -44,21 +44,16 @@ endfunction
function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort
" Look for lines like the following.
"
"test.cpp:974:6: error: Array 'n[3]' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\
" n[3]=3;
" ^
let l:pattern = '\v^(\f+):(\d+):(\d+): (\w+): (.*) \[(\w+)\]\'
" [test.cpp:5]: (error) Array 'a[10]' accessed at index 10, which is out of bounds
let l:pattern = '\v^\[(.+):(\d+)\]: \(([a-z]+)\) (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
if ale#path#IsBufferPath(a:buffer, l:match[1])
call add(l:output, {
\ 'lnum': str2nr(l:match[2]),
\ 'col': str2nr(l:match[3]),
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'sub_type': l:match[4] is# 'style' ? 'style' : '',
\ 'text': l:match[5],
\ 'code': l:match[6]
\ 'lnum': str2nr(l:match[2]),
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
\ 'text': l:match[4],
\})
endif
endfor

View File

@@ -10,7 +10,7 @@ let s:pragma_error = '#pragma once in main file'
" <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
" <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$'
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort
@@ -117,23 +117,6 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
if !empty(l:output)
if !has_key(l:output[-1], 'detail')
let l:output[-1].detail = l:output[-1].text
" handle macro expansion errors/notes
if l:match[5] =~? '^in expansion of macro \w*\w$'
" if the macro expansion is in the file we're in, add
" the lnum and col keys to the previous error
if l:match[1] is# '<stdin>'
\ && !has_key(l:output[-1], 'col')
let l:output[-1].lnum = str2nr(l:match[2])
let l:output[-1].col = str2nr(l:match[3])
else
" the error is not in the current file, and since
" macro expansion errors don't show the full path to
" the error from the current file, we have to just
" give out a generic error message
let l:output[-1].text = 'Error found in macro expansion. See :ALEDetail'
endif
endif
endif
let l:output[-1].detail = l:output[-1].detail . "\n"

View File

@@ -6,12 +6,9 @@
"
" Author: Ben Paxton <ben@gn32.uk>
" Description: moved to generic Golang file from govet
"
" Author: mostfunkyduck <mostfunkyduck@protonmail.com>
" Description: updated to work with go 1.14
function! ale#handlers#go#Handler(buffer, lines) abort
let l:pattern = '\v^%(vet: )?([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? ?(.+)$'
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? ?(.+)$'
let l:output = []
let l:dir = expand('#' . a:buffer . ':p:h')

View File

@@ -1,71 +0,0 @@
" Author: suoto <andre820@gmail.com>
" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
" or xvhdl. More info on https://github.com/suoto/hdl_checker
call ale#Set('hdl_checker_executable', 'hdl_checker')
call ale#Set('hdl_checker_config_file', has('unix') ? '.hdl_checker.config' : '_hdl_checker.config')
call ale#Set('hdl_checker_options', '')
" Use this as a function so we can mock it on testing. Need to do this because
" test files are inside /testplugin (which refers to the ale repo), which will
" always have a .git folder
function! ale#handlers#hdl_checker#IsDotGit(path) abort
return ! empty(a:path) && isdirectory(a:path)
endfunction
" Sould return (in order of preference)
" 1. Nearest config file
" 2. Nearest .git directory
" 3. The current path
function! ale#handlers#hdl_checker#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(
\ a:buffer,
\ ale#Var(a:buffer, 'hdl_checker_config_file'))
if !empty(l:project_root)
return fnamemodify(l:project_root, ':h')
endif
" Search for .git to use as root
let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
if ale#handlers#hdl_checker#IsDotGit(l:project_root)
return fnamemodify(l:project_root, ':h:h')
endif
endfunction
function! ale#handlers#hdl_checker#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'hdl_checker_executable')
endfunction
function! ale#handlers#hdl_checker#GetCommand(buffer) abort
let l:command = ale#Escape(ale#handlers#hdl_checker#GetExecutable(a:buffer)) . ' --lsp'
" Add extra parameters only if config has been set
let l:options = ale#Var(a:buffer, 'hdl_checker_options')
if ! empty(l:options)
let l:command = l:command . ' ' . l:options
endif
return l:command
endfunction
" To allow testing
function! ale#handlers#hdl_checker#GetInitOptions(buffer) abort
return {'project_file': ale#Var(a:buffer, 'hdl_checker_config_file')}
endfunction
" Define the hdl_checker linter for a given filetype.
function! ale#handlers#hdl_checker#DefineLinter(filetype) abort
call ale#linter#Define(a:filetype, {
\ 'name': 'hdl-checker',
\ 'lsp': 'stdio',
\ 'language': a:filetype,
\ 'executable': function('ale#handlers#hdl_checker#GetExecutable'),
\ 'command': function('ale#handlers#hdl_checker#GetCommand'),
\ 'project_root': function('ale#handlers#hdl_checker#GetProjectRoot'),
\ 'initialization_options': function('ale#handlers#hdl_checker#GetInitOptions'),
\ })
endfunction

View File

@@ -13,7 +13,7 @@ function! ale#handlers#ktlint#GetCommand(buffer) abort
return ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . (empty(l:rulesets) ? '' : ' ' . l:rulesets)
\ . ' --stdin'
\ . ' %t'
endfunction
function! ale#handlers#ktlint#GetRulesets(buffer) abort

View File

@@ -2,22 +2,15 @@
" Description: Adds support for markdownlint
function! ale#handlers#markdownlint#Handle(buffer, lines) abort
let l:pattern=': \?\(\d\+\)\(:\(\d\+\)\?\)\? \(MD\d\{3}/[A-Za-z0-9-/]\+\) \(.*\)$'
let l:pattern=': \(\d*\): \(MD\d\{3}\)\(\/\)\([A-Za-z0-9-]\+\)\(.*\)$'
let l:output=[]
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:result = ({
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'code': l:match[4],
\ 'text': l:match[5],
\ 'text': '(' . l:match[2] . l:match[3] . l:match[4] . ')' . l:match[5],
\ 'type': 'W',
\})
if len(l:match[3]) > 0
let l:result.col = (l:match[3] + 0)
endif
call add(l:output, l:result)
endfor
return l:output

View File

@@ -4,24 +4,17 @@
function! ale#handlers#sh#GetShellType(buffer) abort
let l:bang_line = get(getbufline(a:buffer, 1), 0, '')
let l:command = ''
" Take the shell executable from the hashbang, if we can.
if l:bang_line[:1] is# '#!'
" Remove options like -e, etc.
let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g')
endif
" If we couldn't find a hashbang, try the filetype
if l:command is# ''
let l:command = &filetype
for l:possible_shell in ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh']
if l:command =~# l:possible_shell . '\s*$'
return l:possible_shell
endif
endfor
endif
for l:possible_shell in ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh']
if l:command =~# l:possible_shell . '\s*$'
return l:possible_shell
endif
endfor
return ''
endfunction

View File

@@ -42,8 +42,6 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
\&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons')
call balloon_show(a:response.body.displayString)
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(split(a:response.body.displayString, "\n")[0])
elseif g:ale_hover_to_preview
call ale#preview#Show(split(a:response.body.displayString, "\n"), {
\ 'filetype': 'ale-preview.message',
@@ -56,137 +54,6 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
endif
endfunction
" Convert a language name to another one.
" The language name could be an empty string or v:null
function! s:ConvertLanguageName(language) abort
return a:language
endfunction
function! ale#hover#ParseLSPResult(contents) abort
let l:includes = {}
let l:highlights = []
let l:lines = []
let l:list = type(a:contents) is v:t_list ? a:contents : [a:contents]
let l:region_index = 0
for l:item in l:list
if !empty(l:lines)
call add(l:lines, '')
endif
if type(l:item) is v:t_dict && has_key(l:item, 'kind')
if l:item.kind is# 'markdown'
" Handle markdown values as we handle strings below.
let l:item = get(l:item, 'value', '')
elseif l:item.kind is# 'plaintext'
" We shouldn't try to parse plaintext as markdown.
" Pass the lines on and skip parsing them.
call extend(l:lines, split(get(l:item, 'value', ''), "\n"))
continue
endif
endif
let l:marked_list = []
" If the item is a string, then we should parse it as Markdown text.
if type(l:item) is v:t_string
let l:fence_language = v:null
let l:fence_lines = []
for l:line in split(l:item, "\n")
if l:fence_language is v:null
" Look for the start of a code fence. (```python, etc.)
let l:match = matchlist(l:line, '^```\(.*\)$')
if !empty(l:match)
let l:fence_language = l:match[1]
if !empty(l:marked_list)
call add(l:fence_lines, '')
endif
else
if !empty(l:marked_list)
\&& l:marked_list[-1][0] isnot v:null
call add(l:marked_list, [v:null, ['']])
endif
call add(l:marked_list, [v:null, [l:line]])
endif
elseif l:line =~# '^```$'
" When we hit the end of a code fence, pass the fenced
" lines on to the next steps below.
call add(l:marked_list, [l:fence_language, l:fence_lines])
let l:fence_language = v:null
let l:fence_lines = []
else
" Gather lines inside of a code fence.
call add(l:fence_lines, l:line)
endif
endfor
" If the result from the LSP server is a {language: ..., value: ...}
" Dictionary, then that should be interpreted as if it was:
"
" ```${language}
" ${value}
" ```
elseif type(l:item) is v:t_dict
\&& has_key(l:item, 'language')
\&& type(l:item.language) is v:t_string
\&& has_key(l:item, 'value')
\&& type(l:item.value) is v:t_string
call add(
\ l:marked_list,
\ [l:item.language, split(l:item.value, "\n")],
\)
endif
for [l:language, l:marked_lines] in l:marked_list
if l:language is v:null
" NOTE: We could handle other Markdown formatting here.
call map(
\ l:marked_lines,
\ 'substitute(v:val, ''\\_'', ''_'', ''g'')',
\)
else
let l:language = s:ConvertLanguageName(l:language)
if !empty(l:language)
let l:includes[l:language] = printf(
\ 'syntax/%s.vim',
\ l:language,
\)
let l:start = len(l:lines) + 1
let l:end = l:start + len(l:marked_lines)
let l:region_index += 1
call add(l:highlights, 'syntax region'
\ . ' ALE_hover_' . l:region_index
\ . ' start=/\%' . l:start . 'l/'
\ . ' end=/\%' . l:end . 'l/'
\ . ' contains=@ALE_hover_' . l:language
\)
endif
endif
call extend(l:lines, l:marked_lines)
endfor
endfor
let l:include_commands = []
for [l:language, l:lang_path] in sort(items(l:includes))
call add(l:include_commands, 'unlet! b:current_syntax')
call add(
\ l:include_commands,
\ printf('syntax include @ALE_hover_%s %s', l:language, l:lang_path),
\)
endfor
return [l:include_commands + l:highlights, l:lines]
endfunction
function! ale#hover#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:hover_map, a:response.id)
@@ -213,25 +80,37 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
return
endif
let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents)
let l:result = l:result.contents
if !empty(l:lines)
if get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons')
call balloon_show(join(l:lines, "\n"))
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(l:lines[0])
elseif g:ale_hover_to_preview
call ale#preview#Show(l:lines, {
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1,
\ 'commands': l:commands,
\})
else
call ale#util#ShowMessage(join(l:lines, "\n"), {
\ 'commands': l:commands,
\})
if type(l:result) is v:t_string
" The result can be just a string.
let l:result = [l:result]
endif
if type(l:result) is v:t_dict
" If the result is an object, then it's markup content.
let l:result = [l:result.value]
endif
if type(l:result) is v:t_list
" Replace objects with text values.
call map(l:result, 'type(v:val) is v:t_string ? v:val : v:val.value')
let l:str = join(l:result, "\n")
let l:str = substitute(l:str, '^\s*\(.\{-}\)\s*$', '\1', '')
if !empty(l:str)
if get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons')
call balloon_show(l:str)
elseif g:ale_hover_to_preview
call ale#preview#Show(split(l:str, "\n"), {
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1,
\})
else
call ale#util#ShowMessage(l:str)
endif
endif
endif
endif
@@ -264,10 +143,7 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
" hover position probably won't make sense.
call ale#lsp#NotifyForChanges(l:id, l:buffer)
let l:column = max([
\ min([a:column, len(getbufline(l:buffer, a:line)[0])]),
\ 1,
\])
let l:column = min([a:column, len(getbufline(l:buffer, a:line)[0])])
let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column)
endif
@@ -280,7 +156,6 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
\ 'column': l:column,
\ 'hover_from_balloonexpr': get(a:opt, 'called_from_balloonexpr', 0),
\ 'show_documentation': get(a:opt, 'show_documentation', 0),
\ 'truncated_echo': get(a:opt, 'truncated_echo', 0),
\}
endfunction
@@ -306,8 +181,6 @@ function! ale#hover#Show(buffer, line, col, opt) abort
endfor
endfunction
let s:last_pos = [0, 0, 0]
" This function implements the :ALEHover command.
function! ale#hover#ShowAtCursor() abort
let l:buffer = bufnr('')
@@ -316,25 +189,6 @@ function! ale#hover#ShowAtCursor() abort
call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], {})
endfunction
function! ale#hover#ShowTruncatedMessageAtCursor() abort
let l:buffer = bufnr('')
let l:pos = getpos('.')[0:2]
if l:pos != s:last_pos
let s:last_pos = l:pos
let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
if empty(l:loc)
call ale#hover#Show(
\ l:buffer,
\ l:pos[1],
\ l:pos[2],
\ {'truncated_echo': 1},
\)
endif
endif
endfunction
" This function implements the :ALEDocumentation command.
function! ale#hover#ShowDocumentationAtCursor() abort
let l:buffer = bufnr('')

View File

@@ -14,7 +14,6 @@ let s:default_ale_linter_aliases = {
\ 'csh': 'sh',
\ 'javascriptreact': ['javascript', 'jsx'],
\ 'plaintex': 'tex',
\ 'ps1': 'powershell',
\ 'rmarkdown': 'r',
\ 'rmd': 'r',
\ 'systemverilog': 'verilog',
@@ -32,7 +31,7 @@ let s:default_ale_linter_aliases = {
"
" No linters are used for plaintext files by default.
"
" Only cargo and rls are enabled for Rust by default.
" Only cargo is enabled for Rust by default.
" rpmlint is disabled by default because it can result in code execution.
" hhast is disabled by default because it executes code in the project root.
"
@@ -45,8 +44,8 @@ let s:default_ale_linters = {
\ 'help': [],
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo', 'rls'],
\ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'],
\ 'spec': [],
\ 'text': [],
\ 'vue': ['eslint', 'vls'],
@@ -77,6 +76,10 @@ function! s:IsBoolean(value) abort
return type(a:value) is v:t_number && (a:value == 0 || a:value == 1)
endfunction
function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) isnot v:t_dict
throw 'The linter object must be a Dictionary'
@@ -110,7 +113,14 @@ function! ale#linter#PreProcess(filetype, linter) abort
if !l:needs_executable
if has_key(a:linter, 'executable')
throw '`executable` cannot be used when lsp == ''socket'''
\|| has_key(a:linter, 'executable_callback')
throw '`executable` and `executable_callback` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'executable_callback')
let l:obj.executable_callback = a:linter.executable_callback
if !s:IsCallback(l:obj.executable_callback)
throw '`executable_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'executable')
let l:obj.executable = a:linter.executable
@@ -120,12 +130,54 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`executable` must be a String or Function if defined'
endif
else
throw '`executable` must be defined'
throw 'Either `executable` or `executable_callback` must be defined'
endif
if !l:needs_command
if has_key(a:linter, 'command')
throw '`command` cannot be used when lsp == ''socket'''
\|| has_key(a:linter, 'command_callback')
\|| has_key(a:linter, 'command_chain')
throw '`command` and `command_callback` and `command_chain` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'command_chain')
let l:obj.command_chain = a:linter.command_chain
if type(l:obj.command_chain) isnot v:t_list
throw '`command_chain` must be a List'
endif
if empty(l:obj.command_chain)
throw '`command_chain` must contain at least one item'
endif
let l:link_index = 0
for l:link in l:obj.command_chain
let l:err_prefix = 'The `command_chain` item ' . l:link_index . ' '
if !s:IsCallback(get(l:link, 'callback'))
throw l:err_prefix . 'must define a `callback` function'
endif
if has_key(l:link, 'output_stream')
if type(l:link.output_stream) isnot v:t_string
\|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0
throw l:err_prefix . '`output_stream` flag must be '
\ . "'stdout', 'stderr', or 'both'"
endif
endif
if has_key(l:link, 'read_buffer') && !s:IsBoolean(l:link.read_buffer)
throw l:err_prefix . 'value for `read_buffer` must be `0` or `1`'
endif
let l:link_index += 1
endfor
elseif has_key(a:linter, 'command_callback')
let l:obj.command_callback = a:linter.command_callback
if !s:IsCallback(l:obj.command_callback)
throw '`command_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'command')
let l:obj.command = a:linter.command
@@ -135,12 +187,22 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`command` must be a String or Function if defined'
endif
else
throw '`command` must be defined'
throw 'Either `command`, `executable_callback`, `command_chain` '
\ . 'must be defined'
endif
if (
\ has_key(a:linter, 'command')
\ + has_key(a:linter, 'command_chain')
\ + has_key(a:linter, 'command_callback')
\) > 1
throw 'Only one of `command`, `command_callback`, or `command_chain` '
\ . 'should be set'
endif
if !l:needs_address
if has_key(a:linter, 'address')
throw '`address` cannot be used when lsp != ''socket'''
if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback')
throw '`address` or `address_callback` cannot be used when lsp != ''socket'''
endif
elseif has_key(a:linter, 'address')
if type(a:linter.address) isnot v:t_string
@@ -149,17 +211,41 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
let l:obj.address = a:linter.address
elseif has_key(a:linter, 'address_callback')
let l:obj.address_callback = a:linter.address_callback
if !s:IsCallback(l:obj.address_callback)
throw '`address_callback` must be a callback if defined'
endif
else
throw '`address` must be defined for getting the LSP address'
throw '`address` or `address_callback` must be defined for getting the LSP address'
endif
if l:needs_lsp_details
" Default to using the filetype as the language.
let l:obj.language = get(a:linter, 'language', a:filetype)
if has_key(a:linter, 'language_callback')
if has_key(a:linter, 'language')
throw 'Only one of `language` or `language_callback` '
\ . 'should be set'
endif
if type(l:obj.language) isnot v:t_string
\&& type(l:obj.language) isnot v:t_func
throw '`language` must be a String or Funcref if defined'
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
else
" Default to using the filetype as the language.
let l:Language = get(a:linter, 'language', a:filetype)
if type(l:Language) is v:t_string
" Make 'language_callback' return the 'language' value.
let l:obj.language = l:Language
let l:obj.language_callback = function('s:LanguageGetter')
elseif type(l:Language) is v:t_func
let l:obj.language_callback = l:Language
else
throw '`language` must be a String or Funcref'
endif
endif
if has_key(a:linter, 'project_root')
@@ -167,10 +253,16 @@ function! ale#linter#PreProcess(filetype, linter) abort
if type(l:obj.project_root) isnot v:t_string
\&& type(l:obj.project_root) isnot v:t_func
throw '`project_root` must be a String or Function'
throw '`project_root` must be a String or Function if defined'
endif
elseif has_key(a:linter, 'project_root_callback')
let l:obj.project_root_callback = a:linter.project_root_callback
if !s:IsCallback(l:obj.project_root_callback)
throw '`project_root_callback` must be a callback if defined'
endif
else
throw '`project_root` must be defined for LSP linters'
throw '`project_root` or `project_root_callback` must be defined for LSP linters'
endif
if has_key(a:linter, 'completion_filter')
@@ -181,16 +273,37 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
endif
if has_key(a:linter, 'initialization_options')
if has_key(a:linter, 'initialization_options_callback')
if has_key(a:linter, 'initialization_options')
throw 'Only one of `initialization_options` or '
\ . '`initialization_options_callback` should be set'
endif
let l:obj.initialization_options_callback = a:linter.initialization_options_callback
if !s:IsCallback(l:obj.initialization_options_callback)
throw '`initialization_options_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
if type(l:obj.initialization_options) isnot v:t_dict
\&& type(l:obj.initialization_options) isnot v:t_func
throw '`initialization_options` must be a Dictionary or Function if defined'
throw '`initialization_options` must be a String or Function if defined'
endif
endif
if has_key(a:linter, 'lsp_config')
if has_key(a:linter, 'lsp_config_callback')
if has_key(a:linter, 'lsp_config')
throw 'Only one of `lsp_config` or `lsp_config_callback` should be set'
endif
let l:obj.lsp_config_callback = a:linter.lsp_config_callback
if !s:IsCallback(l:obj.lsp_config_callback)
throw '`lsp_config_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'lsp_config')
if type(a:linter.lsp_config) isnot v:t_dict
\&& type(a:linter.lsp_config) isnot v:t_func
throw '`lsp_config` must be a Dictionary or Function if defined'
@@ -211,17 +324,21 @@ function! ale#linter#PreProcess(filetype, linter) abort
" file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0)
if !s:IsBoolean(l:obj.lint_file) && type(l:obj.lint_file) isnot v:t_func
throw '`lint_file` must be `0`, `1`, or a Function'
if !s:IsBoolean(l:obj.lint_file)
throw '`lint_file` must be `0` or `1`'
endif
" An option indicating that the buffer should be read.
let l:obj.read_buffer = get(a:linter, 'read_buffer', 1)
let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file)
if !s:IsBoolean(l:obj.read_buffer)
throw '`read_buffer` must be `0` or `1`'
endif
if l:obj.lint_file && l:obj.read_buffer
throw 'Only one of `lint_file` or `read_buffer` can be `1`'
endif
let l:obj.aliases = get(a:linter, 'aliases', [])
if type(l:obj.aliases) isnot v:t_list
@@ -229,6 +346,14 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`aliases` must be a List of String values'
endif
for l:key in filter(keys(a:linter), 'v:val[-9:] is# ''_callback'' || v:val is# ''command_chain''')
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom l:key . '' is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
break
endfor
return l:obj
endfunction
@@ -394,19 +519,11 @@ function! ale#linter#Get(original_filetypes) abort
return reverse(l:combined_linters)
endfunction
function! ale#linter#RemoveIgnored(buffer, filetype, linters) 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')
return !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(a:filetype, a:linters, l:ignore_config, l:disable_lsp)
\ : a:linters
endfunction
" Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort
let l:Executable = a:linter.executable
let l:Executable = has_key(a:linter, 'executable_callback')
\ ? function(a:linter.executable_callback)
\ : a:linter.executable
return type(l:Executable) is v:t_func
\ ? l:Executable(a:buffer)
@@ -414,21 +531,24 @@ function! ale#linter#GetExecutable(buffer, linter) abort
endfunction
" Given a buffer and linter, get the command String for the linter.
" The command_chain key is not supported.
function! ale#linter#GetCommand(buffer, linter) abort
let l:Command = a:linter.command
let l:Command = has_key(a:linter, 'command_callback')
\ ? function(a:linter.command_callback)
\ : a:linter.command
return type(l:Command) is v:t_func ? l:Command(a:buffer) : l:Command
return type(l:Command) is v:t_func
\ ? l:Command(a:buffer)
\ : l:Command
endfunction
" Given a buffer and linter, get the address for connecting to the server.
function! ale#linter#GetAddress(buffer, linter) abort
let l:Address = a:linter.address
let l:Address = has_key(a:linter, 'address_callback')
\ ? function(a:linter.address_callback)
\ : a:linter.address
return type(l:Address) is v:t_func ? l:Address(a:buffer) : l:Address
endfunction
function! ale#linter#GetLanguage(buffer, linter) abort
let l:Language = a:linter.language
return type(l:Language) is v:t_func ? l:Language(a:buffer) : l:Language
return type(l:Address) is v:t_func
\ ? l:Address(a:buffer)
\ : l:Address
endfunction

View File

@@ -64,9 +64,6 @@ endfunction
" Used only in tests.
function! ale#lsp#GetConnections() abort
" This command will throw from the sandbox.
let &l:equalprg=&l:equalprg
return s:connections
endfunction
@@ -199,26 +196,14 @@ function! s:UpdateCapabilities(conn, capabilities) abort
let a:conn.capabilities.hover = 1
endif
if type(get(a:capabilities, 'hoverProvider')) is v:t_dict
let a:conn.capabilities.hover = 1
endif
if get(a:capabilities, 'referencesProvider') is v:true
let a:conn.capabilities.references = 1
endif
if type(get(a:capabilities, 'referencesProvider')) is v:t_dict
let a:conn.capabilities.references = 1
endif
if get(a:capabilities, 'renameProvider') is v:true
let a:conn.capabilities.rename = 1
endif
if type(get(a:capabilities, 'renameProvider')) is v:t_dict
let a:conn.capabilities.rename = 1
endif
if !empty(get(a:capabilities, 'completionProvider'))
let a:conn.capabilities.completion = 1
endif
@@ -235,25 +220,13 @@ function! s:UpdateCapabilities(conn, capabilities) abort
let a:conn.capabilities.definition = 1
endif
if type(get(a:capabilities, 'definitionProvider')) is v:t_dict
let a:conn.capabilities.definition = 1
endif
if get(a:capabilities, 'typeDefinitionProvider') is v:true
let a:conn.capabilities.typeDefinition = 1
endif
if type(get(a:capabilities, 'typeDefinitionProvider')) is v:t_dict
let a:conn.capabilities.typeDefinition = 1
endif
if get(a:capabilities, 'workspaceSymbolProvider') is v:true
let a:conn.capabilities.symbol_search = 1
endif
if type(get(a:capabilities, 'workspaceSymbolProvider')) is v:t_dict
let a:conn.capabilities.symbol_search = 1
endif
endfunction
" Update a connection's configuration dictionary and notify LSP servers
@@ -452,7 +425,6 @@ function! ale#lsp#StartProgram(conn_id, executable, command) abort
endif
if l:started && !l:conn.is_tsserver
let l:conn.initialized = 0
call s:SendInitMessage(l:conn)
endif

View File

@@ -34,11 +34,7 @@ endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:escaped_name = escape(
\ fnameescape(l:filename),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:buffer = bufnr('^' . l:filename . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
@@ -56,11 +52,7 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver'
let l:escaped_name = escape(
\ fnameescape(a:response.body.file),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:buffer = bufnr('^' . a:response.body.file . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
@@ -235,7 +227,7 @@ function! ale#lsp_linter#OnInit(linter, details, Callback) abort
let l:command = a:details.command
let l:config = ale#lsp_linter#GetConfig(l:buffer, a:linter)
let l:language_id = ale#linter#GetLanguage(l:buffer, a:linter)
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(l:buffer)
call ale#lsp#UpdateConfig(l:conn_id, l:buffer, l:config)
@@ -273,14 +265,7 @@ function! s:StartLSP(options, address, executable, command) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif
let l:command = ale#command#FormatCommand(
\ l:buffer,
\ a:executable,
\ a:command,
\ 0,
\ v:false,
\ [],
\)[1]
let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif

View File

@@ -24,14 +24,6 @@ function! ale#path#Simplify(path) abort
return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks
endfunction
" Simplify a path without a Windows drive letter.
" This function can be used for checking if paths are equal.
function! ale#path#RemoveDriveLetter(path) abort
return has('win32') && a:path[1:2] is# ':\'
\ ? ale#path#Simplify(a:path[2:])
\ : ale#path#Simplify(a:path)
endfunction
" Given a buffer and a filename, find the nearest file by searching upwards
" through the paths relative to the given buffer.
function! ale#path#FindNearestFile(buffer, filename) abort
@@ -82,19 +74,15 @@ endfunction
function! ale#path#CdString(directory) abort
if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && '
else
return 'cd ' . ale#Escape(a:directory) . ' && '
endif
return 'cd ' . ale#Escape(a:directory) . ' && '
endfunction
" Output 'cd <buffer_filename_directory> && '
" This function can be used changing the directory for a linter command.
function! ale#path#BufferCdString(buffer) abort
if has('win32')
return 'cd /d %s:h && '
endif
return 'cd %s:h && '
return ale#path#CdString(fnamemodify(bufname(a:buffer), ':p:h'))
endfunction
" Return 1 if a path is an absolute path.
@@ -107,7 +95,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h'))
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h'))
" Given a filename, return 1 if the file represents some temporary file
" created by Vim.

View File

@@ -1,22 +1,14 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Preview windows for showing whatever information in.
if !has_key(s:, 'last__list')
let s:last_list = []
if !has_key(s:, 'last_selection_list')
let s:last_selection_list = []
endif
if !has_key(s:, 'last_options')
let s:last_options = {}
if !has_key(s:, 'last_selection_open_in')
let s:last_selection_open_in = 'current-buffer'
endif
function! ale#preview#SetLastSelection(item_list, options) abort
let s:last_list = a:item_list
let s:last_options = {
\ 'open_in': get(a:options, 'open_in', 'current-buffer'),
\ 'use_relative_paths': get(a:options, 'use_relative_paths', 0),
\}
endfunction
" Open a preview window and show some lines in it.
" A second argument can be passed as a Dictionary with options. They are...
"
@@ -39,10 +31,6 @@ function! ale#preview#Show(lines, ...) abort
setlocal readonly
let &l:filetype = get(l:options, 'filetype', 'ale-preview')
for l:command in get(l:options, 'commands', [])
call execute(l:command)
endfor
if get(l:options, 'stay_here')
wincmd p
endif
@@ -89,14 +77,19 @@ function! ale#preview#ShowSelection(item_list, ...) abort
let b:ale_preview_item_list = a:item_list
let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer')
" Remember preview state, so we can repeat it later.
call ale#preview#SetLastSelection(a:item_list, l:options)
" Remove the last preview
let s:last_selection_list = b:ale_preview_item_list
let s:last_selection_open_in = b:ale_preview_item_open_in
endfunction
function! ale#preview#RepeatSelection() abort
if !empty(s:last_list)
call ale#preview#ShowSelection(s:last_list, s:last_options)
if empty(s:last_selection_list)
return
endif
call ale#preview#ShowSelection(s:last_selection_list, {
\ 'open_in': s:last_selection_open_in,
\})
endfunction
function! s:Open(open_in) abort

View File

@@ -83,31 +83,6 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
\}, v:true)
endfunction
function! s:getChanges(workspace_edit) abort
let l:changes = {}
if has_key(a:workspace_edit, 'changes') && !empty(a:workspace_edit.changes)
return a:workspace_edit.changes
elseif has_key(a:workspace_edit, 'documentChanges')
let l:document_changes = []
if type(a:workspace_edit.documentChanges) is v:t_dict
\ && has_key(a:workspace_edit.documentChanges, 'edits')
call add(l:document_changes, a:workspace_edit.documentChanges)
elseif type(a:workspace_edit.documentChanges) is v:t_list
let l:document_changes = a:workspace_edit.documentChanges
endif
for l:text_document_edit in l:document_changes
let l:filename = l:text_document_edit.textDocument.uri
let l:edits = l:text_document_edit.edits
let l:changes[l:filename] = l:edits
endfor
endif
return l:changes
endfunction
function! ale#rename#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:rename_map, a:response.id)
@@ -119,9 +94,9 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
return
endif
let l:changes_map = s:getChanges(a:response.result)
let l:workspace_edit = a:response.result
if empty(l:changes_map)
if !has_key(l:workspace_edit, 'changes') || empty(l:workspace_edit.changes)
call s:message('No changes received from server')
return
@@ -129,8 +104,8 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
let l:changes = []
for l:file_name in keys(l:changes_map)
let l:text_edits = l:changes_map[l:file_name]
for l:file_name in keys(l:workspace_edit.changes)
let l:text_edits = l:workspace_edit.changes[l:file_name]
let l:text_changes = []
for l:edit in l:text_edits

View File

@@ -145,8 +145,8 @@ function! ale#test#WaitForJobs(deadline) abort
" end, but before handlers are run.
sleep 10ms
" We must check the buffer data again to see if new jobs started for
" linters with chained commands.
" We must check the buffer data again to see if new jobs started
" for command_chain linters.
let l:has_new_jobs = 0
" Check again to see if any jobs are running.

View File

@@ -1,18 +1,9 @@
function! s:EncodeChar(char) abort
let l:result = ''
for l:index in range(strlen(a:char))
let l:result .= printf('%%%02x', char2nr(a:char[l:index]))
endfor
return l:result
endfunction
" This probably doesn't handle Unicode characters well.
function! ale#uri#Encode(value) abort
return substitute(
\ a:value,
\ '\([^a-zA-Z0-9\\/$\-_.!*''(),]\)',
\ '\=s:EncodeChar(submatch(1))',
\ '\=printf(''%%%02x'', char2nr(submatch(1)))',
\ 'g'
\)
endfunction
@@ -21,7 +12,7 @@ function! ale#uri#Decode(value) abort
return substitute(
\ a:value,
\ '%\(\x\x\)',
\ '\=printf("%c", str2nr(submatch(1), 16))',
\ '\=nr2char(''0x'' . submatch(1))',
\ 'g'
\)
endfunction

View File

@@ -16,9 +16,7 @@ endfunction
" Vim 8 does not support echoing long messages from asynchronous callbacks,
" but NeoVim does. Small messages can be echoed in Vim 8, and larger messages
" have to be shown in preview windows.
function! ale#util#ShowMessage(string, ...) abort
let l:options = get(a:000, 0, {})
function! ale#util#ShowMessage(string) abort
if !has('nvim')
call ale#preview#CloseIfTypeMatches('ale-preview.message')
endif
@@ -27,13 +25,10 @@ function! ale#util#ShowMessage(string, ...) abort
if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns)
execute 'echo a:string'
else
call ale#preview#Show(split(a:string, "\n"), extend(
\ {
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1,
\ },
\ l:options,
\))
call ale#preview#Show(split(a:string, "\n"), {
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1,
\})
endif
endfunction
@@ -423,10 +418,7 @@ function! ale#util#Writefile(buffer, lines, filename) abort
\ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines
" Set binary flag if buffer doesn't have eol and nofixeol to avoid appending newline
let l:flags = !getbufvar(a:buffer, '&eol') && exists('+fixeol') && !&fixeol ? 'bS' : 'S'
call writefile(l:corrected_lines, a:filename, l:flags) " no-custom-checks
call writefile(l:corrected_lines, a:filename, 'S') " no-custom-checks
endfunction
if !exists('s:patial_timers')

View File

@@ -1,36 +1,22 @@
===============================================================================
ALE C Integration *ale-c-options*
For basic checking of problems with C files, ALE offers the `cc` linter, which
runs either `clang`, or `gcc`. See |ale-c-cc|.
===============================================================================
Global Options
g:ale_c_always_make *g:ale_c_always_make*
*b:ale_c_always_make*
Type: |Number|
Default: `has('unix') && !has('macunix')`
If set to `1`, use `--always-make` for `make`, which means that output will
always be parsed from `make` dry runs with GNU make. BSD `make` does not
support this option, so you probably want to turn this option off when using
a BSD variant.
g:ale_c_build_dir_names *g:ale_c_build_dir_names*
*b:ale_c_build_dir_names*
Type: |List|
Default: `['build', 'bin']`
A list of directory names to be used when searching upwards from cpp files
to discover compilation databases with. For directory named `'foo'`, ALE
will search for `'foo/compile_commands.json'` in all directories on and
above the directory containing the cpp file to find path to compilation
database. This feature is useful for the clang tools wrapped around
LibTooling (namely here, clang-tidy)
A list of directory names to be used when searching upwards from cpp
files to discover compilation databases with. For directory named `'foo'`,
ALE will search for `'foo/compile_commands.json'` in all directories on and above
the directory containing the cpp file to find path to compilation database.
This feature is useful for the clang tools wrapped around LibTooling (namely
here, clang-tidy)
g:ale_c_build_dir *g:ale_c_build_dir*
@@ -51,7 +37,7 @@ g:ale_c_build_dir *g:ale_c_build_dir*
g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
*b:ale_c_parse_compile_commands*
Type: |Number|
Default: `1`
Default: `0`
If set to `1`, ALE will parse `compile_commands.json` files to automatically
determine flags for C or C++ compilers. ALE will first search for the
@@ -59,6 +45,9 @@ g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
`compile_commands.json` files in the directories for
|g:ale_c_build_dir_names|.
If |g:ale_c_parse_makefile| or |b:ale_c_parse_makefile| is set to `1`, the
output of `make -n` will be preferred over `compile_commands.json` files.
g:ale_c_parse_makefile *g:ale_c_parse_makefile*
*b:ale_c_parse_makefile*
@@ -69,102 +58,24 @@ g:ale_c_parse_makefile *g:ale_c_parse_makefile*
set for C or C++ compilers. This can make it easier to determine the correct
build flags to use for different files.
NOTE: When using this option on BSD, you may need to set
|g:ale_c_always_make| to `0`, and `make -n` will not provide consistent
results if binaries have already been built, so use `make clean` when
editing your files.
WARNING: Running `make -n` automatically can execute arbitrary code, even
though it's supposed to be a dry run, so enable this option with care. You
might prefer to use the buffer-local version of the option instead with
|g:ale_pattern_options|, or you own code for checking which project you're
in.
You might want to disable this option if `make -n` takes too long to run for
projects you work on.
If |g:ale_c_parse_compile_commands| or |b:ale_c_parse_compile_commands| is
set to `1`, flags taken from `compile_commands.json` will be preferred over
`make -n` output.
===============================================================================
astyle *ale-c-astyle*
clang *ale-c-clang*
g:ale_c_astyle_executable *g:ale_c_astyle_executable*
*b:ale_c_astyle_executable*
g:ale_c_clang_executable *g:ale_c_clang_executable*
*b:ale_c_clang_executable*
Type: |String|
Default: `'astyle'`
Default: `'clang'`
This variable can be changed to use a different executable for astyle.
This variable can be changed to use a different executable for clang.
g:ale_c_astyle_project_options *g:ale_c_astyle_project_options*
*b:ale_c_astyle_project_options*
Type: |String|
Default: `''`
This variable can be changed to use an option file for project level
configurations. Provide only the filename of the option file that should be
present at the project's root directory.
For example, if .astylrc is specified, the file is searched in the parent
directories of the source file's directory.
===============================================================================
cc *ale-c-cc*
*ale-c-gcc*
*ale-c-clang*
g:ale_c_cc_executable *g:ale_c_cc_executable*
*b:ale_c_cc_executable*
Type: |String|
Default: `'<auto>'`
This variable can be changed to use a different executable for a C compiler.
ALE will try to use `clang` if Clang is available, otherwise ALE will
default to checking C code with `gcc`.
g:ale_c_cc_options *g:ale_c_cc_options*
*b:ale_c_cc_options*
g:ale_c_clang_options *g:ale_c_clang_options*
*b:ale_c_clang_options*
Type: |String|
Default: `'-std=c11 -Wall'`
This variable can be change to modify flags given to the C compiler.
===============================================================================
ccls *ale-c-ccls*
g:ale_c_ccls_executable *g:ale_c_ccls_executable*
*b:ale_c_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_c_ccls_init_options *g:ale_c_ccls_init_options*
*b:ale_c_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
This variable can be changed to modify flags given to clang.
===============================================================================
@@ -349,6 +260,25 @@ g:ale_c_flawfinder_error_severity *g:ale_c_flawfinder_error_severity*
error. This setting also applies to flawfinder for c++.
===============================================================================
gcc *ale-c-gcc*
g:ale_c_gcc_executable *g:ale_c_gcc_executable*
*b:ale_c_gcc_executable*
Type: |String|
Default: `'gcc'`
This variable can be changed to use a different executable for gcc.
g:ale_c_gcc_options *g:ale_c_gcc_options*
*b:ale_c_gcc_options*
Type: |String|
Default: `'-std=c11 -Wall'`
This variable can be change to modify flags given to gcc.
===============================================================================
uncrustify *ale-c-uncrustify*
@@ -368,5 +298,36 @@ g:ale_c_uncrustify_options *g:ale_c_uncrustify_options*
This variable can be change to modify flags given to uncrustify.
===============================================================================
ccls *ale-c-ccls*
g:ale_c_ccls_executable *g:ale_c_ccls_executable*
*b:ale_c_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_c_ccls_init_options *g:ale_c_ccls_init_options*
*b:ale_c_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -7,40 +7,8 @@ cfn-python-lint *ale-cloudformation-cfn-python-lint*
cfn-python-lint is a linter for AWS CloudFormation template file.
Website: https://github.com/awslabs/cfn-python-lint
https://github.com/awslabs/cfn-python-lint
Installation
-------------------------------------------------------------------------------
Install cfn-python-lint using either pip or brew: >
`pip install cfn-lint`. If pip is not available, run
`python setup.py clean --all` then `python setup.py install`.
Homebrew (macOS):
`brew install cfn-lint`
<
Configuration
-------------------------------------------------------------------------------
To get cloudformation linter to work on only CloudFormation files we must set
the buffer |filetype| to yaml.cloudformation.
This causes ALE to lint the file with linters configured for cloudformation and
yaml files.
Just put:
>
au BufRead,BufNewFile *.template.yaml set filetype=yaml.cloudformation
<
on `ftdetect/cloudformation.vim`
This will get both cloudformation and yaml linters to work on any file with `.template.yaml` ext.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -1,16 +1,12 @@
===============================================================================
ALE C++ Integration *ale-cpp-options*
For basic checking of problems with C++ files, ALE offers the `cc` linter,
which runs either `clang++`, or `gcc`. See |ale-cpp-cc|.
===============================================================================
Global Options
The following C options also apply to some C++ linters too.
* |g:ale_c_always_make|
* |g:ale_c_build_dir_names|
* |g:ale_c_build_dir|
* |g:ale_c_parse_makefile|
@@ -18,82 +14,41 @@ The following C options also apply to some C++ linters too.
===============================================================================
astyle *ale-cpp-astyle*
clang *ale-cpp-clang*
g:ale_cpp_astyle_executable *g:ale_cpp_astyle_executable*
*b:ale_cpp_astyle_executable*
g:ale_cpp_clang_executable *g:ale_cpp_clang_executable*
*b:ale_cpp_clang_executable*
Type: |String|
Default: `'astyle'`
Default: `'clang++'`
This variable can be changed to use a different executable for astyle.
This variable can be changed to use a different executable for clang.
g:ale_cpp_astyle_project_options *g:ale_cpp_astyle_project_options*
*b:ale_cpp_astyle_project_options*
Type: |String|
Default: `''`
This variable can be changed to use an option file for project level
configurations. Provide only the filename of the option file that should be
present at the project's root directory.
For example, if .astylrc is specified, the file is searched in the parent
directories of the source file's directory.
===============================================================================
cc *ale-cpp-cc*
*ale-cpp-gcc*
*ale-cpp-clang*
g:ale_cpp_cc_executable *g:ale_cpp_cc_executable*
*b:ale_cpp_cc_executable*
Type: |String|
Default: `'<auto>'`
This variable can be changed to use a different executable for a C++ compiler.
ALE will try to use `clang++` if Clang is available, otherwise ALE will
default to checking C++ code with `gcc`.
g:ale_cpp_cc_options *g:ale_cpp_cc_options*
*b:ale_cpp_cc_options*
g:ale_cpp_clang_options *g:ale_cpp_clang_options*
*b:ale_cpp_clang_options*
Type: |String|
Default: `'-std=c++14 -Wall'`
This variable can be change to modify flags given to the C++ compiler.
This variable can be changed to modify flags given to clang.
===============================================================================
ccls *ale-cpp-ccls*
clangd *ale-cpp-clangd*
g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
*b:ale_cpp_ccls_executable*
g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
*b:ale_cpp_clangd_executable*
Type: |String|
Default: `'ccls'`
Default: `'clangd'`
This variable can be changed to use a different executable for ccls.
This variable can be changed to use a different executable for clangd.
g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
*b:ale_cpp_ccls_init_options*
Type: |Dictionary|
Default: `{}`
g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
*b:ale_cpp_clangd_options*
Type: |String|
Default: `''`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
This variable can be changed to modify flags given to clangd.
===============================================================================
@@ -127,25 +82,6 @@ g:ale_cpp_clangcheck_options *g:ale_cpp_clangcheck_options*
option.
===============================================================================
clangd *ale-cpp-clangd*
g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
*b:ale_cpp_clangd_executable*
Type: |String|
Default: `'clangd'`
This variable can be changed to use a different executable for clangd.
g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
*b:ale_cpp_clangd_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to clangd.
===============================================================================
clang-format *ale-cpp-clangformat*
@@ -335,11 +271,61 @@ g:ale_cpp_flawfinder_options *g:ale-cpp-flawfinder*
This variable can be used to pass extra options into the flawfinder command.
===============================================================================
gcc *ale-cpp-gcc*
g:ale_cpp_gcc_executable *g:ale_cpp_gcc_executable*
*b:ale_cpp_gcc_executable*
Type: |String|
Default: `'gcc'`
This variable can be changed to use a different executable for gcc.
g:ale_cpp_gcc_options *g:ale_cpp_gcc_options*
*b:ale_cpp_gcc_options*
Type: |String|
Default: `'-std=c++14 -Wall'`
This variable can be changed to modify flags given to gcc.
===============================================================================
uncrustify *ale-cpp-uncrustify*
See |ale-c-uncrustify| for information about the available options.
===============================================================================
ccls *ale-cpp-ccls*
g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
*b:ale_cpp_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
*b:ale_cpp_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

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