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: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.
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
" 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.
function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_count_map, a:buffer)
call remove(g:ale_buffer_count_map, a:buffer)
endif
if has_key(g:ale_buffer_info, a:buffer)
" When buffers are removed, clear all of the jobs.
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_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)
call remove(g:ale_buffer_info, a:buffer)
endif
endfunction

View File

@ -46,12 +46,12 @@ function! ale#cursor#EchoCursorWarning(...) abort
let l:buffer = bufnr('%')
if !has_key(g:ale_buffer_loclist_map, l:buffer)
if !has_key(g:ale_buffer_info, l:buffer)
return
endif
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])
if l:index >= 0

View File

@ -20,7 +20,18 @@ function! s:GetJobID(job) abort
return ch_info(job_getchannel(a:job)).id
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:linter = s:job_info_map[l:job_id].linter
@ -37,7 +48,26 @@ function! s:ClearJob(job) abort
endif
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
function! s:GatherOutput(job, data) abort
@ -71,17 +101,13 @@ function! s:HandleExit(job) abort
endif
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:output = l:job_info.output
let l:buffer = l:job_info.buffer
if !has_key(g:ale_buffer_should_reset_map, l:buffer)
" A job ended for a buffer which has been closed, so stop here.
return
endif
" Call the same function for stopping jobs again to clean up the job
" which just closed.
call s:StopPreviousJobs(l:buffer, l:linter)
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
endfor
if g:ale_buffer_should_reset_map[l:buffer]
let g:ale_buffer_should_reset_map[l:buffer] = 0
let g:ale_buffer_loclist_map[l:buffer] = []
if g:ale_buffer_info[l:buffer].should_reset
" Set the flag for resetting the loclist to 0 again, so we won't
" empty the list later.
let g:ale_buffer_info[l:buffer].should_reset = 0
let g:ale_buffer_info[l:buffer].loclist = []
endif
" 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.
" 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(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
call setloclist(0, g:ale_buffer_loclist_map[l:buffer])
call setloclist(0, g:ale_buffer_info[l:buffer].loclist)
endif
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
if exists('*ale#statusline#Update')
" 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
" Call user autocommands. This allows users to hook into ALE's lint cycle.
@ -150,10 +178,8 @@ function! s:FixLocList(buffer, loclist) abort
endfunction
function! ale#engine#Invoke(buffer, linter) abort
if has_key(a:linter, 'job')
" Stop previous jobs for the same linter.
call s:ClearJob(a:linter.job)
endif
" Stop previous jobs for the same linter.
call s:StopPreviousJobs(a:buffer, a:linter)
if has_key(a:linter, 'command_callback')
" 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.
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.
let s:job_info_map[s:GetJobID(l:job)] = {
@ -255,6 +282,15 @@ function! ale#engine#Invoke(buffer, linter) abort
endif
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.
" If the jobs to not finish in the given number of milliseconds,
" an exception will be thrown.
@ -270,8 +306,9 @@ function! ale#engine#WaitForJobs(deadline) abort
let l:job_list = []
for l:job_id in keys(s:job_info_map)
call add(l:job_list, s:job_info_map[l:job_id].linter.job)
" Gather all of the jobs from every buffer.
for l:info in values(g:ale_buffer_info)
call extend(l:job_list, l:info.job_list)
endfor
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)
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.
execute 'sign place ' . g:ale_sign_offset
\ . ' line=1 name=ALEDummySign 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
@ -121,10 +121,10 @@ function! ale#sign#SetSigns(buffer, loclist) abort
endfor
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
let g:ale_buffer_sign_dummy_map[a:buffer] = 0
let g:ale_buffer_info[a:buffer].dummy_sign_set = 0
endif
endif
endfunction

View File

@ -14,34 +14,48 @@ function! ale#statusline#Update(buffer, loclist) abort
endif
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
" Returns a tuple of errors and warnings for use in third-party integrations.
function! ale#statusline#Count(buffer) abort
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_count_map, a:buffer)
call ale#statusline#Update(a:buffer, get(g:ale_buffer_loclist_map, a:buffer, []))
if !s:SetupCount(a:buffer)
return [0, 0]
endif
return g:ale_buffer_count_map[a:buffer]
return g:ale_buffer_info[a:buffer].count
endfunction
" Returns a formatted string that can be integrated in the statusline.
function! ale#statusline#Status() abort
let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format
let l:buffer = bufnr('%')
" Cache is cold, so manually ask for an update.
if !has_key(g:ale_buffer_count_map, l:buffer)
call ale#statusline#Update(l:buffer, get(g:ale_buffer_loclist_map, l:buffer, []))
if !s:SetupCount(l:buffer)
return l:no_errors
endif
let [l:error_count, l:warning_count] = g:ale_buffer_info[l:buffer].count
" Build strings based on user formatting preferences.
let l:errors = g:ale_buffer_count_map[l:buffer][0] ?
\ printf(g:ale_statusline_format[0], g:ale_buffer_count_map[l:buffer][0]) : ''
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]
let l:errors = l:error_count ? printf(l:error_format, l:error_count) : ''
let l:warnings = l:warning_count ? printf(l:warning_format, l:warning_count) : ''
" Different formats based on the combination of errors and 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.
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*
Type: |Number|
@ -575,6 +558,13 @@ ale#Queue(delay) *ale#Queue()*
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()*
Given a |String| for a filetype and a |Dictionary| Describing a linter
configuration, add a linter for the given filetype. The dictionaries each

View File

@ -7,6 +7,7 @@
if exists('g:loaded_ale')
finish
endif
let g:loaded_ale = 1
" A flag for detecting if the required features are set.
@ -22,15 +23,25 @@ if !s:ale_has_required_features
finish
endif
" Globals
let g:ale_buffer_count_map = {}
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
" This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against.
let g:ale_buffer_info = {}
" 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.
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
augroup ALERunOnTextChangedGroup
autocmd!
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
call ALEAutoCMD('TextChanged,TextChangedI', 'ale#Queue(g:ale_lint_delay)')
augroup END
endif
@ -57,7 +68,7 @@ let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', 1)
if g:ale_lint_on_enter
augroup ALERunOnEnterGroup
autocmd!
autocmd BufEnter,BufRead * call ale#Queue(100)
call ALEAutoCMD('BufEnter,BufRead', 'ale#Queue(100)')
augroup END
endif
@ -66,7 +77,7 @@ let g:ale_lint_on_save = get(g:, 'ale_lint_on_save', 0)
if g:ale_lint_on_save
augroup ALERunOnSaveGroup
autocmd!
autocmd BufWrite * call ale#Queue(0)
call ALEAutoCMD('BufWrite', 'ale#Queue(0)')
augroup END
endif
@ -103,7 +114,7 @@ let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
if g:ale_echo_cursor
augroup ALECursorGroup
autocmd!
autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay()
call ALEAutoCMD('CursorMoved,CursorHold', 'ale#cursor#EchoCursorWarningWithDelay()')
augroup END
endif
@ -125,7 +136,7 @@ let g:ale_warn_about_trailing_whitespace =
augroup ALECleanupGroup
autocmd!
" 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
" Backwards Compatibility

View File

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

View File

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

View File

@ -1,17 +1,18 @@
Before:
let g:ale_buffer_loclist_map = {
\ bufnr('%'): [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
\ 'linter_name': 'eslint',
\ 'nr': -1,
\ 'type': 'E',
\ 'col': 10,
\ 'text': 'Missing semicolon. (semi)'
\ },
\ {
let g:ale_buffer_info = {
\ bufnr('%'): {
\ '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,
@ -20,8 +21,8 @@ Before:
\ 'type': 'W',
\ 'col': 10,
\ 'text': 'Infix operators must be spaced. (space-infix-ops)'
\ },
\ {
\ },
\ {
\ 'lnum': 2,
\ 'bufnr': bufnr('%'),
\ 'vcol': 0,
@ -30,14 +31,15 @@ Before:
\ 'type': 'E',
\ 'col': 15,
\ 'text': 'Missing radix parameter (radix)'
\ }
\ ],
\ }
\ ],
\ },
\}
After:
unlet! g:output
unlet! g:lines
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_info = {}
Given javascript(A Javscript file with warnings/errors):
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
Before:
let g:ale_buffer_loclist_map = {}
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]'}]}
let g:expected_data = [
\ {
\ '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:
let g:ale_buffer_loclist_map = {}
unlet g:expected_data
Execute(The loclist should be updated after linting is done):
call ale#Lint()
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:
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):
let g:ale_buffer_info = {}
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):
let g:ale_buffer_info = {'44': {'count': [1, 2]}}
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, [])
Then (The cache should reflect the new data):
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):
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):
AssertEqual [0, 0], ale#statusline#Count(9001)
Before:
let g:ale_statusline_format = ['%sE', '%sW', 'OKIE']
Execute (Given some errors):
Execute (Statusline is formatted to the users preference for just errors):
let g:ale_buffer_info = {bufnr('%'): {}}
call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}])
Then (Statusline is formatted to the users preference):
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'}])
Then (Statusline is formatted to the users preference):
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'}])
Then (Statusline is formatted to the users preference):
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('%'), [])
Then (Statusline is formatted to the users preference):
AssertEqual 'OKIE', ale#statusline#Status()