From bbd382ba5d80de097de44b3a8e664112ff90f895 Mon Sep 17 00:00:00 2001 From: LCD 47 Date: Wed, 13 Nov 2013 10:58:33 +0200 Subject: [PATCH] Detailed debugging. New variables: g:syntastic_debug_file, the name of a file where to write debugging messages, in addition to adding them to the message history. The old g:syntastic_debug is now a sum of flags: * 1 - trace checker calls * 2 - dump loclists * 4 - trace notifiers * 8 - trace autocommands * 16 - dump syntastic variables (not implemented yet) --- autoload/syntastic/util.vim | 57 +++++++++++++++++++++-- doc/syntastic.txt | 18 +++++++- plugin/syntastic.vim | 75 ++++++++++++++++++++++++------- plugin/syntastic/autoloclist.vim | 2 + plugin/syntastic/balloons.vim | 2 + plugin/syntastic/checker.vim | 3 +- plugin/syntastic/cursor.vim | 2 + plugin/syntastic/highlighting.vim | 2 + plugin/syntastic/loclist.vim | 2 + plugin/syntastic/notifiers.vim | 2 + plugin/syntastic/signs.vim | 1 + 11 files changed, 145 insertions(+), 21 deletions(-) diff --git a/autoload/syntastic/util.vim b/autoload/syntastic/util.vim index 10c01303..d49d8d6e 100644 --- a/autoload/syntastic/util.vim +++ b/autoload/syntastic/util.vim @@ -225,9 +225,60 @@ function! syntastic#util#redrawHandler() endif endfunction -function! syntastic#util#debug(msg) - if g:syntastic_debug - echomsg "syntastic: debug: " . a:msg +function! syntastic#util#debug(level, msg, ...) + " poor man's bit test for bit N, assuming a:level == 2**N + if (g:syntastic_debug / a:level) % 2 + if has('reltime') + let leader = 'syntastic: ' . split(reltimestr(reltime(g:syntastic_start)))[0] . ': ' + else + let leader = 'syntastic: debug: ' + endif + if exists("g:syntastic_debug_file") + try + execute 'redir >> ' . fnameescape(expand(g:syntastic_debug_file)) + catch /^Vim\%((\a\+)\)\=:/ + unlet g:syntastic_debug_file + silent! redir END + endtry + endif + + if a:0 > 0 + " filter out dictionary functions + echomsg leader . a:msg . + \ strtrans(string(type(a:1) == type({}) || type(a:1) == type([]) ? + \ filter(copy(a:1), 'type(v:val) != type(function("tr"))') : a:1)) + else + echomsg leader . a:msg + endif + + if exists("g:syntastic_debug_file") + silent! redir END + endif + endif +endfunction + +function! syntastic#util#showVariables(level, names) + let vlist = type(a:names) == type("") ? [a:names] : a:names + for name in vlist + let vals = [] + if exists('g:' . name) + call add(vals, 'g:' . name . ' = ' . strtrans(string(g:{name}))) + endif + if exists('b:' . name) + call add(vals, 'b:' . name . ' = ' . strtrans(string(b:{name}))) + endif + + if !empty(vals) + call syntastic#util#debug(a:level, join(vals, ', ')) + endif + endfor +endfunction + +function! syntastic#util#showOptions(level, names) + let vlist = type(a:names) == type("") ? [a:names] : a:names + if !empty(vlist) + call map(vlist, "'&' . v:val . ' = ' . strtrans(string(eval('&' . v:val)))") + call syntastic#util#debug(a:level, join(vlist, ', ')) endif endfunction diff --git a/doc/syntastic.txt b/doc/syntastic.txt index 6cba842c..7fd2dcf7 100644 --- a/doc/syntastic.txt +++ b/doc/syntastic.txt @@ -398,12 +398,26 @@ if you actually need it. *'syntastic_debug'* Default: 0 -Set this to 1 to enable debugging: > +Set this to the sum of one or more of the following flags to enable +debugging: + + 1 - trace checker calls + 2 - dump loclists + 4 - trace notifiers + 8 - trace autocommands + +Example: > let g:syntastic_debug = 1 < -Checkers will then add debugging messages to Vim's |message-history|. You can +Syntastic will then add debugging messages to Vim's |message-history|. You can examine these messages with |:mes|. + *'syntastic_debug_file'* +Default: unset +When set, debugging messages are written to the file named by its value, in +addition to being added to Vim's |message-history|: > + let g:syntastic_debug_file = '~/syntastic.log' +< ============================================================================== 5. Checker Options *syntastic-checker-options* diff --git a/plugin/syntastic.vim b/plugin/syntastic.vim index 415552b7..38c68317 100644 --- a/plugin/syntastic.vim +++ b/plugin/syntastic.vim @@ -15,6 +15,10 @@ if exists("g:loaded_syntastic_plugin") endif let g:loaded_syntastic_plugin = 1 +if has('reltime') + let g:syntastic_start = reltime() +endif + runtime! plugin/syntastic/*.vim let s:running_windows = has("win16") || has("win32") @@ -89,6 +93,13 @@ if !exists("g:syntastic_reuse_loc_lists") let g:syntastic_reuse_loc_lists = (v:version >= 704) endif +" debug constants +let g:SyntasticDebugTrace = 1 +let g:SyntasticDebugLoclist = 2 +let g:SyntasticDebugNotifications = 4 +let g:SyntasticDebugAutocommands = 8 +let g:SyntasticDebugVariables = 16 + let s:registry = g:SyntasticRegistry.Instance() let s:notifiers = g:SyntasticNotifiers.Instance() let s:modemap = g:SyntasticModeMap.Instance() @@ -119,12 +130,12 @@ highlight link SyntasticError SpellBad highlight link SyntasticWarning SpellCap augroup syntastic - autocmd BufReadPost * if g:syntastic_check_on_open | call s:UpdateErrors(1) | endif - autocmd BufWritePost * call s:UpdateErrors(1) + autocmd BufReadPost * call s:BufReadPostHook() + autocmd BufWritePost * call s:BufWritePostHook() autocmd BufWinEnter * call s:BufWinEnterHook() - " TODO: the next autocmd should be "autocmd BufWinLeave * if empty(&bt) | lclose | endif" + " TODO: the next autocmd should be "autocmd BufWinLeave * if empty(&buftype) | lclose | endif" " but in recent versions of Vim lclose can no longer be called from BufWinLeave autocmd BufEnter * call s:BufEnterHook() augroup END @@ -137,23 +148,45 @@ if v:version > 703 || (v:version == 703 && has('patch544')) endif +function! s:BufReadPostHook() + if g:syntastic_check_on_open + call syntastic#util#debug(g:SyntasticDebugAutocommands, + \ 'autocmd: BufReadPost, buffer ' . bufnr("") . ' = ' . string(bufname(str2nr(bufnr(""))))) + call s:UpdateErrors(1) + endif +endfunction + +function! s:BufWritePostHook() + call syntastic#util#debug(g:SyntasticDebugAutocommands, + \ 'autocmd: BufWritePost, buffer ' . bufnr("") . ' = ' . string(bufname(str2nr(bufnr(""))))) + call s:UpdateErrors(1) +endfunction + function! s:BufWinEnterHook() - if empty(&bt) + call syntastic#util#debug(g:SyntasticDebugAutocommands, + \ 'autocmd: BufWinEnter, buffer ' . bufnr("") . ' = ' . string(bufname(str2nr(bufnr("")))) . + \ ', &buftype = ' . string(&buftype)) + if empty(&buftype) let loclist = g:SyntasticLoclist.current() call s:notifiers.refresh(loclist) endif endfunction function! s:BufEnterHook() + call syntastic#util#debug(g:SyntasticDebugAutocommands, + \ 'autocmd: BufEnter, buffer ' . bufnr("") . ' = ' . string(bufname(str2nr(bufnr("")))) . + \ ', &buftype = ' . string(&buftype)) " TODO: at this point there is no b:syntastic_loclist let loclist = filter(getloclist(0), 'v:val["valid"] == 1') let buffers = syntastic#util#unique(map( loclist, 'v:val["bufnr"]' )) - if &bt=='quickfix' && !empty(loclist) && empty(filter( buffers, 'syntastic#util#bufIsActive(v:val)' )) + if &buftype == 'quickfix' && !empty(loclist) && empty(filter( buffers, 'syntastic#util#bufIsActive(v:val)' )) call g:SyntasticLoclistHide() endif endfunction function! s:QuitPreHook() + call syntastic#util#debug(g:SyntasticDebugAutocommands, + \ 'autocmd: QuitPre, buffer ' . bufnr("") . ' = ' . string(bufname(str2nr(bufnr(""))))) let b:syntastic_skip_checks = !g:syntastic_check_on_wq call g:SyntasticLoclistHide() endfunction @@ -207,10 +240,9 @@ function! s:CacheErrors(...) let active_checkers = 0 let names = [] - call syntastic#util#debug("CacheErrors: g:syntastic_aggregate_errors = " . g:syntastic_aggregate_errors) - if exists('b:syntastic_aggregate_errors') - call syntastic#util#debug("CacheErrors: b:syntastic_aggregate_errors = " . b:syntastic_aggregate_errors) - endif + call syntastic#util#showOptions(g:SyntasticDebugTrace, + \ ['shell', 'shellcmdflag', 'shellxquote', 'shellredir', 'shellslash']) + call syntastic#util#showVariables(g:SyntasticDebugTrace, 'syntastic_aggregate_errors') let aggregate_errors = \ exists('b:syntastic_aggregate_errors') ? b:syntastic_aggregate_errors : g:syntastic_aggregate_errors @@ -227,7 +259,7 @@ function! s:CacheErrors(...) for checker in checkers let active_checkers += 1 - call syntastic#util#debug("CacheErrors: Invoking checker: " . checker.getName()) + call syntastic#util#debug(g:SyntasticDebugTrace, "CacheErrors: Invoking checker: " . checker.getName()) let loclist = checker.getLocList() @@ -262,9 +294,11 @@ function! s:CacheErrors(...) if a:0 call syntastic#util#warn('checker ' . a:1 . ' is not active for filetype ' . &filetype) else - call syntastic#util#debug('no active checkers for filetype ' . &filetype) + call syntastic#util#debug(g:SyntasticDebugTrace, 'CacheErrors: no active checkers for filetype ' . &filetype) endif endif + + call syntastic#util#debug(g:SyntasticDebugLoclist, "aggregated:", newLoclist) endif let b:syntastic_loclist = newLoclist @@ -382,7 +416,7 @@ endfunction " 'cwd' - change directory to the given path before running the checker " 'returns' - a list of valid exit codes for the checker function! SyntasticMake(options) - call syntastic#util#debug('SyntasticMake: called with options: '. string(a:options)) + call syntastic#util#debug(g:SyntasticDebugTrace, 'SyntasticMake: called with options:', a:options) let old_shell = &shell let old_shellredir = &shellredir @@ -413,8 +447,11 @@ function! SyntasticMake(options) let $LC_ALL = old_lc_all let $LC_MESSAGES = old_lc_messages + call syntastic#util#debug(g:SyntasticDebugLoclist, "checker output:", err_lines) + if has_key(a:options, 'preprocess') let err_lines = call(a:options['preprocess'], [err_lines]) + call syntastic#util#debug(g:SyntasticDebugLoclist, "preprocess:", err_lines) endif lgetexpr err_lines @@ -434,6 +471,8 @@ function! SyntasticMake(options) call syntastic#util#redraw(g:syntastic_full_redraws) endif + call syntastic#util#debug(g:SyntasticDebugLoclist, "raw loclist:", errors) + if has_key(a:options, 'returns') && index(a:options['returns'], v:shell_error) == -1 throw 'Syntastic: checker error' endif @@ -443,11 +482,16 @@ function! SyntasticMake(options) endif " Apply ignore patterns - let ignore = {} + let ignored = {} + let do_ignore = 0 for buf in syntastic#util#unique(map(copy(errors), 'v:val["bufnr"]')) - let ignore[buf] = s:IgnoreFile(bufname(str2nr(buf))) + let ignored[buf] = s:IgnoreFile(bufname(str2nr(buf))) + let do_ignore = do_ignore || ignored[buf] endfor - call filter(errors, '!ignore[v:val["bufnr"]]') + if do_ignore + call filter(errors, '!ignored[v:val["bufnr"]]') + call syntastic#util#debug(g:SyntasticDebugLoclist, "filtered loclist:", errors) + endif " Add subtype info if present. if has_key(a:options, 'subtype') @@ -458,6 +502,7 @@ function! SyntasticMake(options) for rule in a:options['postprocess'] let errors = call('syntastic#postprocess#' . rule, [errors]) endfor + call syntastic#util#debug(g:SyntasticDebugLoclist, "postprocess:", errors) endif return errors diff --git a/plugin/syntastic/autoloclist.vim b/plugin/syntastic/autoloclist.vim index 9a1a018f..583fb464 100644 --- a/plugin/syntastic/autoloclist.vim +++ b/plugin/syntastic/autoloclist.vim @@ -17,10 +17,12 @@ function! g:SyntasticAutoloclistNotifier.New() endfunction function! g:SyntasticAutoloclistNotifier.refresh(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'autoloclist: refresh') call g:SyntasticAutoloclistNotifier.AutoToggle(a:loclist) endfunction function! g:SyntasticAutoloclistNotifier.AutoToggle(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'autoloclist: toggle') if a:loclist.hasErrorsOrWarningsToDisplay() if g:syntastic_auto_loc_list == 1 call a:loclist.show() diff --git a/plugin/syntastic/balloons.vim b/plugin/syntastic/balloons.vim index f6e60418..9d888e3a 100644 --- a/plugin/syntastic/balloons.vim +++ b/plugin/syntastic/balloons.vim @@ -30,6 +30,7 @@ endfunction function! g:SyntasticBalloonsNotifier.refresh(loclist) let b:syntastic_balloons = {} if self.enabled() && a:loclist.hasErrorsOrWarningsToDisplay() + call syntastic#util#debug(g:SyntasticDebugNotifications, 'balloons: refresh') let buf = bufnr('') let issues = filter(a:loclist.filteredRaw(), 'v:val["bufnr"] == buf') if !empty(issues) @@ -48,6 +49,7 @@ endfunction " Reset the error balloons function! g:SyntasticBalloonsNotifier.reset(loclist) if has('balloon_eval') + call syntastic#util#debug(g:SyntasticDebugNotifications, 'balloons: reset') set nobeval endif endfunction diff --git a/plugin/syntastic/checker.vim b/plugin/syntastic/checker.vim index 7014f1de..dbb836c7 100644 --- a/plugin/syntastic/checker.vim +++ b/plugin/syntastic/checker.vim @@ -58,7 +58,8 @@ endfunction function! g:SyntasticChecker.getLocList() try let list = self._locListFunc() - call syntastic#util#debug('getLocList: checker ' . self._filetype . '/' . self._name . ' returned ' . v:shell_error) + call syntastic#util#debug(g:SyntasticDebugTrace, + \ 'getLocList: checker ' . self._filetype . '/' . self._name . ' returned ' . v:shell_error) catch /\m\C^Syntastic: checker error$/ let list = [] call syntastic#util#error('checker ' . self._filetype . '/' . self._name . ' returned abnormal status ' . v:shell_error) diff --git a/plugin/syntastic/cursor.vim b/plugin/syntastic/cursor.vim index 77f97dc5..3ceffa55 100644 --- a/plugin/syntastic/cursor.vim +++ b/plugin/syntastic/cursor.vim @@ -22,6 +22,7 @@ endfunction function! g:SyntasticCursorNotifier.refresh(loclist) if self.enabled() && a:loclist.hasErrorsOrWarningsToDisplay() + call syntastic#util#debug(g:SyntasticDebugNotifications, 'cursor: refresh') let b:syntastic_messages = copy(a:loclist.messages(bufnr(''))) let b:oldLine = -1 autocmd! syntastic CursorMoved @@ -30,6 +31,7 @@ function! g:SyntasticCursorNotifier.refresh(loclist) endfunction function! g:SyntasticCursorNotifier.reset(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'cursor: reset') autocmd! syntastic CursorMoved unlet! b:syntastic_messages let b:oldLine = -1 diff --git a/plugin/syntastic/highlighting.vim b/plugin/syntastic/highlighting.vim index 72671ba8..9d86253f 100644 --- a/plugin/syntastic/highlighting.vim +++ b/plugin/syntastic/highlighting.vim @@ -29,6 +29,7 @@ endfunction function! g:SyntasticHighlightingNotifier.refresh(loclist) if self.enabled() call self.reset(a:loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'highlighting: refresh') let buf = bufnr('') let issues = filter(a:loclist.filteredRaw(), 'v:val["bufnr"] == buf') for item in issues @@ -55,6 +56,7 @@ endfunction " Remove all error highlights from the window function! g:SyntasticHighlightingNotifier.reset(loclist) if s:has_highlighting + call syntastic#util#debug(g:SyntasticDebugNotifications, 'highlighting: reset') for match in getmatches() if stridx(match['group'], 'Syntastic') == 0 call matchdelete(match['id']) diff --git a/plugin/syntastic/loclist.vim b/plugin/syntastic/loclist.vim index f03a9b20..20515b6f 100644 --- a/plugin/syntastic/loclist.vim +++ b/plugin/syntastic/loclist.vim @@ -149,6 +149,7 @@ endfunction "display the cached errors for this buf in the location list function! g:SyntasticLoclist.show() + call syntastic#util#debug(g:SyntasticDebugNotifications, 'loclist: show') if !exists('w:syntastic_loclist_set') let w:syntastic_loclist_set = 0 endif @@ -184,6 +185,7 @@ endfunction " Non-method functions {{{1 function! g:SyntasticLoclistHide() + call syntastic#util#debug(g:SyntasticDebugNotifications, 'loclist: hide') silent! lclose endfunction diff --git a/plugin/syntastic/notifiers.vim b/plugin/syntastic/notifiers.vim index 645aa669..e1e91a77 100644 --- a/plugin/syntastic/notifiers.vim +++ b/plugin/syntastic/notifiers.vim @@ -19,6 +19,7 @@ function! g:SyntasticNotifiers.Instance() endfunction function! g:SyntasticNotifiers.refresh(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'notifiers: refresh') for type in self._enabled_types let class = substitute(type, '\m.*', 'Syntastic\u&Notifier', '') if !has_key(g:{class}, 'enabled') || self._notifier[type].enabled() @@ -28,6 +29,7 @@ function! g:SyntasticNotifiers.refresh(loclist) endfunction function! g:SyntasticNotifiers.reset(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'notifiers: reset') for type in self._enabled_types let class = substitute(type, '\m.*', 'Syntastic\u&Notifier', '') diff --git a/plugin/syntastic/signs.vim b/plugin/syntastic/signs.vim index db9a612d..7e16fe46 100644 --- a/plugin/syntastic/signs.vim +++ b/plugin/syntastic/signs.vim @@ -54,6 +54,7 @@ function! g:SyntasticSignsNotifier.enabled() endfunction function! g:SyntasticSignsNotifier.refresh(loclist) + call syntastic#util#debug(g:SyntasticDebugNotifications, 'signs: refresh') let old_signs = copy(self._bufSignIds()) if self.enabled() call self._signErrors(a:loclist)