Merge remote-tracking branch 'origin/master' into CsAddImport

This commit is contained in:
Spencer G. Jones 2015-09-13 08:49:28 -06:00
commit 2a41101955
10 changed files with 296 additions and 90 deletions

View File

@ -1,7 +1,7 @@
YouCompleteMe: a code-completion engine for Vim YouCompleteMe: a code-completion engine for Vim
=============================================== ===============================================
[![Build Status](https://travis-ci.org/Valloric/YouCompleteMe.png?branch=master)](https://travis-ci.org/Valloric/YouCompleteMe) [![Build Status](https://travis-ci.org/Valloric/YouCompleteMe.svg?branch=master)](https://travis-ci.org/Valloric/YouCompleteMe)
- [Intro](#intro) - [Intro](#intro)
- [Installation](#installation) - [Installation](#installation)
@ -26,7 +26,6 @@ YouCompleteMe: a code-completion engine for Vim
- [Options](#options) - [Options](#options)
- [FAQ](#faq) - [FAQ](#faq)
- [Contact](#contact) - [Contact](#contact)
- [Project Management](#project-management)
- [License](#license) - [License](#license)
Intro Intro

View File

@ -159,7 +159,6 @@ Introduction ~
- Options - Options
- FAQ - FAQ
- Contact - Contact
- Project Management
- License - License
=============================================================================== ===============================================================================
@ -2322,7 +2321,7 @@ contributors
References ~ References ~
[1] https://travis-ci.org/Valloric/YouCompleteMe [1] https://travis-ci.org/Valloric/YouCompleteMe
[2] https://travis-ci.org/Valloric/YouCompleteMe.png?branch=master [2] https://travis-ci.org/Valloric/YouCompleteMe.svg?branch=master
[3] http://clang.llvm.org/ [3] http://clang.llvm.org/
[4] https://github.com/davidhalter/jedi [4] https://github.com/davidhalter/jedi
[5] https://github.com/nosami/OmniSharpServer [5] https://github.com/nosami/OmniSharpServer

View File

@ -22,6 +22,7 @@ from ycm.client.base_request import BaseRequest, BuildRequestData, ServerError
from ycm import vimsupport from ycm import vimsupport
from ycmd.utils import ToUtf8IfNeeded from ycmd.utils import ToUtf8IfNeeded
def _EnsureBackwardsCompatibility( arguments ): def _EnsureBackwardsCompatibility( arguments ):
if arguments and arguments[ 0 ] == 'GoToDefinitionElseDeclaration': if arguments and arguments[ 0 ] == 'GoToDefinitionElseDeclaration':
arguments[ 0 ] = 'GoTo' arguments[ 0 ] = 'GoTo'
@ -49,7 +50,7 @@ class CommandRequest( BaseRequest ):
} ) } )
try: try:
self._response = self.PostDataToHandler( request_data, self._response = self.PostDataToHandler( request_data,
'run_completer_command' ) 'run_completer_command' )
except ServerError as e: except ServerError as e:
vimsupport.PostMultiLineNotice( e ) vimsupport.PostMultiLineNotice( e )
@ -57,6 +58,7 @@ class CommandRequest( BaseRequest ):
def Response( self ): def Response( self ):
return self._response return self._response
def RunPostCommandActionsIfNeeded( self ): def RunPostCommandActionsIfNeeded( self ):
if not self.Done() or not self._response: if not self.Done() or not self._response:
return return
@ -68,6 +70,7 @@ class CommandRequest( BaseRequest ):
elif 'message' in self._response: elif 'message' in self._response:
self._HandleMessageResponse() self._HandleMessageResponse()
def _HandleGotoResponse( self ): def _HandleGotoResponse( self ):
if isinstance( self._response, list ): if isinstance( self._response, list ):
defs = [ _BuildQfListItem( x ) for x in self._response ] defs = [ _BuildQfListItem( x ) for x in self._response ]
@ -75,56 +78,27 @@ class CommandRequest( BaseRequest ):
vim.eval( 'youcompleteme#OpenGoToList()' ) vim.eval( 'youcompleteme#OpenGoToList()' )
else: else:
vimsupport.JumpToLocation( self._response[ 'filepath' ], vimsupport.JumpToLocation( self._response[ 'filepath' ],
self._response[ 'line_num' ], self._response[ 'line_num' ],
self._response[ 'column_num' ] ) self._response[ 'column_num' ] )
def _HandleFixitResponse( self ): def _HandleFixitResponse( self ):
if not len( self._response[ 'fixits' ] ): if not len( self._response[ 'fixits' ] ):
vimsupport.EchoText( "No fixits found for current line" ) vimsupport.EchoText( "No fixits found for current line" )
else: else:
fixit = self._response[ 'fixits' ][ 0 ] chunks = self._response[ 'fixits' ][ 0 ][ 'chunks' ]
# We need to track the difference in length, but ensuring we apply fixes vimsupport.ReplaceChunksList( chunks )
# in ascending order of insertion point.
fixit[ 'chunks' ].sort( key = lambda chunk: (
str(chunk[ 'range' ][ 'start' ][ 'line_num' ])
+ ','
+ str(chunk[ 'range' ][ 'start' ][ 'column_num' ])
))
# Remember the line number we're processing. Negative line number means we vimsupport.EchoTextVimWidth( "FixIt applied "
# haven't processed any lines yet (by nature of being not equal to any + str( len( chunks ) )
# real line number). + " changes" )
last_line = -1
# Counter of changes applied, so the user has a mental picture of the
# undo history this change is creating.
num_fixed = 0
line_delta = 0
for chunk in fixit[ 'chunks' ]:
if chunk[ 'range' ][ 'start' ][ 'line_num' ] != last_line:
# If this chunk is on a different line than the previous chunk,
# then ignore previous deltas (as offsets won't have changed).
last_line = chunk[ 'range' ][ 'end' ][ 'line_num' ]
char_delta = 0
(new_line_delta, new_char_delta) = vimsupport.ReplaceChunk(
chunk[ 'range' ][ 'start' ],
chunk[ 'range' ][ 'end' ],
chunk[ 'replacement_text' ],
line_delta, char_delta )
line_delta += new_line_delta
char_delta += new_char_delta
num_fixed = num_fixed + 1
vimsupport.EchoTextVimWidth("FixIt applied "
+ str(num_fixed)
+ " changes")
def _HandleMessageResponse( self ): def _HandleMessageResponse( self ):
vimsupport.EchoText( self._response[ 'message' ] ) vimsupport.EchoText( self._response[ 'message' ] )
def SendCommandRequest( arguments, completer ): def SendCommandRequest( arguments, completer ):
request = CommandRequest( arguments, completer ) request = CommandRequest( arguments, completer )
# This is a blocking call. # This is a blocking call.

View File

@ -21,6 +21,7 @@ from ycmd.utils import ToUtf8IfNeeded
from ycm.client.base_request import ( BaseRequest, JsonFromFuture, from ycm.client.base_request import ( BaseRequest, JsonFromFuture,
HandleServerException, HandleServerException,
MakeServerException ) MakeServerException )
import os
TIMEOUT_SECONDS = 0.5 TIMEOUT_SECONDS = 0.5
@ -67,6 +68,13 @@ def ConvertCompletionDataToVimData( completion_data ):
'dup' : 1, 'dup' : 1,
} }
if ( 'extra_data' in completion_data and
'doc_string' in completion_data[ 'extra_data' ] ):
doc_string = ToUtf8IfNeeded(
completion_data[ 'extra_data' ][ 'doc_string' ] )
else:
doc_string = ""
if 'menu_text' in completion_data: if 'menu_text' in completion_data:
vim_data[ 'abbr' ] = ToUtf8IfNeeded( completion_data[ 'menu_text' ] ) vim_data[ 'abbr' ] = ToUtf8IfNeeded( completion_data[ 'menu_text' ] )
if 'extra_menu_info' in completion_data: if 'extra_menu_info' in completion_data:
@ -76,6 +84,10 @@ def ConvertCompletionDataToVimData( completion_data ):
completion_data[ 'kind' ] )[ 0 ].lower() completion_data[ 'kind' ] )[ 0 ].lower()
if 'detailed_info' in completion_data: if 'detailed_info' in completion_data:
vim_data[ 'info' ] = ToUtf8IfNeeded( completion_data[ 'detailed_info' ] ) vim_data[ 'info' ] = ToUtf8IfNeeded( completion_data[ 'detailed_info' ] )
if doc_string:
vim_data[ 'info' ] += os.linesep + doc_string
elif doc_string:
vim_data[ 'info' ] = doc_string
return vim_data return vim_data

View File

View File

@ -0,0 +1,134 @@
#!/usr/bin/env python
#
# Copyright (C) 2015 YouCompleteMe Contributors
#
# 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 nose.tools import eq_
from ycm.test_utils import MockVimModule
vim_mock = MockVimModule()
import os
from .. import completion_request
class ConvertCompletionResponseToVimDatas_test:
""" This class tests the
completion_request._ConvertCompletionResponseToVimDatas method """
def _Check( self, completion_data, expected_vim_data ):
vim_data = completion_request._ConvertCompletionDataToVimData(
completion_data )
try:
eq_( expected_vim_data, vim_data )
except:
print "Expected:\n'{0}'\nwhen parsing:\n'{1}'\nBut found:\n'{2}'".format(
expected_vim_data,
completion_data,
vim_data )
raise
def All_Fields_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
'extra_data': {
'doc_string': 'DOC STRING',
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO' + os.linesep + 'DOC STRING',
'dup' : 1,
} )
def Just_Detailed_Info_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO',
'dup' : 1,
} )
def Just_Doc_String_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'extra_data': {
'doc_string': 'DOC STRING',
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DOC STRING',
'dup' : 1,
} )
def Extra_Info_No_Doc_String_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'extra_data': {
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'dup' : 1,
} )
def Extra_Info_No_Doc_String_With_Detailed_Info_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
'extra_data': {
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO',
'dup' : 1,
} )

View File

@ -20,6 +20,7 @@
from ycm import vimsupport from ycm import vimsupport
from nose.tools import eq_ from nose.tools import eq_
def ReplaceChunk_SingleLine_Repl_1_test(): def ReplaceChunk_SingleLine_Repl_1_test():
# Replace with longer range # Replace with longer range
# 12345678901234567 # 12345678901234567
@ -75,6 +76,7 @@ def ReplaceChunk_SingleLine_Repl_1_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, 10 ) eq_( char_offset, 10 )
def ReplaceChunk_SingleLine_Repl_2_test(): def ReplaceChunk_SingleLine_Repl_2_test():
# Replace with shorter range # Replace with shorter range
# 12345678901234567 # 12345678901234567
@ -91,6 +93,7 @@ def ReplaceChunk_SingleLine_Repl_2_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, -2 ) eq_( char_offset, -2 )
def ReplaceChunk_SingleLine_Repl_3_test(): def ReplaceChunk_SingleLine_Repl_3_test():
# Replace with equal range # Replace with equal range
# 12345678901234567 # 12345678901234567
@ -107,6 +110,7 @@ def ReplaceChunk_SingleLine_Repl_3_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, 0 ) eq_( char_offset, 0 )
def ReplaceChunk_SingleLine_Add_1_test(): def ReplaceChunk_SingleLine_Add_1_test():
# Insert at start # Insert at start
result_buffer = [ "is a string" ] result_buffer = [ "is a string" ]
@ -122,6 +126,7 @@ def ReplaceChunk_SingleLine_Add_1_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, 5 ) eq_( char_offset, 5 )
def ReplaceChunk_SingleLine_Add_2_test(): def ReplaceChunk_SingleLine_Add_2_test():
# Insert at end # Insert at end
result_buffer = [ "This is a " ] result_buffer = [ "This is a " ]
@ -137,6 +142,7 @@ def ReplaceChunk_SingleLine_Add_2_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, 6 ) eq_( char_offset, 6 )
def ReplaceChunk_SingleLine_Add_3_test(): def ReplaceChunk_SingleLine_Add_3_test():
# Insert in the middle # Insert in the middle
result_buffer = [ "This is a string" ] result_buffer = [ "This is a string" ]
@ -152,6 +158,7 @@ def ReplaceChunk_SingleLine_Add_3_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, 4 ) eq_( char_offset, 4 )
def ReplaceChunk_SingleLine_Del_1_test(): def ReplaceChunk_SingleLine_Del_1_test():
# Delete from start # Delete from start
result_buffer = [ "This is a string" ] result_buffer = [ "This is a string" ]
@ -167,6 +174,7 @@ def ReplaceChunk_SingleLine_Del_1_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, -5 ) eq_( char_offset, -5 )
def ReplaceChunk_SingleLine_Del_2_test(): def ReplaceChunk_SingleLine_Del_2_test():
# Delete from end # Delete from end
result_buffer = [ "This is a string" ] result_buffer = [ "This is a string" ]
@ -182,6 +190,7 @@ def ReplaceChunk_SingleLine_Del_2_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, -8 ) eq_( char_offset, -8 )
def ReplaceChunk_SingleLine_Del_3_test(): def ReplaceChunk_SingleLine_Del_3_test():
# Delete from middle # Delete from middle
result_buffer = [ "This is not a string" ] result_buffer = [ "This is not a string" ]
@ -197,6 +206,7 @@ def ReplaceChunk_SingleLine_Del_3_test():
eq_( line_offset, 0 ) eq_( line_offset, 0 )
eq_( char_offset, -4 ) eq_( char_offset, -4 )
def ReplaceChunk_RemoveSingleLine_test(): def ReplaceChunk_RemoveSingleLine_test():
result_buffer = [ "aAa", "aBa", "aCa" ] result_buffer = [ "aAa", "aBa", "aCa" ]
start, end = _BuildLocations( 2, 1, 3, 1 ) start, end = _BuildLocations( 2, 1, 3, 1 )
@ -250,7 +260,7 @@ def ReplaceChunk_SingleToMultipleLines2_test():
0, 0,
0, 0,
result_buffer ) result_buffer )
expected_buffer = [ "aAa", "aEb" ,"bFb", "GBa", "aCa" ] expected_buffer = [ "aAa", "aEb", "bFb", "GBa", "aCa" ]
eq_( expected_buffer, result_buffer ) eq_( expected_buffer, result_buffer )
eq_( line_offset, 2 ) eq_( line_offset, 2 )
eq_( char_offset, 0 ) eq_( char_offset, 0 )
@ -265,11 +275,12 @@ def ReplaceChunk_SingleToMultipleLines3_test():
0, 0,
0, 0,
result_buffer ) result_buffer )
expected_buffer = [ "aAa", "aEb" ,"bFb", "bGbBa", "aCa" ] expected_buffer = [ "aAa", "aEb", "bFb", "bGbBa", "aCa" ]
eq_( expected_buffer, result_buffer ) eq_( expected_buffer, result_buffer )
eq_( line_offset, 2 ) eq_( line_offset, 2 )
eq_( char_offset, 2 ) eq_( char_offset, 2 )
def ReplaceChunk_SingleToMultipleLinesReplace_test(): def ReplaceChunk_SingleToMultipleLinesReplace_test():
result_buffer = [ "aAa", "aBa", "aCa" ] result_buffer = [ "aAa", "aBa", "aCa" ]
start, end = _BuildLocations( 1, 2, 1, 4 ) start, end = _BuildLocations( 1, 2, 1, 4 )
@ -284,6 +295,7 @@ def ReplaceChunk_SingleToMultipleLinesReplace_test():
eq_( line_offset, 2 ) eq_( line_offset, 2 )
eq_( char_offset, 0 ) eq_( char_offset, 0 )
def ReplaceChunk_SingleToMultipleLinesReplace_2_test(): def ReplaceChunk_SingleToMultipleLinesReplace_2_test():
result_buffer = [ "aAa", result_buffer = [ "aAa",
"aBa", "aBa",
@ -521,3 +533,46 @@ def _BuildLocations( start_line, start_column, end_line, end_column ):
'line_num' : end_line, 'line_num' : end_line,
'column_num': end_column, 'column_num': end_column,
} }
def ReplaceChunksList_SortedChunks_test():
chunks = [
_BuildChunk( 1, 4, 1, 4, '('),
_BuildChunk( 1, 11, 1, 11, ')' )
]
result_buffer = [ "CT<10 >> 2> ct" ]
vimsupport.ReplaceChunksList( chunks, result_buffer )
expected_buffer = [ "CT<(10 >> 2)> ct" ]
eq_( expected_buffer, result_buffer )
def ReplaceChunksList_UnsortedChunks_test():
chunks = [
_BuildChunk( 1, 11, 1, 11, ')'),
_BuildChunk( 1, 4, 1, 4, '(' )
]
result_buffer = [ "CT<10 >> 2> ct" ]
vimsupport.ReplaceChunksList( chunks, result_buffer )
expected_buffer = [ "CT<(10 >> 2)> ct" ]
eq_( expected_buffer, result_buffer )
def _BuildChunk( start_line, start_column, end_line, end_column,
replacement_text ):
return {
'range': {
'start': {
'line_num': start_line,
'column_num': start_column,
},
'end': {
'line_num': end_line,
'column_num': end_column,
},
},
'replacement_text': replacement_text
}

View File

@ -474,6 +474,40 @@ def GetIntValue( variable ):
return int( vim.eval( variable ) ) return int( vim.eval( variable ) )
def ReplaceChunksList( chunks, vim_buffer = None ):
if vim_buffer is None:
vim_buffer = vim.current.buffer
# We need to track the difference in length, but ensuring we apply fixes
# in ascending order of insertion point.
chunks.sort( key = lambda chunk: (
chunk[ 'range' ][ 'start' ][ 'line_num' ],
chunk[ 'range' ][ 'start' ][ 'column_num' ]
) )
# Remember the line number we're processing. Negative line number means we
# haven't processed any lines yet (by nature of being not equal to any
# real line number).
last_line = -1
line_delta = 0
for chunk in chunks:
if chunk[ 'range' ][ 'start' ][ 'line_num' ] != last_line:
# If this chunk is on a different line than the previous chunk,
# then ignore previous deltas (as offsets won't have changed).
last_line = chunk[ 'range' ][ 'end' ][ 'line_num' ]
char_delta = 0
( new_line_delta, new_char_delta ) = ReplaceChunk(
chunk[ 'range' ][ 'start' ],
chunk[ 'range' ][ 'end' ],
chunk[ 'replacement_text' ],
line_delta, char_delta,
vim_buffer )
line_delta += new_line_delta
char_delta += new_char_delta
# Replace the chunk of text specified by a contiguous range with the supplied # Replace the chunk of text specified by a contiguous range with the supplied
# text. # text.
# * start and end are objects with line_num and column_num properties # * start and end are objects with line_num and column_num properties
@ -484,10 +518,7 @@ def GetIntValue( variable ):
# returns the delta (in lines and characters) that any position after the end # returns the delta (in lines and characters) that any position after the end
# needs to be adjusted by. # needs to be adjusted by.
def ReplaceChunk( start, end, replacement_text, line_delta, char_delta, def ReplaceChunk( start, end, replacement_text, line_delta, char_delta,
vim_buffer = None ): vim_buffer ):
if vim_buffer is None:
vim_buffer = vim.current.buffer
# ycmd's results are all 1-based, but vim's/python's are all 0-based # ycmd's results are all 1-based, but vim's/python's are all 0-based
# (so we do -1 on all of the values) # (so we do -1 on all of the values)
start_line = start[ 'line_num' ] - 1 + line_delta start_line = start[ 'line_num' ] - 1 + line_delta

View File

@ -193,6 +193,8 @@ class YouCompleteMe( object ):
self._omnicomp, wrapped_request_data ) self._omnicomp, wrapped_request_data )
return self._latest_completion_request return self._latest_completion_request
request_data[ 'working_dir' ] = os.getcwd()
self._AddExtraConfDataIfNeeded( request_data ) self._AddExtraConfDataIfNeeded( request_data )
if force_semantic: if force_semantic:
request_data[ 'force_semantic' ] = True request_data[ 'force_semantic' ] = True

2
third_party/ycmd vendored

@ -1 +1 @@
Subproject commit 01d5f2df8da4a4d960ddc8ab0349d62813147f59 Subproject commit b46b8f09e33ccb6c70dfd02bba879c0b77fff4d5