Auto merge of #2707 - micbou:fix-omnifunc-cursor-move, r=bstaletic

[READY] Restore cursor position after omnifunc call

When compiled without C-family support, YCM will use the default omnifunc from Vim (`ccomplete#Complete`) to provide semantic completion. This omnifunc calls [`searchdecl`](http://vimdoc.sourceforge.net/htmldoc/eval.html#searchdecl()) to find a declaration, which is supposed to move the cursor to that declaration. However, the cursor is not moved when called through the omni completion mapping (`CTRL-X CTRL-O`). Since PR https://github.com/Valloric/YouCompleteMe/pull/2657, YCM calls the omnifunc outside completion mode and thus the cursor is moved to the found declaration after typing `.` or `->`.

Considering this `searchdecl` trick may be used by other omnifuncs, we fix the issue by always restoring the cursor position after calling the omnifunc.

Fixes #2698.

<!-- 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/2707)
<!-- Reviewable:end -->
This commit is contained in:
zzbot 2017-07-07 06:29:34 -07:00 committed by GitHub
commit d299f9eb70
3 changed files with 53 additions and 1 deletions

View File

@ -90,13 +90,22 @@ class OmniCompleter( Completer ):
# because it affects the value returned by 'query'
request_data[ 'start_column' ] = return_value + 1
# Calling directly the omnifunc may move the cursor position. This is the
# case with the default Vim omnifunc for C-family languages
# (ccomplete#Complete) which calls searchdecl to find a declaration. This
# function is supposed to move the cursor to the found declaration but it
# doesn't when called through the omni completion mapping (CTRL-X CTRL-O).
# So, we restore the cursor position after calling the omnifunc.
line, column = vimsupport.CurrentLineAndColumn()
omnifunc_call = [ self._omnifunc,
"(0,'",
vimsupport.EscapeForVim( request_data[ 'query' ] ),
"')" ]
items = vim.eval( ''.join( omnifunc_call ) )
vimsupport.SetCurrentLineAndColumn( line, column )
if isinstance( items, dict ) and 'words' in items:
items = items[ 'words' ]

View File

@ -30,6 +30,7 @@ from ycm.tests.test_utils import ( ExpectedFailure, MockVimBuffers,
MockVimModule, ToBytesOnPY2, VimBuffer )
MockVimModule()
from ycm import vimsupport
from ycm.tests import YouCompleteMeInstance
@ -621,3 +622,39 @@ def OmniCompleter_GetCompletions_Cache_ObjectListObject_Unicode_test( ycm ):
'completion_start_column': 13
} )
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1 } )
def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test(
ycm ):
# This omnifunc moves the cursor to the test definition like
# ccomplete#Complete would.
def Omnifunc( findstart, base ):
if findstart:
return 5
vimsupport.SetCurrentLineAndColumn( 0, 0 )
return [ 'length' ]
current_buffer = VimBuffer( 'buffer',
contents = [ 'String test',
'',
'test.' ],
filetype = 'java',
omnifunc = Omnifunc )
with MockVimBuffers( [ current_buffer ], current_buffer, ( 3, 5 ) ):
# Make sure there is an omnifunc set up.
ycm.OnFileReadyToParse()
ycm.SendCompletionRequest()
assert_that(
vimsupport.CurrentLineAndColumn(),
contains( 2, 5 )
)
assert_that(
ycm.GetCompletionResponse(),
has_entries( {
'completions': ToBytesOnPY2( [ 'length' ] ),
'completion_start_column': 6
} )
)

View File

@ -56,6 +56,12 @@ def CurrentLineAndColumn():
return line, column
def SetCurrentLineAndColumn( line, column ):
"""Sets the cursor position to the 0-based line and 0-based column."""
# Line from vim.current.window.cursor is 1-based.
vim.current.window.cursor = ( line + 1, column )
def CurrentColumn():
"""Returns the 0-based current column. Do NOT access the CurrentColumn in
vim.current.line. It doesn't exist yet when the cursor is at the end of the