소스 검색

Implement a preliminary quest_messages with regex support

dhleong 8 년 전
부모
커밋
f7fbbd16f7
4개의 변경된 파일205개의 추가작업 그리고 1개의 파일을 삭제
  1. 4 0
      plugin/youcompleteme.vim
  2. 95 0
      python/ycm/diagnostic_filter.py
  3. 3 1
      python/ycm/diagnostic_interface.py
  4. 103 0
      python/ycm/tests/diagnostic_filter_tests.py

+ 4 - 0
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' )
 

+ 95 - 0
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 <http://www.gnu.org/licenses/>.
+
+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 }

+ 3 - 1
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 )
 

+ 103 - 0
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 <http://www.gnu.org/licenses/>.
+
+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' )
+