Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Async make #370

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/syntastic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ current filetype is set to passive. See |'syntastic_mode_map'| for more info.
4. Options *syntastic-options*


*'syntastic_async'*
Default: 0
If enabled, syntastic will run the checker as a background process, allowing
the user to continue editing while the checker is running. This option depends
on the AsyncCommand package, and vim must be run with the --servername option.>
let g:syntastic_async=1
<

*'syntastic_check_on_open'*
Default: 0
If enabled, syntastic will do syntax checks when buffers are first loaded as
Expand Down
173 changes: 141 additions & 32 deletions plugin/syntastic.vim
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ if !exists("g:syntastic_loc_list_height")
let g:syntastic_loc_list_height = 10
endif

if has("clientserver") && exists("g:loaded_asynccommand") && exists("g:syntastic_async")
let g:syntastic_do_async = 1
endif

command! SyntasticToggleMode call s:ToggleMode()
command! SyntasticCheck call s:UpdateErrors(0) <bar> redraw!
command! Errors call s:ShowLocList()
Expand All @@ -118,15 +122,7 @@ augroup syntastic
augroup END


"refresh and redraw all the error info for this buf when saving or reading
function! s:UpdateErrors(auto_invoked)
if !empty(&buftype)
return
endif

if !a:auto_invoked || s:ModeMapAllowsAutoChecking()
call s:CacheErrors()
end
function! s:RedrawErrors(bufnr)

call setloclist(0, s:LocList())

Expand All @@ -135,7 +131,7 @@ function! s:UpdateErrors(auto_invoked)
endif

if g:syntastic_enable_signs
call s:RefreshSigns()
call s:RefreshSigns(a:bufnr)
endif

if g:syntastic_enable_highlighting
Expand All @@ -149,6 +145,19 @@ function! s:UpdateErrors(auto_invoked)
call s:AutoToggleLocList()
endfunction

"refresh and redraw all the error info for this buf when saving or reading
function! s:UpdateErrors(auto_invoked)
if !empty(&buftype)
return
endif

if !a:auto_invoked || s:ModeMapAllowsAutoChecking()
call s:CacheErrors()
end

call s:RedrawErrors(bufnr(''))
endfunction

"automatically open/close the location list window depending on the users
"config and buffer error state
function! s:AutoToggleLocList()
Expand Down Expand Up @@ -195,12 +204,20 @@ function! s:CacheErrors()
let fts = substitute(&ft, '-', '_', 'g')
for ft in split(fts, '\.')
if SyntasticCheckable(ft)
let errors = SyntaxCheckers_{ft}_GetLocList()
"keep only lines that effectively match an error/warning
let errors = s:FilterLocList({'valid': 1}, errors)
"make errors have type "E" by default
call SyntasticAddToErrors(errors, {'type': 'E'})
call extend(s:LocList(), errors)
if exists("g:syntastic_do_async") && exists("g:async_".ft."_syntax_checker")
call SyntaxCheckers_{ft}_GetLocList()
else
let errors = SyntaxCheckers_{ft}_GetLocList()
if exists("*SyntaxCheckers_".ft."_PostProcess")
let errors = SyntaxCheckers_{ft}_PostProcess(errors)
endif
let errors = SyntaxCheckers_{ft}_GetLocList()
"keep only lines that effectively match an error/warning
let errors = s:FilterLocList({'valid': 1}, errors)
"make errors have type "E" by default
call SyntasticAddToErrors(errors, {'type': 'E'})
call extend(s:LocList(), errors)
endif
endif
endfor
endif
Expand Down Expand Up @@ -301,10 +318,10 @@ let s:first_sign_id = 5000
let s:next_sign_id = s:first_sign_id

"place signs by all syntax errs in the buffer
function! s:SignErrors()
function! s:SignErrors(bufnr)
if s:BufHasErrorsOrWarningsToDisplay()

let errors = s:FilterLocList({'bufnr': bufnr('')})
let errors = s:FilterLocList({'bufnr': a:bufnr})
for i in errors
let sign_severity = 'Error'
let sign_subtype = ''
Expand All @@ -317,8 +334,8 @@ function! s:SignErrors()
let sign_type = 'Syntastic' . sign_subtype . sign_severity

if !s:WarningMasksError(i, errors)
exec "sign place ". s:next_sign_id ." line=". i['lnum'] ." name=". sign_type ." file=". expand("%:p")
call add(s:BufSignIds(), s:next_sign_id)
exec "sign place ". s:next_sign_id ." line=". i['lnum'] ." name=". sign_type ." buffer=".a:bufnr
call add(s:BufSignIds(a:bufnr), s:next_sign_id)
let s:next_sign_id += 1
endif
endfor
Expand All @@ -336,26 +353,29 @@ function! s:WarningMasksError(error, llist)
endfunction

"remove the signs with the given ids from this buffer
function! s:RemoveSigns(ids)
function! s:RemoveSigns(ids, bufnr)
for i in a:ids
exec "sign unplace " . i
call remove(s:BufSignIds(), index(s:BufSignIds(), i))
exec "sign unplace " . i." buffer=".a:bufnr
call remove(s:BufSignIds(a:bufnr), index(s:BufSignIds(a:bufnr), i))
endfor
endfunction

"get all the ids of the SyntaxError signs in the buffer
function! s:BufSignIds()
if !exists("b:syntastic_sign_ids")
let b:syntastic_sign_ids = []
function! s:BufSignIds(bufnr)
if !exists("t:syntastic_sign_ids")
let t:syntastic_sign_ids = { }
endif
if !exists("t:syntastic_sign_ids['".bufname(a:bufnr)."']")
let t:syntastic_sign_ids[bufname(a:bufnr)] = []
endif
return b:syntastic_sign_ids
return t:syntastic_sign_ids[bufname(a:bufnr)]
endfunction

"update the error signs
function! s:RefreshSigns()
let old_signs = copy(s:BufSignIds())
call s:SignErrors()
call s:RemoveSigns(old_signs)
function! s:RefreshSigns(bufnr)
let old_signs = copy(s:BufSignIds(a:bufnr))
call s:SignErrors(a:bufnr)
call s:RemoveSigns(old_signs, a:bufnr)
let s:first_sign_id = s:next_sign_id
endfunction

Expand Down Expand Up @@ -573,7 +593,7 @@ endfunction
"a:options may also contain:
" 'defaults' - a dict containing default values for the returned errors
" 'subtype' - all errors will be assigned the given subtype
function! SyntasticMake(options)
function! SyntasticLocalMake(options)
let old_loclist = getloclist(0)
let old_makeprg = &l:makeprg
let old_shellpipe = &shellpipe
Expand Down Expand Up @@ -620,6 +640,95 @@ function! SyntasticMake(options)
return errors
endfunction

function! SyntasticRemoteMake(options)
if has_key(a:options, 'makeprg')
let makeprg = a:options['makeprg']
else
let makeprg = &makeprg
endif

if has_key(a:options, 'errorformat')
let efm = a:options['errorformat']
else
let efm = &errorformat
endif

let async_cmd = substitute(makeprg, '\\|', '\|', "g")
let async_env = { 'efm' : efm , 'checker': a:options['checker'] , 'bufnr': bufnr('')}

if has_key(a:options, 'defaults')
let async_env['defaults'] = a:options['defaults']
endif

" Add subtype info if present.
if has_key(a:options, 'subtype')
let async_env['subtype'] = a:options['subtype']
endif

function async_env.get(temp_file) dict
let old_loclist = getloclist(0)
let old_makeprg = &l:makeprg
let old_shellpipe = &shellpipe
let old_shell = &shell
let old_errorformat = &l:errorformat

if !s:running_windows && (s:uname !~ "FreeBSD")
"this is a hack to stop the screen needing to be ':redraw'n when
"when :lmake is run. Otherwise the screen flickers annoyingly
let &shellpipe='&>'
let &shell = '/bin/bash'
endif

" lget error file
let &errorformat = self.efm
let cmd = 'lgetfile ' . a:temp_file
exe cmd
let errors = getloclist(0)

call setloclist(0, old_loclist)
let &l:makeprg = old_makeprg
let &l:errorformat = old_errorformat
let &shellpipe=old_shellpipe
let &shell=old_shell

if !s:running_windows && s:uname =~ "FreeBSD"
redraw!
endif

if has_key(self, 'defaults')
call SyntasticAddToErrors(errors, self['defaults'])
endif

" Add subtype info if present.
if has_key(self, 'subtype')
call SyntasticAddToErrors(errors, {'subtype': self['subtype']})
endif

if exists('*SyntaxCheckers_'.self.checker.'_PostProcess')
let errors = SyntaxCheckers_{self.checker}_PostProcess(errors)
endif
"keep only lines that effectively match an error/warning
let errors = s:FilterLocList({'valid': 1}, errors)
"make errors have type "E" by default
call SyntasticAddToErrors(errors, {'type': 'E'})
call extend(s:LocList(), errors)

call s:RedrawErrors(self.bufnr)
endfunction
" tab_restore prevents interruption when the task completes.
" All provided asynchandlers already use tab_restore.
call asynccommand#run(async_cmd, asynccommand#tab_restore(async_env))
endfunction

function! SyntasticMake(options)
if exists("g:syntastic_do_async") && exists("a:options['checker']") &&
\ exists("g:async_".a:options['checker']."_syntax_checker")
call SyntasticRemoteMake(a:options)
else
return SyntasticLocalMake(a:options)
endif
endfunction

"get the error balloon for the current mouse position
function! SyntasticErrorBalloonExpr()
if !exists('b:syntastic_balloons')
Expand Down
3 changes: 2 additions & 1 deletion syntax_checkers/css.vim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ if exists("loaded_css_syntax_checker")
finish
endif
let loaded_css_syntax_checker = 1
let async_css_syntax_checker = 1

if !exists('g:syntastic_csslint_options')
let g:syntastic_csslint_options = ""
Expand All @@ -35,7 +36,7 @@ function! SyntaxCheckers_css_GetLocList()
" Print CSS Lint's error/warning messages from compact format. Ignores blank lines.
let errorformat = '%-G,%-G%f: lint free!,%f: line %l\, col %c\, %trror - %m,%f: line %l\, col %c\, %tarning - %m,%f: line %l\, col %c\, %m,'

return SyntasticMake({ 'makeprg': makeprg,
return SyntasticMake({ 'checker': 'css', 'makeprg': makeprg,
\ 'errorformat': errorformat,
\ 'defaults': {'bufnr': bufnr("")} })

Expand Down
25 changes: 15 additions & 10 deletions syntax_checkers/html/tidy.vim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"
"============================================================================
" TODO: join this with xhtml.vim for DRY's sake?

let async_html_syntax_checker = 1

function! s:TidyEncOptByFenc()
let tidy_opts = {
\'utf-8' : '-utf8',
Expand Down Expand Up @@ -52,23 +55,25 @@ function! SyntaxCheckers_html_GetLocList()
let encopt = s:TidyEncOptByFenc()
let makeprg="tidy ".encopt." --new-blocklevel-tags ".shellescape('section, article, aside, hgroup, header, footer, nav, figure, figcaption')." --new-inline-tags ".shellescape('video, audio, source, embed, mark, progress, meter, time, ruby, rt, rp, canvas, command, details, datalist')." --new-empty-tags ".shellescape('wbr, keygen')." -e ".shellescape(expand('%'))." 2>&1"
let errorformat='%Wline %l column %c - Warning: %m,%Eline %l column %c - Error: %m,%-G%.%#,%-G%.%#'
let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat })

" process loclist since we need to add some info and filter out valid HTML5
return SyntasticMake({ 'makeprg': makeprg,
\ 'errorformat': errorformat,
\ 'checker': 'html',
\ 'defaults': {'bufnr': bufnr("")} })
endfunction

function! SyntaxCheckers_html_PostProcess(loclist)
" process a:loclist since we need to add some info and filter out valid HTML5
" from the errors
let n = len(loclist) - 1
let bufnum = bufnr("")
let n = len(a:loclist) - 1
while n >= 0
let i = loclist[n]
let i = a:loclist[n]
" filter out valid HTML5
if s:ValidateError(i['text']) == 1
unlet loclist[n]
else
"the file name isnt in the output so stick in the buf num manually
let i['bufnr'] = bufnum
unlet a:loclist[n]
endif
let n -= 1
endwhile

return loclist
return a:loclist
endfunction