123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- # Copyright (C) 2016 YouCompleteMe contributors
- #
- # This file is part of YouCompleteMe.
- #
- # YouCompleteMe is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # YouCompleteMe is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
- from __future__ import unicode_literals
- from __future__ import print_function
- from __future__ import division
- from __future__ import absolute_import
- # Not installing aliases from python-future; it's unreliable and slow.
- from builtins import * # noqa
- from future.utils import iterkeys, iteritems
- from ycm import vimsupport
- import re
- class DiagnosticFilter( object ):
- def __init__( self, config_or_filters ):
- if isinstance( config_or_filters, list ):
- self._filters = config_or_filters
- else:
- self._filters = _CompileFilters( config_or_filters )
- def IsAllowed( self, diagnostic ):
- # NOTE: a diagnostic IsAllowed() ONLY if NO filters match it
- for filterMatches in self._filters:
- if filterMatches( diagnostic ):
- return False
- return True
- def SubsetForTypes( self, filetypes ):
- """Return a sub-filter limited to the given filetypes"""
- # NOTE: actually, this class is already filtered
- return self
- @staticmethod
- def CreateFromOptions( user_options ):
- all_filters = user_options[ 'filter_diagnostics' ]
- compiled_by_type = {}
- for type_spec, filter_value in iteritems( all_filters ):
- filetypes = [ type_spec ]
- if type_spec.find( ',' ) != -1:
- filetypes = type_spec.split( ',' )
- for filetype in filetypes:
- compiled_by_type[ filetype ] = _CompileFilters( filter_value )
- return _MasterDiagnosticFilter( compiled_by_type )
- class _MasterDiagnosticFilter( object ):
- def __init__( self, all_filters ):
- self._all_filters = all_filters
- self._cache = {}
- def IsAllowed( self, diagnostic ):
- # NOTE: in this class's implementation, we ask vimsupport for
- # the current filetypes and delegate automatically; it is probably,
- # more efficient, however, to call SubsetForTypes() and reuse
- # the returned DiagnosticFilter if it will be checked repeatedly.
- filetypes = vimsupport.CurrentFiletypes()
- return self.SubsetForTypes( filetypes ).IsAllowed( diagnostic )
- def SubsetForTypes( self, filetypes ):
- # check cache
- cache_key = ','.join( filetypes )
- cached = self._cache.get( cache_key )
- if cached is not None:
- return cached
- # build a new DiagnosticFilter merging all filters
- # for the provided filetypes
- spec = []
- for filetype in filetypes:
- type_specific = self._all_filters.get( filetype, [] )
- spec.extend( type_specific )
- new_filter = DiagnosticFilter( spec )
- self._cache[ cache_key ] = new_filter
- return new_filter
- def _ListOf( config_entry ):
- if isinstance( config_entry, list ):
- return config_entry
- if config_entry is None:
- return []
- return [ config_entry ]
- def CompileRegex( raw_regex ):
- pattern = re.compile( raw_regex, re.IGNORECASE )
- def FilterRegex( diagnostic ):
- return pattern.search( diagnostic[ 'text' ] ) is not None
- return FilterRegex
- def CompileLevel( level ):
- # valid kinds are WARNING and ERROR;
- # expected input levels are `warning` and `error`
- # NOTE: we don't validate the input...
- expected_kind = level.upper()
- def FilterLevel( diagnostic ):
- return diagnostic[ 'kind' ] == expected_kind
- return FilterLevel
- FILTER_COMPILERS = { 'regex' : CompileRegex,
- 'level' : CompileLevel }
- def _CompileFilters( config ):
- """Given a filter config dictionary, return a list of compiled filters"""
- filters = []
- for filter_type in iterkeys( config ):
- compiler = FILTER_COMPILERS.get( filter_type )
- if compiler is not None:
- for filter_config in _ListOf( config[ filter_type ] ):
- compiledFilter = compiler( filter_config )
- filters.append( compiledFilter )
- return filters
|