diff --git a/ale_linters/javascript/eslint.vim b/ale_linters/javascript/eslint.vim index 8eafd8a..96dfef9 100644 --- a/ale_linters/javascript/eslint.vim +++ b/ale_linters/javascript/eslint.vim @@ -4,7 +4,7 @@ endif 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: " " :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. call add(output, { - \ 'bufnr': bufnr('%'), + \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'vcol': 0, \ 'col': l:match[2] + 0, diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim index 4850f8e..8f33f9e 100644 --- a/ale_linters/python/flake8.vim +++ b/ale_linters/python/flake8.vim @@ -4,7 +4,7 @@ endif 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: " " 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. call add(output, { - \ 'bufnr': bufnr('%'), + \ 'bufnr': a:buffer, \ 'lnum': line, \ 'vcol': 0, \ 'col': column, diff --git a/plugin/ale/cursor.vim b/plugin/ale/cursor.vim index 9987266..aa8ae7a 100644 --- a/plugin/ale/cursor.vim +++ b/plugin/ale/cursor.vim @@ -53,16 +53,20 @@ function! ale#cursor#TruncatedEcho(message) endfunction function! ale#cursor#EchoCursorWarning() - if !exists('b:ale_loclist') + let buffer = bufnr('%') + + if !has_key(g:ale_buffer_loclist_map, buffer) return endif + let loclist = g:ale_buffer_loclist_map[buffer] + 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 - call ale#cursor#TruncatedEcho(b:ale_loclist[index]['text']) + call ale#cursor#TruncatedEcho(loclist[index]['text']) else echo endif diff --git a/plugin/ale/sign.vim b/plugin/ale/sign.vim index 4797e52..999e3a6 100644 --- a/plugin/ale/sign.vim +++ b/plugin/ale/sign.vim @@ -25,10 +25,8 @@ sign define ALEErrorSign text=>> texthl=ALEErrorSign sign define ALEWarningSign text=-- texthl=ALEWarningSign " This function will set the signs which show up on the left. -function! ale#sign#SetSigns(loclist) - let buffer = bufnr('%') - - exec 'sign unplace * buffer=' . buffer +function! ale#sign#SetSigns(buffer, loclist) + exec 'sign unplace * buffer=' . a:buffer let signlist = [] @@ -59,7 +57,7 @@ function! ale#sign#SetSigns(loclist) let sign_line = 'sign place ' . (i + 1) \. ' line=' . obj['lnum'] \. ' name=' . name - \. ' buffer=' . buffer + \. ' buffer=' . a:buffer exec sign_line endfor diff --git a/plugin/ale/zmain.vim b/plugin/ale/zmain.vim index 7a8ceb1..548ae29 100644 --- a/plugin/ale/zmain.vim +++ b/plugin/ale/zmain.vim @@ -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') finish endif @@ -10,9 +6,22 @@ let g:loaded_ale_zmain = 1 let s:lint_timer = -1 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_buffer_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) if type(a:string_or_ref) == type('') return function(a:string_or_ref) @@ -22,7 +31,7 @@ function! s:GetFunction(string_or_ref) endfunction function! s:ClearJob(job) - let linter = s:job_linter_map[a:job] + let linter = s:job_info_map[a:job].linter if has('nvim') call jobstop(a:job) @@ -30,17 +39,16 @@ function! s:ClearJob(job) call job_stop(a:job) endif - call remove(s:job_output_map, a:job) - call remove(s:job_linter_map, a:job) + call remove(s:job_info_map, a:job) call remove(linter, 'job') endfunction function! s:GatherOutput(job, data) - if !has_key(s:job_output_map, a:job) + if !has_key(s:job_info_map, a:job) return endif - call extend(s:job_output_map[a:job], a:data) + call extend(s:job_info_map[a:job].output, a:data) endfunction function! s:GatherOutputNeoVim(job, data, event) @@ -72,36 +80,39 @@ function! s:LocItemCompare(left, right) endfunction function! s:HandleExit(job) - if !has_key(s:job_linter_map, a:job) + if !has_key(s:job_info_map, a:job) return endif - let linter = s:job_linter_map[a:job] - let output = s:job_output_map[a:job] + let job_info = s:job_info_map[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 b:ale_should_reset_loclist = 0 - let b:ale_loclist = [] + let linter_loclist = s:GetFunction(linter.callback)(buffer, output) + + 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 " 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. " We need a sorted list so we can run a binary search against it " 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 - call setloclist(0, b:ale_loclist) + call setloclist(0, g:ale_buffer_loclist_map[buffer]) endif if g:ale_set_signs - call ale#sign#SetSigns(b:ale_loclist) + call ale#sign#SetSigns(buffer, g:ale_buffer_loclist_map[buffer]) endif " 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)) endfunction -function! s:ApplyLinter(linter) +function! s:ApplyLinter(buffer, linter) if has_key(a:linter, 'job') " Stop previous jobs for the same linter. call s:ClearJob(a:linter.job) endif - let buffer = bufnr('%') - if has_key(a:linter, 'command_callback') " 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 let command = a:linter.command endif @@ -144,14 +153,17 @@ function! s:ApplyLinter(linter) \ 'out_cb': function('s:GatherOutputVim'), \ 'close_cb': function('s:HandleExitVim'), \ 'in_io': 'buffer', - \ 'in_buf': buffer, + \ 'in_buf': a:buffer, \}) call ch_close_in(job_getchannel(a:linter.job)) endif - let s:job_linter_map[a:linter.job] = a:linter - let s:job_output_map[a:linter.job] = [] + let s:job_info_map[a:linter.job] = { + \ 'linter': a:linter, + \ 'buffer': a:buffer, + \ 'output': [], + \} if has('nvim') " 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 linters = ALEGetLinters(filetype) + let buffer = bufnr('%') + " 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 - call s:ApplyLinter(linter) + call s:ApplyLinter(buffer, linter) endfor 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) " Check if the linter program is executable before adding it. if !executable(a:linter.executable) @@ -244,3 +268,9 @@ if g:ale_lint_on_enter autocmd BufEnter * call ALELint(0) augroup END endif + +" Clean up buffers automatically when they are unloaded. +augroup ALEBuffferCleanup + autocmd! + autocmd BufUnload * call s:BufferCleanup('') +augroup END