Implement a more efficient statusbar

The statusbar now keeps its state in a separate variable, in order to
avoid excess iterations. The engine now updates said variable on run,
and a new function is made available for external statusbars to call (to
avoid dependencies on internal implementation details of ale).

To keep things light, the status bar code is not loaded unless invoked
by the user or an external plugin. On the first load it will update
itself from the global loclist, after that, the engine will handle all
updates.

The external integration function, `ale#statusline#Count()`, will return
a tuple in the format [E, W] (where E is errors, W is warnings), unless
no data exists (ie, the plugin doesn't have a linter for a file or has
not run yet), in which case it returns 0/false.
This commit is contained in:
Bjorn Neergaard 2016-10-11 16:51:01 -05:00
parent f4159ac7ee
commit dc58db7640
No known key found for this signature in database
GPG Key ID: D8F4DB0CE841305D
5 changed files with 76 additions and 40 deletions

View File

@ -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

View File

@ -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.

View File

@ -1,20 +1,12 @@
" Author: KabbAmine <amine.kabb@gmail.com>
" 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,8 +14,41 @@ 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 (or false if no data exists)
" for use in third-party integrations.
function! ale#statusline#Count(buffer) abort
if !has_key(g:ale_buffer_count_map, a:buffer)
if has_key(g:ale_buffer_loclist_map, a:buffer)
call ale#statusline#Update(a:buffer, g:ale_buffer_loclist_map[a:buffer])
return ale#statusline#Count(a:buffer)
else
return 0
endif
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('%')
if !has_key(g:ale_buffer_count_map, l:buffer)
if has_key(g:ale_buffer_loclist_map, l:buffer)
call ale#statusline#Update(l:buffer, g:ale_buffer_loclist_map[l:buffer])
return ale#statusline#Status()
else
return ''
endif
endif
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

View File

@ -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

View File

@ -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('<abuf>')
autocmd BufUnload * call ale#cleanup#Buffer(expand('<abuf>'))
augroup END
" Backwards Compatibility