diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 00000000..e9cda3d9
--- /dev/null
+++ b/.github/stale.yml
@@ -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
diff --git a/README.md b/README.md
index dcc4ed38..ffc6dd19 100644
--- a/README.md
+++ b/README.md
@@ -61,23 +61,24 @@ other content at [w0rp.com](https://w0rp.com).
4. [Contributing](#contributing)
5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters)
- 2. [How can I keep the sign gutter open?](#faq-keep-signs)
- 3. [How can I change the signs ALE uses?](#faq-change-signs)
- 4. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
- 5. [How can I show errors or warnings in my statusline?](#faq-statusline)
- 6. [How can I show errors or warnings in my lightline?](#faq-lightline)
- 7. [How can I change the format for echo messages?](#faq-echo-format)
- 8. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
- 9. [How can I navigate between errors quickly?](#faq-navigation)
- 10. [How can I run linters only when I save files?](#faq-lint-on-save)
- 11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
- 12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
- 13. [How can I check Vue files with ESLint?](#faq-vue-eslint)
- 14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
- 15. [How can I configure my C or C++ project?](#faq-c-configuration)
- 16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
- 17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
- 18. [How can I see what ALE has configured for the current file?](#faq-get-info)
+ 2. [How can I see what ALE has configured for the current file?](#faq-get-info)
+ 3. [How can I use ALE and coc.nvim together?](#faq-coc-nvim)
+ 4. [How can I keep the sign gutter open?](#faq-keep-signs)
+ 5. [How can I change the signs ALE uses?](#faq-change-signs)
+ 6. [How can I change or disable the highlights ALE uses?](#faq-change-highlights)
+ 7. [How can I show errors or warnings in my statusline?](#faq-statusline)
+ 8. [How can I show errors or warnings in my lightline?](#faq-lightline)
+ 9. [How can I change the format for echo messages?](#faq-echo-format)
+ 10. [How can I execute some code when ALE starts or stops linting?](#faq-autocmd)
+ 11. [How can I navigate between errors quickly?](#faq-navigation)
+ 12. [How can I run linters only when I save files?](#faq-lint-on-save)
+ 13. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
+ 14. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
+ 15. [How can I check Vue files with ESLint?](#faq-vue-eslint)
+ 16. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
+ 17. [How can I configure my C or C++ project?](#faq-c-configuration)
+ 18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
+ 19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
@@ -193,12 +194,11 @@ completion manually with ``.
set omnifunc=ale#completion#OmniFunc
```
-When working with TypeScript files, ALE supports automatic imports from
-external modules. This behavior is disabled by default and can be enabled by
-setting:
+ALE supports automatic imports from external modules. This behavior is disabled
+by default and can be enabled by setting:
```vim
-let g:ale_completion_tsserver_autoimport = 1
+let g:ale_completion_autoimport = 1
```
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
in each directory corresponds to the name of a particular linter.
+
+
+### 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
+```
+
+
+
+### 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`.
+
-### 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
`g:ale_sign_column_always` to 1
@@ -429,7 +476,7 @@ let g:ale_sign_column_always = 1
-### 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:
@@ -449,7 +496,7 @@ highlight clear ALEWarningSign
-### 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`,
`SpellCap`, `error`, and `todo` groups by default. The characters that are
@@ -475,7 +522,7 @@ See `:help ale-highlights` for more information.
-### 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
for displaying error information in the status bar. If you want to see the
@@ -524,7 +571,7 @@ for more information.
-### 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
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
-### 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.
@@ -562,7 +609,7 @@ See `:help g:ale_echo_msg_format` for more information.
-### 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)
events when a lint or fix cycle are started and stopped. There is also an event
@@ -585,7 +632,7 @@ augroup END
-### 5.ix. How can I navigate between errors quickly?
+### 5.xi. How can I navigate between errors quickly?
ALE offers some commands with `` keybinds for moving between warnings and
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
-### 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
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`.
-### 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`
option on. If you wish to also disable the loclist, you can disable
@@ -652,7 +699,7 @@ instead of the default horizontally.
-### 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
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.
-### 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
configured to use the [Vue plugin](https://github.com/vuejs/eslint-plugin-vue).
@@ -725,7 +772,7 @@ let g:ale_linters = {'vue': ['eslint', 'vls']}
-### 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
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
-### 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
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
want to use only `gcc` for one project, and only `clang` for another.
+ALE will attempt to parse `compile_commands.json` files to discover compiler
+flags to use when linting code. See `:help g:ale_c_parse_compile_commands` for
+more information. See Clang's documentation for
+[compile_commands.json files](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
+You should strongly consider generating them in your builds, which is easy to do
+with CMake.
+
+You can also configure ALE to automatically run `make -n` to run dry runs on
+`Makefile`s to discover compiler flags. This can execute arbitrary code, so the
+option is disabled by default. See `:help g:ale_c_parse_makefile`.
+
You may also configure buffer-local settings for linters with project-specific
vimrc files. [local_vimrc](https://github.com/LucHermitte/local_vimrc) can be
used for executing local vimrc files which can be shared in your project.
-### 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
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.
-### 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.
@@ -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)
let g:ale_list_window_size = 5
```
-
-
-
-### 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
-```
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 191b7b07..5e062d86 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -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
endif
+ " Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file.
+ if expand('#' . a:buffer) =~# '\.h$'
+ let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
+ endif
+
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
diff --git a/ale_linters/java/eclipselsp.vim b/ale_linters/java/eclipselsp.vim
index c981b749..8bc09039 100644
--- a/ale_linters/java/eclipselsp.vim
+++ b/ale_linters/java/eclipselsp.vim
@@ -31,21 +31,28 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
" 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)
- if len(l:files) > 1
+ if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within VSCode extensions folder.
let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
- 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]
endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
- if len(l:files) > 1
+ if len(l:files) >= 1
return l:files[0]
endif
diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim
index 99178585..3407abed 100644
--- a/ale_linters/rust/cargo.vim
+++ b/ale_linters/rust/cargo.vim
@@ -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_use_clippy', 0)
call ale#Set('rust_cargo_clippy_options', '')
+call ale#Set('rust_cargo_target_dir', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@@ -31,6 +32,9 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0])
+ let l:target_dir = ale#Var(a:buffer, 'rust_cargo_target_dir')
+ let l:use_target_dir = !empty(l:target_dir)
+ \ && ale#semver#GTE(a:version, [0, 17, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
@@ -82,6 +86,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
+ \ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features
diff --git a/ale_linters/verilog/vlog.vim b/ale_linters/verilog/vlog.vim
index 951e2037..45e1977c 100644
--- a/ale_linters/verilog/vlog.vim
+++ b/ale_linters/verilog/vlog.vim
@@ -13,14 +13,15 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"Matches patterns like the following:
"** Warning: add.v(7): (vlog-2623) Undefined variable: C.
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C.
- let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
+ let l:pattern = '^**\s\(\w*\): \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
- \ 'lnum': l:match[2] + 0,
+ \ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
- \ 'text': l:match[3],
+ \ 'text': l:match[4],
+ \ 'filename': l:match[2],
\})
endfor
@@ -28,13 +29,14 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"** Warning: (vlog-2623) add.v(7): Undefined variable: C.
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.
" let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
- let l:pattern = '^**\s\(\w*\):\s\([^)]*)\)[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
+ let l:pattern = '^**\s\(\w*\):\s\([^)]*)\) \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
- \ 'lnum': l:match[3] + 0,
+ \ 'lnum': l:match[4] + 0,
\ '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
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim
index 9b428700..39892d42 100644
--- a/autoload/ale/c.vim
+++ b/autoload/ale/c.vim
@@ -2,20 +2,13 @@
" Description: Functions for integrating with C-family linters.
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') ? '\' : '/'
" Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
function! ale#c#GetBuildDirectory(buffer) abort
- " Don't include build directory for header files, as compile_commands.json
- " files don't consider headers to be translation units, and provide no
- " commands for compiling header files.
- if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
- return ''
- endif
-
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
" c_build_dir has the priority if defined
@@ -334,10 +327,6 @@ endfunction
function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = v:null
- if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
- let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
- endif
-
if ale#Var(a:buffer, 'c_parse_compile_commands')
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
@@ -346,6 +335,12 @@ function! ale#c#GetCFlags(buffer, output) abort
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
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif
diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim
index b00fc6a3..a273d4e1 100644
--- a/autoload/ale/completion.vim
+++ b/autoload/ale/completion.vim
@@ -16,7 +16,8 @@ onoremap (ale_show_completion_menu)
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
-let g:ale_completion_tsserver_autoimport = get(g:, 'ale_completion_tsserver_autoimport', 0)
+let 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:last_done_pos = []
@@ -397,10 +398,14 @@ function! ale#completion#ParseTSServerCompletions(response) abort
let l:names = []
for l:suggestion in a:response.body
- call add(l:names, {
- \ 'word': l:suggestion.name,
- \ 'source': get(l:suggestion, 'source', ''),
- \})
+ let l:kind = get(l:suggestion, 'kind', '')
+
+ if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning'
+ call add(l:names, {
+ \ 'word': l:suggestion.name,
+ \ 'source': get(l:suggestion, 'source', ''),
+ \})
+ endif
endfor
return l:names
@@ -413,12 +418,22 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
for l:suggestion in a:response.body
let l:displayParts = []
+ let l:local_name = v:null
for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ')
endfor
for l:part in l:suggestion.displayParts
+ " Stop on stop on line breaks for the menu.
+ if get(l:part, 'kind') is# 'lineBreak'
+ break
+ endif
+
+ if get(l:part, 'kind') is# 'localName'
+ let l:local_name = l:part.text
+ endif
+
call add(l:displayParts, l:part.text)
endfor
@@ -431,11 +446,17 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items
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),
\ 'icase': 1,
\ 'menu': join(l:displayParts, ''),
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ 'info': join(l:documentationParts, ''),
\}
@@ -517,6 +538,12 @@ function! ale#completion#ParseLSPCompletions(response) abort
continue
endif
+ " Don't use LSP items with additional text edits when autoimport for
+ " completions is turned off.
+ if has_key(l:item, 'additionalTextEdits') && !g:ale_completion_autoimport
+ continue
+ endif
+
let l:doc = get(l:item, 'documentation', '')
if type(l:doc) is v:t_dict && has_key(l:doc, 'value')
@@ -661,12 +688,16 @@ function! s:OnReady(linter, lsp_details) abort
call ale#lsp#RegisterCallback(l:id, l:Callback)
if a:linter.lsp is# 'tsserver'
+ if get(g:, 'ale_completion_tsserver_autoimport') is 1
+ execute 'echom `g:ale_completion_tsserver_autoimport` is deprecated. Use `g:ale_completion_autoimport` instead.'''
+ endif
+
let l:message = ale#lsp#tsserver_message#Completions(
\ l:buffer,
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ b:ale_completion_info.prefix,
- \ g:ale_completion_tsserver_autoimport,
+ \ g:ale_completion_autoimport,
\)
else
" Send a message saying the buffer has changed first, otherwise
diff --git a/autoload/ale/fixers/prettier_standard.vim b/autoload/ale/fixers/prettier_standard.vim
index b6e0a6f9..9d982ff6 100644
--- a/autoload/ale/fixers/prettier_standard.vim
+++ b/autoload/ale/fixers/prettier_standard.vim
@@ -17,8 +17,8 @@ function! ale#fixers#prettier_standard#Fix(buffer) abort
return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
- \ . ' %t'
+ \ . ' --stdin'
+ \ . ' --stdin-filepath=%s'
\ . ' ' . l:options,
- \ 'read_temporary_file': 1,
\}
endfunction
diff --git a/autoload/ale/fixers/rubocop.vim b/autoload/ale/fixers/rubocop.vim
index 0c7441e4..d9615256 100644
--- a/autoload/ale/fixers/rubocop.vim
+++ b/autoload/ale/fixers/rubocop.vim
@@ -1,20 +1,41 @@
call ale#Set('ruby_rubocop_options', '')
+call ale#Set('ruby_rubocop_auto_correct_all', 0)
call ale#Set('ruby_rubocop_executable', 'rubocop')
+" Rubocop fixer outputs diagnostics first and then the fixed
+" output. These are delimited by a "=======" string that we
+" look for to remove everything before it.
+function! ale#fixers#rubocop#PostProcess(buffer, output) abort
+ let l:line = 0
+
+ for l:output in a:output
+ let l:line = l:line + 1
+
+ if l:output =~# "^=\\+$"
+ break
+ endif
+ endfor
+
+ return a:output[l:line :]
+endfunction
+
function! ale#fixers#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options')
+ let l:auto_correct_all = ale#Var(a:buffer, 'ruby_rubocop_auto_correct_all')
return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --auto-correct --force-exclusion %t'
+ \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
+ \ . ' --force-exclusion --stdin '
+ \ . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction
function! ale#fixers#rubocop#Fix(buffer) abort
return {
\ 'command': ale#fixers#rubocop#GetCommand(a:buffer),
- \ 'read_temporary_file': 1,
+ \ 'process_with': 'ale#fixers#rubocop#PostProcess'
\}
endfunction
diff --git a/autoload/ale/fixers/tslint.vim b/autoload/ale/fixers/tslint.vim
index b352af3a..15768fd5 100644
--- a/autoload/ale/fixers/tslint.vim
+++ b/autoload/ale/fixers/tslint.vim
@@ -16,7 +16,7 @@ function! ale#fixers#tslint#Fix(buffer) abort
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . l:tslint_config_option
- \ . ' --fix %t',
+ \ . ' --outputAbsolutePaths --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction
diff --git a/autoload/ale/hover.vim b/autoload/ale/hover.vim
index a6462227..168ff424 100644
--- a/autoload/ale/hover.vim
+++ b/autoload/ale/hover.vim
@@ -56,6 +56,137 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
endif
endfunction
+" Convert a language name to another one.
+" The language name could be an empty string or v:null
+function! s:ConvertLanguageName(language) abort
+ return a:language
+endfunction
+
+function! ale#hover#ParseLSPResult(contents) abort
+ let l:includes = {}
+ let l:highlights = []
+ let l:lines = []
+ let l:list = type(a:contents) is v:t_list ? a:contents : [a:contents]
+ let l:region_index = 0
+
+ for l:item in l:list
+ if !empty(l:lines)
+ call add(l:lines, '')
+ endif
+
+ if type(l:item) is v:t_dict && has_key(l:item, 'kind')
+ if l:item.kind is# 'markdown'
+ " Handle markdown values as we handle strings below.
+ let l:item = get(l:item, 'value', '')
+ elseif l:item.kind is# 'plaintext'
+ " We shouldn't try to parse plaintext as markdown.
+ " Pass the lines on and skip parsing them.
+ call extend(l:lines, split(get(l:item, 'value', ''), "\n"))
+
+ continue
+ endif
+ endif
+
+ let l:marked_list = []
+
+ " If the item is a string, then we should parse it as Markdown text.
+ if type(l:item) is v:t_string
+ let l:fence_language = v:null
+ let l:fence_lines = []
+
+ for l:line in split(l:item, "\n")
+ if l:fence_language is v:null
+ " Look for the start of a code fence. (```python, etc.)
+ let l:match = matchlist(l:line, '^```\(.*\)$')
+
+ if !empty(l:match)
+ let l:fence_language = l:match[1]
+
+ if !empty(l:marked_list)
+ call add(l:fence_lines, '')
+ endif
+ else
+ if !empty(l:marked_list)
+ \&& l:marked_list[-1][0] isnot v:null
+ call add(l:marked_list, [v:null, ['']])
+ endif
+
+ call add(l:marked_list, [v:null, [l:line]])
+ endif
+ elseif l:line =~# '^```$'
+ " When we hit the end of a code fence, pass the fenced
+ " lines on to the next steps below.
+ call add(l:marked_list, [l:fence_language, l:fence_lines])
+ let l:fence_language = v:null
+ let l:fence_lines = []
+ else
+ " Gather lines inside of a code fence.
+ call add(l:fence_lines, l:line)
+ endif
+ endfor
+ " If the result from the LSP server is a {language: ..., value: ...}
+ " Dictionary, then that should be interpreted as if it was:
+ "
+ " ```${language}
+ " ${value}
+ " ```
+ elseif type(l:item) is v:t_dict
+ \&& has_key(l:item, 'language')
+ \&& type(l:item.language) is v:t_string
+ \&& has_key(l:item, 'value')
+ \&& type(l:item.value) is v:t_string
+ call add(
+ \ l:marked_list,
+ \ [l:item.language, split(l:item.value, "\n")],
+ \)
+ endif
+
+ for [l:language, l:marked_lines] in l:marked_list
+ if l:language is v:null
+ " NOTE: We could handle other Markdown formatting here.
+ call map(
+ \ l:marked_lines,
+ \ 'substitute(v:val, ''\\_'', ''_'', ''g'')',
+ \)
+ else
+ let l:language = s:ConvertLanguageName(l:language)
+
+ if !empty(l:language)
+ let l:includes[l:language] = printf(
+ \ 'syntax/%s.vim',
+ \ l:language,
+ \)
+
+ let l:start = len(l:lines) + 1
+ let l:end = l:start + len(l:marked_lines)
+ let l:region_index += 1
+
+ call add(l:highlights, 'syntax region'
+ \ . ' ALE_hover_' . l:region_index
+ \ . ' start=/\%' . l:start . 'l/'
+ \ . ' end=/\%' . l:end . 'l/'
+ \ . ' contains=@ALE_hover_' . l:language
+ \)
+ endif
+ endif
+
+ call extend(l:lines, l:marked_lines)
+ endfor
+ endfor
+
+ let l:include_commands = []
+
+ for [l:language, l:lang_path] in sort(items(l:includes))
+ call add(l:include_commands, 'unlet! b:current_syntax')
+ call add(
+ \ l:include_commands,
+ \ printf('syntax include @ALE_hover_%s %s', l:language, l:lang_path),
+ \)
+ endfor
+
+ return [l:include_commands + l:highlights, l:lines]
+endfunction
+
function! ale#hover#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:hover_map, a:response.id)
@@ -82,40 +213,25 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
return
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
- " The result can be just a string.
- let l:result = [l:result]
- endif
-
- if type(l:result) is v:t_dict
- " If the result is an object, then it's markup content.
- let l:result = has_key(l:result, 'value') ? [l:result.value] : []
- endif
-
- if type(l:result) is v:t_list
- " Replace objects with text values.
- 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')
- let l:str = join(l:result, "\n")
- let l:str = substitute(l:str, '^\s*\(.\{-}\)\s*$', '\1', '')
-
- if !empty(l:str)
- if get(l:options, 'hover_from_balloonexpr', 0)
- \&& exists('*balloon_show')
- \&& ale#Var(l:options.buffer, 'set_balloons')
- call balloon_show(l:str)
- elseif 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
+ if !empty(l:lines)
+ if get(l:options, 'hover_from_balloonexpr', 0)
+ \&& exists('*balloon_show')
+ \&& ale#Var(l:options.buffer, 'set_balloons')
+ call balloon_show(join(l:lines, "\n"))
+ elseif get(l:options, 'truncated_echo', 0)
+ call ale#cursor#TruncatedEcho(l:lines[0])
+ elseif g:ale_hover_to_preview
+ call ale#preview#Show(l:lines, {
+ \ 'filetype': 'ale-preview.message',
+ \ 'stay_here': 1,
+ \ 'commands': l:commands,
+ \})
+ else
+ call ale#util#ShowMessage(join(l:lines, "\n"), {
+ \ 'commands': l:commands,
+ \})
endif
endif
endif
@@ -187,6 +303,8 @@ function! ale#hover#Show(buffer, line, col, opt) abort
endfor
endfunction
+let s:last_pos = [0, 0, 0]
+
" This function implements the :ALEHover command.
function! ale#hover#ShowAtCursor() abort
let l:buffer = bufnr('')
@@ -197,11 +315,20 @@ endfunction
function! ale#hover#ShowTruncatedMessageAtCursor() abort
let l:buffer = bufnr('')
- let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
+ let l:pos = getpos('.')[0:2]
- if empty(l:loc)
- let l:pos = getpos('.')
- call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], {'truncated_echo': 1})
+ 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
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index f81b62be..0e935149 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -14,6 +14,7 @@ let s:default_ale_linter_aliases = {
\ 'csh': 'sh',
\ 'javascriptreact': ['javascript', 'jsx'],
\ 'plaintex': 'tex',
+\ 'ps1': 'powershell',
\ 'rmarkdown': 'r',
\ 'rmd': 'r',
\ 'systemverilog': 'verilog',
diff --git a/autoload/ale/preview.vim b/autoload/ale/preview.vim
index 7902ec63..faf45cb0 100644
--- a/autoload/ale/preview.vim
+++ b/autoload/ale/preview.vim
@@ -31,6 +31,10 @@ function! ale#preview#Show(lines, ...) abort
setlocal readonly
let &l:filetype = get(l:options, 'filetype', 'ale-preview')
+ for l:command in get(l:options, 'commands', [])
+ call execute(l:command)
+ endfor
+
if get(l:options, 'stay_here')
wincmd p
endif
diff --git a/autoload/ale/uri.vim b/autoload/ale/uri.vim
index 934637d9..e71c6340 100644
--- a/autoload/ale/uri.vim
+++ b/autoload/ale/uri.vim
@@ -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
return substitute(
\ a:value,
\ '\([^a-zA-Z0-9\\/$\-_.!*''(),]\)',
- \ '\=printf(''%%%02x'', char2nr(submatch(1)))',
+ \ '\=s:EncodeChar(submatch(1))',
\ 'g'
\)
endfunction
@@ -12,7 +21,7 @@ function! ale#uri#Decode(value) abort
return substitute(
\ a:value,
\ '%\(\x\x\)',
- \ '\=nr2char(''0x'' . submatch(1))',
+ \ '\=printf("%c", str2nr(submatch(1), 16))',
\ 'g'
\)
endfunction
diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim
index ee62af28..1f396377 100644
--- a/autoload/ale/util.vim
+++ b/autoload/ale/util.vim
@@ -16,7 +16,9 @@ endfunction
" Vim 8 does not support echoing long messages from asynchronous callbacks,
" but NeoVim does. Small messages can be echoed in Vim 8, and larger messages
" have to be shown in preview windows.
-function! ale#util#ShowMessage(string) abort
+function! ale#util#ShowMessage(string, ...) abort
+ let l:options = get(a:000, 0, {})
+
if !has('nvim')
call ale#preview#CloseIfTypeMatches('ale-preview.message')
endif
@@ -25,10 +27,13 @@ function! ale#util#ShowMessage(string) abort
if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns)
execute 'echo a:string'
else
- call ale#preview#Show(split(a:string, "\n"), {
- \ 'filetype': 'ale-preview.message',
- \ 'stay_here': 1,
- \})
+ call ale#preview#Show(split(a:string, "\n"), extend(
+ \ {
+ \ 'filetype': 'ale-preview.message',
+ \ 'stay_here': 1,
+ \ },
+ \ l:options,
+ \))
endif
endfunction
@@ -418,7 +423,10 @@ function! ale#util#Writefile(buffer, lines, filename) abort
\ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : 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
if !exists('s:patial_timers')
diff --git a/doc/ale-c.txt b/doc/ale-c.txt
index efc26f93..fc0d941a 100644
--- a/doc/ale-c.txt
+++ b/doc/ale-c.txt
@@ -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*
*b:ale_c_parse_compile_commands*
Type: |Number|
- Default: `0`
+ Default: `1`
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
@@ -45,9 +45,6 @@ g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
`compile_commands.json` files in the directories for
|g:ale_c_build_dir_names|.
- If |g:ale_c_parse_makefile| or |b:ale_c_parse_makefile| is set to `1`, the
- output of `make -n` will be preferred over `compile_commands.json` files.
-
g:ale_c_parse_makefile *g:ale_c_parse_makefile*
*b:ale_c_parse_makefile*
@@ -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
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*
diff --git a/doc/ale-powershell.txt b/doc/ale-powershell.txt
index c28ef9ea..485c9bd0 100644
--- a/doc/ale-powershell.txt
+++ b/doc/ale-powershell.txt
@@ -25,13 +25,6 @@ Installation
Install PSScriptAnalyzer by any means, so long as it can be automatically
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*
diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt
index a27a20b2..8815404a 100644
--- a/doc/ale-ruby.txt
+++ b/doc/ale-ruby.txt
@@ -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.
+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*
@@ -172,8 +180,8 @@ g:ale_ruby_sorbet_options *g:ale_ruby_sorbet_options*
===============================================================================
standardrb *ale-ruby-standardrb*
-g:ale_ruby_standardrb_executable *g:ale_ruby_standardrb_executable*
- *b:ale_ruby_standardrb_executable*
+g:ale_ruby_standardrb_executable *g:ale_ruby_standardrb_executable*
+ *b:ale_ruby_standardrb_executable*
Type: String
Default: `'standardrb'`
diff --git a/doc/ale-rust.txt b/doc/ale-rust.txt
index 46d4714b..2c0222b7 100644
--- a/doc/ale-rust.txt
+++ b/doc/ale-rust.txt
@@ -174,6 +174,18 @@ g:ale_rust_cargo_clippy_options
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*
diff --git a/doc/ale.txt b/doc/ale.txt
index a19c6060..1951d7bd 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -246,7 +246,7 @@ A plugin might integrate its own checks with ALE like so: >
function! WorkDone(buffer, results) abort
" 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
<
@@ -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
completion information with Deoplete, consult Deoplete's documentation.
-When working with TypeScript files, ALE by can support automatic imports
-from external modules. This behavior can be enabled by setting the
-|g:ale_completion_tsserver_autoimport| variable to `1`.
+ALE by can support automatic imports from external modules. This behavior can
+be enabled by setting the |g:ale_completion_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*
@@ -681,8 +684,16 @@ g:ale_completion_enabled *g:ale_completion_enabled*
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
Default: `0`
@@ -1227,6 +1238,7 @@ g:ale_linter_aliases *g:ale_linter_aliases*
\ 'csh': 'sh',
\ 'javascriptreact': ['javascript', 'jsx'],
\ 'plaintex': 'tex',
+ \ 'ps1': 'powershell',
\ 'rmarkdown': 'r',
\ 'rmd': 'r',
\ 'systemverilog': 'verilog',
diff --git a/test/command_callback/test_c_clang_tidy_command_callback.vader b/test/command_callback/test_c_clang_tidy_command_callback.vader
index 5ebbbd45..c4433550 100644
--- a/test/command_callback/test_c_clang_tidy_command_callback.vader
+++ b/test/command_callback/test_c_clang_tidy_command_callback.vader
@@ -57,7 +57,7 @@ Execute(The build directory setting should override the options):
\ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -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')
let b:ale_c_clangtidy_checks = ['*']
@@ -66,12 +66,8 @@ Execute(The build directory should be ignored for header files):
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy')
- \ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
-
- call ale#test#SetFilename('test.h')
-
- AssertLinter 'clang-tidy',
- \ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
+ \ . ' -checks=' . ale#Escape('*') . ' %s'
+ \ . ' -p ' . ale#Escape('/foo/bar')
Execute(The executable should be configurable):
let b:ale_c_clangtidy_checks = ['*']
diff --git a/test/command_callback/test_cargo_command_callbacks.vader b/test/command_callback/test_cargo_command_callbacks.vader
index e56551ae..2d83351e 100644
--- a/test/command_callback/test_cargo_command_callbacks.vader
+++ b/test/command_callback/test_cargo_command_callbacks.vader
@@ -169,10 +169,11 @@ Execute(Build supports all cargo flags):
let g:ale_rust_cargo_check_tests = 1
let g:ale_rust_cargo_check_examples = 1
let b:ale_rust_cargo_default_feature_behavior = 'all'
+ let b:ale_rust_cargo_target_dir = 'target/ale'
AssertLinter 'cargo', [
\ 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):
@@ -182,10 +183,11 @@ Execute(Clippy supports all cargo flags):
let g:ale_rust_cargo_check_examples = 1
let b:ale_rust_cargo_default_feature_behavior = 'all'
let b:ale_rust_cargo_clippy_options = '-D warnings'
+ let b:ale_rust_cargo_target_dir = 'target/ale'
AssertLinter 'cargo', [
\ 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):
@@ -197,3 +199,21 @@ Execute(cargo-check does not refer ale_rust_cargo_clippy_options):
\ ale#Escape('cargo') . ' --version',
\ '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,
+ \]
diff --git a/test/command_callback/test_clang_tidy_command_callback.vader b/test/command_callback/test_clang_tidy_command_callback.vader
index c2d18dea..f0a07e8c 100644
--- a/test/command_callback/test_clang_tidy_command_callback.vader
+++ b/test/command_callback/test_clang_tidy_command_callback.vader
@@ -57,7 +57,7 @@ Execute(The build directory setting should override the options):
\ . ' -checks=' . ale#Escape('*') . ' %s'
\ . ' -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')
let b:ale_cpp_clangtidy_checks = ['*']
@@ -66,12 +66,16 @@ Execute(The build directory should be ignored for header files):
AssertLinter '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')
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):
let b:ale_cpp_clangtidy_checks = ['*']
diff --git a/test/command_callback/test_cpp_clazy_command_callback.vader b/test/command_callback/test_cpp_clazy_command_callback.vader
index 1be43b96..e5a81b8f 100644
--- a/test/command_callback/test_cpp_clazy_command_callback.vader
+++ b/test/command_callback/test_cpp_clazy_command_callback.vader
@@ -34,18 +34,20 @@ Execute(The build directory should be configurable):
\ ale#Escape('clazy-standalone')
\ . ' -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')
let b:ale_c_build_dir = '/foo/bar'
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')
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):
let b:ale_cpp_clazy_executable = 'foobar'
diff --git a/test/completion/test_lsp_completion_messages.vader b/test/completion/test_lsp_completion_messages.vader
index 4b7392f5..ee810113 100644
--- a/test/completion/test_lsp_completion_messages.vader
+++ b/test/completion/test_lsp_completion_messages.vader
@@ -121,7 +121,7 @@ Execute(The right message should be sent for the initial tsserver request):
\ 'line': 1,
\ 'offset': 3,
\ 'prefix': 'fo',
- \ 'includeExternalModuleExports': g:ale_completion_tsserver_autoimport,
+ \ 'includeExternalModuleExports': g:ale_completion_autoimport,
\ }]],
\ g:message_list
" We should set up the completion info correctly.
diff --git a/test/completion/test_lsp_completion_parsing.vader b/test/completion/test_lsp_completion_parsing.vader
index e233c955..8b8b41c7 100644
--- a/test/completion/test_lsp_completion_parsing.vader
+++ b/test/completion/test_lsp_completion_parsing.vader
@@ -1,4 +1,12 @@
+Before:
+ Save g:ale_completion_autoimport
+ Save g:ale_completion_max_suggestions
+
+ let g:ale_completion_max_suggestions = 50
+
After:
+ Restore
+
unlet! b:ale_completion_info
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
\ [
\ {
@@ -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',
+ \ },
+ \ ],
+ \ },
+ \ ],
+ \ },
+ \ })
diff --git a/test/completion/test_tsserver_completion_parsing.vader b/test/completion/test_tsserver_completion_parsing.vader
index 6beb7b0a..aaaaae95 100644
--- a/test/completion/test_tsserver_completion_parsing.vader
+++ b/test/completion/test_tsserver_completion_parsing.vader
@@ -1,4 +1,11 @@
+Before:
+ Save g:ale_completion_tsserver_remove_warnings
+
+ let g:ale_completion_tsserver_remove_warnings = 0
+
After:
+ Restore
+
unlet! b:ale_tsserver_completion_names
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):
AssertEqual
\ [
@@ -38,7 +90,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ },
\ {
\ 'word': 'def',
@@ -46,7 +98,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': 'foo bar baz',
\ 'kind': 'v',
\ 'icase': 1,
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ },
\ {
\ 'word': 'ghi',
@@ -54,7 +106,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ },
\ ],
\ ale#completion#ParseTSServerCompletionEntryDetails({
@@ -132,7 +184,7 @@ Execute(Entries without details should be included in the responses):
\ 'changes': [],
\ }],
\ }),
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ },
\ {
\ 'word': 'def',
@@ -140,7 +192,7 @@ Execute(Entries without details should be included in the responses):
\ 'info': 'foo bar baz',
\ 'kind': 'v',
\ 'icase': 1,
- \ 'dup': g:ale_completion_tsserver_autoimport,
+ \ 'dup': g:ale_completion_autoimport,
\ },
\ {
\ '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': [],
+ \ },
+ \ ],
+ \ },
+ \ ],
+ \ })
diff --git a/test/fixers/test_prettier_standard_callback.vader b/test/fixers/test_prettier_standard_callback.vader
new file mode 100644
index 00000000..ab33fe20
--- /dev/null
+++ b/test/fixers/test_prettier_standard_callback.vader
@@ -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 ',
+ \ }
diff --git a/test/fixers/test_rubocop_fixer_callback.vader b/test/fixers/test_rubocop_fixer_callback.vader
index 866326bf..305881e0 100644
--- a/test/fixers/test_rubocop_fixer_callback.vader
+++ b/test/fixers/test_rubocop_fixer_callback.vader
@@ -21,9 +21,10 @@ Execute(The rubocop callback should return the correct default values):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ '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(''))
@@ -32,10 +33,11 @@ Execute(The rubocop callback should include configuration files):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ '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 --force-exclusion %t',
+ \ . ' --auto-correct --force-exclusion --stdin '
+ \ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
@@ -45,10 +47,64 @@ Execute(The rubocop callback should include custom rubocop options):
AssertEqual
\ {
- \ 'read_temporary_file': 1,
+ \ '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'))
\ . ' --except Lint/Debugger'
- \ . ' --auto-correct --force-exclusion %t',
+ \ . ' --auto-correct --force-exclusion --stdin '
+ \ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ },
\ 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'']',
+ \ ])
diff --git a/test/fixers/test_tslint_fixer_callback.vader b/test/fixers/test_tslint_fixer_callback.vader
index aa9c0322..a88992fa 100644
--- a/test/fixers/test_tslint_fixer_callback.vader
+++ b/test/fixers/test_tslint_fixer_callback.vader
@@ -27,7 +27,7 @@ Execute(The tslint callback should return the correct default values):
\ 'read_temporary_file': 1,
\ 'command': ale#Escape('tslint')
\ . ' -c ' . ale#Escape('tslint.json')
- \ . ' --fix %t',
+ \ . ' --outputAbsolutePaths --fix %t',
\ },
\ ale#fixers#tslint#Fix(bufnr(''))
@@ -40,6 +40,6 @@ Execute(The tslint callback should include custom tslint config option):
\ 'read_temporary_file': 1,
\ 'command': ale#Escape('tslint')
\ . ' -c ' . ale#Escape('.tslintrc')
- \ . ' --fix %t',
+ \ . ' --outputAbsolutePaths --fix %t',
\ },
\ ale#fixers#tslint#Fix(bufnr(''))
diff --git a/test/handler/test_vlog_handler.vader b/test/handler/test_vlog_handler.vader
index daf3cdcf..7262f63d 100644
--- a/test/handler/test_vlog_handler.vader
+++ b/test/handler/test_vlog_handler.vader
@@ -10,12 +10,14 @@ Execute(The vlog handler should parse old-style lines correctly):
\ {
\ 'lnum': 7,
\ 'type': 'W',
- \ 'text': '(vlog-2623) Undefined variable: C.'
+ \ 'text': '(vlog-2623) Undefined variable: C.',
+ \ 'filename': 'add.v'
\ },
\ {
\ 'lnum': 1,
\ '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(''), [
@@ -29,12 +31,14 @@ Execute(The vlog handler should parse new-style lines correctly):
\ {
\ 'lnum': 7,
\ 'type': 'W',
- \ 'text': '(vlog-2623) Undefined variable: C.'
+ \ 'text': '(vlog-2623) Undefined variable: C.',
+ \ 'filename': 'add.v'
\ },
\ {
\ 'lnum': 1,
\ '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(''), [
diff --git a/test/test_hover.vader b/test/test_hover.vader
index 8b4cf7bd..9689cda2 100644
--- a/test/test_hover.vader
+++ b/test/test_hover.vader
@@ -5,7 +5,7 @@ Before:
let g:Callback = 0
let g:message_list = []
let g:item_list = []
- let g:echo_list = []
+ let g:show_message_arg_list = []
runtime autoload/ale/linter.vim
runtime autoload/ale/lsp.vim
@@ -27,8 +27,8 @@ Before:
return 42
endfunction
- function! ale#util#ShowMessage(string) abort
- call add(g:echo_list, a:string)
+ function! ale#util#ShowMessage(string, ...) abort
+ call add(g:show_message_arg_list, [a:string] + a:000)
endfunction
function! HandleValidLSPResult(result) abort
@@ -58,7 +58,7 @@ After:
unlet! g:Callback
unlet! g:message_list
unlet! b:ale_linters
- unlet! g:echo_list
+ unlet! g:show_message_arg_list
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()
Execute(LSP hover responses with just a string should be handled):
call HandleValidLSPResult({'contents': 'foobar'})
- AssertEqual ['foobar'], g:echo_list
+ AssertEqual [['foobar', {'commands': []}]], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover null responses should be handled):
call HandleValidLSPResult(v:null)
- AssertEqual [], g:echo_list
+ AssertEqual [], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap()
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()
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()
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",
\]})
- AssertEqual ["foo\n\nbar\n"], g:echo_list
+ AssertEqual [["foo\n\nbar", {'commands': []}]], g:show_message_arg_list
AssertEqual {}, ale#hover#GetMap()
Execute(LSP hover response with lists of strings and marked strings should be handled):
call HandleValidLSPResult({'contents': [
\ {'language': 'rust', 'value': 'foo'},
- \ {'language': 'foobar'},
\ "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()
Execute(tsserver responses for documentation requests should be handled):
diff --git a/test/test_hover_parsing.vader b/test/test_hover_parsing.vader
new file mode 100644
index 00000000..4129c26a
--- /dev/null
+++ b/test/test_hover_parsing.vader
@@ -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"))
diff --git a/test/test_path_uri.vader b/test/test_path_uri.vader
index cc2287cb..0f2cba7e 100644
--- a/test/test_path_uri.vader
+++ b/test/test_path_uri.vader
@@ -1,3 +1,6 @@
+Before:
+ scriptencoding utf-8
+
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 '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):
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')
diff --git a/test/test_writefile_function.vader b/test/test_writefile_function.vader
index 811d59e8..53a88331 100644
--- a/test/test_writefile_function.vader
+++ b/test/test_writefile_function.vader
@@ -69,3 +69,49 @@ Execute(Unix file lines should be written as normal):
AssertEqual
\ ['first', 'second', 'third', ''],
\ 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')
+