Auto merge of #2631 - davits:changedtick, r=bstaletic
[READY] Moved change tracking to python. Per buffer diagnostics Thank you for working on YCM! :) - [x] I have read and understood YCM's [CONTRIBUTING][cont] document. - [x] I have read and understood YCM's [CODE_OF_CONDUCT][code] document. - [x] I have included tests for the changes in my PR. If not, I have included a rationale for why I haven't. - [x] **I understand my PR may be closed if it becomes obvious I didn't actually perform all of these steps.** Adds an emulation of Vim buffer object and moves change tracking into python. Now diagnostics are stored per buffer, which effectively solves #2165 . <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2631) <!-- Reviewable:end -->
This commit is contained in:
commit
c2906b6fef
@ -105,6 +105,9 @@ function! youcompleteme#Enable()
|
|||||||
autocmd CompleteDone * call s:OnCompleteDone()
|
autocmd CompleteDone * call s:OnCompleteDone()
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
|
" The BufEnter event is not triggered for the first loaded file.
|
||||||
|
exec s:python_command "ycm_state.SetCurrentBuffer()"
|
||||||
|
|
||||||
" The FileType event is not triggered for the first loaded file. We wait until
|
" The FileType event is not triggered for the first loaded file. We wait until
|
||||||
" the server is ready to manually run the s:OnFileTypeSet function.
|
" the server is ready to manually run the s:OnFileTypeSet function.
|
||||||
let s:pollers.server_ready.id = timer_start(
|
let s:pollers.server_ready.id = timer_start(
|
||||||
@ -431,6 +434,8 @@ endfunction
|
|||||||
|
|
||||||
|
|
||||||
function! s:OnBufferEnter()
|
function! s:OnBufferEnter()
|
||||||
|
exec s:python_command "ycm_state.SetCurrentBuffer()"
|
||||||
|
|
||||||
if !s:VisitedBufferRequiresReparse()
|
if !s:VisitedBufferRequiresReparse()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
@ -460,7 +465,7 @@ endfunction
|
|||||||
|
|
||||||
|
|
||||||
function! s:PollServerReady( timer_id )
|
function! s:PollServerReady( timer_id )
|
||||||
if !s:Pyeval( 'ycm_state.IsServerReady()' )
|
if !s:Pyeval( 'ycm_state.CheckIfServerIsReady()' )
|
||||||
let s:pollers.server_ready.id = timer_start(
|
let s:pollers.server_ready.id = timer_start(
|
||||||
\ s:pollers.server_ready.wait_milliseconds,
|
\ s:pollers.server_ready.wait_milliseconds,
|
||||||
\ function( 's:PollServerReady' ) )
|
\ function( 's:PollServerReady' ) )
|
||||||
@ -479,15 +484,13 @@ function! s:OnFileReadyToParse( ... )
|
|||||||
|
|
||||||
" We only want to send a new FileReadyToParse event notification if the buffer
|
" We only want to send a new FileReadyToParse event notification if the buffer
|
||||||
" has changed since the last time we sent one, or if forced.
|
" has changed since the last time we sent one, or if forced.
|
||||||
if force_parsing || b:changedtick != get( b:, 'ycm_changedtick', -1 )
|
if force_parsing || s:Pyeval( "ycm_state.NeedsReparse()" )
|
||||||
exec s:python_command "ycm_state.OnFileReadyToParse()"
|
exec s:python_command "ycm_state.OnFileReadyToParse()"
|
||||||
|
|
||||||
call timer_stop( s:pollers.file_parse_response.id )
|
call timer_stop( s:pollers.file_parse_response.id )
|
||||||
let s:pollers.file_parse_response.id = timer_start(
|
let s:pollers.file_parse_response.id = timer_start(
|
||||||
\ s:pollers.file_parse_response.wait_milliseconds,
|
\ s:pollers.file_parse_response.wait_milliseconds,
|
||||||
\ function( 's:PollFileParseResponse' ) )
|
\ function( 's:PollFileParseResponse' ) )
|
||||||
|
|
||||||
let b:ycm_changedtick = b:changedtick
|
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
109
python/ycm/buffer.py
Normal file
109
python/ycm/buffer.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
# Emulates Vim buffer
|
||||||
|
# Used to store buffer related information like diagnostics, latest parse
|
||||||
|
# request. Stores buffer change tick at the parse request moment, allowing
|
||||||
|
# to effectively determine whether reparse is needed for the buffer.
|
||||||
|
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 bool( self._parse_request and
|
||||||
|
( block or self._parse_request.Done() ) )
|
||||||
|
|
||||||
|
|
||||||
|
def SendParseRequest( self, extra_data ):
|
||||||
|
self._parse_request = EventNotification( 'FileReadyToParse',
|
||||||
|
extra_data = extra_data )
|
||||||
|
self._parse_request.Start()
|
||||||
|
# Decrement handled tick to ensure correct handling when we are forcing
|
||||||
|
# reparse on buffer visit and changed tick remains the same.
|
||||||
|
self._handled_tick -= 1
|
||||||
|
self._parse_tick = self._ChangedTick()
|
||||||
|
|
||||||
|
|
||||||
|
def NeedsReparse( self ):
|
||||||
|
return self._parse_tick != self._ChangedTick()
|
||||||
|
|
||||||
|
|
||||||
|
def UpdateDiagnostics( self ):
|
||||||
|
self._diag_interface.UpdateWithNewDiagnostics(
|
||||||
|
self._parse_request.Response() )
|
||||||
|
|
||||||
|
|
||||||
|
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 ):
|
||||||
|
# Python does not allow to return assignment operation result directly
|
||||||
|
new_value = self[ key ] = Buffer( key, self._user_options )
|
||||||
|
return new_value
|
@ -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 ]
|
||||||
|
@ -59,7 +59,7 @@ def UnplaceSign_Call( sign_id, buffer_num ):
|
|||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def MockArbitraryBuffer( filetype ):
|
def MockArbitraryBuffer( filetype, ycm ):
|
||||||
"""Used via the with statement, set up a single buffer with an arbitrary name
|
"""Used via the with statement, set up a single buffer with an arbitrary name
|
||||||
and no contents. Its filetype is set to the supplied filetype."""
|
and no contents. Its filetype is set to the supplied filetype."""
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ def MockArbitraryBuffer( filetype ):
|
|||||||
window = 1,
|
window = 1,
|
||||||
filetype = filetype )
|
filetype = filetype )
|
||||||
|
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@ -105,7 +105,10 @@ 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 ):
|
||||||
|
|
||||||
yield
|
with patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||||
|
return_value = True ):
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||||
@ -121,7 +124,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_Error_test(
|
|||||||
def ErrorResponse( *args ):
|
def ErrorResponse( *args ):
|
||||||
raise ServerError( ERROR_TEXT )
|
raise ServerError( ERROR_TEXT )
|
||||||
|
|
||||||
with MockArbitraryBuffer( 'javascript' ):
|
with MockArbitraryBuffer( 'javascript', ycm ):
|
||||||
with MockEventNotification( ErrorResponse ):
|
with MockEventNotification( ErrorResponse ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
ok_( ycm.FileParseRequestReady() )
|
ok_( ycm.FileParseRequestReady() )
|
||||||
@ -153,7 +156,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_Error_test(
|
|||||||
def EventNotification_FileReadyToParse_NonDiagnostic_Error_NonNative_test(
|
def EventNotification_FileReadyToParse_NonDiagnostic_Error_NonNative_test(
|
||||||
ycm, vim_command ):
|
ycm, vim_command ):
|
||||||
|
|
||||||
with MockArbitraryBuffer( 'javascript' ):
|
with MockArbitraryBuffer( 'javascript', ycm ):
|
||||||
with MockEventNotification( None, False ):
|
with MockEventNotification( None, False ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
ycm.HandleFileParseRequest()
|
ycm.HandleFileParseRequest()
|
||||||
@ -179,7 +182,7 @@ def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
|
|||||||
def UnknownExtraConfResponse( *args ):
|
def UnknownExtraConfResponse( *args ):
|
||||||
raise UnknownExtraConf( FILE_NAME )
|
raise UnknownExtraConf( FILE_NAME )
|
||||||
|
|
||||||
with MockArbitraryBuffer( 'javascript' ):
|
with MockArbitraryBuffer( 'javascript', ycm ):
|
||||||
with MockEventNotification( UnknownExtraConfResponse ):
|
with MockEventNotification( UnknownExtraConfResponse ):
|
||||||
|
|
||||||
# When the user accepts the extra conf, we load it
|
# When the user accepts the extra conf, we load it
|
||||||
@ -279,7 +282,7 @@ 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 MockArbitraryBuffer( 'cpp', ycm ):
|
||||||
with MockEventNotification( DiagnosticResponse ):
|
with MockEventNotification( DiagnosticResponse ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
ok_( ycm.FileParseRequestReady() )
|
ok_( ycm.FileParseRequestReady() )
|
||||||
@ -293,7 +296,6 @@ 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() )
|
|
||||||
ycm.HandleFileParseRequest()
|
ycm.HandleFileParseRequest()
|
||||||
vim_command.assert_not_called()
|
vim_command.assert_not_called()
|
||||||
eq_( ycm.GetErrorCount(), 1 )
|
eq_( ycm.GetErrorCount(), 1 )
|
||||||
@ -312,7 +314,7 @@ 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 MockArbitraryBuffer( 'cpp', ycm ):
|
||||||
with MockEventNotification( DiagnosticResponse ):
|
with MockEventNotification( DiagnosticResponse ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
ok_( ycm.FileParseRequestReady() )
|
ok_( ycm.FileParseRequestReady() )
|
||||||
@ -327,7 +329,6 @@ 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() )
|
|
||||||
ycm.HandleFileParseRequest()
|
ycm.HandleFileParseRequest()
|
||||||
vim_command.assert_not_called()
|
vim_command.assert_not_called()
|
||||||
eq_( ycm.GetErrorCount(), 0 )
|
eq_( ycm.GetErrorCount(), 0 )
|
||||||
@ -339,7 +340,7 @@ 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 MockArbitraryBuffer( 'cpp', ycm ):
|
||||||
with MockEventNotification( MagicMock( return_value = [] ) ):
|
with MockEventNotification( MagicMock( return_value = [] ) ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
ycm.HandleFileParseRequest()
|
ycm.HandleFileParseRequest()
|
||||||
@ -351,6 +352,8 @@ def _Check_FileReadyToParse_Diagnostic_Clean( ycm, vim_command ):
|
|||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
|
@patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
|
||||||
|
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||||
|
return_value = True )
|
||||||
@YouCompleteMeInstance( { 'collect_identifiers_from_tags_files': 1 } )
|
@YouCompleteMeInstance( { 'collect_identifiers_from_tags_files': 1 } )
|
||||||
def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
|
def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
@ -363,7 +366,7 @@ def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
|
|||||||
with patch( 'ycm.client.event_notification.EventNotification.'
|
with patch( 'ycm.client.event_notification.EventNotification.'
|
||||||
'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 ), ycm ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
|
|
||||||
assert_that(
|
assert_that(
|
||||||
@ -495,6 +498,8 @@ def EventNotification_BufferUnload_BuildRequestForDeletedAndUnsavedBuffers_test(
|
|||||||
|
|
||||||
@patch( 'ycm.syntax_parse.SyntaxKeywordsForCurrentBuffer',
|
@patch( 'ycm.syntax_parse.SyntaxKeywordsForCurrentBuffer',
|
||||||
return_value = [ 'foo', 'bar' ] )
|
return_value = [ 'foo', 'bar' ] )
|
||||||
|
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||||
|
return_value = True )
|
||||||
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
|
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
|
||||||
def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
|
def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
@ -504,7 +509,7 @@ def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
|
|||||||
|
|
||||||
with patch( 'ycm.client.event_notification.EventNotification.'
|
with patch( 'ycm.client.event_notification.EventNotification.'
|
||||||
'PostDataToHandlerAsync' ) as post_data_to_handler_async:
|
'PostDataToHandlerAsync' ) as post_data_to_handler_async:
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
assert_that(
|
assert_that(
|
||||||
# Positional arguments passed to PostDataToHandlerAsync.
|
# Positional arguments passed to PostDataToHandlerAsync.
|
||||||
@ -529,6 +534,8 @@ def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
|
|||||||
|
|
||||||
@patch( 'ycm.syntax_parse.SyntaxKeywordsForCurrentBuffer',
|
@patch( 'ycm.syntax_parse.SyntaxKeywordsForCurrentBuffer',
|
||||||
return_value = [ 'foo', 'bar' ] )
|
return_value = [ 'foo', 'bar' ] )
|
||||||
|
@patch( 'ycm.youcompleteme.YouCompleteMe.IsServerReady',
|
||||||
|
return_value = True )
|
||||||
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
|
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
|
||||||
def EventNotification_FileReadyToParse_SyntaxKeywords_ClearCacheIfRestart_test(
|
def EventNotification_FileReadyToParse_SyntaxKeywords_ClearCacheIfRestart_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
@ -538,7 +545,7 @@ def EventNotification_FileReadyToParse_SyntaxKeywords_ClearCacheIfRestart_test(
|
|||||||
|
|
||||||
with patch( 'ycm.client.event_notification.EventNotification.'
|
with patch( 'ycm.client.event_notification.EventNotification.'
|
||||||
'PostDataToHandlerAsync' ) as post_data_to_handler_async:
|
'PostDataToHandlerAsync' ) as post_data_to_handler_async:
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
ycm.OnFileReadyToParse()
|
ycm.OnFileReadyToParse()
|
||||||
assert_that(
|
assert_that(
|
||||||
# Positional arguments passed to PostDataToHandlerAsync.
|
# Positional arguments passed to PostDataToHandlerAsync.
|
||||||
|
@ -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 ):
|
||||||
@ -268,7 +271,8 @@ class VimMatch( object ):
|
|||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def MockVimBuffers( buffers, current_buffer, cursor_position = ( 1, 1 ) ):
|
def MockVimBuffers( buffers, current_buffer, cursor_position = ( 1, 1 ),
|
||||||
|
ycm_state = None):
|
||||||
"""Simulates the Vim buffers list |buffers| where |current_buffer| is the
|
"""Simulates the Vim buffers list |buffers| where |current_buffer| is the
|
||||||
buffer displayed in the current window and |cursor_position| is the current
|
buffer displayed in the current window and |cursor_position| is the current
|
||||||
cursor position. All buffers are represented by a VimBuffer object."""
|
cursor position. All buffers are represented by a VimBuffer object."""
|
||||||
@ -278,6 +282,8 @@ def MockVimBuffers( buffers, current_buffer, cursor_position = ( 1, 1 ) ):
|
|||||||
with patch( 'vim.buffers', buffers ):
|
with patch( 'vim.buffers', buffers ):
|
||||||
with patch( 'vim.current.buffer', current_buffer ):
|
with patch( 'vim.current.buffer', current_buffer ):
|
||||||
with patch( 'vim.current.window.cursor', cursor_position ):
|
with patch( 'vim.current.window.cursor', cursor_position ):
|
||||||
|
if ycm_state is not None:
|
||||||
|
ycm_state.SetCurrentBuffer()
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ def YouCompleteMe_ShowDiagnostics_NoDiagnosticsDetected_test(
|
|||||||
ycm, set_location_list, post_vim_message, *args ):
|
ycm, set_location_list, post_vim_message, *args ):
|
||||||
|
|
||||||
current_buffer = VimBuffer( 'buffer', filetype = 'cpp' )
|
current_buffer = VimBuffer( 'buffer', filetype = 'cpp' )
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
||||||
return_value = {} ):
|
return_value = {} ):
|
||||||
ycm.ShowDiagnostics()
|
ycm.ShowDiagnostics()
|
||||||
@ -349,6 +349,8 @@ 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(
|
||||||
@ -365,7 +367,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_buffer = VimBuffer( 'buffer', filetype = 'cpp', number = 3 )
|
current_buffer = VimBuffer( 'buffer', filetype = 'cpp', number = 3 )
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
||||||
return_value = [ diagnostic ] ):
|
return_value = [ diagnostic ] ):
|
||||||
ycm.ShowDiagnostics()
|
ycm.ShowDiagnostics()
|
||||||
@ -388,6 +390,8 @@ 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 )
|
||||||
@ -405,7 +409,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_OpenLocationList_test(
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_buffer = VimBuffer( 'buffer', filetype = 'cpp', number = 3 )
|
current_buffer = VimBuffer( 'buffer', filetype = 'cpp', number = 3 )
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ycm_state = ycm ):
|
||||||
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
with patch( 'ycm.client.event_notification.EventNotification.Response',
|
||||||
return_value = [ diagnostic ] ):
|
return_value = [ diagnostic ] ):
|
||||||
ycm.ShowDiagnostics()
|
ycm.ShowDiagnostics()
|
||||||
@ -431,6 +435,8 @@ 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(
|
||||||
@ -508,7 +514,7 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
|
|||||||
|
|
||||||
test_utils.VIM_MATCHES = []
|
test_utils.VIM_MATCHES = []
|
||||||
|
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 1 ) ):
|
with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 1 ), ycm ):
|
||||||
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()
|
||||||
|
@ -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
|
||||||
|
@ -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,10 @@ 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._current_buffer = None
|
||||||
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 +132,7 @@ class YouCompleteMe( object ):
|
|||||||
'cs': lambda self: self._OnCompleteDone_Csharp()
|
'cs': lambda self: self._OnCompleteDone_Csharp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _SetupServer( self ):
|
def _SetupServer( self ):
|
||||||
self._available_completers = {}
|
self._available_completers = {}
|
||||||
self._user_notified_about_crash = False
|
self._user_notified_about_crash = False
|
||||||
@ -222,7 +221,7 @@ class YouCompleteMe( object ):
|
|||||||
return return_code is None
|
return return_code is None
|
||||||
|
|
||||||
|
|
||||||
def IsServerReady( self ):
|
def CheckIfServerIsReady( self ):
|
||||||
if not self._server_is_ready_with_cache and self.IsServerAlive():
|
if not self._server_is_ready_with_cache and self.IsServerAlive():
|
||||||
with HandleServerException( display = False ):
|
with HandleServerException( display = False ):
|
||||||
self._server_is_ready_with_cache = BaseRequest.GetDataFromHandler(
|
self._server_is_ready_with_cache = BaseRequest.GetDataFromHandler(
|
||||||
@ -230,6 +229,10 @@ class YouCompleteMe( object ):
|
|||||||
return self._server_is_ready_with_cache
|
return self._server_is_ready_with_cache
|
||||||
|
|
||||||
|
|
||||||
|
def IsServerReady( self ):
|
||||||
|
return self._server_is_ready_with_cache
|
||||||
|
|
||||||
|
|
||||||
def _NotifyUserIfServerCrashed( self ):
|
def _NotifyUserIfServerCrashed( self ):
|
||||||
if self._user_notified_about_crash or self.IsServerAlive():
|
if self._user_notified_about_crash or self.IsServerAlive():
|
||||||
return
|
return
|
||||||
@ -353,11 +356,18 @@ class YouCompleteMe( object ):
|
|||||||
self.NativeFiletypeCompletionAvailable() )
|
self.NativeFiletypeCompletionAvailable() )
|
||||||
|
|
||||||
|
|
||||||
|
def NeedsReparse( self ):
|
||||||
|
return self._current_buffer.NeedsReparse()
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self ):
|
||||||
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 )
|
||||||
|
|
||||||
extra_data = {}
|
extra_data = {}
|
||||||
@ -365,9 +375,7 @@ class YouCompleteMe( object ):
|
|||||||
self._AddSyntaxDataIfNeeded( extra_data )
|
self._AddSyntaxDataIfNeeded( extra_data )
|
||||||
self._AddExtraConfDataIfNeeded( extra_data )
|
self._AddExtraConfDataIfNeeded( extra_data )
|
||||||
|
|
||||||
self._latest_file_parse_request = EventNotification(
|
self._current_buffer.SendParseRequest( extra_data )
|
||||||
'FileReadyToParse', extra_data = extra_data )
|
|
||||||
self._latest_file_parse_request.Start()
|
|
||||||
|
|
||||||
|
|
||||||
def OnBufferUnload( self, deleted_buffer_file ):
|
def OnBufferUnload( self, deleted_buffer_file ):
|
||||||
@ -380,12 +388,16 @@ class YouCompleteMe( object ):
|
|||||||
SendEventNotificationAsync( 'BufferVisit', extra_data = extra_data )
|
SendEventNotificationAsync( 'BufferVisit', extra_data = extra_data )
|
||||||
|
|
||||||
|
|
||||||
|
def SetCurrentBuffer( self ):
|
||||||
|
self._current_buffer = self._buffers[ vimsupport.GetCurrentBufferNumber() ]
|
||||||
|
|
||||||
|
|
||||||
def OnInsertLeave( self ):
|
def OnInsertLeave( self ):
|
||||||
SendEventNotificationAsync( 'InsertLeave' )
|
SendEventNotificationAsync( 'InsertLeave' )
|
||||||
|
|
||||||
|
|
||||||
def OnCursorMoved( self ):
|
def OnCursorMoved( self ):
|
||||||
self._diag_interface.OnCursorMoved()
|
self._current_buffer.OnCursorMoved()
|
||||||
|
|
||||||
|
|
||||||
def _CleanLogfile( self ):
|
def _CleanLogfile( self ):
|
||||||
@ -512,11 +524,11 @@ class YouCompleteMe( object ):
|
|||||||
|
|
||||||
|
|
||||||
def GetErrorCount( self ):
|
def GetErrorCount( self ):
|
||||||
return self._diag_interface.GetErrorCount()
|
return self._current_buffer.GetErrorCount()
|
||||||
|
|
||||||
|
|
||||||
def GetWarningCount( self ):
|
def GetWarningCount( self ):
|
||||||
return self._diag_interface.GetWarningCount()
|
return self._current_buffer.GetWarningCount()
|
||||||
|
|
||||||
|
|
||||||
def DiagnosticUiSupportedForCurrentFiletype( self ):
|
def DiagnosticUiSupportedForCurrentFiletype( self ):
|
||||||
@ -530,31 +542,29 @@ class YouCompleteMe( object ):
|
|||||||
|
|
||||||
|
|
||||||
def _PopulateLocationListWithLatestDiagnostics( self ):
|
def _PopulateLocationListWithLatestDiagnostics( self ):
|
||||||
# Do nothing if loc list is already populated by diag_interface
|
return self._current_buffer.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 True if server is not ready yet, to stop repeating check timer.
|
||||||
|
return ( not self.IsServerReady() or
|
||||||
|
self._current_buffer.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, block = False ):
|
def HandleFileParseRequest( self, block = False ):
|
||||||
|
if not self.IsServerReady():
|
||||||
|
return
|
||||||
|
|
||||||
|
current_buffer = self._current_buffer
|
||||||
# Order is important here:
|
# Order is important here:
|
||||||
# FileParseRequestReady has a low cost, while
|
# FileParseRequestReady has a low cost, while
|
||||||
# NativeFiletypeCompletionUsable is a blocking server request
|
# NativeFiletypeCompletionUsable is a blocking server request
|
||||||
if ( self.FileParseRequestReady( block ) and
|
if ( not current_buffer.IsResponseHandled() and
|
||||||
|
current_buffer.FileParseRequestReady( block ) and
|
||||||
self.NativeFiletypeCompletionUsable() ):
|
self.NativeFiletypeCompletionUsable() ):
|
||||||
|
|
||||||
if self.ShouldDisplayDiagnostics():
|
if self.ShouldDisplayDiagnostics():
|
||||||
self._latest_diagnostics = self._latest_file_parse_request.Response()
|
current_buffer.UpdateDiagnostics()
|
||||||
self.UpdateDiagnosticInterface()
|
|
||||||
else:
|
else:
|
||||||
# YCM client has a hard-coded list of filetypes which are known
|
# YCM client has a hard-coded list of filetypes which are known
|
||||||
# to support diagnostics, self.DiagnosticUiSupportedForCurrentFiletype()
|
# to support diagnostics, self.DiagnosticUiSupportedForCurrentFiletype()
|
||||||
@ -563,18 +573,17 @@ class YouCompleteMe( object ):
|
|||||||
# the _latest_file_parse_request for any exception or UnknownExtraConf
|
# the _latest_file_parse_request for any exception or UnknownExtraConf
|
||||||
# response, to allow the server to raise configuration warnings, etc.
|
# response, to allow the server to raise configuration warnings, etc.
|
||||||
# to the user. We ignore any other supplied data.
|
# to the user. We ignore any other supplied data.
|
||||||
self._latest_file_parse_request.Response()
|
current_buffer.GetResponse()
|
||||||
|
|
||||||
# We set the file parse request to None because we want to prevent
|
# We set the file parse request as handled because we want to prevent
|
||||||
# repeated issuing of the same warnings/errors/prompts. Setting this to
|
# repeated issuing of the same warnings/errors/prompts. Setting this
|
||||||
# None makes FileParseRequestReady return False until the next
|
# makes IsRequestHandled return True until the next request is created.
|
||||||
# request is created.
|
|
||||||
#
|
#
|
||||||
# Note: it is the server's responsibility to determine the frequency of
|
# Note: it is the server's responsibility to determine the frequency of
|
||||||
# error/warning/prompts when receiving a FileReadyToParse event, but
|
# error/warning/prompts when receiving a FileReadyToParse event, but
|
||||||
# it our responsibility to ensure that we only apply the
|
# it is our responsibility to ensure that we only apply the
|
||||||
# warning/error/prompt received once (for each event).
|
# warning/error/prompt received once (for each event).
|
||||||
self._latest_file_parse_request = None
|
current_buffer.MarkResponseHandled()
|
||||||
|
|
||||||
|
|
||||||
def DebugInfo( self ):
|
def DebugInfo( self ):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user