diff --git a/autoload/syntastic.vim b/autoload/syntastic.vim new file mode 100644 index 00000000..2849417b --- /dev/null +++ b/autoload/syntastic.vim @@ -0,0 +1,26 @@ +if !has('balloon_eval') + finish +endif + +function! syntastic#ErrorBalloonExpr() + if !exists('b:syntastic_balloons') | return '' | endif + return get(b:syntastic_balloons, v:beval_lnum, '') +endfunction + +function! syntastic#HighlightErrors(errors, termfunc) + call clearmatches() + for item in a:errors + if item['col'] + let lastcol = col([item['lnum'], '$']) + let lcol = min([lastcol, item['col']]) + call matchadd('SpellBad', '\%'.item['lnum'].'l\%'.lcol.'c') + else + let group = item['type'] == 'E' ? 'SpellBad' : 'SpellCap' + let term = a:termfunc(item) + if len(term) > 0 + call matchadd(group, '\%' . item['lnum'] . 'l' . term) + endif + endif + endfor +endfunction + diff --git a/plugin/syntastic.vim b/plugin/syntastic.vim index a620eb8c..f2508368 100644 --- a/plugin/syntastic.vim +++ b/plugin/syntastic.vim @@ -23,6 +23,10 @@ if !exists("g:syntastic_enable_signs") || !has('signs') let g:syntastic_enable_signs = 0 endif +if !exists("g:syntastic_enable_balloons") || !has('balloon_eval') + let g:syntastic_enable_balloons = 0 +endif + if !exists("g:syntastic_auto_loc_list") let g:syntastic_auto_loc_list = 0 endif @@ -54,6 +58,14 @@ function! s:UpdateErrors() endif call s:CacheErrors() + if g:syntastic_enable_balloons + let b:syntastic_balloons = {} + for i in b:syntastic_loclist + let b:syntastic_balloons[i['lnum']] = i['text'] + endfor + set beval bexpr=syntastic#ErrorBalloonExpr() + endif + if g:syntastic_enable_signs call s:RefreshSigns() endif diff --git a/syntax_checkers/html.vim b/syntax_checkers/html.vim index 0f26493e..550c786b 100644 --- a/syntax_checkers/html.vim +++ b/syntax_checkers/html.vim @@ -19,11 +19,30 @@ if !executable("tidy") || !executable("grep") finish endif +" TODO: join this with xhtml.vim for DRY's sake? +function! s:TidyEncOptByFenc() + let tidy_opts = { + \'utf-8' : '-utf8', + \'ascii' : '-ascii', + \'latin1' : '-latin1', + \'iso-2022-jp' : '-iso-2022', + \'cp1252' : '-win1252', + \'macroman' : '-mac', + \'utf-16le' : '-utf16le', + \'utf-16' : '-utf16', + \'big5' : '-big5', + \'sjis' : '-shiftjis', + \'cp850' : '-ibm858', + \} + return get(tidy_opts, &fileencoding, '-utf8') +endfunction + function! SyntaxCheckers_html_GetLocList() "grep out the ' lacks "summary" attribute' since it is almost "always present and almost always useless - let makeprg="tidy --new-blocklevel-tags 'section, article, aside, hgroup, header, footer, nav, figure, figcaption' --new-inline-tags 'video, audio, embed, mark, progress, meter, time, ruby, rt, rp, canvas, command, details, datalist' --new-empty-tags 'wbr, keygen' -e ".shellescape(expand('%'))." 2>&1 \\| grep -v '\ lacks \"summary\" attribute' \\| grep -v 'not approved by W3C'" + let encopt = s:TidyEncOptByFenc() + let makeprg="tidy ".encopt." --new-blocklevel-tags 'section, article, aside, hgroup, header, footer, nav, figure, figcaption' --new-inline-tags 'video, audio, embed, mark, progress, meter, time, ruby, rt, rp, canvas, command, details, datalist' --new-empty-tags 'wbr, keygen' -e ".shellescape(expand('%'))." 2>&1 \\| grep -v '\ lacks \"summary\" attribute' \\| grep -v 'not approved by W3C'" let errorformat='%Wline %l column %c - Warning: %m,%Eline %l column %c - Error: %m,%-G%.%#,%-G%.%#' let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) diff --git a/syntax_checkers/lua.vim b/syntax_checkers/lua.vim index 63c724ac..426db88c 100644 --- a/syntax_checkers/lua.vim +++ b/syntax_checkers/lua.vim @@ -20,18 +20,43 @@ if !executable('luac') finish endif +function! SyntaxCheckers_lua_Term(pos) + let near = matchstr(a:pos['text'], "near '[^']\\+'") + let result = '' + if len(near) > 0 + let near = split(near, "'")[1] + if near == '' + let p = getpos('$') + let a:pos['lnum'] = p[1] + let a:pos['col'] = p[2] + let result = '\%'.p[2].'c' + else + let result = '\V'.near + endif + let open = matchstr(a:pos['text'], "(to close '[^']\\+' at line [0-9]\\+)") + if len(open) > 0 + let oline = split(open, "'")[1:2] + let line = 0+strpart(oline[1], 9) + call matchadd('SpellCap', '\%'.line.'l\V'.oline[0]) + endif + endif + return result +endfunction + function! SyntaxCheckers_lua_GetLocList() let makeprg = 'luac -p ' . shellescape(expand('%')) let errorformat = 'luac: %#%f:%l: %m' let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) - let bn = bufnr('') - for loc in loclist - let loc['bufnr'] = bn - let loc['type'] = 'E' + let bufn = bufnr('') + for pos in loclist + let pos['bufnr'] = bufn + let pos['type'] = 'E' endfor + call syntastic#HighlightErrors(loclist, function("SyntaxCheckers_lua_Term")) + return loclist endfunction diff --git a/syntax_checkers/php.vim b/syntax_checkers/php.vim index 33a339cd..1092b752 100644 --- a/syntax_checkers/php.vim +++ b/syntax_checkers/php.vim @@ -19,8 +19,18 @@ if !executable("php") finish endif +function! SyntaxCheckers_php_Term(item) + let unexpected = matchstr(a:item['text'], "unexpected '[^']\\+'") + if len(unexpected) < 1 | return '' | end + return '\V'.split(unexpected, "'")[1] +endfunction + function! SyntaxCheckers_php_GetLocList() let makeprg = "php -l ".shellescape(expand('%')) let errorformat='%-GNo syntax errors detected in%.%#,PHP Parse error: %#syntax %trror\, %m in %f on line %l,PHP Fatal %trror: %m in %f on line %l,%-GErrors parsing %.%#,%-G\s%#,Parse error: %#syntax %trror\, %m in %f on line %l,Fatal %trror: %m in %f on line %l' - return SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) + let errors = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) + + call syntastic#HighlightErrors(errors, function('SyntaxCheckers_php_Term')) + + return errors endfunction diff --git a/syntax_checkers/python.vim b/syntax_checkers/python.vim index 10abe7f1..5622f34a 100644 --- a/syntax_checkers/python.vim +++ b/syntax_checkers/python.vim @@ -8,17 +8,28 @@ if !executable("pyflakes") finish endif +function! SyntaxCheckers_python_Term(i) + if a:i['type'] ==# 'E' + let a:i['text'] = "Syntax error" + endif + if match(a:i['text'], 'is assigned to but never used') > -1 + \ || match(a:i['text'], 'imported but unused') > -1 + \ || match(a:i['text'], 'undefined name') > -1 + \ || match(a:i['text'], 'redefinition of unused') > -1 + + let term = split(a:i['text'], "'", 1)[1] + return '\V'.term + endif + return '' +endfunction + function! SyntaxCheckers_python_GetLocList() let makeprg = 'pyflakes '.shellescape(expand('%')) let errorformat = '%E%f:%l: could not compile,%-Z%p^,%W%f:%l: %m,%-G%.%#' let errors = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) - for i in errors - if i['type'] ==# 'E' - let i['text'] = "Syntax error" - endif - endfor + call syntastic#HighlightErrors(errors, function('SyntaxCheckers_python_Term')) return errors endfunction diff --git a/syntax_checkers/xhtml.vim b/syntax_checkers/xhtml.vim index 399e035c..409347f9 100644 --- a/syntax_checkers/xhtml.vim +++ b/syntax_checkers/xhtml.vim @@ -19,9 +19,28 @@ if !executable("tidy") finish endif +" TODO: join this with html.vim DRY's sake? +function! s:TidyEncOptByFenc() + let tidy_opts = { + \'utf-8' : '-utf8', + \'ascii' : '-ascii', + \'latin1' : '-latin1', + \'iso-2022-jp' : '-iso-2022', + \'cp1252' : '-win1252', + \'macroman' : '-mac', + \'utf-16le' : '-utf16le', + \'utf-16' : '-utf16', + \'big5' : '-big5', + \'sjis' : '-shiftjis', + \'cp850' : '-ibm858', + \} + return get(tidy_opts, &fileencoding, '-utf8') +endfunction + function! SyntaxCheckers_xhtml_GetLocList() - let makeprg="tidy -xml -e ".shellescape(expand('%')) + let encopt = s:TidyEncOptByFenc() + let makeprg="tidy ".encopt." -xml -e ".shellescape(expand('%')) let errorformat='%Wline %l column %c - Warning: %m,%Eline %l column %c - Error: %m,%-G%.%#,%-G%.%#' let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat })