Notifiers refactor.

Creates a notifier class.
Changes the existing signer class to fit the new notifier.
Moves balloons and highlighting to their own classes.
Caches and speeds up EchoCurrentError().
Adds all relevant messages to balloons rather than using the first one.
Fixes yet another (minor) bug related to g:syntastic_quiet_warnings.
This commit is contained in:
LCD 47 2013-04-07 22:10:26 +03:00
parent 01232979aa
commit 0deeefd08e
6 changed files with 229 additions and 139 deletions

View File

@ -21,22 +21,6 @@ runtime! plugin/syntastic/*.vim
let s:running_windows = has("win16") || has("win32")
if !exists("g:syntastic_enable_balloons")
let g:syntastic_enable_balloons = 1
endif
if !has('balloon_eval')
let g:syntastic_enable_balloons = 0
endif
if !exists("g:syntastic_enable_highlighting")
let g:syntastic_enable_highlighting = 1
endif
" highlighting requires getmatches introduced in 7.1.040
if v:version < 701 || (v:version == 701 && !has('patch040'))
let g:syntastic_enable_highlighting = 0
endif
if !exists("g:syntastic_echo_current_error")
let g:syntastic_echo_current_error = 1
endif
@ -70,9 +54,9 @@ if !exists("g:syntastic_loc_list_height")
endif
let s:registry = g:SyntasticRegistry.Instance()
let s:signer = g:SyntasticSigner.New()
call s:signer.SetUpSignStyles()
let s:notifiers = g:SyntasticNotifiers.New()
let s:modemap = g:SyntasticModeMap.Instance()
let s:old_line = -1
function! s:CompleteCheckerName(argLead, cmdLine, cursorPos)
let checker_names = []
@ -93,7 +77,7 @@ highlight link SyntasticWarning SpellCap
augroup syntastic
if g:syntastic_echo_current_error
autocmd cursormoved * call s:EchoCurrentError()
autocmd CursorMoved * call s:EchoCurrentError()
endif
autocmd BufReadPost * if g:syntastic_check_on_open | call s:UpdateErrors(1) | endif
@ -118,17 +102,7 @@ function! s:UpdateErrors(auto_invoked, ...)
endif
end
if g:syntastic_enable_balloons
call s:RefreshBalloons()
endif
if g:syntastic_enable_signs
call s:signer.refreshSigns(s:LocList())
endif
if g:syntastic_enable_highlighting
call s:HighlightErrors()
endif
call s:notifiers.refresh(s:LocList())
let loclist = s:LocList()
if g:syntastic_always_populate_loc_list && loclist.hasErrorsOrWarningsToDisplay()
@ -172,6 +146,7 @@ endfunction
"clear the loc list for the buffer
function! s:ClearCache()
unlet! b:syntastic_loclist
let s:old_line = -1
endfunction
function! s:CurrentFiletypes()
@ -242,58 +217,6 @@ function! s:HideLocList()
endif
endfunction
"highlight the current errors using matchadd()
"
"The function `Syntastic_{filetype}_{checker}_GetHighlightRegex` is used
"to override default highlighting. This function must take one arg (an
"error item) and return a regex to match that item in the buffer.
function! s:HighlightErrors()
call s:ClearErrorHighlights()
let loclist = s:LocList()
let fts = substitute(&ft, '-', '_', 'g')
for ft in split(fts, '\.')
for item in loclist.filteredRaw()
let group = item['type'] == 'E' ? 'SyntasticError' : 'SyntasticWarning'
if has_key(item, 'hl')
call matchadd(group, '\%' . item['lnum'] . 'l' . item['hl'])
elseif get(item, 'col')
let lastcol = col([item['lnum'], '$'])
let lcol = min([lastcol, item['col']])
"a bug in vim can sometimes cause there to be no 'vcol' key,
"so check for its existence
let coltype = has_key(item, 'vcol') && item['vcol'] ? 'v' : 'c'
call matchadd(group, '\%' . item['lnum'] . 'l\%' . lcol . coltype)
endif
endfor
endfor
endfunction
"remove all error highlights from the window
function! s:ClearErrorHighlights()
for match in getmatches()
if stridx(match['group'], 'Syntastic') == 0
call matchdelete(match['id'])
endif
endfor
endfunction
"set up error ballons for the current set of errors
function! s:RefreshBalloons()
let b:syntastic_balloons = {}
let loclist = s:LocList()
if loclist.hasErrorsOrWarningsToDisplay()
for i in loclist.filteredRaw()
let b:syntastic_balloons[i['lnum']] = i['text']
endfor
set beval bexpr=SyntasticErrorBalloonExpr()
endif
endfunction
"print as much of a:msg as possible without "Press Enter" prompt appearing
function! s:WideMsg(msg)
let old_ruler = &ruler
@ -321,23 +244,18 @@ endfunction
"echo out the first error we find for the current line in the cmd window
function! s:EchoCurrentError()
let l = line('.')
if l == s:old_line
return
endif
let s:old_line = l
let loclist = s:LocList()
"If we have an error or warning at the current line, show it
let errors = loclist.filter({'lnum': line("."), "type": 'e'})
let warnings = loclist.filter({'lnum': line("."), "type": 'w'})
let b:syntastic_echoing_error = len(errors) || len(warnings)
if len(errors)
return s:WideMsg(errors[0]['text'])
endif
if len(warnings)
return s:WideMsg(warnings[0]['text'])
endif
"Otherwise, clear the status line
if b:syntastic_echoing_error
let messages = loclist.messages()
if has_key(messages, l)
return s:WideMsg(messages[l])
else
echo
let b:syntastic_echoing_error = 0
endif
endfunction
@ -484,14 +402,6 @@ function! SyntasticMake(options)
return errors
endfunction
"get the error balloon for the current mouse position
function! SyntasticErrorBalloonExpr()
if !exists('b:syntastic_balloons')
return ''
endif
return get(b:syntastic_balloons, v:beval_lnum, '')
endfunction
"take a list of errors and add default values to them from a:options
function! SyntasticAddToErrors(errors, options)
for i in range(0, len(a:errors)-1)

View File

@ -0,0 +1,47 @@
if exists("g:loaded_syntastic_notifier_balloons")
finish
endif
let g:loaded_syntastic_notifier_balloons=1
if !exists("g:syntastic_enable_balloons")
let g:syntastic_enable_balloons = 1
endif
if !has('balloon_eval')
let g:syntastic_enable_balloons = 0
endif
let g:SyntasticNotifierBalloons = {}
" Public methods {{{1
function! g:SyntasticNotifierBalloons.New()
let newObj = copy(self)
return newObj
endfunction
" Update the error balloons
function! g:SyntasticNotifierBalloons.refresh(loclist)
let b:syntastic_balloons = {}
if a:loclist.hasErrorsOrWarningsToDisplay()
for i in a:loclist.filteredRaw()
if has_key(b:syntastic_balloons, i['lnum'])
let b:syntastic_balloons[i['lnum']] .= "\n" . i['text']
else
let b:syntastic_balloons[i['lnum']] = i['text']
endif
endfor
set beval bexpr=SyntasticNotifierBalloonsExpr()
endif
endfunction
" Private functions {{{1
function! SyntasticNotifierBalloonsExpr()
if !exists('b:syntastic_balloons')
return ''
endif
return get(b:syntastic_balloons, v:beval_lnum, '')
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@ -0,0 +1,63 @@
if exists("g:loaded_syntastic_notifier_highlighting")
finish
endif
let g:loaded_syntastic_notifier_highlighting=1
if !exists("g:syntastic_enable_highlighting")
let g:syntastic_enable_highlighting = 1
endif
" Highlighting requires getmatches introduced in 7.1.040
if v:version < 701 || (v:version == 701 && !has('patch040'))
let g:syntastic_enable_highlighting = 0
endif
let g:SyntasticNotifierHighlighting = {}
" Public methods {{{1
function! g:SyntasticNotifierHighlighting.New()
let newObj = copy(self)
return newObj
endfunction
" The function `Syntastic_{filetype}_{checker}_GetHighlightRegex` is used
" to override default highlighting. This function must take one arg (an
" error item) and return a regex to match that item in the buffer.
function! g:SyntasticNotifierHighlighting.refresh(loclist)
call self._reset()
let fts = substitute(&ft, '-', '_', 'g')
for ft in split(fts, '\.')
for item in a:loclist.filteredRaw()
let group = item['type'] == 'E' ? 'SyntasticError' : 'SyntasticWarning'
if has_key(item, 'hl')
call matchadd(group, '\%' . item['lnum'] . 'l' . item['hl'])
elseif get(item, 'col')
let lastcol = col([item['lnum'], '$'])
let lcol = min([lastcol, item['col']])
" a bug in vim can sometimes cause there to be no 'vcol' key,
" so check for its existence
let coltype = has_key(item, 'vcol') && item['vcol'] ? 'v' : 'c'
call matchadd(group, '\%' . item['lnum'] . 'l\%' . lcol . coltype)
endif
endfor
endfor
endfunction
" Private functions {{{1
" Remove all error highlights from the window
function! g:SyntasticNotifierHighlighting._reset()
for match in getmatches()
if stridx(match['group'], 'Syntastic') == 0
call matchdelete(match['id'])
endif
endfor
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@ -63,13 +63,36 @@ function! g:SyntasticLoclist.errors()
return self._cachedErrors
endfunction
function! SyntasticLoclist.warnings()
function! g:SyntasticLoclist.warnings()
if !exists("self._cachedWarnings")
let self._cachedWarnings = self.filter({'type': "W"})
endif
return self._cachedWarnings
endfunction
" cache used by EchoCurrentError()
function! g:SyntasticLoclist.messages()
if !exists("self._cachedMessages")
let self._cachedMessages = {}
for e in self.errors()
if !has_key(self._cachedMessages, e['lnum'])
let self._cachedMessages[e['lnum']] = e['text']
endif
endfor
if !self._quietWarnings
for e in self.warnings()
if !has_key(self._cachedMessages, e['lnum'])
let self._cachedMessages[e['lnum']] = e['text']
endif
endfor
endif
endif
return self._cachedMessages
endfunction
"Filter the list and return new native loclist
"e.g.
" .filter({'bufnr': 10, 'type': 'e'})

View File

@ -0,0 +1,34 @@
if exists("g:loaded_syntastic_notifiers")
finish
endif
let g:loaded_syntastic_notifiers=1
let g:SyntasticNotifiers = {}
let s:notifier_types = ['signs', 'balloons', 'highlighting']
" Public methods {{{1
function! g:SyntasticNotifiers.New()
let newObj = copy(self)
let newObj._notifier = {}
for type in s:notifier_types
let class = substitute(type, '.*', 'SyntasticNotifier\u&', '')
let newObj._notifier[type] = g:{class}.New()
endfor
let newObj._enabled_types = copy(s:notifier_types)
return newObj
endfunction
function! g:SyntasticNotifiers.refresh(loclist)
for type in self._enabled_types
if ( exists('b:syntastic_enable_'.type) ? b:syntastic_enable_{type} : g:syntastic_enable_{type} )
call self._notifier[type].refresh(a:loclist)
endif
endfor
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@ -1,7 +1,7 @@
if exists("g:loaded_syntastic_signer")
if exists("g:loaded_syntastic_notifier_signs")
finish
endif
let g:loaded_syntastic_signer=1
let g:loaded_syntastic_notifier_signs=1
if !exists("g:syntastic_enable_signs")
let g:syntastic_enable_signs = 1
@ -34,15 +34,34 @@ endif
let s:first_sign_id = 5000
let s:next_sign_id = s:first_sign_id
let g:SyntasticSigner = {}
let g:SyntasticNotifierSigns = {}
let s:setup_done = 0
" Public methods {{{1
function! g:SyntasticSigner.New()
function! g:SyntasticNotifierSigns.New()
let newObj = copy(self)
if !s:setup_done
call self._setup()
let s:setup_done = 1
endif
return newObj
endfunction
function! g:SyntasticSigner.SetUpSignStyles()
" Update the error signs
function! g:SyntasticNotifierSigns.refresh(loclist)
let old_signs = copy(self._bufSignIds())
call self._signErrors(a:loclist)
call self._removeSigns(old_signs)
let s:first_sign_id = s:next_sign_id
endfunction
" Private methods {{{1
function! g:SyntasticNotifierSigns._setup()
if has('signs')
if !hlexists('SyntasticErrorSign')
highlight link SyntasticErrorSign error
@ -64,25 +83,19 @@ function! g:SyntasticSigner.SetUpSignStyles()
endif
" define the signs used to display syntax and style errors/warns
exe 'sign define SyntasticError text='.g:syntastic_error_symbol.' texthl=SyntasticErrorSign linehl=SyntasticErrorLine'
exe 'sign define SyntasticWarning text='.g:syntastic_warning_symbol.' texthl=SyntasticWarningSign linehl=SyntasticWarningLine'
exe 'sign define SyntasticStyleError text='.g:syntastic_style_error_symbol.' texthl=SyntasticStyleErrorSign linehl=SyntasticStyleErrorLine'
exe 'sign define SyntasticStyleWarning text='.g:syntastic_style_warning_symbol.' texthl=SyntasticStyleWarningSign linehl=SyntasticStyleWarningLine'
exe 'sign define SyntasticError text=' . g:syntastic_error_symbol .
\ ' texthl=SyntasticErrorSign linehl=SyntasticErrorLine'
exe 'sign define SyntasticWarning text=' . g:syntastic_warning_symbol .
\ ' texthl=SyntasticWarningSign linehl=SyntasticWarningLine'
exe 'sign define SyntasticStyleError text=' . g:syntastic_style_error_symbol .
\ ' texthl=SyntasticStyleErrorSign linehl=SyntasticStyleErrorLine'
exe 'sign define SyntasticStyleWarning text=' . g:syntastic_style_warning_symbol .
\ ' texthl=SyntasticStyleWarningSign linehl=SyntasticStyleWarningLine'
endif
endfunction
"update the error signs
function! g:SyntasticSigner.refreshSigns(loclist)
let old_signs = copy(self._bufSignIds())
call self._signErrors(a:loclist)
call self._removeSigns(old_signs)
let s:first_sign_id = s:next_sign_id
endfunction
"Private methods {{{1
"
"place signs by all syntax errs in the buffer
function! g:SyntasticSigner._signErrors(loclist)
" Place signs by all syntax errs in the buffer
function! g:SyntasticNotifierSigns._signErrors(loclist)
let loclist = a:loclist
if loclist.hasErrorsOrWarningsToDisplay()
@ -111,9 +124,9 @@ function! g:SyntasticSigner._signErrors(loclist)
endif
endfunction
"return true if the given error item is a warning that, if signed, would
" Return true if the given error item is a warning that, if signed, would
" potentially mask an error if displayed at the same time
function! g:SyntasticSigner._warningMasksError(error, llist)
function! g:SyntasticNotifierSigns._warningMasksError(error, llist)
if a:error['type'] !=? 'w'
return 0
endif
@ -122,16 +135,16 @@ function! g:SyntasticSigner._warningMasksError(error, llist)
return len(loclist.filter({ 'type': "E", 'lnum': a:error['lnum'] })) > 0
endfunction
"remove the signs with the given ids from this buffer
function! g:SyntasticSigner._removeSigns(ids)
" Remove the signs with the given ids from this buffer
function! g:SyntasticNotifierSigns._removeSigns(ids)
for i in a:ids
exec "sign unplace " . i
call remove(self._bufSignIds(), index(self._bufSignIds(), i))
endfor
endfunction
"get all the ids of the SyntaxError signs in the buffer
function! g:SyntasticSigner._bufSignIds()
" Get all the ids of the SyntaxError signs in the buffer
function! g:SyntasticNotifierSigns._bufSignIds()
if !exists("b:syntastic_sign_ids")
let b:syntastic_sign_ids = []
endif