Auto merge of #2907 - puremourning:java-additional-fixits, r=micbou
[READY] Support for additional FixIts on java completions, e.g. for automatic imports
Java completer can include FixIts which are applied when a completion
entry is selected. We use the existing mechanism implemented for c-sharp
to perform these edits using the CompleteDone autocommand.
However, the existing mechanism relies on pattern matching the source to
work out which item was completed. Vim patch 8.0.1493 introduces support
for user_data on completion items, so when available we populate it with
the completion array index of the item and use that to get the exact
element that was selected. This is both a lot faster and a lot more
accirate.
Of course when applying these 'FixIts' we don't interrupt the user with
confirmation or the quickfix list as this would just be annoying. If the
server reports that an edit must be made, we just make the edit.
## Use SplitLines in ReplaceChunk to allow newlines to be inserted.
The Java completer frequently inserts newlines as part of its FixIts. We
previously used the base python splitlines implementation which consumed
terminating newlines and also consumed empty strings.
We can therefore now remove the duplicate newline in InsertNamespace, as
this was only to work around the splitlines behaviour.
In the tests, be clear that replacement_text in ReplaceChunks is Unicode
# PR Prelude
Thank you for working on YCM! :)
**Please complete these steps and check these boxes (by putting an `x` inside
the brackets) _before_ filing your PR:**
- [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.**
# Why this change is necessary and useful
Automatic addition of import statements is a highly desirable feature when working with languages like java where it is idiomatic to literally import everything by name. Users expect this function: it was the first question I got when i put java live at work.
I was at first reticent to include it due to the irksome complete_done interface, but since Bram merged my PR: 9b56a57cda
we can now identify the exact completion selected which makes this a _lot_ more robust.
We can't just remove the old code as nobody will actually have that version yet, but I have tested before and after and it is fully backwardly compatible.
# Test case
A simple way to verify this is with the ycmd tests:
* open `third_party/ycmd/ycmd/tests/java/testdata/simple_eclipse_project/src/com/test/TestFactory.java`
* Invoke completion for `CUTHBERT` on line 19 (replace to end of line)
* select one of the enum values
You should get the enum value automatically imported at the top of the file.
[cont]: https://github.com/Valloric/YouCompleteMe/blob/master/CONTRIBUTING.md
[code]: https://github.com/Valloric/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md
<!-- 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/2907)
<!-- Reviewable:end -->
This commit is contained in:
commit
ce1764cf40
@ -826,7 +826,7 @@ Quick Feature Summary
|
|||||||
**NOTE**: Java support is currently experimental. Please let us know your
|
**NOTE**: Java support is currently experimental. Please let us know your
|
||||||
[feedback](#contact).
|
[feedback](#contact).
|
||||||
|
|
||||||
* Semantic auto-completion
|
* Semantic auto-completion with automatic import insertion
|
||||||
* Go to definition (`GoTo`, `GoToDefinition`, and `GoToDeclaration` are
|
* Go to definition (`GoTo`, `GoToDefinition`, and `GoToDeclaration` are
|
||||||
identical)
|
identical)
|
||||||
* Reference finding (`GoToReferences`)
|
* Reference finding (`GoToReferences`)
|
||||||
@ -834,7 +834,7 @@ Quick Feature Summary
|
|||||||
* Renaming symbols (`RefactorRename <new name>`)
|
* Renaming symbols (`RefactorRename <new name>`)
|
||||||
* View documentation comments for identifiers (`GetDoc`)
|
* View documentation comments for identifiers (`GetDoc`)
|
||||||
* Type information for identifiers (`GetType`)
|
* Type information for identifiers (`GetType`)
|
||||||
* Automatically fix certain errors (`FixIt`)
|
* Automatically fix certain errors including code generation (`FixIt`)
|
||||||
* Detection of java projects
|
* Detection of java projects
|
||||||
* Management of `jdt.ls` server instance
|
* Management of `jdt.ls` server instance
|
||||||
|
|
||||||
@ -1185,6 +1185,9 @@ package you have in the virtual environment.
|
|||||||
|
|
||||||
4. Edit a Java file from your project.
|
4. Edit a Java file from your project.
|
||||||
|
|
||||||
|
For the best experience, we highly recommend at least Vim 8.0.1493 when using
|
||||||
|
Java support with YouCompleteMe.
|
||||||
|
|
||||||
#### Java Project Files
|
#### Java Project Files
|
||||||
|
|
||||||
In order to provide semantic analysis, the Java completion engine requires
|
In order to provide semantic analysis, the Java completion engine requires
|
||||||
|
@ -1074,7 +1074,7 @@ Java ~
|
|||||||
**NOTE**: Java support is currently experimental. Please let us know your
|
**NOTE**: Java support is currently experimental. Please let us know your
|
||||||
feedback.
|
feedback.
|
||||||
|
|
||||||
- Semantic auto-completion
|
- Semantic auto-completion with automatic import insertion
|
||||||
- Go to definition (|GoTo|, |GoToDefinition|, and |GoToDeclaration| are
|
- Go to definition (|GoTo|, |GoToDefinition|, and |GoToDeclaration| are
|
||||||
identical)
|
identical)
|
||||||
- Reference finding (|GoToReferences|)
|
- Reference finding (|GoToReferences|)
|
||||||
@ -1082,7 +1082,7 @@ feedback.
|
|||||||
- Renaming symbols ('RefactorRename <new name>')
|
- Renaming symbols ('RefactorRename <new name>')
|
||||||
- View documentation comments for identifiers (|GetDoc|)
|
- View documentation comments for identifiers (|GetDoc|)
|
||||||
- Type information for identifiers (|GetType|)
|
- Type information for identifiers (|GetType|)
|
||||||
- Automatically fix certain errors (|FixIt|)
|
- Automatically fix certain errors including code generation (|FixIt|)
|
||||||
- Detection of java projects
|
- Detection of java projects
|
||||||
- Management of 'jdt.ls' server instance
|
- Management of 'jdt.ls' server instance
|
||||||
|
|
||||||
@ -1454,6 +1454,9 @@ Java quick Start ~
|
|||||||
|
|
||||||
4. Edit a Java file from your project.
|
4. Edit a Java file from your project.
|
||||||
|
|
||||||
|
For the best experience, we highly recommend at least Vim 8.0.1493 when using
|
||||||
|
Java support with YouCompleteMe.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
*youcompleteme-java-project-files*
|
*youcompleteme-java-project-files*
|
||||||
Java Project Files ~
|
Java Project Files ~
|
||||||
|
@ -69,7 +69,7 @@ class CompletionRequest( BaseRequest ):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def ConvertCompletionDataToVimData( completion_data ):
|
def ConvertCompletionDataToVimData( completion_identifier, completion_data ):
|
||||||
# see :h complete-items for a description of the dictionary fields
|
# see :h complete-items for a description of the dictionary fields
|
||||||
vim_data = {
|
vim_data = {
|
||||||
'word' : '',
|
'word' : '',
|
||||||
@ -100,9 +100,19 @@ def ConvertCompletionDataToVimData( completion_data ):
|
|||||||
elif doc_string:
|
elif doc_string:
|
||||||
vim_data[ 'info' ] = doc_string
|
vim_data[ 'info' ] = doc_string
|
||||||
|
|
||||||
|
# We store the completion item index as a string in the completion user_data.
|
||||||
|
# This allows us to identify the _exact_ item that was completed in the
|
||||||
|
# CompleteDone handler, by inspecting this item from v:completed_item
|
||||||
|
#
|
||||||
|
# We convert to string because completion user data items must be strings.
|
||||||
|
#
|
||||||
|
# Note: Not all versions of Vim support this (added in 8.0.1483), but adding
|
||||||
|
# the item to the dictionary is harmless in earlier Vims.
|
||||||
|
vim_data[ 'user_data' ] = str( completion_identifier )
|
||||||
|
|
||||||
return vim_data
|
return vim_data
|
||||||
|
|
||||||
|
|
||||||
def _ConvertCompletionDatasToVimDatas( response_data ):
|
def _ConvertCompletionDatasToVimDatas( response_data ):
|
||||||
return [ ConvertCompletionDataToVimData( x )
|
return [ ConvertCompletionDataToVimData( i, x )
|
||||||
for x in response_data ]
|
for i, x in enumerate( response_data ) ]
|
||||||
|
@ -33,8 +33,9 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
""" This class tests the
|
""" This class tests the
|
||||||
completion_request._ConvertCompletionResponseToVimDatas method """
|
completion_request._ConvertCompletionResponseToVimDatas method """
|
||||||
|
|
||||||
def _Check( self, completion_data, expected_vim_data ):
|
def _Check( self, completion_id, completion_data, expected_vim_data ):
|
||||||
vim_data = completion_request.ConvertCompletionDataToVimData(
|
vim_data = completion_request.ConvertCompletionDataToVimData(
|
||||||
|
completion_id,
|
||||||
completion_data )
|
completion_data )
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -48,7 +49,7 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
|
|
||||||
|
|
||||||
def All_Fields_test( self ):
|
def All_Fields_test( self ):
|
||||||
self._Check( {
|
self._Check( 0, {
|
||||||
'insertion_text': 'INSERTION TEXT',
|
'insertion_text': 'INSERTION TEXT',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -64,12 +65,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DETAILED INFO\nDOC STRING',
|
'info' : 'DETAILED INFO\nDOC STRING',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '0',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def Just_Detailed_Info_test( self ):
|
def Just_Detailed_Info_test( self ):
|
||||||
self._Check( {
|
self._Check( 9999999999, {
|
||||||
'insertion_text': 'INSERTION TEXT',
|
'insertion_text': 'INSERTION TEXT',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -82,12 +84,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DETAILED INFO',
|
'info' : 'DETAILED INFO',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '9999999999',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def Just_Doc_String_test( self ):
|
def Just_Doc_String_test( self ):
|
||||||
self._Check( {
|
self._Check( 'not_an_int', {
|
||||||
'insertion_text': 'INSERTION TEXT',
|
'insertion_text': 'INSERTION TEXT',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -102,12 +105,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DOC STRING',
|
'info' : 'DOC STRING',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': 'not_an_int',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def Extra_Info_No_Doc_String_test( self ):
|
def Extra_Info_No_Doc_String_test( self ):
|
||||||
self._Check( {
|
self._Check( 0, {
|
||||||
'insertion_text': 'INSERTION TEXT',
|
'insertion_text': 'INSERTION TEXT',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -120,12 +124,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'menu' : 'EXTRA MENU INFO',
|
'menu' : 'EXTRA MENU INFO',
|
||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '0',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def Extra_Info_No_Doc_String_With_Detailed_Info_test( self ):
|
def Extra_Info_No_Doc_String_With_Detailed_Info_test( self ):
|
||||||
self._Check( {
|
self._Check( '0', {
|
||||||
'insertion_text': 'INSERTION TEXT',
|
'insertion_text': 'INSERTION TEXT',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -140,12 +145,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DETAILED INFO',
|
'info' : 'DETAILED INFO',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '0',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def Empty_Insertion_Text_test( self ):
|
def Empty_Insertion_Text_test( self ):
|
||||||
self._Check( {
|
self._Check( 0, {
|
||||||
'insertion_text': '',
|
'insertion_text': '',
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
@ -161,12 +167,13 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DETAILED INFO\nDOC STRING',
|
'info' : 'DETAILED INFO\nDOC STRING',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '0',
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
def No_Insertion_Text_test( self ):
|
def No_Insertion_Text_test( self ):
|
||||||
self._Check( {
|
self._Check( 0, {
|
||||||
'menu_text': 'MENU TEXT',
|
'menu_text': 'MENU TEXT',
|
||||||
'extra_menu_info': 'EXTRA MENU INFO',
|
'extra_menu_info': 'EXTRA MENU INFO',
|
||||||
'kind': 'K',
|
'kind': 'K',
|
||||||
@ -181,5 +188,6 @@ class ConvertCompletionResponseToVimDatas_test( object ):
|
|||||||
'kind' : 'k',
|
'kind' : 'k',
|
||||||
'info' : 'DETAILED INFO\nDOC STRING',
|
'info' : 'DETAILED INFO\nDOC STRING',
|
||||||
'dup' : 1,
|
'dup' : 1,
|
||||||
'empty': 1,
|
'empty' : 1,
|
||||||
|
'user_data': '0'
|
||||||
} )
|
} )
|
||||||
|
@ -36,27 +36,43 @@ from ycm import vimsupport
|
|||||||
from ycm.tests import YouCompleteMeInstance
|
from ycm.tests import YouCompleteMeInstance
|
||||||
from ycmd.utils import ToBytes
|
from ycmd.utils import ToBytes
|
||||||
|
|
||||||
|
from ycm.youcompleteme import _CompleteDoneHook_CSharp
|
||||||
|
from ycm.youcompleteme import _CompleteDoneHook_Java
|
||||||
|
|
||||||
def GetVariableValue_CompleteItemIs( word, abbr = None, menu = None,
|
|
||||||
info = None, kind = None ):
|
def CompleteItemIs( word, abbr = None, menu = None,
|
||||||
def Result( variable ):
|
info = None, kind = None, **kwargs ):
|
||||||
if variable == 'v:completed_item':
|
item = {
|
||||||
return {
|
|
||||||
'word': ToBytes( word ),
|
'word': ToBytes( word ),
|
||||||
'abbr': ToBytes( abbr ),
|
'abbr': ToBytes( abbr ),
|
||||||
'menu': ToBytes( menu ),
|
'menu': ToBytes( menu ),
|
||||||
'info': ToBytes( info ),
|
'info': ToBytes( info ),
|
||||||
'kind': ToBytes( kind ),
|
'kind': ToBytes( kind ),
|
||||||
}
|
}
|
||||||
|
item.update( **kwargs )
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
def GetVariableValue_CompleteItemIs( word, abbr = None, menu = None,
|
||||||
|
info = None, kind = None, **kwargs ):
|
||||||
|
def Result( variable ):
|
||||||
|
if variable == 'v:completed_item':
|
||||||
|
return CompleteItemIs( word, abbr, menu, info, kind, **kwargs )
|
||||||
return DEFAULT
|
return DEFAULT
|
||||||
return MagicMock( side_effect = Result )
|
return MagicMock( side_effect = Result )
|
||||||
|
|
||||||
|
|
||||||
def BuildCompletion( namespace = None, insertion_text = 'Test',
|
def BuildCompletion( insertion_text = 'Test',
|
||||||
menu_text = None, extra_menu_info = None,
|
menu_text = None,
|
||||||
detailed_info = None, kind = None ):
|
extra_menu_info = None,
|
||||||
|
detailed_info = None,
|
||||||
|
kind = None,
|
||||||
|
extra_data = None ):
|
||||||
|
if extra_data is None:
|
||||||
|
extra_data = {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'extra_data': { 'required_namespace_import': namespace },
|
'extra_data': extra_data,
|
||||||
'insertion_text': insertion_text,
|
'insertion_text': insertion_text,
|
||||||
'menu_text': menu_text,
|
'menu_text': menu_text,
|
||||||
'extra_menu_info': extra_menu_info,
|
'extra_menu_info': extra_menu_info,
|
||||||
@ -65,13 +81,53 @@ def BuildCompletion( namespace = None, insertion_text = 'Test',
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def BuildCompletionNamespace( namespace = None,
|
||||||
|
insertion_text = 'Test',
|
||||||
|
menu_text = None,
|
||||||
|
extra_menu_info = None,
|
||||||
|
detailed_info = None,
|
||||||
|
kind = None ):
|
||||||
|
return BuildCompletion( insertion_text = insertion_text,
|
||||||
|
menu_text = menu_text,
|
||||||
|
extra_menu_info = extra_menu_info,
|
||||||
|
detailed_info = detailed_info,
|
||||||
|
kind = kind,
|
||||||
|
extra_data = {
|
||||||
|
'required_namespace_import': namespace
|
||||||
|
} )
|
||||||
|
|
||||||
|
|
||||||
|
def BuildCompletionFixIt( fixits,
|
||||||
|
insertion_text = 'Test',
|
||||||
|
menu_text = None,
|
||||||
|
extra_menu_info = None,
|
||||||
|
detailed_info = None,
|
||||||
|
kind = None ):
|
||||||
|
return BuildCompletion( insertion_text = insertion_text,
|
||||||
|
menu_text = menu_text,
|
||||||
|
extra_menu_info = extra_menu_info,
|
||||||
|
detailed_info = detailed_info,
|
||||||
|
kind = kind,
|
||||||
|
extra_data = {
|
||||||
|
'fixits': fixits,
|
||||||
|
} )
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _SetupForCsharpCompletionDone( ycm, completions ):
|
def _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
with patch( 'ycm.vimsupport.InsertNamespace' ):
|
with patch( 'ycm.vimsupport.InsertNamespace' ):
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _SetUpCompleteDone( ycm, completions ):
|
||||||
with patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Test' ):
|
with patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Test' ):
|
||||||
request = MagicMock()
|
request = MagicMock()
|
||||||
request.Done = MagicMock( return_value = True )
|
request.Done = MagicMock( return_value = True )
|
||||||
request.RawResponse = MagicMock( return_value = completions )
|
request.RawResponse = MagicMock( return_value = {
|
||||||
|
'completions': completions
|
||||||
|
} )
|
||||||
ycm._latest_completion_request = request
|
ycm._latest_completion_request = request
|
||||||
yield
|
yield
|
||||||
|
|
||||||
@ -79,127 +135,137 @@ def _SetupForCsharpCompletionDone( ycm, completions ):
|
|||||||
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'cs' ] )
|
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'cs' ] )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def GetCompleteDoneHooks_ResultOnCsharp_test( ycm, *args ):
|
def GetCompleteDoneHooks_ResultOnCsharp_test( ycm, *args ):
|
||||||
result = ycm.GetCompleteDoneHooks()
|
result = list( ycm.GetCompleteDoneHooks() )
|
||||||
eq_( 1, len( list( result ) ) )
|
eq_( [ _CompleteDoneHook_CSharp ], result )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'txt' ] )
|
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'java' ] )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def GetCompleteDoneHooks_ResultOnJava_test( ycm, *args ):
|
||||||
|
result = list( ycm.GetCompleteDoneHooks() )
|
||||||
|
eq_( [ _CompleteDoneHook_Java ], result )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def GetCompleteDoneHooks_EmptyOnOtherFiletype_test( ycm, *args ):
|
def GetCompleteDoneHooks_EmptyOnOtherFiletype_test( ycm, *args ):
|
||||||
result = ycm.GetCompleteDoneHooks()
|
result = ycm.GetCompleteDoneHooks()
|
||||||
eq_( 0, len( list( result ) ) )
|
eq_( 0, len( list( result ) ) )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'txt' ] )
|
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def OnCompleteDone_WithActionCallsIt_test( ycm, *args ):
|
def OnCompleteDone_WithActionCallsIt_test( ycm, *args ):
|
||||||
action = MagicMock()
|
action = MagicMock()
|
||||||
ycm._complete_done_hooks[ 'txt' ] = action
|
ycm._complete_done_hooks[ 'ycmtest' ] = action
|
||||||
ycm.OnCompleteDone()
|
ycm.OnCompleteDone()
|
||||||
ok_( action.called )
|
ok_( action.called )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'txt' ] )
|
@patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def OnCompleteDone_NoActionNoError_test( ycm, *args ):
|
def OnCompleteDone_NoActionNoError_test( ycm, *args ):
|
||||||
|
with patch.object( ycm, '_OnCompleteDone_Csharp' ) as csharp:
|
||||||
|
with patch.object( ycm, '_OnCompleteDone_Java' ) as java:
|
||||||
ycm.OnCompleteDone()
|
ycm.OnCompleteDone()
|
||||||
|
csharp.assert_not_called()
|
||||||
|
java.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'Test' ) )
|
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def FilterToCompletedCompletions_MatchIsReturned_test( ycm, *args ):
|
def FilterToCompletedCompletions_MatchIsReturned_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
||||||
result = ycm._FilterToMatchingCompletions( completions, False )
|
result = ycm._FilterToMatchingCompletions( CompleteItemIs( 'Test' ),
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
eq_( list( result ), completions )
|
eq_( list( result ), completions )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'A' ) )
|
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def FilterToCompletedCompletions_ShortTextDoesntRaise_test( ycm, *args ):
|
def FilterToCompletedCompletions_ShortTextDoesntRaise_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
|
completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
|
||||||
ycm._FilterToMatchingCompletions( completions, False )
|
ycm._FilterToMatchingCompletions( CompleteItemIs( 'A' ),
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'Test' ) )
|
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def FilterToCompletedCompletions_ExactMatchIsReturned_test( ycm, *args ):
|
def FilterToCompletedCompletions_ExactMatchIsReturned_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
||||||
result = ycm._FilterToMatchingCompletions( completions, False )
|
result = ycm._FilterToMatchingCompletions( CompleteItemIs( 'Test' ),
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
eq_( list( result ), completions )
|
eq_( list( result ), completions )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( ' Quote' ) )
|
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def FilterToCompletedCompletions_NonMatchIsntReturned_test( ycm, *args ):
|
def FilterToCompletedCompletions_NonMatchIsntReturned_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'A' ) ]
|
completions = [ BuildCompletion( insertion_text = 'A' ) ]
|
||||||
result = ycm._FilterToMatchingCompletions( completions, False )
|
result = ycm._FilterToMatchingCompletions( CompleteItemIs( ' Quote' ),
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
assert_that( list( result ), empty() )
|
assert_that( list( result ), empty() )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( '†es†' ) )
|
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def FilterToCompletedCompletions_Unicode_test( ycm, *args ):
|
def FilterToCompletedCompletions_Unicode_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = '†es†' ) ]
|
completions = [ BuildCompletion( insertion_text = '†es†' ) ]
|
||||||
result = ycm._FilterToMatchingCompletions( completions, False )
|
result = ycm._FilterToMatchingCompletions( CompleteItemIs( '†es†' ),
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
eq_( list( result ), completions )
|
eq_( list( result ), completions )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'Te' ) )
|
|
||||||
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def HasCompletionsThatCouldBeCompletedWithMoreText_MatchIsReturned_test(
|
def HasCompletionsThatCouldBeCompletedWithMoreText_MatchIsReturned_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
||||||
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions )
|
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
|
||||||
|
CompleteItemIs( 'Te' ),
|
||||||
|
completions )
|
||||||
eq_( result, True )
|
eq_( result, True )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'X' ) )
|
|
||||||
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def HasCompletionsThatCouldBeCompletedWithMoreText_ShortTextDoesntRaise_test(
|
def HasCompletionsThatCouldBeCompletedWithMoreText_ShortTextDoesntRaise_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
|
completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
|
||||||
ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions )
|
ycm._HasCompletionsThatCouldBeCompletedWithMoreText( CompleteItemIs( 'X' ),
|
||||||
|
completions )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'Test' ) )
|
|
||||||
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def HasCompletionsThatCouldBeCompletedWithMoreText_ExactMatchIsntReturned_test(
|
def HasCompletionsThatCouldBeCompletedWithMoreText_ExactMatchIsntReturned_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
completions = [ BuildCompletion( insertion_text = 'Test' ) ]
|
||||||
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions )
|
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
|
||||||
|
CompleteItemIs( 'Test' ),
|
||||||
|
completions )
|
||||||
eq_( result, False )
|
eq_( result, False )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( ' Quote' ) )
|
|
||||||
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def HasCompletionsThatCouldBeCompletedWithMoreText_NonMatchIsntReturned_test(
|
def HasCompletionsThatCouldBeCompletedWithMoreText_NonMatchIsntReturned_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = "A" ) ]
|
completions = [ BuildCompletion( insertion_text = "A" ) ]
|
||||||
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions )
|
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
|
||||||
|
CompleteItemIs( ' Quote' ),
|
||||||
|
completions )
|
||||||
eq_( result, False )
|
eq_( result, False )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
|
||||||
GetVariableValue_CompleteItemIs( 'Uniç' ) )
|
|
||||||
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = 'Uniç' )
|
@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = 'Uniç' )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def HasCompletionsThatCouldBeCompletedWithMoreText_Unicode_test(
|
def HasCompletionsThatCouldBeCompletedWithMoreText_Unicode_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( insertion_text = 'Uniçø∂¢' ) ]
|
completions = [ BuildCompletion( insertion_text = 'Uniçø∂¢' ) ]
|
||||||
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions )
|
result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
|
||||||
|
CompleteItemIs( 'Uniç' ),
|
||||||
|
completions )
|
||||||
eq_( result, True )
|
eq_( result, True )
|
||||||
|
|
||||||
|
|
||||||
@ -212,7 +278,7 @@ def GetRequiredNamespaceImport_ReturnNoneForNoExtraData_test( ycm ):
|
|||||||
def GetRequiredNamespaceImport_ReturnNamespaceFromExtraData_test( ycm ):
|
def GetRequiredNamespaceImport_ReturnNamespaceFromExtraData_test( ycm ):
|
||||||
namespace = 'A_NAMESPACE'
|
namespace = 'A_NAMESPACE'
|
||||||
eq_( namespace, ycm._GetRequiredNamespaceImport(
|
eq_( namespace, ycm._GetRequiredNamespaceImport(
|
||||||
BuildCompletion( namespace )
|
BuildCompletionNamespace( namespace )
|
||||||
) )
|
) )
|
||||||
|
|
||||||
|
|
||||||
@ -228,7 +294,7 @@ def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfNotDone_test( ycm ):
|
|||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_test(
|
def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( None ) ]
|
completions = [ BuildCompletionNamespace( None ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
eq_( [], ycm.GetCompletionsUserMayHaveCompleted() )
|
eq_( [], ycm.GetCompletionsUserMayHaveCompleted() )
|
||||||
|
|
||||||
@ -237,7 +303,7 @@ def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_test(
|
|||||||
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatches_test(
|
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatches_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
|
info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
|
||||||
completions = [ BuildCompletion( *info ) ]
|
completions = [ BuildCompletionNamespace( *info ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
with patch( 'ycm.vimsupport.GetVariableValue',
|
with patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
GetVariableValue_CompleteItemIs( *info[ 1: ] ) ):
|
GetVariableValue_CompleteItemIs( *info[ 1: ] ) ):
|
||||||
@ -248,7 +314,7 @@ def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatches_test(
|
|||||||
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatchesEvenIfPartial_test( # noqa
|
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatchesEvenIfPartial_test( # noqa
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
|
info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
|
||||||
completions = [ BuildCompletion( *info ),
|
completions = [ BuildCompletionNamespace( *info ),
|
||||||
BuildCompletion( insertion_text = 'TestTest' ) ]
|
BuildCompletion( insertion_text = 'TestTest' ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
with patch( 'ycm.vimsupport.GetVariableValue',
|
with patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
@ -272,11 +338,41 @@ def GetCompletionsUserMayHaveCompleted_DontReturnMatchIfNoExactMatchesAndPartial
|
|||||||
GetVariableValue_CompleteItemIs( 'Test' ) )
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfMatches_test( ycm, *args ):
|
def GetCompletionsUserMayHaveCompleted_ReturnMatchIfMatches_test( ycm, *args ):
|
||||||
completions = [ BuildCompletion( None ) ]
|
completions = [ BuildCompletionNamespace( None ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
eq_( completions, ycm.GetCompletionsUserMayHaveCompleted() )
|
eq_( completions, ycm.GetCompletionsUserMayHaveCompleted() )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test', user_data='0' ) )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def GetCompletionsUserMayHaveCompleted_UseUserData0_test( ycm, *args ):
|
||||||
|
# identical completions but we specify the first one via user_data
|
||||||
|
completions = [
|
||||||
|
BuildCompletionNamespace( 'namespace1' ),
|
||||||
|
BuildCompletionNamespace( 'namespace2' )
|
||||||
|
]
|
||||||
|
|
||||||
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
|
eq_( [ BuildCompletionNamespace( 'namespace1' ) ],
|
||||||
|
ycm.GetCompletionsUserMayHaveCompleted() )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test', user_data='1' ) )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def GetCompletionsUserMayHaveCompleted_UseUserData1_test( ycm, *args ):
|
||||||
|
# identical completions but we specify the second one via user_data
|
||||||
|
completions = [
|
||||||
|
BuildCompletionNamespace( 'namespace1' ),
|
||||||
|
BuildCompletionNamespace( 'namespace2' )
|
||||||
|
]
|
||||||
|
|
||||||
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
|
eq_( [ BuildCompletionNamespace( 'namespace2' ) ],
|
||||||
|
ycm.GetCompletionsUserMayHaveCompleted() )
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetVariableValue',
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
GetVariableValue_CompleteItemIs( 'Test' ) )
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
@ -291,7 +387,7 @@ def PostCompleteCsharp_EmptyDoesntInsertNamespace_test( ycm, *args ):
|
|||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def PostCompleteCsharp_ExistingWithoutNamespaceDoesntInsertNamespace_test(
|
def PostCompleteCsharp_ExistingWithoutNamespaceDoesntInsertNamespace_test(
|
||||||
ycm, *args ):
|
ycm, *args ):
|
||||||
completions = [ BuildCompletion( None ) ]
|
completions = [ BuildCompletionNamespace( None ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
ycm._OnCompleteDone_Csharp()
|
ycm._OnCompleteDone_Csharp()
|
||||||
ok_( not vimsupport.InsertNamespace.called )
|
ok_( not vimsupport.InsertNamespace.called )
|
||||||
@ -302,7 +398,7 @@ def PostCompleteCsharp_ExistingWithoutNamespaceDoesntInsertNamespace_test(
|
|||||||
@YouCompleteMeInstance()
|
@YouCompleteMeInstance()
|
||||||
def PostCompleteCsharp_ValueDoesInsertNamespace_test( ycm, *args ):
|
def PostCompleteCsharp_ValueDoesInsertNamespace_test( ycm, *args ):
|
||||||
namespace = 'A_NAMESPACE'
|
namespace = 'A_NAMESPACE'
|
||||||
completions = [ BuildCompletion( namespace ) ]
|
completions = [ BuildCompletionNamespace( namespace ) ]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
ycm._OnCompleteDone_Csharp()
|
ycm._OnCompleteDone_Csharp()
|
||||||
vimsupport.InsertNamespace.assert_called_once_with( namespace )
|
vimsupport.InsertNamespace.assert_called_once_with( namespace )
|
||||||
@ -316,9 +412,92 @@ def PostCompleteCsharp_InsertSecondNamespaceIfSelected_test( ycm, *args ):
|
|||||||
namespace = 'A_NAMESPACE'
|
namespace = 'A_NAMESPACE'
|
||||||
namespace2 = 'ANOTHER_NAMESPACE'
|
namespace2 = 'ANOTHER_NAMESPACE'
|
||||||
completions = [
|
completions = [
|
||||||
BuildCompletion( namespace ),
|
BuildCompletionNamespace( namespace ),
|
||||||
BuildCompletion( namespace2 ),
|
BuildCompletionNamespace( namespace2 ),
|
||||||
]
|
]
|
||||||
with _SetupForCsharpCompletionDone( ycm, completions ):
|
with _SetupForCsharpCompletionDone( ycm, completions ):
|
||||||
ycm._OnCompleteDone_Csharp()
|
ycm._OnCompleteDone_Csharp()
|
||||||
vimsupport.InsertNamespace.assert_called_once_with( namespace2 )
|
vimsupport.InsertNamespace.assert_called_once_with( namespace2 )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_NoFixIts_test( ycm, replace_chunks, *args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletionFixIt( [] )
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_EmptyFixIt_test( ycm, replace_chunks, *args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': [] } ] )
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_called_once_with( [], silent=True )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_NoFixIt_test( ycm, replace_chunks, *args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletion( )
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_PickFirst_test( ycm, replace_chunks, *args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_called_once_with( 'one', silent=True )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test', user_data='0' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_PickFirstUserData_test( ycm,
|
||||||
|
replace_chunks,
|
||||||
|
*args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_called_once_with( 'one', silent=True )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.GetVariableValue',
|
||||||
|
GetVariableValue_CompleteItemIs( 'Test', user_data='1' ) )
|
||||||
|
@patch( 'ycm.vimsupport.ReplaceChunks' )
|
||||||
|
@YouCompleteMeInstance()
|
||||||
|
def PostCompleteJava_ApplyFixIt_PickSecond_test( ycm, replace_chunks, *args ):
|
||||||
|
completions = [
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
|
||||||
|
BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
|
||||||
|
]
|
||||||
|
with _SetUpCompleteDone( ycm, completions ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
replace_chunks.assert_called_once_with( 'two', silent=True )
|
||||||
|
@ -841,6 +841,103 @@ def ReplaceChunks_SingleFile_NotOpen_test( vim_command,
|
|||||||
] )
|
] )
|
||||||
|
|
||||||
|
|
||||||
|
@patch( 'ycm.vimsupport.VariableExists', return_value = False )
|
||||||
|
@patch( 'ycm.vimsupport.SetFittingHeightForCurrentWindow' )
|
||||||
|
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
|
||||||
|
side_effect = [ -1, 1 ],
|
||||||
|
new_callable = ExtendedMock )
|
||||||
|
@patch( 'ycm.vimsupport.BufferIsVisible',
|
||||||
|
side_effect = [ False, True ],
|
||||||
|
new_callable = ExtendedMock )
|
||||||
|
@patch( 'ycm.vimsupport.OpenFilename',
|
||||||
|
new_callable = ExtendedMock )
|
||||||
|
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
|
||||||
|
@patch( 'ycm.vimsupport.Confirm',
|
||||||
|
return_value = True,
|
||||||
|
new_callable = ExtendedMock )
|
||||||
|
@patch( 'vim.eval', return_value = 10, new_callable = ExtendedMock )
|
||||||
|
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||||
|
def ReplaceChunks_SingleFile_NotOpen_Silent_test(
|
||||||
|
vim_command,
|
||||||
|
vim_eval,
|
||||||
|
confirm,
|
||||||
|
post_vim_message,
|
||||||
|
open_filename,
|
||||||
|
buffer_is_visible,
|
||||||
|
get_buffer_number_for_filename,
|
||||||
|
set_fitting_height,
|
||||||
|
variable_exists ):
|
||||||
|
|
||||||
|
# This test is the same as ReplaceChunks_SingleFile_NotOpen_test, but we pass
|
||||||
|
# the silent flag, as used by post-complete actions, and shows the stuff we
|
||||||
|
# _don't_ call in that case.
|
||||||
|
|
||||||
|
single_buffer_name = os.path.realpath( 'single_file' )
|
||||||
|
|
||||||
|
chunks = [
|
||||||
|
_BuildChunk( 1, 1, 2, 1, 'replacement', single_buffer_name )
|
||||||
|
]
|
||||||
|
|
||||||
|
result_buffer = VimBuffer(
|
||||||
|
single_buffer_name,
|
||||||
|
contents = [
|
||||||
|
'line1',
|
||||||
|
'line2',
|
||||||
|
'line3'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch( 'vim.buffers', [ None, result_buffer, None ] ):
|
||||||
|
vimsupport.ReplaceChunks( chunks, silent=True )
|
||||||
|
|
||||||
|
# We didn't check if it was OK to open the file (silent)
|
||||||
|
confirm.assert_not_called()
|
||||||
|
|
||||||
|
# Ensure that we applied the replacement correctly
|
||||||
|
eq_( result_buffer.GetLines(), [
|
||||||
|
'replacementline2',
|
||||||
|
'line3',
|
||||||
|
] )
|
||||||
|
|
||||||
|
# GetBufferNumberForFilename is called 2 times. The return values are set in
|
||||||
|
# the @patch call above:
|
||||||
|
# - once whilst applying the changes (-1 return)
|
||||||
|
# - finally after calling OpenFilename (1 return)
|
||||||
|
get_buffer_number_for_filename.assert_has_exact_calls( [
|
||||||
|
call( single_buffer_name ),
|
||||||
|
call( single_buffer_name ),
|
||||||
|
] )
|
||||||
|
|
||||||
|
# BufferIsVisible is called 2 times for the same reasons as above, with the
|
||||||
|
# return of each one
|
||||||
|
buffer_is_visible.assert_has_exact_calls( [
|
||||||
|
call( -1 ),
|
||||||
|
call( 1 ),
|
||||||
|
] )
|
||||||
|
|
||||||
|
# We open 'single_file' as expected.
|
||||||
|
open_filename.assert_called_with( single_buffer_name, {
|
||||||
|
'focus': True,
|
||||||
|
'fix': True,
|
||||||
|
'size': 10
|
||||||
|
} )
|
||||||
|
|
||||||
|
# And close it again, but don't show the quickfix window
|
||||||
|
vim_command.assert_has_exact_calls( [
|
||||||
|
call( 'lclose' ),
|
||||||
|
call( 'hide' ),
|
||||||
|
] )
|
||||||
|
set_fitting_height.assert_not_called()
|
||||||
|
|
||||||
|
# But we _don't_ update the QuickFix list
|
||||||
|
vim_eval.assert_has_exact_calls( [
|
||||||
|
call( '&previewheight' ),
|
||||||
|
] )
|
||||||
|
|
||||||
|
# And we don't print a message either
|
||||||
|
post_vim_message.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
|
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
|
||||||
side_effect = [ -1, -1, 1 ],
|
side_effect = [ -1, -1, 1 ],
|
||||||
new_callable = ExtendedMock )
|
new_callable = ExtendedMock )
|
||||||
|
@ -735,7 +735,7 @@ def _OpenFileInSplitIfNeeded( filepath ):
|
|||||||
return ( buffer_num, True )
|
return ( buffer_num, True )
|
||||||
|
|
||||||
|
|
||||||
def ReplaceChunks( chunks ):
|
def ReplaceChunks( chunks, silent=False ):
|
||||||
"""Apply the source file deltas supplied in |chunks| to arbitrary files.
|
"""Apply the source file deltas supplied in |chunks| to arbitrary files.
|
||||||
|chunks| is a list of changes defined by ycmd.responses.FixItChunk,
|
|chunks| is a list of changes defined by ycmd.responses.FixItChunk,
|
||||||
which may apply arbitrary modifications to arbitrary files.
|
which may apply arbitrary modifications to arbitrary files.
|
||||||
@ -755,6 +755,7 @@ def ReplaceChunks( chunks ):
|
|||||||
# We sort the file list simply to enable repeatable testing.
|
# We sort the file list simply to enable repeatable testing.
|
||||||
sorted_file_list = sorted( iterkeys( chunks_by_file ) )
|
sorted_file_list = sorted( iterkeys( chunks_by_file ) )
|
||||||
|
|
||||||
|
if not silent:
|
||||||
# Make sure the user is prepared to have her screen mutilated by the new
|
# Make sure the user is prepared to have her screen mutilated by the new
|
||||||
# buffers.
|
# buffers.
|
||||||
num_files_to_open = _GetNumNonVisibleFiles( sorted_file_list )
|
num_files_to_open = _GetNumNonVisibleFiles( sorted_file_list )
|
||||||
@ -788,6 +789,7 @@ def ReplaceChunks( chunks ):
|
|||||||
vim.command( 'hide' )
|
vim.command( 'hide' )
|
||||||
|
|
||||||
# Open the quickfix list, populated with entries for each location we changed.
|
# Open the quickfix list, populated with entries for each location we changed.
|
||||||
|
if not silent:
|
||||||
if locations:
|
if locations:
|
||||||
SetQuickFixList( locations )
|
SetQuickFixList( locations )
|
||||||
OpenQuickFixList()
|
OpenQuickFixList()
|
||||||
|
@ -108,6 +108,15 @@ SERVER_LOGFILE_FORMAT = 'ycmd_{port}_{std}_'
|
|||||||
HANDLE_FLAG_INHERIT = 0x00000001
|
HANDLE_FLAG_INHERIT = 0x00000001
|
||||||
|
|
||||||
|
|
||||||
|
# The following two methods exist for testability only
|
||||||
|
def _CompleteDoneHook_CSharp( ycm ):
|
||||||
|
ycm._OnCompleteDone_Csharp()
|
||||||
|
|
||||||
|
|
||||||
|
def _CompleteDoneHook_Java( ycm ):
|
||||||
|
ycm._OnCompleteDone_Java()
|
||||||
|
|
||||||
|
|
||||||
class YouCompleteMe( object ):
|
class YouCompleteMe( object ):
|
||||||
def __init__( self, user_options ):
|
def __init__( self, user_options ):
|
||||||
self._available_completers = {}
|
self._available_completers = {}
|
||||||
@ -128,7 +137,8 @@ class YouCompleteMe( object ):
|
|||||||
self._SetUpServer()
|
self._SetUpServer()
|
||||||
self._ycmd_keepalive.Start()
|
self._ycmd_keepalive.Start()
|
||||||
self._complete_done_hooks = {
|
self._complete_done_hooks = {
|
||||||
'cs': lambda self: self._OnCompleteDone_Csharp()
|
'cs': _CompleteDoneHook_CSharp,
|
||||||
|
'java': _CompleteDoneHook_Java,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -491,42 +501,63 @@ class YouCompleteMe( object ):
|
|||||||
if not latest_completion_request or not latest_completion_request.Done():
|
if not latest_completion_request or not latest_completion_request.Done():
|
||||||
return []
|
return []
|
||||||
|
|
||||||
completions = latest_completion_request.RawResponse()
|
completed_item = vimsupport.GetVariableValue( 'v:completed_item' )
|
||||||
|
completions = latest_completion_request.RawResponse()[ 'completions' ]
|
||||||
|
|
||||||
result = self._FilterToMatchingCompletions( completions, True )
|
if 'user_data' in completed_item and completed_item[ 'user_data' ] != '':
|
||||||
|
# Vim supports user_data (8.0.1493) or later, so we actually know the
|
||||||
|
# _exact_ element that was selected, having put its index in the user_data
|
||||||
|
# field.
|
||||||
|
return [ completions[ int( completed_item[ 'user_data' ] ) ] ]
|
||||||
|
|
||||||
|
# Otherwise, we have to guess by matching the values in the completed item
|
||||||
|
# and the list of completions. Sometimes this returns multiple
|
||||||
|
# possibilities, which is essentially unresolvable.
|
||||||
|
|
||||||
|
result = self._FilterToMatchingCompletions( completed_item,
|
||||||
|
completions,
|
||||||
|
True )
|
||||||
result = list( result )
|
result = list( result )
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if self._HasCompletionsThatCouldBeCompletedWithMoreText( completions ):
|
if self._HasCompletionsThatCouldBeCompletedWithMoreText( completed_item,
|
||||||
|
completions ):
|
||||||
# Since the way that YCM works leads to CompleteDone called on every
|
# Since the way that YCM works leads to CompleteDone called on every
|
||||||
# character, return blank if the completion might not be done. This won't
|
# character, return blank if the completion might not be done. This won't
|
||||||
# match if the completion is ended with typing a non-keyword character.
|
# match if the completion is ended with typing a non-keyword character.
|
||||||
return []
|
return []
|
||||||
|
|
||||||
result = self._FilterToMatchingCompletions( completions, False )
|
result = self._FilterToMatchingCompletions( completed_item,
|
||||||
|
completions,
|
||||||
|
False )
|
||||||
|
|
||||||
return list( result )
|
return list( result )
|
||||||
|
|
||||||
|
|
||||||
def _FilterToMatchingCompletions( self, completions, full_match_only ):
|
def _FilterToMatchingCompletions( self,
|
||||||
|
completed_item,
|
||||||
|
completions,
|
||||||
|
full_match_only ):
|
||||||
"""Filter to completions matching the item Vim said was completed"""
|
"""Filter to completions matching the item Vim said was completed"""
|
||||||
completed = vimsupport.GetVariableValue( 'v:completed_item' )
|
|
||||||
for completion in completions:
|
|
||||||
item = ConvertCompletionDataToVimData( completion )
|
|
||||||
match_keys = ( [ "word", "abbr", "menu", "info" ] if full_match_only
|
match_keys = ( [ "word", "abbr", "menu", "info" ] if full_match_only
|
||||||
else [ 'word' ] )
|
else [ 'word' ] )
|
||||||
|
|
||||||
|
for index, completion in enumerate( completions ):
|
||||||
|
item = ConvertCompletionDataToVimData( index, completion )
|
||||||
|
|
||||||
def matcher( key ):
|
def matcher( key ):
|
||||||
return ( utils.ToUnicode( completed.get( key, "" ) ) ==
|
return ( utils.ToUnicode( completed_item.get( key, "" ) ) ==
|
||||||
utils.ToUnicode( item.get( key, "" ) ) )
|
utils.ToUnicode( item.get( key, "" ) ) )
|
||||||
|
|
||||||
if all( [ matcher( i ) for i in match_keys ] ):
|
if all( [ matcher( i ) for i in match_keys ] ):
|
||||||
yield completion
|
yield completion
|
||||||
|
|
||||||
|
|
||||||
def _HasCompletionsThatCouldBeCompletedWithMoreText( self, completions ):
|
def _HasCompletionsThatCouldBeCompletedWithMoreText( self,
|
||||||
completed_item = vimsupport.GetVariableValue( 'v:completed_item' )
|
completed_item,
|
||||||
|
completions ):
|
||||||
if not completed_item:
|
if not completed_item:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -542,9 +573,9 @@ class YouCompleteMe( object ):
|
|||||||
reject_exact_match = False
|
reject_exact_match = False
|
||||||
completed_word += text[ -1 ]
|
completed_word += text[ -1 ]
|
||||||
|
|
||||||
for completion in completions:
|
for index, completion in enumerate( completions ):
|
||||||
word = utils.ToUnicode(
|
word = utils.ToUnicode(
|
||||||
ConvertCompletionDataToVimData( completion )[ 'word' ] )
|
ConvertCompletionDataToVimData( index, completion )[ 'word' ] )
|
||||||
if reject_exact_match and word == completed_word:
|
if reject_exact_match and word == completed_word:
|
||||||
continue
|
continue
|
||||||
if word.startswith( completed_word ):
|
if word.startswith( completed_word ):
|
||||||
@ -580,6 +611,33 @@ class YouCompleteMe( object ):
|
|||||||
return completion[ "extra_data" ][ "required_namespace_import" ]
|
return completion[ "extra_data" ][ "required_namespace_import" ]
|
||||||
|
|
||||||
|
|
||||||
|
def _OnCompleteDone_Java( self ):
|
||||||
|
completions = self.GetCompletionsUserMayHaveCompleted()
|
||||||
|
fixit_completions = [ self._GetFixItCompletion( c ) for c in completions ]
|
||||||
|
fixit_completions = [ f for f in fixit_completions if f ]
|
||||||
|
if not fixit_completions:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If we have user_data in completions (8.0.1493 or later), then we would
|
||||||
|
# only ever return max. 1 completion here. However, if we had to guess, it
|
||||||
|
# is possible that we matched multiple completion items (e.g. for overloads,
|
||||||
|
# or similar classes in multiple packages). In any case, rather than
|
||||||
|
# prompting the user and disturbing her workflow, we just apply the first
|
||||||
|
# one. This might be wrong, but the solution is to use a (very) new version
|
||||||
|
# of Vim which supports user_data on completion items
|
||||||
|
fixit_completion = fixit_completions[ 0 ]
|
||||||
|
|
||||||
|
for fixit in fixit_completion:
|
||||||
|
vimsupport.ReplaceChunks( fixit[ 'chunks' ], silent=True )
|
||||||
|
|
||||||
|
|
||||||
|
def _GetFixItCompletion( self, completion ):
|
||||||
|
if ( "extra_data" not in completion
|
||||||
|
or "fixits" not in completion[ "extra_data" ] ):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return completion[ "extra_data" ][ "fixits" ]
|
||||||
|
|
||||||
def GetErrorCount( self ):
|
def GetErrorCount( self ):
|
||||||
return self.CurrentBuffer().GetErrorCount()
|
return self.CurrentBuffer().GetErrorCount()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user