diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 52d9f5af..5a69051d 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -91,7 +91,7 @@ function! youcompleteme#Enable() autocmd BufReadPre * call s:OnBufferReadPre( expand( ':p' ) ) autocmd BufRead,FileType * call s:OnBufferRead() autocmd BufEnter * call s:OnBufferEnter() - autocmd BufUnload * call s:OnBufferUnload( expand( ':p' ) ) + autocmd BufUnload * call s:OnBufferUnload() autocmd CursorHold,CursorHoldI * call s:OnCursorHold() autocmd InsertLeave * call s:OnInsertLeave() autocmd InsertEnter * call s:OnInsertEnter() @@ -323,10 +323,12 @@ function! s:TurnOffSyntasticForCFamily() endfunction -function! s:AllowedToCompleteInCurrentBuffer() - if empty( &filetype ) || - \ getbufvar( winbufnr( winnr() ), "&buftype" ) ==# 'nofile' || - \ &filetype ==# 'qf' +function! s:AllowedToCompleteInBuffer( buffer ) + let buffer_filetype = getbufvar( a:buffer, '&filetype' ) + + if empty( buffer_filetype ) || + \ getbufvar( a:buffer, '&buftype' ) ==# 'nofile' || + \ buffer_filetype ==# 'qf' return 0 endif @@ -335,13 +337,18 @@ function! s:AllowedToCompleteInCurrentBuffer() endif let whitelist_allows = has_key( g:ycm_filetype_whitelist, '*' ) || - \ has_key( g:ycm_filetype_whitelist, &filetype ) - let blacklist_allows = !has_key( g:ycm_filetype_blacklist, &filetype ) + \ has_key( g:ycm_filetype_whitelist, buffer_filetype ) + let blacklist_allows = !has_key( g:ycm_filetype_blacklist, buffer_filetype ) return whitelist_allows && blacklist_allows endfunction +function! s:AllowedToCompleteInCurrentBuffer() + return s:AllowedToCompleteInBuffer( '%' ) +endfunction + + function! s:VisitedBufferRequiresReparse() if !s:AllowedToCompleteInCurrentBuffer() return 0 @@ -471,13 +478,16 @@ function! s:OnBufferEnter() endfunction -function! s:OnBufferUnload( deleted_buffer_file ) - if !s:AllowedToCompleteInCurrentBuffer() || empty( a:deleted_buffer_file ) +function! s:OnBufferUnload() + " Expanding 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( '' ) ) ) return endif + let deleted_buffer_file = expand( ':p' ) exec s:python_command "ycm_state.OnBufferUnload(" - \ "vim.eval( 'a:deleted_buffer_file' ) )" + \ "vim.eval( 'deleted_buffer_file' ) )" endfunction diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index 97f4bf31..1fae1ea8 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -154,20 +154,29 @@ class BaseRequest( object ): 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() - filepath = vimsupport.GetCurrentBufferFilepath() - request_data = { + + return { + 'filepath': current_filepath, 'line_num': line + 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 ): response = future.result() diff --git a/python/ycm/client/event_notification.py b/python/ycm/client/event_notification.py index b9a60d18..bd73f31f 100644 --- a/python/ycm/client/event_notification.py +++ b/python/ycm/client/event_notification.py @@ -32,15 +32,16 @@ from ycm.client.base_request import ( BaseRequest, BuildRequestData, 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__() self._event_name = event_name + self._filepath = filepath self._extra_data = extra_data self._cached_response = None def Start( self ): - request_data = BuildRequestData() + request_data = BuildRequestData( self._filepath ) if self._extra_data: request_data.update( self._extra_data ) request_data[ 'event_name' ] = self._event_name @@ -74,8 +75,10 @@ class EventNotification( BaseRequest ): return self._cached_response if self._cached_response else [] -def SendEventNotificationAsync( event_name, extra_data = None ): - event = EventNotification( event_name, extra_data ) +def SendEventNotificationAsync( event_name, + filepath = None, + extra_data = None ): + event = EventNotification( event_name, filepath, extra_data ) event.Start() diff --git a/python/ycm/tests/vimsupport_test.py b/python/ycm/tests/vimsupport_test.py index 785a948a..74af6bb0 100644 --- a/python/ycm/tests/vimsupport_test.py +++ b/python/ycm/tests/vimsupport_test.py @@ -1403,15 +1403,17 @@ def OpenFilename_test( vim_current, vim_command ): @patch( 'ycm.vimsupport.BufferModified', side_effect = [ True ] ) @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.name = os.path.realpath( 'filename' ) + mock_buffer.name = filepath mock_buffer.number = 1 mock_buffer.__iter__.return_value = [ ToBytes ( u'abc' ), ToBytes( u'fДa' ) ] with patch( 'vim.buffers', [ mock_buffer ] ): - assert_that( vimsupport.GetUnsavedAndCurrentBufferData(), - has_entry( mock_buffer.name, + assert_that( vimsupport.GetUnsavedAndSpecifiedBufferData( filepath ), + has_entry( filepath, has_entry( u'contents', u'abc\nfДa\n' ) ) ) diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 068922d4..c50641e0 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -116,14 +116,17 @@ def BufferModified( buffer_object ): 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 = {} for buffer_object in vim.buffers: + buffer_filepath = GetBufferFilepath( buffer_object ) if not ( BufferModified( buffer_object ) or - buffer_object == vim.current.buffer ): + buffer_filepath == including_filepath ): continue - buffers_data[ GetBufferFilepath( buffer_object ) ] = { + buffers_data[ buffer_filepath ] = { # Add a newline to match what gets saved to disk. See #1455 for details. 'contents': JoinLinesAsUnicode( buffer_object ) + '\n', 'filetypes': FiletypesForBuffer( buffer_object ) diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index 33a324ff..461fcb3a 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -311,16 +311,18 @@ class YouCompleteMe( object ): self._AddSyntaxDataIfNeeded( extra_data ) self._AddExtraConfDataIfNeeded( extra_data ) - self._latest_file_parse_request = EventNotification( 'FileReadyToParse', - extra_data ) + self._latest_file_parse_request = EventNotification( + 'FileReadyToParse', extra_data = extra_data ) self._latest_file_parse_request.Start() def OnBufferUnload( self, deleted_buffer_file ): if not self.IsServerAlive(): return - SendEventNotificationAsync( 'BufferUnload', - { 'unloaded_buffer': deleted_buffer_file } ) + SendEventNotificationAsync( + 'BufferUnload', + filepath = deleted_buffer_file, + extra_data = { 'unloaded_buffer': deleted_buffer_file } ) def OnBufferVisit( self ): @@ -328,7 +330,7 @@ class YouCompleteMe( object ): return extra_data = {} self._AddUltiSnipsDataIfNeeded( extra_data ) - SendEventNotificationAsync( 'BufferVisit', extra_data ) + SendEventNotificationAsync( 'BufferVisit', extra_data = extra_data ) def OnInsertLeave( self ):