Fix BufferUnload event notification
Send the request as the unloaded buffer instead of the current buffer for the BufferUnload event notification. This fixes the issue where the filetype of the current buffer is not the same as the unloaded buffer one, making the ycmd server uses the wrong completer when handling the request.
This commit is contained in:
parent
b6d5af3424
commit
2fabac5a67
@ -91,7 +91,7 @@ function! youcompleteme#Enable()
|
|||||||
autocmd BufReadPre * call s:OnBufferReadPre( expand( '<afile>:p' ) )
|
autocmd BufReadPre * call s:OnBufferReadPre( expand( '<afile>:p' ) )
|
||||||
autocmd BufRead,FileType * call s:OnBufferRead()
|
autocmd BufRead,FileType * call s:OnBufferRead()
|
||||||
autocmd BufEnter * call s:OnBufferEnter()
|
autocmd BufEnter * call s:OnBufferEnter()
|
||||||
autocmd BufUnload * call s:OnBufferUnload( expand( '<afile>:p' ) )
|
autocmd BufUnload * call s:OnBufferUnload()
|
||||||
autocmd CursorHold,CursorHoldI * call s:OnCursorHold()
|
autocmd CursorHold,CursorHoldI * call s:OnCursorHold()
|
||||||
autocmd InsertLeave * call s:OnInsertLeave()
|
autocmd InsertLeave * call s:OnInsertLeave()
|
||||||
autocmd InsertEnter * call s:OnInsertEnter()
|
autocmd InsertEnter * call s:OnInsertEnter()
|
||||||
@ -323,10 +323,12 @@ function! s:TurnOffSyntasticForCFamily()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
function! s:AllowedToCompleteInCurrentBuffer()
|
function! s:AllowedToCompleteInBuffer( buffer )
|
||||||
if empty( &filetype ) ||
|
let buffer_filetype = getbufvar( a:buffer, '&filetype' )
|
||||||
\ getbufvar( winbufnr( winnr() ), "&buftype" ) ==# 'nofile' ||
|
|
||||||
\ &filetype ==# 'qf'
|
if empty( buffer_filetype ) ||
|
||||||
|
\ getbufvar( a:buffer, '&buftype' ) ==# 'nofile' ||
|
||||||
|
\ buffer_filetype ==# 'qf'
|
||||||
return 0
|
return 0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -335,13 +337,18 @@ function! s:AllowedToCompleteInCurrentBuffer()
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
let whitelist_allows = has_key( g:ycm_filetype_whitelist, '*' ) ||
|
let whitelist_allows = has_key( g:ycm_filetype_whitelist, '*' ) ||
|
||||||
\ has_key( g:ycm_filetype_whitelist, &filetype )
|
\ has_key( g:ycm_filetype_whitelist, buffer_filetype )
|
||||||
let blacklist_allows = !has_key( g:ycm_filetype_blacklist, &filetype )
|
let blacklist_allows = !has_key( g:ycm_filetype_blacklist, buffer_filetype )
|
||||||
|
|
||||||
return whitelist_allows && blacklist_allows
|
return whitelist_allows && blacklist_allows
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! s:AllowedToCompleteInCurrentBuffer()
|
||||||
|
return s:AllowedToCompleteInBuffer( '%' )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
function! s:VisitedBufferRequiresReparse()
|
function! s:VisitedBufferRequiresReparse()
|
||||||
if !s:AllowedToCompleteInCurrentBuffer()
|
if !s:AllowedToCompleteInCurrentBuffer()
|
||||||
return 0
|
return 0
|
||||||
@ -471,13 +478,16 @@ function! s:OnBufferEnter()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
function! s:OnBufferUnload( deleted_buffer_file )
|
function! s:OnBufferUnload()
|
||||||
if !s:AllowedToCompleteInCurrentBuffer() || empty( a:deleted_buffer_file )
|
" Expanding <abuf> returns the unloaded buffer number as a string but we want
|
||||||
|
" it as a true number for the getbufvar function.
|
||||||
|
if !s:AllowedToCompleteInBuffer( str2nr( expand( '<abuf>' ) ) )
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let deleted_buffer_file = expand( '<afile>:p' )
|
||||||
exec s:python_command "ycm_state.OnBufferUnload("
|
exec s:python_command "ycm_state.OnBufferUnload("
|
||||||
\ "vim.eval( 'a:deleted_buffer_file' ) )"
|
\ "vim.eval( 'deleted_buffer_file' ) )"
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,20 +154,29 @@ class BaseRequest( object ):
|
|||||||
hmac_secret = ''
|
hmac_secret = ''
|
||||||
|
|
||||||
|
|
||||||
def BuildRequestData( include_buffer_data = True ):
|
def BuildRequestData( filepath = None ):
|
||||||
|
"""Build request for the current buffer or the buffer corresponding to
|
||||||
|
|filepath| if specified."""
|
||||||
|
current_filepath = vimsupport.GetCurrentBufferFilepath()
|
||||||
|
|
||||||
|
if filepath and current_filepath != filepath:
|
||||||
|
# Cursor position is irrelevant when filepath is not the current buffer.
|
||||||
|
return {
|
||||||
|
'filepath': filepath,
|
||||||
|
'line_num': 1,
|
||||||
|
'column_num': 1,
|
||||||
|
'file_data': vimsupport.GetUnsavedAndSpecifiedBufferData( filepath )
|
||||||
|
}
|
||||||
|
|
||||||
line, column = vimsupport.CurrentLineAndColumn()
|
line, column = vimsupport.CurrentLineAndColumn()
|
||||||
filepath = vimsupport.GetCurrentBufferFilepath()
|
|
||||||
request_data = {
|
return {
|
||||||
|
'filepath': current_filepath,
|
||||||
'line_num': line + 1,
|
'line_num': line + 1,
|
||||||
'column_num': column + 1,
|
'column_num': column + 1,
|
||||||
'filepath': filepath
|
'file_data': vimsupport.GetUnsavedAndSpecifiedBufferData( current_filepath )
|
||||||
}
|
}
|
||||||
|
|
||||||
if include_buffer_data:
|
|
||||||
request_data[ 'file_data' ] = vimsupport.GetUnsavedAndCurrentBufferData()
|
|
||||||
|
|
||||||
return request_data
|
|
||||||
|
|
||||||
|
|
||||||
def JsonFromFuture( future ):
|
def JsonFromFuture( future ):
|
||||||
response = future.result()
|
response = future.result()
|
||||||
|
@ -32,15 +32,16 @@ from ycm.client.base_request import ( BaseRequest, BuildRequestData,
|
|||||||
|
|
||||||
|
|
||||||
class EventNotification( BaseRequest ):
|
class EventNotification( BaseRequest ):
|
||||||
def __init__( self, event_name, extra_data = None ):
|
def __init__( self, event_name, filepath = None, extra_data = None ):
|
||||||
super( EventNotification, self ).__init__()
|
super( EventNotification, self ).__init__()
|
||||||
self._event_name = event_name
|
self._event_name = event_name
|
||||||
|
self._filepath = filepath
|
||||||
self._extra_data = extra_data
|
self._extra_data = extra_data
|
||||||
self._cached_response = None
|
self._cached_response = None
|
||||||
|
|
||||||
|
|
||||||
def Start( self ):
|
def Start( self ):
|
||||||
request_data = BuildRequestData()
|
request_data = BuildRequestData( self._filepath )
|
||||||
if self._extra_data:
|
if self._extra_data:
|
||||||
request_data.update( self._extra_data )
|
request_data.update( self._extra_data )
|
||||||
request_data[ 'event_name' ] = self._event_name
|
request_data[ 'event_name' ] = self._event_name
|
||||||
@ -74,8 +75,10 @@ class EventNotification( BaseRequest ):
|
|||||||
return self._cached_response if self._cached_response else []
|
return self._cached_response if self._cached_response else []
|
||||||
|
|
||||||
|
|
||||||
def SendEventNotificationAsync( event_name, extra_data = None ):
|
def SendEventNotificationAsync( event_name,
|
||||||
event = EventNotification( event_name, extra_data )
|
filepath = None,
|
||||||
|
extra_data = None ):
|
||||||
|
event = EventNotification( event_name, filepath, extra_data )
|
||||||
event.Start()
|
event.Start()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1403,15 +1403,17 @@ def OpenFilename_test( vim_current, vim_command ):
|
|||||||
|
|
||||||
@patch( 'ycm.vimsupport.BufferModified', side_effect = [ True ] )
|
@patch( 'ycm.vimsupport.BufferModified', side_effect = [ True ] )
|
||||||
@patch( 'ycm.vimsupport.FiletypesForBuffer', side_effect = [ [ 'cpp' ] ] )
|
@patch( 'ycm.vimsupport.FiletypesForBuffer', side_effect = [ [ 'cpp' ] ] )
|
||||||
def GetUnsavedAndCurrentBufferData_EncodedUnicodeCharsInBuffers_test( *args ):
|
def GetUnsavedAndSpecifiedBufferData_EncodedUnicodeCharsInBuffers_test( *args ):
|
||||||
|
filepath = os.path.realpath( 'filename' )
|
||||||
|
|
||||||
mock_buffer = MagicMock()
|
mock_buffer = MagicMock()
|
||||||
mock_buffer.name = os.path.realpath( 'filename' )
|
mock_buffer.name = filepath
|
||||||
mock_buffer.number = 1
|
mock_buffer.number = 1
|
||||||
mock_buffer.__iter__.return_value = [ ToBytes ( u'abc' ), ToBytes( u'fДa' ) ]
|
mock_buffer.__iter__.return_value = [ ToBytes ( u'abc' ), ToBytes( u'fДa' ) ]
|
||||||
|
|
||||||
with patch( 'vim.buffers', [ mock_buffer ] ):
|
with patch( 'vim.buffers', [ mock_buffer ] ):
|
||||||
assert_that( vimsupport.GetUnsavedAndCurrentBufferData(),
|
assert_that( vimsupport.GetUnsavedAndSpecifiedBufferData( filepath ),
|
||||||
has_entry( mock_buffer.name,
|
has_entry( filepath,
|
||||||
has_entry( u'contents', u'abc\nfДa\n' ) ) )
|
has_entry( u'contents', u'abc\nfДa\n' ) ) )
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,14 +116,17 @@ def BufferModified( buffer_object ):
|
|||||||
return bool( int( GetBufferOption( buffer_object, 'mod' ) ) )
|
return bool( int( GetBufferOption( buffer_object, 'mod' ) ) )
|
||||||
|
|
||||||
|
|
||||||
def GetUnsavedAndCurrentBufferData():
|
def GetUnsavedAndSpecifiedBufferData( including_filepath ):
|
||||||
|
"""Build part of the request containing the contents and filetypes of all
|
||||||
|
dirty buffers as well as the buffer with filepath |including_filepath|."""
|
||||||
buffers_data = {}
|
buffers_data = {}
|
||||||
for buffer_object in vim.buffers:
|
for buffer_object in vim.buffers:
|
||||||
|
buffer_filepath = GetBufferFilepath( buffer_object )
|
||||||
if not ( BufferModified( buffer_object ) or
|
if not ( BufferModified( buffer_object ) or
|
||||||
buffer_object == vim.current.buffer ):
|
buffer_filepath == including_filepath ):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
buffers_data[ GetBufferFilepath( buffer_object ) ] = {
|
buffers_data[ buffer_filepath ] = {
|
||||||
# Add a newline to match what gets saved to disk. See #1455 for details.
|
# Add a newline to match what gets saved to disk. See #1455 for details.
|
||||||
'contents': JoinLinesAsUnicode( buffer_object ) + '\n',
|
'contents': JoinLinesAsUnicode( buffer_object ) + '\n',
|
||||||
'filetypes': FiletypesForBuffer( buffer_object )
|
'filetypes': FiletypesForBuffer( buffer_object )
|
||||||
|
@ -311,16 +311,18 @@ 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( 'FileReadyToParse',
|
self._latest_file_parse_request = EventNotification(
|
||||||
extra_data )
|
'FileReadyToParse', extra_data = extra_data )
|
||||||
self._latest_file_parse_request.Start()
|
self._latest_file_parse_request.Start()
|
||||||
|
|
||||||
|
|
||||||
def OnBufferUnload( self, deleted_buffer_file ):
|
def OnBufferUnload( self, deleted_buffer_file ):
|
||||||
if not self.IsServerAlive():
|
if not self.IsServerAlive():
|
||||||
return
|
return
|
||||||
SendEventNotificationAsync( 'BufferUnload',
|
SendEventNotificationAsync(
|
||||||
{ 'unloaded_buffer': deleted_buffer_file } )
|
'BufferUnload',
|
||||||
|
filepath = deleted_buffer_file,
|
||||||
|
extra_data = { 'unloaded_buffer': deleted_buffer_file } )
|
||||||
|
|
||||||
|
|
||||||
def OnBufferVisit( self ):
|
def OnBufferVisit( self ):
|
||||||
@ -328,7 +330,7 @@ class YouCompleteMe( object ):
|
|||||||
return
|
return
|
||||||
extra_data = {}
|
extra_data = {}
|
||||||
self._AddUltiSnipsDataIfNeeded( extra_data )
|
self._AddUltiSnipsDataIfNeeded( extra_data )
|
||||||
SendEventNotificationAsync( 'BufferVisit', extra_data )
|
SendEventNotificationAsync( 'BufferVisit', extra_data = extra_data )
|
||||||
|
|
||||||
|
|
||||||
def OnInsertLeave( self ):
|
def OnInsertLeave( self ):
|
||||||
|
Loading…
Reference in New Issue
Block a user