diff options
Diffstat (limited to 'vim/bundle/syntastic/autoload')
| -rw-r--r-- | vim/bundle/syntastic/autoload/syntastic/c.vim | 341 | ||||
| -rw-r--r-- | vim/bundle/syntastic/autoload/syntastic/log.vim | 222 | ||||
| -rw-r--r-- | vim/bundle/syntastic/autoload/syntastic/postprocess.vim | 73 | ||||
| -rw-r--r-- | vim/bundle/syntastic/autoload/syntastic/preprocess.vim | 614 | ||||
| -rw-r--r-- | vim/bundle/syntastic/autoload/syntastic/util.vim | 552 | 
5 files changed, 1802 insertions, 0 deletions
| diff --git a/vim/bundle/syntastic/autoload/syntastic/c.vim b/vim/bundle/syntastic/autoload/syntastic/c.vim new file mode 100644 index 0000000..e49a29a --- /dev/null +++ b/vim/bundle/syntastic/autoload/syntastic/c.vim @@ -0,0 +1,341 @@ +if exists('g:loaded_syntastic_c_autoload') || !exists('g:loaded_syntastic_plugin') +    finish +endif +let g:loaded_syntastic_c_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +" Public functions {{{1 + +" convenience function to determine the 'null device' parameter +" based on the current operating system +function! syntastic#c#NullOutput() abort " {{{2 +    let known_os = has('unix') || has('mac') || syntastic#util#isRunningWindows() +    return known_os ? '-o ' . syntastic#util#DevNull() : '' +endfunction " }}}2 + +" read additional compiler flags from the given configuration file +" the file format and its parsing mechanism is inspired by clang_complete +function! syntastic#c#ReadConfig(file) abort " {{{2 +    call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: looking for', a:file) + +    " search upwards from the current file's directory +    let config = syntastic#util#findFileInParent(a:file, expand('%:p:h', 1)) +    if config ==# '' +        call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: file not found') +        return '' +    endif +    call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: config file:', config) +    if !filereadable(config) +        call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: file unreadable') +        return '' +    endif + +    " convert filename into absolute path +    let filepath = fnamemodify(config, ':p:h') + +    " try to read config file +    try +        let lines = readfile(config) +    catch /\m^Vim\%((\a\+)\)\=:E48[45]/ +        call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, 'ReadConfig: error reading file') +        return '' +    endtry + +    " filter out empty lines and comments +    call filter(lines, 'v:val !~# ''\v^(\s*#|$)''') + +    " remove leading and trailing spaces +    call map(lines, 'substitute(v:val, ''\m^\s\+'', "", "")') +    call map(lines, 'substitute(v:val, ''\m\s\+$'', "", "")') + +    let parameters = [] +    for line in lines +        let matches = matchstr(line, '\m\C^\s*-I\s*\zs.\+') +        if matches !=# '' +            " this one looks like an absolute path +            if match(matches, '\m^\%(/\|\a:\)') != -1 +                call add(parameters, '-I' . matches) +            else +                call add(parameters, '-I' . filepath . syntastic#util#Slash() . matches) +            endif +        else +            call add(parameters, line) +        endif +    endfor + +    return join(map(parameters, 'syntastic#util#shescape(v:val)')) +endfunction " }}}2 + +" GetLocList() for C-like compilers +function! syntastic#c#GetLocList(filetype, subchecker, options) abort " {{{2 +    try +        let flags = s:_get_cflags(a:filetype, a:subchecker, a:options) +    catch /\m\C^Syntastic: skip checks$/ +        return [] +    endtry + +    let makeprg = syntastic#util#shexpand(g:syntastic_{a:filetype}_compiler) . +        \ ' ' . flags . ' ' . syntastic#util#shexpand('%') + +    let errorformat = s:_get_checker_var('g', a:filetype, a:subchecker, 'errorformat', a:options['errorformat']) + +    let postprocess = s:_get_checker_var('g', a:filetype, a:subchecker, 'remove_include_errors', 0) ? +        \ ['filterForeignErrors'] : [] + +    " process makeprg +    return SyntasticMake({ +        \ 'makeprg': makeprg, +        \ 'errorformat': errorformat, +        \ 'postprocess': postprocess }) +endfunction " }}}2 + +" }}}1 + +" Private functions {{{1 + +" initialize c/cpp syntax checker handlers +function! s:_init() abort " {{{2 +    let s:handlers = [] +    let s:cflags = {} + +    call s:_registerHandler('\m\<cairo',       's:_checkPackage', ['cairo', 'cairo']) +    call s:_registerHandler('\m\<freetype',    's:_checkPackage', ['freetype', 'freetype2', 'freetype']) +    call s:_registerHandler('\m\<glade',       's:_checkPackage', ['glade', 'libglade-2.0', 'libglade']) +    call s:_registerHandler('\m\<glib',        's:_checkPackage', ['glib', 'glib-2.0', 'glib']) +    call s:_registerHandler('\m\<gtk',         's:_checkPackage', ['gtk', 'gtk+-2.0', 'gtk+', 'glib-2.0', 'glib']) +    call s:_registerHandler('\m\<libsoup',     's:_checkPackage', ['libsoup', 'libsoup-2.4', 'libsoup-2.2']) +    call s:_registerHandler('\m\<libxml',      's:_checkPackage', ['libxml', 'libxml-2.0', 'libxml']) +    call s:_registerHandler('\m\<pango',       's:_checkPackage', ['pango', 'pango']) +    call s:_registerHandler('\m\<SDL',         's:_checkPackage', ['sdl', 'sdl']) +    call s:_registerHandler('\m\<opengl',      's:_checkPackage', ['opengl', 'gl']) +    call s:_registerHandler('\m\<webkit',      's:_checkPackage', ['webkit', 'webkit-1.0']) + +    call s:_registerHandler('\m\<php\.h\>',    's:_checkPhp',    []) +    call s:_registerHandler('\m\<Python\.h\>', 's:_checkPython', []) +    call s:_registerHandler('\m\<ruby',        's:_checkRuby',   []) +endfunction " }}}2 + +" register a handler dictionary object +function! s:_registerHandler(regex, function, args) abort " {{{2 +    let handler = {} +    let handler['regex'] = a:regex +    let handler['func'] = function(a:function) +    let handler['args'] = a:args +    call add(s:handlers, handler) +endfunction " }}}2 + +" try to find library with 'pkg-config' +" search possible libraries from first to last given +" argument until one is found +function! s:_checkPackage(name, ...) abort " {{{2 +    if executable('pkg-config') +        if !has_key(s:cflags, a:name) +            for pkg in a:000 +                let pkg_flags = syntastic#util#system('pkg-config --cflags ' . pkg) +                " since we cannot necessarily trust the pkg-config exit code +                " we have to check for an error output as well +                if v:shell_error == 0 && pkg_flags !~? 'not found' +                    let pkg_flags = ' ' . substitute(pkg_flags, "\n", '', '') +                    let s:cflags[a:name] = pkg_flags +                    return pkg_flags +                endif +            endfor +        else +            return s:cflags[a:name] +        endif +    endif +    return '' +endfunction " }}}2 + +" try to find PHP includes with 'php-config' +function! s:_checkPhp() abort " {{{2 +    if executable('php-config') +        if !has_key(s:cflags, 'php') +            let s:cflags['php'] = syntastic#util#system('php-config --includes') +            let s:cflags['php'] = ' ' . substitute(s:cflags['php'], "\n", '', '') +        endif +        return s:cflags['php'] +    endif +    return '' +endfunction " }}}2 + +" try to find the python headers with distutils +function! s:_checkPython() abort " {{{2 +    if executable('python') +        if !has_key(s:cflags, 'python') +            let s:cflags['python'] = syntastic#util#system('python -c ''from distutils import ' . +                \ 'sysconfig; import sys; sys.stdout.write(sysconfig.get_python_inc())''') +            let s:cflags['python'] = substitute(s:cflags['python'], "\n", '', '') +            let s:cflags['python'] = ' -I' . s:cflags['python'] +        endif +        return s:cflags['python'] +    endif +    return '' +endfunction " }}}2 + +" try to find the ruby headers with 'rbconfig' +function! s:_checkRuby() abort " {{{2 +    if executable('ruby') +        if !has_key(s:cflags, 'ruby') +            let s:cflags['ruby'] = syntastic#util#system('ruby -r rbconfig -e ' . +                \ '''puts RbConfig::CONFIG["rubyhdrdir"] || RbConfig::CONFIG["archdir"]''') +            let s:cflags['ruby'] = substitute(s:cflags['ruby'], "\n", '', '') +            let s:cflags['ruby'] = ' -I' . s:cflags['ruby'] +        endif +        return s:cflags['ruby'] +    endif +    return '' +endfunction " }}}2 + +" }}}1 + +" Utilities {{{1 + +" resolve checker-related user variables +function! s:_get_checker_var(scope, filetype, subchecker, name, default) abort " {{{2 +    let prefix = a:scope . ':' . 'syntastic_' +    if exists(prefix . a:filetype . '_' . a:subchecker . '_' . a:name) +        return {a:scope}:syntastic_{a:filetype}_{a:subchecker}_{a:name} +    elseif exists(prefix . a:filetype . '_' . a:name) +        return {a:scope}:syntastic_{a:filetype}_{a:name} +    else +        return a:default +    endif +endfunction " }}}2 + +" resolve user CFLAGS +function! s:_get_cflags(ft, ck, opts) abort " {{{2 +    " determine whether to parse header files as well +    if has_key(a:opts, 'header_names') && expand('%', 1) =~? a:opts['header_names'] +        if s:_get_checker_var('g', a:ft, a:ck, 'check_header', 0) +            let flags = get(a:opts, 'header_flags', '') . ' -c ' . syntastic#c#NullOutput() +        else +            " checking headers when check_header is unset: bail out +            throw 'Syntastic: skip checks' +        endif +    else +        let flags = get(a:opts, 'main_flags', '') +    endif + +    let flags .= ' ' . s:_get_checker_var('g', a:ft, a:ck, 'compiler_options', '') . ' ' . s:_get_include_dirs(a:ft) + +    " check if the user manually set some cflags +    let b_cflags = s:_get_checker_var('b', a:ft, a:ck, 'cflags', '') +    if b_cflags !=# '' +        let flags .= ' ' . b_cflags +    endif + +    " add optional config file parameters +    let config_file = s:_get_checker_var('g', a:ft, a:ck, 'config_file', '.syntastic_' . a:ft . '_config') +    let flags .= ' ' . syntastic#c#ReadConfig(config_file) + +    if b_cflags ==# '' && (a:ft ==# 'c' || a:ft ==# 'cpp') && !s:_get_checker_var('g', a:ft, a:ck, 'no_include_search', 0) +        " refresh the include file search if desired +        if s:_get_checker_var('g', a:ft, a:ck, 'auto_refresh_includes', 0) +            let flags .= ' ' . s:_search_headers() +        else +            " search for header includes if not cached already +            if !exists('b:syntastic_' . a:ft . '_includes') +                let b:syntastic_{a:ft}_includes = s:_search_headers() +            endif +            let flags .= ' ' . b:syntastic_{a:ft}_includes +        endif +    endif + +    return flags +endfunction " }}}2 + +" get the gcc include directory argument depending on the default +" includes and the optional user-defined 'g:syntastic_c_include_dirs' +function! s:_get_include_dirs(filetype) abort " {{{2 +    let include_dirs = [] + +    if a:filetype =~# '\v^%(c|cpp|objc|objcpp)$' && +                \ (!exists('g:syntastic_'.a:filetype.'_no_default_include_dirs') || +                \ !g:syntastic_{a:filetype}_no_default_include_dirs) +        let include_dirs = copy(s:default_includes) +    endif + +    if exists('g:syntastic_'.a:filetype.'_include_dirs') +        call extend(include_dirs, g:syntastic_{a:filetype}_include_dirs) +    endif + +    return join(map(syntastic#util#unique(include_dirs), 'syntastic#util#shescape("-I" . v:val)')) +endfunction " }}}2 + +" search the first 100 lines for include statements that are +" given in the handlers dictionary +function! s:_search_headers() abort " {{{2 +    let includes = '' +    let files = [] +    let found = [] +    let lines = filter(getline(1, 100), 'v:val =~# ''\m^\s*#\s*include''') + +    " search current buffer +    for line in lines +        let file = matchstr(line, '\m"\zs\S\+\ze"') +        if file !=# '' +            call add(files, file) +            continue +        endif + +        for handler in s:handlers +            if line =~# handler['regex'] +                let includes .= call(handler['func'], handler['args']) +                call add(found, handler['regex']) +                break +            endif +        endfor +    endfor + +    " search included headers +    for hfile in files +        if hfile !=# '' +            let filename = expand('%:p:h', 1) . syntastic#util#Slash() . hfile + +            try +                let lines = readfile(filename, '', 100) +            catch /\m^Vim\%((\a\+)\)\=:E484/ +                continue +            endtry + +            call filter(lines, 'v:val =~# ''\m^\s*#\s*include''') + +            for handler in s:handlers +                if index(found, handler['regex']) != -1 +                    continue +                endif + +                for line in lines +                    if line =~# handler['regex'] +                        let includes .= call(handler['func'], handler['args']) +                        call add(found, handler['regex']) +                        break +                    endif +                endfor +            endfor +        endif +    endfor + +    return includes +endfunction " }}}2 + +" }}}1 + +" default include directories +let s:default_includes = [ +    \ '.', +    \ '..', +    \ 'include', +    \ 'includes', +    \ '..' . syntastic#util#Slash() . 'include', +    \ '..' . syntastic#util#Slash() . 'includes' ] + +call s:_init() + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/syntastic/autoload/syntastic/log.vim b/vim/bundle/syntastic/autoload/syntastic/log.vim new file mode 100644 index 0000000..5ad562d --- /dev/null +++ b/vim/bundle/syntastic/autoload/syntastic/log.vim @@ -0,0 +1,222 @@ +if exists('g:loaded_syntastic_log_autoload') || !exists('g:loaded_syntastic_plugin') +    finish +endif +let g:loaded_syntastic_log_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +let s:one_time_notices_issued = [] + +" Public functions {{{1 + +function! syntastic#log#info(msg) abort " {{{2 +    echomsg 'syntastic: info: ' . a:msg +endfunction " }}}2 + +function! syntastic#log#warn(msg) abort " {{{2 +    echohl WarningMsg +    echomsg 'syntastic: warning: ' . a:msg +    echohl None +endfunction " }}}2 + +function! syntastic#log#error(msg) abort " {{{2 +    execute "normal \<Esc>" +    echohl ErrorMsg +    echomsg 'syntastic: error: ' . a:msg +    echohl None +endfunction " }}}2 + +function! syntastic#log#oneTimeWarn(msg) abort " {{{2 +    if index(s:one_time_notices_issued, a:msg) >= 0 +        return +    endif + +    call add(s:one_time_notices_issued, a:msg) +    call syntastic#log#warn(a:msg) +endfunction " }}}2 + +" @vimlint(EVL102, 1, l:OLD_VAR) +function! syntastic#log#deprecationWarn(old, new, ...) abort " {{{2 +    if exists('g:syntastic_' . a:old) && !exists('g:syntastic_' . a:new) +        let msg = 'variable g:syntastic_' . a:old . ' is deprecated, please use ' + +        if a:0 +            let OLD_VAR = g:syntastic_{a:old} +            try +                let NEW_VAR = eval(a:1) +                let msg .= 'in its stead: let g:syntastic_' . a:new . ' = ' . string(NEW_VAR) +                let g:syntastic_{a:new} = NEW_VAR +            catch +                let msg .= 'g:syntastic_' . a:new . ' instead' +            endtry +        else +            let msg .= 'g:syntastic_' . a:new . ' instead' +            let g:syntastic_{a:new} = g:syntastic_{a:old} +        endif + +        call syntastic#log#oneTimeWarn(msg) +    endif +endfunction " }}}2 +" @vimlint(EVL102, 0, l:OLD_VAR) + +function! syntastic#log#debug(level, msg, ...) abort " {{{2 +    if !s:_isDebugEnabled(a:level) +        return +    endif + +    let leader = s:_log_timestamp() +    call s:_logRedirect(1) + +    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 + +    call s:_logRedirect(0) +endfunction " }}}2 + +function! syntastic#log#debugShowOptions(level, names) abort " {{{2 +    if !s:_isDebugEnabled(a:level) +        return +    endif + +    let leader = s:_log_timestamp() +    call s:_logRedirect(1) + +    let vlist = copy(type(a:names) == type('') ? [a:names] : a:names) +    let add_shell = index(vlist, 'shell') >= 0 && &shell !=# syntastic#util#var('shell') +    if !empty(vlist) +        call map(vlist, "'&' . v:val . ' = ' . strtrans(string(eval('&' . v:val))) . (s:_is_modified(v:val) ? ' (!)' : '')") +        if add_shell +            call add(vlist, 'u:shell = ' . strtrans(string(syntastic#util#var('shell'))) . ' (!)') +        endif +        echomsg leader . join(vlist, ', ') +    endif +    call s:_logRedirect(0) +endfunction " }}}2 + +function! syntastic#log#debugShowVariables(level, names) abort " {{{2 +    if !s:_isDebugEnabled(a:level) +        return +    endif + +    let leader = s:_log_timestamp() +    call s:_logRedirect(1) + +    let vlist = type(a:names) == type('') ? [a:names] : a:names +    for name in vlist +        let msg = s:_format_variable(name) +        if msg !=# '' +            echomsg leader . msg +        endif +    endfor + +    call s:_logRedirect(0) +endfunction " }}}2 + +function! syntastic#log#debugDump(level) abort " {{{2 +    if !s:_isDebugEnabled(a:level) +        return +    endif + +    call syntastic#log#debugShowVariables( a:level, sort(keys(g:_SYNTASTIC_DEFAULTS)) ) +endfunction " }}}2 + +function! syntastic#log#ndebug(level, title, messages) abort " {{{2 +    if s:_isDebugEnabled(a:level) +        return +    endif + +    call syntastic#log#error(a:title) +    if type(a:messages) == type([]) +        for msg in a:messages +            echomsg msg +        endfor +    else +        echomsg a:messages +    endif +endfunction " }}}2 + +" }}}1 + +" Private functions {{{1 + +function! s:_isDebugEnabled_smart(level) abort " {{{2 +    return and(g:syntastic_debug, a:level) +endfunction " }}}2 + +function! s:_isDebugEnabled_dumb(level) abort " {{{2 +    " poor man's bit test for bit N, assuming a:level == 2**N +    return (g:syntastic_debug / a:level) % 2 +endfunction " }}}2 + +let s:_isDebugEnabled = function(exists('*and') ? 's:_isDebugEnabled_smart' : 's:_isDebugEnabled_dumb') +lockvar s:_isDebugEnabled + +function! s:_logRedirect(on) abort " {{{2 +    if exists('g:syntastic_debug_file') +        if a:on +            try +                execute 'redir >> ' . fnameescape(expand(g:syntastic_debug_file, 1)) +            catch /\m^Vim\%((\a\+)\)\=:/ +                silent! redir END +                unlet g:syntastic_debug_file +            endtry +        else +            silent! redir END +        endif +    endif +endfunction " }}}2 + +" }}}1 + +" Utilities {{{1 + +function! s:_log_timestamp_smart() abort " {{{2 +    return printf('syntastic: %f: ', reltimefloat(reltime(g:_SYNTASTIC_START))) +endfunction " }}}2 + +function! s:_log_timestamp_dumb() abort " {{{2 +    return 'syntastic: ' . split(reltimestr(reltime(g:_SYNTASTIC_START)))[0] . ': ' +endfunction " }}}2 + +let s:_log_timestamp = function(has('float') && exists('*reltimefloat') ? 's:_log_timestamp_smart' : 's:_log_timestamp_dumb') +lockvar s:_log_timestamp + +function! s:_format_variable(name) abort " {{{2 +    let vals = [] +    if exists('g:syntastic_' . a:name) +        call add(vals, 'g:syntastic_' . a:name . ' = ' . strtrans(string(g:syntastic_{a:name}))) +    endif +    if exists('b:syntastic_' . a:name) +        call add(vals, 'b:syntastic_' . a:name . ' = ' . strtrans(string(b:syntastic_{a:name}))) +    endif + +    return join(vals, ', ') +endfunction " }}}2 + +function! s:_is_modified(name) abort " {{{2 +    if !exists('s:option_defaults') +        let s:option_defaults = {} +    endif +    if !has_key(s:option_defaults, a:name) +        let opt_save = eval('&' . a:name) +        execute 'set ' . a:name . '&' +        let s:option_defaults[a:name] = eval('&' . a:name) +        execute 'let &' . a:name . ' = ' . string(opt_save) +    endif + +    return s:option_defaults[a:name] !=# eval('&' . a:name) +endfunction " }}}2 + +" }}}1 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/syntastic/autoload/syntastic/postprocess.vim b/vim/bundle/syntastic/autoload/syntastic/postprocess.vim new file mode 100644 index 0000000..136fa58 --- /dev/null +++ b/vim/bundle/syntastic/autoload/syntastic/postprocess.vim @@ -0,0 +1,73 @@ +if exists('g:loaded_syntastic_postprocess_autoload') || !exists('g:loaded_syntastic_plugin') +    finish +endif +let g:loaded_syntastic_postprocess_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +" Public functions {{{1 + +" merge consecutive blanks +function! syntastic#postprocess#compressWhitespace(errors) abort " {{{2 +    for e in a:errors +        let e['text'] = substitute(e['text'], "\001", '', 'g') +        let e['text'] = substitute(e['text'], '\n', ' ', 'g') +        let e['text'] = substitute(e['text'], '\m\s\{2,}', ' ', 'g') +        let e['text'] = substitute(e['text'], '\m^\s\+', '', '') +        let e['text'] = substitute(e['text'], '\m\s\+$', '', '') +    endfor + +    return a:errors +endfunction " }}}2 + +" remove spurious CR under Cygwin +function! syntastic#postprocess#cygwinRemoveCR(errors) abort " {{{2 +    if has('win32unix') +        for e in a:errors +            let e['text'] = substitute(e['text'], '\r', '', 'g') +        endfor +    endif + +    return a:errors +endfunction " }}}2 + +" decode XML entities +function! syntastic#postprocess#decodeXMLEntities(errors) abort " {{{2 +    for e in a:errors +        let e['text'] = syntastic#util#decodeXMLEntities(e['text']) +    endfor + +    return a:errors +endfunction " }}}2 + +" filter out errors referencing other files +function! syntastic#postprocess#filterForeignErrors(errors) abort " {{{2 +    return filter(copy(a:errors), 'get(v:val, "bufnr") == ' . bufnr('')) +endfunction " }}}2 + +" make sure line numbers are not past end of buffers +" XXX: this loads all referenced buffers in memory +function! syntastic#postprocess#guards(errors) abort " {{{2 +    let buffers = syntastic#util#unique(map(filter(copy(a:errors), 'v:val["valid"]'), 'str2nr(v:val["bufnr"])')) + +    let guards = {} +    for b in buffers +        let guards[b] = len(getbufline(b, 1, '$')) +    endfor + +    for e in a:errors +        if e['valid'] && e['lnum'] > guards[e['bufnr']] +            let e['lnum'] = guards[e['bufnr']] +        endif +    endfor + +    return a:errors +endfunction " }}}2 + +" }}}1 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/syntastic/autoload/syntastic/preprocess.vim b/vim/bundle/syntastic/autoload/syntastic/preprocess.vim new file mode 100644 index 0000000..cbab6fd --- /dev/null +++ b/vim/bundle/syntastic/autoload/syntastic/preprocess.vim @@ -0,0 +1,614 @@ +if exists('g:loaded_syntastic_preprocess_autoload') || !exists('g:loaded_syntastic_plugin') +    finish +endif +let g:loaded_syntastic_preprocess_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +" Public functions {{{1 + +function! syntastic#preprocess#cabal(errors) abort " {{{2 +    let out = [] +    let star = 0 +    for err in a:errors +        if star +            if err ==# '' +                let star = 0 +            else +                let out[-1] .= ' ' . err +            endif +        else +            call add(out, err) +            if err =~# '\m^*\s' +                let star = 1 +            endif +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#checkstyle(errors) abort " {{{2 +    let out = [] +    let fname = expand('%', 1) +    for err in a:errors +        if match(err, '\m<error\>') > -1 +            let line = str2nr(matchstr(err, '\m\<line="\zs\d\+\ze"')) +            if line == 0 +                continue +            endif + +            let col = str2nr(matchstr(err, '\m\<column="\zs\d\+\ze"')) + +            let type = matchstr(err, '\m\<severity="\zs.\ze') +            if type !~? '^[EW]' +                let type = 'E' +            endif + +            let message = syntastic#util#decodeXMLEntities(matchstr(err, '\m\<message="\zs[^"]\+\ze"')) + +            call add(out, join([fname, type, line, col, message], ':')) +        elseif match(err, '\m<file name="') > -1 +            let fname = syntastic#util#decodeXMLEntities(matchstr(err, '\v\<file name\="\zs[^"]+\ze"')) +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#cppcheck(errors) abort " {{{2 +    return map(copy(a:errors), 'substitute(v:val, ''\v^\[[^]]+\]\zs( -\> \[[^]]+\])+\ze:'', "", "")') +endfunction " }}}2 + +function! syntastic#preprocess#dockerfile_lint(errors) abort " {{{2 +    let out = [] +    let json = s:_decode_JSON(join(a:errors, '')) + +    if type(json) == type({}) +        try +            let data = json['error']['data'] + json['warn']['data'] + json['info']['data'] +            for e in data +                let type = toupper(e['level'][0]) +                if type ==# 'I' +                    let type = 'W' +                    let style = 1 +                else +                    let style = 0 +                endif + +                let line = get(e, 'line', 1) +                let message = e['message'] +                if has_key(e, 'description') && e['description'] !=# 'None' +                    let message = message . '. ' . e['description'] +                endif + +                let msg = +                    \ type . ':' . +                    \ style . ':' . +                    \ line . ':' . +                    \ message +                call add(out, msg) +            endfor +        catch /\m^Vim\%((\a\+)\)\=:E716/ +            call syntastic#log#warn('checker dockerfile/dockerfile_lint: unrecognized error format') +            let out = [] +        endtry +    else +        call syntastic#log#warn('checker dockerfile/dockerfile_lint: unrecognized error format') +    endif +    return out +endfunction " }}}2 + +function! syntastic#preprocess#flow(errors) abort " {{{2 +    let idx = 0 +    while idx < len(a:errors) && a:errors[idx][0] !=# '{' +        let idx += 1 +    endwhile +    let errs = s:_decode_JSON(join(a:errors[idx :], '')) + +    let out = [] +    if type(errs) == type({}) && has_key(errs, 'errors') && type(errs['errors']) == type([]) +        for e in errs['errors'] +            if type(e) == type({}) && has_key(e, 'message') && type(e['message']) == type([]) && len(e['message']) +                let m = e['message'][0] +                let t = e['message'][1:] + +                try +                    let msg = +                        \ m['path'] . ':' . +                        \ m['line'] . ':' . +                        \ m['start'] . ':' . +                        \ (m['line'] ==# m['endline'] && str2nr(m['end']) > 0 ? m['end'] . ':' : '') . +                        \ ' ' . m['descr'] + +                    if len(t) +                        let msg .= ' ' . join(map(t, +                            \ 'v:val["descr"] . " (" . v:val["path"] . ":" . v:val["line"] . ":" . v:val["start"] . ' . +                            \ '"," . (v:val["line"] !=# v:val["endline"] ? v:val["endline"] . ":" : "") . ' . +                            \ 'v:val["end"] . ")"')) +                    endif + +                    let msg = substitute(msg, '\r', '', 'g') +                    let msg = substitute(msg, '\n', ' ', 'g') + +                    call add(out, msg) +                catch /\m^Vim\%((\a\+)\)\=:E716/ +                    call syntastic#log#warn('checker javascript/flow: unrecognized error format') +                    let out = [] +                    break +                endtry +            else +                call syntastic#log#warn('checker javascript/flow: unrecognized error format') +                let out = [] +                break +            endif +        endfor +    else +        call syntastic#log#warn('checker javascript/flow: unrecognized error format') +    endif + +    return out +endfunction " }}}2 + +function! syntastic#preprocess#iconv(errors) abort " {{{2 +    return +        \ has('iconv') && &encoding !=# '' && &encoding !=# 'utf-8' ? +        \       map(a:errors, 'iconv(v:val, "utf-8", &encoding)') : +        \       a:errors +endfunction " }}}2 + +function! syntastic#preprocess#jscs(errors) abort " {{{2 +    let errs = join(a:errors, '') +    if errs ==# '' +        return [] +    endif + +    let json = s:_decode_JSON(errs) + +    let out = [] +    if type(json) == type({}) +        for fname in keys(json) +            if type(json[fname]) == type([]) +                for e in json[fname] +                    try +                        let e['message'] = substitute(e['message'], "\n", ' ', 'g') +                        cal add(out, fname . ':' . e['line'] . ':' . e['column'] . ':' . e['message']) +                    catch /\m^Vim\%((\a\+)\)\=:E716/ +                        call syntastic#log#warn('checker javascript/jscs: unrecognized error item ' . string(e)) +                        let out = [] +                    endtry +                endfor +            else +                call syntastic#log#warn('checker javascript/jscs: unrecognized error format') +            endif +        endfor +    else +        call syntastic#log#warn('checker javascript/jscs: unrecognized error format') +    endif +    return out +endfunction " }}}2 + +function! syntastic#preprocess#killEmpty(errors) abort " {{{2 +    return filter(copy(a:errors), 'v:val !=# ""') +endfunction " }}}2 + +function! syntastic#preprocess#perl(errors) abort " {{{2 +    let out = [] + +    for e in a:errors +        let parts = matchlist(e, '\v^(.*)\sat\s(.{-})\sline\s(\d+)(.*)$') +        if !empty(parts) +            call add(out, parts[2] . ':' . parts[3] . ':' . parts[1] . parts[4]) +        endif +    endfor + +    return syntastic#util#unique(out) +endfunction " }}}2 + +function! syntastic#preprocess#prospector(errors) abort " {{{2 +    let errs = s:_decode_JSON(join(a:errors, '')) + +    let out = [] +    if type(errs) == type({}) && has_key(errs, 'messages') +        if type(errs['messages']) == type([]) +            for e in errs['messages'] +                if type(e) == type({}) +                    try +                        if e['source'] ==# 'pylint' +                            let e['location']['character'] += 1 +                        endif + +                        let msg = +                            \ e['location']['path'] . ':' . +                            \ e['location']['line'] . ':' . +                            \ e['location']['character'] . ': ' . +                            \ e['code'] . ' ' . +                            \ e['message'] . ' ' . +                            \ '[' . e['source'] . ']' + +                        call add(out, msg) +                    catch /\m^Vim\%((\a\+)\)\=:E716/ +                        call syntastic#log#warn('checker python/prospector: unrecognized error item ' . string(e)) +                        let out = [] +                        break +                    endtry +                else +                    call syntastic#log#warn('checker python/prospector: unrecognized error item ' . string(e)) +                    let out = [] +                    break +                endif +            endfor +        else +            call syntastic#log#warn('checker python/prospector: unrecognized error format') +        endif +    endif + +    return out +endfunction " }}}2 + +function! syntastic#preprocess#rparse(errors) abort " {{{2 +    let errlist = copy(a:errors) + +    " remove uninteresting lines and handle continuations +    let i = 0 +    while i < len(errlist) +        if i > 0 && errlist[i][:1] ==# '  ' && errlist[i] !~# '\m\s\+\^$' +            let errlist[i-1] .= errlist[i][1:] +            call remove(errlist, i) +        elseif errlist[i] !~# '\m^\(Lint:\|Lint checking:\|Error in\) ' +            call remove(errlist, i) +        else +            let i += 1 +        endif +    endwhile + +    let out = [] +    let fname = '' +    for e in errlist +        if match(e, '\m^Lint: ') == 0 +            let parts = matchlist(e, '\m^Lint: \(.*\): found on lines \([0-9, ]\+\)\(+\(\d\+\) more\)\=') +            if len(parts) >= 3 +                for line in split(parts[2], '\m,\s*') +                    call add(out, 'E:' . fname . ':' . line . ': ' . parts[1]) +                endfor +            endif +            if len(parts) >= 5 && parts[4] !=# '' +                call add(out, 'E:' . fname . ':0: ' . parts[1] . ' - ' . parts[4] . ' messages not shown') +            endif +        elseif match(e, '\m^Lint checking: ') == 0 +            let fname = matchstr(e, '\m^Lint checking: \zs.*') +        elseif match(e, '\m^Error in ') == 0 +            call add(out, substitute(e, '\m^Error in .\+ : .\+\ze:\d\+:\d\+: ', 'E:' . fname, '')) +        endif +    endfor + +    return out +endfunction " }}}2 + +function! syntastic#preprocess#scss_lint(errors) abort " {{{2 +    let errs = join(a:errors, '') +    if errs ==# '' +        return [] +    endif + +    let json = s:_decode_JSON(errs) + +    let out = [] +    if type(json) == type({}) +        for fname in keys(json) +            if type(json[fname]) == type([]) +                for e in json[fname] +                    try +                        cal add(out, fname . ':' . +                            \ e['severity'][0] . ':' . +                            \ e['line'] . ':' . +                            \ e['column'] . ':' . +                            \ e['length'] . ':' . +                            \ ( has_key(e, 'linter') ? e['linter'] . ': ' : '' ) . +                            \ e['reason']) +                    catch /\m^Vim\%((\a\+)\)\=:E716/ +                        call syntastic#log#warn('checker scss/scss_lint: unrecognized error item ' . string(e)) +                        let out = [] +                    endtry +                endfor +            else +                call syntastic#log#warn('checker scss/scss_lint: unrecognized error format') +            endif +        endfor +    else +        call syntastic#log#warn('checker scss/scss_lint: unrecognized error format') +    endif +    return out +endfunction " }}}2 + +function! syntastic#preprocess#stylelint(errors) abort " {{{2 +    let out = [] + +    " CssSyntaxError: /path/to/file.css:2:11: Missed semicolon +    let parts = matchlist(a:errors[0], '\v^CssSyntaxError: (.{-1,}):(\d+):(\d+): (.+)') +    if len(parts) > 4 +        call add(out, 'E:' . join(parts[1:4], ':')) +    else +        let errs = s:_decode_JSON(join(a:errors, '')) + +        let out = [] +        if type(errs) == type([]) && len(errs) == 1 && type(errs[0]) == type({}) && +            \ has_key(errs[0], 'source') && has_key(errs[0], 'warnings') && type(errs[0]['warnings']) == type([]) + +            for e in errs[0]['warnings'] +                try +                    let severity = type(e['severity']) == type(0) ? ['W', 'E'][e['severity']-1] : e['severity'][0] +                    let msg = +                        \ severity . ':' . +                        \ errs[0]['source'] . ':' . +                        \ e['line'] . ':' . +                        \ e['column'] . ':' . +                        \ e['text'] +                    call add(out, msg) +                catch /\m^Vim\%((\a\+)\)\=:E716/ +                    call syntastic#log#warn('checker css/stylelint: unrecognized error item ' . string(e)) +                    let out = [] +                    break +                endtry +            endfor +        else +            call syntastic#log#warn('checker css/stylelint: unrecognized error format') +        endif +    endif +    return out +endfunction " }}}2 + +function! syntastic#preprocess#tern_lint(errors) abort " {{{2 +    let errs = join(a:errors, '') +    let json = s:_decode_JSON(errs) + +echomsg string(json) +    let out = [] +    if type(json) == type({}) && has_key(json, 'messages') && type(json['messages']) == type([]) +        for e in json['messages'] +            try +                let line_from = byte2line(e['from'] + 1) +                if line_from > 0 +                    let line = line_from +                    let column = e['from'] - line2byte(line_from) + 2 +                    let line_to = byte2line(e['from'] + 1) +                    let hl = line_to == line ? e['to'] - line2byte(line_to) + 1 : 0 +                else +                    let line = 0 +                    let column = 0 +                    let hl = 0 +                endif + +                if column < 0 +                    let column = 0 +                endif +                if hl < 0 +                    let hl = 0 +                endif + +                call add(out, +                    \ e['file'] . ':' . +                    \ e['severity'][0] . ':' . +                    \ line . ':' . +                    \ column . ':' . +                    \ hl . ':' . +                    \ e['message']) +            catch /\m^Vim\%((\a\+)\)\=:E716/ +                call syntastic#log#warn('checker javascript/tern_lint: unrecognized error item ' . string(e)) +                let out = [] +            endtry +        endfor +    else +        call syntastic#log#warn('checker javascript/tern_lint: unrecognized error format') +    endif + +echomsg string(out) +    return out +endfunction " }}}2 + +function! syntastic#preprocess#tslint(errors) abort " {{{2 +    return map(copy(a:errors), 'substitute(v:val, ''\m^\(([^)]\+)\)\s\(.\+\)$'', ''\2 \1'', "")') +endfunction " }}}2 + +function! syntastic#preprocess#validator(errors) abort " {{{2 +    let out = [] +    for e in a:errors +        let parts = matchlist(e, '\v^"([^"]+)"(.+)') +        if len(parts) >= 3 +            " URL decode, except leave alone any "+" +            let parts[1] = substitute(parts[1], '\m%\(\x\x\)', '\=nr2char("0x".submatch(1))', 'g') +            let parts[1] = substitute(parts[1], '\m\\"', '"', 'g') +            let parts[1] = substitute(parts[1], '\m\\\\', '\\', 'g') +            call add(out, '"' . parts[1] . '"' . parts[2]) +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#vint(errors) abort " {{{2 +    let errs = s:_decode_JSON(join(a:errors, '')) + +    let out = [] +    if type(errs) == type([]) +        for e in errs +            if type(e) == type({}) +                try +                    let msg = +                        \ e['file_path'] . ':' . +                        \ e['line_number'] . ':' . +                        \ e['column_number'] . ':' . +                        \ e['severity'][0] . ': ' . +                        \ e['description'] . ' (' . +                        \ e['policy_name'] . ')' + +                    call add(out, msg) +                catch /\m^Vim\%((\a\+)\)\=:E716/ +                    call syntastic#log#warn('checker vim/vint: unrecognized error item ' . string(e)) +                    let out = [] +                    break +                endtry +            else +                call syntastic#log#warn('checker vim/vint: unrecognized error item ' . string(e)) +                let out = [] +                break +            endif +        endfor +    else +        call syntastic#log#warn('checker vim/vint: unrecognized error format') +    endif + +    return out +endfunction " }}}2 + +" }}}1 + +" Workarounds {{{1 + +" In errorformat, \ or % following %f make it depend on isfname.  The default +" setting of isfname is crafted to work with completion, rather than general +" filename matching.  The result for syntastic is that filenames containing +" spaces (or a few other special characters) can't be matched. +" +" Fixing isfname to address this problem would depend on the set of legal +" characters for filenames on the filesystem the project's files lives on. +" Inferring the kind of filesystem a file lives on, in advance to parsing the +" file's name, is an interesting problem (think f.i. a file loaded from a VFAT +" partition, mounted on Linux).  A problem syntastic is not prepared to solve. +" +" As a result, the functions below exist for the only reason to avoid using +" things like %f\, in errorformat. +" +" References: +" https://groups.google.com/forum/#!topic/vim_dev/pTKmZmouhio +" https://vimhelp.appspot.com/quickfix.txt.html#error-file-format + +function! syntastic#preprocess#basex(errors) abort " {{{2 +    let out = [] +    let idx = 0 +    while idx < len(a:errors) +        let parts = matchlist(a:errors[idx], '\v^\[\S+\] Stopped at (.+), (\d+)/(\d+):') +        if len(parts) > 3 +            let err = parts[1] . ':' . parts[2] . ':' . parts[3] . ':' +            let parts = matchlist(a:errors[idx+1], '\v^\[(.)\D+(\d+)\] (.+)') +            if len(parts) > 3 +                let err .= (parts[1] ==? 'W' || parts[1] ==? 'E' ? parts[1] : 'E') . ':' . parts[2] . ':' . parts[3] +                call add(out, err) +                let idx +=1 +            endif +        elseif a:errors[idx] =~# '\m^\[' +            " unparseable errors +            call add(out, a:errors[idx]) +        endif +        let idx +=1 +    endwhile +    return out +endfunction " }}}2 + +function! syntastic#preprocess#bro(errors) abort " {{{2 +    let out = [] +    for e in a:errors +        let parts = matchlist(e, '\v^%(fatal )?(error|warning) in (.{-1,}), line (\d+): (.+)') +        if len(parts) > 4 +            let parts[1] = parts[1][0] +            call add(out, join(parts[1:4], ':')) +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#coffeelint(errors) abort " {{{2 +    let out = [] +    for e in a:errors +        let parts = matchlist(e, '\v^(.{-1,}),(\d+)%(,\d*)?,(error|warn),(.+)') +        if len(parts) > 4 +            let parts[3] = parts[3][0] +            call add(out, join(parts[1:4], ':')) +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#mypy(errors) abort " {{{2 +    let out = [] +    for e in a:errors +        " new format +        let parts = matchlist(e, '\v^(.{-1,}):(\d+): error: (.+)') +        if len(parts) > 3 +            call add(out, join(parts[1:3], ':')) +            continue +        endif + +        " old format +        let parts = matchlist(e, '\v^(.{-1,}), line (\d+): (.+)') +        if len(parts) > 3 +            call add(out, join(parts[1:3], ':')) +        endif +    endfor +    return out +endfunction " }}}2 + +function! syntastic#preprocess#nix(errors) abort " {{{2 +    let out = [] +    for e in a:errors +        let parts = matchlist(e, '\v^(.{-1,}), at (.{-1,}):(\d+):(\d+)$') +        if len(parts) > 4 +            call add(out, join(parts[2:4], ':') . ':' . parts[1]) +            continue +        endif + +        let parts = matchlist(e, '\v^(.{-1,}) at (.{-1,}), line (\d+):') +        if len(parts) > 3 +            call add(out, parts[2] . ':' . parts[3] . ':' . parts[1]) +            continue +        endif + +        let parts = matchlist(e, '\v^error: (.{-1,}), in (.{-1,})$') +        if len(parts) > 2 +            call add(out, parts[2] . ':' . parts[1]) +        endif +    endfor +    return out +endfunction " }}}2 + +" }}}1 + +" Private functions {{{1 + +" @vimlint(EVL102, 1, l:true) +" @vimlint(EVL102, 1, l:false) +" @vimlint(EVL102, 1, l:null) +function! s:_decode_JSON(json) abort " {{{2 +    if a:json ==# '' +        return [] +    endif + +    " The following is inspired by https://github.com/MarcWeber/vim-addon-manager and +    " http://stackoverflow.com/questions/17751186/iterating-over-a-string-in-vimscript-or-parse-a-json-file/19105763#19105763 +    " A hat tip to Marc Weber for this trick +    if substitute(a:json, '\v\"%(\\.|[^"\\])*\"|true|false|null|[+-]?\d+%(\.\d+%([Ee][+-]?\d+)?)?', '', 'g') !~# "[^,:{}[\\] \t]" +        " JSON artifacts +        let true = 1 +        let false = 0 +        let null = '' + +        try +            let object = eval(a:json) +        catch +            " malformed JSON +            let object = '' +        endtry +    else +        let object = '' +    endif + +    return object +endfunction " }}}2 +" @vimlint(EVL102, 0, l:true) +" @vimlint(EVL102, 0, l:false) +" @vimlint(EVL102, 0, l:null) + +" }}}1 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/syntastic/autoload/syntastic/util.vim b/vim/bundle/syntastic/autoload/syntastic/util.vim new file mode 100644 index 0000000..68eb06e --- /dev/null +++ b/vim/bundle/syntastic/autoload/syntastic/util.vim @@ -0,0 +1,552 @@ +if exists('g:loaded_syntastic_util_autoload') || !exists('g:loaded_syntastic_plugin') +    finish +endif +let g:loaded_syntastic_util_autoload = 1 + +let s:save_cpo = &cpo +set cpo&vim + +" Public functions {{{1 + +function! syntastic#util#isRunningWindows() abort " {{{2 +    return has('win16') || has('win32') || has('win64') +endfunction " }}}2 + +function! syntastic#util#DevNull() abort " {{{2 +    if syntastic#util#isRunningWindows() +        return 'NUL' +    endif +    return '/dev/null' +endfunction " }}}2 + +" Get directory separator +function! syntastic#util#Slash() abort " {{{2 +    return (!exists('+shellslash') || &shellslash) ? '/' : '\' +endfunction " }}}2 + +function! syntastic#util#CygwinPath(path) abort " {{{2 +    return substitute(syntastic#util#system('cygpath -m ' . syntastic#util#shescape(a:path)), "\n", '', 'g') +endfunction " }}}2 + +function! syntastic#util#system(command) abort " {{{2 +    let old_shell = &shell +    let old_lc_messages = $LC_MESSAGES +    let old_lc_all = $LC_ALL + +    let &shell = syntastic#util#var('shell') +    let $LC_MESSAGES = 'C' +    let $LC_ALL = '' + +    let cmd_start = reltime() +    let out = system(a:command) +    let cmd_time = split(reltimestr(reltime(cmd_start)))[0] + +    let $LC_ALL = old_lc_all +    let $LC_MESSAGES = old_lc_messages + +    let &shell = old_shell + +    if exists('g:_SYNTASTIC_DEBUG_TRACE') +        call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'system: command run in ' . cmd_time . 's') +    endif + +    return out +endfunction " }}}2 + +" Create a temporary directory +function! syntastic#util#tmpdir() abort " {{{2 +    let tempdir = '' + +    if (has('unix') || has('mac')) && executable('mktemp') && !has('win32unix') +        " TODO: option "-t" to mktemp(1) is not portable +        let tmp = $TMPDIR !=# '' ? $TMPDIR : $TMP !=# '' ? $TMP : '/tmp' +        let out = split(syntastic#util#system('mktemp -q -d ' . tmp . '/vim-syntastic-' . getpid() . '-XXXXXXXX'), "\n") +        if v:shell_error == 0 && len(out) == 1 +            let tempdir = out[0] +        endif +    endif + +    if tempdir ==# '' +        if has('win32') || has('win64') +            let tempdir = $TEMP . syntastic#util#Slash() . 'vim-syntastic-' . getpid() +        elseif has('win32unix') +            let tempdir = syntastic#util#CygwinPath('/tmp/vim-syntastic-'  . getpid()) +        elseif $TMPDIR !=# '' +            let tempdir = $TMPDIR . '/vim-syntastic-' . getpid() +        else +            let tempdir = '/tmp/vim-syntastic-' . getpid() +        endif + +        try +            call mkdir(tempdir, 'p', 0700) +        catch /\m^Vim\%((\a\+)\)\=:E739/ +            call syntastic#log#error(v:exception) +            let tempdir = '.' +        endtry +    endif + +    return tempdir +endfunction " }}}2 + +" Recursively remove a directory +function! syntastic#util#rmrf(what) abort " {{{2 +    " try to make sure we don't delete directories we didn't create +    if a:what !~? 'vim-syntastic-' +        return +    endif + +    if  getftype(a:what) ==# 'dir' +        call s:_delete(a:what, 'rf') +    else +        silent! call delete(a:what) +    endif +endfunction " }}}2 + +" Search the first 5 lines of the file for a magic number and return a map +" containing the args and the executable +" +" e.g. +" +" #!/usr/bin/perl -f -bar +" +" returns +" +" {'exe': '/usr/bin/perl', 'args': ['-f', '-bar']} +function! syntastic#util#parseShebang() abort " {{{2 +    for lnum in range(1, 5) +        let line = getline(lnum) +        if line =~# '^#!' +            let line = substitute(line, '\v^#!\s*(\S+/env(\s+-\S+)*\s+)?', '', '') +            let exe = matchstr(line, '\m^\S*\ze') +            let args = split(matchstr(line, '\m^\S*\zs.*')) +            return { 'exe': exe, 'args': args } +        endif +    endfor + +    return { 'exe': '', 'args': [] } +endfunction " }}}2 + +" Get the value of a Vim variable.  Allow local variables to override global ones. +function! syntastic#util#rawVar(name, ...) abort " {{{2 +    return get(b:, a:name, get(g:, a:name, a:0 > 0 ? a:1 : '')) +endfunction " }}}2 + +" Get the value of a syntastic variable.  Allow local variables to override global ones. +function! syntastic#util#var(name, ...) abort " {{{2 +    return call('syntastic#util#rawVar', ['syntastic_' . a:name] + a:000) +endfunction " }}}2 + +" Parse a version string.  Return an array of version components. +function! syntastic#util#parseVersion(version, ...) abort " {{{2 +    return map(split(matchstr( a:version, a:0 ? a:1 : '\v^\D*\zs\d+(\.\d+)+\ze' ), '\m\.'), 'str2nr(v:val)') +endfunction " }}}2 + +" Verify that the 'installed' version is at least the 'required' version. +" +" 'installed' and 'required' must be arrays. If they have different lengths, +" the "missing" elements will be assumed to be 0 for the purposes of checking. +" +" See http://semver.org for info about version numbers. +function! syntastic#util#versionIsAtLeast(installed, required) abort " {{{2 +    return syntastic#util#compareLexi(a:installed, a:required) >= 0 +endfunction " }}}2 + +" Almost lexicographic comparison of two lists of integers. :) If lists +" have different lengths, the "missing" elements are assumed to be 0. +function! syntastic#util#compareLexi(a, b) abort " {{{2 +    for idx in range(max([len(a:a), len(a:b)])) +        let a_element = str2nr(get(a:a, idx, 0)) +        let b_element = str2nr(get(a:b, idx, 0)) +        if a_element != b_element +            return a_element > b_element ? 1 : -1 +        endif +    endfor +    " still here, thus everything matched +    return 0 +endfunction " }}}2 + +" strwidth() was added in Vim 7.3; if it doesn't exist, we use strlen() +" and hope for the best :) +let s:_width = function(exists('*strwidth') ? 'strwidth' : 'strlen') +lockvar s:_width + +function! syntastic#util#screenWidth(str, tabstop) abort " {{{2 +    let chunks = split(a:str, "\t", 1) +    let width = s:_width(chunks[-1]) +    for c in chunks[:-2] +        let cwidth = s:_width(c) +        let width += cwidth + a:tabstop - cwidth % a:tabstop +    endfor +    return width +endfunction " }}}2 + +" Print as much of a:msg as possible without "Press Enter" prompt appearing +function! syntastic#util#wideMsg(msg) abort " {{{2 +    let old_ruler = &ruler +    let old_showcmd = &showcmd + +    "This is here because it is possible for some error messages to +    "begin with \n which will cause a "press enter" prompt. +    let msg = substitute(a:msg, "\n", '', 'g') + +    "convert tabs to spaces so that the tabs count towards the window +    "width as the proper amount of characters +    let chunks = split(msg, "\t", 1) +    let msg = join(map(chunks[:-2], 'v:val . repeat(" ", &tabstop - s:_width(v:val) % &tabstop)'), '') . chunks[-1] +    let msg = strpart(msg, 0, &columns - 1) + +    set noruler noshowcmd +    call syntastic#util#redraw(0) + +    echo msg + +    let &ruler = old_ruler +    let &showcmd = old_showcmd +endfunction " }}}2 + +" Check whether a buffer is loaded, listed, and not hidden +function! syntastic#util#bufIsActive(buffer) abort " {{{2 +    " convert to number, or hell breaks loose +    let buf = str2nr(a:buffer) + +    if !bufloaded(buf) || !buflisted(buf) +        return 0 +    endif + +    " get rid of hidden buffers +    for tab in range(1, tabpagenr('$')) +        if index(tabpagebuflist(tab), buf) >= 0 +            return 1 +        endif +    endfor + +    return 0 +endfunction " }}}2 + +" Start in directory a:where and walk up the parent folders until it finds a +" file named a:what; return path to that file +function! syntastic#util#findFileInParent(what, where) abort " {{{2 +    let old_suffixesadd = &suffixesadd +    let &suffixesadd = '' +    let file = findfile(a:what, escape(a:where, ' ') . ';') +    let &suffixesadd = old_suffixesadd +    return file +endfunction " }}}2 + +" Start in directory a:where and walk up the parent folders until it finds a +" file matching a:what; return path to that file +function! syntastic#util#findGlobInParent(what, where) abort " {{{2 +    let here = fnamemodify(a:where, ':p') + +    let root = syntastic#util#Slash() +    if syntastic#util#isRunningWindows() && here[1] ==# ':' +        " The drive letter is an ever-green source of fun.  That's because +        " we don't care about running syntastic on Amiga these days. ;) +        let root = fnamemodify(root, ':p') +        let root = here[0] . root[1:] +    endif + +    let old = '' +    while here !=# '' +        try +            " Vim 7.4.279 and later +            let p = globpath(here, a:what, 1, 1) +        catch /\m^Vim\%((\a\+)\)\=:E118/ +            let p = split(globpath(here, a:what, 1), "\n") +        endtry + +        if !empty(p) +            return fnamemodify(p[0], ':p') +        elseif here ==? root || here ==? old +            break +        endif + +        let old = here + +        " we use ':h:h' rather than ':h' since ':p' adds a trailing '/' +        " if 'here' is a directory +        let here = fnamemodify(here, ':p:h:h') +    endwhile + +    return '' +endfunction " }}}2 + +" Returns unique elements in a list +function! syntastic#util#unique(list) abort " {{{2 +    let seen = {} +    let uniques = [] +    for e in a:list +        let k = string(e) +        if !has_key(seen, k) +            let seen[k] = 1 +            call add(uniques, e) +        endif +    endfor +    return uniques +endfunction " }}}2 + +" A less noisy shellescape() +function! syntastic#util#shescape(string) abort " {{{2 +    return a:string =~# '\m^[A-Za-z0-9_/.-]\+$' ? a:string : shellescape(a:string) +endfunction " }}}2 + +" A less noisy shellescape(expand()) +function! syntastic#util#shexpand(string, ...) abort " {{{2 +    return syntastic#util#shescape(a:0 ? expand(a:string, a:1) : expand(a:string, 1)) +endfunction " }}}2 + +" Escape arguments +function! syntastic#util#argsescape(opt) abort " {{{2 +    if type(a:opt) == type('') && a:opt !=# '' +        return [a:opt] +    elseif type(a:opt) == type([]) +        return map(copy(a:opt), 'syntastic#util#shescape(v:val)') +    endif + +    return [] +endfunction " }}}2 + +" Decode XML entities +function! syntastic#util#decodeXMLEntities(string) abort " {{{2 +    let str = a:string +    let str = substitute(str, '\m<', '<', 'g') +    let str = substitute(str, '\m>', '>', 'g') +    let str = substitute(str, '\m"', '"', 'g') +    let str = substitute(str, '\m'', "'", 'g') +    let str = substitute(str, '\m&', '\&', 'g') +    return str +endfunction " }}}2 + +function! syntastic#util#redraw(full) abort " {{{2 +    if a:full +        redraw! +    else +        redraw +    endif +endfunction " }}}2 + +function! syntastic#util#dictFilter(errors, filter) abort " {{{2 +    let rules = s:_translateFilter(a:filter) +    " call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, "applying filter:", rules) +    try +        call filter(a:errors, rules) +    catch /\m^Vim\%((\a\+)\)\=:E/ +        let msg = matchstr(v:exception, '\m^Vim\%((\a\+)\)\=:\zs.*') +        call syntastic#log#error('quiet_messages: ' . msg) +    endtry +endfunction " }}}2 + +" Return a [seconds, fractions] list of strings, representing the +" (hopefully high resolution) time since program start +function! syntastic#util#stamp() abort " {{{2 +    return split( split(reltimestr(reltime(g:_SYNTASTIC_START)))[0], '\.' ) +endfunction " }}}2 + +function! syntastic#util#setChangedtick() abort " {{{2 +    unlockvar! b:syntastic_changedtick +    let b:syntastic_changedtick = b:changedtick +    lockvar! b:syntastic_changedtick +endfunction " }}}2 + +let s:_wid_base = 'syntastic_' . getpid() . '_' . reltimestr(g:_SYNTASTIC_START) . '_' +let s:_wid_pool = 0 + +" Add unique IDs to windows +function! syntastic#util#setWids() abort " {{{2 +    for tab in range(1, tabpagenr('$')) +        for win in range(1, tabpagewinnr(tab, '$')) +            if gettabwinvar(tab, win, 'syntastic_wid') ==# '' +                call settabwinvar(tab, win, 'syntastic_wid', s:_wid_base . s:_wid_pool) +                let s:_wid_pool += 1 +            endif +        endfor +    endfor +endfunction " }}}2 + +let s:_str2float = function(exists('*str2float') ? 'str2float' : 'str2nr') +lockvar s:_str2float + +function! syntastic#util#str2float(val) abort " {{{2 +    return s:_str2float(a:val) +endfunction " }}}2 + +function! syntastic#util#float2str(val) abort " {{{2 +    return s:_float2str(a:val) +endfunction " }}}2 + +" Crude printf()-like width formatter.  Handles wide characters. +function! syntastic#util#wformat(format, str) abort " {{{2 +    if a:format ==# '' +        return a:str +    endif + + echomsg string(a:format) . ', ' . string(a:str) +    let specs = matchlist(a:format, '\v^(-?)(0?)(%([1-9]\d*))?%(\.(\d+))?$') +    if len(specs) < 5 +        return a:str +    endif + +    let flushleft = specs[1] ==# '-' +    let lpad = specs[2] ==# '0' ? '0' : ' ' +    let minlen = str2nr(specs[3]) +    let maxlen = str2nr(specs[4]) +    let out = substitute(a:str, "\t", ' ', 'g') + +    if maxlen && s:_width(out) > maxlen +        let chars = filter(split(out, '\zs\ze', 1), 'v:val !=# ""') +        let out = '' + +        if flushleft +            for c in chars +                if s:_width(out . c) < maxlen +                    let out .= c +                else +                    let out .= &encoding ==# 'utf-8' && &termencoding ==# 'utf-8' ? "\u2026" : '>' +                    break +                endif +            endfor +        else +            call reverse(chars) +            for c in chars +                if s:_width(c . out) < maxlen +                    let out = c . out +                else +                    let out = (&encoding ==# 'utf-8' && &termencoding ==# 'utf-8' ? "\u2026" : '<') . out +                    break +                endif +            endfor +        endif +    endif + +    if minlen && s:_width(out) < minlen +        if flushleft +            let out .= repeat(' ', minlen - s:_width(out)) +        else +            let out = repeat(lpad, minlen - s:_width(out)) . out +        endif +    endif + +    return out +endfunction " }}}2 + +" }}}1 + +" Private functions {{{1 + +function! s:_translateFilter(filters) abort " {{{2 +    let conditions = [] +    for k in keys(a:filters) +        if type(a:filters[k]) == type([]) +            call extend(conditions, map(copy(a:filters[k]), 's:_translateElement(k, v:val)')) +        else +            call add(conditions, s:_translateElement(k, a:filters[k])) +        endif +    endfor + +    if conditions == [] +        let conditions = ['1'] +    endif +    return len(conditions) == 1 ? conditions[0] : join(map(conditions, '"(" . v:val . ")"'), ' && ') +endfunction " }}}2 + +function! s:_translateElement(key, term) abort " {{{2 +    let fkey = a:key +    if fkey[0] ==# '!' +        let fkey = fkey[1:] +        let not = 1 +    else +        let not = 0 +    endif + +    if fkey ==? 'level' +        let op = not ? ' ==? ' : ' !=? ' +        let ret = 'v:val["type"]' . op . string(a:term[0]) +    elseif fkey ==? 'type' +        if a:term ==? 'style' +            let op = not ? ' ==? ' : ' !=? ' +            let ret = 'get(v:val, "subtype", "")' . op . '"style"' +        else +            let op = not ? '!' : '' +            let ret = op . 'has_key(v:val, "subtype")' +        endif +    elseif fkey ==? 'regex' +        let op = not ? ' =~? ' : ' !~? ' +        let ret = 'v:val["text"]' . op . string(a:term) +    elseif fkey ==? 'file' || fkey[:4] ==? 'file:' +        let op = not ? ' =~# ' : ' !~# ' +        let ret = 'bufname(str2nr(v:val["bufnr"]))' +        let mod = fkey[4:] +        if mod !=# '' +            let ret = 'fnamemodify(' . ret . ', ' . string(mod) . ')' +        endif +        let ret .= op . string(a:term) +    else +        call syntastic#log#warn('quiet_messages: ignoring invalid key ' . strtrans(string(fkey))) +        let ret = '1' +    endif +    return ret +endfunction " }}}2 + +" @vimlint(EVL103, 1, a:flags) +function! s:_delete_dumb(what, flags) abort " {{{2 +    if !exists('s:rmrf') +        let s:rmrf = +            \ has('unix') || has('mac') ? 'rm -rf' : +            \ has('win32') || has('win64') ? 'rmdir /S /Q' : +            \ has('win16') || has('win95') || has('dos16') || has('dos32') ? 'deltree /Y' : '' +    endif + +    if s:rmrf !=# '' +        silent! call syntastic#util#system(s:rmrf . ' ' . syntastic#util#shescape(a:what)) +    else +        call s:_rmrf(a:what) +    endif +endfunction " }}}2 +" @vimlint(EVL103, 0, a:flags) + +" delete(dir, 'rf') was added in Vim 7.4.1107, but it didn't become usable until 7.4.1128 +let s:_delete = function(v:version > 704 || (v:version == 704 && has('patch1128')) ? 'delete' : 's:_delete_dumb') +lockvar s:_delete + +function! s:_rmrf(what) abort " {{{2 +    if !exists('s:rmdir') +        let s:rmdir = syntastic#util#shescape(get(g:, 'netrw_localrmdir', 'rmdir')) +    endif + +    if getftype(a:what) ==# 'dir' +        if filewritable(a:what) != 2 +            return +        endif + +        try +            " Vim 7.4.279 and later +            let entries = globpath(a:what, '*', 1, 1) +        catch /\m^Vim\%((\a\+)\)\=:E118/ +            let entries = split(globpath(a:what, '*', 1), "\n") +        endtry +        for f in entries +            call s:_rmrf(f) +        endfor +        silent! call syntastic#util#system(s:rmdir . ' ' . syntastic#util#shescape(a:what)) +    else +        silent! call delete(a:what) +    endif +endfunction " }}}2 + +function! s:_float2str_smart(val) abort " {{{2 +    return printf('%.1f', a:val) +endfunction " }}}2 + +function! s:_float2str_dumb(val) abort " {{{2 +    return a:val +endfunction " }}}2 + +let s:_float2str = function(has('float') ? 's:_float2str_smart' : 's:_float2str_dumb') +lockvar s:_float2str + +" }}}1 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set sw=4 sts=4 et fdm=marker: | 
