Moved change tracking to python. Per buffer diags

This commit is contained in:
Davit Samvelyan 2017-05-01 01:17:20 +04:00
parent 263bd88bd5
commit 979f14acfd
7 changed files with 236 additions and 120 deletions

100
python/ycm/buffer.py Normal file
View File

@ -0,0 +1,100 @@
# Copyright (C) 2016, Davit Samvelyan
#
# 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 ycm import vimsupport
from ycm.client.event_notification import EventNotification
from ycm.diagnostic_interface import DiagnosticInterface
class Buffer( object ):
def __init__( self, bufnr, user_options ):
self.number = bufnr
self._parse_tick = 0
self._handled_tick = 0
self._parse_request = None
self._diag_interface = DiagnosticInterface( user_options )
def FileParseRequestReady( self, block = False ):
return self._parse_tick == 0 or block or self._parse_request.Done()
def SendParseRequest( self, extra_data ):
self._parse_request = EventNotification( 'FileReadyToParse',
extra_data = extra_data )
self._parse_request.Start()
self._parse_tick = self._ChangedTick()
def NeedsReparse( self ):
return self._parse_tick != self._ChangedTick()
def UpdateDiagnostics( self ):
diagnostics = self._parse_request.Response()
self._diag_interface.UpdateWithNewDiagnostics( diagnostics )
def PopulateLocationList( self ):
return self._diag_interface.PopulateLocationList()
def GetResponse( self ):
return self._parse_request.Response()
def IsResponseHandled( self ):
return self._handled_tick == self._parse_tick
def MarkResponseHandled( self ):
self._handled_tick = self._parse_tick
def OnCursorMoved( self ):
self._diag_interface.OnCursorMoved()
def GetErrorCount( self ):
return self._diag_interface.GetErrorCount()
def GetWarningCount( self ):
return self._diag_interface.GetWarningCount()
def _ChangedTick( self ):
return vimsupport.GetBufferChangedTick( self.number )
class BufferDict( dict ):
def __init__( self, user_options ):
self._user_options = user_options
def __missing__( self, key ):
value = self[ key ] = Buffer( key, self._user_options )
return value

View File

@ -32,6 +32,7 @@ import vim
class DiagnosticInterface( object ): class DiagnosticInterface( object ):
def __init__( self, user_options ): def __init__( self, user_options ):
self._user_options = user_options self._user_options = user_options
self._diagnostics = []
self._diag_filter = DiagnosticFilter.CreateFromOptions( user_options ) self._diag_filter = DiagnosticFilter.CreateFromOptions( user_options )
# Line and column numbers are 1-based # Line and column numbers are 1-based
self._buffer_number_to_line_to_diags = defaultdict( self._buffer_number_to_line_to_diags = defaultdict(
@ -60,17 +61,18 @@ class DiagnosticInterface( object ):
return len( self._FilterDiagnostics( _DiagnosticIsWarning ) ) return len( self._FilterDiagnostics( _DiagnosticIsWarning ) )
def PopulateLocationList( self, diags ): def PopulateLocationList( self ):
vimsupport.SetLocationList( # Do nothing if loc list is already populated by diag_interface
vimsupport.ConvertDiagnosticsToQfList( if not self._user_options[ 'always_populate_location_list' ]:
self._ApplyDiagnosticFilter( diags ) ) ) self._UpdateLocationList()
return bool( self._diagnostics )
def UpdateWithNewDiagnostics( self, diags ): def UpdateWithNewDiagnostics( self, diags ):
normalized_diags = [ _NormalizeDiagnostic( x ) for x in self._diagnostics = [ _NormalizeDiagnostic( x ) for x in
self._ApplyDiagnosticFilter( diags ) ] self._ApplyDiagnosticFilter( diags ) ]
self._buffer_number_to_line_to_diags = _ConvertDiagListToDict( self._buffer_number_to_line_to_diags = _ConvertDiagListToDict(
normalized_diags ) self._diagnostics )
if self._user_options[ 'enable_diagnostic_signs' ]: if self._user_options[ 'enable_diagnostic_signs' ]:
self._placed_signs, self._next_sign_id = _UpdateSigns( self._placed_signs, self._next_sign_id = _UpdateSigns(
@ -82,7 +84,7 @@ class DiagnosticInterface( object ):
_UpdateSquiggles( self._buffer_number_to_line_to_diags ) _UpdateSquiggles( self._buffer_number_to_line_to_diags )
if self._user_options[ 'always_populate_location_list' ]: if self._user_options[ 'always_populate_location_list' ]:
self.PopulateLocationList( normalized_diags ) self._UpdateLocationList()
def _ApplyDiagnosticFilter( self, diags, extra_predicate = None ): def _ApplyDiagnosticFilter( self, diags, extra_predicate = None ):
@ -128,6 +130,11 @@ class DiagnosticInterface( object ):
return matched_diags return matched_diags
def _UpdateLocationList( self ):
vimsupport.SetLocationList(
vimsupport.ConvertDiagnosticsToQfList( self._diagnostics ) )
def _UpdateSquiggles( buffer_number_to_line_to_diags ): def _UpdateSquiggles( buffer_number_to_line_to_diags ):
vimsupport.ClearYcmSyntaxMatches() vimsupport.ClearYcmSyntaxMatches()
line_to_diags = buffer_number_to_line_to_diags[ vim.current.buffer.number ] line_to_diags = buffer_number_to_line_to_diags[ vim.current.buffer.number ]

View File

@ -25,6 +25,7 @@ from __future__ import absolute_import
from builtins import * # noqa from builtins import * # noqa
from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock, from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock,
EmulateCurrentBufferChange,
MockVimBuffers, MockVimModule, VimBuffer ) MockVimBuffers, MockVimModule, VimBuffer )
MockVimModule() MockVimModule()
@ -105,6 +106,9 @@ def MockEventNotification( response_method, native_filetype_completer = True ):
'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype', 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = native_filetype_completer ): return_value = native_filetype_completer ):
with patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
return_value = True ):
yield yield
@ -138,6 +142,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_Error_test(
call( ERROR_TEXT, truncate = True ) call( ERROR_TEXT, truncate = True )
] ) ] )
EmulateCurrentBufferChange()
# But it does if a subsequent event raises again # But it does if a subsequent event raises again
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ok_( ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
@ -207,6 +212,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
call( FILE_NAME ), call( FILE_NAME ),
] ) ] )
EmulateCurrentBufferChange()
# But it does if a subsequent event raises again # But it does if a subsequent event raises again
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ok_( ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
@ -221,6 +227,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
call( FILE_NAME ), call( FILE_NAME ),
] ) ] )
EmulateCurrentBufferChange()
# When the user rejects the extra conf, we reject it # When the user rejects the extra conf, we reject it
with patch( 'ycm.vimsupport.PresentDialog', with patch( 'ycm.vimsupport.PresentDialog',
return_value = 1, return_value = 1,
@ -246,6 +253,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
call( FILE_NAME ), call( FILE_NAME ),
] ) ] )
EmulateCurrentBufferChange()
# But it does if a subsequent event raises again # But it does if a subsequent event raises again
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ok_( ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
@ -263,8 +271,11 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
@YouCompleteMeInstance() @YouCompleteMeInstance()
def EventNotification_FileReadyToParse_Diagnostic_Error_Native_test( ycm ): def EventNotification_FileReadyToParse_Diagnostic_Error_Native_test( ycm ):
with MockArbitraryBuffer( 'cpp' ):
_Check_FileReadyToParse_Diagnostic_Error( ycm ) _Check_FileReadyToParse_Diagnostic_Error( ycm )
EmulateCurrentBufferChange()
_Check_FileReadyToParse_Diagnostic_Warning( ycm ) _Check_FileReadyToParse_Diagnostic_Warning( ycm )
EmulateCurrentBufferChange()
_Check_FileReadyToParse_Diagnostic_Clean( ycm ) _Check_FileReadyToParse_Diagnostic_Clean( ycm )
@ -279,7 +290,6 @@ def _Check_FileReadyToParse_Diagnostic_Error( ycm, vim_command ):
diagnostic = Diagnostic( [], start, extent, 'expected ;', 'ERROR' ) diagnostic = Diagnostic( [], start, extent, 'expected ;', 'ERROR' )
return [ BuildDiagnosticData( diagnostic ) ] return [ BuildDiagnosticData( diagnostic ) ]
with MockArbitraryBuffer( 'cpp' ):
with MockEventNotification( DiagnosticResponse ): with MockEventNotification( DiagnosticResponse ):
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ok_( ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
@ -293,7 +303,7 @@ def _Check_FileReadyToParse_Diagnostic_Error( ycm, vim_command ):
# Consequent calls to HandleFileParseRequest shouldn't mess with # Consequent calls to HandleFileParseRequest shouldn't mess with
# existing diagnostics, when there is no new parse request. # existing diagnostics, when there is no new parse request.
vim_command.reset_mock() vim_command.reset_mock()
ok_( not ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
ycm.HandleFileParseRequest() ycm.HandleFileParseRequest()
vim_command.assert_not_called() vim_command.assert_not_called()
eq_( ycm.GetErrorCount(), 1 ) eq_( ycm.GetErrorCount(), 1 )
@ -312,7 +322,6 @@ def _Check_FileReadyToParse_Diagnostic_Warning( ycm, vim_command ):
diagnostic = Diagnostic( [], start, extent, 'cast', 'WARNING' ) diagnostic = Diagnostic( [], start, extent, 'cast', 'WARNING' )
return [ BuildDiagnosticData( diagnostic ) ] return [ BuildDiagnosticData( diagnostic ) ]
with MockArbitraryBuffer( 'cpp' ):
with MockEventNotification( DiagnosticResponse ): with MockEventNotification( DiagnosticResponse ):
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ok_( ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
@ -327,7 +336,7 @@ def _Check_FileReadyToParse_Diagnostic_Warning( ycm, vim_command ):
# Consequent calls to HandleFileParseRequest shouldn't mess with # Consequent calls to HandleFileParseRequest shouldn't mess with
# existing diagnostics, when there is no new parse request. # existing diagnostics, when there is no new parse request.
vim_command.reset_mock() vim_command.reset_mock()
ok_( not ycm.FileParseRequestReady() ) ok_( ycm.FileParseRequestReady() )
ycm.HandleFileParseRequest() ycm.HandleFileParseRequest()
vim_command.assert_not_called() vim_command.assert_not_called()
eq_( ycm.GetErrorCount(), 0 ) eq_( ycm.GetErrorCount(), 0 )
@ -339,7 +348,6 @@ def _Check_FileReadyToParse_Diagnostic_Clean( ycm, vim_command ):
# Tests Vim sign unplacement and error/warning count python API # Tests Vim sign unplacement and error/warning count python API
# when there are no errors/warnings left. # when there are no errors/warnings left.
# Should be called after _Check_FileReadyToParse_Diagnostic_Warning # Should be called after _Check_FileReadyToParse_Diagnostic_Warning
with MockArbitraryBuffer( 'cpp' ):
with MockEventNotification( MagicMock( return_value = [] ) ): with MockEventNotification( MagicMock( return_value = [] ) ):
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
ycm.HandleFileParseRequest() ycm.HandleFileParseRequest()
@ -364,6 +372,8 @@ def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
'PostDataToHandlerAsync' ) as post_data_to_handler_async: 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
with CurrentWorkingDirectory( unicode_dir ): with CurrentWorkingDirectory( unicode_dir ):
with MockVimBuffers( [ current_buffer ], current_buffer, ( 6, 5 ) ): with MockVimBuffers( [ current_buffer ], current_buffer, ( 6, 5 ) ):
with patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
return_value = True ):
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse()
assert_that( assert_that(

View File

@ -40,7 +40,7 @@ BUFWINNR_REGEX = re.compile( '^bufwinnr\((?P<buffer_number>[0-9]+)\)$' )
BWIPEOUT_REGEX = re.compile( BWIPEOUT_REGEX = re.compile(
'^(?:silent! )bwipeout!? (?P<buffer_number>[0-9]+)$' ) '^(?:silent! )bwipeout!? (?P<buffer_number>[0-9]+)$' )
GETBUFVAR_REGEX = re.compile( GETBUFVAR_REGEX = re.compile(
'^getbufvar\((?P<buffer_number>[0-9]+), "&(?P<option>.+)"\)$' ) '^getbufvar\((?P<buffer_number>[0-9]+), "(?P<option>.+)"\)$' )
MATCHADD_REGEX = re.compile( MATCHADD_REGEX = re.compile(
'^matchadd\(\'(?P<group>.+)\', \'(?P<pattern>.+)\'\)$' ) '^matchadd\(\'(?P<group>.+)\', \'(?P<pattern>.+)\'\)$' )
MATCHDELETE_REGEX = re.compile( '^matchdelete\((?P<id>)\)$' ) MATCHDELETE_REGEX = re.compile( '^matchdelete\((?P<id>)\)$' )
@ -85,10 +85,12 @@ def _MockGetBufferWindowNumber( buffer_number ):
def _MockGetBufferVariable( buffer_number, option ): def _MockGetBufferVariable( buffer_number, option ):
for vim_buffer in VIM_MOCK.buffers: for vim_buffer in VIM_MOCK.buffers:
if vim_buffer.number == buffer_number: if vim_buffer.number == buffer_number:
if option == 'mod': if option == '&mod':
return vim_buffer.modified return vim_buffer.modified
if option == 'ft': if option == '&ft':
return vim_buffer.filetype return vim_buffer.filetype
if option == 'changedtick':
return vim_buffer.changedtick
return '' return ''
return '' return ''
@ -230,6 +232,7 @@ class VimBuffer( object ):
self.modified = modified self.modified = modified
self.window = window self.window = window
self.omnifunc = omnifunc self.omnifunc = omnifunc
self.changedtick = 1
def __getitem__( self, index ): def __getitem__( self, index ):
@ -250,6 +253,10 @@ class VimBuffer( object ):
return [ ToUnicode( x ) for x in self.contents ] return [ ToUnicode( x ) for x in self.contents ]
def EmulateCurrentBufferChange():
VIM_MOCK.current.buffer.changedtick += 1
class VimMatch( object ): class VimMatch( object ):
def __init__( self, group, pattern ): def __init__( self, group, pattern ):

View File

@ -349,6 +349,7 @@ def YouCompleteMe_ShowDiagnostics_NoDiagnosticsDetected_test(
'open_loclist_on_ycm_diags': 0 } ) 'open_loclist_on_ycm_diags': 0 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype', @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True ) return_value = True )
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock )
def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test( def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
@ -388,6 +389,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
@YouCompleteMeInstance( { 'open_loclist_on_ycm_diags': 1 } ) @YouCompleteMeInstance( { 'open_loclist_on_ycm_diags': 1 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype', @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True ) return_value = True )
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock )
@patch( 'ycm.vimsupport.OpenLocationList', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.OpenLocationList', new_callable = ExtendedMock )
@ -431,6 +433,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_OpenLocationList_test(
'enable_diagnostic_highlighting': 1 } ) 'enable_diagnostic_highlighting': 1 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype', @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True ) return_value = True )
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@patch( 'vim.command', new_callable = ExtendedMock ) @patch( 'vim.command', new_callable = ExtendedMock )
def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test( def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
@ -511,8 +514,7 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 1 ) ): with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 1 ) ):
with patch( 'ycm.client.event_notification.EventNotification.Response', with patch( 'ycm.client.event_notification.EventNotification.Response',
return_value = diagnostics ): return_value = diagnostics ):
ycm.OnFileReadyToParse() ycm.OnFileReadyToParse( block = True )
ycm.HandleFileParseRequest( block = True )
# Error match is added after warning matches. # Error match is added after warning matches.
assert_that( assert_that(

View File

@ -147,6 +147,14 @@ def GetBufferFilepath( buffer_object ):
return os.path.join( GetCurrentDirectory(), str( buffer_object.number ) ) return os.path.join( GetCurrentDirectory(), str( buffer_object.number ) )
def GetCurrentBufferNumber():
return vim.current.buffer.number
def GetBufferChangedTick( bufnr ):
return GetIntValue( 'getbufvar({0}, "changedtick")'.format( bufnr ) )
def UnplaceSignInBuffer( buffer_number, sign_id ): def UnplaceSignInBuffer( buffer_number, sign_id ):
if buffer_number < 0: if buffer_number < 0:
return return

View File

@ -33,10 +33,10 @@ import vim
from subprocess import PIPE from subprocess import PIPE
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from ycm import base, paths, vimsupport from ycm import base, paths, vimsupport
from ycm.buffer import BufferDict
from ycmd import utils from ycmd import utils
from ycmd import server_utils from ycmd import server_utils
from ycmd.request_wrap import RequestWrap from ycmd.request_wrap import RequestWrap
from ycm.diagnostic_interface import DiagnosticInterface
from ycm.omni_completer import OmniCompleter from ycm.omni_completer import OmniCompleter
from ycm import syntax_parse from ycm import syntax_parse
from ycm.client.ycmd_keepalive import YcmdKeepalive from ycm.client.ycmd_keepalive import YcmdKeepalive
@ -49,8 +49,7 @@ from ycm.client.completion_request import ( CompletionRequest,
from ycm.client.debug_info_request import ( SendDebugInfoRequest, from ycm.client.debug_info_request import ( SendDebugInfoRequest,
FormatDebugInfoResponse ) FormatDebugInfoResponse )
from ycm.client.omni_completion_request import OmniCompletionRequest from ycm.client.omni_completion_request import OmniCompletionRequest
from ycm.client.event_notification import ( SendEventNotificationAsync, from ycm.client.event_notification import SendEventNotificationAsync
EventNotification )
from ycm.client.shutdown_request import SendShutdownRequest from ycm.client.shutdown_request import SendShutdownRequest
@ -114,11 +113,9 @@ class YouCompleteMe( object ):
self._available_completers = {} self._available_completers = {}
self._user_options = user_options self._user_options = user_options
self._user_notified_about_crash = False self._user_notified_about_crash = False
self._diag_interface = DiagnosticInterface( user_options )
self._omnicomp = OmniCompleter( user_options ) self._omnicomp = OmniCompleter( user_options )
self._latest_file_parse_request = None self._buffers = BufferDict( user_options )
self._latest_completion_request = None self._latest_completion_request = None
self._latest_diagnostics = []
self._logger = logging.getLogger( 'ycm' ) self._logger = logging.getLogger( 'ycm' )
self._client_logfile = None self._client_logfile = None
self._server_stdout = None self._server_stdout = None
@ -134,6 +131,11 @@ class YouCompleteMe( object ):
'cs': lambda self: self._OnCompleteDone_Csharp() 'cs': lambda self: self._OnCompleteDone_Csharp()
} }
def _GetCurrentBuffer( self ):
return self._buffers[ vimsupport.GetCurrentBufferNumber() ]
def _SetupServer( self ): def _SetupServer( self ):
self._available_completers = {} self._available_completers = {}
self._user_notified_about_crash = False self._user_notified_about_crash = False
@ -353,21 +355,28 @@ class YouCompleteMe( object ):
self.NativeFiletypeCompletionAvailable() ) self.NativeFiletypeCompletionAvailable() )
def OnFileReadyToParse( self ): def OnFileReadyToParse( self, block = False, force = False ):
if not self.IsServerAlive(): if not self.IsServerAlive():
self._NotifyUserIfServerCrashed() self._NotifyUserIfServerCrashed()
return return
if not self.IsServerReady():
return
self._omnicomp.OnFileReadyToParse( None ) self._omnicomp.OnFileReadyToParse( None )
self.HandleFileParseRequest()
current_buffer = self._GetCurrentBuffer()
if force_parsing or current_buffer.NeedsReparse():
extra_data = {} extra_data = {}
self._AddTagsFilesIfNeeded( extra_data ) self._AddTagsFilesIfNeeded( extra_data )
self._AddSyntaxDataIfNeeded( extra_data ) self._AddSyntaxDataIfNeeded( extra_data )
self._AddExtraConfDataIfNeeded( extra_data ) self._AddExtraConfDataIfNeeded( extra_data )
self._latest_file_parse_request = EventNotification( current_buffer.SendParseRequest( extra_data )
'FileReadyToParse', extra_data = extra_data ) if block:
self._latest_file_parse_request.Start() self.HandleFileParseRequest()
def OnBufferUnload( self, deleted_buffer_file ): def OnBufferUnload( self, deleted_buffer_file ):
@ -385,7 +394,7 @@ class YouCompleteMe( object ):
def OnCursorMoved( self ): def OnCursorMoved( self ):
self._diag_interface.OnCursorMoved() self._GetCurrentBuffer().OnCursorMoved()
def _CleanLogfile( self ): def _CleanLogfile( self ):
@ -512,11 +521,11 @@ class YouCompleteMe( object ):
def GetErrorCount( self ): def GetErrorCount( self ):
return self._diag_interface.GetErrorCount() return self._GetCurrentBuffer().GetErrorCount()
def GetWarningCount( self ): def GetWarningCount( self ):
return self._diag_interface.GetWarningCount() return self._GetCurrentBuffer().GetWarningCount()
def DiagnosticUiSupportedForCurrentFiletype( self ): def DiagnosticUiSupportedForCurrentFiletype( self ):
@ -530,51 +539,25 @@ class YouCompleteMe( object ):
def _PopulateLocationListWithLatestDiagnostics( self ): def _PopulateLocationListWithLatestDiagnostics( self ):
# Do nothing if loc list is already populated by diag_interface return self._GetCurrentBuffer().PopulateLocationList()
if not self._user_options[ 'always_populate_location_list' ]:
self._diag_interface.PopulateLocationList( self._latest_diagnostics )
return bool( self._latest_diagnostics )
def UpdateDiagnosticInterface( self ): def FileParseRequestReady( self ):
self._diag_interface.UpdateWithNewDiagnostics( self._latest_diagnostics ) return self._GetCurrentBuffer().FileParseRequestReady()
def FileParseRequestReady( self, block = False ): def HandleFileParseRequest( self ):
return bool( self._latest_file_parse_request and current_buffer = self._GetCurrentBuffer()
( block or self._latest_file_parse_request.Done() ) ) if current_buffer.IsResponseHandled():
return
def HandleFileParseRequest( self, block = False ):
# Order is important here:
# FileParseRequestReady has a low cost, while
# NativeFiletypeCompletionUsable is a blocking server request # NativeFiletypeCompletionUsable is a blocking server request
if ( self.FileParseRequestReady( block ) and if self.NativeFiletypeCompletionUsable():
self.NativeFiletypeCompletionUsable() ): current_buffer.GetResponse()
if self.ShouldDisplayDiagnostics(): if self.ShouldDisplayDiagnostics():
self._latest_diagnostics = self._latest_file_parse_request.Response() current_buffer.UpdateDiagnostics()
self.UpdateDiagnosticInterface()
else:
# YCM client has a hard-coded list of filetypes which are known
# to support diagnostics, self.DiagnosticUiSupportedForCurrentFiletype()
#
# For filetypes which don't support diagnostics, we just want to check
# the _latest_file_parse_request for any exception or UnknownExtraConf
# response, to allow the server to raise configuration warnings, etc.
# to the user. We ignore any other supplied data.
self._latest_file_parse_request.Response()
# We set the file parse request to None because we want to prevent current_buffer.MarkResponseHandled()
# repeated issuing of the same warnings/errors/prompts. Setting this to
# None makes FileParseRequestReady return False until the next
# request is created.
#
# Note: it is the server's responsibility to determine the frequency of
# error/warning/prompts when receiving a FileReadyToParse event, but
# it our responsibility to ensure that we only apply the
# warning/error/prompt received once (for each event).
self._latest_file_parse_request = None
def DebugInfo( self ): def DebugInfo( self ):
@ -683,8 +666,7 @@ class YouCompleteMe( object ):
vimsupport.PostVimMessage( vimsupport.PostVimMessage(
'Forcing compilation, this will block Vim until done.', 'Forcing compilation, this will block Vim until done.',
warning = False ) warning = False )
self.OnFileReadyToParse() self.OnFileReadyToParse( block = True )
self.HandleFileParseRequest( block = True )
vimsupport.PostVimMessage( 'Diagnostics refreshed', warning = False ) vimsupport.PostVimMessage( 'Diagnostics refreshed', warning = False )
return True return True