#2132 - Set up fixers for deferred support

This commit is contained in:
w0rp 2019-02-26 08:35:58 +00:00
parent 89e5491862
commit 70a9176de0
No known key found for this signature in database
GPG Key ID: 0FC1ECAA8C81CD83
2 changed files with 94 additions and 84 deletions

View File

@ -131,35 +131,55 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
\}) \})
endfunction endfunction
function! s:RunJob(options) abort function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer if ale#command#IsDeferred(a:result)
let l:command = a:options.command let a:result.result_callback = {x -> s:RunJob(x, a:options)}
let l:input = a:options.input
let l:ChainWith = a:options.chain_with
let l:read_buffer = a:options.read_buffer
if empty(l:command) return
" If there's nothing further to chain the command with, stop here. endif
if l:ChainWith is v:null
return v:false let l:buffer = a:options.buffer
let l:input = a:options.input
if a:result is 0 || type(a:result) is v:t_list
if type(a:result) is v:t_list
let l:input = a:result
endif endif
" If there's another chained callback to run, then run that.
call s:RunFixer({ call s:RunFixer({
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index + 1,
\ 'callback_list': a:options.callback_list,
\})
return
endif
let l:command = get(a:result, 'command', '')
let l:ChainWith = get(a:result, 'chain_with', v:null)
if empty(l:command)
" If the command is empty, skip to the next item, or call the
" chain_with function.
call s:RunFixer({
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_index': a:options.callback_index + (l:ChainWith is v:null),
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith, \ 'chain_callback': l:ChainWith,
\ 'output': [], \ 'output': [],
\}) \})
return v:true return
endif endif
let l:output_stream = a:options.output_stream let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
" Default to piping the buffer for the last fixer in the chain.
let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
let l:output_stream = get(a:result, 'output_stream', 'stdout')
if a:options.read_temporary_file if l:read_temporary_file
let l:output_stream = 'none' let l:output_stream = 'none'
endif endif
@ -168,10 +188,10 @@ function! s:RunJob(options) abort
\ 'chain_with': l:ChainWith, \ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'process_with': a:options.process_with, \ 'process_with': get(a:result, 'process_with', v:null),
\ 'read_temporary_file': a:options.read_temporary_file, \ 'read_temporary_file': l:read_temporary_file,
\}]) \}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, { let l:run_result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream, \ 'output_stream': l:output_stream,
\ 'executable': '', \ 'executable': '',
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
@ -179,70 +199,54 @@ function! s:RunJob(options) abort
\ 'log_output': 0, \ 'log_output': 0,
\}) \})
return !empty(l:result) if empty(l:run_result)
call s:RunFixer({
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_index': a:options.callback_index + 1,
\ 'callback_list': a:options.callback_list,
\})
endif
endfunction endfunction
function! s:RunFixer(options) abort function! s:RunFixer(options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:input = a:options.input let l:input = a:options.input
let l:index = a:options.callback_index let l:index = a:options.callback_index
if len(a:options.callback_list) <= l:index
call ale#fix#ApplyFixes(l:buffer, l:input)
return
endif
let l:ChainCallback = get(a:options, 'chain_callback', v:null) let l:ChainCallback = get(a:options, 'chain_callback', v:null)
" Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer')
while len(a:options.callback_list) > l:index
let l:Function = l:ChainCallback isnot v:null let l:Function = l:ChainCallback isnot v:null
\ ? ale#util#GetFunction(l:ChainCallback) \ ? ale#util#GetFunction(l:ChainCallback)
\ : a:options.callback_list[l:index] \ : a:options.callback_list[l:index]
" Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer')
if l:ChainCallback isnot v:null if l:ChainCallback isnot v:null
" Chained commands accept (buffer, output, [input]) " Chained commands accept (buffer, output, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 2 let l:result = ale#util#FunctionArgCount(l:Function) == 2
\ ? call(l:Function, [l:buffer, a:options.output]) \ ? call(l:Function, [l:buffer, a:options.output])
\ : call(l:Function, [l:buffer, a:options.output, copy(l:input)]) \ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
else else
" Chained commands accept (buffer, [input]) " Regular fixer commands accept (buffer, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 1 let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? call(l:Function, [l:buffer]) \ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)]) \ : call(l:Function, [l:buffer, copy(l:input)])
endif endif
if type(l:result) is v:t_number && l:result == 0 call s:RunJob(l:result, {
" When `0` is returned, skip this item.
let l:index += 1
elseif type(l:result) is v:t_list
let l:input = l:result
let l:index += 1
else
let l:ChainWith = get(l:result, 'chain_with', v:null)
" Default to piping the buffer for the last fixer in the chain.
let l:read_buffer = get(l:result, 'read_buffer', l:ChainWith is v:null)
let l:job_ran = s:RunJob({
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'command': l:result.command,
\ 'input': l:input, \ 'input': l:input,
\ 'output_stream': get(l:result, 'output_stream', 'stdout'),
\ 'read_temporary_file': get(l:result, 'read_temporary_file', 0),
\ 'read_buffer': l:read_buffer,
\ 'chain_with': l:ChainWith,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index, \ 'callback_index': l:index,
\ 'process_with': get(l:result, 'process_with', v:null),
\}) \})
if !l:job_ran
" The job failed to run, so skip to the next item.
let l:index += 1
else
" Stop here, we will handle exit later on.
return
endif
endif
endwhile
call ale#fix#ApplyFixes(l:buffer, l:input)
endfunction endfunction
function! s:AddSubCallbacks(full_list, callbacks) abort function! s:AddSubCallbacks(full_list, callbacks) abort

View File

@ -180,6 +180,7 @@ Before:
After: After:
Restore Restore
unlet! g:test_filename
unlet! g:ale_run_synchronously unlet! g:ale_run_synchronously
unlet! g:ale_set_lists_synchronously unlet! g:ale_set_lists_synchronously
unlet! g:ale_run_synchronously_callbacks unlet! g:ale_run_synchronously_callbacks
@ -224,8 +225,8 @@ After:
setlocal buftype=nofile setlocal buftype=nofile
if filereadable('fix_test_file') if exists('g:test_filename') && filereadable(g:test_filename)
call delete('fix_test_file') call delete(g:test_filename)
endif endif
call setloclist(0, []) call setloclist(0, [])
@ -479,8 +480,9 @@ Execute(ALEFix should fix files on the save event):
let g:ale_lint_on_save = 1 let g:ale_lint_on_save = 1
let g:ale_enabled = 1 let g:ale_enabled = 1
noautocmd silent file fix_test_file let g:test_filename = tempname()
call writefile(getline(1, '$'), 'fix_test_file') execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call writefile(getline(1, '$'), g:test_filename)
let g:ale_fixers.testft = ['AddDollars'] let g:ale_fixers.testft = ['AddDollars']
@ -492,8 +494,8 @@ Execute(ALEFix should fix files on the save event):
call ale#test#FlushJobs() call ale#test#FlushJobs()
" We should save the file. " We should save the file.
AssertEqual ['$a', '$b', '$c'], readfile('fix_test_file') AssertEqual ['$a', '$b', '$c'], readfile(g:test_filename)
Assert !&modified, 'The was marked as ''modified''' Assert !&modified, 'The file was marked as ''modified'''
if !has('win32') if !has('win32')
" We should have run the linter. " We should have run the linter.
@ -520,8 +522,9 @@ Execute(ALEFix should not fix files on :wq):
let g:ale_lint_on_save = 1 let g:ale_lint_on_save = 1
let g:ale_enabled = 1 let g:ale_enabled = 1
noautocmd silent file fix_test_file let g:test_filename = tempname()
call writefile(getline(1, '$'), 'fix_test_file') execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call writefile(getline(1, '$'), g:test_filename)
let g:ale_fixers.testft = ['AddDollars'] let g:ale_fixers.testft = ['AddDollars']
@ -534,7 +537,7 @@ Execute(ALEFix should not fix files on :wq):
call ale#events#SaveEvent(bufnr('')) call ale#events#SaveEvent(bufnr(''))
" We should save the file. " We should save the file.
AssertEqual ['a', 'b', 'c'], readfile('fix_test_file') AssertEqual ['a', 'b', 'c'], readfile(g:test_filename)
Assert &modified, 'The was not marked as ''modified''' Assert &modified, 'The was not marked as ''modified'''
" We should not run the linter. " We should not run the linter.
@ -555,7 +558,8 @@ Execute(ALEFix should still lint with no linters to be applied):
let g:ale_lint_on_save = 1 let g:ale_lint_on_save = 1
let g:ale_enabled = 1 let g:ale_enabled = 1
noautocmd silent file fix_test_file let g:test_filename = tempname()
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
let g:ale_fixers.testft = [] let g:ale_fixers.testft = []
@ -563,7 +567,7 @@ Execute(ALEFix should still lint with no linters to be applied):
call ale#events#SaveEvent(bufnr('')) call ale#events#SaveEvent(bufnr(''))
call ale#test#FlushJobs() call ale#test#FlushJobs()
Assert !filereadable('fix_test_file'), 'The file should not have been saved' Assert !filereadable(g:test_filename), 'The file should not have been saved'
if !has('win32') if !has('win32')
" We have run the linter. " We have run the linter.
@ -590,7 +594,8 @@ Execute(ALEFix should still lint when nothing was fixed on save):
let g:ale_lint_on_save = 1 let g:ale_lint_on_save = 1
let g:ale_enabled = 1 let g:ale_enabled = 1
noautocmd silent file fix_test_file let g:test_filename = tempname()
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
let g:ale_fixers.testft = ['DoNothing'] let g:ale_fixers.testft = ['DoNothing']
@ -598,7 +603,7 @@ Execute(ALEFix should still lint when nothing was fixed on save):
call ale#events#SaveEvent(bufnr('')) call ale#events#SaveEvent(bufnr(''))
call ale#test#FlushJobs() call ale#test#FlushJobs()
Assert !filereadable('fix_test_file'), 'The file should not have been saved' Assert !filereadable(g:test_filename), 'The file should not have been saved'
if !has('win32') if !has('win32')
" We should have run the linter. " We should have run the linter.
@ -626,7 +631,8 @@ Given testft (A file with three lines):
c c
Execute(ale#fix#InitBufferData() should set up the correct data): Execute(ale#fix#InitBufferData() should set up the correct data):
noautocmd silent file fix_test_file let g:test_filename = tempname()
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call ale#fix#InitBufferData(bufnr(''), 'save_file') call ale#fix#InitBufferData(bufnr(''), 'save_file')