Fix issues with switching buffers rapidly causing errors by remembering the buffer and passing the buffer value to various functions.

This commit is contained in:
w0rp 2016-09-14 11:47:52 +01:00
parent 746ffe8acd
commit 7fa437985f
5 changed files with 73 additions and 41 deletions

View File

@ -4,7 +4,7 @@ endif
let g:loaded_ale_linters_javascript_eslint = 1 let g:loaded_ale_linters_javascript_eslint = 1
function! ale_linters#javascript#eslint#Handle(lines) function! ale_linters#javascript#eslint#Handle(buffer, lines)
" Matches patterns line the following: " Matches patterns line the following:
" "
" <text>:47:14: Missing trailing comma. [Warning/comma-dangle] " <text>:47:14: Missing trailing comma. [Warning/comma-dangle]
@ -29,7 +29,7 @@ function! ale_linters#javascript#eslint#Handle(lines)
" vcol is Needed to indicate that the column is a character. " vcol is Needed to indicate that the column is a character.
call add(output, { call add(output, {
\ 'bufnr': bufnr('%'), \ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'vcol': 0, \ 'vcol': 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,

View File

@ -4,7 +4,7 @@ endif
let g:loaded_ale_linters_python_flake8 = 1 let g:loaded_ale_linters_python_flake8 = 1
function! ale_linters#python#flake8#Handle(lines) function! ale_linters#python#flake8#Handle(buffer, lines)
" Matches patterns line the following: " Matches patterns line the following:
" "
" stdin:6:6: E111 indentation is not a multiple of four " stdin:6:6: E111 indentation is not a multiple of four
@ -26,7 +26,7 @@ function! ale_linters#python#flake8#Handle(lines)
" vcol is Needed to indicate that the column is a character. " vcol is Needed to indicate that the column is a character.
call add(output, { call add(output, {
\ 'bufnr': bufnr('%'), \ 'bufnr': a:buffer,
\ 'lnum': line, \ 'lnum': line,
\ 'vcol': 0, \ 'vcol': 0,
\ 'col': column, \ 'col': column,

View File

@ -53,16 +53,20 @@ function! ale#cursor#TruncatedEcho(message)
endfunction endfunction
function! ale#cursor#EchoCursorWarning() function! ale#cursor#EchoCursorWarning()
if !exists('b:ale_loclist') let buffer = bufnr('%')
if !has_key(g:ale_buffer_loclist_map, buffer)
return return
endif endif
let loclist = g:ale_buffer_loclist_map[buffer]
let pos = getcurpos() let pos = getcurpos()
let index = s:BinarySearch(b:ale_loclist, pos[1], pos[2]) let index = s:BinarySearch(loclist, pos[1], pos[2])
if index >= 0 if index >= 0
call ale#cursor#TruncatedEcho(b:ale_loclist[index]['text']) call ale#cursor#TruncatedEcho(loclist[index]['text'])
else else
echo echo
endif endif

View File

@ -25,10 +25,8 @@ sign define ALEErrorSign text=>> texthl=ALEErrorSign
sign define ALEWarningSign text=-- texthl=ALEWarningSign sign define ALEWarningSign text=-- texthl=ALEWarningSign
" This function will set the signs which show up on the left. " This function will set the signs which show up on the left.
function! ale#sign#SetSigns(loclist) function! ale#sign#SetSigns(buffer, loclist)
let buffer = bufnr('%') exec 'sign unplace * buffer=' . a:buffer
exec 'sign unplace * buffer=' . buffer
let signlist = [] let signlist = []
@ -59,7 +57,7 @@ function! ale#sign#SetSigns(loclist)
let sign_line = 'sign place ' . (i + 1) let sign_line = 'sign place ' . (i + 1)
\. ' line=' . obj['lnum'] \. ' line=' . obj['lnum']
\. ' name=' . name \. ' name=' . name
\. ' buffer=' . buffer \. ' buffer=' . a:buffer
exec sign_line exec sign_line
endfor endfor

View File

@ -1,7 +1,3 @@
" Always set buffer variables for each buffer
let b:ale_should_reset_loclist = 0
let b:ale_loclist = []
if exists('g:loaded_ale_zmain') if exists('g:loaded_ale_zmain')
finish finish
endif endif
@ -10,9 +6,22 @@ let g:loaded_ale_zmain = 1
let s:lint_timer = -1 let s:lint_timer = -1
let s:linters = {} let s:linters = {}
" Stores information for each job including:
"
" linter: The linter dictionary for the job.
" buffer: The buffer number for the job.
" output: The array of lines for the ouptut of the job.
let s:job_info_map = {}
let s:job_linter_map = {} let s:job_linter_map = {}
let s:job_buffer_map = {}
let s:job_output_map = {} let s:job_output_map = {}
" Globals which each part of the plugin should use.
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
function! s:GetFunction(string_or_ref) function! s:GetFunction(string_or_ref)
if type(a:string_or_ref) == type('') if type(a:string_or_ref) == type('')
return function(a:string_or_ref) return function(a:string_or_ref)
@ -22,7 +31,7 @@ function! s:GetFunction(string_or_ref)
endfunction endfunction
function! s:ClearJob(job) function! s:ClearJob(job)
let linter = s:job_linter_map[a:job] let linter = s:job_info_map[a:job].linter
if has('nvim') if has('nvim')
call jobstop(a:job) call jobstop(a:job)
@ -30,17 +39,16 @@ function! s:ClearJob(job)
call job_stop(a:job) call job_stop(a:job)
endif endif
call remove(s:job_output_map, a:job) call remove(s:job_info_map, a:job)
call remove(s:job_linter_map, a:job)
call remove(linter, 'job') call remove(linter, 'job')
endfunction endfunction
function! s:GatherOutput(job, data) function! s:GatherOutput(job, data)
if !has_key(s:job_output_map, a:job) if !has_key(s:job_info_map, a:job)
return return
endif endif
call extend(s:job_output_map[a:job], a:data) call extend(s:job_info_map[a:job].output, a:data)
endfunction endfunction
function! s:GatherOutputNeoVim(job, data, event) function! s:GatherOutputNeoVim(job, data, event)
@ -72,36 +80,39 @@ function! s:LocItemCompare(left, right)
endfunction endfunction
function! s:HandleExit(job) function! s:HandleExit(job)
if !has_key(s:job_linter_map, a:job) if !has_key(s:job_info_map, a:job)
return return
endif endif
let linter = s:job_linter_map[a:job] let job_info = s:job_info_map[a:job]
let output = s:job_output_map[a:job]
call s:ClearJob(a:job) call s:ClearJob(a:job)
let linter_loclist = s:GetFunction(linter.callback)(output) let linter = job_info.linter
let output = job_info.output
let buffer = job_info.buffer
if b:ale_should_reset_loclist let linter_loclist = s:GetFunction(linter.callback)(buffer, output)
let b:ale_should_reset_loclist = 0
let b:ale_loclist = [] if g:ale_buffer_should_reset_map[buffer]
let g:ale_buffer_should_reset_map[buffer] = 0
let g:ale_buffer_loclist_map[buffer] = []
endif endif
" Add the loclist items from the linter. " Add the loclist items from the linter.
call extend(b:ale_loclist, linter_loclist) call extend(g:ale_buffer_loclist_map[buffer], linter_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(b:ale_loclist, 's:LocItemCompare') call sort(g:ale_buffer_loclist_map[buffer], 's:LocItemCompare')
if g:ale_set_loclist if g:ale_set_loclist
call setloclist(0, b:ale_loclist) call setloclist(0, g:ale_buffer_loclist_map[buffer])
endif endif
if g:ale_set_signs if g:ale_set_signs
call ale#sign#SetSigns(b:ale_loclist) call ale#sign#SetSigns(buffer, g:ale_buffer_loclist_map[buffer])
endif endif
" Mark line 200, column 17 with a squiggly line or something " Mark line 200, column 17 with a squiggly line or something
@ -116,17 +127,15 @@ function! s:HandleExitVim(channel)
call s:HandleExit(ch_getjob(a:channel)) call s:HandleExit(ch_getjob(a:channel))
endfunction endfunction
function! s:ApplyLinter(linter) function! s:ApplyLinter(buffer, linter)
if has_key(a:linter, 'job') if has_key(a:linter, 'job')
" Stop previous jobs for the same linter. " Stop previous jobs for the same linter.
call s:ClearJob(a:linter.job) call s:ClearJob(a:linter.job)
endif endif
let buffer = bufnr('%')
if has_key(a:linter, 'command_callback') if has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead. " If there is a callback for generating a command, call that instead.
let command = s:GetFunction(a:linter.command_callback)(buffer) let command = s:GetFunction(a:linter.command_callback)(a:buffer)
else else
let command = a:linter.command let command = a:linter.command
endif endif
@ -144,14 +153,17 @@ function! s:ApplyLinter(linter)
\ 'out_cb': function('s:GatherOutputVim'), \ 'out_cb': function('s:GatherOutputVim'),
\ 'close_cb': function('s:HandleExitVim'), \ 'close_cb': function('s:HandleExitVim'),
\ 'in_io': 'buffer', \ 'in_io': 'buffer',
\ 'in_buf': buffer, \ 'in_buf': a:buffer,
\}) \})
call ch_close_in(job_getchannel(a:linter.job)) call ch_close_in(job_getchannel(a:linter.job))
endif endif
let s:job_linter_map[a:linter.job] = a:linter let s:job_info_map[a:linter.job] = {
let s:job_output_map[a:linter.job] = [] \ 'linter': a:linter,
\ 'buffer': a:buffer,
\ 'output': [],
\}
if has('nvim') if has('nvim')
" For NeoVim, we have to send the text in the buffer to the command. " For NeoVim, we have to send the text in the buffer to the command.
@ -164,14 +176,26 @@ function! s:TimerHandler(...)
let filetype = &filetype let filetype = &filetype
let linters = ALEGetLinters(filetype) let linters = ALEGetLinters(filetype)
let buffer = bufnr('%')
" Set a variable telling us to clear the loclist later. " Set a variable telling us to clear the loclist later.
let b:ale_should_reset_loclist = 1 let g:ale_buffer_should_reset_map[buffer] = 1
for linter in linters for linter in linters
call s:ApplyLinter(linter) call s:ApplyLinter(buffer, linter)
endfor endfor
endfunction endfunction
function s:BufferCleanup(buffer)
if has_key(g:ale_buffer_should_reset_map, a:buffer)
call remove(g:ale_buffer_should_reset_map, a:buffer)
endif
if has_key(g:ale_buffer_loclist_map, a:buffer)
call remove(g:ale_buffer_loclist_map, a:buffer)
endif
endfunction
function! ALEAddLinter(filetype, linter) function! ALEAddLinter(filetype, linter)
" Check if the linter program is executable before adding it. " Check if the linter program is executable before adding it.
if !executable(a:linter.executable) if !executable(a:linter.executable)
@ -244,3 +268,9 @@ if g:ale_lint_on_enter
autocmd BufEnter * call ALELint(0) autocmd BufEnter * call ALELint(0)
augroup END augroup END
endif endif
" Clean up buffers automatically when they are unloaded.
augroup ALEBuffferCleanup
autocmd!
autocmd BufUnload * call s:BufferCleanup('<abuf>')
augroup END