#333 Finish implementing the lint_file option
This commit is contained in:
parent
c59204b94f
commit
18bae7da2e
@ -3,7 +3,7 @@
|
|||||||
" Manages execution of linters when requested by autocommands
|
" Manages execution of linters when requested by autocommands
|
||||||
|
|
||||||
let s:lint_timer = -1
|
let s:lint_timer = -1
|
||||||
let s:should_lint_file = 0
|
let s:should_lint_file_for_buffer = {}
|
||||||
|
|
||||||
" A function for checking various conditions whereby ALE just shouldn't
|
" A function for checking various conditions whereby ALE just shouldn't
|
||||||
" attempt to do anything, say if particular buffer types are open in Vim.
|
" attempt to do anything, say if particular buffer types are open in Vim.
|
||||||
@ -20,8 +20,8 @@ function! ale#Queue(delay, ...) abort
|
|||||||
throw 'too many arguments!'
|
throw 'too many arguments!'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Default run_file_linters to 0
|
" Default linting_flag to ''
|
||||||
let l:linting_flag = len(a:0) > 1 ? a:1 : ''
|
let l:linting_flag = get(a:000, 0, '')
|
||||||
|
|
||||||
if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
|
if l:linting_flag !=# '' && l:linting_flag !=# 'lint_file'
|
||||||
throw "linting_flag must be either '' or 'lint_file'"
|
throw "linting_flag must be either '' or 'lint_file'"
|
||||||
@ -31,8 +31,11 @@ function! ale#Queue(delay, ...) abort
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Remember the event used for linting.
|
" Remember that we want to check files for this buffer.
|
||||||
let s:should_lint_file = l:linting_flag ==# 'lint_file'
|
" We will remember this until we finally run the linters, via any event.
|
||||||
|
if l:linting_flag ==# 'lint_file'
|
||||||
|
let s:should_lint_file_for_buffer[bufnr('%')] = 1
|
||||||
|
endif
|
||||||
|
|
||||||
if s:lint_timer != -1
|
if s:lint_timer != -1
|
||||||
call timer_stop(s:lint_timer)
|
call timer_stop(s:lint_timer)
|
||||||
@ -59,6 +62,13 @@ function! ale#Lint(...) abort
|
|||||||
|
|
||||||
let l:buffer = bufnr('%')
|
let l:buffer = bufnr('%')
|
||||||
let l:linters = ale#linter#Get(&filetype)
|
let l:linters = ale#linter#Get(&filetype)
|
||||||
|
let l:should_lint_file = 0
|
||||||
|
|
||||||
|
" Check if we previously requested checking the file.
|
||||||
|
if has_key(s:should_lint_file_for_buffer, l:buffer)
|
||||||
|
unlet s:should_lint_file_for_buffer[l:buffer]
|
||||||
|
let l:should_lint_file = 1
|
||||||
|
endif
|
||||||
|
|
||||||
" Initialise the buffer information if needed.
|
" Initialise the buffer information if needed.
|
||||||
call ale#engine#InitBufferInfo(l:buffer)
|
call ale#engine#InitBufferInfo(l:buffer)
|
||||||
@ -66,7 +76,22 @@ function! ale#Lint(...) abort
|
|||||||
" Clear the new loclist again, so we will work with all new items.
|
" Clear the new loclist again, so we will work with all new items.
|
||||||
let g:ale_buffer_info[l:buffer].new_loclist = []
|
let g:ale_buffer_info[l:buffer].new_loclist = []
|
||||||
|
|
||||||
|
if l:should_lint_file
|
||||||
|
" Clear loclist items for files if we are checking files again.
|
||||||
|
let g:ale_buffer_info[l:buffer].lint_file_loclist = []
|
||||||
|
else
|
||||||
|
" Otherwise, don't run any `lint_file` linters
|
||||||
|
" We will continue running any linters which are currently checking
|
||||||
|
" the file, and the items will be mixed together with any new items.
|
||||||
|
call filter(l:linters, '!v:val.lint_file')
|
||||||
|
endif
|
||||||
|
|
||||||
for l:linter in l:linters
|
for l:linter in l:linters
|
||||||
call ale#engine#Invoke(l:buffer, l:linter)
|
call ale#engine#Invoke(l:buffer, l:linter)
|
||||||
endfor
|
endfor
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" Reset flags indicating that files should be checked for all buffers.
|
||||||
|
function! ale#ResetLintFileMarkers() abort
|
||||||
|
let s:should_lint_file_for_buffer = {}
|
||||||
|
endfunction
|
||||||
|
@ -226,7 +226,13 @@ function! s:HandleExit(job) abort
|
|||||||
let l:linter_loclist = ale#engine#FixLocList(l:buffer, l:linter, l:linter_loclist)
|
let l:linter_loclist = ale#engine#FixLocList(l:buffer, l:linter, l:linter_loclist)
|
||||||
|
|
||||||
" Add the loclist items from the linter.
|
" Add the loclist items from the linter.
|
||||||
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
|
" loclist items for files which are checked go into a different list,
|
||||||
|
" and are kept between runs.
|
||||||
|
if l:linter.lint_file
|
||||||
|
call extend(g:ale_buffer_info[l:buffer].lint_file_loclist, l:linter_loclist)
|
||||||
|
else
|
||||||
|
call extend(g:ale_buffer_info[l:buffer].new_loclist, l:linter_loclist)
|
||||||
|
endif
|
||||||
|
|
||||||
if !empty(g:ale_buffer_info[l:buffer].job_list)
|
if !empty(g:ale_buffer_info[l:buffer].job_list)
|
||||||
" Wait for all jobs to complete before doing anything else.
|
" Wait for all jobs to complete before doing anything else.
|
||||||
@ -237,14 +243,18 @@ function! s:HandleExit(job) abort
|
|||||||
" now that all jobs have completed.
|
" now that all jobs have completed.
|
||||||
call ale#engine#RemoveManagedFiles(l:buffer)
|
call ale#engine#RemoveManagedFiles(l:buffer)
|
||||||
|
|
||||||
|
" Combine the lint_file List and the List for everything else.
|
||||||
|
let l:combined_list = g:ale_buffer_info[l:buffer].lint_file_loclist
|
||||||
|
\ + g:ale_buffer_info[l:buffer].new_loclist
|
||||||
|
|
||||||
" Sort the loclist again.
|
" Sort the loclist again.
|
||||||
" We need a sorted list so we can run a binary search against it
|
" We need a sorted list so we can run a binary search against it
|
||||||
" for efficient lookup of the messages in the cursor handler.
|
" for efficient lookup of the messages in the cursor handler.
|
||||||
call sort(g:ale_buffer_info[l:buffer].new_loclist, 'ale#util#LocItemCompare')
|
call sort(l:combined_list, 'ale#util#LocItemCompare')
|
||||||
|
|
||||||
" Now swap the old and new loclists, after we have collected everything
|
" Now swap the old and new loclists, after we have collected everything
|
||||||
" and sorted the list again.
|
" and sorted the list again.
|
||||||
let g:ale_buffer_info[l:buffer].loclist = g:ale_buffer_info[l:buffer].new_loclist
|
let g:ale_buffer_info[l:buffer].loclist = l:combined_list
|
||||||
let g:ale_buffer_info[l:buffer].new_loclist = []
|
let g:ale_buffer_info[l:buffer].new_loclist = []
|
||||||
|
|
||||||
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
call ale#engine#SetResults(l:buffer, g:ale_buffer_info[l:buffer].loclist)
|
||||||
@ -255,6 +265,7 @@ endfunction
|
|||||||
|
|
||||||
function! ale#engine#SetResults(buffer, loclist) abort
|
function! ale#engine#SetResults(buffer, loclist) abort
|
||||||
" Set signs first. This could potentially fix some line numbers.
|
" Set signs first. This could potentially fix some line numbers.
|
||||||
|
" The List could be sorted again here by SetSigns.
|
||||||
if g:ale_set_signs
|
if g:ale_set_signs
|
||||||
call ale#sign#SetSigns(a:buffer, a:loclist)
|
call ale#sign#SetSigns(a:buffer, a:loclist)
|
||||||
endif
|
endif
|
||||||
@ -698,10 +709,14 @@ function! ale#engine#WaitForJobs(deadline) abort
|
|||||||
" for command_chain linters.
|
" for command_chain linters.
|
||||||
let l:has_new_jobs = 0
|
let l:has_new_jobs = 0
|
||||||
|
|
||||||
|
" Check again to see if any jobs are running.
|
||||||
for l:info in values(g:ale_buffer_info)
|
for l:info in values(g:ale_buffer_info)
|
||||||
if !empty(l:info.job_list)
|
for l:job in l:info.job_list
|
||||||
let l:has_new_jobs = 1
|
if job_status(l:job) ==# 'run'
|
||||||
endif
|
let l:has_new_jobs = 1
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
if l:has_new_jobs
|
if l:has_new_jobs
|
||||||
|
18
doc/ale.txt
18
doc/ale.txt
@ -1407,6 +1407,24 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||||||
if a command manually reads from a temporary file
|
if a command manually reads from a temporary file
|
||||||
instead, etc.
|
instead, etc.
|
||||||
|
|
||||||
|
`lint_file` A |Number| (`0` or `1`) indicating whether a command
|
||||||
|
should read the file instead of the Vim buffer. This
|
||||||
|
option can be used for linters which must check the
|
||||||
|
file on disk, and which cannot check a Vim buffer
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Linters set with this option will not be run as a
|
||||||
|
user types, per |g:ale_lint_on_text_changed|. Linters
|
||||||
|
will instead be run only when events occur against
|
||||||
|
the file on disk, including |g:ale_lint_on_enter|
|
||||||
|
and |g:ale_lint_on_save|. Linters with this option
|
||||||
|
set to `1` will also be run when linters are run
|
||||||
|
manually, per |ALELint-autocmd|.
|
||||||
|
|
||||||
|
When this option is set to `1`, `read_buffer` will
|
||||||
|
be set automatically to `0`. The two options cannot
|
||||||
|
be used together.
|
||||||
|
|
||||||
Only one of `command`, `command_callback`, or `command_chain` should be
|
Only one of `command`, `command_callback`, or `command_chain` should be
|
||||||
specified. `command_callback` is generally recommended when a command string
|
specified. `command_callback` is generally recommended when a command string
|
||||||
needs to be generated dynamically, or any global options are used.
|
needs to be generated dynamically, or any global options are used.
|
||||||
|
174
test/test_lint_file_linters.vader
Normal file
174
test/test_lint_file_linters.vader
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
Before:
|
||||||
|
let g:buffer_result = [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\]
|
||||||
|
|
||||||
|
function! LintFileCallback(buffer, output)
|
||||||
|
return [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! BufferCallback(buffer, output)
|
||||||
|
return deepcopy(g:buffer_result)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! GetSimplerLoclist()
|
||||||
|
let l:loclist = []
|
||||||
|
|
||||||
|
for l:item in getloclist(0)
|
||||||
|
call add(l:loclist, {
|
||||||
|
\ 'lnum': l:item.lnum,
|
||||||
|
\ 'col': l:item.col,
|
||||||
|
\ 'text': l:item.text,
|
||||||
|
\ 'type': l:item.type,
|
||||||
|
\})
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:loclist
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call ale#linter#Define('foobar', {
|
||||||
|
\ 'name': 'lint_file_linter',
|
||||||
|
\ 'callback': 'LintFileCallback',
|
||||||
|
\ 'executable': 'echo',
|
||||||
|
\ 'command': 'echo',
|
||||||
|
\ 'lint_file': 1,
|
||||||
|
\})
|
||||||
|
|
||||||
|
call ale#linter#Define('foobar', {
|
||||||
|
\ 'name': 'buffer_linter',
|
||||||
|
\ 'callback': 'BufferCallback',
|
||||||
|
\ 'executable': 'echo',
|
||||||
|
\ 'command': 'echo',
|
||||||
|
\ 'read_buffer': 0,
|
||||||
|
\})
|
||||||
|
|
||||||
|
After:
|
||||||
|
unlet g:buffer_result
|
||||||
|
let g:ale_buffer_info = {}
|
||||||
|
call ale#linter#Reset()
|
||||||
|
call setloclist(0, [])
|
||||||
|
delfunction LintFileCallback
|
||||||
|
delfunction BufferCallback
|
||||||
|
|
||||||
|
Given foobar (Some imaginary filetype):
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
Execute(Running linters without 'lint_file' should run only buffer linters):
|
||||||
|
call ale#ResetLintFileMarkers()
|
||||||
|
let g:ale_buffer_info = {}
|
||||||
|
call ale#Queue(0)
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
AssertEqual [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\], GetSimplerLoclist()
|
||||||
|
|
||||||
|
Execute(Running linters with 'lint_file' should run all linters):
|
||||||
|
call ale#ResetLintFileMarkers()
|
||||||
|
let g:ale_buffer_info = {}
|
||||||
|
call ale#Queue(0, 'lint_file')
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
AssertEqual [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'buffer warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\], GetSimplerLoclist()
|
||||||
|
|
||||||
|
Execute(Linter errors from files should be kept):
|
||||||
|
call ale#ResetLintFileMarkers()
|
||||||
|
let g:ale_buffer_info = {}
|
||||||
|
call ale#Queue(0, 'lint_file')
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
" Change the results for the buffer callback.
|
||||||
|
let g:buffer_result = [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'new buffer error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\]
|
||||||
|
|
||||||
|
call ale#Queue(0)
|
||||||
|
call ale#engine#WaitForJobs(2000)
|
||||||
|
|
||||||
|
AssertEqual [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 1,
|
||||||
|
\ 'text': 'new buffer error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 1,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file warning',
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 2,
|
||||||
|
\ 'col': 3,
|
||||||
|
\ 'text': 'file error',
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ },
|
||||||
|
\], GetSimplerLoclist()
|
Loading…
Reference in New Issue
Block a user