#2017 Add support for display results from other sources

This commit is contained in:
w0rp 2018-10-29 18:28:28 +00:00
parent 2846e86217
commit caac5c93d6
No known key found for this signature in database
GPG key ID: 0FC1ECAA8C81CD83
16 changed files with 393 additions and 38 deletions

View file

@ -94,6 +94,11 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
\ : l:linters
" Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer
silent doautocmd <nomodeline> User ALEWantResults
unlet! g:ale_want_results_buffer
" Don't set up buffer data and so on if there are no linters to run.
if !has_key(g:ale_buffer_info, a:buffer) && empty(l:linters)
return

View file

@ -79,6 +79,7 @@ function! ale#engine#InitBufferInfo(buffer) abort
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'active_linter_list': [],
\ 'active_other_sources_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
@ -97,6 +98,7 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
return !empty(get(l:info, 'active_linter_list', []))
\ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction
" Register a temporary file to be managed with the ALE engine for
@ -177,20 +179,27 @@ function! s:GatherOutput(job_id, line) abort
endif
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:info)
return
endif
if !a:from_other_source
" Remove this linter from the list of active linters.
" This may have already been done when the job exits.
call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name')
endif
" Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items.
let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist)
let l:linter_loclist = ale#engine#FixLocList(
\ a:buffer,
\ a:linter_name,
\ a:from_other_source,
\ a:loclist,
\)
" Remove previous items for this linter.
call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name')
@ -263,7 +272,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:loclist = []
endtry
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0)
endfunction
function! ale#engine#SetResults(buffer, loclist) abort
@ -335,7 +344,7 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfor
endfunction
function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:bufnr_map = {}
let l:new_loclist = []
@ -368,6 +377,10 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
\ 'linter_name': a:linter_name,
\}
if a:from_other_source
let l:item.from_other_source = 1
endif
if has_key(l:old_item, 'code')
let l:item.code = l:old_item.code
endif
@ -691,6 +704,7 @@ endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
" Problems from other sources will be kept.
let l:name_map = {}
for l:linter in a:linters
@ -699,7 +713,7 @@ function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
call filter(
\ get(g:ale_buffer_info[a:buffer], 'loclist', []),
\ 'get(l:name_map, get(v:val, ''linter_name''))',
\ 'get(v:val, ''from_other_source'') || get(l:name_map, get(v:val, ''linter_name''))',
\)
endfunction

View file

@ -17,7 +17,7 @@ function! ale#lsp#reset#StopAllLSPs() abort
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp)
call ale#engine#HandleLoclist(l:linter.name, l:buffer, [])
call ale#engine#HandleLoclist(l:linter.name, l:buffer, [], 0)
endif
endfor
endfor

View file

@ -38,7 +38,7 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
@ -81,7 +81,7 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort

View file

@ -0,0 +1,21 @@
" Tell ALE that another source has started checking a buffer.
function! ale#other_source#StartChecking(buffer, linter_name) abort
call ale#engine#InitBufferInfo(a:buffer)
let l:list = g:ale_buffer_info[a:buffer].active_other_sources_list
call add(l:list, a:linter_name)
call uniq(sort(l:list))
endfunction
" Show some results, and stop checking a buffer.
" To clear results or cancel checking a buffer, an empty List can be given.
function! ale#other_source#ShowResults(buffer, linter_name, loclist) abort
call ale#engine#InitBufferInfo(a:buffer)
let l:info = g:ale_buffer_info[a:buffer]
" Remove this linter name from the active list.
let l:list = l:info.active_other_sources_list
call filter(l:list, 'v:val isnot# a:linter_name')
call ale#engine#HandleLoclist(a:linter_name, a:buffer, a:loclist, 1)
endfunction

View file

@ -9,6 +9,7 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint|
3.1 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion|
@ -574,6 +575,68 @@ ALE offers several options for controlling which linters are run.
* Only running linters you asked for. - |g:ale_linters_explicit|
-------------------------------------------------------------------------------
3.1 Other Sources *ale-lint-other-sources*
Problems for a buffer can be taken from other sources and rendered by ALE.
This allows ALE to be used in combination with other plugins which also want
to display any problems they might find with a buffer. ALE's API includes the
following components for making this possible.
* |ale#other_source#StartChecking()| - Tell ALE that a buffer is being checked.
* |ale#other_source#ShowResults()| - Show results from another source.
* |ALEWantResults| - A signal for when ALE wants results.
Other resources can provide results for ALE to display at any time, following
ALE's loclist format. (See |ale-loclist-format|) For example: >
" Tell ALE to show some results.
" This function can be called at any time.
call ale#other_source#ShowResults(bufnr(''), 'some-linter-name', [
\ {'text': 'Something went wrong', lnum: 13},
\])
<
Other sources should use a unique name for identifying themselves. A single
linter name can be used for all problems from another source, or a series of
unique linter names can be used. Results can be cleared for that source by
providing an empty List.
|ale#other_source#StartChecking()| should be called whenever another source
starts checking a buffer, so other tools can know that a buffer is being
checked by some plugin. The |ALEWantResults| autocmd event can be used to
start checking a buffer for problems every time that ALE does. When
|ALEWantResults| is signaled, |g:ale_want_results_buffer| will be set to the
number of the buffer that ALE wants to check.
|ale#other_source#StartChecking()| should be called synchronously, and other
sources should perform their checks on a buffer in the background
asynchronously, so they don't interrupt editing.
A plugin might integrate its own checks with ALE like so: >
augroup SomeGroupName
autocmd!
autocmd User ALEWantResults call Hook(g:ale_want_results_buffer)
augroup END
function! DoBackgroundWork(buffer) abort
" Start some work in the background here.
" ...
" Then call WorkDone(a:buffer, results)
endfunction
function! Hook(buffer) abort
" Tell ALE we're going to check this buffer.
call ale#other_source#StartChecking(a:buffer, 'some-name')
call DoBackgroundWork(a:buffer)
endfunction
function! WorkDone(buffer, results) abort
" Send results to ALE after they have been collected.
call ale#other_source#ShowResults(buffer, 'some-name', a:results)
endfunction
<
===============================================================================
4. Fixing Problems *ale-fix*
@ -2763,6 +2826,25 @@ ale#linter#PreventLoading(filetype) *ale#linter#PreventLoading()*
|runtimepath| for that filetype. This function can be called from vimrc or
similar to prevent ALE from loading linters.
ale#other_source#ShowResults(buffer, linter_name, loclist)
*ale#other_source#ShowResults()*
Show results from another source of information.
`buffer` must be a valid buffer number, and `linter_name` must be a unique
name for identifying another source of information. The `loclist` given
where the problems in a buffer are, and should be provided in the format ALE
uses for regular linter results. See |ale-loclist-format|.
ale#other_source#StartChecking(buffer, linter_name)
*ale#other_source#StartChecking()*
Tell ALE that another source of information has started checking a buffer.
`buffer` must be a valid buffer number, and `linter_name` must be a unique
name for identifying another source of information.
ale#statusline#Count(buffer) *ale#statusline#Count()*
@ -2791,10 +2873,21 @@ b:ale_linted *b:ale_linted*
echo getbufvar(bufnr(''), 'ale_linted', 0) > 0 ? 'checked' : 'not checked'
<
g:ale_want_results_buffer *g:ale_want_results_buffer*
`g:ale_want_results_buffer` is set to the number of the buffer being checked
when the |ALEWantResults| event is signaled. This variable should be read to
figure out which buffer other sources should lint.
ALELintPre *ALELintPre-autocmd*
*ALELintPre*
ALELintPost *ALELintPost-autocmd*
*ALELintPost*
ALEFixPre *ALEFixPre-autocmd*
*ALEFixPre*
ALEFixPost *ALEFixPost-autocmd*
*ALEFixPost*
These |User| autocommands are triggered before and after every lint or fix
cycle. They can be used to update statuslines, send notifications, etc.
@ -2808,7 +2901,7 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd!
autocmd User ALELintPre hi Statusline ctermfg=darkgrey
autocmd User ALELintPost hi Statusline ctermfg=NONE
augroup end
augroup END
<
Or to display the progress in the statusline:
>
@ -2818,10 +2911,11 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd!
autocmd User ALELintPre let s:ale_running = 1 | redrawstatus
autocmd User ALELintPost let s:ale_running = 0 | redrawstatus
augroup end
augroup END
<
ALEJobStarted *ALEJobStarted-autocmd*
*ALEJobStarted*
This |User| autocommand is triggered immediately after a job is successfully
run. This provides better accuracy for checking linter status with
@ -2829,6 +2923,22 @@ ALEJobStarted *ALEJobStarted-autocmd*
triggered before any linters are executed.
ALEWantResults *ALEWantResults-autocmd*
*ALEWantResults*
This |User| autocommand is triggered before ALE begins a lint cycle. Another
source can respond by calling |ale#other_source#StartChecking()|, and
|ALELintPre| will be signaled thereafter, to allow other plugins to know
that another source is checking the buffer.
|g:ale_want_results_buffer| will be set to the number for a buffer being
checked when the event is signaled, and deleted after the event is done.
This variable should be read to know which buffer to check.
Other plugins can use this event to start checking buffers when ALE events
for checking buffers are triggered.
===============================================================================
10. Special Thanks *ale-special-thanks*

View file

@ -23,7 +23,7 @@ Before:
autocmd!
autocmd User ALEFixPre let g:pre_success = 1
autocmd User ALEFixPost let g:post_success = 1
augroup end
augroup END
if !has('win32')
let &shell = '/bin/bash'
@ -180,7 +180,6 @@ After:
unlet! g:ale_emulate_job_failure
unlet! b:ale_fixers
unlet! b:ale_fix_on_save
augroup! VaderTest
delfunction AddCarets
delfunction AddDollars
delfunction DoNothing
@ -204,6 +203,12 @@ After:
delfunction FixWithJSONPostProcessing
delfunction JSONPostProcessor
augroup VaderTest
autocmd!
augroup END
augroup! VaderTest
call ale#test#RestoreDirectory()
call ale#fix#registry#ResetToDefaults()

View file

@ -23,10 +23,11 @@ After:
let g:ale_run_synchronously = 0
try
augroup VaderTest
autocmd!
augroup END
augroup! VaderTest
catch
endtry
unlet! g:job_started_success
@ -38,7 +39,7 @@ Execute(Run a lint cycle with an actual job to check for ALEJobStarted):
augroup VaderTest
autocmd!
autocmd User ALEJobStarted let g:job_started_success = 1
augroup end
augroup END
ALELint

View file

@ -9,10 +9,11 @@ After:
let g:ale_run_synchronously = 0
let g:ale_buffer_info = {}
try
augroup VaderTest
autocmd!
augroup END
augroup! VaderTest
catch
endtry
Given testft(An empty file):
Execute(Run a lint cycle, and check that a variable is set in the autocmd):
@ -20,7 +21,7 @@ Execute(Run a lint cycle, and check that a variable is set in the autocmd):
autocmd!
autocmd User ALELintPre let g:pre_success = 1
autocmd User ALELintPost let g:post_success = 1
augroup end
augroup END
call ale#Queue(0)

View file

@ -31,7 +31,7 @@ After:
augroup VaderTest
autocmd!
augroup end
augroup END
augroup! VaderTest
@ -40,7 +40,7 @@ Execute(ALELintPre should not return success on ale#engine#IsCheckingBuffer):
augroup VaderTest
autocmd!
autocmd User ALELintPre let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0
augroup end
augroup END
ALELint
@ -50,7 +50,7 @@ Execute(ALEJobStarted should return success on ale#engine#IsCheckingBuffer):
augroup VaderTest
autocmd!
autocmd User ALEJobStarted let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0
augroup end
augroup END
ALELint

View file

@ -108,7 +108,7 @@ Before:
let g:run_linters_called = 1
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let g:loclist = a:loclist
endfunction

View file

@ -16,7 +16,7 @@ Execute(It should be possible to remap errors to style errors):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@ -35,7 +35,7 @@ Execute(It should be possible to remap errors to style errors with buffer-local
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@ -54,7 +54,7 @@ Execute(It should be possible to remap warnings to style warnings):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@ -73,7 +73,7 @@ Execute(It should be possible to remap style errors to errors):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@ -92,7 +92,7 @@ Execute(It should be possible to remap style warnings to warnings):
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@ -111,7 +111,7 @@ Execute(It should be possible to info problems to warnings):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
\ ale#engine#FixLocList(bufnr(''), 'foo', [
\ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},

View file

@ -41,6 +41,7 @@ Execute(FixLocList should set all the default values correctly):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': 2}, {'text': 'b', 'lnum': 2}],
\ )
@ -61,6 +62,7 @@ Execute(FixLocList should use the values we supply):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{
\ 'text': 'a',
\ 'lnum': 3,
@ -89,6 +91,7 @@ Execute(FixLocList should set items with lines beyond the end to the last line):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': 11}],
\ )
@ -109,6 +112,7 @@ Execute(FixLocList should move line 0 to line 1):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': 0}],
\ )
@ -130,6 +134,7 @@ Execute(FixLocList should convert line and column numbers correctly):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': '010', 'col': '010'}],
\ )
@ -163,6 +168,7 @@ Execute(FixLocList should pass on end_col values):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [
\ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012'},
\ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12},
@ -200,6 +206,7 @@ Execute(FixLocList should pass on end_lnum values):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [
\ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012', 'end_lnum': '013'},
\ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12, 'end_lnum': 13},
@ -224,6 +231,7 @@ Execute(FixLocList should allow subtypes to be set):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': 11, 'sub_type': 'style'}],
\ )
@ -285,6 +293,7 @@ Execute(FixLocList should accept filenames):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [
\ {'text': 'a', 'lnum': 2, 'filename': expand('%:p')},
\ {'text': 'a', 'lnum': 3, 'filename': expand('%:p')},
@ -322,6 +331,7 @@ Execute(FixLocList should interpret temporary filenames as being the current buf
\ ale#engine#FixLocList(
\ bufnr(''),
\ 'foobar',
\ 0,
\ [
\ {'text': 'a', 'lnum': 2, 'filename': b:temp_name},
\ {'text': 'a', 'lnum': 3, 'filename': substitute(b:temp_name, '\\', '/', 'g')},
@ -346,9 +356,43 @@ Execute(The error code should be passed on):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [{'text': 'a', 'lnum': 11, 'code': 'some-code'}],
\ )
Execute(FixLocList should mark problems as coming from other sources if requested):
AssertEqual
\ [
\ {
\ 'text': 'a',
\ 'lnum': 2,
\ 'col': 0,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'type': 'E',
\ 'nr': -1,
\ 'linter_name': 'foobar',
\ 'from_other_source': 1,
\ },
\ {
\ 'text': 'b',
\ 'lnum': 2,
\ 'col': 0,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'type': 'E',
\ 'nr': -1,
\ 'linter_name': 'foobar',
\ 'from_other_source': 1,
\ },
\],
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 1,
\ [{'text': 'a', 'lnum': 2}, {'text': 'b', 'lnum': 2}],
\ )
Given(A file with Japanese multi-byte text):
はじめまして!
-私はワープです。
@ -367,6 +411,7 @@ Execute(character positions should be converted to byte positions):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
\ 0,
\ [
\ {'text': 'a', 'lnum': 1, 'col': 0, 'vcol': 1},
\ {'text': 'a', 'lnum': 1, 'col': 1, 'vcol': 1},

View file

@ -0,0 +1,153 @@
Before:
Save g:ale_buffer_info
Save g:ale_set_signs
Save g:ale_set_quickfix
Save g:ale_set_loclist
Save g:ale_set_highlights
Save g:ale_echo_cursor
let g:ale_buffer_info = {}
let g:ale_run_synchronously = 1
let g:ale_set_lists_synchronously = 1
let g:ale_set_signs = 0
let g:ale_set_quickfix = 0
let g:ale_set_loclist = 1
let g:ale_set_highlights = 0
let g:ale_echo_cursor = 0
function! TestCallback(buffer, output)
return []
endfunction
call ale#linter#Define('foobar', {
\ 'name': 'testlinter',
\ 'callback': 'TestCallback',
\ 'executable': has('win32') ? 'cmd' : 'echo',
\ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''',
\})
After:
Restore
unlet! b:ale_linters
unlet! g:want_results_signaled
unlet! g:want_results_buffer_value
unlet! g:lint_pre_signaled
unlet! g:ale_run_synchronously
unlet! g:ale_set_lists_synchronously
delfunction TestCallback
augroup VaderTest
autocmd!
augroup END
augroup! VaderTest
call ale#linter#Reset()
call setloclist(0, [])
Given foobar (Some imaginary filetype):
Execute(StartChecking should mark a buffer as being actively checked):
Assert !ale#engine#IsCheckingBuffer(bufnr(''))
call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
Assert ale#engine#IsCheckingBuffer(bufnr(''))
Execute(ShowResults sould make a buffer inactive):
call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
call ale#other_source#StartChecking(bufnr(''), 'second-other-source-linter')
call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [])
Assert ale#engine#IsCheckingBuffer(bufnr(''))
call ale#other_source#ShowResults(bufnr(''), 'second-other-source-linter', [])
Assert !ale#engine#IsCheckingBuffer(bufnr(''))
Execute(ShowResults should show results at any time):
call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [
\ {'text': 'xyz', 'lnum': 1},
\])
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 0,
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'E',
\ 'pattern': '',
\ 'text': 'xyz',
\ },
\ ],
\ ale#test#GetLoclistWithoutModule()
call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [])
AssertEqual [], ale#test#GetLoclistWithoutModule()
Execute(A regular lint cycle shouldn't clear results from other sources):
call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [
\ {'text': 'xyz', 'lnum': 1},
\])
ALELint
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 0,
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'E',
\ 'pattern': '',
\ 'text': 'xyz',
\ },
\ ],
\ ale#test#GetLoclistWithoutModule()
Execute(ALEWantResults should be signaled when a buffer is checked):
augroup VaderTest
autocmd!
autocmd User ALEWantResults let g:want_results_signaled = 1
autocmd User ALELintPre let g:lint_pre_signaled = 1
augroup END
" Even when all linters are disabled, we should send the signal.
let b:ale_linters = []
ALELint
Assert get(g:, 'want_results_signaled')
Assert !get(g:, 'lint_pre_signaled')
Execute(ALEWantResults should set a variable indicating which buffer is being checked):
augroup VaderTest
autocmd!
autocmd User ALEWantResults let g:want_results_buffer_value = g:ale_want_results_buffer
augroup END
let b:ale_linters = []
ALELint
AssertEqual bufnr(''), g:want_results_buffer_value
Execute(ALEWantResults should lead to an ALELintPre signal if another source responds):
augroup VaderTest
autocmd!
autocmd User ALEWantResults call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
autocmd User ALELintPre let g:lint_pre_signaled = 1
augroup END
" Even when all linters are disabled, we should send the signal.
let b:ale_linters = []
ALELint
Assert get(g:, 'lint_pre_signaled')

View file

@ -45,7 +45,7 @@ Before:
let g:ale_buffer_info = {bufnr(''): {'loclist': []}}
let g:ale_handle_loclist_called = 0
function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let g:ale_handle_loclist_called = 1
endfunction

View file

@ -9,14 +9,14 @@ Before:
let g:ale_buffer_info = {}
call ale#engine#InitBufferInfo(bufnr('') + 1)
let g:ale_buffer_info[bufnr('') + 1].loclist =
\ ale#engine#FixLocList(bufnr('') + 1, 'linter_one', [
\ ale#engine#FixLocList(bufnr('') + 1, 'linter_one', 0, [
\ {'lnum': 1, 'filename': expand('%:p'), 'text': 'foo'},
\ {'lnum': 2, 'filename': expand('%:p'), 'text': 'bar'},
\ {'lnum': 2, 'text': 'ignore this one'},
\ ])
call ale#engine#InitBufferInfo(bufnr('') + 2)
let g:ale_buffer_info[bufnr('') + 2].loclist =
\ ale#engine#FixLocList(bufnr('') + 2, 'linter_one', [
\ ale#engine#FixLocList(bufnr('') + 2, 'linter_one', 0, [
\ {'lnum': 1, 'filename': expand('%:p'), 'text': 'foo'},
\ {'lnum': 3, 'filename': expand('%:p'), 'text': 'baz'},
\ {'lnum': 5, 'text': 'ignore this one'},