diff --git a/plugin/syntastic.vim b/plugin/syntastic.vim index 780977b5..74d109b0 100644 --- a/plugin/syntastic.vim +++ b/plugin/syntastic.vim @@ -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) diff --git a/plugin/syntastic/balloons.vim b/plugin/syntastic/balloons.vim new file mode 100644 index 00000000..78b1ceb6 --- /dev/null +++ b/plugin/syntastic/balloons.vim @@ -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: diff --git a/plugin/syntastic/highlighting.vim b/plugin/syntastic/highlighting.vim new file mode 100644 index 00000000..61ce5b2c --- /dev/null +++ b/plugin/syntastic/highlighting.vim @@ -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: diff --git a/plugin/syntastic/loclist.vim b/plugin/syntastic/loclist.vim index 8f6f8037..db581028 100644 --- a/plugin/syntastic/loclist.vim +++ b/plugin/syntastic/loclist.vim @@ -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'}) diff --git a/plugin/syntastic/notifiers.vim b/plugin/syntastic/notifiers.vim new file mode 100644 index 00000000..c865d3f4 --- /dev/null +++ b/plugin/syntastic/notifiers.vim @@ -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: diff --git a/plugin/syntastic/signer.vim b/plugin/syntastic/signer.vim index 0aefdc03..4388af5d 100644 --- a/plugin/syntastic/signer.vim +++ b/plugin/syntastic/signer.vim @@ -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 @@ -28,21 +28,40 @@ if !has('signs') endif -"start counting sign ids at 5000, start here to hopefully avoid conflicting -"with any other code that places signs (not sure if this precaution is -"actually needed) +" start counting sign ids at 5000, start here to hopefully avoid conflicting +" with any other code that places signs (not sure if this precaution is +" actually needed) let s:first_sign_id = 5000 let s:next_sign_id = s:first_sign_id -let g:SyntasticSigner = {} +let g:SyntasticNotifierSigns = {} -"Public methods {{{1 -function! g:SyntasticSigner.New() +let s:setup_done = 0 + +" Public methods {{{1 + +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 @@ -63,26 +82,20 @@ function! g:SyntasticSigner.SetUpSignStyles() highlight link SyntasticStyleWarningLine SyntasticWarningLine 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' + " 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' 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 -"potentially mask an error if displayed at the same time -function! g:SyntasticSigner._warningMasksError(error, llist) +" 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: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