Merge branch 'master' into dhall

This commit is contained in:
toastal 2020-09-14 08:54:07 +07:00
commit b32954a46c
No known key found for this signature in database
GPG Key ID: A1CAFFE4DB109A47
22 changed files with 467 additions and 160 deletions

View File

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

View File

@ -13,12 +13,17 @@ function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:warning_flag = ale#Var(a:buffer, 'vim_vint_show_style_issues') ? '-s' : '-w'
" Use the --stdin-display-name argument if supported, temp file otherwise.
let l:stdin_or_temp = ale#semver#GTE(a:version, [0, 4, 0])
\ ? ' --stdin-display-name %s -'
\ : ' %t'
return '%e'
\ . ' ' . l:warning_flag
\ . (l:can_use_no_color_flag ? ' --no-color' : '')
\ . s:enable_neovim
\ . ' ' . s:format
\ . ' %t'
\ . l:stdin_or_temp
endfunction
let s:word_regex_list = [

View File

@ -100,13 +100,7 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
" Use the filetype from the buffer
let l:filetype = getbufvar(a:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype)
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
let l:linters = !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config, l:disable_lsp)
\ : l:linters
let l:linters = ale#linter#RemoveIgnored(a:buffer, l:filetype, l:linters)
" Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer
@ -163,7 +157,7 @@ function! ale#Queue(delay, ...) abort
endif
endfunction
let s:current_ale_version = [2, 7, 0]
let s:current_ale_version = [3, 0, 0]
" A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort

View File

@ -503,17 +503,19 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ || g:ale_completion_autoimport,
\ 'info': join(l:documentationParts, ''),
\}
" This flag is used to tell if this completion came from ALE or not.
let l:user_data = {'_ale_completion_item': 1}
if has_key(l:suggestion, 'codeActions')
let l:result.user_data = json_encode({
\ 'codeActions': l:suggestion.codeActions,
\ })
let l:user_data.code_actions = l:suggestion.codeActions
endif
let l:result.user_data = json_encode(l:user_data)
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:result, 'user_data')
\|| has_key(l:user_data, 'code_actions')
call add(l:results, l:result)
endif
endfor
@ -534,6 +536,7 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ 'icase': 1,
\ 'menu': '',
\ 'info': '',
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\})
endfor
endif
@ -610,6 +613,8 @@ function! ale#completion#ParseLSPCompletions(response) abort
\ 'menu': get(l:item, 'detail', ''),
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\}
" This flag is used to tell if this completion came from ALE or not.
let l:user_data = {'_ale_completion_item': 1}
if has_key(l:item, 'additionalTextEdits')
let l:text_changes = []
@ -629,24 +634,24 @@ function! ale#completion#ParseLSPCompletions(response) abort
endfor
if !empty(l:text_changes)
let l:result.user_data = json_encode({
\ 'codeActions': [{
\ 'description': 'completion',
\ 'changes': [
\ {
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\ }
\ ],
\ }],
\})
let l:user_data.code_actions = [{
\ 'description': 'completion',
\ 'changes': [
\ {
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\ },
\ ],
\}]
endif
endif
let l:result.user_data = json_encode(l:user_data)
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:result, 'user_data')
\|| has_key(l:user_data, 'code_actions')
call add(l:results, l:result)
endif
endfor
@ -983,30 +988,29 @@ function! ale#completion#Queue() abort
endfunction
function! ale#completion#HandleUserData(completed_item) abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source isnot# 'ale-automatic'
\&& l:source isnot# 'ale-manual'
\&& l:source isnot# 'ale-callback'
\&& l:source isnot# 'ale-import'
return
endif
let l:user_data_json = get(a:completed_item, 'user_data', '')
if empty(l:user_data_json)
return
endif
let l:user_data = json_decode(l:user_data_json)
let l:user_data = !empty(l:user_data_json)
\ ? json_decode(l:user_data_json)
\ : v:null
if type(l:user_data) isnot v:t_dict
\|| get(l:user_data, '_ale_completion_item', 0) isnot 1
return
endif
for l:code_action in get(l:user_data, 'codeActions', [])
call ale#code_action#HandleCodeAction(l:code_action, v:false)
endfor
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic'
\|| l:source is# 'ale-manual'
\|| l:source is# 'ale-callback'
\|| l:source is# 'ale-import'
\|| l:source is# 'ale-omnifunc'
for l:code_action in get(l:user_data, 'code_actions', [])
call ale#code_action#HandleCodeAction(l:code_action, v:false)
endfor
endif
silent doautocmd <nomodeline> User ALECompletePost
endfunction
function! ale#completion#Done() abort

View File

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

View File

@ -444,7 +444,7 @@ function! s:RunJob(command, options) abort
return 1
endfunction
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
call ale#command#StopJobs(a:buffer, 'linter')
@ -453,11 +453,25 @@ function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
call ale#command#StopJobs(a:buffer, 'file_linter')
let l:info.active_linter_list = []
else
let l:lint_file_map = {}
" Use a previously computed map of `lint_file` values to find
" linters that are used for linting files.
for [l:lint_file, l:linter] in a:linter_slots
if l:lint_file is 1
let l:lint_file_map[l:linter.name] = 1
endif
endfor
" Keep jobs for linting files when we're only linting buffers.
call filter(l:info.active_linter_list, 'get(v:val, ''lint_file'')')
call filter(l:info.active_linter_list, 'get(l:lint_file_map, v:val.name)')
endif
endfunction
function! ale#engine#Stop(buffer) abort
call s:StopCurrentJobs(a:buffer, 1, [])
endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
@ -558,6 +572,22 @@ function! s:RunLinter(buffer, linter, lint_file) abort
return 0
endfunction
function! s:GetLintFileSlots(buffer, linters) abort
let l:linter_slots = []
for l:linter in a:linters
let l:LintFile = l:linter.lint_file
if type(l:LintFile) is v:t_func
let l:LintFile = l:LintFile(a:buffer)
endif
call add(l:linter_slots, [l:LintFile, l:linter])
endfor
return l:linter_slots
endfunction
function! s:GetLintFileValues(slots, Callback) abort
let l:deferred_list = []
let l:new_slots = []
@ -591,12 +621,18 @@ endfunction
function! s:RunLinters(
\ buffer,
\ linters,
\ slots,
\ should_lint_file,
\ new_buffer,
\ can_clear_results
\) abort
let l:can_clear_results = a:can_clear_results
call s:StopCurrentJobs(a:buffer, a:should_lint_file, a:slots)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
silent doautocmd <nomodeline> User ALELintPre
for [l:lint_file, l:linter] in a:slots
" Only run lint_file linters if we should.
@ -627,36 +663,19 @@ endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
silent doautocmd <nomodeline> User ALELintPre
" Handle `lint_file` callbacks first.
let l:linter_slots = []
for l:linter in a:linters
let l:LintFile = l:linter.lint_file
if type(l:LintFile) is v:t_func
let l:LintFile = l:LintFile(a:buffer)
endif
call add(l:linter_slots, [l:LintFile, l:linter])
endfor
call s:GetLintFileValues(l:linter_slots, {
\ new_slots -> s:RunLinters(
\ a:buffer,
\ new_slots,
\ a:should_lint_file,
\ l:new_buffer,
\ l:can_clear_results,
\ )
\})
call s:GetLintFileValues(
\ s:GetLintFileSlots(a:buffer, a:linters),
\ {
\ slots -> s:RunLinters(
\ a:buffer,
\ a:linters,
\ slots,
\ a:should_lint_file,
\ l:new_buffer,
\ )
\ }
\)
endfunction
" Clean up a buffer.

View File

@ -75,7 +75,10 @@ function! ale#fix#ApplyFixes(buffer, output) abort
if l:data.lines_before != l:lines
call remove(g:ale_fix_buffer_data, a:buffer)
execute 'echoerr ''The file was changed before fixing finished'''
if !l:data.ignore_file_changed_errors
execute 'echoerr ''The file was changed before fixing finished'''
endif
return
endif
@ -329,6 +332,7 @@ function! ale#fix#InitBufferData(buffer, fixing_flag) abort
\ 'lines_before': getbufline(a:buffer, 1, '$'),
\ 'done': 0,
\ 'should_save': a:fixing_flag is# 'save_file',
\ 'ignore_file_changed_errors': a:fixing_flag is# '!',
\ 'temporary_directory_list': [],
\}
endfunction
@ -337,19 +341,23 @@ endfunction
"
" Returns 0 if no fixes can be applied, and 1 if fixing can be done.
function! ale#fix#Fix(buffer, fixing_flag, ...) abort
if a:fixing_flag isnot# '' && a:fixing_flag isnot# 'save_file'
throw "fixing_flag must be either '' or 'save_file'"
if a:fixing_flag isnot# ''
\&& a:fixing_flag isnot# '!'
\&& a:fixing_flag isnot# 'save_file'
throw "fixing_flag must be '', '!', or 'save_file'"
endif
try
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
catch /E700\|BADNAME/
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
\ l:function_name,
\)
execute 'echom l:echo_message'
if a:fixing_flag isnot# '!'
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(
\ 'There is no fixer named `%s`. Check :ALEFixSuggest',
\ l:function_name,
\)
execute 'echom l:echo_message'
endif
return 0
endtry

View File

@ -394,6 +394,16 @@ function! ale#linter#Get(original_filetypes) abort
return reverse(l:combined_linters)
endfunction
function! ale#linter#RemoveIgnored(buffer, filetype, linters) abort
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
return !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(a:filetype, a:linters, l:ignore_config, l:disable_lsp)
\ : a:linters
endfunction
" Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort
let l:Executable = a:linter.executable

View File

@ -147,6 +147,8 @@ ALE offers several options for controlling which linters are run.
* Disabling only a subset of linters. - |g:ale_linters_ignore|
* Disabling LSP linters and `tsserver`. - |g:ale_disable_lsp|
You can stop ALE any currently running linters with the |ALELintStop| command.
Any existing problems will be kept.
-------------------------------------------------------------------------------
3.1 Linting On Other Machines *ale-lint-other-machines*
@ -177,8 +179,11 @@ script like so. >
#!/usr/bin/env bash
exec docker run --rm -v "$(pwd):/data" cytopia/pylint "$@"
exec docker run -i --rm -v "$(pwd):/data" cytopia/pylint "$@"
<
You will run to run Docker commands with `-i` in order to read from stdin.
With the above script in mind, you might configure ALE to lint your Python
project with `pylint` by providing the path to the script to execute, and
mappings which describe how to between the two file systems in your
@ -532,6 +537,9 @@ potential completion result which includes additional text to insert into the
current buffer, which ALE will assume is code for an import line. This command
can be useful when your code already contains something you need to import.
You can execute other commands whenever ALE inserts some completion text with
the |ALECompletePost| event.
When working with TypeScript files, ALE can remove warnings from your
completions by setting the |g:ale_completion_tsserver_remove_warnings|
variable to 1.
@ -2980,6 +2988,10 @@ ALEFix *ALEFix*
Fix problems with the current buffer. See |ale-fix| for more information.
If the command is run with a bang (`:ALEFix!`), all warnings will be
suppressed, including warnings about no fixers being defined, and warnings
about not being able to apply fixes to a file because it has been changed.
A plug mapping `<Plug>(ale_fix)` is defined for this command.
@ -3119,6 +3131,13 @@ ALELint *ALELint*
A plug mapping `<Plug>(ale_lint)` is defined for this command.
ALELintStop *ALELintStop*
Stop any currently running jobs for checking the current buffer.
Any problems from previous linter results will continue to be shown.
ALEPrevious *ALEPrevious*
ALEPreviousWrap *ALEPreviousWrap*
ALENext *ALENext*
@ -3984,6 +4003,23 @@ g:ale_want_results_buffer *g:ale_want_results_buffer*
figure out which buffer other sources should lint.
ALECompletePost *ALECompletePost-autocmd*
*ALECompletePost*
This |User| autocmd is triggered after ALE inserts an item on
|CompleteDone|. This event can be used to run commands after a buffer
is changed by ALE as the result of completion. For example, |ALEFix| can
be configured to run automatically when completion is done: >
augroup FixAfterComplete
autocmd!
" Run ALEFix when completion items are added.
autocmd User ALECompletePost ALEFix!
" If ALE starts fixing a file, stop linters running for now.
autocmd User ALEFixPre ALELintStop
augroup END
<
ALELintPre *ALELintPre-autocmd*
*ALELintPre*
ALELintPost *ALELintPost-autocmd*

View File

@ -195,6 +195,8 @@ command! -bar ALEStopAllLSPs :call ale#lsp#reset#StopAllLSPs()
" A command for linting manually.
command! -bar ALELint :call ale#Queue(0, 'lint_file')
" Stop current jobs when linting.
command! -bar ALELintStop :call ale#engine#Stop(bufnr(''))
" Define a command to get information about current filetype.
command! -bar ALEInfo :call ale#debugging#Info()
@ -204,7 +206,7 @@ command! -bar ALEInfoToClipboard :call ale#debugging#InfoToClipboard()
command! -bar -nargs=1 ALEInfoToFile :call ale#debugging#InfoToFile(<f-args>)
" Fix problems in files.
command! -bar -nargs=* -complete=customlist,ale#fix#registry#CompleteFixers ALEFix :call ale#fix#Fix(bufnr(''), '', <f-args>)
command! -bar -bang -nargs=* -complete=customlist,ale#fix#registry#CompleteFixers ALEFix :call ale#fix#Fix(bufnr(''), '<bang>', <f-args>)
" Suggest registered functions to use for fixing problems.
command! -bar ALEFixSuggest :call ale#fix#registry#Suggest(&filetype)

View File

@ -49,12 +49,13 @@ class Source(Base):
if event == 'Async':
result = self.vim.call('ale#completion#GetCompletionResult')
return result or []
if context.get('is_refresh'):
self.vim.command(
"call ale#completion#GetCompletions('ale-callback', " + \
"{'callback': {completions -> deoplete#auto_complete() }})"
"call ale#completion#GetCompletions('ale-callback', "
+ "{'callback': {completions -> deoplete#auto_complete() }})"
)
return []

View File

@ -8,6 +8,8 @@ Before:
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
let b:command_tail = ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
GivenCommandOutput ['pylint 2.3.0']
After:
unlet! b:bin_dir
unlet! b:executable
@ -17,26 +19,33 @@ After:
Execute(The pylint callbacks should return the correct default values):
AssertLinter 'pylint',
\ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pylint') . ' ' . b:command_tail
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('pylint') . b:command_tail
Execute(Pylint should run with the --from-stdin in new enough versions):
GivenCommandOutput ['pylint 2.4.0']
AssertLinter 'pylint',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('pylint') . b:command_tail[:-3] . '--from-stdin %s'
Execute(The option for disabling changing directories should work):
let g:ale_python_pylint_change_directory = 0
AssertLinter 'pylint', ale#Escape('pylint') . ' ' . b:command_tail
AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail
Execute(The pylint executable should be configurable, and escaped properly):
let g:ale_python_pylint_executable = 'executable with spaces'
AssertLinter 'executable with spaces',
\ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('executable with spaces') . ' ' . b:command_tail
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('executable with spaces') . b:command_tail
Execute(The pylint command callback should let you set options):
let g:ale_python_pylint_options = '--some-option'
AssertLinter 'pylint',
\ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('pylint') . ' --some-option' . b:command_tail
Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist):
@ -44,7 +53,7 @@ Execute(The pylint callbacks shouldn't detect virtualenv directories where they
AssertLinter 'pylint',
\ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/no_virtualenv/subdir'))
\ . ale#Escape('pylint') . ' ' . b:command_tail
\ . ale#Escape('pylint') . b:command_tail
Execute(The pylint callbacks should detect virtualenv directories):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
@ -55,7 +64,7 @@ Execute(The pylint callbacks should detect virtualenv directories):
AssertLinter b:executable,
\ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
\ . ale#Escape(b:executable) . ' ' . b:command_tail
\ . ale#Escape(b:executable) . b:command_tail
Execute(You should able able to use the global pylint instead):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
@ -63,7 +72,7 @@ Execute(You should able able to use the global pylint instead):
AssertLinter 'pylint',
\ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
\ . ale#Escape('pylint') . ' ' . b:command_tail
\ . ale#Escape('pylint') . b:command_tail
Execute(Setting executable to 'pipenv' appends 'run pylint'):
let g:ale_python_pylint_executable = 'path/to/pipenv'
@ -71,7 +80,7 @@ Execute(Setting executable to 'pipenv' appends 'run pylint'):
AssertLinter 'path/to/pipenv',
\ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('path/to/pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
Execute(Pipenv is detected when python_pylint_auto_pipenv is set):
let g:ale_python_pylint_auto_pipenv = 1
@ -80,4 +89,4 @@ Execute(Pipenv is detected when python_pylint_auto_pipenv is set):
AssertLinter 'pipenv',
\ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'

View File

@ -1,17 +1,17 @@
Before:
call ale#assert#SetUpLinterTest('vim', 'vint')
let b:command_tail = (has('nvim') ? ' --enable-neovim' : '')
\ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})" %t'
let b:common_flags = (has('nvim') ? ' --enable-neovim' : '')
\ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"'
After:
unlet! b:bin_dir
unlet! b:executable
unlet! b:common_flags
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
AssertLinter 'vint', [
\ ale#Escape('vint') .' --version',
\ ale#Escape('vint') .' -s --no-color' . b:command_tail,
\ ale#Escape('vint') .' -s --no-color' . b:common_flags . ' %t',
\]
Execute(The executable should be configurable):
@ -19,5 +19,16 @@ Execute(The executable should be configurable):
AssertLinter 'foobar', [
\ ale#Escape('foobar') .' --version',
\ ale#Escape('foobar') .' -s --no-color' . b:command_tail,
\ ale#Escape('foobar') .' -s --no-color' . b:common_flags . ' %t',
\]
Execute(The --no-color flag should not be used for older Vint versions):
GivenCommandOutput ['v0.3.5']
AssertLinter 'vint', ale#Escape('vint') .' -s' . b:common_flags . ' %t'
Execute(--stdin-display-name should be used in newer versions):
GivenCommandOutput ['v0.4.0']
AssertLinter 'vint', ale#Escape('vint') .' -s --no-color' . b:common_flags
\ . ' --stdin-display-name %s -'

View File

@ -0,0 +1,35 @@
Before:
let g:complete_post_triggered = 0
augroup VaderTest
autocmd!
autocmd User ALECompletePost let g:complete_post_triggered = 1
augroup END
After:
unlet! b:ale_completion_info
unlet! g:complete_post_triggered
augroup VaderTest
autocmd!
augroup END
augroup! VaderTest
Execute(ALECompletePost should not be triggered when completion is cancelled):
call ale#completion#HandleUserData({})
Assert !g:complete_post_triggered
Execute(ALECompletePost should not be triggered when tools other than ALE insert completions):
call ale#completion#HandleUserData({'user_data': ''})
call ale#completion#HandleUserData({'user_data': '{}'})
Assert !g:complete_post_triggered
Execute(ALECompletePost should be triggered when ALE inserts completions):
call ale#completion#HandleUserData({
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\})
Assert g:complete_post_triggered

View File

@ -407,41 +407,75 @@ Execute(HandleUserData should call ale#code_action#HandleCodeAction):
AssertEqual g:handle_code_action_called, 0
call ale#completion#HandleUserData({
\ 'user_data': ''
\ 'user_data': ''
\})
AssertEqual g:handle_code_action_called, 0
call ale#completion#HandleUserData({
\ 'user_data': '{}'
\ 'user_data': json_encode({}),
\})
AssertEqual g:handle_code_action_called, 0
call ale#completion#HandleUserData({
\ 'user_data': '{"codeActions": []}'
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [],
\ }),
\})
AssertEqual g:handle_code_action_called, 0
call ale#completion#HandleUserData({
\ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {'description': '', 'changes': []},
\ ],
\ }),
\})
AssertEqual g:handle_code_action_called, 1
let b:ale_completion_info = {'source': 'ale-automatic'}
call ale#completion#HandleUserData({
\ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {'description': '', 'changes': []},
\ ],
\ }),
\})
AssertEqual g:handle_code_action_called, 2
let b:ale_completion_info = {'source': 'ale-callback'}
call ale#completion#HandleUserData({
\ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {'description': '', 'changes': []},
\ ],
\ }),
\})
AssertEqual g:handle_code_action_called, 3
let b:ale_completion_info = {'source': 'ale-omnifunc'}
call ale#completion#HandleUserData({
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {'description': '', 'changes': []},
\ ],
\ }),
\})
AssertEqual g:handle_code_action_called, 4
Execute(ale#code_action#HandleCodeAction should not be called when when source is not ALE):
call MockHandleCodeAction()
let b:ale_completion_info = {'source': 'syntastic'}
call ale#completion#HandleUserData({
\ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
\ 'user_data': json_encode({
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {'description': '', 'changes': []},
\ ],
\ }),
\})
AssertEqual g:handle_code_action_called, 0

View File

@ -12,34 +12,34 @@ After:
Execute(Should handle Rust completion results correctly):
AssertEqual
\ [
\ {'word': 'new', 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'with_capacity', 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_utf8', 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_utf8_lossy', 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_utf16', 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_utf16_lossy', 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_raw_parts', 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_utf8_unchecked', 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'Searcher', 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'default', 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Target', 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'Err', 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1},
\ {'word': 'from_str', 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from', 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from', 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'from', 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1},
\ {'word': 'new', 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'with_capacity', 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_utf8', 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_utf8_lossy', 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_utf16', 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_utf16_lossy', 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_raw_parts', 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_utf8_unchecked', 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Searcher', 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'default', 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Target', 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'Err', 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from_str', 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from', 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from', 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from', 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\],
\ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0",
@ -195,7 +195,7 @@ Execute(Should handle Python completion results correctly):
AssertEqual
\ [
\ {'word': 'what', 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1},
\ {'word': 'what', 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0",
@ -399,7 +399,7 @@ Execute(Should handle Python completion results correctly):
\ }
\ })
Execute(Should handle Python completion results correctly):
Execute(Should handle extra Python completion results correctly):
let b:ale_completion_info = {
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\ 'prefix': 'mig',
@ -407,8 +407,8 @@ Execute(Should handle Python completion results correctly):
AssertEqual
\ [
\ {'word': 'migrations', 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1},
\ {'word': 'MigEngine', 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1},
\ {'word': 'migrations', 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'MigEngine', 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@ -441,7 +441,7 @@ Execute(Should handle Python completion results correctly):
Execute(Should handle missing keys):
AssertEqual
\ [
\ {'word': 'x', 'menu': '', 'info': '', 'kind': 'v', 'icase': 1},
\ {'word': 'x', 'menu': '', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@ -459,7 +459,7 @@ Execute(Should handle missing keys):
Execute(Should handle documentation in the markdown format):
AssertEqual
\ [
\ {'word': 'migrations', 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1},
\ {'word': 'migrations', 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'jsonrpc': '2.0',
@ -483,7 +483,7 @@ Execute(Should handle documentation in the markdown format):
Execute(Should handle completion messages with textEdit objects):
AssertEqual
\ [
\ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1},
\ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
@ -514,7 +514,7 @@ Execute(Should handle completion messages with textEdit objects):
Execute(Should handle completion messages with the deprecated insertText attribute):
AssertEqual
\ [
\ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1},
\ {'word': 'next_callback', 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
@ -547,7 +547,8 @@ Execute(Should handle completion messages with additionalTextEdits when ale_comp
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({
\ 'codeActions': [
\ '_ale_completion_item': 1,
\ 'code_actions': [
\ {
\ 'description': 'completion',
\ 'changes': [
@ -658,6 +659,7 @@ Execute(Should still handle completion messages with empty additionalTextEdits w
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ }
\ ],
\ ale#completion#ParseLSPCompletions({

View File

@ -90,6 +90,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ 'dup': g:ale_completion_autoimport,
\ },
\ {
@ -98,6 +99,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': 'foo bar baz',
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ 'dup': g:ale_completion_autoimport,
\ },
\ {
@ -106,6 +108,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ 'dup': g:ale_completion_autoimport,
\ },
\ ],
@ -179,7 +182,8 @@ Execute(Entries without details should be included in the responses):
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({
\ 'codeActions': [{
\ '_ale_completion_item': 1,
\ 'code_actions': [{
\ 'description': 'import { def } from "./Foo";',
\ 'changes': [],
\ }],
@ -192,6 +196,7 @@ Execute(Entries without details should be included in the responses):
\ 'info': 'foo bar baz',
\ 'kind': 'v',
\ 'icase': 1,
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ 'dup': g:ale_completion_autoimport,
\ },
\ {
@ -199,6 +204,7 @@ Execute(Entries without details should be included in the responses):
\ 'menu': '',
\ 'info': '',
\ 'kind': 'v',
\ 'user_data': json_encode({'_ale_completion_item': 1}),
\ 'icase': 1,
\ },
\ ],
@ -260,7 +266,8 @@ Execute(Default imports should be handled correctly):
\ 'kind': 't',
\ 'icase': 1,
\ 'user_data': json_encode({
\ 'codeActions': [{
\ '_ale_completion_item': 1,
\ 'code_actions': [{
\ 'description': 'Import default ''abcd'' from module "./foo"',
\ 'changes': [],
\ }],

View File

@ -196,6 +196,10 @@ After:
" Clear the messages between tests.
echomsg ''
if !exists('g:ale_command_wrapper')
let g:ale_command_wrapper = ''
endif
Given testft (A file with three lines):
a
b
@ -206,6 +210,13 @@ Execute(ALEFix should complain when there are no functions to call):
call ale#test#FlushJobs()
AssertEqual 'No fixers have been defined. Try :ALEFixSuggest', GetLastMessage()
Execute(ALEFix should not complain when the command is run with a bang):
echom 'none'
ALEFix!
call ale#test#FlushJobs()
AssertEqual 'none', GetLastMessage()
Execute(ALEFix should apply simple functions):
let g:ale_fixers.testft = ['AddCarets']
ALEFix
@ -715,6 +726,19 @@ Execute(ale#fix#InitBufferData() should set up the correct data):
\ 'done': 0,
\ 'lines_before': ['a', 'b', 'c'],
\ 'should_save': 1,
\ 'ignore_file_changed_errors': 0,
\ },
\}, g:ale_fix_buffer_data
call ale#fix#InitBufferData(bufnr(''), '!')
AssertEqual {
\ bufnr(''): {
\ 'temporary_directory_list': [],
\ 'done': 0,
\ 'lines_before': ['a', 'b', 'c'],
\ 'should_save': 0,
\ 'ignore_file_changed_errors': 1,
\ },
\}, g:ale_fix_buffer_data

View File

@ -1,4 +1,5 @@
Execute(Checks for versions below the current version should succeed):
AssertEqual 1, ale#Has('ale-3.0.0')
AssertEqual 1, ale#Has('ale-2.7.0')
AssertEqual 1, ale#Has('ale-2.6.0')
AssertEqual 1, ale#Has('ale-2.5.0')

View File

@ -6,6 +6,7 @@ Before:
Save g:ale_completion_delay
Save g:ale_completion_enabled
Save g:ale_completion_max_suggestions
Save g:ale_disable_lsp
Save g:ale_echo_cursor
Save g:ale_echo_msg_error_str
Save g:ale_echo_msg_format
@ -24,6 +25,7 @@ Before:
Save g:ale_lint_on_text_changed
Save g:ale_linters
Save g:ale_linters_explicit
Save g:ale_linters_ignore
Save g:ale_list_vertical
Save g:ale_list_window_size
Save g:ale_loclist_msg_format
@ -64,6 +66,7 @@ Before:
let g:ale_completion_delay = 100
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = 50
let g:ale_disable_lsp = 0
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = '%code: %%s'
@ -80,6 +83,7 @@ Before:
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'normal'
let g:ale_linters_explicit = 0
let g:ale_linters_ignore = {'python': ['pyright']}
let g:ale_list_vertical = 0
let g:ale_list_window_size = 10
let g:ale_loclist_msg_format = '%code: %%s'
@ -138,6 +142,7 @@ Before:
\ 'let g:ale_completion_delay = 100',
\ 'let g:ale_completion_enabled = 0',
\ 'let g:ale_completion_max_suggestions = 50',
\ 'let g:ale_disable_lsp = 0',
\ 'let g:ale_echo_cursor = 1',
\ 'let g:ale_echo_msg_error_str = ''Error''',
\ 'let g:ale_echo_msg_format = ''%code: %%s''',
@ -158,6 +163,7 @@ Before:
\ 'let g:ale_linter_aliases = {}',
\ 'let g:ale_linters = {}',
\ 'let g:ale_linters_explicit = 0',
\ 'let g:ale_linters_ignore = {''python'': [''pyright'']}',
\ 'let g:ale_list_vertical = 0',
\ 'let g:ale_list_window_size = 10',
\ 'let g:ale_loclist_msg_format = ''%code: %%s''',
@ -243,6 +249,7 @@ Execute (ALEInfo with no linters should return the right output):
\ ' Current Filetype: nolintersft',
\ 'Available Linters: []',
\ ' Enabled Linters: []',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -265,6 +272,7 @@ Execute (ALEInfo should return buffer-local global ALE settings):
\ ' Current Filetype: ',
\ 'Available Linters: []',
\ ' Enabled Linters: []',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -279,6 +287,7 @@ Execute (ALEInfo with no filetype should return the right output):
\ ' Current Filetype: ',
\ 'Available Linters: []',
\ ' Enabled Linters: []',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -295,6 +304,7 @@ Execute (ALEInfo with a single linter should return the right output):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -312,6 +322,7 @@ Execute (ALEInfo with two linters should return the right output):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -333,6 +344,7 @@ Execute (ALEInfo should calculate enabled linters correctly):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -350,6 +362,7 @@ Execute (ALEInfo should only return linters for current filetype):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -367,6 +380,7 @@ Execute (ALEInfo with compound filetypes should return linters for both of them)
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -389,6 +403,7 @@ Execute (ALEInfo should return appropriately named global variables):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + [
@ -420,6 +435,7 @@ Execute (ALEInfoToFile should write to a file correctly):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + [
@ -447,6 +463,7 @@ Execute (ALEInfo should buffer-local linter variables):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + [
@ -478,6 +495,7 @@ Execute (ALEInfo should output linter aliases):
\ '''testlinter1'' -> [''testftalias1'', ''testftalias2'']',
\ '''testlinter2'' -> [''testftalias3'', ''testftalias4'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + [
@ -505,6 +523,7 @@ Execute (ALEInfo should return command history):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -532,6 +551,7 @@ Execute (ALEInfo command history should print exit codes correctly):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -580,6 +600,7 @@ Execute (ALEInfo command history should print command output if logging is on):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -618,6 +639,7 @@ Execute (ALEInfo should include executable checks in the history):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -647,6 +669,7 @@ Execute (The option for caching failing executable checks should work):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -669,6 +692,7 @@ Execute (LSP errors for a linter should be outputted):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -693,6 +717,7 @@ Execute (LSP errors for other linters shouldn't appear):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -715,6 +740,7 @@ Execute (ALEInfo should include linter global options):
\ ' Current Filetype: testft.testft2',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines
@ -740,6 +766,7 @@ Execute (ALEInfo should include linter global options for enabled linters):
\ ' Current Filetype: testft',
\ 'Available Linters: [''testlinter1'', ''testlinter2'']',
\ ' Enabled Linters: [''testlinter1'']',
\ ' Ignored Linters: []',
\ ]
\ + g:fixer_lines
\ + g:variables_lines

View File

@ -0,0 +1,27 @@
Before:
Save g:ale_buffer_info
let g:ale_buffer_info = {}
call ale#linter#PreventLoading('testft')
call ale#linter#Define('testft', {
\ 'name': 'testlinter',
\ 'callback': {-> []},
\ 'executable': has('win32') ? 'cmd' : 'true',
\ 'command': 'sleep 9001',
\})
After:
Restore
call ale#linter#Reset()
Given testft (An empty file):
Execute(ALELintStop should stop ALE from linting):
ALELint
Assert ale#engine#IsCheckingBuffer(bufnr('')), 'ALE did not start checking the buffer'
ALELintStop
Assert !ale#engine#IsCheckingBuffer(bufnr('')), 'ALELintStop didn''t work'

View File

@ -132,3 +132,19 @@ Execute(Linters where lint_file eventually evaluates to 1 shouldn't be run if we
call ale#test#FlushJobs()
AssertEqual [], ale#test#GetLoclistWithoutModule()
Execute(Keeping computed lint_file jobs running should work):
AssertEqual 'testlinter2', ale#linter#Get('foobar')[1].name
call ale#engine#InitBufferInfo(bufnr(''))
call ale#engine#MarkLinterActive(
\ g:ale_buffer_info[bufnr('')],
\ ale#linter#Get('foobar')[1]
\)
call ale#engine#RunLinters(bufnr(''), ale#linter#Get('foobar'), 0)
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list),
\ 'The active linter list was empty'
Assert ale#engine#IsCheckingBuffer(bufnr('')),
\ 'The IsCheckingBuffer function returned 0'