Fixed vim and zsh

This commit is contained in:
2018-04-05 13:06:54 +02:00
parent f9db886bd3
commit 0331f6518a
2009 changed files with 256303 additions and 0 deletions

View File

@ -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:

View File

@ -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
" 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:

View File

@ -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:

View File

@ -0,0 +1,681 @@
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#bandit(errors) abort " {{{2
let out = []
let json = s:_decode_JSON(join(a:errors, ''))
if type(json) == type({}) && has_key(json, 'results') && type(json['results']) == type([])
for issue in json['results']
if type(issue) == type({})
try
call add(out,
\ issue['filename'] . ':' .
\ issue['line_number'] . ':' .
\ { 'LOW': 'I', 'MEDIUM': 'W', 'HIGH': 'E' }[issue['issue_severity']] . ':' .
\ issue['test_id'][1:] . ':' .
\ issue['issue_text'] .
\ ' [' . issue['test_name'] . '] (confidence: ' . issue['issue_confidence'] . ')')
catch /\m^Vim\%((\a\+)\)\=:E716/
call syntastic#log#warn('checker python/bandit: unrecognized error item ' . string(issue))
let out = []
break
endtry
else
call syntastic#log#warn('checker python/bandit: unrecognized error item ' . string(issue))
endif
endfor
else
call syntastic#log#warn('checker python/bandit: unrecognized error format (crashed checker?)')
endif
return out
endfunction " }}}2
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 (crashed checker?)')
let out = []
endtry
else
call syntastic#log#warn('checker dockerfile/dockerfile_lint: unrecognized error format (crashed checker?)')
endif
return out
endfunction " }}}2
function! syntastic#preprocess#dscanner(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, 'issues') && type(errs['issues']) == type([])
for issue in errs['issues']
try
call add(out,
\ issue['fileName'] . ':' .
\ issue['line'] . ':' .
\ issue['column'] . ':' .
\ issue['message'] . ' [' . issue['key'] . ']')
catch /\m^Vim\%((\a\+)\)\=:E716/
call syntastic#log#warn('checker d/dscanner: unrecognized error item ' . string(issue))
let out = []
break
endtry
endfor
else
call syntastic#log#warn('checker d/dscanner: unrecognized error format (crashed checker?)')
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 (crashed checker?)')
let out = []
break
endtry
else
call syntastic#log#warn('checker javascript/flow: unrecognized error format (crashed checker?)')
let out = []
break
endif
endfor
else
call syntastic#log#warn('checker javascript/flow: unrecognized error format (crashed checker?)')
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 (crashed checker?)')
endif
endfor
else
call syntastic#log#warn('checker javascript/jscs: unrecognized error format (crashed checker?)')
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 = join(a:errors, '')
if errs ==# ''
return []
endif
let json = s:_decode_JSON(errs)
let out = []
if type(json) == type({}) && has_key(json, 'messages')
if type(json['messages']) == type([])
for e in json['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 (crashed checker?)')
endif
else
call syntastic#log#warn('checker python/prospector: unrecognized error format (crashed checker?)')
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 (crashed checker?)')
endif
endfor
else
call syntastic#log#warn('checker scss/scss_lint: unrecognized error format (crashed checker?)')
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 (crashed checker?)')
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 (crashed checker?)')
endif
echomsg string(out)
return out
endfunction " }}}2
function! syntastic#preprocess#tslint(errors) abort " {{{2
return map(copy(a:errors), 'substitute(v:val, ''\v^((ERROR|WARNING): )?\zs(\([^)]+\))\s(.+)$'', ''\4 \3'', "")')
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 (crashed checker?)')
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:

View File

@ -0,0 +1,622 @@
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 crashed = 0
let cmd_start = reltime()
try
let out = system(a:command)
catch
let crashed = 1
call syntastic#log#error('exception running system(' . string(a:command) . '): ' . v:exception)
if syntastic#util#isRunningWindows()
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMP = ' . string($TMP) . ', $TEMP = ' . string($TEMP))
else
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TERM = ' . string($TERM))
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, '$TMPDIR = ' . string($TMPDIR))
endif
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, '$PATH = ' . string($PATH))
call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getcwd() = ' . string(getcwd()))
call syntastic#log#debugShowOptions(g:_SYNTASTIC_DEBUG_TRACE, g:_SYNTASTIC_SHELL_OPTIONS)
let out = ''
endtry
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 !crashed && 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
function! syntastic#util#getbufvar(buf, name, ...) abort " {{{2
return a:0 ? s:_getbufvar(a:buf, a:name, a:1) : getbufvar(a:buf, a:name)
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(buf) abort " {{{2
for lnum in range(1, 5)
let line = get(getbufline(a:buf, lnum), 0, '')
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 buffer variables to override global ones.
function! syntastic#util#bufRawVar(buf, name, ...) abort " {{{2
return s:_getbufvar(a:buf, a:name, get(g:, a:name, a:0 ? a:1 : ''))
endfunction "}}}2
" Get the value of a syntastic variable. Allow buffer variables to override global ones.
function! syntastic#util#bufVar(buf, name, ...) abort " {{{2
return call('syntastic#util#bufRawVar', [a:buf, 'syntastic_' . a:name] + a:000)
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 ? 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
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 the buffer number of a filename
" @vimlint(EVL104, 1, l:old_shellslash)
function! syntastic#util#fname2buf(fname) abort " {{{2
if exists('+shellslash')
" bufnr() can't cope with backslashes
let old_shellslash = &shellslash
let &shellslash = 1
endif
" this is a best-effort attempt to escape file patterns (cf. :h file-pattern)
" XXX it fails for filenames containing something like \{2,3}
for md in [':~:.', ':~', ':p']
let buf = bufnr('^' . escape(fnamemodify(a:fname, md), '\*?,{}[') . '$')
if buf != -1
break
endif
endfor
if buf == -1
" XXX definitely wrong, but hope is the last thing to die :)
let buf = bufnr(fnamemodify(a:fname, ':p'))
endif
if exists('+shellslash')
let &shellslash = old_shellslash
endif
return buf
endfunction " }}}2
" @vimlint(EVL104, 0, l:old_shellslash)
" 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&lt;', '<', 'g')
let str = substitute(str, '\m&gt;', '>', 'g')
let str = substitute(str, '\m&quot;', '"', 'g')
let str = substitute(str, '\m&apos;', "'", 'g')
let str = substitute(str, '\m&amp;', '\&', '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#setLastTick(buf) abort " {{{2
call setbufvar(a:buf, 'syntastic_lasttick', getbufvar(a:buf, '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
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
" 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
" @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
let s:_str2float = function(exists('*str2float') ? 'str2float' : 'str2nr')
lockvar s:_str2float
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
function! s:_getbufvar_dumb(buf, name, ...) abort " {{{2
let ret = getbufvar(a:buf, a:name)
if a:0 && type(ret) == type('') && ret ==# ''
unlet! ret
let ret = a:1
endif
return ret
endfunction "}}}2
let s:_getbufvar = function(v:version > 703 || (v:version == 703 && has('patch831')) ? 'getbufvar' : 's:_getbufvar_dumb')
lockvar s:_getbufvar
" }}}1
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: set sw=4 sts=4 et fdm=marker: