mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-24 21:11:28 +08:00
A new function is added here which will later be modified for public use in linter and fixer callbacks. All linting and fixing now goes through this new function, to prove that it works in all cases.
188 lines
5.8 KiB
VimL
188 lines
5.8 KiB
VimL
" Author: w0rp <devw0rp@gmail.com>
|
|
" Description: Functions for making testing ALE easier.
|
|
"
|
|
" This file should not typically be loaded during the normal execution of ALE.
|
|
|
|
" Change the directory for checking things in particular test directories
|
|
"
|
|
" This function will set the g:dir variable, which represents the working
|
|
" directory after changing the path. This variable allows a test to change
|
|
" directories, and then switch back to a directory at the start of the test
|
|
" run.
|
|
"
|
|
" This function should be run in a Vader Before: block.
|
|
function! ale#test#SetDirectory(docker_path) abort
|
|
if a:docker_path[:len('/testplugin/') - 1] isnot# '/testplugin/'
|
|
throw 'docker_path must start with /testplugin/!'
|
|
endif
|
|
|
|
" Try to switch directory, which will fail when running tests directly,
|
|
" and not through the Docker image.
|
|
silent! execute 'cd ' . fnameescape(a:docker_path)
|
|
let g:dir = getcwd() " no-custom-checks
|
|
endfunction
|
|
|
|
" When g:dir is defined, switch back to the directory we saved, and then
|
|
" delete that variable.
|
|
"
|
|
" The filename will be reset to dummy.txt
|
|
"
|
|
" This function should be run in a Vader After: block.
|
|
function! ale#test#RestoreDirectory() abort
|
|
call ale#test#SetFilename('dummy.txt')
|
|
silent execute 'cd ' . fnameescape(g:dir)
|
|
unlet! g:dir
|
|
endfunction
|
|
|
|
" Change the filename for the current buffer using a relative path to
|
|
" the script without running autocmd commands.
|
|
"
|
|
" If a g:dir variable is set, it will be used as the path to the directory
|
|
" containing the test file.
|
|
function! ale#test#SetFilename(path) abort
|
|
let l:dir = get(g:, 'dir', '')
|
|
|
|
if empty(l:dir)
|
|
let l:dir = getcwd() " no-custom-checks
|
|
endif
|
|
|
|
let l:full_path = ale#path#IsAbsolute(a:path)
|
|
\ ? a:path
|
|
\ : l:dir . '/' . a:path
|
|
|
|
silent! noautocmd execute 'file ' . fnameescape(ale#path#Simplify(l:full_path))
|
|
endfunction
|
|
|
|
function! s:RemoveModule(results) abort
|
|
for l:item in a:results
|
|
if has_key(l:item, 'module')
|
|
call remove(l:item, 'module')
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
" Return loclist data without the module string, only in newer Vim versions.
|
|
function! ale#test#GetLoclistWithoutModule() abort
|
|
let l:results = getloclist(0)
|
|
call s:RemoveModule(l:results)
|
|
|
|
return l:results
|
|
endfunction
|
|
|
|
function! ale#test#GetQflistWithoutModule() abort
|
|
let l:results = getqflist()
|
|
call s:RemoveModule(l:results)
|
|
|
|
return l:results
|
|
endfunction
|
|
|
|
function! ale#test#GetPreviewWindowText() abort
|
|
for l:window in range(1, winnr('$'))
|
|
if getwinvar(l:window, '&previewwindow', 0)
|
|
let l:buffer = winbufnr(l:window)
|
|
|
|
return getbufline(l:buffer, 1, '$')
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
" This function can be called with a timeout to wait for all jobs to finish.
|
|
" If the jobs to not finish in the given number of milliseconds,
|
|
" an exception will be thrown.
|
|
"
|
|
" The time taken will be a very rough approximation, and more time may be
|
|
" permitted than is specified.
|
|
function! ale#test#WaitForJobs(deadline) abort
|
|
let l:start_time = ale#events#ClockMilliseconds()
|
|
|
|
if l:start_time == 0
|
|
throw 'Failed to read milliseconds from the clock!'
|
|
endif
|
|
|
|
let l:job_list = []
|
|
|
|
" Gather all of the jobs from every buffer.
|
|
for [l:buffer, l:data] in items(ale#command#GetData())
|
|
call extend(l:job_list, map(keys(l:data.jobs), 'str2nr(v:val)'))
|
|
endfor
|
|
|
|
" NeoVim has a built-in API for this, so use that.
|
|
if has('nvim')
|
|
let l:nvim_code_list = jobwait(l:job_list, a:deadline)
|
|
|
|
if index(l:nvim_code_list, -1) >= 0
|
|
throw 'Jobs did not complete on time!'
|
|
endif
|
|
|
|
return
|
|
endif
|
|
|
|
let l:should_wait_more = 1
|
|
|
|
while l:should_wait_more
|
|
let l:should_wait_more = 0
|
|
|
|
for l:job_id in l:job_list
|
|
if ale#job#IsRunning(l:job_id)
|
|
let l:now = ale#events#ClockMilliseconds()
|
|
|
|
if l:now - l:start_time > a:deadline
|
|
" Stop waiting after a timeout, so we don't wait forever.
|
|
throw 'Jobs did not complete on time!'
|
|
endif
|
|
|
|
" Wait another 10 milliseconds
|
|
let l:should_wait_more = 1
|
|
sleep 10ms
|
|
break
|
|
endif
|
|
endfor
|
|
endwhile
|
|
|
|
" Sleep for a small amount of time after all jobs finish.
|
|
" This seems to be enough to let handlers after jobs end run, and
|
|
" prevents the occasional failure where this function exits after jobs
|
|
" end, but before handlers are run.
|
|
sleep 10ms
|
|
|
|
" We must check the buffer data again to see if new jobs started
|
|
" for command_chain linters.
|
|
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:job_id, l:linter] in get(l:info, 'job_list', [])
|
|
if ale#job#IsRunning(l:job_id)
|
|
let l:has_new_jobs = 1
|
|
break
|
|
endif
|
|
endfor
|
|
endfor
|
|
|
|
if l:has_new_jobs
|
|
" We have to wait more. Offset the timeout by the time taken so far.
|
|
let l:now = ale#events#ClockMilliseconds()
|
|
let l:new_deadline = a:deadline - (l:now - l:start_time)
|
|
|
|
if l:new_deadline <= 0
|
|
" Enough time passed already, so stop immediately.
|
|
throw 'Jobs did not complete on time!'
|
|
endif
|
|
|
|
call ale#test#WaitForJobs(l:new_deadline)
|
|
endif
|
|
endfunction
|
|
|
|
function! ale#test#FlushJobs() abort
|
|
" The variable is checked for in a loop, as calling one series of
|
|
" callbacks can trigger a further series of callbacks.
|
|
while exists('g:ale_run_synchronously_callbacks')
|
|
let l:callbacks = g:ale_run_synchronously_callbacks
|
|
unlet g:ale_run_synchronously_callbacks
|
|
|
|
for l:Callback in l:callbacks
|
|
call l:Callback()
|
|
endfor
|
|
endwhile
|
|
endfunction
|