diff options
29 files changed, 451 insertions, 83 deletions
diff --git a/ale_linters/handlebars/embertemplatelint.vim b/ale_linters/handlebars/embertemplatelint.vim index 74bd6a99..31d65b70 100644 --- a/ale_linters/handlebars/embertemplatelint.vim +++ b/ale_linters/handlebars/embertemplatelint.vim @@ -4,6 +4,28 @@ call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint') call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0)) +function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort + return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [ + \ 'node_modules/.bin/ember-template-lint', + \]) +endfunction + +function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer, version) abort + " Reading from stdin was introduced in ember-template-lint@1.6.0 + return ale#semver#GTE(a:version, [1, 6, 0]) + \ ? '%e --json --filename %s' + \ : '%e --json %t' +endfunction + +function! ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck(buffer) abort + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer), + \ '%e --version', + \ function('ale_linters#handlebars#embertemplatelint#GetCommand'), + \ ) +endfunction + function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort let l:output = [] let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) @@ -31,9 +53,7 @@ endfunction call ale#linter#Define('handlebars', { \ 'name': 'ember-template-lint', -\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [ -\ 'node_modules/.bin/ember-template-lint', -\ ])}, -\ 'command': '%e --json %t', +\ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'), +\ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'), \ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle', \}) diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim index ab4dbbc9..286c8a96 100644 --- a/ale_linters/php/psalm.vim +++ b/ale_linters/php/psalm.vim @@ -1,9 +1,9 @@ " Author: Matt Brown <https://github.com/muglug> " Description: plugin for Psalm, static analyzer for PHP -call ale#Set('psalm_langserver_executable', 'psalm') -call ale#Set('psalm_langserver_options', '') -call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0)) +call ale#Set('php_psalm_executable', 'psalm') +call ale#Set('php_psalm_options', '') +call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#php#psalm#GetProjectRoot(buffer) abort let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') @@ -12,13 +12,13 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort endfunction function! ale_linters#php#psalm#GetCommand(buffer) abort - return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'psalm_langserver_options')) + return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'php_psalm_options')) endfunction call ale#linter#Define('php', { \ 'name': 'psalm', \ 'lsp': 'stdio', -\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [ +\ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [ \ 'vendor/bin/psalm', \ ])}, \ 'command': function('ale_linters#php#psalm#GetCommand'), diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim index e2e7b743..fc4ab692 100644 --- a/ale_linters/python/flake8.vim +++ b/ale_linters/python/flake8.vim @@ -4,7 +4,7 @@ call ale#Set('python_flake8_executable', 'flake8') call ale#Set('python_flake8_options', '') call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0)) -call ale#Set('python_flake8_change_directory', 1) +call ale#Set('python_flake8_change_directory', 'project') call ale#Set('python_flake8_auto_pipenv', 0) function! s:UsingModule(buffer) abort @@ -38,10 +38,30 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort \) endfunction +function! ale_linters#python#flake8#GetCdString(buffer) abort + let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory') + let l:cd_string = '' + + if l:change_directory is# 'project' + let l:project_root = ale#python#FindProjectRootIni(a:buffer) + + if !empty(l:project_root) + let l:cd_string = ale#path#CdString(l:project_root) + endif + endif + + if (l:change_directory is# 'project' && empty(l:cd_string)) + \|| l:change_directory is# 1 + \|| l:change_directory is# 'file' + let l:cd_string = ale#path#BufferCdString(a:buffer) + endif + + return l:cd_string +endfunction + function! ale_linters#python#flake8#GetCommand(buffer, version) abort - let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory') - \ ? ale#path#BufferCdString(a:buffer) - \ : '' + let l:cd_string = ale_linters#python#flake8#GetCdString(a:buffer) + let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) let l:exec_args = l:executable =~? 'pipenv$' diff --git a/ale_linters/vim/vint.vim b/ale_linters/vim/vint.vim index 65e19126..c7461bc8 100644 --- a/ale_linters/vim/vint.vim +++ b/ale_linters/vim/vint.vim @@ -5,7 +5,7 @@ call ale#Set('vim_vint_show_style_issues', 1) call ale#Set('vim_vint_executable', 'vint') let s:enable_neovim = has('nvim') ? ' --enable-neovim' : '' -let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"' +let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"' function! ale_linters#vim#vint#GetCommand(buffer, version) abort let l:can_use_no_color_flag = empty(a:version) diff --git a/autoload/ale.vim b/autoload/ale.vim index b75c9fc9..5ec22f57 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -263,6 +263,8 @@ function! ale#GetLocItemMessage(item, format_string) abort let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g') " Replace %s with the text. let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g') + " Windows may insert carriage return line endings (^M), strip these characters. + let l:msg = substitute(l:msg, '\r', '', 'g') return l:msg endfunction diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim index d0a4fa06..cff53125 100644 --- a/autoload/ale/c.vim +++ b/autoload/ale/c.vim @@ -2,7 +2,9 @@ " Description: Functions for integrating with C-family linters. call ale#Set('c_parse_makefile', 0) +call ale#Set('c_always_make', has('unix') && !has('macunix')) call ale#Set('c_parse_compile_commands', 1) + let s:sep = has('win32') ? '\' : '/' " Set just so tests can override it. @@ -504,7 +506,10 @@ function! ale#c#GetMakeCommand(buffer) abort let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile') if !empty(l:path) - return ale#path#CdString(fnamemodify(l:path, ':h')) . 'make -n' + let l:always_make = ale#Var(a:buffer, 'c_always_make') + + return ale#path#CdString(fnamemodify(l:path, ':h')) + \ . 'make -n' . (l:always_make ? ' --always-make' : '') endif endif diff --git a/autoload/ale/code_action.vim b/autoload/ale/code_action.vim index 60c3bbef..8c7263f3 100644 --- a/autoload/ale/code_action.vim +++ b/autoload/ale/code_action.vim @@ -24,6 +24,42 @@ function! ale#code_action#HandleCodeAction(code_action, should_save) abort endfor endfunction +function! s:ChangeCmp(left, right) abort + if a:left.start.line < a:right.start.line + return -1 + endif + + if a:left.start.line > a:right.start.line + return 1 + endif + + if a:left.start.offset < a:right.start.offset + return -1 + endif + + if a:left.start.offset > a:right.start.offset + return 1 + endif + + if a:left.end.line < a:right.end.line + return -1 + endif + + if a:left.end.line > a:right.end.line + return 1 + endif + + if a:left.end.offset < a:right.end.offset + return -1 + endif + + if a:left.end.offset > a:right.end.offset + return 1 + endif + + return 0 +endfunction + function! ale#code_action#ApplyChanges(filename, changes, should_save) abort let l:current_buffer = bufnr('') " The buffer is used to determine the fileformat, if available. @@ -48,7 +84,8 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort let l:column_offset = 0 let l:last_end_line = 0 - for l:code_edit in a:changes + " Changes have to be sorted so we apply them from top-to-bottom. + for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp')) if l:code_edit.start.line isnot l:last_end_line let l:column_offset = 0 endif diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index f6a0c350..c2cfd74a 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -5,7 +5,7 @@ scriptencoding utf-8 " The omnicompletion menu is shown through a special Plug mapping which is " only valid in Insert mode. This way, feedkeys() won't send these keys if you " quit Insert mode quickly enough. -inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o> +inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o><C-p> " If we hit the key sequence in normal mode, then we won't show the menu, so " we should restore the old settings right away. nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR> @@ -324,6 +324,12 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort endif endfunction +function! s:OpenCompletionMenu(...) abort + if !&l:paste + call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)") + endif +endfunction + function! ale#completion#Show(result) abort if ale#util#Mode() isnot# 'i' return @@ -344,10 +350,7 @@ function! ale#completion#Show(result) abort let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') if l:source is# 'ale-automatic' || l:source is# 'ale-manual' - call timer_start( - \ 0, - \ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")} - \) + call timer_start(0, function('s:OpenCompletionMenu')) endif if l:source is# 'ale-callback' diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index 3ad0a433..8b841b13 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -15,22 +15,29 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort call remove(g:ale_fix_buffer_data, a:buffer) - if l:data.changes_made - let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output) - - if l:data.should_save - if a:buffer is bufnr('') - if empty(&buftype) - noautocmd :w! + try + if l:data.changes_made + let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output) + + if l:data.should_save + if a:buffer is bufnr('') + if empty(&buftype) + noautocmd :w! + else + set nomodified + endif else - set nomodified + call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks + call setbufvar(a:buffer, '&modified', 0) endif - else - call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks - call setbufvar(a:buffer, '&modified', 0) endif endif - endif + catch /E21/ + " If we cannot modify the buffer now, try again later. + let g:ale_fix_buffer_data[a:buffer] = l:data + + return + endtry if l:data.should_save let l:should_lint = ale#Var(a:buffer, 'fix_on_save') @@ -376,3 +383,4 @@ endfunction augroup ALEBufferFixGroup autocmd! autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>'))) +augroup END diff --git a/autoload/ale/handlers/gcc.vim b/autoload/ale/handlers/gcc.vim index ec16b977..0b37c98a 100644 --- a/autoload/ale/handlers/gcc.vim +++ b/autoload/ale/handlers/gcc.vim @@ -10,7 +10,7 @@ let s:pragma_error = '#pragma once in main file' " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=] " <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’) " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] -let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' +let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$' let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$' function! s:IsHeaderFile(filename) abort @@ -117,6 +117,23 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort if !empty(l:output) if !has_key(l:output[-1], 'detail') let l:output[-1].detail = l:output[-1].text + + " handle macro expansion errors/notes + if l:match[5] =~? '^in expansion of macro ‘\w*\w’$' + " if the macro expansion is in the file we're in, add + " the lnum and col keys to the previous error + if l:match[1] is# '<stdin>' + \ && !has_key(l:output[-1], 'col') + let l:output[-1].lnum = str2nr(l:match[2]) + let l:output[-1].col = str2nr(l:match[3]) + else + " the error is not in the current file, and since + " macro expansion errors don't show the full path to + " the error from the current file, we have to just + " give out a generic error message + let l:output[-1].text = 'Error found in macro expansion. See :ALEDetail' + endif + endif endif let l:output[-1].detail = l:output[-1].detail . "\n" diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index 05f11993..1f396377 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -505,13 +505,6 @@ function! ale#util#SetBufferContents(buffer, lines) abort \ : a:lines let l:first_line_to_remove = len(l:new_lines) + 1 - " We'll temporarily make a buffer modifiable, to force edits. - let l:modifiable = getbufvar(a:buffer, '&modifiable') - - if !l:modifiable - call setbufvar(a:buffer, '&modifiable', 1) - endif - " Use a Vim API for setting lines in other buffers, if available. if l:has_bufline_api call setbufline(a:buffer, 1, l:new_lines) @@ -530,9 +523,5 @@ function! ale#util#SetBufferContents(buffer, lines) abort call setline(1, l:new_lines) endif - if !l:modifiable - call setbufvar(a:buffer, '&modifiable', 0) - endif - return l:new_lines endfunction diff --git a/doc/ale-c.txt b/doc/ale-c.txt index fe28cf4a..b0d94b8e 100644 --- a/doc/ale-c.txt +++ b/doc/ale-c.txt @@ -8,6 +8,17 @@ runs either `clang`, or `gcc`. See |ale-c-cc|. =============================================================================== Global Options +g:ale_c_always_make *g:ale_c_always_make* + *b:ale_c_always_make* + Type: |Number| + Default: `has('unix') && !has('macunix')` + + If set to `1`, use `--always-make` for `make`, which means that output will + always be parsed from `make` dry runs with GNU make. BSD `make` does not + support this option, so you probably want to turn this option off when using + a BSD variant. + + g:ale_c_build_dir_names *g:ale_c_build_dir_names* *b:ale_c_build_dir_names* @@ -58,6 +69,11 @@ g:ale_c_parse_makefile *g:ale_c_parse_makefile* set for C or C++ compilers. This can make it easier to determine the correct build flags to use for different files. + NOTE: When using this option on BSD, you may need to set + |g:ale_c_always_make| to `0`, and `make -n` will not provide consistent + results if binaries have already been built, so use `make clean` when + editing your files. + WARNING: Running `make -n` automatically can execute arbitrary code, even though it's supposed to be a dry run, so enable this option with care. You might prefer to use the buffer-local version of the option instead with diff --git a/doc/ale-cpp.txt b/doc/ale-cpp.txt index 651b4160..17894e6e 100644 --- a/doc/ale-cpp.txt +++ b/doc/ale-cpp.txt @@ -10,6 +10,7 @@ Global Options The following C options also apply to some C++ linters too. +* |g:ale_c_always_make| * |g:ale_c_build_dir_names| * |g:ale_c_build_dir| * |g:ale_c_parse_makefile| diff --git a/doc/ale-php.txt b/doc/ale-php.txt index 645decd7..9fe868f8 100644 --- a/doc/ale-php.txt +++ b/doc/ale-php.txt @@ -189,42 +189,55 @@ g:ale_php_psalm_executable *g:ale_php_psalm_executable* This variable sets the executable used for psalm. -g:ale_psalm_langserver_options *g:ale_psalm_langserver_options* - *b:ale_psalm_langserver_options* + +g:ale_php_psalm_options *g:ale_php_psalm_options* + *b:ale_php_psalm_options* Type: |String| Default: `''` This variable can be set to pass additional options to psalm. + +g:ale_php_psalm_use_global *g:ale_php_psalm_use_global* + *b:ale_php_psalm_use_global* + Type: |Boolean| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== -php-cs-fixer *ale-php-php-cs-fixer* +php-cs-fixer *ale-php-php-cs-fixer* -g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable* - *b:ale_php_cs_fixer_executable* +g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable* + *b:ale_php_cs_fixer_executable* Type: |String| Default: `'php-cs-fixer'` This variable sets executable used for php-cs-fixer. -g:ale_php_cs_fixer_use_global *g:ale_php_cs_fixer_use_global* - *b:ale_php_cs_fixer_use_global* - Type: |Boolean| - Default: `get(g:, 'ale_use_global_executables', 0)` - - This variable force globally installed fixer. -g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options* - *b:ale_php_cs_fixer_options* +g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options* + *b:ale_php_cs_fixer_options* Type: |String| Default: `''` This variable can be set to pass additional options to php-cs-fixer. + +g:ale_php_cs_fixer_use_global *g:ale_php_cs_fixer_use_global* + *b:ale_php_cs_fixer_use_global* + Type: |Boolean| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== -php *ale-php-php* +php *ale-php-php* -g:ale_php_php_executable *g:ale_php_php_executable* - *b:ale_php_php_executable* +g:ale_php_php_executable *g:ale_php_php_executable* + *b:ale_php_php_executable* Type: |String| Default: `'php'` diff --git a/doc/ale-python.txt b/doc/ale-python.txt index 60b0771d..6b1a6d33 100644 --- a/doc/ale-python.txt +++ b/doc/ale-python.txt @@ -169,13 +169,14 @@ flake8 *ale-python-flake8* g:ale_python_flake8_change_directory *g:ale_python_flake8_change_directory* *b:ale_python_flake8_change_directory* - Type: |Number| - Default: `1` + Type: |String| + Default: `project` - If set to `1`, ALE will switch to the directory the Python file being - checked with `flake8` is in before checking it. This helps `flake8` find - configuration files more easily. This option can be turned off if you want - to control the directory Python is executed from yourself. + If set to `project`, ALE will switch to the project root before checking file. + If set to `file`, ALE will switch to directory the Python file being + checked with `flake8` is in before checking it. + You can turn it off with `off` option if you want to control the directory + Python is executed from yourself. g:ale_python_flake8_executable *g:ale_python_flake8_executable* diff --git a/doc/ale.txt b/doc/ale.txt index f3b83df3..472c4852 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -463,12 +463,56 @@ is loaded. The delay for completion can be configured with |g:ale_completion_delay|. This setting should not be enabled if you wish to use ALE as a completion source for other plugins. +ALE automatic completion will not work when 'paste' is active. Only set +'paste' when you are copy and pasting text into your buffers. + +ALE automatic completion will interfere with default insert completion with +`CTRL-N` and so on (|compl-vim|). You can write your own keybinds and a +function in your |vimrc| file to force insert completion instead, like so: > + + function! SmartInsertCompletion() abort + " Use the default CTRL-N in completion menus + if pumvisible() + return "\<C-n>" + endif + + " Exit and re-enter insert mode, and use insert completion + return "\<C-c>a\<C-n>" + endfunction + + inoremap <silent> <C-n> <C-R>=SmartInsertCompletion()<CR> +< ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| > " Use ALE's function for omnicompletion. set omnifunc=ale#completion#OmniFunc < + *ale-completion-fallback* + +You can write your own completion function and fallback on other methods of +completion by checking if there are no results that ALE can determine. For +example, for Python code, you could fall back on the `python3complete` +function. > + + function! TestCompletionFunc(findstart, base) abort + let l:result = ale#completion#OmniFunc(a:findstart, a:base) + + " Check if ALE couldn't find anything. + if (a:findstart && l:result is -3) + \|| (!a:findstart && empty(l:result)) + " Defer to another omnifunc if ALE couldn't find anything. + return python3complete#Complete(a:findstart, a:base) + endif + + return l:result + endfunction + + set omnifunc=TestCompletionFunc +< +See |complete-functions| for documentation on how to write completion +functions. + ALE will only suggest so many possible matches for completion. The maximum number of items can be controlled with |g:ale_completion_max_suggestions|. @@ -729,6 +773,9 @@ g:ale_completion_enabled *g:ale_completion_enabled* This setting should not be enabled if you wish to use ALE as a completion source for other completion plugins. + ALE automatic completion will not work when 'paste' is active. Only set + 'paste' when you are copy and pasting text into your buffers. + A buffer-local version of this setting `b:ale_completion_enabled` can be set to `0` to disable ALE's automatic completion support for a single buffer. ALE's completion support must be enabled globally to be enabled locally. diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader index f082a63a..09f64ee3 100644 --- a/test/command_callback/test_flake8_command_callback.vader +++ b/test/command_callback/test_flake8_command_callback.vader @@ -34,13 +34,52 @@ Execute(The flake8 callbacks should return the correct default values): \] Execute(The option for disabling changing directories should work): - let g:ale_python_flake8_change_directory = 0 + let g:ale_python_flake8_change_directory = 'off' AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] + let g:ale_python_flake8_change_directory = 0 + + AssertLinter 'flake8', [ + \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \] + + " Invalid options should be considered the same as turning the setting off. + let g:ale_python_flake8_change_directory = 'xxx' + + AssertLinter 'flake8', [ + \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \] + +Execute(The option for changing directory to project root should work): + silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_tox/namespace/foo/bar.py') + + AssertLinter 'flake8', [ + \ ale#Escape('flake8') . ' --version', + \ ale#path#CdString(ale#python#FindProjectRootIni(bufnr(''))) + \ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \] + +Execute(The option for changing directory to file dir should work): + let g:ale_python_flake8_change_directory = 'file' + silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_tox/namespace/foo/bar.py') + + AssertLinter 'flake8', [ + \ ale#Escape('flake8') . ' --version', + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \] + + let g:ale_python_flake8_change_directory = 1 + + AssertLinter 'flake8', [ + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \] + Execute(The flake8 command callback should let you set options): let g:ale_python_flake8_options = '--some-option' @@ -163,5 +202,5 @@ Execute(Pipenv is detected when python_flake8_auto_pipenv is set): call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py') AssertLinter 'pipenv', - \ ale#path#BufferCdString(bufnr('')) + \ ale#path#CdString(ale#python#FindProjectRootIni(bufnr(''))) \ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -' diff --git a/test/command_callback/test_psalm_command_callbacks.vader b/test/command_callback/test_psalm_command_callbacks.vader index 70b5af95..d32780e6 100644 --- a/test/command_callback/test_psalm_command_callbacks.vader +++ b/test/command_callback/test_psalm_command_callbacks.vader @@ -2,6 +2,9 @@ Before: call ale#assert#SetUpLinterTest('php', 'psalm') After: + unlet! g:i + unlet! g:matched + if isdirectory(g:dir . '/.git') call delete(g:dir . '/.git', 'd') endif @@ -22,19 +25,36 @@ Execute(Vendor executables should be detected): \ . '/psalm-project/vendor/bin/psalm' \ )) . ' --language-server' + let g:ale_php_psalm_use_global = 1 + + AssertLinter 'psalm', + \ ale#Escape('psalm') . ' --language-server' + Execute(User provided options should be used): - let g:ale_psalm_langserver_options = '--my-user-provided-option my-value' + let g:ale_php_psalm_options = '--my-user-provided-option my-value' AssertLinter 'psalm', \ ale#Escape('psalm') \ . ' --language-server --my-user-provided-option my-value' - Execute(The project path should be correct for .git directories): call ale#test#SetFilename('psalm-project/test.php') + let g:matched = 0 - if !isdirectory(g:dir . '/.git') - call mkdir(g:dir . '/.git') - endif + for g:i in range(4) + if !isdirectory(g:dir . '/.git') + call mkdir(g:dir . '/.git') + endif + + try + AssertLSPProject g:dir + catch /.+/ + endtry - AssertLSPProject g:dir + let g:matched = 1 + break + endfor + + if !g:matched + AssertLSPProject g:dir + endif diff --git a/test/command_callback/test_vint_command_callback.vader b/test/command_callback/test_vint_command_callback.vader index e0051f26..4ce277e8 100644 --- a/test/command_callback/test_vint_command_callback.vader +++ b/test/command_callback/test_vint_command_callback.vader @@ -1,7 +1,7 @@ Before: call ale#assert#SetUpLinterTest('vim', 'vint') let b:command_tail = (has('nvim') ? ' --enable-neovim' : '') - \ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})" %t' + \ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})" %t' After: unlet! b:bin_dir diff --git a/test/completion/test_completion_events.vader b/test/completion/test_completion_events.vader index 3a7a31d0..87bd10ad 100644 --- a/test/completion/test_completion_events.vader +++ b/test/completion/test_completion_events.vader @@ -35,7 +35,7 @@ Before: let g:ale_completion_delay = 0 " Run this check a few times, as it can fail randomly. - for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1) + for l:i in range(has('nvim-0.3') || has('win32') ? 5 : 1) call ale#completion#Queue() sleep 1m diff --git a/test/ember-template-lint-test-files/app/template.hbs b/test/ember-template-lint-test-files/app/template.hbs new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/ember-template-lint-test-files/app/template.hbs diff --git a/test/ember-template-lint-test-files/package.json b/test/ember-template-lint-test-files/package.json new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/ember-template-lint-test-files/package.json diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader index e8a9dd7a..a51a5a53 100644 --- a/test/fix/test_ale_fix.vader +++ b/test/fix/test_ale_fix.vader @@ -727,6 +727,19 @@ Expect(There should be only two lines): a b +Execute(ALEFix should modify a buffer that is not modifiable, if it becomes modifiable later): + let g:ale_fixers.testft = ['RemoveLastLineOneArg'] + + set nomodifiable + ALEFix + call ale#test#FlushJobs() + set modifiable + call ale#fix#ApplyQueuedFixes(bufnr('')) + +Expect(There should be only two lines): + a + b + Execute(b:ale_fix_on_save = 1 should override g:ale_fix_on_save = 0): let g:ale_fix_on_save = 0 let b:ale_fix_on_save = 1 diff --git a/test/handler/test_gcc_handler.vader b/test/handler/test_gcc_handler.vader index b67483a6..a4231cab 100644 --- a/test/handler/test_gcc_handler.vader +++ b/test/handler/test_gcc_handler.vader @@ -279,3 +279,38 @@ Execute(The GCC handler should handle errors for inlined header functions): \ ' __open_too_many_args ();', \ ' ^~~~~~~~~~~~~~~~~~~~~~~', \ ]) + +Execute(The GCC handler should handle macro expansion errors in current file): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'col': 19, + \ 'type': 'E', + \ 'text': 'error message', + \ 'detail': "error message\n<stdin>:1:19: note: in expansion of macro 'TEST'", + \ }, + \ ], + \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ + \ '<command-line>: error: error message', + \ '<stdin>:1:19: note: in expansion of macro ‘TEST’', + \ ' 1 | std::string str = TEST;', + \ ' | ^~~~', + \ ]) + +Execute(The GCC handler should handle macro expansion errors in other files): + AssertEqual + \ [ + \ { + \ 'lnum': 0, + \ 'type': 'E', + \ 'text': 'Error found in macro expansion. See :ALEDetail', + \ 'detail': "error message\ninc.h:1:19: note: in expansion of macro 'TEST'", + \ }, + \ ], + \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ + \ '<command-line>: error: error message', + \ 'inc.h:1:19: note: in expansion of macro ‘TEST’', + \ ' 1 | std::string str = TEST;', + \ ' | ^~~~', + \ ]) diff --git a/test/test_c_flag_parsing.vader b/test/test_c_flag_parsing.vader index 076be6a1..99722b17 100644 --- a/test/test_c_flag_parsing.vader +++ b/test/test_c_flag_parsing.vader @@ -1,9 +1,13 @@ Before: Save g:ale_c_parse_makefile + Save g:ale_c_always_make + Save b:ale_c_always_make call ale#test#SetDirectory('/testplugin/test') let g:ale_c_parse_makefile = 1 + let g:ale_c_always_make = 1 + let b:ale_c_always_make = 1 function SplitAndParse(path_prefix, command) abort let l:args = ale#c#ShellSplit(a:command) @@ -18,6 +22,22 @@ After: call ale#test#RestoreDirectory() +Execute(The make command should be correct): + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ale#path#CdString(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project')) + \ . 'make -n --always-make', + \ ale#c#GetMakeCommand(bufnr('')) + + " You should be able to disable --always-make for a buffer. + let b:ale_c_always_make = 0 + + AssertEqual + \ ale#path#CdString(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project')) + \ . 'make -n', + \ ale#c#GetMakeCommand(bufnr('')) + Execute(The CFlags parser should be able to parse include directives): call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') diff --git a/test/test_code_action.vader b/test/test_code_action.vader index b47f24ff..19de7268 100644 --- a/test/test_code_action.vader +++ b/test/test_code_action.vader @@ -1,4 +1,8 @@ Before: + Save g:ale_enabled + + let g:ale_enabled = 0 + runtime autoload/ale/code_action.vim runtime autoload/ale/util.vim @@ -35,6 +39,8 @@ Before: endfunction! After: + Restore + " Close the extra buffers if we opened it. if bufnr(g:file1) != -1 execute ':bp! | :bd! ' . bufnr(g:file1) @@ -50,9 +56,10 @@ After: call delete(g:file2) endif - unlet g:file1 - unlet g:file2 - unlet g:test + unlet! g:file1 + unlet! g:file2 + unlet! g:test + unlet! g:changes delfunction WriteFileAndEdit runtime autoload/ale/code_action.vim @@ -350,3 +357,36 @@ Execute(It should just modify file when should_save is set to v:false): \ ' value: string', \ '}', \], getline(1, '$') + +Given typescript(An example TypeScript file): + type Foo = {} + + export interface ISomething { + fooLongName: Foo | null + } + + export class SomethingElse implements ISomething { + // Bindings + fooLongName!: ISomething['fooLongName'] + } + +Execute(): + let g:changes = [ + \ {'end': {'offset': 14, 'line': 4}, 'newText': 'foo', 'start': {'offset': 3, 'line': 4}}, + \ {'end': {'offset': 40, 'line': 9}, 'newText': 'foo', 'start': {'offset': 29, 'line': 9}}, + \ {'end': {'offset': 14, 'line': 9}, 'newText': 'foo', 'start': {'offset': 3, 'line': 9}}, + \] + + call ale#code_action#ApplyChanges(expand('%:p'), g:changes, 0) + +Expect(The changes should be applied correctly): + type Foo = {} + + export interface ISomething { + foo: Foo | null + } + + export class SomethingElse implements ISomething { + // Bindings + foo!: ISomething['foo'] + } diff --git a/test/test_cursor_warnings.vader b/test/test_cursor_warnings.vader index 339cd71e..ef385061 100644 --- a/test/test_cursor_warnings.vader +++ b/test/test_cursor_warnings.vader @@ -30,7 +30,7 @@ Before: \ 'nr': -1, \ 'type': 'E', \ 'code': 'semi', - \ 'text': 'Missing semicolon.', + \ 'text': "Missing semicolon.\r", \ 'detail': "Every statement should end with a semicolon\nsecond line", \ }, \ { diff --git a/test/test_embertemplatelint_executable_detection.vader b/test/test_embertemplatelint_executable_detection.vader new file mode 100644 index 00000000..bd0f5dd9 --- /dev/null +++ b/test/test_embertemplatelint_executable_detection.vader @@ -0,0 +1,22 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + + runtime ale_linters/handlebars/embertemplatelint.vim + +After: + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(ember-template-lint executables runs the right command): + call ale#test#SetFilename('ember-template-lint-test-files/app/template.hbs') + + AssertEqual + \ ale_linters#handlebars#embertemplatelint#GetCommand(bufnr(''), [2, 0, 0]), + \ '%e --json --filename %s' + +Execute(old ember-template-lint executables runs the right command): + call ale#test#SetFilename('ember-template-lint-test-files/app/template.hbs') + + AssertEqual + \ ale_linters#handlebars#embertemplatelint#GetCommand(bufnr(''), [1, 5, 0]), + \ '%e --json %t' diff --git a/test/test_list_formatting.vader b/test/test_list_formatting.vader index dcefac53..d79a664b 100644 --- a/test/test_list_formatting.vader +++ b/test/test_list_formatting.vader @@ -36,7 +36,7 @@ After: call setqflist([]) Execute(Formatting with codes should work for the loclist): - call AddItem({'text': 'nocode'}) + call AddItem({'text': "nocode\r"}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual @@ -79,7 +79,7 @@ Execute(Formatting with codes should work for the quickfix list): let g:ale_set_loclist = 0 let g:ale_set_quickfix = 1 - call AddItem({'text': 'nocode'}) + call AddItem({'text': "nocode\r"}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual |