Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bartek thindil Jasicki 2020-08-14 19:38:09 +02:00
commit 04bd84e914
36 changed files with 998 additions and 193 deletions

16
.github/stale.yml vendored Normal file
View file

@ -0,0 +1,16 @@
---
# This configuration closes stale PRs after 30 days.
# Issues in ALE are never, ever stale. They are either resolved or not.
only: pulls
daysUntilStale: 28
daysUntilClose: 2
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

142
README.md
View file

@ -61,23 +61,24 @@ 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 keep the sign gutter open?](#faq-keep-signs) 2. [How can I see what ALE has configured for the current file?](#faq-get-info)
3. [How can I change the signs ALE uses?](#faq-change-signs) 3. [How can I use ALE and coc.nvim together?](#faq-coc-nvim)
4. [How can I change or disable the highlights ALE uses?](#faq-change-highlights) 4. [How can I keep the sign gutter open?](#faq-keep-signs)
5. [How can I show errors or warnings in my statusline?](#faq-statusline) 5. [How can I change the signs ALE uses?](#faq-change-signs)
6. [How can I show errors or warnings in my lightline?](#faq-lightline) 6. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
7. [How can I change the format for echo messages?](#faq-echo-format) 7. [How can I show errors or warnings in my statusline?](#faq-statusline)
8. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd) 8. [How can I show errors or warnings in my lightline?](#faq-lightline)
9. [How can I navigate between errors quickly?](#faq-navigation) 9. [How can I change the format for echo messages?](#faq-echo-format)
10. [How can I run linters only when I save files?](#faq-lint-on-save) 10. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix) 11. [How can I navigate between errors quickly?](#faq-navigation)
12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint) 12. [How can I run linters only when I save files?](#faq-lint-on-save)
13. [How can I check Vue files with ESLint?](#faq-vue-eslint) 13. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad) 14. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
15. [How can I configure my C or C++ project?](#faq-c-configuration) 15. [How can I check Vue files with ESLint?](#faq-vue-eslint)
16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration) 16. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height) 17. [How can I configure my C or C++ project?](#faq-c-configuration)
18. [How can I see what ALE has configured for the current file?](#faq-get-info) 18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
<a name="supported-languages"></a> <a name="supported-languages"></a>
@ -193,12 +194,11 @@ completion manually with `<C-x><C-o>`.
set omnifunc=ale#completion#OmniFunc set omnifunc=ale#completion#OmniFunc
``` ```
When working with TypeScript files, ALE supports automatic imports from ALE supports automatic imports from external modules. This behavior is disabled
external modules. This behavior is disabled by default and can be enabled by by default and can be enabled by setting:
setting:
```vim ```vim
let g:ale_completion_tsserver_autoimport = 1 let g:ale_completion_autoimport = 1
``` ```
See `:help ale-completion` for more information. See `:help ale-completion` for more information.
@ -416,9 +416,56 @@ 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.ii. How can I keep the sign gutter open? ### 5.iv. 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
@ -429,7 +476,7 @@ let g:ale_sign_column_always = 1
<a name="faq-change-signs"></a> <a name="faq-change-signs"></a>
### 5.iii. How can I change the signs ALE uses? ### 5.v. 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:
@ -449,7 +496,7 @@ highlight clear ALEWarningSign
<a name="faq-change-highlights"></a> <a name="faq-change-highlights"></a>
### 5.iv. How can I change or disable the highlights ALE uses? ### 5.vi. 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
@ -475,7 +522,7 @@ See `:help ale-highlights` for more information.
<a name="faq-statusline"></a> <a name="faq-statusline"></a>
### 5.v. How can I show errors or warnings in my statusline? ### 5.vii. 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
@ -524,7 +571,7 @@ for more information.
<a name="faq-lightline"></a> <a name="faq-lightline"></a>
### 5.vi. How can I show errors or warnings in my lightline? ### 5.viii. 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).
@ -533,7 +580,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.vii. How can I change the format for echo messages? ### 5.ix. 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.
@ -562,7 +609,7 @@ See `:help g:ale_echo_msg_format` for more information.
<a name="faq-autocmd"></a> <a name="faq-autocmd"></a>
### 5.viii. How can I execute some code when ALE starts or stops linting? ### 5.x. 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
@ -585,7 +632,7 @@ augroup END
<a name="faq-navigation"></a> <a name="faq-navigation"></a>
### 5.ix. How can I navigate between errors quickly? ### 5.xi. 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
@ -601,7 +648,7 @@ For more information, consult the online documentation with
<a name="faq-lint-on-save"></a> <a name="faq-lint-on-save"></a>
### 5.x. How can I run linters only when I save files? ### 5.xii. 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
@ -622,7 +669,7 @@ files, you can set `g:ale_lint_on_save` to `0`.
<a name="faq-quickfix"></a> <a name="faq-quickfix"></a>
### 5.xi. How can I use the quickfix list instead of the loclist? ### 5.xiii. 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
@ -652,7 +699,7 @@ instead of the default horizontally.
<a name="faq-jsx-stylelint-eslint"></a> <a name="faq-jsx-stylelint-eslint"></a>
### 5.xii. How can I check JSX files with both stylelint and eslint? ### 5.xiv. 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.
@ -694,7 +741,7 @@ no linter will be run twice for the same file.
<a name="faq-vue-eslint"></a> <a name="faq-vue-eslint"></a>
### 5.xiii. How can I check Vue files with ESLint? ### 5.xv. 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).
@ -725,7 +772,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.xiv. Will this plugin eat all of my laptop battery power? ### 5.xvi. 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
@ -749,7 +796,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.xv. How can I configure my C or C++ project? ### 5.xvii. 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
@ -769,13 +816,24 @@ 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.xvi. How can I configure ALE differently for different buffers? ### 5.xviii. 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
@ -811,7 +869,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.xvii. How can I configure the height of the list in which ALE displays errors? ### 5.xix. 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.
@ -819,13 +877,3 @@ To set a default height for the error list, use the `g:ale_list_window_size` var
" Show 5 lines of errors (default: 10) " Show 5 lines of errors (default: 10)
let g:ale_list_window_size = 5 let g:ale_list_window_size = 5
``` ```
<a name="faq-get-info"></a>
### 5.xviii. How can I see what ALE has configured for the current file?
Run the following to see what is currently configured:
```vim
:ALEInfo
```

View file

@ -25,6 +25,11 @@ 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

@ -31,21 +31,28 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
" 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:files = globpath(l:path, '**/'.l:platform.'/**/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, '**/'.l:platform.'/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

View file

@ -11,6 +11,7 @@ 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# ''
@ -31,6 +32,9 @@ 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')
@ -82,6 +86,7 @@ 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

@ -13,14 +13,15 @@ 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[2] + 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[3], \ 'text': l:match[4],
\ 'filename': l:match[2],
\}) \})
endfor endfor
@ -28,13 +29,14 @@ 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[3] + 0, \ 'lnum': l:match[4] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[2] . ' ' . l:match[4], \ 'text': l:match[2] . ' ' . l:match[5],
\ 'filename': l:match[3],
\}) \})
endfor endfor

View file

@ -2,20 +2,13 @@
" 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_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']
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
@ -334,10 +327,6 @@ 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)
@ -346,6 +335,12 @@ function! ale#c#GetCFlags(buffer, output) abort
endif endif
endif endif
if ale#Var(a:buffer, 'c_parse_makefile')
\&& !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

View file

@ -16,7 +16,8 @@ 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_tsserver_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0) let g:ale_completion_autoimport = get(g:, 'ale_completion_autoimport', 0)
let g:ale_completion_tsserver_remove_warnings = get(g:, 'ale_completion_tsserver_remove_warnings', 0)
let s:timer_id = -1 let s:timer_id = -1
let s:last_done_pos = [] let s:last_done_pos = []
@ -397,10 +398,14 @@ 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
call add(l:names, { let l:kind = get(l:suggestion, 'kind', '')
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''), if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning'
\}) call add(l:names, {
\ 'word': l:suggestion.name,
\ 'source': get(l:suggestion, 'source', ''),
\})
endif
endfor endfor
return l:names return l:names
@ -413,12 +418,22 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
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
@ -431,11 +446,17 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items " See :help complete-items
let l:result = { let l:result = {
\ 'word': l:suggestion.name, \ 'word': (
\ 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': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ 'info': join(l:documentationParts, ''), \ 'info': join(l:documentationParts, ''),
\} \}
@ -517,6 +538,12 @@ 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 has_key(l:item, 'additionalTextEdits') && !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')
@ -661,12 +688,16 @@ 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,
\ 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

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))
\ . ' %t' \ . ' --stdin'
\ . ' --stdin-filepath=%s'
\ . ' ' . l:options, \ . ' ' . l:options,
\ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View file

@ -1,20 +1,41 @@
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 : '')
\ . ' --auto-correct --force-exclusion %t' \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
\ . ' --force-exclusion --stdin '
\ . ale#Escape(expand('#' . a:buffer . ':p'))
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),
\ 'read_temporary_file': 1, \ 'process_with': 'ale#fixers#rubocop#PostProcess'
\} \}
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
\ . ' --fix %t', \ . ' --outputAbsolutePaths --fix %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View file

@ -56,6 +56,137 @@ 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)
@ -82,40 +213,25 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
return return
endif endif
let l:result = l:result.contents let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents)
if type(l:result) is v:t_string if !empty(l:lines)
" The result can be just a string. if get(l:options, 'hover_from_balloonexpr', 0)
let l:result = [l:result] \&& exists('*balloon_show')
endif \&& ale#Var(l:options.buffer, 'set_balloons')
call balloon_show(join(l:lines, "\n"))
if type(l:result) is v:t_dict elseif get(l:options, 'truncated_echo', 0)
" If the result is an object, then it's markup content. call ale#cursor#TruncatedEcho(l:lines[0])
let l:result = has_key(l:result, 'value') ? [l:result.value] : [] elseif g:ale_hover_to_preview
endif call ale#preview#Show(l:lines, {
\ 'filetype': 'ale-preview.message',
if type(l:result) is v:t_list \ 'stay_here': 1,
" Replace objects with text values. \ 'commands': l:commands,
call filter(l:result, '!(type(v:val) is v:t_dict && !has_key(v:val, ''value''))') \})
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 get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(split(l:str, "\n")[0])
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
@ -187,6 +303,8 @@ 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('')
@ -197,11 +315,20 @@ endfunction
function! ale#hover#ShowTruncatedMessageAtCursor() abort function! ale#hover#ShowTruncatedMessageAtCursor() abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) let l:pos = getpos('.')[0:2]
if empty(l:loc) if l:pos != s:last_pos
let l:pos = getpos('.') let s:last_pos = l:pos
call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], {'truncated_echo': 1}) 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 endif
endfunction endfunction

View file

@ -14,6 +14,7 @@ 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',

View file

@ -31,6 +31,10 @@ 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

View file

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

View file

@ -16,7 +16,9 @@ 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
@ -25,10 +27,13 @@ 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"), { call ale#preview#Show(split(a:string, "\n"), extend(
\ 'filetype': 'ale-preview.message', \ {
\ 'stay_here': 1, \ 'filetype': 'ale-preview.message',
\}) \ 'stay_here': 1,
\ },
\ l:options,
\))
endif endif
endfunction endfunction
@ -418,7 +423,10 @@ 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
call writefile(l:corrected_lines, a:filename, 'S') " no-custom-checks " Set binary flag if buffer doesn't have eol and nofixeol to avoid appending newline
let l:flags = !getbufvar(a:buffer, '&eol') && exists('+fixeol') && !&fixeol ? 'bS' : 'S'
call writefile(l:corrected_lines, a:filename, l:flags) " no-custom-checks
endfunction endfunction
if !exists('s:patial_timers') if !exists('s:patial_timers')

View file

@ -37,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: `0` Default: `1`
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
@ -45,9 +45,6 @@ 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*
@ -58,6 +55,19 @@ 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.
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* astyle *ale-c-astyle*

View file

@ -25,13 +25,6 @@ Installation
Install PSScriptAnalyzer by any means, so long as it can be automatically Install PSScriptAnalyzer by any means, so long as it can be automatically
imported in PowerShell. imported in PowerShell.
Some PowerShell plugins set the filetype of files to `ps1`. To continue using
these plugins, use the ale_linter_aliases global to alias `ps1` to `powershell`
>
" Allow ps1 filetype to work with powershell linters
let g:ale_linter_aliases = {'ps1': 'powershell'}
<
g:ale_powershell_psscriptanalyzer_executable g:ale_powershell_psscriptanalyzer_executable
*g:ale_powershell_psscriptanalyzer_executable* *g:ale_powershell_psscriptanalyzer_executable*

View file

@ -114,6 +114,14 @@ g:ale_ruby_rubocop_options *g:ale_ruby_rubocop_options*
This variable can be changed to modify flags given to rubocop. This variable can be changed to modify flags given to rubocop.
g:ale_ruby_rubocop_auto_correct_all *g:ale_ruby_rubocop_auto_correct_all*
*b:ale_ruby_rubocop_auto_correct_all*
Type: Number
Default: `0`
This variable can be changed to make rubocop to correct all offenses (unsafe).
=============================================================================== ===============================================================================
ruby *ale-ruby-ruby* ruby *ale-ruby-ruby*
@ -172,8 +180,8 @@ g:ale_ruby_sorbet_options *g:ale_ruby_sorbet_options*
=============================================================================== ===============================================================================
standardrb *ale-ruby-standardrb* standardrb *ale-ruby-standardrb*
g:ale_ruby_standardrb_executable *g:ale_ruby_standardrb_executable* g:ale_ruby_standardrb_executable *g:ale_ruby_standardrb_executable*
*b:ale_ruby_standardrb_executable* *b:ale_ruby_standardrb_executable*
Type: String Type: String
Default: `'standardrb'` Default: `'standardrb'`

View file

@ -174,6 +174,18 @@ g:ale_rust_cargo_clippy_options
only `cargo clippy` supports (e.g. `--deny`). only `cargo clippy` supports (e.g. `--deny`).
g:ale_rust_cargo_target_dir
*g:ale_rust_cargo_target_dir*
*b:ale_rust_cargo_target_dir*
Type: |String|
Default: `''`
Use a custom target directory when running the commands for ALE. This can
help to avoid "waiting for file lock on build directory" messages when
running `cargo` commands manually while ALE is performing its checks.
=============================================================================== ===============================================================================
rls *ale-rust-rls* rls *ale-rust-rls*

View file

@ -246,7 +246,7 @@ A plugin might integrate its own checks with ALE like so: >
function! WorkDone(buffer, results) abort function! WorkDone(buffer, results) abort
" Send results to ALE after they have been collected. " Send results to ALE after they have been collected.
call ale#other_source#ShowResults(buffer, 'some-name', a:results) call ale#other_source#ShowResults(a:buffer, 'some-name', a:results)
endfunction endfunction
< <
@ -418,9 +418,12 @@ The |ALEComplete| command can be used to show completion suggestions manually,
even when |g:ale_completion_enabled| is set to `0`. For manually requesting even when |g:ale_completion_enabled| is set to `0`. For manually requesting
completion information with Deoplete, consult Deoplete's documentation. completion information with Deoplete, consult Deoplete's documentation.
When working with TypeScript files, ALE by can support automatic imports ALE by can support automatic imports from external modules. This behavior can
from external modules. This behavior can be enabled by setting the be enabled by setting the |g:ale_completion_autoimport| variable to `1`.
|g:ale_completion_tsserver_autoimport| variable to `1`.
When working with TypeScript files, ALE can remove warnings from your
completions by setting the |g:ale_completion_tsserver_remove_warnings|
variable to 1.
*ale-completion-completeopt-bug* *ale-completion-completeopt-bug*
@ -681,8 +684,16 @@ g:ale_completion_enabled *g:ale_completion_enabled*
See |ale-completion| See |ale-completion|
g:ale_completion_tsserver_remove_warnings *g:ale_completion_tsserver_remove_warnings*
g:ale_completion_tsserver_autoimport *g:ale_completion_tsserver_autoimport* Type: Number
Default: `0`
When this option is set to `0`, ALE will return all completion items,
including those that are a warning. Warnings can be excluded from completed
items by setting it to `1`.
g:ale_completion_autoimport *g:ale_completion_autoimport*
Type: Number Type: Number
Default: `0` Default: `0`
@ -1227,6 +1238,7 @@ g:ale_linter_aliases *g: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',

View file

@ -57,7 +57,7 @@ Execute(The build directory setting should override the options):
\ . ' -checks=' . ale#Escape('*') . ' %s' \ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar') \ . ' -p ' . ale#Escape('/foo/bar')
Execute(The build directory should be ignored for header files): Execute(The build directory should be used for header files):
call ale#test#SetFilename('test.h') call ale#test#SetFilename('test.h')
let b:ale_c_clangtidy_checks = ['*'] let b:ale_c_clangtidy_checks = ['*']
@ -66,12 +66,8 @@ Execute(The build directory should be ignored for header files):
AssertLinter 'clang-tidy', AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') \ ale#Escape('clang-tidy')
\ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall' \ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar')
call ale#test#SetFilename('test.h')
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
Execute(The executable should be configurable): Execute(The executable should be configurable):
let b:ale_c_clangtidy_checks = ['*'] let b:ale_c_clangtidy_checks = ['*']

View file

@ -169,10 +169,11 @@ Execute(Build supports all cargo flags):
let g:ale_rust_cargo_check_tests = 1 let g:ale_rust_cargo_check_tests = 1
let g:ale_rust_cargo_check_examples = 1 let g:ale_rust_cargo_check_examples = 1
let b:ale_rust_cargo_default_feature_behavior = 'all' let b:ale_rust_cargo_default_feature_behavior = 'all'
let b:ale_rust_cargo_target_dir = 'target/ale'
AssertLinter 'cargo', [ AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version', \ ale#Escape('cargo') . ' --version',
\ 'cargo build --all-targets --examples --tests --frozen --message-format=json -q --all-features', \ 'cargo build --all-targets --examples --tests --target-dir ' . ale#Escape('target/ale') . ' --frozen --message-format=json -q --all-features',
\] \]
Execute(Clippy supports all cargo flags): Execute(Clippy supports all cargo flags):
@ -182,10 +183,11 @@ Execute(Clippy supports all cargo flags):
let g:ale_rust_cargo_check_examples = 1 let g:ale_rust_cargo_check_examples = 1
let b:ale_rust_cargo_default_feature_behavior = 'all' let b:ale_rust_cargo_default_feature_behavior = 'all'
let b:ale_rust_cargo_clippy_options = '-D warnings' let b:ale_rust_cargo_clippy_options = '-D warnings'
let b:ale_rust_cargo_target_dir = 'target/ale'
AssertLinter 'cargo', [ AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version', \ ale#Escape('cargo') . ' --version',
\ 'cargo clippy --all-targets --examples --tests --frozen --message-format=json -q --all-features -- -D warnings', \ 'cargo clippy --all-targets --examples --tests --target-dir ' . ale#Escape('target/ale') . ' --frozen --message-format=json -q --all-features -- -D warnings',
\] \]
Execute(cargo-check does not refer ale_rust_cargo_clippy_options): Execute(cargo-check does not refer ale_rust_cargo_clippy_options):
@ -197,3 +199,21 @@ Execute(cargo-check does not refer ale_rust_cargo_clippy_options):
\ ale#Escape('cargo') . ' --version', \ ale#Escape('cargo') . ' --version',
\ 'cargo check --frozen --message-format=json -q', \ 'cargo check --frozen --message-format=json -q',
\] \]
Execute(`cargo --target-dir` should be used when the version is new enough and it is set):
let b:ale_rust_cargo_target_dir = 'target/ale'
GivenCommandOutput ['cargo 0.17.0 (3423351a5 2017-10-06)']
AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version',
\ 'cargo check --target-dir ' . ale#Escape('target/ale') . g:suffix,
\]
Execute(`cargo --target-dir` should not be used when the version is not new enough and it is set):
let b:ale_rust_cargo_target_dir = 'target/ale'
GivenCommandOutput ['cargo 0.16.0 (3423351a5 2017-10-06)']
AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version',
\ 'cargo build' . g:suffix,
\]

View file

@ -57,7 +57,7 @@ Execute(The build directory setting should override the options):
\ . ' -checks=' . ale#Escape('*') . ' %s' \ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar') \ . ' -p ' . ale#Escape('/foo/bar')
Execute(The build directory should be ignored for header files): Execute(The build directory should be used for header files):
call ale#test#SetFilename('test.h') call ale#test#SetFilename('test.h')
let b:ale_cpp_clangtidy_checks = ['*'] let b:ale_cpp_clangtidy_checks = ['*']
@ -66,12 +66,16 @@ Execute(The build directory should be ignored for header files):
AssertLinter 'clang-tidy', AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') \ ale#Escape('clang-tidy')
\ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall' \ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar')
\ . ' -- -x c++'
call ale#test#SetFilename('test.hpp') call ale#test#SetFilename('test.hpp')
AssertLinter 'clang-tidy', AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall' \ ale#Escape('clang-tidy')
\ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -p ' . ale#Escape('/foo/bar')
Execute(The executable should be configurable): Execute(The executable should be configurable):
let b:ale_cpp_clangtidy_checks = ['*'] let b:ale_cpp_clangtidy_checks = ['*']

View file

@ -34,18 +34,20 @@ Execute(The build directory should be configurable):
\ ale#Escape('clazy-standalone') \ ale#Escape('clazy-standalone')
\ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s' \ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s'
Execute(The build directory should be ignored for header files): Execute(The build directory should be used for header files):
call ale#test#SetFilename('test.h') call ale#test#SetFilename('test.h')
let b:ale_c_build_dir = '/foo/bar' let b:ale_c_build_dir = '/foo/bar'
AssertLinter 'clazy-standalone', AssertLinter 'clazy-standalone',
\ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' %s' \ ale#Escape('clazy-standalone')
\ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s'
call ale#test#SetFilename('test.hpp') call ale#test#SetFilename('test.hpp')
AssertLinter 'clazy-standalone', AssertLinter 'clazy-standalone',
\ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' %s' \ ale#Escape('clazy-standalone')
\ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s'
Execute(The executable should be configurable): Execute(The executable should be configurable):
let b:ale_cpp_clazy_executable = 'foobar' let b:ale_cpp_clazy_executable = 'foobar'

View file

@ -121,7 +121,7 @@ Execute(The right message should be sent for the initial tsserver request):
\ 'line': 1, \ 'line': 1,
\ 'offset': 3, \ 'offset': 3,
\ 'prefix': 'fo', \ 'prefix': 'fo',
\ 'includeExternalModuleExports': g:ale_completion_tsserver_autoimport, \ 'includeExternalModuleExports': g:ale_completion_autoimport,
\ }]], \ }]],
\ g:message_list \ g:message_list
" We should set up the completion info correctly. " We should set up the completion info correctly.

View file

@ -1,4 +1,12 @@
Before:
Save g:ale_completion_autoimport
Save g:ale_completion_max_suggestions
let g:ale_completion_max_suggestions = 50
After: After:
Restore
unlet! b:ale_completion_info unlet! b:ale_completion_info
Execute(Should handle Rust completion results correctly): Execute(Should handle Rust completion results correctly):
@ -527,7 +535,9 @@ Execute(Should handle completion messages with the deprecated insertText attribu
\ }, \ },
\ }) \ })
Execute(Should handle completion messages with additionalTextEdits): Execute(Should handle completion messages with additionalTextEdits when ale_completion_autoimport is turned on):
let g:ale_completion_autoimport = 1
AssertEqual AssertEqual
\ [ \ [
\ { \ {
@ -596,3 +606,42 @@ Execute(Should handle completion messages with additionalTextEdits):
\ ], \ ],
\ }, \ },
\ }) \ })
Execute(Should not handle completion messages with additionalTextEdits when ale_completion_autoimport is turned off):
let g:ale_completion_autoimport = 0
AssertEqual
\ [],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
\ 'jsonrpc': '2.0',
\ 'result': {
\ 'isIncomplete': v:false,
\ 'items': [
\ {
\ 'detail': 'PlayTimeCallback',
\ 'filterText': 'next_callback',
\ 'insertText': 'next_callback',
\ 'insertTextFormat': 1,
\ 'kind': 6,
\ 'label': ' next_callback',
\ 'sortText': '3ee19999next_callback',
\ 'additionalTextEdits': [
\ {
\ 'range': {
\ 'start': {
\ 'line': 10,
\ 'character': 1,
\ },
\ 'end': {
\ 'line': 12,
\ 'character': 3,
\ },
\ },
\ 'newText': 'from "module" import next_callback',
\ },
\ ],
\ },
\ ],
\ },
\ })

View file

@ -1,4 +1,11 @@
Before:
Save g:ale_completion_tsserver_remove_warnings
let g:ale_completion_tsserver_remove_warnings = 0
After: After:
Restore
unlet! b:ale_tsserver_completion_names unlet! b:ale_tsserver_completion_names
Execute(TypeScript completions responses should be parsed correctly): Execute(TypeScript completions responses should be parsed correctly):
@ -29,6 +36,51 @@ Execute(TypeScript completions responses should be parsed correctly):
\ ], \ ],
\}) \})
Execute(TypeScript completions responses should include warnings):
AssertEqual
\ [
\ {
\ 'word': 'foo',
\ 'source': '/path/to/foo.ts',
\ },
\ {
\ 'word': 'bar',
\ 'source': '',
\ },
\ {
\ 'word': 'baz',
\ 'source': '',
\ }
\ ],
\ ale#completion#ParseTSServerCompletions({
\ 'body': [
\ {'name': 'foo', 'source': '/path/to/foo.ts'},
\ {'name': 'bar', 'kind': 'warning'},
\ {'name': 'baz'},
\ ],
\})
Execute(TypeScript completions responses should not include warnings if excluded):
let g:ale_completion_tsserver_remove_warnings = 1
AssertEqual
\ [
\ {
\ 'word': 'foo',
\ 'source': '/path/to/foo.ts',
\ },
\ {
\ 'word': 'baz',
\ 'source': '',
\ }
\ ],
\ ale#completion#ParseTSServerCompletions({
\ 'body': [
\ {'name': 'foo', 'source': '/path/to/foo.ts'},
\ {'name': 'bar', 'kind': 'warning'},
\ {'name': 'baz'},
\ ],
\})
Execute(TypeScript completion details responses should be parsed correctly): Execute(TypeScript completion details responses should be parsed correctly):
AssertEqual AssertEqual
\ [ \ [
@ -38,7 +90,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '', \ 'info': '',
\ 'kind': 'v', \ 'kind': 'v',
\ 'icase': 1, \ 'icase': 1,
\ 'dup': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ }, \ },
\ { \ {
\ 'word': 'def', \ 'word': 'def',
@ -46,7 +98,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': 'foo bar baz', \ 'info': 'foo bar baz',
\ 'kind': 'v', \ 'kind': 'v',
\ 'icase': 1, \ 'icase': 1,
\ 'dup': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ }, \ },
\ { \ {
\ 'word': 'ghi', \ 'word': 'ghi',
@ -54,7 +106,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '', \ 'info': '',
\ 'kind': 'v', \ 'kind': 'v',
\ 'icase': 1, \ 'icase': 1,
\ 'dup': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ }, \ },
\ ], \ ],
\ ale#completion#ParseTSServerCompletionEntryDetails({ \ ale#completion#ParseTSServerCompletionEntryDetails({
@ -132,7 +184,7 @@ Execute(Entries without details should be included in the responses):
\ 'changes': [], \ 'changes': [],
\ }], \ }],
\ }), \ }),
\ 'dup': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ }, \ },
\ { \ {
\ 'word': 'def', \ 'word': 'def',
@ -140,7 +192,7 @@ Execute(Entries without details should be included in the responses):
\ 'info': 'foo bar baz', \ 'info': 'foo bar baz',
\ 'kind': 'v', \ 'kind': 'v',
\ 'icase': 1, \ 'icase': 1,
\ 'dup': g:ale_completion_tsserver_autoimport, \ 'dup': g:ale_completion_autoimport,
\ }, \ },
\ { \ {
\ 'word': 'xyz', \ 'word': 'xyz',
@ -197,3 +249,54 @@ Execute(Entries without details should be included in the responses):
\ }, \ },
\ ], \ ],
\}) \})
Execute(Default imports should be handled correctly):
AssertEqual
\ [
\ {
\ 'word': 'abcd',
\ 'menu': 'Import default ''abcd'' from module "./foo" (alias) const abcd: 3',
\ 'info': '',
\ 'kind': 't',
\ 'icase': 1,
\ 'user_data': json_encode({
\ 'codeActions': [{
\ 'description': 'Import default ''abcd'' from module "./foo"',
\ 'changes': [],
\ }],
\ }),
\ 'dup': g:ale_completion_autoimport,
\ },
\ ],
\ ale#completion#ParseTSServerCompletionEntryDetails({
\ 'body': [
\ {
\ 'name': 'default',
\ 'kind': 'alias',
\ 'displayParts': [
\ {'kind': 'punctuation', 'text': '('},
\ {'kind': 'text', 'text': 'alias'},
\ {'kind': 'punctuation', 'text': ')'},
\ {'kind': 'space', 'text': ' '},
\ {'kind': 'keyword', 'text': 'const'},
\ {'kind': 'space', 'text': ' '},
\ {'kind': 'localName', 'text': 'abcd'},
\ {'kind': 'punctuation', 'text': ':'},
\ {'kind': 'space', 'text': ' '},
\ {'kind': 'stringLiteral', 'text': '3'},
\ {'kind': 'lineBreak', 'text': '^@'},
\ {'kind': 'keyword', 'text': 'export'},
\ {'kind': 'space', 'text': ' '},
\ {'kind': 'keyword', 'text': 'default'},
\ {'kind': 'space', 'text': ' '},
\ {'kind': 'aliasName', 'text': 'abcd'}
\ ],
\ 'codeActions': [
\ {
\ 'description': 'Import default ''abcd'' from module "./foo"',
\ 'changes': [],
\ },
\ ],
\ },
\ ],
\ })

View file

@ -0,0 +1,19 @@
Before:
call ale#assert#SetUpFixerTest('javascript', 'prettier_standard')
silent cd ..
silent cd command_callback
let g:dir = getcwd()
After:
call ale#assert#TearDownFixerTest()
Execute(The prettier callback should return the correct default values):
call ale#test#SetFilename('../prettier-test-files/testfile.js')
AssertFixer
\ {
\ 'command': ale#Escape(g:ale_javascript_prettier_standard_executable)
\ . ' --stdin'
\ . ' --stdin-filepath=%s ',
\ }

View file

@ -21,9 +21,10 @@ Execute(The rubocop callback should return the correct default values):
AssertEqual AssertEqual
\ { \ {
\ 'read_temporary_file': 1, \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --auto-correct --force-exclusion %t', \ . ' --auto-correct --force-exclusion --stdin '
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
@ -32,10 +33,11 @@ Execute(The rubocop callback should include configuration files):
AssertEqual AssertEqual
\ { \ {
\ 'read_temporary_file': 1, \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml')) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --auto-correct --force-exclusion %t', \ . ' --auto-correct --force-exclusion --stdin '
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
@ -45,10 +47,64 @@ Execute(The rubocop callback should include custom rubocop options):
AssertEqual AssertEqual
\ { \ {
\ 'read_temporary_file': 1, \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml')) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --except Lint/Debugger' \ . ' --except Lint/Debugger'
\ . ' --auto-correct --force-exclusion %t', \ . ' --auto-correct --force-exclusion --stdin '
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
Execute(The rubocop callback should use auto-correct-all option when set):
let g:ale_ruby_rubocop_auto_correct_all = 1
call ale#test#SetFilename('ruby_paths/with_config/dummy.rb')
AssertEqual
\ {
\ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --auto-correct-all --force-exclusion --stdin '
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
Execute(The rubocop post-processor should remove diagnostics content):
AssertEqual
\ [
\ 'class MyModel < ApplicationRecord',
\ ' # rubocop:disable Rails/InverseOf',
\ ' has_one :something',
\ ' # rubocop:enable Rails/InverseOf',
\ 'end',
\ '',
\ 'array = [1, 2, 3,',
\ ' 4, 5, 6]',
\ 'array = [''run'',',
\ ' ''forrest'',',
\ ' ''run'']',
\ ],
\ ale#fixers#rubocop#PostProcess(bufnr(''), [
\ 'Inspecting 1 file',
\ 'C',
\ '',
\ 'Offenses:',
\ 'app/models/my_model.rb:8:3: C: [Corrected] Layout/ArrayAlignment: ',
\ '4, 5, 6]',
\ '^',
\ '',
\ '1 file inspected, 3 offenses detected, 3 offenses corrected',
\ '====================',
\ 'class MyModel < ApplicationRecord',
\ ' # rubocop:disable Rails/InverseOf',
\ ' has_one :something',
\ ' # rubocop:enable Rails/InverseOf',
\ 'end',
\ '',
\ 'array = [1, 2, 3,',
\ ' 4, 5, 6]',
\ 'array = [''run'',',
\ ' ''forrest'',',
\ ' ''run'']',
\ ])

View file

@ -27,7 +27,7 @@ Execute(The tslint callback should return the correct default values):
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\ 'command': ale#Escape('tslint') \ 'command': ale#Escape('tslint')
\ . ' -c ' . ale#Escape('tslint.json') \ . ' -c ' . ale#Escape('tslint.json')
\ . ' --fix %t', \ . ' --outputAbsolutePaths --fix %t',
\ }, \ },
\ ale#fixers#tslint#Fix(bufnr('')) \ ale#fixers#tslint#Fix(bufnr(''))
@ -40,6 +40,6 @@ Execute(The tslint callback should include custom tslint config option):
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\ 'command': ale#Escape('tslint') \ 'command': ale#Escape('tslint')
\ . ' -c ' . ale#Escape('.tslintrc') \ . ' -c ' . ale#Escape('.tslintrc')
\ . ' --fix %t', \ . ' --outputAbsolutePaths --fix %t',
\ }, \ },
\ ale#fixers#tslint#Fix(bufnr('')) \ ale#fixers#tslint#Fix(bufnr(''))

View file

@ -10,12 +10,14 @@ Execute(The vlog handler should parse old-style lines correctly):
\ { \ {
\ 'lnum': 7, \ 'lnum': 7,
\ 'type': 'W', \ 'type': 'W',
\ 'text': '(vlog-2623) Undefined variable: C.' \ 'text': '(vlog-2623) Undefined variable: C.',
\ 'filename': 'add.v'
\ }, \ },
\ { \ {
\ 'lnum': 1, \ 'lnum': 1,
\ 'type': 'E', \ 'type': 'E',
\ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.' \ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.',
\ 'filename': 'file.v'
\ }, \ },
\ ], \ ],
\ ale_linters#verilog#vlog#Handle(bufnr(''), [ \ ale_linters#verilog#vlog#Handle(bufnr(''), [
@ -29,12 +31,14 @@ Execute(The vlog handler should parse new-style lines correctly):
\ { \ {
\ 'lnum': 7, \ 'lnum': 7,
\ 'type': 'W', \ 'type': 'W',
\ 'text': '(vlog-2623) Undefined variable: C.' \ 'text': '(vlog-2623) Undefined variable: C.',
\ 'filename': 'add.v'
\ }, \ },
\ { \ {
\ 'lnum': 1, \ 'lnum': 1,
\ 'type': 'E', \ 'type': 'E',
\ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.' \ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.',
\ 'filename': 'file.v'
\ }, \ },
\ ], \ ],
\ ale_linters#verilog#vlog#Handle(bufnr(''), [ \ ale_linters#verilog#vlog#Handle(bufnr(''), [

View file

@ -5,7 +5,7 @@ Before:
let g:Callback = 0 let g:Callback = 0
let g:message_list = [] let g:message_list = []
let g:item_list = [] let g:item_list = []
let g:echo_list = [] let g:show_message_arg_list = []
runtime autoload/ale/linter.vim runtime autoload/ale/linter.vim
runtime autoload/ale/lsp.vim runtime autoload/ale/lsp.vim
@ -27,8 +27,8 @@ Before:
return 42 return 42
endfunction endfunction
function! ale#util#ShowMessage(string) abort function! ale#util#ShowMessage(string, ...) abort
call add(g:echo_list, a:string) call add(g:show_message_arg_list, [a:string] + a:000)
endfunction endfunction
function! HandleValidLSPResult(result) abort function! HandleValidLSPResult(result) abort
@ -58,7 +58,7 @@ After:
unlet! g:Callback unlet! g:Callback
unlet! g:message_list unlet! g:message_list
unlet! b:ale_linters unlet! b:ale_linters
unlet! g:echo_list unlet! g:show_message_arg_list
delfunction HandleValidLSPResult delfunction HandleValidLSPResult
@ -112,31 +112,31 @@ Execute(tsserver quickinfo displayString values should be displayed):
\ } \ }
\) \)
AssertEqual ['foo bar'], g:echo_list AssertEqual [['foo bar']], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover responses with just a string should be handled): Execute(LSP hover responses with just a string should be handled):
call HandleValidLSPResult({'contents': 'foobar'}) call HandleValidLSPResult({'contents': 'foobar'})
AssertEqual ['foobar'], g:echo_list AssertEqual [['foobar', {'commands': []}]], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover null responses should be handled): Execute(LSP hover null responses should be handled):
call HandleValidLSPResult(v:null) call HandleValidLSPResult(v:null)
AssertEqual [], g:echo_list AssertEqual [], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover responses with markup content should be handled): Execute(LSP hover responses with markup content should be handled):
call HandleValidLSPResult({'contents': {'kind': 'something', 'value': 'markup'}}) call HandleValidLSPResult({'contents': {'kind': 'markdown', 'value': 'markup'}})
AssertEqual ['markup'], g:echo_list AssertEqual [['markup', {'commands': []}]], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover responses with markup content missing values should be handled): Execute(LSP hover responses with markup content missing values should be handled):
call HandleValidLSPResult({'contents': {'kind': 'something'}}) call HandleValidLSPResult({'contents': {'kind': 'markdown'}})
AssertEqual [], g:echo_list AssertEqual [], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover response with lists of strings should be handled): Execute(LSP hover response with lists of strings should be handled):
@ -145,17 +145,27 @@ Execute(LSP hover response with lists of strings should be handled):
\ "bar\n", \ "bar\n",
\]}) \]})
AssertEqual ["foo\n\nbar\n"], g:echo_list AssertEqual [["foo\n\nbar", {'commands': []}]], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover response with lists of strings and marked strings should be handled): Execute(LSP hover response with lists of strings and marked strings should be handled):
call HandleValidLSPResult({'contents': [ call HandleValidLSPResult({'contents': [
\ {'language': 'rust', 'value': 'foo'}, \ {'language': 'rust', 'value': 'foo'},
\ {'language': 'foobar'},
\ "bar\n", \ "bar\n",
\]}) \]})
AssertEqual ["foo\nbar\n"], g:echo_list AssertEqual [
\ [
\ "foo\n\nbar",
\ {
\ 'commands': [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_rust syntax/rust.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%2l/ contains=@ALE_hover_rust',
\ ],
\ },
\ ],
\], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(tsserver responses for documentation requests should be handled): Execute(tsserver responses for documentation requests should be handled):

View file

@ -0,0 +1,173 @@
Execute(Invalid results should be handled):
AssertEqual [[], []], ale#hover#ParseLSPResult(0)
AssertEqual [[], []], ale#hover#ParseLSPResult([0])
AssertEqual [[], []], ale#hover#ParseLSPResult('')
AssertEqual [[], []], ale#hover#ParseLSPResult({})
AssertEqual [[], []], ale#hover#ParseLSPResult([{}])
AssertEqual [[], []], ale#hover#ParseLSPResult([''])
AssertEqual [[], []], ale#hover#ParseLSPResult({'value': ''})
AssertEqual [[], []], ale#hover#ParseLSPResult([{'value': ''}])
AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'markdown'})
AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'plaintext'})
AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'x', 'value': 'xxx'})
Execute(A string with a code fence should be handled):
AssertEqual
\ [
\ [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_python syntax/python.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python',
\ ],
\ [
\ 'def foo():',
\ ' pass',
\ ],
\ ],
\ ale#hover#ParseLSPResult(join([
\ '```python',
\ 'def foo():',
\ ' pass',
\ '```',
\ ], "\n"))
AssertEqual
\ [
\ [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_python syntax/python.vim',
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_typescript syntax/typescript.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python',
\ 'syntax region ALE_hover_2 start=/\%5l/ end=/\%8l/ contains=@ALE_hover_python',
\ 'syntax region ALE_hover_3 start=/\%8l/ end=/\%10l/ contains=@ALE_hover_typescript',
\ ],
\ [
\ 'def foo():',
\ ' pass',
\ '',
\ 'middle line',
\ '',
\ 'def bar():',
\ ' pass',
\ '',
\ 'const baz = () => undefined',
\ ],
\ ],
\ ale#hover#ParseLSPResult(join([
\ '```python',
\ 'def foo():',
\ ' pass',
\ '```',
\ 'middle line',
\ '```python',
\ 'def bar():',
\ ' pass',
\ '```',
\ '```typescript',
\ 'const baz = () => undefined',
\ '```',
\ ], "\n"))
Execute(Multiple strings with fences should be handled):
AssertEqual
\ [
\ [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_python syntax/python.vim',
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_typescript syntax/typescript.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python',
\ 'syntax region ALE_hover_2 start=/\%5l/ end=/\%8l/ contains=@ALE_hover_python',
\ 'syntax region ALE_hover_3 start=/\%8l/ end=/\%10l/ contains=@ALE_hover_typescript',
\ ],
\ [
\ 'def foo():',
\ ' pass',
\ '',
\ 'middle line',
\ '',
\ 'def bar():',
\ ' pass',
\ '',
\ 'const baz = () => undefined',
\ ],
\ ],
\ ale#hover#ParseLSPResult([
\ join([
\ '```python',
\ 'def foo():',
\ ' pass',
\ '```',
\ ], "\n"),
\ join([
\ 'middle line',
\ '```python',
\ 'def bar():',
\ ' pass',
\ '```',
\ '```typescript',
\ 'const baz = () => undefined',
\ '```',
\ ], "\n"),
\ ])
Execute(Objects with kinds should be handled):
AssertEqual
\ [
\ [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_python syntax/python.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python',
\ ],
\ [
\ 'def foo():',
\ ' pass',
\ '',
\ '```typescript',
\ 'const baz = () => undefined',
\ '```',
\ ],
\ ],
\ ale#hover#ParseLSPResult([
\ {
\ 'kind': 'markdown',
\ 'value': join([
\ '```python',
\ 'def foo():',
\ ' pass',
\ '```',
\ ], "\n"),
\ },
\ {
\ 'kind': 'plaintext',
\ 'value': join([
\ '```typescript',
\ 'const baz = () => undefined',
\ '```',
\ ], "\n"),
\ },
\ ])
Execute(Simple markdown formatting should be handled):
AssertEqual
\ [
\ [
\ 'unlet! b:current_syntax',
\ 'syntax include @ALE_hover_python syntax/python.vim',
\ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python',
\ ],
\ [
\ 'def foo():',
\ ' pass',
\ '',
\ 'formatted _ line _',
\ ],
\ ],
\ ale#hover#ParseLSPResult(join([
\ '```python',
\ 'def foo():',
\ ' pass',
\ '```',
\ 'formatted \_ line \_',
\ ], "\n"))

View file

@ -1,3 +1,6 @@
Before:
scriptencoding utf-8
Execute(ale#path#ToURI should work for Windows paths): Execute(ale#path#ToURI should work for Windows paths):
AssertEqual 'file:///C:/foo/bar/baz.tst', ale#path#ToURI('C:\foo\bar\baz.tst') AssertEqual 'file:///C:/foo/bar/baz.tst', ale#path#ToURI('C:\foo\bar\baz.tst')
AssertEqual 'foo/bar/baz.tst', ale#path#ToURI('foo\bar\baz.tst') AssertEqual 'foo/bar/baz.tst', ale#path#ToURI('foo\bar\baz.tst')
@ -62,3 +65,9 @@ Execute(ale#path#ToURI should percent encode unsafe characters):
Execute(ale#path#FromURI should decode percent encodings): Execute(ale#path#FromURI should decode percent encodings):
AssertEqual ' +:?&=', ale#path#FromURI('%20%2b%3a%3f%26%3d') AssertEqual ' +:?&=', ale#path#FromURI('%20%2b%3a%3f%26%3d')
Execute(ale#path#ToURI should handle UTF-8):
AssertEqual 'file:///T%c3%a9l%c3%a9chargement', ale#path#ToURI('/Téléchargement')
Execute(ale#path#FromURI should handle UTF-8):
AssertEqual '/Téléchargement', ale#path#FromURI('file:///T%C3%A9l%C3%A9chargement')

View file

@ -69,3 +69,49 @@ Execute(Unix file lines should be written as normal):
AssertEqual AssertEqual
\ ['first', 'second', 'third', ''], \ ['first', 'second', 'third', ''],
\ readfile(g:new_line_test_file, 'b') \ readfile(g:new_line_test_file, 'b')
Execute(Newline at end of file should be preserved even when nofixeol):
call ale#test#SetFilename(g:new_line_test_file)
setlocal buftype=
noautocmd :w
noautocmd :e! ++ff=unix
set eol
set nofixeol
call ale#util#Writefile(bufnr(''), getline(1, '$'), g:new_line_test_file)
AssertEqual
\ ['first', 'second', 'third', ''],
\ readfile(g:new_line_test_file, 'b')
Execute(Newline should not be appended on write when noeol and nofixeol):
call ale#test#SetFilename(g:new_line_test_file)
setlocal buftype=
noautocmd :w
noautocmd :e! ++ff=unix
set noeol
set nofixeol
call ale#util#Writefile(bufnr(''), getline(1, '$'), g:new_line_test_file)
AssertEqual
\ ['first', 'second', 'third'],
\ readfile(g:new_line_test_file, 'b')
Execute(Newline should be appended on write when noeol and fixeol):
call ale#test#SetFilename(g:new_line_test_file)
setlocal buftype=
noautocmd :w
noautocmd :e! ++ff=unix
set noeol
set fixeol
call ale#util#Writefile(bufnr(''), getline(1, '$'), g:new_line_test_file)
AssertEqual
\ ['first', 'second', 'third', ''],
\ readfile(g:new_line_test_file, 'b')