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 # Stop git from changing newlines
- git config --global core.autocrlf input - 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: install:
# Download and unpack Vim # Download and unpack Vim
- ps: >- - 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 !.editorconfig
*.obj *.obj
*.pyc
# Ignore all hidden files everywhere. # Ignore all hidden files everywhere.
# Use `git add -f` to add hidden files. # Use `git add -f` to add hidden files.
.* .*
__pycache__
*.pyc
/doc/tags /doc/tags
/init.vim /init.vim
/test/ale-info-test-file /test/ale-info-test-file
/vader_output
__pycache__
tags 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. All rights reserved.
Redistribution and use in source and binary forms, with or without 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) 4. [Contributing](#contributing)
5. [FAQ](#faq) 5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters) 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) 2. [How can I keep the sign gutter open?](#faq-keep-signs)
3. [How can I use ALE and coc.nvim together?](#faq-coc-nvim) 3. [How can I change the signs ALE uses?](#faq-change-signs)
4. [How can I keep the sign gutter open?](#faq-keep-signs) 4. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
5. [How can I change the signs ALE uses?](#faq-change-signs) 5. [How can I show errors or warnings in my statusline?](#faq-statusline)
6. [How can I change or disable the highlights ALE uses?](#faq-change-highlights) 6. [How can I show errors or warnings in my lightline?](#faq-lightline)
7. [How can I show errors or warnings in my statusline?](#faq-statusline) 7. [How can I change the format for echo messages?](#faq-echo-format)
8. [How can I show errors or warnings in my lightline?](#faq-lightline) 8. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
9. [How can I change the format for echo messages?](#faq-echo-format) 9. [How can I navigate between errors quickly?](#faq-navigation)
10. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd) 10. [How can I run linters only when I save files?](#faq-lint-on-save)
11. [How can I navigate between errors quickly?](#faq-navigation) 11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
12. [How can I run linters only when I save files?](#faq-lint-on-save) 12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
13. [How can I use the quickfix list instead of the loclist?](#faq-quickfix) 13. [How can I check Vue files with ESLint?](#faq-vue-eslint)
14. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint) 14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
15. [How can I check Vue files with ESLint?](#faq-vue-eslint) 15. [How can I configure my C or C++ project?](#faq-c-configuration)
16. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad) 16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
17. [How can I configure my C or C++ project?](#faq-c-configuration) 17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration) 18. [How can I see what ALE has configured for the current file?](#faq-get-info)
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)
<a name="supported-languages"></a> <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 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. 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 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 options ALE offers, consult `:help ale-options` for global options and `:help
ale-integration-options` for options specified to particular linters. 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 set omnifunc=ale#completion#OmniFunc
``` ```
ALE supports automatic imports from external modules. This behavior is disabled When working with TypeScript files, ALE supports automatic imports from
by default and can be enabled by setting: external modules. This behavior is disabled by default and can be enabled by
setting:
```vim ```vim
let g:ale_completion_autoimport = 1 let g:ale_completion_tsserver_autoimport = 1
``` ```
See `:help ale-completion` for more information. 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 the cursor taken from Language Server Protocol linters and `tsserver` with the
`ALEHover` command. `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 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, hovering your mouse over symbols. Mouse hovering is enabled by default in GVim,
and needs to be configured for Vim 8.1+ in terminals. 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 Each directory within corresponds to a particular filetype in Vim, and each file
in each directory corresponds to the name of a particular linter. 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> <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 You can keep the sign gutter open at all times by setting the
`g:ale_sign_column_always` to 1 `g:ale_sign_column_always` to 1
@@ -477,7 +426,7 @@ let g:ale_sign_column_always = 1
<a name="faq-change-signs"></a> <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: 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> <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`, ALE's highlights problems with highlight groups which link to `SpellBad`,
`SpellCap`, `error`, and `todo` groups by default. The characters that are `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> <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 [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 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> <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 [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). 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> <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. 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> <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) 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 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> <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 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 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> <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 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 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> <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` 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 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> <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 If you configure ALE options correctly in your vimrc file, and install
the right tools, you can check JSX files with stylelint and eslint. 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> <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 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). 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> <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 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 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 type, and this delay can be increased so linters are run less often. See
`:help g:ale_lint_delay` for more information. `: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 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 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. 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> <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 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 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 `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. 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 You may also configure buffer-local settings for linters with project-specific
vimrc files. [local_vimrc](https://github.com/LucHermitte/local_vimrc) can be 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. used for executing local vimrc files which can be shared in your project.
<a name="faq-buffer-configuration"></a> <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 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 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> <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. 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 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 Run the following to see what is currently configured:
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 ```vim
correct commands and map filename paths between different file systems. See :ALEInfo
`:help ale-lint-other-machines` for the full documentation on how to configure ```
ALE to support this.

View File

@@ -18,7 +18,7 @@ function! ale_linters#ada#gcc#GetCommand(buffer) abort
" -gnatc: Check syntax and semantics only (no code generation attempted) " -gnatc: Check syntax and semantics only (no code generation attempted)
return '%e -x ada -c -gnatc' return '%e -x ada -c -gnatc'
\ . ' -o ' . ale#Escape(l:out_file) \ . ' -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')) \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
\ . ' %t' \ . ' %t'
endfunction 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. " -fsyntax-only doesn't catch everything.
return '%e -x assembler' return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file \ . ' -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') . ' -' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction 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_executable', 'ccls')
call ale#Set('c_ccls_init_options', {}) call ale#Set('c_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('c', { call ale#linter#Define('c', {
\ 'name': 'ccls', \ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('c', {
\ 'executable': {b -> ale#Var(b, 'c_ccls_executable')}, \ 'executable': {b -> ale#Var(b, 'c_ccls_executable')},
\ 'command': '%e', \ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ '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) let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : '' \ : ''
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command return l:cd_command
\ . '%e -q --language=c' \ . '%e -q --language=c'
\ . l:template
\ . ale#Pad(l:compile_commands_option) \ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options')) \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . l:buffer_path_include \ . 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_executable', 'ccls')
call ale#Set('cpp_ccls_init_options', {}) call ale#Set('cpp_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'ccls', \ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('cpp', {
\ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')}, \ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')},
\ 'command': '%e', \ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ '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 let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
endif 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 " Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options') 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) let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : '' \ : ''
let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command return l:cd_command
\ . '%e -q --language=c++' \ . '%e -q --language=c++'
\ . l:template
\ . ale#Pad(l:compile_commands_option) \ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options')) \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . l:buffer_path_include \ . 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') call ale#Set('cuda_nvcc_options', '-std=c++11')
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort 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' return '%e -cuda'
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))) \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options')) \ . 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:line = get(l:object, 'line', -1)
let l:message = l:object['message'] 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' 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 endif
let l:detail .= "\n\n" . l:link
call add(l:messages, { call add(l:messages, {
\ 'lnum': l:line, \ 'lnum': l:line,
\ 'text': l:message, \ 'text': l:message,
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type), \ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
\ 'detail': l:detail,
\}) \})
endfor endfor
endfor endfor

View File

@@ -46,7 +46,7 @@ function! ale_linters#elixir#credo#GetMode() abort
endfunction endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort 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() let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root) 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') return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options') \ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin %s' \ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction endfunction
function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort 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' \ . '%e -e %t'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gofmt', \ 'name': 'gofmt',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View File

@@ -4,28 +4,6 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint') call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0)) 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 function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = [] let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@@ -52,9 +30,10 @@ function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
endfunction endfunction
call ale#linter#Define('handlebars', { call ale#linter#Define('handlebars', {
\ 'name': 'embertemplatelint', \ 'name': 'ember-template-lint',
\ 'aliases': ['ember-template-lint'], \ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [
\ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'), \ 'node_modules/.bin/ember-template-lint',
\ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'), \ ])},
\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle', \ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\}) \})

View File

@@ -52,7 +52,7 @@ endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort function! ale_linters#java#checkstyle#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'java_checkstyle_options') let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config') let l:config_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) \ ? s:GetConfig(a:buffer, l:config_option)
\ : '' \ : ''

View File

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

View File

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

View File

@@ -1,22 +1,11 @@
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com> " Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
" Description: Adds support for markdownlint " 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', { call ale#linter#Define('markdown', {
\ 'name': 'markdownlint', \ 'name': 'markdownlint',
\ 'executable': 'markdownlint', \ 'executable': 'markdownlint',
\ 'lint_file': 1, \ 'lint_file': 1,
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'), \ 'command': 'markdownlint %s',
\ 'callback': 'ale#handlers#markdownlint#Handle' \ '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 function! ale_linters#nasm#nasm#GetCommand(buffer) abort
" Note that NASM requires a trailing slash for the -I option. " Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/' 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' 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')) \ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s' \ . ' %s'
\ . ' -o ' . l:output_null \ . ' -o ' . l:output_null

View File

@@ -3,7 +3,6 @@
call ale#Set('objc_ccls_executable', 'ccls') call ale#Set('objc_ccls_executable', 'ccls')
call ale#Set('objc_ccls_init_options', {}) call ale#Set('objc_ccls_init_options', {})
call ale#Set('c_build_dir', '')
call ale#linter#Define('objc', { call ale#linter#Define('objc', {
\ 'name': 'ccls', \ 'name': 'ccls',
@@ -11,5 +10,5 @@ call ale#linter#Define('objc', {
\ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')}, \ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')},
\ 'command': '%e', \ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ '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 " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return 'clang -S -x objective-c -fsyntax-only ' 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') . ' -' \ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -'
endfunction 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 " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return 'clang++ -S -x objective-c++ -fsyntax-only ' 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') . ' -' \ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -'
endfunction endfunction

View File

@@ -9,6 +9,6 @@ call ale#linter#Define('ocaml', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ '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'), \ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\}) \})

View File

@@ -1,9 +1,9 @@
" Author: Matt Brown <https://github.com/muglug> " Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP " Description: plugin for Psalm, static analyzer for PHP
call ale#Set('php_psalm_executable', 'psalm') call ale#Set('psalm_langserver_executable', 'psalm')
call ale#Set('php_psalm_options', '') call ale#Set('psalm_langserver_options', '')
call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@@ -12,13 +12,13 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
endfunction endfunction
function! ale_linters#php#psalm#GetCommand(buffer) abort 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 endfunction
call ale#linter#Define('php', { call ale#linter#Define('php', {
\ 'name': 'psalm', \ 'name': 'psalm',
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [ \ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
\ 'vendor/bin/psalm', \ 'vendor/bin/psalm',
\ ])}, \ ])},
\ 'command': function('ale_linters#php#psalm#GetCommand'), \ '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 ':' 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 '='; 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: 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) let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
" 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:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[5] + 0, \ 'lnum': l:match[4] + 0,
\ 'col': l:match[7] + 0, \ 'col': l:match[6] + 0,
\ 'text': l:match[1], \ 'text': l:match[1],
\}) \})
endfor endfor

View File

@@ -6,7 +6,9 @@ call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra') call ale#Set('pyrex_cython_options', '--warning-extra')
function! ale_linters#pyrex#cython#GetCommand(buffer) abort 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')) \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction endfunction

View File

@@ -4,7 +4,7 @@
call ale#Set('python_flake8_executable', 'flake8') call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '') 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_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) call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort function! s:UsingModule(buffer) abort
@@ -38,30 +38,10 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
\) \)
endfunction 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 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:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'

View File

@@ -16,15 +16,17 @@ function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#python#pydocstyle#GetCommand(buffer) abort 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:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pydocstyle' \ ? ' run pydocstyle'
\ : '' \ : ''
return ale#path#BufferCdString(a:buffer) return ale#path#CdString(l:dir)
\ . ale#Escape(l:executable) . l:exec_args \ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options')) \ . ' ' . ale#Var(a:buffer, 'python_pydocstyle_options')
\ . ' %s:t' \ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:t'))
endfunction endfunction
function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort 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']) return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction endfunction
function! ale_linters#python#pylint#GetCommand(buffer, version) abort function! ale_linters#python#pylint#GetCommand(buffer) abort
let l:cd_string = '' let l:cd_string = ''
if ale#Var(a:buffer, 'python_pylint_change_directory') 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 return l:cd_string
\ . ale#Escape(l:executable) . l:exec_args \ . 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' \ . ' --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' \ . ' %s'
endfunction endfunction
function! ale_linters#python#pylint#Handle(buffer, lines) abort 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: " Matches patterns like the following:
" "
" test.py:4:4: W0101 (unreachable) Unreachable code " test.py:4:4: W0101 (unreachable) Unreachable code
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ([[:alnum:]]+) \(([^(]*)\) (.*)$' let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ([[:alnum:]]+) \(([^(]*)\) (.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
"let l:failed = append(0, l:match) "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] let l:code_out = l:match[4]
endif endif
let l:item = { call add(l:output, {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 1, \ 'col': l:match[2] + 1,
\ 'text': l:match[5], \ 'text': l:match[5],
\ 'code': l:code_out, \ 'code': l:code_out,
\ 'type': 'W', \ 'type': l:code[:0] is# 'E' ? 'E' : 'W',
\} \})
if l:code[:0] is# 'E'
let l:item.type = 'E'
endif
call add(l:output, l:item)
endfor endfor
return l:output return l:output
@@ -98,17 +86,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'pylint', \ 'name': 'pylint',
\ 'executable': function('ale_linters#python#pylint#GetExecutable'), \ 'executable': function('ale_linters#python#pylint#GetExecutable'),
\ 'lint_file': {buffer -> ale#semver#RunWithVersionCheck( \ 'command': function('ale_linters#python#pylint#GetCommand'),
\ 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'),
\ )},
\ 'callback': 'ale_linters#python#pylint#Handle', \ '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', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ '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'), \ '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') return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options') \ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin %s' \ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction endfunction
function! ale_linters#ruby#rubocop#GetType(severity) abort 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') return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options') \ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin %s' \ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction endfunction
" standardrb is based on RuboCop so the callback is the same " 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_include_features', '')
call ale#Set('rust_cargo_use_clippy', 0) call ale#Set('rust_cargo_use_clippy', 0)
call ale#Set('rust_cargo_clippy_options', '') call ale#Set('rust_cargo_clippy_options', '')
call ale#Set('rust_cargo_target_dir', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# '' 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]) \ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests') let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0]) \ && 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') 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_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '') \ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '') \ . (l:use_tests ? ' --tests' : '')
\ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '')
\ . ' --frozen --message-format=json -q' \ . ' --frozen --message-format=json -q'
\ . l:default_feature \ . l:default_feature
\ . l:include_features \ . 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> " Author: w0rp <devw0rp@gmail.com>
" Description: Lints shell files by invoking the shell with -n " Description: Lints sh files using bash -n
" Backwards compatibility " Backwards compatibility
if exists('g:ale_linters_sh_shell_default_shell') 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: "Matches patterns like the following:
"** Warning: add.v(7): (vlog-2623) Undefined variable: C. "** Warning: add.v(7): (vlog-2623) Undefined variable: C.
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: 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 = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[3] + 0, \ 'lnum': l:match[2] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[4], \ 'text': l:match[3],
\ 'filename': l:match[2],
\}) \})
endfor endfor
@@ -29,14 +28,13 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"** Warning: (vlog-2623) add.v(7): Undefined variable: C. "** Warning: (vlog-2623) add.v(7): Undefined variable: C.
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: 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*\):[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) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[4] + 0, \ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[2] . ' ' . l:match[5], \ 'text': l:match[2] . ' ' . l:match[4],
\ 'filename': l:match[3],
\}) \})
endfor 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_show_style_issues', 1)
call ale#Set('vim_vint_executable', 'vint') call ale#Set('vim_vint_executable', 'vint')
let s:enable_neovim = has('nvim') ? ' --enable-neovim' : '' 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 function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:can_use_no_color_flag = empty(a:version) 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' 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' return '%e'
\ . ' ' . l:warning_flag \ . ' ' . l:warning_flag
\ . (l:can_use_no_color_flag ? ' --no-color' : '') \ . (l:can_use_no_color_flag ? ' --no-color' : '')
\ . s:enable_neovim \ . s:enable_neovim
\ . ' ' . s:format \ . ' ' . s:format
\ . l:stdin_or_temp \ . ' %t'
endfunction endfunction
let s:word_regex_list = [ 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 " Use the filetype from the buffer
let l:filetype = getbufvar(a:buffer, '&filetype') let l:filetype = getbufvar(a:buffer, '&filetype')
let l:linters = ale#linter#Get(l: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. " Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer let g:ale_want_results_buffer = a:buffer
@@ -157,7 +163,7 @@ function! ale#Queue(delay, ...) abort
endif endif
endfunction 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. " A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort 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') let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
" Replace %s with the text. " Replace %s with the text.
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g') 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 return l:msg
endfunction 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 function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:linter = s:GetLinter() 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 AssertEqual a:expected_language, l:language
endfunction endfunction

View File

@@ -2,28 +2,20 @@
" Description: Functions for integrating with C-family linters. " Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0) call ale#Set('c_parse_makefile', 0)
call ale#Set('c_always_make', has('unix') && !has('macunix')) call ale#Set('c_parse_compile_commands', 0)
call ale#Set('c_parse_compile_commands', 1)
let s:sep = has('win32') ? '\' : '/' let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it. " Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt'] 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 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') let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
" c_build_dir has the priority if defined " c_build_dir has the priority if defined
@@ -76,73 +68,14 @@ function! ale#c#ShellSplit(line) abort
return l:args return l:args
endfunction endfunction
" Takes the path prefix and a list of cflags and expands @file arguments to function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
" the contents of the file. let l:cflags_list = []
"
" @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 = []
for l:option in a:raw_split_lines let l:split_lines = ale#c#ShellSplit(a:cflag_line)
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:option_index = 0 let l:option_index = 0
while l:option_index < len(l:arguments) while l:option_index < len(l:split_lines)
let l:option = l:arguments[l:option_index] let l:option = l:split_lines[l:option_index]
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Include options, that may need relative path fix " 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, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0 \ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 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' if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '') let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I' let l:option = '-I'
else 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 let l:option_index = l:option_index + 1
endif endif
" Fix relative paths if needed " 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:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', '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 endif
call add(l:items, [1, l:option]) call add(l:cflags_list, l:option)
call add(l:items, [1, ale#Escape(l:arg)]) call add(l:cflags_list, l:arg)
" Options with arg that can be grouped with the option or separate " Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0 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' if l:option is# '-D' || l:option is# '-B'
call add(l:items, [1, l:option]) call add(l:cflags_list, l:split_lines[l:option_index])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
else
call add(l:items, [0, l:option])
endif endif
" Options that have an argument (always separate) " Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0 elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib' \ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:items, [0, l:option]) call add(l:cflags_list, 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 let l:option_index = l:option_index + 1
" Options without argument " Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0) 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# '-w' || stridx(l:option, '-pedantic') == 0
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 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 \ || stridx(l:option, '-O') == 0
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs' \ || 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, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix' \ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0 \ || stridx(l:option, '-m') == 0
call add(l:items, [0, l:option]) call add(l:cflags_list, l:option)
endif endif
endwhile endwhile
if a:should_quote return join(l:cflags_list, ' ')
" 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, ' ')
endfunction endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !s:CanParseMakefile(a:buffer) if !g:ale_c_parse_makefile
return v:null return v:null
endif 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_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h') 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 endfunction
" Given a buffer number, find the project directory containing " Given a buffer number, find the project directory containing
@@ -296,10 +218,6 @@ if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {} let s:compile_commands_cache = {}
endif endif
function! ale#c#ResetCompileCommandsCache() abort
let s:compile_commands_cache = {}
endfunction
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:empty = [{}, {}] let l:empty = [{}, {}]
@@ -330,20 +248,9 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:dir_lookup = {} let l:dir_lookup = {}
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : []) 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:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] 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:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t'))
let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry] let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
endfor endfor
@@ -358,80 +265,28 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty return l:empty
endfunction endfunction
" Get [should_quote, arguments] from either 'command' or 'arguments' function! ale#c#GetCompileCommand(json_item) abort
" 'arguments' should be quoted later, the split 'command' strings should not. if has_key(a:json_item, 'command')
function! s:GetArguments(json_item) abort return a:json_item.command
if has_key(a:json_item, 'arguments') elseif has_key(a:json_item, 'arguments')
return [1, a:json_item.arguments] return join(a:json_item.arguments, ' ')
elseif has_key(a:json_item, 'command')
return [0, ale#c#ShellSplit(a:json_item.command)]
endif endif
return [0, []] return ''
endfunction endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort 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. " Search for an exact file match first.
let l:file_list = get(a:file_lookup, l:buffer_filename, []) let l:basename = tolower(expand('#' . a:buffer . ':t'))
let l:file_list = get(a:file_lookup, l:basename, [])
" 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
" A source file matching the header filename. " A source file matching the header filename.
let l:source_file = '' let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$' if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
for l:suffix in ['.c', '.cpp'] for l:suffix in ['.c', '.cpp']
" Try to find a source file by an absolute path first. let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:key = fnamemodify(l:buffer_filename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, []) 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) if !empty(l:file_list)
let l:source_file = l:key let l:source_file = l:key
break break
@@ -440,31 +295,28 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
endif endif
for l:item in l:file_list 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 " Load the flags for this file, or for a source file matching the
" header file. " header file.
if ( if (
\ bufnr(l:filename) is a:buffer \ bufnr(l:item.file) is a:buffer
\ || ( \ || (
\ !empty(l:source_file) \ !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, ale#c#GetCompileCommand(l:item))
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
endif endif
endfor 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 for l:item in l:dir_list
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file) if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
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)
endif endif
endfor endfor
@@ -482,6 +334,10 @@ endfunction
function! ale#c#GetCFlags(buffer, output) abort function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = v:null 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') if ale#Var(a:buffer, 'c_parse_compile_commands')
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
@@ -490,10 +346,6 @@ function! ale#c#GetCFlags(buffer, output) abort
endif endif
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 if l:cflags is v:null
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif endif
@@ -502,14 +354,11 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction endfunction
function! ale#c#GetMakeCommand(buffer) abort function! ale#c#GetMakeCommand(buffer) abort
if s:CanParseMakefile(a:buffer) if ale#Var(a:buffer, 'c_parse_makefile')
let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile') let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:path) if !empty(l:makefile_path)
let l:always_make = ale#Var(a:buffer, 'c_always_make') return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
return ale#path#CdString(fnamemodify(l:path, ':h'))
\ . 'make -n' . (l:always_make ? ' --always-make' : '')
endif endif
endif endif
@@ -578,3 +427,8 @@ function! ale#c#IncludeOptions(include_paths) abort
return join(l:option_list) return join(l:option_list)
endfunction 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 endfor
endfunction 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 function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:current_buffer = bufnr('') let l:current_buffer = bufnr('')
" The buffer is used to determine the fileformat, if available. " 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:column_offset = 0
let l:last_end_line = 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 a:changes
for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp'))
if l:code_edit.start.line isnot l:last_end_line if l:code_edit.start.line isnot l:last_end_line
let l:column_offset = 0 let l:column_offset = 0
endif endif

View File

@@ -133,36 +133,11 @@ function! ale#command#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g') return substitute(a:command_part, '%', '%%', 'g')
endfunction 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... " Given a command string, replace every...
" %s -> with the current filename " %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory " %t -> with the name of an unused file in a temporary directory
" %% -> with a literal % " %% -> with a literal %
function! ale#command#FormatCommand( function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed, input) abort
\ buffer,
\ executable,
\ command,
\ pipe_file_if_needed,
\ input,
\ mappings,
\) abort
let l:temporary_file = '' let l:temporary_file = ''
let l:command = a:command let l:command = a:command
@@ -179,24 +154,14 @@ function! ale#command#FormatCommand(
" file. " file.
if l:command =~# '%s' if l:command =~# '%s'
let l:filename = fnamemodify(bufname(a:buffer), ':p') let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute( let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g')
\ l:command,
\ '\v\%s(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
if a:input isnot v:false && l:command =~# '%t' if a:input isnot v:false && l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename> " Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function. " The file itself will not be created by this function.
let l:temporary_file = s:TemporaryFilename(a:buffer) let l:temporary_file = s:TemporaryFilename(a:buffer)
let l:command = substitute( let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g')
\ l:command,
\ '\v\%t(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
" Finish formatting so %% becomes %. " Finish formatting so %% becomes %.
@@ -300,7 +265,6 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
\ a:command, \ a:command,
\ get(l:options, 'read_buffer', 0), \ get(l:options, 'read_buffer', 0),
\ get(l:options, 'input', v:null), \ get(l:options, 'input', v:null),
\ get(l:options, 'filename_mappings', []),
\) \)
let l:command = ale#job#PrepareCommand(a:buffer, l:command) let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:job_options = { 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 " 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 " only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough. " 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 " 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. " we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR> 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_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', []) 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_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_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0)
let g:ale_completion_tsserver_remove_warnings = get(g:, 'ale_completion_tsserver_remove_warnings', 0)
let s:timer_id = -1 let s:timer_id = -1
let s:last_done_pos = [] let s:last_done_pos = []
@@ -188,13 +187,7 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return '' return ''
endfunction endfunction
function! ale#completion#Filter( function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
\ buffer,
\ filetype,
\ suggestions,
\ prefix,
\ exact_prefix_match,
\) abort
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words') let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
if empty(a:prefix) if empty(a:prefix)
@@ -221,17 +214,10 @@ function! ale#completion#Filter(
" Dictionaries is accepted here. " Dictionaries is accepted here.
let l:word = type(l:item) is v:t_string ? l:item : l:item.word let l:word = type(l:item) is v:t_string ? l:item : l:item.word
if a:exact_prefix_match " Add suggestions if the suggestion starts with a
" Add suggestions if the word is an exact match. " case-insensitive match for the prefix.
if l:word is# a:prefix if l:word[: len(a:prefix) - 1] is? a:prefix
call add(l:filtered_suggestions, l:item) 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
endif endif
endfor endfor
endif endif
@@ -254,17 +240,21 @@ function! ale#completion#Filter(
return l:filtered_suggestions return l:filtered_suggestions
endfunction endfunction
function! s:ReplaceCompletionOptions(source) abort function! s:ReplaceCompletionOptions() abort
" Remember the old omnifunc value, if there is one. let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing. if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc) " Remember the old omnifunc value, if there is one.
let b:ale_old_omnifunc = &l:omnifunc " 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 endif
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc' if l:source is# 'ale-automatic'
if a:source is# 'ale-automatic'
if !exists('b:ale_old_completeopt') if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt let b:ale_old_completeopt = &l:completeopt
endif endif
@@ -327,70 +317,41 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort
else else
let l:result = ale#completion#GetCompletionResult() let l:result = ale#completion#GetCompletionResult()
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') call s:ReplaceCompletionOptions()
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call s:ReplaceCompletionOptions(l:source)
endif
return l:result isnot v:null ? l:result : [] return l:result isnot v:null ? l:result : []
endif endif
endfunction 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 function! ale#completion#Show(result) abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') if ale#util#Mode() isnot# 'i'
if ale#util#Mode() isnot# 'i' && l:source isnot# 'ale-import'
return return
endif 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 let b:ale_completion_result = a:result
" Don't try to open the completion menu if there's nothing to show. " Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result) 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 return
endif endif
" Replace completion options shortly before opening the menu. " Replace completion options shortly before opening the menu.
if l:source is# 'ale-automatic' || l:source is# 'ale-manual' call s:ReplaceCompletionOptions()
call s:ReplaceCompletionOptions(l:source)
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 endif
if l:source is# 'ale-callback' if l:source is# 'ale-callback'
call b:CompleteCallback(b:ale_completion_result) call b:CompleteCallback(b:ale_completion_result)
endif 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 endfunction
function! ale#completion#GetAllTriggers() abort function! ale#completion#GetAllTriggers() abort
@@ -421,18 +382,14 @@ endfunction
function! s:CompletionStillValid(request_id) abort function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getpos('.')[1:2] let [l:line, l:column] = getpos('.')[1:2]
return has_key(b:, 'ale_completion_info') return ale#util#Mode() is# 'i'
\&& ( \&& has_key(b:, 'ale_completion_info')
\ ale#util#Mode() is# 'i'
\ || b:ale_completion_info.source is# 'ale-import'
\)
\&& b:ale_completion_info.request_id == a:request_id \&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line \&& b:ale_completion_info.line == l:line
\&& ( \&& (
\ b:ale_completion_info.column == l:column \ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'ale-omnifunc' \ || b:ale_completion_info.source is# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback' \ || b:ale_completion_info.source is# 'ale-callback'
\ || b:ale_completion_info.source is# 'ale-import'
\) \)
endfunction endfunction
@@ -440,14 +397,10 @@ function! ale#completion#ParseTSServerCompletions(response) abort
let l:names = [] let l:names = []
for l:suggestion in a:response.body for l:suggestion in a:response.body
let l:kind = get(l:suggestion, 'kind', '') call add(l:names, {
\ 'word': l:suggestion.name,
if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning' \ 'source': get(l:suggestion, 'source', ''),
call add(l:names, { \})
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''),
\})
endif
endfor endfor
return l:names return l:names
@@ -457,26 +410,15 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:results = [] let l:results = []
let l:names_with_details = [] let l:names_with_details = []
let l:info = get(b:, 'ale_completion_info', {})
for l:suggestion in a:response.body for l:suggestion in a:response.body
let l:displayParts = [] let l:displayParts = []
let l:local_name = v:null
for l:action in get(l:suggestion, 'codeActions', []) for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ') call add(l:displayParts, l:action.description . ' ')
endfor endfor
for l:part in l:suggestion.displayParts 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) call add(l:displayParts, l:part.text)
endfor endfor
@@ -489,35 +431,21 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items " See :help complete-items
let l:result = { let l:result = {
\ 'word': ( \ 'word': l:suggestion.name,
\ l:suggestion.name is# 'default'
\ && l:suggestion.kind is# 'alias'
\ && !empty(l:local_name)
\ ? l:local_name
\ : l:suggestion.name
\ ),
\ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind), \ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind),
\ 'icase': 1, \ 'icase': 1,
\ 'menu': join(l:displayParts, ''), \ 'menu': join(l:displayParts, ''),
\ 'dup': get(l:info, 'additional_edits_only', 0) \ 'dup': g:ale_completion_tsserver_autoimport,
\ || g:ale_completion_autoimport,
\ 'info': join(l:documentationParts, ''), \ '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') 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 endif
let l:result.user_data = json_encode(l:user_data) call add(l:results, l:result)
" 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 endfor
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', []) let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
@@ -536,7 +464,6 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ 'icase': 1, \ 'icase': 1,
\ 'menu': '', \ 'menu': '',
\ 'info': '', \ 'info': '',
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\}) \})
endfor endfor
endif endif
@@ -590,80 +517,23 @@ function! ale#completion#ParseLSPCompletions(response) abort
continue continue
endif 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', '') let l:doc = get(l:item, 'documentation', '')
if type(l:doc) is v:t_dict && has_key(l:doc, 'value') if type(l:doc) is v:t_dict && has_key(l:doc, 'value')
let l:doc = l:doc.value let l:doc = l:doc.value
endif endif
let l:result = { call add(l:results, {
\ 'word': l:word, \ 'word': l:word,
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')), \ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
\ 'icase': 1, \ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''), \ 'menu': get(l:item, 'detail', ''),
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''), \ '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 endfor
if has_key(l:info, 'prefix') if has_key(l:info, 'prefix')
let l:results = ale#completion#Filter( let l:results = ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
\ l:buffer,
\ &filetype,
\ l:results,
\ l:info.prefix,
\ get(l:info, 'additional_edits_only', 0),
\)
endif endif
return l:results[: g:ale_completion_max_suggestions - 1] return l:results[: g:ale_completion_max_suggestions - 1]
@@ -687,18 +557,13 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
\ &filetype, \ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response), \ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix, \ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0),
\)[: g:ale_completion_max_suggestions - 1] \)[: g:ale_completion_max_suggestions - 1]
" We need to remember some names for tsserver, as it doesn't send " We need to remember some names for tsserver, as it doesn't send
" details back for everything we send. " details back for everything we send.
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names) call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
if empty(l:names) if !empty(l:names)
" Response with no results now and skip making a redundant request
" for nothing.
call ale#completion#Show([])
else
let l:identifiers = [] let l:identifiers = []
for l:name in l:names 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) call ale#lsp#RegisterCallback(l:id, l:Callback)
if a:linter.lsp is# 'tsserver' 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( let l:message = ale#lsp#tsserver_message#Completions(
\ l:buffer, \ l:buffer,
\ b:ale_completion_info.line, \ b:ale_completion_info.line,
\ b:ale_completion_info.column, \ b:ale_completion_info.column,
\ b:ale_completion_info.prefix, \ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0) \ g:ale_completion_tsserver_autoimport,
\ || g:ale_completion_autoimport,
\) \)
else else
" Send a message saying the buffer has changed first, otherwise " Send a message saying the buffer has changed first, otherwise
@@ -832,19 +692,9 @@ function! ale#completion#GetCompletions(...) abort
let b:CompleteCallback = l:CompleteCallback let b:CompleteCallback = l:CompleteCallback
endif endif
if has_key(l:options, 'line') && has_key(l:options, 'column') let [l:line, l:column] = getpos('.')[1:2]
" 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
if has_key(l:options, 'prefix') let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
let l:prefix = l:options.prefix
else
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
endif
if l:source is# 'ale-automatic' && empty(l:prefix) if l:source is# 'ale-automatic' && empty(l:prefix)
return 0 return 0
@@ -863,11 +713,6 @@ function! ale#completion#GetCompletions(...) abort
\} \}
unlet! b:ale_completion_result 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:buffer = bufnr('')
let l:Callback = function('s:OnReady') let l:Callback = function('s:OnReady')
@@ -884,37 +729,6 @@ function! ale#completion#GetCompletions(...) abort
return l:started return l:started
endfunction 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 function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc') let l:started = ale#completion#GetCompletions('ale-omnifunc')
@@ -988,29 +802,29 @@ function! ale#completion#Queue() abort
endfunction endfunction
function! ale#completion#HandleUserData(completed_item) abort function! ale#completion#HandleUserData(completed_item) abort
let l:user_data_json = get(a:completed_item, 'user_data', '') let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
let l:user_data = !empty(l:user_data_json)
\ ? json_decode(l:user_data_json)
\ : v:null
if type(l:user_data) isnot v:t_dict if l:source isnot# 'ale-automatic'
\|| get(l:user_data, '_ale_completion_item', 0) isnot 1 \&& l:source isnot# 'ale-manual'
\&& l:source isnot# 'ale-callback'
return return
endif 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' if empty(l:user_data_json)
\|| l:source is# 'ale-manual' return
\|| 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
endif 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 endfunction
function! ale#completion#Done() abort function! ale#completion#Done() abort
@@ -1022,8 +836,6 @@ function! ale#completion#Done() abort
endfunction endfunction
augroup ALECompletionActions augroup ALECompletionActions
autocmd!
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item) autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END augroup END

View File

@@ -39,8 +39,6 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endif endif
exec 'echomsg l:message' exec 'echomsg l:message'
catch /E481/
" Do nothing if running from a visual selection.
endtry endtry
" Reset the cursor position if we moved off the end of the line. " 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_delay',
\ 'ale_completion_enabled', \ 'ale_completion_enabled',
\ 'ale_completion_max_suggestions', \ 'ale_completion_max_suggestions',
\ 'ale_disable_lsp',
\ 'ale_echo_cursor', \ 'ale_echo_cursor',
\ 'ale_echo_msg_error_str', \ 'ale_echo_msg_error_str',
\ 'ale_echo_msg_format', \ 'ale_echo_msg_format',
@@ -29,7 +28,6 @@ let s:global_variable_list = [
\ 'ale_linter_aliases', \ 'ale_linter_aliases',
\ 'ale_linters', \ 'ale_linters',
\ 'ale_linters_explicit', \ 'ale_linters_explicit',
\ 'ale_linters_ignore',
\ 'ale_list_vertical', \ 'ale_list_vertical',
\ 'ale_list_window_size', \ 'ale_list_window_size',
\ 'ale_loclist_msg_format', \ 'ale_loclist_msg_format',
@@ -198,7 +196,6 @@ function! s:EchoLSPErrorMessages(all_linter_names) abort
endfunction endfunction
function! ale#debugging#Info() abort function! ale#debugging#Info() abort
let l:buffer = bufnr('')
let l:filetype = &filetype let l:filetype = &filetype
" We get the list of enabled linters for free by the above function. " 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 = uniq(sort(l:fixers[0] + l:fixers[1]))
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '') 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(' Current Filetype: ' . l:filetype)
call s:Echo('Available Linters: ' . string(l:all_names)) call s:Echo('Available Linters: ' . string(l:all_names))
call s:EchoLinterAliases(l:all_linters) call s:EchoLinterAliases(l:all_linters)
call s:Echo(' Enabled Linters: ' . string(l:enabled_names)) 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(' Suggested Fixers: ' . l:fixers_string)
call s:Echo(' Linter Variables:') call s:Echo(' Linter Variables:')
call s:Echo('') call s:Echo('')

View File

@@ -135,6 +135,10 @@ function! s:GoToLSPDefinition(linter, options, capability) abort
endfunction endfunction
function! ale#definition#GoTo(options) abort 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) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call s:GoToLSPDefinition(l:linter, a:options, 'definition') call s:GoToLSPDefinition(l:linter, a:options, 'definition')
@@ -143,6 +147,10 @@ function! ale#definition#GoTo(options) abort
endfunction endfunction
function! ale#definition#GoToType(options) abort 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) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
" TODO: handle typeDefinition for tsserver if supported by the " TODO: handle typeDefinition for tsserver if supported by the

View File

@@ -4,7 +4,6 @@
" Remapping of linter problems. " Remapping of linter problems.
let g:ale_type_map = get(g:, 'ale_type_map', {}) 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') if !has_key(s:, 'executable_cache_map')
let 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', [])) \ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction 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 function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) 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:linter = a:job_info.linter
let l:executable = a:job_info.executable let l:executable = a:job_info.executable
let l:next_chain_index = a:job_info.next_chain_index
" Remove this job from the list. " Remove this job from the list.
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name) 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) call remove(a:output, -1)
endif 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 try
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output) let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
" Handle the function being unknown, or being deleted. " Handle the function being unknown, or being deleted.
@@ -257,13 +307,6 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfunction endfunction
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort 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:bufnr_map = {}
let l:new_loclist = [] 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 let l:item.code = l:old_item.code
endif endif
let l:old_name = get(l:old_item, 'filename', '') if has_key(l:old_item, 'filename')
\&& !ale#path#IsTempName(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)
" Use the filename given. " Use the filename given.
" Temporary files are assumed to be for this buffer, " Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad " and the filename is not included then, because it looks bad
" in the loclist window. " in the loclist window.
let l:filename = l:old_name let l:filename = l:old_item.filename
let l:item.filename = l:filename let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr') 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:buffer = a:options.buffer
let l:linter = a:options.linter let l:linter = a:options.linter
let l:output_stream = a:options.output_stream 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:info = g:ale_buffer_info[l:buffer]
let l:Callback = function('s:HandleExit', [{ let l:Callback = function('s:HandleExit', [{
\ 'linter': l:linter, \ 'linter': l:linter,
\ 'executable': l:executable, \ 'executable': l:executable,
\ 'next_chain_index': l:next_chain_index,
\}]) \}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, { let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream, \ 'output_stream': l:output_stream,
\ 'executable': l:executable, \ 'executable': l:executable,
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
\ 'log_output': 1, \ 'log_output': l:next_chain_index >= len(get(l:linter, 'command_chain', [])),
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
\}) \})
" Only proceed if the job is being run. " Only proceed if the job is being run.
@@ -444,7 +482,69 @@ function! s:RunJob(command, options) abort
return 1 return 1
endfunction 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, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
call ale#command#StopJobs(a:buffer, 'linter') 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') call ale#command#StopJobs(a:buffer, 'file_linter')
let l:info.active_linter_list = [] let l:info.active_linter_list = []
else 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. " 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 endif
endfunction endfunction
function! ale#engine#Stop(buffer) abort
call s:StopCurrentJobs(a:buffer, 1, [])
endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove " Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled. " problems for linters which are no longer enabled.
@@ -522,15 +608,10 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
endif endif
endfunction endfunction
function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort function! s:RunIfExecutable(buffer, linter, executable) abort
if ale#command#IsDeferred(a:executable) if ale#command#IsDeferred(a:executable)
let a:executable.result_callback = { let a:executable.result_callback = {
\ executable -> s:RunIfExecutable( \ executable -> s:RunIfExecutable(a:buffer, a:linter, executable)
\ a:buffer,
\ a:linter,
\ a:lint_file,
\ executable
\ )
\} \}
return 1 return 1
@@ -538,17 +619,29 @@ function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
if ale#engine#IsExecutable(a:buffer, a:executable) if ale#engine#IsExecutable(a:buffer, a:executable)
" Use different job types for file or linter jobs. " 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) 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:command = ale#linter#GetCommand(a:buffer, a:linter)
let l:options = { let l:options = {
\ 'executable': a:executable, \ 'executable': a:executable,
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'linter': a:linter, \ 'linter': a:linter,
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'), \ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
\ 'next_chain_index': 1,
\ 'read_buffer': a:linter.read_buffer, \ 'read_buffer': a:linter.read_buffer,
\ 'lint_file': a:lint_file,
\} \}
return s:RunJob(l:command, l:options) return s:RunJob(l:command, l:options)
@@ -560,73 +653,22 @@ endfunction
" Run a linter for a buffer. " Run a linter for a buffer.
" "
" Returns 1 if the linter was successfully run. " 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) if !empty(a:linter.lsp)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter) return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) 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 endif
return 0 return 0
endfunction endfunction
function! s:GetLintFileSlots(buffer, linters) abort function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
let l:linter_slots = [] " Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
for l:linter in a:linters call s:StopCurrentJobs(a:buffer, a:should_lint_file)
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)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters) call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer. " 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 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. " Only run lint_file linters if we should.
if !l:lint_file || a:should_lint_file if !l:linter.lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter, l:lint_file) if s:RunLinter(a:buffer, l:linter)
" If a single linter ran, we shouldn't clear everything. " If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0 let l:can_clear_results = 0
endif endif
@@ -652,32 +694,11 @@ function! s:RunLinters(
" disabled, or ALE itself is disabled. " disabled, or ALE itself is disabled.
if l:can_clear_results if l:can_clear_results
call ale#engine#SetResults(a:buffer, []) call ale#engine#SetResults(a:buffer, [])
elseif a:new_buffer elseif l:new_buffer
call s:AddProblemsFromOtherBuffers( call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
\ a:buffer,
\ map(copy(a:slots), 'v:val[1]')
\)
endif endif
endfunction 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. " Clean up a buffer.
" "
" This function will stop all current jobs for the 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 g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1' 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' 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' 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 endif
if g:ale_lint_on_enter 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 autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif
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 if g:ale_close_preview_on_insert
autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
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> call ale#Set('fix_on_save_ignore', {})
" 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', {})
" Apply fixes queued up for buffers which may be hidden. " Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers. " 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) call remove(g:ale_fix_buffer_data, a:buffer)
try if l:data.changes_made
if l:data.changes_made let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
if l:data.should_save if l:data.should_save
if a:buffer is bufnr('') if a:buffer is bufnr('')
if empty(&buftype) if empty(&buftype)
noautocmd :w! noautocmd :w!
else
set nomodified
endif
else else
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks set nomodified
call setbufvar(a:buffer, '&modified', 0)
endif endif
else
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif endif
endif endif
catch /E21/ endif
" If we cannot modify the buffer now, try again later.
let g:ale_fix_buffer_data[a:buffer] = l:data
return
endtry
if l:data.should_save if l:data.should_save
let l:should_lint = ale#Var(a:buffer, 'fix_on_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 if l:data.lines_before != l:lines
call remove(g:ale_fix_buffer_data, a:buffer) call remove(g:ale_fix_buffer_data, a:buffer)
execute 'echoerr ''The file was changed before fixing finished'''
if !l:data.ignore_file_changed_errors
execute 'echoerr ''The file was changed before fixing finished'''
endif
return return
endif endif
@@ -104,6 +90,7 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
let l:output = a:job_output let l:output = a:job_output
endif endif
let l:ChainCallback = get(a:job_info, 'chain_with', v:null)
let l:ProcessWith = get(a:job_info, 'process_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. " 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. " otherwise skip this job and use the input from before.
" "
" We'll use the input from before for chained commands. " 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 let l:input = l:output
else else
let l:input = a:job_info.input let l:input = a:job_info.input
endif 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({ call s:RunFixer({
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'output': l:output,
\ 'callback_list': a:job_info.callback_list, \ '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 endfunction
@@ -138,7 +135,6 @@ function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:input = a:options.input 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 a:result is 0 || type(a:result) is v:t_list
if 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 endif
let l:command = get(a:result, 'command', '') let l:command = get(a:result, 'command', '')
let l:ChainWith = get(a:result, 'chain_with', v:null)
if empty(l:command) 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({ call s:RunFixer({
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ '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, \ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith,
\ 'output': [],
\}) \})
return return
endif endif
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0) 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') let l:output_stream = get(a:result, 'output_stream', 'stdout')
if l:read_temporary_file if l:read_temporary_file
@@ -179,6 +180,7 @@ function! s:RunJob(result, options) abort
let l:Callback = function('s:HandleExit', [{ let l:Callback = function('s:HandleExit', [{
\ 'input': l:input, \ 'input': l:input,
\ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'process_with': get(a:result, 'process_with', v:null), \ 'process_with': get(a:result, 'process_with', v:null),
@@ -190,7 +192,6 @@ function! s:RunJob(result, options) abort
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'log_output': 0, \ 'log_output': 0,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\}) \})
if empty(l:run_result) if empty(l:run_result)
@@ -214,22 +215,32 @@ function! s:RunFixer(options) abort
return return
endif 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. " Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer') call setbufvar(l:buffer, 'ale_job_type', 'fixer')
" Regular fixer commands accept (buffer, [input]) if l:ChainCallback isnot v:null
let l:result = ale#util#FunctionArgCount(l:Function) == 1 " Chained commands accept (buffer, output, [input])
\ ? call(l:Function, [l:buffer]) let l:result = ale#util#FunctionArgCount(l:Function) == 2
\ : call(l:Function, [l:buffer, copy(l:input)]) \ ? 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, { call s:RunJob(l:result, {
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index, \ 'callback_index': l:index,
\ 'fixer_name': l:fixer_name,
\}) \})
endfunction endfunction
@@ -297,24 +308,16 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
" Variables with capital characters are needed, or Vim will complain about " Variables with capital characters are needed, or Vim will complain about
" funcref variables. " funcref variables.
for l:Item in l:callback_list 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 if type(l:Item) is v:t_string
let l:Func = ale#fix#registry#GetFunc(l:Item) let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func) if !empty(l:Func)
let l:fixer_name = l:Item
let l:Item = l:Func let l:Item = l:Func
endif endif
endif endif
try try
call add(l:corrected_list, [ call add(l:corrected_list, ale#util#GetFunction(l:Item))
\ l:fixer_name,
\ ale#util#GetFunction(l:Item)
\])
catch /E475/ catch /E475/
" Rethrow exceptions for failing to get a function so we can print " Rethrow exceptions for failing to get a function so we can print
" a friendly message about it. " a friendly message about it.
@@ -332,7 +335,6 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
\ 'lines_before': getbufline(a:buffer, 1, '$'), \ 'lines_before': getbufline(a:buffer, 1, '$'),
\ 'done': 0, \ 'done': 0,
\ 'should_save': a:fixing_flag is# 'save_file', \ 'should_save': a:fixing_flag is# 'save_file',
\ 'ignore_file_changed_errors': a:fixing_flag is# '!',
\ 'temporary_directory_list': [], \ 'temporary_directory_list': [],
\} \}
endfunction endfunction
@@ -341,23 +343,19 @@ endfunction
" "
" Returns 0 if no fixes can be applied, and 1 if fixing can be done. " Returns 0 if no fixes can be applied, and 1 if fixing can be done.
function! ale#fix#Fix(buffer, fixing_flag, ...) abort function! ale#fix#Fix(buffer, fixing_flag, ...) abort
if a:fixing_flag isnot# '' if a:fixing_flag isnot# '' && a:fixing_flag isnot# 'save_file'
\&& a:fixing_flag isnot# '!' throw "fixing_flag must be either '' or 'save_file'"
\&& a:fixing_flag isnot# 'save_file'
throw "fixing_flag must be '', '!', or 'save_file'"
endif endif
try try
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000) let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
catch /E700\|BADNAME/ catch /E700\|BADNAME/
if a:fixing_flag isnot# '!' let l:function_name = join(split(split(v:exception, ':')[3]))
let l:function_name = join(split(split(v:exception, ':')[3])) let l:echo_message = printf(
let l:echo_message = printf( \ 'There is no fixer named `%s`. Check :ALEFixSuggest',
\ 'There is no fixer named `%s`. Check :ALEFixSuggest', \ l:function_name,
\ l:function_name, \)
\) execute 'echom l:echo_message'
execute 'echom l:echo_message'
endif
return 0 return 0
endtry endtry
@@ -391,4 +389,3 @@ endfunction
augroup ALEBufferFixGroup augroup ALEBufferFixGroup
autocmd! autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>'))) autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END

View File

@@ -160,11 +160,6 @@ let s:default_registry = {
\ 'suggested_filetypes': ['php'], \ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with php-cs-fixer.', \ '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': { \ 'clangtidy': {
\ 'function': 'ale#fixers#clangtidy#Fix', \ 'function': 'ale#fixers#clangtidy#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'objc'], \ 'suggested_filetypes': ['c', 'cpp', 'objc'],
@@ -365,21 +360,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['nix'], \ 'suggested_filetypes': ['nix'],
\ 'description': 'A formatter for Nix code', \ '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': { \ 'html-beautify': {
\ 'function': 'ale#fixers#html_beautify#Fix', \ 'function': 'ale#fixers#html_beautify#Fix',
\ 'suggested_filetypes': ['html', 'htmldjango'], \ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.', \ '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. " 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 function! ale#fixers#ktlint#Fix(buffer) abort
return { return {
\ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format' \ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format',
\ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View File

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

View File

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

View File

@@ -34,21 +34,6 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output return a:output
endfunction 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 function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options') 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 " 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(a:version, [1, 4, 0]) if ale#semver#GTE(a:version, [1, 4, 0])
return { return {
\ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer) \ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) \ . ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',

View File

@@ -17,8 +17,8 @@ function! ale#fixers#prettier_standard#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer)) \ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
\ . ' --stdin' \ . ' %t'
\ . ' --stdin-filepath=%s'
\ . ' ' . l:options, \ . ' ' . l:options,
\ 'read_temporary_file': 1,
\} \}
endfunction 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_options', '')
call ale#Set('ruby_rubocop_auto_correct_all', 0)
call ale#Set('ruby_rubocop_executable', 'rubocop') 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 function! ale#fixers#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable') let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options') 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') return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct') \ . ' --auto-correct --force-exclusion %t'
\ . ' --force-exclusion --stdin %s'
endfunction endfunction
function! ale#fixers#rubocop#Fix(buffer) abort function! ale#fixers#rubocop#Fix(buffer) abort
return { return {
\ 'command': ale#fixers#rubocop#GetCommand(a:buffer), \ 'command': ale#fixers#rubocop#GetCommand(a:buffer),
\ 'process_with': 'ale#fixers#rubocop#PostProcess' \ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View File

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

View File

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

View File

@@ -17,10 +17,3 @@ function! ale#handlers#ccls#GetProjectRoot(buffer) abort
" Fall back on default project root detection. " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer) return ale#c#FindProjectRoot(a:buffer)
endfunction 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 function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort
" Look for lines like the following. " Look for lines like the following.
" "
"test.cpp:974:6: error: Array 'n[3]' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\ " [test.cpp:5]: (error) Array 'a[10]' accessed at index 10, which is out of bounds
" n[3]=3; let l:pattern = '\v^\[(.+):(\d+)\]: \(([a-z]+)\) (.+)$'
" ^
let l:pattern = '\v^(\f+):(\d+):(\d+): (\w+): (.*) \[(\w+)\]\'
let l:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
if ale#path#IsBufferPath(a:buffer, l:match[1]) if ale#path#IsBufferPath(a:buffer, l:match[1])
call add(l:output, { call add(l:output, {
\ 'lnum': str2nr(l:match[2]), \ 'lnum': str2nr(l:match[2]),
\ 'col': str2nr(l:match[3]), \ 'type': l:match[3] is# 'error' ? 'E' : 'W',
\ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'text': l:match[4],
\ 'sub_type': l:match[4] is# 'style' ? 'style' : '',
\ 'text': l:match[5],
\ 'code': l:match[6]
\}) \})
endif endif
endfor 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>:8:5: warning: conversion lacks type at end of format [-Wformat=]
" <stdin>:10:27: error: invalid operands to binary - (have int and char *) " <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] " -: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+):$' let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort function! s:IsHeaderFile(filename) abort
@@ -117,23 +117,6 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
if !empty(l:output) if !empty(l:output)
if !has_key(l:output[-1], 'detail') if !has_key(l:output[-1], 'detail')
let l:output[-1].detail = l:output[-1].text 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 endif
let l:output[-1].detail = l:output[-1].detail . "\n" let l:output[-1].detail = l:output[-1].detail . "\n"

View File

@@ -6,12 +6,9 @@
" "
" Author: Ben Paxton <ben@gn32.uk> " Author: Ben Paxton <ben@gn32.uk>
" Description: moved to generic Golang file from govet " 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 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:output = []
let l:dir = expand('#' . a:buffer . ':p:h') 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) return ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . (empty(l:rulesets) ? '' : ' ' . l:rulesets) \ . (empty(l:rulesets) ? '' : ' ' . l:rulesets)
\ . ' --stdin' \ . ' %t'
endfunction endfunction
function! ale#handlers#ktlint#GetRulesets(buffer) abort function! ale#handlers#ktlint#GetRulesets(buffer) abort

View File

@@ -2,22 +2,15 @@
" Description: Adds support for markdownlint " Description: Adds support for markdownlint
function! ale#handlers#markdownlint#Handle(buffer, lines) abort 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=[] let l:output=[]
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:result = ({ call add(l:output, {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'code': l:match[4], \ 'text': '(' . l:match[2] . l:match[3] . l:match[4] . ')' . l:match[5],
\ 'text': l:match[5],
\ 'type': 'W', \ 'type': 'W',
\}) \})
if len(l:match[3]) > 0
let l:result.col = (l:match[3] + 0)
endif
call add(l:output, l:result)
endfor endfor
return l:output return l:output

View File

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

View File

@@ -42,8 +42,6 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
\&& exists('*balloon_show') \&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons') \&& ale#Var(l:options.buffer, 'set_balloons')
call balloon_show(a:response.body.displayString) 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 elseif g:ale_hover_to_preview
call ale#preview#Show(split(a:response.body.displayString, "\n"), { call ale#preview#Show(split(a:response.body.displayString, "\n"), {
\ 'filetype': 'ale-preview.message', \ 'filetype': 'ale-preview.message',
@@ -56,137 +54,6 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
endif endif
endfunction 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 function! ale#hover#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id') if has_key(a:response, 'id')
\&& has_key(s:hover_map, a:response.id) \&& has_key(s:hover_map, a:response.id)
@@ -213,25 +80,37 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
return return
endif endif
let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents) let l:result = l:result.contents
if !empty(l:lines) if type(l:result) is v:t_string
if get(l:options, 'hover_from_balloonexpr', 0) " The result can be just a string.
\&& exists('*balloon_show') let l:result = [l:result]
\&& ale#Var(l:options.buffer, 'set_balloons') endif
call balloon_show(join(l:lines, "\n"))
elseif get(l:options, 'truncated_echo', 0) if type(l:result) is v:t_dict
call ale#cursor#TruncatedEcho(l:lines[0]) " If the result is an object, then it's markup content.
elseif g:ale_hover_to_preview let l:result = [l:result.value]
call ale#preview#Show(l:lines, { endif
\ 'filetype': 'ale-preview.message',
\ 'stay_here': 1, if type(l:result) is v:t_list
\ 'commands': l:commands, " Replace objects with text values.
\}) call map(l:result, 'type(v:val) is v:t_string ? v:val : v:val.value')
else let l:str = join(l:result, "\n")
call ale#util#ShowMessage(join(l:lines, "\n"), { let l:str = substitute(l:str, '^\s*\(.\{-}\)\s*$', '\1', '')
\ 'commands': l:commands,
\}) 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 endif
endif endif
@@ -264,10 +143,7 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
" hover position probably won't make sense. " hover position probably won't make sense.
call ale#lsp#NotifyForChanges(l:id, l:buffer) call ale#lsp#NotifyForChanges(l:id, l:buffer)
let l:column = max([ let l:column = min([a:column, len(getbufline(l:buffer, a:line)[0])])
\ min([a:column, len(getbufline(l:buffer, a:line)[0])]),
\ 1,
\])
let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column) let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column)
endif endif
@@ -280,7 +156,6 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
\ 'column': l:column, \ 'column': l:column,
\ 'hover_from_balloonexpr': get(a:opt, 'called_from_balloonexpr', 0), \ 'hover_from_balloonexpr': get(a:opt, 'called_from_balloonexpr', 0),
\ 'show_documentation': get(a:opt, 'show_documentation', 0), \ 'show_documentation': get(a:opt, 'show_documentation', 0),
\ 'truncated_echo': get(a:opt, 'truncated_echo', 0),
\} \}
endfunction endfunction
@@ -306,8 +181,6 @@ function! ale#hover#Show(buffer, line, col, opt) abort
endfor endfor
endfunction endfunction
let s:last_pos = [0, 0, 0]
" This function implements the :ALEHover command. " This function implements the :ALEHover command.
function! ale#hover#ShowAtCursor() abort function! ale#hover#ShowAtCursor() abort
let l:buffer = bufnr('') 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], {}) call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], {})
endfunction 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. " This function implements the :ALEDocumentation command.
function! ale#hover#ShowDocumentationAtCursor() abort function! ale#hover#ShowDocumentationAtCursor() abort
let l:buffer = bufnr('') let l:buffer = bufnr('')

View File

@@ -14,7 +14,6 @@ let s:default_ale_linter_aliases = {
\ 'csh': 'sh', \ 'csh': 'sh',
\ 'javascriptreact': ['javascript', 'jsx'], \ 'javascriptreact': ['javascript', 'jsx'],
\ 'plaintex': 'tex', \ 'plaintex': 'tex',
\ 'ps1': 'powershell',
\ 'rmarkdown': 'r', \ 'rmarkdown': 'r',
\ 'rmd': 'r', \ 'rmd': 'r',
\ 'systemverilog': 'verilog', \ 'systemverilog': 'verilog',
@@ -32,7 +31,7 @@ let s:default_ale_linter_aliases = {
" "
" No linters are used for plaintext files by default. " 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. " 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. " hhast is disabled by default because it executes code in the project root.
" "
@@ -45,8 +44,8 @@ let s:default_ale_linters = {
\ 'help': [], \ 'help': [],
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [], \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo', 'rls'], \ 'rust': ['cargo'],
\ 'spec': [], \ 'spec': [],
\ 'text': [], \ 'text': [],
\ 'vue': ['eslint', 'vls'], \ '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) return type(a:value) is v:t_number && (a:value == 0 || a:value == 1)
endfunction endfunction
function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(filetype, linter) abort function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) isnot v:t_dict if type(a:linter) isnot v:t_dict
throw 'The linter object must be a Dictionary' throw 'The linter object must be a Dictionary'
@@ -110,7 +113,14 @@ function! ale#linter#PreProcess(filetype, linter) abort
if !l:needs_executable if !l:needs_executable
if has_key(a:linter, '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 endif
elseif has_key(a:linter, 'executable') elseif has_key(a:linter, 'executable')
let l:obj.executable = 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' throw '`executable` must be a String or Function if defined'
endif endif
else else
throw '`executable` must be defined' throw 'Either `executable` or `executable_callback` must be defined'
endif endif
if !l:needs_command if !l:needs_command
if has_key(a:linter, '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 endif
elseif has_key(a:linter, 'command') elseif has_key(a:linter, 'command')
let l:obj.command = 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' throw '`command` must be a String or Function if defined'
endif endif
else 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 endif
if !l:needs_address if !l:needs_address
if has_key(a:linter, 'address') if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback')
throw '`address` cannot be used when lsp != ''socket''' throw '`address` or `address_callback` cannot be used when lsp != ''socket'''
endif endif
elseif has_key(a:linter, 'address') elseif has_key(a:linter, 'address')
if type(a:linter.address) isnot v:t_string if type(a:linter.address) isnot v:t_string
@@ -149,17 +211,41 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif endif
let l:obj.address = a:linter.address 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 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 endif
if l:needs_lsp_details if l:needs_lsp_details
" Default to using the filetype as the language. if has_key(a:linter, 'language_callback')
let l:obj.language = get(a:linter, 'language', a:filetype) 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 let l:obj.language_callback = get(a:linter, 'language_callback')
\&& type(l:obj.language) isnot v:t_func
throw '`language` must be a String or Funcref if defined' 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 endif
if has_key(a:linter, 'project_root') 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 if type(l:obj.project_root) isnot v:t_string
\&& type(l:obj.project_root) isnot v:t_func \&& 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 endif
else else
throw '`project_root` must be defined for LSP linters' throw '`project_root` or `project_root_callback` must be defined for LSP linters'
endif endif
if has_key(a:linter, 'completion_filter') if has_key(a:linter, 'completion_filter')
@@ -181,16 +273,37 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif endif
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 let l:obj.initialization_options = a:linter.initialization_options
if type(l:obj.initialization_options) isnot v:t_dict if type(l:obj.initialization_options) isnot v:t_dict
\&& type(l:obj.initialization_options) isnot v:t_func \&& 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
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 if type(a:linter.lsp_config) isnot v:t_dict
\&& type(a:linter.lsp_config) isnot v:t_func \&& type(a:linter.lsp_config) isnot v:t_func
throw '`lsp_config` must be a Dictionary or Function if defined' 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. " file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0) 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 if !s:IsBoolean(l:obj.lint_file)
throw '`lint_file` must be `0`, `1`, or a Function' throw '`lint_file` must be `0` or `1`'
endif endif
" An option indicating that the buffer should be read. " 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) if !s:IsBoolean(l:obj.read_buffer)
throw '`read_buffer` must be `0` or `1`' throw '`read_buffer` must be `0` or `1`'
endif 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', []) let l:obj.aliases = get(a:linter, 'aliases', [])
if type(l:obj.aliases) isnot v:t_list 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' throw '`aliases` must be a List of String values'
endif 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 return l:obj
endfunction endfunction
@@ -394,19 +519,11 @@ function! ale#linter#Get(original_filetypes) abort
return reverse(l:combined_linters) return reverse(l:combined_linters)
endfunction 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. " Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort 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 return type(l:Executable) is v:t_func
\ ? l:Executable(a:buffer) \ ? l:Executable(a:buffer)
@@ -414,21 +531,24 @@ function! ale#linter#GetExecutable(buffer, linter) abort
endfunction endfunction
" Given a buffer and linter, get the command String for the linter. " 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 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 endfunction
" Given a buffer and linter, get the address for connecting to the server. " Given a buffer and linter, get the address for connecting to the server.
function! ale#linter#GetAddress(buffer, linter) abort 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 return type(l:Address) is v:t_func
endfunction \ ? l:Address(a:buffer)
\ : l:Address
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
endfunction endfunction

View File

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

View File

@@ -34,11 +34,7 @@ endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id] let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri) let l:filename = ale#path#FromURI(a:response.params.uri)
let l:escaped_name = escape( let l:buffer = bufnr('^' . l:filename . '$')
\ fnameescape(l:filename),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
@@ -56,11 +52,7 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver' let l:linter_name = 'tsserver'
let l:escaped_name = escape( let l:buffer = bufnr('^' . a:response.body.file . '$')
\ fnameescape(a:response.body.file),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) 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:command = a:details.command
let l:config = ale#lsp_linter#GetConfig(l:buffer, a:linter) 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) 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) call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif endif
let l:command = ale#command#FormatCommand( let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1]
\ l:buffer,
\ a:executable,
\ a:command,
\ 0,
\ v:false,
\ [],
\)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command) let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command) let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif endif

View File

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

View File

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

View File

@@ -83,31 +83,6 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
\}, v:true) \}, v:true)
endfunction 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 function! ale#rename#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id') if has_key(a:response, 'id')
\&& has_key(s:rename_map, a:response.id) \&& has_key(s:rename_map, a:response.id)
@@ -119,9 +94,9 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
return return
endif 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') call s:message('No changes received from server')
return return
@@ -129,8 +104,8 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
let l:changes = [] let l:changes = []
for l:file_name in keys(l:changes_map) for l:file_name in keys(l:workspace_edit.changes)
let l:text_edits = l:changes_map[l:file_name] let l:text_edits = l:workspace_edit.changes[l:file_name]
let l:text_changes = [] let l:text_changes = []
for l:edit in l:text_edits 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. " end, but before handlers are run.
sleep 10ms sleep 10ms
" We must check the buffer data again to see if new jobs started for " We must check the buffer data again to see if new jobs started
" linters with chained commands. " for command_chain linters.
let l:has_new_jobs = 0 let l:has_new_jobs = 0
" Check again to see if any jobs are running. " Check again to see if any jobs are running.

View File

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

View File

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

View File

@@ -1,36 +1,22 @@
=============================================================================== ===============================================================================
ALE C Integration *ale-c-options* 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 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* g:ale_c_build_dir_names *g:ale_c_build_dir_names*
*b:ale_c_build_dir_names* *b:ale_c_build_dir_names*
Type: |List| Type: |List|
Default: `['build', 'bin']` Default: `['build', 'bin']`
A list of directory names to be used when searching upwards from cpp files A list of directory names to be used when searching upwards from cpp
to discover compilation databases with. For directory named `'foo'`, ALE files to discover compilation databases with. For directory named `'foo'`,
will search for `'foo/compile_commands.json'` in all directories on and ALE will search for `'foo/compile_commands.json'` in all directories on and above
above the directory containing the cpp file to find path to compilation the directory containing the cpp file to find path to compilation database.
database. This feature is useful for the clang tools wrapped around This feature is useful for the clang tools wrapped around LibTooling (namely
LibTooling (namely here, clang-tidy) here, clang-tidy)
g:ale_c_build_dir *g:ale_c_build_dir* 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* g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
*b:ale_c_parse_compile_commands* *b:ale_c_parse_compile_commands*
Type: |Number| Type: |Number|
Default: `1` Default: `0`
If set to `1`, ALE will parse `compile_commands.json` files to automatically 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 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 `compile_commands.json` files in the directories for
|g:ale_c_build_dir_names|. |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* g:ale_c_parse_makefile *g:ale_c_parse_makefile*
*b: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 set for C or C++ compilers. This can make it easier to determine the correct
build flags to use for different files. 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* g:ale_c_clang_executable *g:ale_c_clang_executable*
*b:ale_c_astyle_executable* *b:ale_c_clang_executable*
Type: |String| 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* g:ale_c_clang_options *g:ale_c_clang_options*
*b:ale_c_astyle_project_options* *b:ale_c_clang_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*
Type: |String| Type: |String|
Default: `'-std=c11 -Wall'` Default: `'-std=c11 -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-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.
=============================================================================== ===============================================================================
@@ -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++. 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* 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. 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: 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. 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: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -1,16 +1,12 @@
=============================================================================== ===============================================================================
ALE C++ Integration *ale-cpp-options* 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 Global Options
The following C options also apply to some C++ linters too. 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_names|
* |g:ale_c_build_dir| * |g:ale_c_build_dir|
* |g:ale_c_parse_makefile| * |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* g:ale_cpp_clang_executable *g:ale_cpp_clang_executable*
*b:ale_cpp_astyle_executable* *b:ale_cpp_clang_executable*
Type: |String| 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* g:ale_cpp_clang_options *g:ale_cpp_clang_options*
*b:ale_cpp_astyle_project_options* *b:ale_cpp_clang_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*
Type: |String| Type: |String|
Default: `'-std=c++14 -Wall'` 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* g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
*b:ale_cpp_ccls_executable* *b:ale_cpp_clangd_executable*
Type: |String| 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* g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
*b:ale_cpp_ccls_init_options* *b:ale_cpp_clangd_options*
Type: |Dictionary| Type: |String|
Default: `{}` Default: `''`
This variable can be changed to customize ccls initialization options. This variable can be changed to modify flags given to clangd.
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.
=============================================================================== ===============================================================================
@@ -127,25 +82,6 @@ g:ale_cpp_clangcheck_options *g:ale_cpp_clangcheck_options*
option. 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* 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. 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* uncrustify *ale-cpp-uncrustify*
See |ale-c-uncrustify| for information about the available options. 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: 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