Skip to content

Commit

Permalink
Auto merge of #2707 - micbou:fix-omnifunc-cursor-move, r=bstaletic
Browse files Browse the repository at this point in the history
[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 #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 -->
  • Loading branch information
zzbot authored Jul 7, 2017
2 parents c9be11a + dec9c0f commit d299f9e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
11 changes: 10 additions & 1 deletion python/ycm/omni_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,22 @@ def ComputeCandidatesInner( self, request_data ):
# 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' ]

Expand Down
37 changes: 37 additions & 0 deletions python/ycm/tests/omni_completer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
MockVimModule, ToBytesOnPY2, VimBuffer )
MockVimModule()

from ycm import vimsupport
from ycm.tests import YouCompleteMeInstance


Expand Down Expand Up @@ -621,3 +622,39 @@ def Omnifunc( findstart, base ):
'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
} )
)
6 changes: 6 additions & 0 deletions python/ycm/vimsupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d299f9e

Please sign in to comment.