Merge pull request #143 from w0rp/better-buffer-cleanup

Stop jobs when buffers close
This commit is contained in:
w0rp 2016-10-25 16:02:47 +01:00 committed by GitHub
commit 60762d5018
15 changed files with 289 additions and 152 deletions

View File

@ -27,8 +27,11 @@ 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)
" Initialise the buffer information if needed.
call ale#engine#InitBufferInfo(l:buffer)
" Set a variable telling us to clear the loclist later. " Set a variable telling us to clear the loclist later.
let g:ale_buffer_should_reset_map[l:buffer] = 1 let g:ale_buffer_info[l:buffer].should_reset = 1
for l:linter in l:linters for l:linter in l:linters
" Check if a given linter has a program which can be executed. " Check if a given linter has a program which can be executed.

View File

@ -2,19 +2,12 @@
" Description: Utility functions related to cleaning state. " Description: Utility functions related to cleaning state.
function! ale#cleanup#Buffer(buffer) abort function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_count_map, a:buffer) if has_key(g:ale_buffer_info, a:buffer)
call remove(g:ale_buffer_count_map, a:buffer) " When buffers are removed, clear all of the jobs.
endif for l:job in get(g:ale_buffer_info[a:buffer], 'job_list', [])
call ale#engine#ClearJob(l:job)
endfor
if has_key(g:ale_buffer_loclist_map, a:buffer) call remove(g:ale_buffer_info, a:buffer)
call remove(g:ale_buffer_loclist_map, a:buffer)
endif
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_sign_dummy_map, a:buffer)
call remove(g:ale_buffer_sign_dummy_map, a:buffer)
endif endif
endfunction endfunction

View File

@ -46,12 +46,12 @@ function! ale#cursor#EchoCursorWarning(...) abort
let l:buffer = bufnr('%') let l:buffer = bufnr('%')
if !has_key(g:ale_buffer_loclist_map, l:buffer) if !has_key(g:ale_buffer_info, l:buffer)
return return
endif endif
let l:pos = getcurpos() let l:pos = getcurpos()
let l:loclist = g:ale_buffer_loclist_map[l:buffer] let l:loclist = g:ale_buffer_info[l:buffer].loclist
let l:index = ale#util#BinarySearch(l:loclist, l:pos[1], l:pos[2]) let l:index = ale#util#BinarySearch(l:loclist, l:pos[1], l:pos[2])
if l:index >= 0 if l:index >= 0

View File

@ -20,7 +20,18 @@ function! s:GetJobID(job) abort
return ch_info(job_getchannel(a:job)).id return ch_info(job_getchannel(a:job)).id
endfunction endfunction
function! s:ClearJob(job) abort function! ale#engine#InitBufferInfo(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'should_reset': 1,
\ 'dummy_sign_set': 0,
\ 'loclist': [],
\}
endif
endfunction
function! ale#engine#ClearJob(job) abort
let l:job_id = s:GetJobID(a:job) let l:job_id = s:GetJobID(a:job)
let l:linter = s:job_info_map[l:job_id].linter let l:linter = s:job_info_map[l:job_id].linter
@ -37,7 +48,26 @@ function! s:ClearJob(job) abort
endif endif
call remove(s:job_info_map, l:job_id) call remove(s:job_info_map, l:job_id)
call remove(l:linter, 'job') endfunction
function! s:StopPreviousJobs(buffer, linter) abort
let l:new_job_list = []
for l:job in g:ale_buffer_info[a:buffer].job_list
let l:job_id = s:GetJobID(l:job)
if has_key(s:job_info_map, l:job_id)
\&& s:job_info_map[l:job_id].linter.name ==# a:linter.name
" Stop jobs which match the buffer and linter.
call ale#engine#ClearJob(l:job)
else
" Keep other jobs in the list.
call add(l:new_job_list, l:job)
endif
endfor
" Update the list, removing the previously run job.
let g:ale_buffer_info[a:buffer].job_list = l:new_job_list
endfunction endfunction
function! s:GatherOutput(job, data) abort function! s:GatherOutput(job, data) abort
@ -71,17 +101,13 @@ function! s:HandleExit(job) abort
endif endif
let l:job_info = s:job_info_map[l:job_id] let l:job_info = s:job_info_map[l:job_id]
call s:ClearJob(a:job)
let l:linter = l:job_info.linter let l:linter = l:job_info.linter
let l:output = l:job_info.output let l:output = l:job_info.output
let l:buffer = l:job_info.buffer let l:buffer = l:job_info.buffer
if !has_key(g:ale_buffer_should_reset_map, l:buffer) " Call the same function for stopping jobs again to clean up the job
" A job ended for a buffer which has been closed, so stop here. " which just closed.
return call s:StopPreviousJobs(l:buffer, l:linter)
endif
let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output) let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
@ -92,30 +118,32 @@ function! s:HandleExit(job) abort
let l:item.linter_name = l:linter.name let l:item.linter_name = l:linter.name
endfor endfor
if g:ale_buffer_should_reset_map[l:buffer] if g:ale_buffer_info[l:buffer].should_reset
let g:ale_buffer_should_reset_map[l:buffer] = 0 " Set the flag for resetting the loclist to 0 again, so we won't
let g:ale_buffer_loclist_map[l:buffer] = [] " empty the list later.
let g:ale_buffer_info[l:buffer].should_reset = 0
let g:ale_buffer_info[l:buffer].loclist = []
endif endif
" Add the loclist items from the linter. " Add the loclist items from the linter.
call extend(g:ale_buffer_loclist_map[l:buffer], l:linter_loclist) call extend(g:ale_buffer_info[l:buffer].loclist, l: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(g:ale_buffer_loclist_map[l:buffer], 'ale#util#LocItemCompare') call sort(g:ale_buffer_info[l:buffer].loclist, 'ale#util#LocItemCompare')
if g:ale_set_loclist if g:ale_set_loclist
call setloclist(0, g:ale_buffer_loclist_map[l:buffer]) call setloclist(0, g:ale_buffer_info[l:buffer].loclist)
endif endif
if g:ale_set_signs if g:ale_set_signs
call ale#sign#SetSigns(l:buffer, g:ale_buffer_loclist_map[l:buffer]) call ale#sign#SetSigns(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif endif
if exists('*ale#statusline#Update') if exists('*ale#statusline#Update')
" Don't load/run if not already loaded. " Don't load/run if not already loaded.
call ale#statusline#Update(l:buffer, g:ale_buffer_loclist_map[l:buffer]) call ale#statusline#Update(l:buffer, g:ale_buffer_info[l:buffer].loclist)
endif endif
" Call user autocommands. This allows users to hook into ALE's lint cycle. " Call user autocommands. This allows users to hook into ALE's lint cycle.
@ -150,10 +178,8 @@ function! s:FixLocList(buffer, loclist) abort
endfunction endfunction
function! ale#engine#Invoke(buffer, linter) abort function! ale#engine#Invoke(buffer, linter) abort
if has_key(a:linter, 'job') " Stop previous jobs for the same linter.
" Stop previous jobs for the same linter. call s:StopPreviousJobs(a:buffer, a:linter)
call s:ClearJob(a:linter.job)
endif
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.
@ -227,7 +253,8 @@ function! ale#engine#Invoke(buffer, linter) abort
" Only proceed if the job is being run. " Only proceed if the job is being run.
if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run') if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run')
let a:linter.job = l:job " Add the job to the list of jobs, so we can track them.
call add(g:ale_buffer_info[a:buffer].job_list, l:job)
" Store the ID for the job in the map to read back again. " Store the ID for the job in the map to read back again.
let s:job_info_map[s:GetJobID(l:job)] = { let s:job_info_map[s:GetJobID(l:job)] = {
@ -255,6 +282,15 @@ function! ale#engine#Invoke(buffer, linter) abort
endif endif
endfunction endfunction
" Given a buffer number, return the warnings and errors for a given buffer.
function! ale#engine#GetLoclist(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
return []
endif
return g:ale_buffer_info[a:buffer].loclist
endfunction
" This function can be called with a timeout to wait for all jobs to finish. " 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, " If the jobs to not finish in the given number of milliseconds,
" an exception will be thrown. " an exception will be thrown.
@ -270,8 +306,9 @@ function! ale#engine#WaitForJobs(deadline) abort
let l:job_list = [] let l:job_list = []
for l:job_id in keys(s:job_info_map) " Gather all of the jobs from every buffer.
call add(l:job_list, s:job_info_map[l:job_id].linter.job) for l:info in values(g:ale_buffer_info)
call extend(l:job_list, l:info.job_list)
endfor endfor
let l:should_wait_more = 1 let l:should_wait_more = 1

View File

@ -89,13 +89,13 @@ function! ale#sign#SetSigns(buffer, loclist) abort
let l:signlist = ale#sign#CombineSigns(a:loclist) let l:signlist = ale#sign#CombineSigns(a:loclist)
if len(l:signlist) > 0 || g:ale_sign_column_always if len(l:signlist) > 0 || g:ale_sign_column_always
if !get(g:ale_buffer_sign_dummy_map, a:buffer, 0) if !g:ale_buffer_info[a:buffer].dummy_sign_set
" Insert a dummy sign if one is missing. " Insert a dummy sign if one is missing.
execute 'sign place ' . g:ale_sign_offset execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign buffer=' \ . ' line=1 name=ALEDummySign buffer='
\ . a:buffer \ . a:buffer
let g:ale_buffer_sign_dummy_map[a:buffer] = 1 let g:ale_buffer_info[a:buffer].dummy_sign_set = 1
endif endif
endif endif
@ -121,10 +121,10 @@ function! ale#sign#SetSigns(buffer, loclist) abort
endfor endfor
if !g:ale_sign_column_always && len(l:signlist) > 0 if !g:ale_sign_column_always && len(l:signlist) > 0
if get(g:ale_buffer_sign_dummy_map, a:buffer, 0) if g:ale_buffer_info[a:buffer].dummy_sign_set
execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
let g:ale_buffer_sign_dummy_map[a:buffer] = 0 let g:ale_buffer_info[a:buffer].dummy_sign_set = 0
endif endif
endif endif
endfunction endfunction

View File

@ -14,34 +14,48 @@ function! ale#statusline#Update(buffer, loclist) abort
endif endif
endfor endfor
let g:ale_buffer_count_map[a:buffer] = [l:errors, l:warnings] let g:ale_buffer_info[a:buffer].count = [l:errors, l:warnings]
endfunction
" Set the error and warning counts, calling for an update only if needed.
" If counts cannot be set, return 0.
function! s:SetupCount(buffer) abort
if !has_key(g:ale_buffer_info, a:buffer)
" Linters have not been run for the buffer yet, so stop here.
return 0
endif
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_info[a:buffer], 'count')
call ale#statusline#Update(a:buffer, g:ale_buffer_info[a:buffer].loclist)
endif
return 1
endfunction endfunction
" Returns a tuple of errors and warnings for use in third-party integrations. " Returns a tuple of errors and warnings for use in third-party integrations.
function! ale#statusline#Count(buffer) abort function! ale#statusline#Count(buffer) abort
" Cache is cold, so manually ask for an update. if !s:SetupCount(a:buffer)
if !has_key(g:ale_buffer_count_map, a:buffer) return [0, 0]
call ale#statusline#Update(a:buffer, get(g:ale_buffer_loclist_map, a:buffer, []))
endif endif
return g:ale_buffer_count_map[a:buffer] return g:ale_buffer_info[a:buffer].count
endfunction endfunction
" Returns a formatted string that can be integrated in the statusline. " Returns a formatted string that can be integrated in the statusline.
function! ale#statusline#Status() abort function! ale#statusline#Status() abort
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
let l:buffer = bufnr('%') let l:buffer = bufnr('%')
" Cache is cold, so manually ask for an update. if !s:SetupCount(l:buffer)
if !has_key(g:ale_buffer_count_map, l:buffer) return l:no_errors
call ale#statusline#Update(l:buffer, get(g:ale_buffer_loclist_map, l:buffer, []))
endif endif
let [l:error_count, l:warning_count] = g:ale_buffer_info[l:buffer].count
" Build strings based on user formatting preferences. " Build strings based on user formatting preferences.
let l:errors = g:ale_buffer_count_map[l:buffer][0] ? let l:errors = l:error_count ? printf(l:error_format, l:error_count) : ''
\ printf(g:ale_statusline_format[0], g:ale_buffer_count_map[l:buffer][0]) : '' let l:warnings = l:warning_count ? printf(l:warning_format, l:warning_count) : ''
let l:warnings = g:ale_buffer_count_map[l:buffer][1] ?
\ printf(g:ale_statusline_format[1], g:ale_buffer_count_map[l:buffer][1]) : ''
let l:no_errors = g:ale_statusline_format[2]
" Different formats based on the combination of errors and warnings. " Different formats based on the combination of errors and warnings.
if empty(l:errors) && empty(l:warnings) if empty(l:errors) && empty(l:warnings)

View File

@ -147,23 +147,6 @@ g:ale_linter_aliases *g:ale_linter_aliases*
different set of linters from the type it is being mapped to. different set of linters from the type it is being mapped to.
g:ale_buffer_loclist_map *g:ale_buffer_loclist_map*
Type: |Dictionary|
Default: `{}`
This variable is used internally by ALE for tracking the warnings and
errors for a particular buffer. The dictionary maps a buffer number to
a |List| of |Dictionary| items in the format accepted by |setqflist()|,
with a minor addition of a `linter_name` for each object which describes
the linter which reported the warnings and errors. (A buffer may run
multiple linters in combination on the same filetype.)
NOTE: This variable should not be modified outside of the plugin itself,
but can be read in other plugins whenever information about the current
errors and warnings ALE is reporting is needed.
g:ale_lint_on_text_changed *g:ale_lint_on_text_changed* g:ale_lint_on_text_changed *g:ale_lint_on_text_changed*
Type: |Number| Type: |Number|
@ -575,6 +558,13 @@ ale#Queue(delay) *ale#Queue()*
again from the same buffer again from the same buffer
ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()*
Given a buffer number, this function will rerurn the list of warnings and
errors reported by ALE for a given buffer in the format accepted by
|setqflist()|.
ale#linter#Define(filetype, linter) *ale#linter#Define()* ale#linter#Define(filetype, linter) *ale#linter#Define()*
Given a |String| for a filetype and a |Dictionary| Describing a linter Given a |String| for a filetype and a |Dictionary| Describing a linter
configuration, add a linter for the given filetype. The dictionaries each configuration, add a linter for the given filetype. The dictionaries each

View File

@ -7,6 +7,7 @@
if exists('g:loaded_ale') if exists('g:loaded_ale')
finish finish
endif endif
let g:loaded_ale = 1 let g:loaded_ale = 1
" A flag for detecting if the required features are set. " A flag for detecting if the required features are set.
@ -22,15 +23,25 @@ if !s:ale_has_required_features
finish finish
endif endif
" Globals " This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against.
let g:ale_buffer_count_map = {} let g:ale_buffer_info = {}
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
" User Configuration " User Configuration
" This option prevents ALE autocmd commands from being run for particular
" filetypes which can cause issues.
let g:ale_filetype_blacklist = ['nerdtree', 'unite']
" This function lets you define autocmd commands which blacklist particular
" filetypes.
function! ALEAutoCMD(events, function_call)
execute 'autocmd '
\ . a:events
\ ' * if index(g:ale_filetype_blacklist, &filetype) < 0 | call '
\ . a:function_call
endfunction
" This Dictionary configures which linters are enabled for which languages. " This Dictionary configures which linters are enabled for which languages.
let g:ale_linters = get(g:, 'ale_linters', {}) let g:ale_linters = get(g:, 'ale_linters', {})
@ -48,7 +59,7 @@ let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 1)
if g:ale_lint_on_text_changed if g:ale_lint_on_text_changed
augroup ALERunOnTextChangedGroup augroup ALERunOnTextChangedGroup
autocmd! autocmd!
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay) call ALEAutoCMD('TextChanged,TextChangedI', 'ale#Queue(g:ale_lint_delay)')
augroup END augroup END
endif endif
@ -57,7 +68,7 @@ let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', 1)
if g:ale_lint_on_enter if g:ale_lint_on_enter
augroup ALERunOnEnterGroup augroup ALERunOnEnterGroup
autocmd! autocmd!
autocmd BufEnter,BufRead * call ale#Queue(100) call ALEAutoCMD('BufEnter,BufRead', 'ale#Queue(100)')
augroup END augroup END
endif endif
@ -66,7 +77,7 @@ let g:ale_lint_on_save = get(g:, 'ale_lint_on_save', 0)
if g:ale_lint_on_save if g:ale_lint_on_save
augroup ALERunOnSaveGroup augroup ALERunOnSaveGroup
autocmd! autocmd!
autocmd BufWrite * call ale#Queue(0) call ALEAutoCMD('BufWrite', 'ale#Queue(0)')
augroup END augroup END
endif endif
@ -103,7 +114,7 @@ let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
if g:ale_echo_cursor if g:ale_echo_cursor
augroup ALECursorGroup augroup ALECursorGroup
autocmd! autocmd!
autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay() call ALEAutoCMD('CursorMoved,CursorHold', 'ale#cursor#EchoCursorWarningWithDelay()')
augroup END augroup END
endif endif
@ -125,7 +136,7 @@ let g:ale_warn_about_trailing_whitespace =
augroup ALECleanupGroup augroup ALECleanupGroup
autocmd! autocmd!
" Clean up buffers automatically when they are unloaded. " Clean up buffers automatically when they are unloaded.
autocmd BufUnload * call ale#cleanup#Buffer(expand('<abuf>')) call ALEAutoCMD('BufUnload', "ale#cleanup#Buffer(expand('<abuf>'))")
augroup END augroup END
" Backwards Compatibility " Backwards Compatibility

View File

@ -7,11 +7,14 @@ Before:
After: After:
augroup! VaderTest augroup! VaderTest
let g:ale_buffer_info = {}
Given vim (Some vimscript): Given vim (Some vimscript):
set nocompatible set nocompatible
Execute (Lint it): Execute (Lint it):
call ale#Lint() call ale#Lint()
call ale#engine#WaitForJobs(2000) call ale#engine#WaitForJobs(2000)
Then (Autocommands should have run): Then (Autocommands should have run):
AssertEqual g:success, 1 AssertEqual g:success, 1

View File

@ -1,32 +1,15 @@
Before: Before:
let g:buffer = bufnr('%') let g:buffer = bufnr('%')
let g:ale_buffer_count_map = {
\ g:buffer: [1, 1], let g:ale_buffer_info = {
\ 10347: [1, 1], \ g:buffer : {},
\} \ 10347: {},
let g:ale_buffer_loclist_map = {
\ g:buffer : [],
\ 10347: [],
\}
let g:ale_buffer_should_reset_map = {
\ g:buffer : 1,
\ 10347: 1,
\}
let g:ale_buffer_sign_dummy_map = {
\ g:buffer : 1,
\ 10347: 1,
\} \}
After: After:
unlet! g:buffer unlet! g:buffer
let g:ale_buffer_count_map = {} let g:ale_buffer_info = {}
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
Execute('ALE globals should be cleared when the buffer is closed.'): Execute('ALE globals should be cleared when the buffer is closed.'):
:q! :q!
AssertEqual {10347: [1, 1]}, g:ale_buffer_count_map AssertEqual {10347: {}}, g:ale_buffer_info
AssertEqual {10347: []}, g:ale_buffer_loclist_map
AssertEqual {10347: 1}, g:ale_buffer_should_reset_map
AssertEqual {10347: 1}, g:ale_buffer_sign_dummy_map

View File

@ -1,17 +1,18 @@
Before: Before:
let g:ale_buffer_loclist_map = { let g:ale_buffer_info = {
\ bufnr('%'): [ \ bufnr('%'): {
\ { \ 'loclist': [
\ 'lnum': 1, \ {
\ 'bufnr': bufnr('%'), \ 'lnum': 1,
\ 'vcol': 0, \ 'bufnr': bufnr('%'),
\ 'linter_name': 'eslint', \ 'vcol': 0,
\ 'nr': -1, \ 'linter_name': 'eslint',
\ 'type': 'E', \ 'nr': -1,
\ 'col': 10, \ 'type': 'E',
\ 'text': 'Missing semicolon. (semi)' \ 'col': 10,
\ }, \ 'text': 'Missing semicolon. (semi)'
\ { \ },
\ {
\ 'lnum': 2, \ 'lnum': 2,
\ 'bufnr': bufnr('%'), \ 'bufnr': bufnr('%'),
\ 'vcol': 0, \ 'vcol': 0,
@ -20,8 +21,8 @@ Before:
\ 'type': 'W', \ 'type': 'W',
\ 'col': 10, \ 'col': 10,
\ 'text': 'Infix operators must be spaced. (space-infix-ops)' \ 'text': 'Infix operators must be spaced. (space-infix-ops)'
\ }, \ },
\ { \ {
\ 'lnum': 2, \ 'lnum': 2,
\ 'bufnr': bufnr('%'), \ 'bufnr': bufnr('%'),
\ 'vcol': 0, \ 'vcol': 0,
@ -30,14 +31,15 @@ Before:
\ 'type': 'E', \ 'type': 'E',
\ 'col': 15, \ 'col': 15,
\ 'text': 'Missing radix parameter (radix)' \ 'text': 'Missing radix parameter (radix)'
\ } \ }
\ ], \ ],
\ },
\} \}
After: After:
unlet! g:output unlet! g:output
unlet! g:lines unlet! g:lines
let g:ale_buffer_loclist_map = {} let g:ale_buffer_info = {}
Given javascript(A Javscript file with warnings/errors): Given javascript(A Javscript file with warnings/errors):
var x = 3 var x = 3

View File

@ -0,0 +1,31 @@
Before:
let g:loclist = [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'linter_name': 'eslint',
\ 'nr': -1,
\ 'type': 'E',
\ 'col': 10,
\ 'text': 'Missing semicolon. (semi)'
\ },
\ {
\ 'lnum': 2,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'linter_name': 'eslint',
\ 'nr': -1,
\ 'type': 'W',
\ 'col': 10,
\ 'text': 'Infix operators must be spaced. (space-infix-ops)'
\ },
\]
let g:ale_buffer_info = {'1': {'loclist': g:loclist}}
After:
unlet g:loclist
let g:ale_buffer_info = {}
Execute(GetLoclist should return the loclist):
AssertEqual g:loclist, ale#engine#GetLoclist(1)

View File

@ -0,0 +1,39 @@
Given javascript (Some JavaScript with problems):
var y = 3+3;
var y = 3
Before:
sign unplace *
let g:actual_sign_list = []
let g:expected_sign_list = [
\ ['1', 'ALEWarningSign'],
\ ['2', 'ALEErrorSign'],
\]
function! g:CollectSigns()
redir => l:output
silent exec 'sign place'
redir END
for l:line in split(l:output, "\n")
let l:match = matchlist(l:line, 'line=\(\d\+\).*name=\(ALE[a-zA-Z]\+\)')
if len(l:match) > 0
call add(g:actual_sign_list, [l:match[1], l:match[2]])
endif
endfor
endfunction
After:
sign unplace *
let g:ale_buffer_info = {}
delfunction g:CollectSigns
unlet g:actual_sign_list
unlet g:expected_sign_list
Execute(The signs should be updated after linting is done):
call ale#Lint()
call ale#engine#WaitForJobs(2000)
call g:CollectSigns()
AssertEqual g:expected_sign_list, g:actual_sign_list

View File

@ -3,15 +3,35 @@ Given javascript (Some JavaScript with problems):
var y = 3 var y = 3
Before: Before:
let g:ale_buffer_loclist_map = {} let g:expected_data = [
let g:expected_data = {bufnr('%'): [{'lnum': 1, 'bufnr': bufnr('%'), 'vcol': 0, 'linter_name': 'eslint', 'nr': -1, 'type': 'W', 'col': 10, 'text': 'Infix operators must be spaced. [Warning/space-infix-ops]'}, {'lnum': 2, 'bufnr': bufnr('%'), 'vcol': 0, 'linter_name': 'eslint', 'nr': -1, 'type': 'E', 'col': 10, 'text': 'Missing semicolon. [Error/semi]'}]} \ {
\ 'lnum': 1,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'linter_name': 'eslint',
\ 'nr': -1,
\ 'type': 'W',
\ 'col': 10,
\ 'text': 'Infix operators must be spaced. [Warning/space-infix-ops]',
\ },
\ {
\ 'lnum': 2,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'linter_name': 'eslint',
\ 'nr': -1,
\ 'type': 'E',
\ 'col': 10,
\ 'text': 'Missing semicolon. [Error/semi]',
\ }
\]
After: After:
let g:ale_buffer_loclist_map = {}
unlet g:expected_data unlet g:expected_data
Execute(The loclist should be updated after linting is done): Execute(The loclist should be updated after linting is done):
call ale#Lint() call ale#Lint()
call ale#engine#WaitForJobs(2000) call ale#engine#WaitForJobs(2000)
AssertEqual g:expected_data, g:ale_buffer_loclist_map AssertEqual ['' . bufnr('%')], keys(g:ale_buffer_info)
AssertEqual g:expected_data, g:ale_buffer_info[bufnr('%')].loclist

View File

@ -1,49 +1,60 @@
Before: Before:
let g:ale_buffer_loclist_map = {} let g:ale_statusline_format = ['%sE', '%sW', 'OKIE']
After:
let g:ale_buffer_info = {}
Execute (Count should be 0 when data is empty): Execute (Count should be 0 when data is empty):
let g:ale_buffer_info = {}
AssertEqual [0, 0], ale#statusline#Count(bufnr('%')) AssertEqual [0, 0], ale#statusline#Count(bufnr('%'))
Before:
let g:ale_buffer_count_map = {'44': [1, 2]}
Execute (Count should read data from the cache): Execute (Count should read data from the cache):
let g:ale_buffer_info = {'44': {'count': [1, 2]}}
AssertEqual [1, 2], ale#statusline#Count(44) AssertEqual [1, 2], ale#statusline#Count(44)
Execute (Update the cache with new data): Execute (The count should be correct after an update):
let g:ale_buffer_info = {'44': {}}
call ale#statusline#Update(44, []) call ale#statusline#Update(44, [])
Then (The cache should reflect the new data):
AssertEqual [0, 0], ale#statusline#Count(44) AssertEqual [0, 0], ale#statusline#Count(44)
Before:
let g:ale_buffer_loclist_map = {'1': [{'lnum': 1, 'bufnr': 1, 'vcol': 0, 'linter_name': 'testlinter', 'nr': -1, 'type': 'E', 'col': 1, 'text': 'Test Error'}]}
Execute (Count should be match the loclist): Execute (Count should be match the loclist):
AssertEqual [1, 0], ale#statusline#Count(1) let g:ale_buffer_info = {
\ bufnr('%'): {
\ 'loclist': [
\ {
\ 'lnum': 1,
\ 'bufnr': 1,
\ 'vcol': 0,
\ 'linter_name': 'testlinter',
\ 'nr': -1,
\ 'type': 'E',
\ 'col': 1,
\ 'text': 'Test Error',
\ },
\ ],
\ },
\}
AssertEqual [1, 0], ale#statusline#Count(bufnr('%'))
Execute (Output should be empty for non-existant buffer): Execute (Output should be empty for non-existant buffer):
AssertEqual [0, 0], ale#statusline#Count(9001) AssertEqual [0, 0], ale#statusline#Count(9001)
Before: Execute (Statusline is formatted to the users preference for just errors):
let g:ale_statusline_format = ['%sE', '%sW', 'OKIE'] let g:ale_buffer_info = {bufnr('%'): {}}
Execute (Given some errors):
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}]) call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}])
Then (Statusline is formatted to the users preference):
AssertEqual '2E', ale#statusline#Status() AssertEqual '2E', ale#statusline#Status()
Execute (Given some warnings): Execute (Statusline is formatted to the users preference for just warnings):
let g:ale_buffer_info = {bufnr('%'): {}}
call ale#statusline#Update(bufnr('%'), [{'type': 'W'}, {'type': 'W'}, {'type': 'W'}]) call ale#statusline#Update(bufnr('%'), [{'type': 'W'}, {'type': 'W'}, {'type': 'W'}])
Then (Statusline is formatted to the users preference):
AssertEqual '3W', ale#statusline#Status() AssertEqual '3W', ale#statusline#Status()
Execute (Given some warnings, and errors): Execute (Statusline is formatted to the users preference for errors and warnings):
let g:ale_buffer_info = {bufnr('%'): {}}
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'W'}, {'type': 'W'}]) call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'W'}, {'type': 'W'}])
Then (Statusline is formatted to the users preference):
AssertEqual '1E 2W', ale#statusline#Status() AssertEqual '1E 2W', ale#statusline#Status()
Execute (Given a lack of data): Execute (Statusline is formatted to the users preference for no errors or warnings):
let g:ale_buffer_info = {bufnr('%'): {}}
call ale#statusline#Update(bufnr('%'), []) call ale#statusline#Update(bufnr('%'), [])
Then (Statusline is formatted to the users preference):
AssertEqual 'OKIE', ale#statusline#Status() AssertEqual 'OKIE', ale#statusline#Status()