Core: make autocommands aware of buffers.

Also move "check_on_open" checks to BufEnter.  This allows correct
handling of files that specify a non-default filetype in modelines.
This commit is contained in:
LCD 47 2016-08-28 21:16:19 +03:00
parent 68f473ecc8
commit d50e8c0f6b
3 changed files with 69 additions and 49 deletions

View File

@ -271,6 +271,11 @@ function! syntastic#util#findGlobInParent(what, where) abort " {{{2
return '' return ''
endfunction " }}}2 endfunction " }}}2
" Returns the buffer number of a filename
function! syntastic#util#fname2buf(fname) abort " {{{2
return bufnr('^' . escape( fnamemodify(a:fname, ':p'), '\$.*~[' ) . '$')
endfunction " }}}2
" Returns unique elements in a list " Returns unique elements in a list
function! syntastic#util#unique(list) abort " {{{2 function! syntastic#util#unique(list) abort " {{{2
let seen = {} let seen = {}
@ -342,10 +347,8 @@ function! syntastic#util#stamp() abort " {{{2
return split( split(reltimestr(reltime(g:_SYNTASTIC_START)))[0], '\.' ) return split( split(reltimestr(reltime(g:_SYNTASTIC_START)))[0], '\.' )
endfunction " }}}2 endfunction " }}}2
function! syntastic#util#setChangedtick() abort " {{{2 function! syntastic#util#setChangedtick(buf) abort " {{{2
unlockvar! b:syntastic_changedtick call setbufvar(a:buf, 'syntastic_changedtick', getbufvar(a:buf, 'changedtick'))
let b:syntastic_changedtick = b:changedtick
lockvar! b:syntastic_changedtick
endfunction " }}}2 endfunction " }}}2
let s:_wid_base = 'syntastic_' . getpid() . '_' . reltimestr(g:_SYNTASTIC_START) . '_' let s:_wid_base = 'syntastic_' . getpid() . '_' . reltimestr(g:_SYNTASTIC_START) . '_'

View File

@ -19,7 +19,7 @@ if has('reltime')
lockvar! g:_SYNTASTIC_START lockvar! g:_SYNTASTIC_START
endif endif
let g:_SYNTASTIC_VERSION = '3.7.0-200' let g:_SYNTASTIC_VERSION = '3.7.0-201'
lockvar g:_SYNTASTIC_VERSION lockvar g:_SYNTASTIC_VERSION
" Sanity checks {{{1 " Sanity checks {{{1
@ -163,6 +163,7 @@ let s:registry = g:SyntasticRegistry.Instance()
let s:notifiers = g:SyntasticNotifiers.Instance() let s:notifiers = g:SyntasticNotifiers.Instance()
let s:modemap = g:SyntasticModeMap.Instance() let s:modemap = g:SyntasticModeMap.Instance()
let s:_check_stack = []
let s:_quit_pre = [] let s:_quit_pre = []
" Commands {{{1 " Commands {{{1
@ -207,7 +208,7 @@ command! SyntasticJavacEditConfig runtime! syntax_checkers/java/*.vim | Synta
" Public API {{{1 " Public API {{{1
function! SyntasticCheck(...) abort " {{{2 function! SyntasticCheck(...) abort " {{{2
call s:UpdateErrors(0, a:000) call s:UpdateErrors(bufnr(''), 0, a:000)
call syntastic#util#redraw(g:syntastic_full_redraws) call syntastic#util#redraw(g:syntastic_full_redraws)
endfunction " }}}2 endfunction " }}}2
@ -222,13 +223,13 @@ function! SyntasticErrors() abort " {{{2
endfunction " }}}2 endfunction " }}}2
function! SyntasticReset() abort " {{{2 function! SyntasticReset() abort " {{{2
call s:ClearCache() call s:ClearCache(bufnr(''))
call s:notifiers.refresh(g:SyntasticLoclist.New([])) call s:notifiers.refresh(g:SyntasticLoclist.New([]))
endfunction " }}}2 endfunction " }}}2
function! SyntasticToggleMode() abort " {{{2 function! SyntasticToggleMode() abort " {{{2
call s:modemap.toggleMode() call s:modemap.toggleMode()
call s:ClearCache() call s:ClearCache(bufnr(''))
call s:notifiers.refresh(g:SyntasticLoclist.New([])) call s:notifiers.refresh(g:SyntasticLoclist.New([]))
call s:modemap.echoMode() call s:modemap.echoMode()
endfunction " }}}2 endfunction " }}}2
@ -243,54 +244,64 @@ endfunction " }}}2
augroup syntastic augroup syntastic
autocmd! autocmd!
autocmd BufEnter * call s:BufEnterHook() autocmd BufEnter * call s:BufEnterHook(expand('<afile>', 1))
augroup END augroup END
if g:syntastic_nested_autocommands if g:syntastic_nested_autocommands
augroup syntastic augroup syntastic
autocmd BufReadPost * nested call s:BufReadPostHook() autocmd BufReadPost * nested call s:BufReadPostHook(expand('<afile>', 1))
autocmd BufWritePost * nested call s:BufWritePostHook() autocmd BufWritePost * nested call s:BufWritePostHook(expand('<afile>', 1))
augroup END augroup END
else else
augroup syntastic augroup syntastic
autocmd BufReadPost * call s:BufReadPostHook() autocmd BufReadPost * call s:BufReadPostHook(expand('<afile>', 1))
autocmd BufWritePost * call s:BufWritePostHook() autocmd BufWritePost * call s:BufWritePostHook(expand('<afile>', 1))
augroup END augroup END
endif endif
if exists('##QuitPre') if exists('##QuitPre')
" QuitPre was added in Vim 7.3.544 " QuitPre was added in Vim 7.3.544
augroup syntastic augroup syntastic
autocmd QuitPre * call s:QuitPreHook(expand('<amatch>', 1)) autocmd QuitPre * call s:QuitPreHook(expand('<afile>', 1))
augroup END augroup END
endif endif
function! s:BufReadPostHook() abort " {{{2 function! s:BufReadPostHook(fname) abort " {{{2
let buf = syntastic#util#fname2buf(a:fname)
if g:syntastic_check_on_open if g:syntastic_check_on_open
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS,
\ 'autocmd: BufReadPost, buffer ' . bufnr('') . ' = ' . string(bufname(str2nr(bufnr(''))))) \ 'autocmd: BufReadPost, buffer ' . buf . ' = ' . string(a:fname))
call s:UpdateErrors(1, []) if index(s:_check_stack, buf) == -1
call add(s:_check_stack, buf)
endif
endif endif
endfunction " }}}2 endfunction " }}}2
function! s:BufWritePostHook() abort " {{{2 function! s:BufWritePostHook(fname) abort " {{{2
let buf = syntastic#util#fname2buf(a:fname)
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS,
\ 'autocmd: BufWritePost, buffer ' . bufnr('') . ' = ' . string(bufname(str2nr(bufnr(''))))) \ 'autocmd: BufWritePost, buffer ' . buf . ' = ' . string(a:fname))
call s:UpdateErrors(1, []) call s:UpdateErrors(buf, 1, [])
endfunction " }}}2 endfunction " }}}2
function! s:BufEnterHook() abort " {{{2 function! s:BufEnterHook(fname) abort " {{{2
let buf = syntastic#util#fname2buf(a:fname)
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS,
\ 'autocmd: BufEnter, buffer ' . bufnr('') . ' = ' . string(bufname(str2nr(bufnr('')))) . \ 'autocmd: BufEnter, buffer ' . buf . ' = ' . string(a:fname) . ', &buftype = ' . string(&buftype))
\ ', &buftype = ' . string(&buftype))
if &buftype ==# '' if &buftype ==# ''
call s:notifiers.refresh(g:SyntasticLoclist.current()) let idx = index(reverse(copy(s:_check_stack)), buf)
if idx >= 0
call remove(s:_check_stack, -idx - 1)
call s:UpdateErrors(buf, 1, [])
else
call s:notifiers.refresh(g:SyntasticLoclist.current())
endif
elseif &buftype ==# 'quickfix' elseif &buftype ==# 'quickfix'
" TODO: this is needed because in recent versions of Vim lclose " TODO: this is needed because in recent versions of Vim lclose
" can no longer be called from BufWinLeave " can no longer be called from BufWinLeave
" TODO: at this point there is no b:syntastic_loclist " TODO: at this point there is no b:syntastic_loclist
let loclist = filter(copy(getloclist(0)), 'v:val["valid"] == 1') let loclist = filter(copy(getloclist(0)), 'v:val["valid"] == 1')
let owner = str2nr(getbufvar(bufnr(''), 'syntastic_owner_buffer')) let owner = str2nr(getbufvar(buf, 'syntastic_owner_buffer'))
let buffers = syntastic#util#unique(map(loclist, 'v:val["bufnr"]') + (owner ? [owner] : [])) let buffers = syntastic#util#unique(map(loclist, 'v:val["bufnr"]') + (owner ? [owner] : []))
if !empty(get(w:, 'syntastic_loclist_set', [])) && !empty(loclist) && empty(filter( buffers, 'syntastic#util#bufIsActive(v:val)' )) if !empty(get(w:, 'syntastic_loclist_set', [])) && !empty(loclist) && empty(filter( buffers, 'syntastic#util#bufIsActive(v:val)' ))
call SyntasticLoclistHide() call SyntasticLoclistHide()
@ -299,7 +310,7 @@ function! s:BufEnterHook() abort " {{{2
endfunction " }}}2 endfunction " }}}2
function! s:QuitPreHook(fname) abort " {{{2 function! s:QuitPreHook(fname) abort " {{{2
let buf = bufnr(fnameescape(a:fname)) let buf = syntastic#util#fname2buf(a:fname)
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, 'autocmd: QuitPre, buffer ' . buf . ' = ' . string(a:fname)) call syntastic#log#debug(g:_SYNTASTIC_DEBUG_AUTOCOMMANDS, 'autocmd: QuitPre, buffer ' . buf . ' = ' . string(a:fname))
if !syntastic#util#var('check_on_wq') if !syntastic#util#var('check_on_wq')
@ -317,7 +328,7 @@ endfunction " }}}2
" Main {{{1 " Main {{{1
"refresh and redraw all the error info for this buf when saving or reading "refresh and redraw all the error info for this buf when saving or reading
function! s:UpdateErrors(auto_invoked, checker_names) abort " {{{2 function! s:UpdateErrors(buf, auto_invoked, checker_names) abort " {{{2
call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'version') call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'version')
call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, s:_DEBUG_DUMP_OPTIONS) call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, s:_DEBUG_DUMP_OPTIONS)
call syntastic#log#debugDump(g:_SYNTASTIC_DEBUG_VARIABLES) call syntastic#log#debugDump(g:_SYNTASTIC_DEBUG_VARIABLES)
@ -326,14 +337,14 @@ function! s:UpdateErrors(auto_invoked, checker_names) abort " {{{2
call s:modemap.synch() call s:modemap.synch()
if s:_skip_file() if s:_skip_file(a:buf)
return return
endif endif
let run_checks = !a:auto_invoked || s:modemap.doAutoChecking() let run_checks = !a:auto_invoked || s:modemap.doAutoChecking()
if run_checks if run_checks
call s:CacheErrors(a:checker_names) call s:CacheErrors(a:buf, a:checker_names)
call syntastic#util#setChangedtick() call syntastic#util#setChangedtick(a:buf)
else else
if a:auto_invoked if a:auto_invoked
return return
@ -361,9 +372,9 @@ function! s:UpdateErrors(auto_invoked, checker_names) abort " {{{2
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: setloclist (new)') call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: setloclist (new)')
call setloclist(0, loclist.getRaw()) call setloclist(0, loclist.getRaw())
if !exists('b:syntastic_changedtick') if !exists('b:syntastic_changedtick')
call syntastic#util#setChangedtick() call syntastic#util#setChangedtick(a:buf)
endif endif
let w:syntastic_loclist_set = [bufnr(''), b:syntastic_changedtick] let w:syntastic_loclist_set = [a:buf, b:syntastic_changedtick]
if run_checks && do_jump && !loclist.isEmpty() if run_checks && do_jump && !loclist.isEmpty()
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: jump') call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: jump')
execute 'silent! lrewind ' . do_jump execute 'silent! lrewind ' . do_jump
@ -383,19 +394,22 @@ function! s:UpdateErrors(auto_invoked, checker_names) abort " {{{2
endfunction " }}}2 endfunction " }}}2
"clear the loc list for the buffer "clear the loc list for the buffer
function! s:ClearCache() abort " {{{2 function! s:ClearCache(buf) abort " {{{2
call s:notifiers.reset(g:SyntasticLoclist.current()) call s:notifiers.reset(g:SyntasticLoclist.current())
call b:syntastic_loclist.destroy() let loclist = getbufvar(a:buf, 'syntastic_loclist')
if type(loclist) == type({})
call loclist.destroy()
endif
endfunction " }}}2 endfunction " }}}2
"detect and cache all syntax errors in this buffer "detect and cache all syntax errors in this buffer
function! s:CacheErrors(checker_names) abort " {{{2 function! s:CacheErrors(buf, checker_names) abort " {{{2
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: ' . call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'CacheErrors: ' .
\ (len(a:checker_names) ? join(a:checker_names) : 'default checkers')) \ (len(a:checker_names) ? join(a:checker_names) : 'default checkers'))
call s:ClearCache() call s:ClearCache(a:buf)
let newLoclist = g:SyntasticLoclist.New([]) let newLoclist = g:SyntasticLoclist.New([])
if !s:_skip_file() if !s:_skip_file(a:buf)
" debug logging {{{3 " debug logging {{{3
call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'aggregate_errors') call syntastic#log#debugShowVariables(g:_SYNTASTIC_DEBUG_TRACE, 'aggregate_errors')
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$PATH = ' . string($PATH)) call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$PATH = ' . string($PATH))
@ -660,10 +674,10 @@ function! s:_is_quitting(buf) abort " {{{2
endfunction " }}}2 endfunction " }}}2
" Skip running in special buffers " Skip running in special buffers
function! s:_skip_file() abort " {{{2 function! s:_skip_file(buf) abort " {{{2
let fname = expand('%', 1) let fname = bufname(a:buf)
let skip = s:_is_quitting(bufnr('%')) || get(b:, 'syntastic_skip_checks', 0) || let skip = s:_is_quitting(a:buf) || getbufvar(a:buf, 'syntastic_skip_checks') ||
\ (&buftype !=# '') || !filereadable(fname) || getwinvar(0, '&diff') || \ (getbufvar(a:buf, '&buftype') !=# '') || !filereadable(fname) || getwinvar(0, '&diff') ||
\ getwinvar(0, '&previewwindow') || s:_ignore_file(fname) || \ getwinvar(0, '&previewwindow') || s:_ignore_file(fname) ||
\ fnamemodify(fname, ':e') =~? g:syntastic_ignore_extensions \ fnamemodify(fname, ':e') =~? g:syntastic_ignore_extensions
if skip if skip
@ -674,17 +688,19 @@ endfunction " }}}2
" Explain why checks will be skipped for the current file " Explain why checks will be skipped for the current file
function! s:_explain_skip(filetypes) abort " {{{2 function! s:_explain_skip(filetypes) abort " {{{2
if empty(a:filetypes) && s:_skip_file() let buf = bufnr('')
if empty(a:filetypes) && s:_skip_file(buf)
let why = [] let why = []
let fname = expand('%', 1) let fname = bufname(buf)
let bt = getbufvar(buf, '&buftype')
if s:_is_quitting(bufnr('%')) if s:_is_quitting(buf)
call add(why, 'quitting buffer') call add(why, 'quitting buffer')
endif endif
if get(b:, 'syntastic_skip_checks', 0) if getbufvar(buf, 'syntastic_skip_checks')
call add(why, 'b:syntastic_skip_checks set') call add(why, 'b:syntastic_skip_checks set')
endif endif
if &buftype !=# '' if bt !=# ''
call add(why, 'buftype = ' . string(&buftype)) call add(why, 'buftype = ' . string(&buftype))
endif endif
if !filereadable(fname) if !filereadable(fname)

View File

@ -293,12 +293,13 @@ function! g:SyntasticLoclist.setloclist() abort " {{{2
if !exists('w:syntastic_loclist_set') if !exists('w:syntastic_loclist_set')
let w:syntastic_loclist_set = [] let w:syntastic_loclist_set = []
endif endif
if empty(w:syntastic_loclist_set) || w:syntastic_loclist_set != [bufnr(''), b:changedtick] let buf = bufnr('')
if empty(w:syntastic_loclist_set) || w:syntastic_loclist_set != [buf, getbufvar(buf, 'changedtick')]
let replace = g:syntastic_reuse_loc_lists && !empty(w:syntastic_loclist_set) let replace = g:syntastic_reuse_loc_lists && !empty(w:syntastic_loclist_set)
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: setloclist ' . (replace ? '(replace)' : '(new)')) call syntastic#log#debug(g:_SYNTASTIC_DEBUG_NOTIFICATIONS, 'loclist: setloclist ' . (replace ? '(replace)' : '(new)'))
call setloclist(0, self.getRaw(), replace ? 'r' : ' ') call setloclist(0, self.getRaw(), replace ? 'r' : ' ')
call syntastic#util#setChangedtick() call syntastic#util#setChangedtick(buf)
let w:syntastic_loclist_set = [bufnr(''), b:syntastic_changedtick] let w:syntastic_loclist_set = [buf, getbufvar(buf, 'syntastic_changedtick')]
endif endif
endfunction " }}}2 endfunction " }}}2