diff --git a/autoload/ale/cleanup.vim b/autoload/ale/cleanup.vim index 2f636eee..45eccb98 100644 --- a/autoload/ale/cleanup.vim +++ b/autoload/ale/cleanup.vim @@ -2,14 +2,18 @@ " Description: Utility functions related to cleaning state. function! ale#cleanup#Buffer(buffer) abort - if has_key(g:ale_buffer_should_reset_map, a:buffer) - call remove(g:ale_buffer_should_reset_map, a:buffer) + 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_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) endif diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 7342a541..1d0ad3d5 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -98,7 +98,7 @@ function! s:HandleExit(job) abort " 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_loclist_map[l:buffer], 's:LocItemCompare') if g:ale_set_loclist call setloclist(0, g:ale_buffer_loclist_map[l:buffer]) @@ -108,6 +108,11 @@ function! s:HandleExit(job) abort call ale#sign#SetSigns(l:buffer, g:ale_buffer_loclist_map[l:buffer]) 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]) + endif + " Mark line 200, column 17 with a squiggly line or something " matchadd('ALEError', '\%200l\%17v') endfunction @@ -136,6 +141,26 @@ function! s:FixLocList(buffer, loclist) abort endfor endfunction +function! s:LocItemCompare(left, right) abort + if a:left['lnum'] < a:right['lnum'] + return -1 + endif + + if a:left['lnum'] > a:right['lnum'] + return 1 + endif + + if a:left['col'] < a:right['col'] + return -1 + endif + + if a:left['col'] > a:right['col'] + return 1 + endif + + return 0 +endfunction + function! ale#engine#Invoke(buffer, linter) abort if has_key(a:linter, 'job') " Stop previous jobs for the same linter. diff --git a/autoload/ale/statusline.vim b/autoload/ale/statusline.vim index 995fcd94..8a31bc39 100644 --- a/autoload/ale/statusline.vim +++ b/autoload/ale/statusline.vim @@ -1,20 +1,12 @@ " Author: KabbAmine " Description: Statusline related function(s) -function! ale#statusline#Status() abort - " Returns a formatted string that can be integrated in the - " statusline - - let l:buffer = bufnr('%') - let l:loclist = g:ale_buffer_loclist_map - - if !has_key(l:loclist, l:buffer) - return '' - endif - +" Update the buffer error/warning count with data from loclist. +function! ale#statusline#Update(buffer, loclist) abort let l:errors = 0 let l:warnings = 0 - for l:entry in l:loclist[l:buffer] + + for l:entry in a:loclist if l:entry.type ==# 'E' let l:errors += 1 else @@ -22,11 +14,36 @@ function! ale#statusline#Status() abort endif endfor - let l:errors = l:errors ? printf(g:ale_statusline_format[0], l:errors) : '' - let l:warnings = l:warnings ? printf(g:ale_statusline_format[1], l:warnings) : '' + let g:ale_buffer_count_map[a:buffer] = [l:errors, l:warnings] +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, [])) + endif + + return g:ale_buffer_count_map[a:buffer] +endfunction + +" Returns a formatted string that can be integrated in the statusline. +function! ale#statusline#Status() abort + 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, [])) + endif + + " 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] - " Different formats if no errors or no warnings + " Different formats based on the combination of errors and warnings. if empty(l:errors) && empty(l:warnings) let l:res = l:no_errors elseif !empty(l:errors) && !empty(l:warnings) diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index 17ce7c44..4217ac49 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -43,23 +43,3 @@ function! ale#util#GetFunction(string_or_ref) abort return a:string_or_ref endfunction - -function! ale#util#LocItemCompare(left, right) abort - if a:left['lnum'] < a:right['lnum'] - return -1 - endif - - if a:left['lnum'] > a:right['lnum'] - return 1 - endif - - if a:left['col'] < a:right['col'] - return -1 - endif - - if a:left['col'] > a:right['col'] - return 1 - endif - - return 0 -endfunction diff --git a/plugin/ale.vim b/plugin/ale.vim index 9b45cd7c..d1c29902 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -24,6 +24,7 @@ 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 = {} @@ -98,7 +99,8 @@ let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error') let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning') " This flag can be set to 0 to disable echoing when the cursor moves. -if get(g:, 'ale_echo_cursor', 1) +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() @@ -120,10 +122,10 @@ let g:ale_warn_about_trailing_whitespace = " Housekeeping -augroup ALECleanup +augroup ALECleanupGroup autocmd! " Clean up buffers automatically when they are unloaded. - autocmd BufUnload * call ale#cleanup#Buffer('') + autocmd BufUnload * call ale#cleanup#Buffer(expand('')) augroup END " Backwards Compatibility diff --git a/test/test_ale_statusline.vader b/test/test_ale_statusline.vader new file mode 100644 index 00000000..e935b1ec --- /dev/null +++ b/test/test_ale_statusline.vader @@ -0,0 +1,50 @@ +Before: + let g:ale_buffer_loclist_map = {} + +Execute (Count should be 0 when data is empty): + AssertEqual ale#statusline#Count(bufnr('%')), [0, 0] + + +Before: + let g:ale_buffer_count_map = {'44': [1, 2]} + +Execute (Count should read data from the cache): + AssertEqual ale#statusline#Count(44), [1, 2] + +Execute (Update the cache with new data): + call ale#statusline#Update(44, []) +Then (The cache should reflect the new data): + AssertEqual ale#statusline#Count(44), [0, 0] + + +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 ale#statusline#Count(1), [1, 0] + +Execute (Output should be empty for non-existant buffer): + AssertEqual ale#statusline#Count(9001), [0, 0] + +Before: + let g:ale_statusline_format = ['%sE', '%sW', 'OKIE'] + +Execute (Given some errors): + call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'E'}]) +Then (Statusline is formatted to the users preference): + AssertEqual ale#statusline#Status(), "2E" + +Execute (Given some warnings): + call ale#statusline#Update(bufnr('%'), [{'type': 'W'}, {'type': 'W'}, {'type': 'W'}]) +Then (Statusline is formatted to the users preference): + AssertEqual ale#statusline#Status(), "3W" + +Execute (Given some warnings, and errors.): + call ale#statusline#Update(bufnr('%'), [{'type': 'E'}, {'type': 'W'}, {'type': 'W'}]) +Then (Statusline is formatted to the users preference): + AssertEqual ale#statusline#Status(), "1E 2W" + +Execute (Given a lack of data): + call ale#statusline#Update(bufnr('%'), []) +Then (Statusline is formatted to the users preference): + AssertEqual ale#statusline#Status(), 'OKIE' diff --git a/test/vimrc b/test/vimrc index 1ab04d04..77be5e29 100644 --- a/test/vimrc +++ b/test/vimrc @@ -2,9 +2,7 @@ " Load builtin plugins " We need this because run_vim.sh sets -i NONE -set runtimepath=/home/vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,/testplugin -set runtimepath+=/home/ale -set runtimepath+=/vader +set runtimepath=/home/vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,/testplugin,/vader " The following is just an example filetype plugin indent on