diff options
Diffstat (limited to 'vim/bundle/syntastic/plugin/syntastic/checker.vim')
-rw-r--r-- | vim/bundle/syntastic/plugin/syntastic/checker.vim | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/vim/bundle/syntastic/plugin/syntastic/checker.vim b/vim/bundle/syntastic/plugin/syntastic/checker.vim new file mode 100644 index 0000000..22ad820 --- /dev/null +++ b/vim/bundle/syntastic/plugin/syntastic/checker.vim @@ -0,0 +1,273 @@ +if exists('g:loaded_syntastic_checker') || !exists('g:loaded_syntastic_plugin') + finish +endif +let g:loaded_syntastic_checker = 1 + +let g:SyntasticChecker = {} + +" Public methods {{{1 + +function! g:SyntasticChecker.New(args, ...) abort " {{{2 + let newObj = copy(self) + + let newObj._filetype = a:args['filetype'] + let newObj._name = a:args['name'] + + if a:0 + " redirected checker + let newObj._exec = get(a:args, 'exec', a:1['_exec']) + + let filetype = a:1['_filetype'] + let name = a:1['_name'] + let prefix = 'SyntaxCheckers_' . filetype . '_' . name . '_' + + if exists('g:syntastic_' . filetype . '_' . name . '_sort') && !exists('g:syntastic_' . newObj._filetype . '_' . newObj._name . '_sort') + let g:syntastic_{newObj._filetype}_{newObj._name}_sort = g:syntastic_{filetype}_{name}_sort + endif + + if has_key(a:args, 'enable') + let newObj._enable = a:args['enable'] + elseif has_key(a:1, '_enable') + let newObj._enable = a:1['_enable'] + endif + else + let newObj._exec = get(a:args, 'exec', newObj._name) + let prefix = 'SyntaxCheckers_' . newObj._filetype . '_' . newObj._name . '_' + + if has_key(a:args, 'enable') + let newObj._enable = a:args['enable'] + endif + endif + + let newObj._locListFunc = function(prefix . 'GetLocList') + + if exists('*' . prefix . 'IsAvailable') + let newObj._isAvailableFunc = function(prefix . 'IsAvailable') + else + let newObj._isAvailableFunc = function('s:_isAvailableDefault') + endif + + if exists('*' . prefix . 'GetHighlightRegex') + let newObj._highlightRegexFunc = function(prefix . 'GetHighlightRegex') + endif + + return newObj +endfunction " }}}2 + +function! g:SyntasticChecker.getFiletype() abort " {{{2 + return self._filetype +endfunction " }}}2 + +function! g:SyntasticChecker.getName() abort " {{{2 + return self._name +endfunction " }}}2 + +" Synchronise _exec with user's setting. Force re-validation if needed. +" +" XXX: This function must be called at least once before calling either +" getExec() or getExecEscaped(). Normally isAvailable() does that for you +" automatically, but you should keep still this in mind if you change the +" current checker workflow. +function! g:SyntasticChecker.syncExec() abort " {{{2 + let user_exec = + \ expand( exists('b:syntastic_' . self._name . '_exec') ? b:syntastic_{self._name}_exec : + \ syntastic#util#var(self._filetype . '_' . self._name . '_exec'), 1 ) + + if user_exec !=# '' && user_exec !=# self._exec + let self._exec = user_exec + if has_key(self, '_available') + " we have a new _exec on the block, it has to be validated + call remove(self, '_available') + endif + endif +endfunction " }}}2 + +function! g:SyntasticChecker.getExec() abort " {{{2 + return self._exec +endfunction " }}}2 + +function! g:SyntasticChecker.getExecEscaped() abort " {{{2 + return syntastic#util#shescape(self._exec) +endfunction " }}}2 + +function! g:SyntasticChecker.getLocListRaw() abort " {{{2 + let checker_start = reltime() + let name = self._filetype . '/' . self._name + + if has_key(self, '_enable') + let status = syntastic#util#var(self._enable, -1) + if type(status) != type(0) + call syntastic#log#error('checker ' . name . ': invalid value ' . strtrans(string(status)) . + \ ' for g:syntastic_' . self._enable . '; try 0 or 1 instead') + return [] + endif + if status < 0 + call syntastic#log#error('checker ' . name . ': checks disabled for security reasons; ' . + \ 'set g:syntastic_' . self._enable . ' to 1 to override') + endif + if status <= 0 + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' enabled but not forced') + return [] + else + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' forced') + endif + endif + + try + let list = self._locListFunc() + if self._exec !=# '' + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, 'getLocList: checker ' . name . ' returned ' . v:shell_error) + endif + catch /\m\C^Syntastic: checker error$/ + let list = [] + if self._exec !=# '' + call syntastic#log#error('checker ' . name . ' returned abnormal status ' . v:shell_error) + else + call syntastic#log#error('checker ' . name . ' aborted') + endif + endtry + call self._populateHighlightRegexes(list) + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, name . ' raw:', list) + call self._quietMessages(list) + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_TRACE, + \ 'getLocList: checker ' . name . ' run in ' . split(reltimestr(reltime(checker_start)))[0] . 's') + return list +endfunction " }}}2 + +function! g:SyntasticChecker.getLocList() abort " {{{2 + return g:SyntasticLoclist.New(self.getLocListRaw()) +endfunction " }}}2 + +function! g:SyntasticChecker.getVersion(...) abort " {{{2 + if !exists('self._version') + let command = a:0 ? a:1 : self.getExecEscaped() . ' --version' + let version_output = syntastic#util#system(command) + call self.log('getVersion: ' . string(command) . ': ' . + \ string(split(version_output, "\n", 1)) . + \ (v:shell_error ? ' (exit code ' . v:shell_error . ')' : '') ) + let parsed_ver = syntastic#util#parseVersion(version_output) + if len(parsed_ver) + call self.setVersion(parsed_ver) + else + call syntastic#log#ndebug(g:_SYNTASTIC_DEBUG_LOCLIST, 'checker output:', split(version_output, "\n", 1)) + call syntastic#log#error("checker " . self._filetype . "/" . self._name . ": can't parse version string (abnormal termination?)") + endif + endif + return get(self, '_version', []) +endfunction " }}}2 + +function! g:SyntasticChecker.setVersion(version) abort " {{{2 + if len(a:version) + let self._version = copy(a:version) + call self.log(self.getExec() . ' version =', a:version) + endif +endfunction " }}}2 + +function! g:SyntasticChecker.log(msg, ...) abort " {{{2 + let leader = self._filetype . '/' . self._name . ': ' + if a:0 > 0 + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, leader . a:msg, a:1) + else + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_CHECKERS, leader . a:msg) + endif +endfunction " }}}2 + +function! g:SyntasticChecker.makeprgBuild(opts) abort " {{{2 + let basename = self._filetype . '_' . self._name . '_' + + let parts = [] + call extend(parts, self._getOpt(a:opts, basename, 'exe', self.getExecEscaped())) + call extend(parts, self._getOpt(a:opts, basename, 'args', '')) + call extend(parts, self._getOpt(a:opts, basename, 'fname', syntastic#util#shexpand('%'))) + call extend(parts, self._getOpt(a:opts, basename, 'post_args', '')) + call extend(parts, self._getOpt(a:opts, basename, 'tail', '')) + + return join(parts) +endfunction " }}}2 + +function! g:SyntasticChecker.isAvailable() abort " {{{2 + call self.syncExec() + if !has_key(self, '_available') + let self._available = self._isAvailableFunc() + endif + return self._available +endfunction " }}}2 + +function! g:SyntasticChecker.isDisabled() abort " {{{2 + return has_key(self, '_enable') && syntastic#util#var(self._enable, -1) <= 0 +endfunction " }}}2 + +function! g:SyntasticChecker.wantSort() abort " {{{2 + return syntastic#util#var(self._filetype . '_' . self._name . '_sort', 0) +endfunction " }}}2 + +" This method is no longer used by syntastic. It's here only to maintain +" backwards compatibility with external checkers which might depend on it. +function! g:SyntasticChecker.setWantSort(val) abort " {{{2 + if !exists('g:syntastic_' . self._filetype . '_' . self._name . '_sort') + let g:syntastic_{self._filetype}_{self._name}_sort = a:val + endif +endfunction " }}}2 + +" }}}1 + +" Private methods {{{1 + +function! g:SyntasticChecker._quietMessages(errors) abort " {{{2 + " wildcard quiet_messages + let quiet_filters = copy(syntastic#util#var('quiet_messages', {})) + if type(quiet_filters) != type({}) + call syntastic#log#warn('ignoring invalid syntastic_quiet_messages') + unlet quiet_filters + let quiet_filters = {} + endif + + " per checker quiet_messages + let name = self._filetype . '_' . self._name + try + call extend( quiet_filters, copy(syntastic#util#var(name . '_quiet_messages', {})), 'force' ) + catch /\m^Vim\%((\a\+)\)\=:E712/ + call syntastic#log#warn('ignoring invalid syntastic_' . name . '_quiet_messages') + endtry + + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'quiet_messages filter:', quiet_filters) + + if !empty(quiet_filters) + call syntastic#util#dictFilter(a:errors, quiet_filters) + call syntastic#log#debug(g:_SYNTASTIC_DEBUG_LOCLIST, 'filtered by quiet_messages:', a:errors) + endif +endfunction " }}}2 + +function! g:SyntasticChecker._populateHighlightRegexes(errors) abort " {{{2 + if has_key(self, '_highlightRegexFunc') + for e in a:errors + if e['valid'] + let term = self._highlightRegexFunc(e) + if term !=# '' + let e['hl'] = term + endif + endif + endfor + endif +endfunction " }}}2 + +function! g:SyntasticChecker._getOpt(opts, basename, name, default) abort " {{{2 + let ret = [] + call extend( ret, syntastic#util#argsescape(get(a:opts, a:name . '_before', '')) ) + call extend( ret, syntastic#util#argsescape(syntastic#util#var( a:basename . a:name, get(a:opts, a:name, a:default) )) ) + call extend( ret, syntastic#util#argsescape(get(a:opts, a:name . '_after', '')) ) + + return ret +endfunction " }}}2 + +" }}}1 + +" Private functions {{{1 + +function! s:_isAvailableDefault() dict " {{{2 + return executable(self.getExec()) +endfunction " }}}2 + +" }}}1 + +" vim: set sw=4 sts=4 et fdm=marker: |