Moved change tracking to python. Per buffer diags
This commit is contained in:
parent
263bd88bd5
commit
979f14acfd
100
python/ycm/buffer.py
Normal file
100
python/ycm/buffer.py
Normal 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
|
@ -32,6 +32,7 @@ import vim
|
||||
class DiagnosticInterface( object ):
|
||||
def __init__( self, user_options ):
|
||||
self._user_options = user_options
|
||||
self._diagnostics = []
|
||||
self._diag_filter = DiagnosticFilter.CreateFromOptions( user_options )
|
||||
# Line and column numbers are 1-based
|
||||
self._buffer_number_to_line_to_diags = defaultdict(
|
||||
@ -60,17 +61,18 @@ class DiagnosticInterface( object ):
|
||||
return len( self._FilterDiagnostics( _DiagnosticIsWarning ) )
|
||||
|
||||
|
||||
def PopulateLocationList( self, diags ):
|
||||
vimsupport.SetLocationList(
|
||||
vimsupport.ConvertDiagnosticsToQfList(
|
||||
self._ApplyDiagnosticFilter( diags ) ) )
|
||||
def PopulateLocationList( self ):
|
||||
# Do nothing if loc list is already populated by diag_interface
|
||||
if not self._user_options[ 'always_populate_location_list' ]:
|
||||
self._UpdateLocationList()
|
||||
return bool( self._diagnostics )
|
||||
|
||||
|
||||
def UpdateWithNewDiagnostics( self, diags ):
|
||||
normalized_diags = [ _NormalizeDiagnostic( x ) for x in
|
||||
self._ApplyDiagnosticFilter( diags ) ]
|
||||
self._diagnostics = [ _NormalizeDiagnostic( x ) for x in
|
||||
self._ApplyDiagnosticFilter( diags ) ]
|
||||
self._buffer_number_to_line_to_diags = _ConvertDiagListToDict(
|
||||
normalized_diags )
|
||||
self._diagnostics )
|
||||
|
||||
if self._user_options[ 'enable_diagnostic_signs' ]:
|
||||
self._placed_signs, self._next_sign_id = _UpdateSigns(
|
||||
@ -82,7 +84,7 @@ class DiagnosticInterface( object ):
|
||||
_UpdateSquiggles( self._buffer_number_to_line_to_diags )
|
||||
|
||||
if self._user_options[ 'always_populate_location_list' ]:
|
||||
self.PopulateLocationList( normalized_diags )
|
||||
self._UpdateLocationList()
|
||||
|
||||
|
||||
def _ApplyDiagnosticFilter( self, diags, extra_predicate = None ):
|
||||
@ -128,6 +130,11 @@ class DiagnosticInterface( object ):
|
||||
return matched_diags
|
||||
|
||||
|
||||
def _UpdateLocationList( self ):
|
||||
vimsupport.SetLocationList(
|
||||
vimsupport.ConvertDiagnosticsToQfList( self._diagnostics ) )
|
||||
|
||||
|
||||
def _UpdateSquiggles( buffer_number_to_line_to_diags ):
|
||||
vimsupport.ClearYcmSyntaxMatches()
|
||||
line_to_diags = buffer_number_to_line_to_diags[ vim.current.buffer.number ]
|
||||
|
@ -25,6 +25,7 @@ from __future__ import absolute_import
|
||||
from builtins import * # noqa
|
||||
|
||||
from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock,
|
||||
EmulateCurrentBufferChange,
|
||||
MockVimBuffers, MockVimModule, VimBuffer )
|
||||
MockVimModule()
|
||||
|
||||
@ -105,7 +106,10 @@ def MockEventNotification( response_method, native_filetype_completer = True ):
|
||||
'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
|
||||
return_value = native_filetype_completer ):
|
||||
|
||||
yield
|
||||
with patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||
return_value = True ):
|
||||
|
||||
yield
|
||||
|
||||
|
||||
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||
@ -138,6 +142,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_Error_test(
|
||||
call( ERROR_TEXT, truncate = True )
|
||||
] )
|
||||
|
||||
EmulateCurrentBufferChange()
|
||||
# But it does if a subsequent event raises again
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
@ -207,6 +212,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
|
||||
call( FILE_NAME ),
|
||||
] )
|
||||
|
||||
EmulateCurrentBufferChange()
|
||||
# But it does if a subsequent event raises again
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
@ -221,6 +227,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
|
||||
call( FILE_NAME ),
|
||||
] )
|
||||
|
||||
EmulateCurrentBufferChange()
|
||||
# When the user rejects the extra conf, we reject it
|
||||
with patch( 'ycm.vimsupport.PresentDialog',
|
||||
return_value = 1,
|
||||
@ -246,6 +253,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
|
||||
call( FILE_NAME ),
|
||||
] )
|
||||
|
||||
EmulateCurrentBufferChange()
|
||||
# But it does if a subsequent event raises again
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
@ -263,9 +271,12 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
|
||||
|
||||
@YouCompleteMeInstance()
|
||||
def EventNotification_FileReadyToParse_Diagnostic_Error_Native_test( ycm ):
|
||||
_Check_FileReadyToParse_Diagnostic_Error( ycm )
|
||||
_Check_FileReadyToParse_Diagnostic_Warning( ycm )
|
||||
_Check_FileReadyToParse_Diagnostic_Clean( ycm )
|
||||
with MockArbitraryBuffer( 'cpp' ):
|
||||
_Check_FileReadyToParse_Diagnostic_Error( ycm )
|
||||
EmulateCurrentBufferChange()
|
||||
_Check_FileReadyToParse_Diagnostic_Warning( ycm )
|
||||
EmulateCurrentBufferChange()
|
||||
_Check_FileReadyToParse_Diagnostic_Clean( ycm )
|
||||
|
||||
|
||||
@patch( 'vim.command' )
|
||||
@ -279,25 +290,24 @@ def _Check_FileReadyToParse_Diagnostic_Error( ycm, vim_command ):
|
||||
diagnostic = Diagnostic( [], start, extent, 'expected ;', 'ERROR' )
|
||||
return [ BuildDiagnosticData( diagnostic ) ]
|
||||
|
||||
with MockArbitraryBuffer( 'cpp' ):
|
||||
with MockEventNotification( DiagnosticResponse ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
PlaceSign_Call( 1, 1, 1, True )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 1 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
with MockEventNotification( DiagnosticResponse ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
PlaceSign_Call( 1, 1, 1, True )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 1 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
|
||||
# Consequent calls to HandleFileParseRequest shouldn't mess with
|
||||
# existing diagnostics, when there is no new parse request.
|
||||
vim_command.reset_mock()
|
||||
ok_( not ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_not_called()
|
||||
eq_( ycm.GetErrorCount(), 1 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
# Consequent calls to HandleFileParseRequest shouldn't mess with
|
||||
# existing diagnostics, when there is no new parse request.
|
||||
vim_command.reset_mock()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_not_called()
|
||||
eq_( ycm.GetErrorCount(), 1 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
|
||||
|
||||
@patch( 'vim.command' )
|
||||
@ -312,26 +322,25 @@ def _Check_FileReadyToParse_Diagnostic_Warning( ycm, vim_command ):
|
||||
diagnostic = Diagnostic( [], start, extent, 'cast', 'WARNING' )
|
||||
return [ BuildDiagnosticData( diagnostic ) ]
|
||||
|
||||
with MockArbitraryBuffer( 'cpp' ):
|
||||
with MockEventNotification( DiagnosticResponse ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
PlaceSign_Call( 2, 2, 1, False ),
|
||||
UnplaceSign_Call( 1, 1 )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 1 )
|
||||
with MockEventNotification( DiagnosticResponse ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
PlaceSign_Call( 2, 2, 1, False ),
|
||||
UnplaceSign_Call( 1, 1 )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 1 )
|
||||
|
||||
# Consequent calls to HandleFileParseRequest shouldn't mess with
|
||||
# existing diagnostics, when there is no new parse request.
|
||||
vim_command.reset_mock()
|
||||
ok_( not ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_not_called()
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 1 )
|
||||
# Consequent calls to HandleFileParseRequest shouldn't mess with
|
||||
# existing diagnostics, when there is no new parse request.
|
||||
vim_command.reset_mock()
|
||||
ok_( ycm.FileParseRequestReady() )
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_not_called()
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 1 )
|
||||
|
||||
|
||||
@patch( 'vim.command' )
|
||||
@ -339,15 +348,14 @@ def _Check_FileReadyToParse_Diagnostic_Clean( ycm, vim_command ):
|
||||
# Tests Vim sign unplacement and error/warning count python API
|
||||
# when there are no errors/warnings left.
|
||||
# Should be called after _Check_FileReadyToParse_Diagnostic_Warning
|
||||
with MockArbitraryBuffer( 'cpp' ):
|
||||
with MockEventNotification( MagicMock( return_value = [] ) ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
UnplaceSign_Call( 2, 1 )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
with MockEventNotification( MagicMock( return_value = [] ) ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ycm.HandleFileParseRequest()
|
||||
vim_command.assert_has_calls( [
|
||||
UnplaceSign_Call( 2, 1 )
|
||||
] )
|
||||
eq_( ycm.GetErrorCount(), 0 )
|
||||
eq_( ycm.GetWarningCount(), 0 )
|
||||
|
||||
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
|
||||
@ -364,7 +372,9 @@ def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
|
||||
'PostDataToHandlerAsync' ) as post_data_to_handler_async:
|
||||
with CurrentWorkingDirectory( unicode_dir ):
|
||||
with MockVimBuffers( [ current_buffer ], current_buffer, ( 6, 5 ) ):
|
||||
ycm.OnFileReadyToParse()
|
||||
with patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||
return_value = True ):
|
||||
ycm.OnFileReadyToParse()
|
||||
|
||||
assert_that(
|
||||
# Positional arguments passed to PostDataToHandlerAsync.
|
||||
|
@ -40,7 +40,7 @@ BUFWINNR_REGEX = re.compile( '^bufwinnr\((?P<buffer_number>[0-9]+)\)$' )
|
||||
BWIPEOUT_REGEX = re.compile(
|
||||
'^(?:silent! )bwipeout!? (?P<buffer_number>[0-9]+)$' )
|
||||
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\(\'(?P<group>.+)\', \'(?P<pattern>.+)\'\)$' )
|
||||
MATCHDELETE_REGEX = re.compile( '^matchdelete\((?P<id>)\)$' )
|
||||
@ -85,10 +85,12 @@ def _MockGetBufferWindowNumber( buffer_number ):
|
||||
def _MockGetBufferVariable( buffer_number, option ):
|
||||
for vim_buffer in VIM_MOCK.buffers:
|
||||
if vim_buffer.number == buffer_number:
|
||||
if option == 'mod':
|
||||
if option == '&mod':
|
||||
return vim_buffer.modified
|
||||
if option == 'ft':
|
||||
if option == '&ft':
|
||||
return vim_buffer.filetype
|
||||
if option == 'changedtick':
|
||||
return vim_buffer.changedtick
|
||||
return ''
|
||||
return ''
|
||||
|
||||
@ -230,6 +232,7 @@ class VimBuffer( object ):
|
||||
self.modified = modified
|
||||
self.window = window
|
||||
self.omnifunc = omnifunc
|
||||
self.changedtick = 1
|
||||
|
||||
|
||||
def __getitem__( self, index ):
|
||||
@ -250,6 +253,10 @@ class VimBuffer( object ):
|
||||
return [ ToUnicode( x ) for x in self.contents ]
|
||||
|
||||
|
||||
def EmulateCurrentBufferChange():
|
||||
VIM_MOCK.current.buffer.changedtick += 1
|
||||
|
||||
|
||||
class VimMatch( object ):
|
||||
|
||||
def __init__( self, group, pattern ):
|
||||
|
@ -349,6 +349,7 @@ def YouCompleteMe_ShowDiagnostics_NoDiagnosticsDetected_test(
|
||||
'open_loclist_on_ycm_diags': 0 } )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
|
||||
return_value = True )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
|
||||
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||
@patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock )
|
||||
def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
|
||||
@ -388,6 +389,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
|
||||
@YouCompleteMeInstance( { 'open_loclist_on_ycm_diags': 1 } )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
|
||||
return_value = True )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
|
||||
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||
@patch( 'ycm.vimsupport.SetLocationList', new_callable = ExtendedMock )
|
||||
@patch( 'ycm.vimsupport.OpenLocationList', new_callable = ExtendedMock )
|
||||
@ -431,6 +433,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_OpenLocationList_test(
|
||||
'enable_diagnostic_highlighting': 1 } )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
|
||||
return_value = True )
|
||||
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady', return_value = True )
|
||||
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||
def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
|
||||
@ -511,8 +514,7 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
|
||||
with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 1 ) ):
|
||||
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
||||
return_value = diagnostics ):
|
||||
ycm.OnFileReadyToParse()
|
||||
ycm.HandleFileParseRequest( block = True )
|
||||
ycm.OnFileReadyToParse( block = True )
|
||||
|
||||
# Error match is added after warning matches.
|
||||
assert_that(
|
||||
|
@ -147,6 +147,14 @@ def GetBufferFilepath( buffer_object ):
|
||||
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 ):
|
||||
if buffer_number < 0:
|
||||
return
|
||||
|
@ -33,10 +33,10 @@ import vim
|
||||
from subprocess import PIPE
|
||||
from tempfile import NamedTemporaryFile
|
||||
from ycm import base, paths, vimsupport
|
||||
from ycm.buffer import BufferDict
|
||||
from ycmd import utils
|
||||
from ycmd import server_utils
|
||||
from ycmd.request_wrap import RequestWrap
|
||||
from ycm.diagnostic_interface import DiagnosticInterface
|
||||
from ycm.omni_completer import OmniCompleter
|
||||
from ycm import syntax_parse
|
||||
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,
|
||||
FormatDebugInfoResponse )
|
||||
from ycm.client.omni_completion_request import OmniCompletionRequest
|
||||
from ycm.client.event_notification import ( SendEventNotificationAsync,
|
||||
EventNotification )
|
||||
from ycm.client.event_notification import SendEventNotificationAsync
|
||||
from ycm.client.shutdown_request import SendShutdownRequest
|
||||
|
||||
|
||||
@ -114,11 +113,9 @@ class YouCompleteMe( object ):
|
||||
self._available_completers = {}
|
||||
self._user_options = user_options
|
||||
self._user_notified_about_crash = False
|
||||
self._diag_interface = DiagnosticInterface( 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_diagnostics = []
|
||||
self._logger = logging.getLogger( 'ycm' )
|
||||
self._client_logfile = None
|
||||
self._server_stdout = None
|
||||
@ -134,6 +131,11 @@ class YouCompleteMe( object ):
|
||||
'cs': lambda self: self._OnCompleteDone_Csharp()
|
||||
}
|
||||
|
||||
|
||||
def _GetCurrentBuffer( self ):
|
||||
return self._buffers[ vimsupport.GetCurrentBufferNumber() ]
|
||||
|
||||
|
||||
def _SetupServer( self ):
|
||||
self._available_completers = {}
|
||||
self._user_notified_about_crash = False
|
||||
@ -353,21 +355,28 @@ class YouCompleteMe( object ):
|
||||
self.NativeFiletypeCompletionAvailable() )
|
||||
|
||||
|
||||
def OnFileReadyToParse( self ):
|
||||
def OnFileReadyToParse( self, block = False, force = False ):
|
||||
if not self.IsServerAlive():
|
||||
self._NotifyUserIfServerCrashed()
|
||||
return
|
||||
|
||||
if not self.IsServerReady():
|
||||
return
|
||||
|
||||
self._omnicomp.OnFileReadyToParse( None )
|
||||
|
||||
extra_data = {}
|
||||
self._AddTagsFilesIfNeeded( extra_data )
|
||||
self._AddSyntaxDataIfNeeded( extra_data )
|
||||
self._AddExtraConfDataIfNeeded( extra_data )
|
||||
self.HandleFileParseRequest()
|
||||
|
||||
self._latest_file_parse_request = EventNotification(
|
||||
'FileReadyToParse', extra_data = extra_data )
|
||||
self._latest_file_parse_request.Start()
|
||||
current_buffer = self._GetCurrentBuffer()
|
||||
if force_parsing or current_buffer.NeedsReparse():
|
||||
extra_data = {}
|
||||
self._AddTagsFilesIfNeeded( extra_data )
|
||||
self._AddSyntaxDataIfNeeded( extra_data )
|
||||
self._AddExtraConfDataIfNeeded( extra_data )
|
||||
|
||||
current_buffer.SendParseRequest( extra_data )
|
||||
if block:
|
||||
self.HandleFileParseRequest()
|
||||
|
||||
|
||||
def OnBufferUnload( self, deleted_buffer_file ):
|
||||
@ -385,7 +394,7 @@ class YouCompleteMe( object ):
|
||||
|
||||
|
||||
def OnCursorMoved( self ):
|
||||
self._diag_interface.OnCursorMoved()
|
||||
self._GetCurrentBuffer().OnCursorMoved()
|
||||
|
||||
|
||||
def _CleanLogfile( self ):
|
||||
@ -512,11 +521,11 @@ class YouCompleteMe( object ):
|
||||
|
||||
|
||||
def GetErrorCount( self ):
|
||||
return self._diag_interface.GetErrorCount()
|
||||
return self._GetCurrentBuffer().GetErrorCount()
|
||||
|
||||
|
||||
def GetWarningCount( self ):
|
||||
return self._diag_interface.GetWarningCount()
|
||||
return self._GetCurrentBuffer().GetWarningCount()
|
||||
|
||||
|
||||
def DiagnosticUiSupportedForCurrentFiletype( self ):
|
||||
@ -530,51 +539,25 @@ class YouCompleteMe( object ):
|
||||
|
||||
|
||||
def _PopulateLocationListWithLatestDiagnostics( self ):
|
||||
# Do nothing if loc list is already populated by diag_interface
|
||||
if not self._user_options[ 'always_populate_location_list' ]:
|
||||
self._diag_interface.PopulateLocationList( self._latest_diagnostics )
|
||||
return bool( self._latest_diagnostics )
|
||||
return self._GetCurrentBuffer().PopulateLocationList()
|
||||
|
||||
|
||||
def UpdateDiagnosticInterface( self ):
|
||||
self._diag_interface.UpdateWithNewDiagnostics( self._latest_diagnostics )
|
||||
def FileParseRequestReady( self ):
|
||||
return self._GetCurrentBuffer().FileParseRequestReady()
|
||||
|
||||
|
||||
def FileParseRequestReady( self, block = False ):
|
||||
return bool( self._latest_file_parse_request and
|
||||
( block or self._latest_file_parse_request.Done() ) )
|
||||
def HandleFileParseRequest( self ):
|
||||
current_buffer = self._GetCurrentBuffer()
|
||||
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
|
||||
if ( self.FileParseRequestReady( block ) and
|
||||
self.NativeFiletypeCompletionUsable() ):
|
||||
|
||||
if self.NativeFiletypeCompletionUsable():
|
||||
current_buffer.GetResponse()
|
||||
if self.ShouldDisplayDiagnostics():
|
||||
self._latest_diagnostics = self._latest_file_parse_request.Response()
|
||||
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()
|
||||
current_buffer.UpdateDiagnostics()
|
||||
|
||||
# We set the file parse request to None because we want to prevent
|
||||
# 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
|
||||
current_buffer.MarkResponseHandled()
|
||||
|
||||
|
||||
def DebugInfo( self ):
|
||||
@ -683,8 +666,7 @@ class YouCompleteMe( object ):
|
||||
vimsupport.PostVimMessage(
|
||||
'Forcing compilation, this will block Vim until done.',
|
||||
warning = False )
|
||||
self.OnFileReadyToParse()
|
||||
self.HandleFileParseRequest( block = True )
|
||||
self.OnFileReadyToParse( block = True )
|
||||
vimsupport.PostVimMessage( 'Diagnostics refreshed', warning = False )
|
||||
return True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user