From f7fbbd16f7fc75ab0622a2eb9f7149e06e2f1516 Mon Sep 17 00:00:00 2001 From: dhleong Date: Mon, 10 Oct 2016 14:08:51 -0400 Subject: [PATCH] Implement a preliminary quest_messages with regex support --- plugin/youcompleteme.vim | 4 + python/ycm/diagnostic_filter.py | 95 ++++++++++++++++++ python/ycm/diagnostic_interface.py | 4 +- python/ycm/tests/diagnostic_filter_tests.py | 103 ++++++++++++++++++++ 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 python/ycm/diagnostic_filter.py create mode 100644 python/ycm/tests/diagnostic_filter_tests.py diff --git a/plugin/youcompleteme.vim b/plugin/youcompleteme.vim index 268a7274..ec5399c9 100644 --- a/plugin/youcompleteme.vim +++ b/plugin/youcompleteme.vim @@ -121,6 +121,10 @@ let g:ycm_warning_symbol = \ get( g:, 'ycm_warning_symbol', \ get( g:, 'syntastic_warning_symbol', '>>' ) ) +let g:ycm_quiet_messages = + \ get( g:, 'ycm_quiet_messages', + \ get( g:, 'syntastic_quiet_messages', {} ) ) + let g:ycm_goto_buffer_command = \ get( g:, 'ycm_goto_buffer_command', 'same-buffer' ) diff --git a/python/ycm/diagnostic_filter.py b/python/ycm/diagnostic_filter.py new file mode 100644 index 00000000..523d605d --- /dev/null +++ b/python/ycm/diagnostic_filter.py @@ -0,0 +1,95 @@ +# Copyright (C) 2013 Google Inc. +# +# 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 . + +from __future__ import unicode_literals +from __future__ import print_function +from __future__ import division +from __future__ import absolute_import +from future import standard_library +standard_library.install_aliases() +from builtins import * # noqa + +from future.utils import itervalues, iteritems +from collections import defaultdict, namedtuple +from ycm import vimsupport +import re +import vim + + +class DiagnosticFilter( object ): + def __init__( self, config ): + self._filters = [] + + for filter_type in config.iterkeys(): + wrapper = lambda x: x + actual_filter_type = filter_type + + if filter_type[0] == '!': + wrapper = _Not + filter_type = filter_type[1:] + compiler = FILTER_COMPILERS.get( filter_type ) + + if compiler is not None: + for filter_config in _ListOf( config[ actual_filter_type ] ): + fn = wrapper( compiler( filter_config ) ) + self._filters.append( fn ) + + + def Accept( self, diagnostic ): + # NB: we Accept() the diagnostic ONLY if + # no filters match it + for f in self._filters: + if f( diagnostic ): + return False + + return True + + + @staticmethod + def from_filetype( user_options, filetypes ): + base = dict( user_options[ 'quiet_messages' ] ) + + for filetype in filetypes: + type_specific = user_options.get( filetype + '_quiet_messages', {} ) + base.update( type_specific ) + return DiagnosticFilter( base ) + + +def _ListOf( config_entry ): + if type( config_entry ) == type( [] ): + return config_entry + + return [ config_entry ] + + +def _Not( fn ): + def Inverted( diagnostic ): + return not fn( diagnostic ) + + return Inverted + + +def _CompileRegex( raw_regex ): + pattern = re.compile( raw_regex, re.IGNORECASE ) + + def Filter( diagnostic ): + return pattern.search( diagnostic[ 'text' ] ) is not None + + return Filter + + +FILTER_COMPILERS = { 'regex' : _CompileRegex } diff --git a/python/ycm/diagnostic_interface.py b/python/ycm/diagnostic_interface.py index 8607d8ec..089eac2d 100644 --- a/python/ycm/diagnostic_interface.py +++ b/python/ycm/diagnostic_interface.py @@ -26,6 +26,7 @@ from builtins import * # noqa from future.utils import itervalues, iteritems from collections import defaultdict, namedtuple from ycm import vimsupport +from ycm.diagnostic_filter import DiagnosticFilter import vim @@ -65,7 +66,8 @@ class DiagnosticInterface( object ): def UpdateWithNewDiagnostics( self, diags ): - normalized_diags = [ _NormalizeDiagnostic( x ) for x in diags ] + diag_filter = DiagnosticFilter.from_filetype( self._user_options, vimsupport.CurrentFiletypes() ) + normalized_diags = [ _NormalizeDiagnostic( x ) for x in diags if diag_filter.Accept(x) ] self._buffer_number_to_line_to_diags = _ConvertDiagListToDict( normalized_diags ) diff --git a/python/ycm/tests/diagnostic_filter_tests.py b/python/ycm/tests/diagnostic_filter_tests.py new file mode 100644 index 00000000..e03d96d8 --- /dev/null +++ b/python/ycm/tests/diagnostic_filter_tests.py @@ -0,0 +1,103 @@ +# Copyright (C) 2013 Google Inc. +# +# 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 . + +from __future__ import unicode_literals +from __future__ import print_function +from __future__ import division +from __future__ import absolute_import +from future import standard_library +standard_library.install_aliases() +from builtins import * # noqa + +from ycm.test_utils import MockVimModule +MockVimModule() + +import os +from hamcrest import assert_that, equal_to +from ycm.diagnostic_filter import DiagnosticFilter + + +def _assert_accept_equals( filter, text, expected ): + assert_that( filter.Accept( { 'text': text } ), equal_to( expected ) ) + +def _assert_accepts( filter, text ): + _assert_accept_equals( filter, text, True ) + +def _assert_rejects( filter, text ): + _assert_accept_equals( filter, text, False ) + + +class ConfigPriority_test(): + + def ConfigPriority_Global_test( self ): + opts = { 'quiet_messages': { 'regex': 'taco' } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_rejects( f, 'This is a Taco' ) + _assert_accepts( f, 'This is a Burrito' ) + + + def ConfigPriority_Filetype_test( self ): + opts = { 'quiet_messages' : {}, + 'java_quiet_messages' : { 'regex': 'taco' } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_rejects( f, 'This is a Taco' ) + _assert_accepts( f, 'This is a Burrito' ) + + + def ConfigPriority_FiletypeOverridesGlobal_test( self ): + # NB: if the filetype doesn't override the global, + # we would reject burrito and accept taco + opts = { 'quiet_messages' : { 'regex': 'burrito'}, + 'java_quiet_messages' : { 'regex': 'taco' } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_rejects( f, 'This is a Taco' ) + _assert_accepts( f, 'This is a Burrito' ) + + +class ListOrSingle_test(): + # NB: we already test the single config above + + def ListOrSingle_SingleList_test( self ): + # NB: if the filetype doesn't override the global, + # we would reject burrito and accept taco + opts = { 'quiet_messages' : { 'regex': [ 'taco' ] } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_rejects( f, 'This is a Taco' ) + _assert_accepts( f, 'This is a Burrito' ) + + + def ListOrSingle_MultiList_test( self ): + # NB: if the filetype doesn't override the global, + # we would reject burrito and accept taco + opts = { 'quiet_messages' : { 'regex': [ 'taco', 'burrito' ] } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_rejects( f, 'This is a Taco' ) + _assert_rejects( f, 'This is a Burrito' ) + + +def Invert_test(): + opts = { 'quiet_messages' : { '!regex': [ 'taco' ] } } + f = DiagnosticFilter.from_filetype( opts, [ 'java' ] ) + + _assert_accepts( f, 'This is a Taco' ) + _assert_rejects( f, 'This is a Burrito' ) +