Auto merge of #3091 - micbou:completer-command-mods, r=Valloric
[READY] Support modifiers for GoTo commands This PR allows users to customize how a window is split when running the `GoTo*` commands by prefixing them with the modifiers `:aboveleft`, `:belowright`, `:botright`, etc. (see `:h mods` for the complete list). For instance, to split a window vertically at the right of the screen, one could do: ```viml :botright vertical YcmCompleter GoTo ``` The `'horizontal-split'` and `'vertical-split'` values of the `g:ycm_goto_buffer_command` option are replaced by `'split'` since a vertical split can be obtained by prefixing the `:vertical` modifier. Those values are still kept for backward compatibility. A new value is added `'split-or-existing-window'` that is equivalent to `new-or-existing-tab` when the `:tab` modifier is used. Without the `:tab` modifier, the `GoTo*` commands only jump to an existing window if that window is in the current tab page. Closes https://github.com/Valloric/YouCompleteMe/pull/3090. <!-- 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/3091) <!-- Reviewable:end -->
This commit is contained in:
commit
1e9c59abfa
27
README.md
27
README.md
@ -2896,13 +2896,30 @@ let g:ycm_use_ultisnips_completer = 1
|
||||
|
||||
### The `g:ycm_goto_buffer_command` option
|
||||
|
||||
Defines where `GoTo*` commands result should be opened.
|
||||
Can take one of the following values:
|
||||
`[ 'same-buffer', 'horizontal-split', 'vertical-split', 'new-tab',
|
||||
'new-or-existing-tab' ]`
|
||||
Defines where `GoTo*` commands result should be opened. Can take one of the
|
||||
following values:
|
||||
`[ 'same-buffer', 'split', 'split-or-existing-window' ]`
|
||||
If this option is set to the `'same-buffer'` but current buffer can not
|
||||
be switched (when buffer is modified and `nohidden` option is set),
|
||||
then result will be opened in horizontal split.
|
||||
then result will be opened in a split. When the option is set to
|
||||
`'split-or-existing-window'`, if the result is already open in a window of the
|
||||
current tab page (or any tab pages with the `:tab` modifier; see below), it
|
||||
will jump to that window. Otherwise, the result will be opened in a split as if
|
||||
the option was set to `'split'`.
|
||||
|
||||
To customize the way a new window is split, prefix the `GoTo*` command with one
|
||||
of the following modifiers: `:aboveleft`, `:belowright`, `:botright`,
|
||||
`:leftabove`, `:rightbelow`, `:topleft`, and `:vertical`. For instance, to
|
||||
split vertically to the right of the current window, run the command:
|
||||
```viml
|
||||
:rightbelow vertical YcmCompleter GoTo
|
||||
```
|
||||
|
||||
To open in a new tab page, use the `:tab` modifier with the `'split'` or
|
||||
`'split-or-existing-window'` options e.g.:
|
||||
```viml
|
||||
:tab YcmCompleter GoTo
|
||||
```
|
||||
|
||||
Default: `'same-buffer'`
|
||||
|
||||
|
@ -845,7 +845,8 @@ function! s:SetUpCommands()
|
||||
command! -nargs=* -complete=custom,youcompleteme#LogsComplete
|
||||
\ YcmToggleLogs call s:ToggleLogs(<f-args>)
|
||||
command! -nargs=* -complete=custom,youcompleteme#SubCommandsComplete -range
|
||||
\ YcmCompleter call s:CompleterCommand(<count>,
|
||||
\ YcmCompleter call s:CompleterCommand(<q-mods>,
|
||||
\ <count>,
|
||||
\ <line1>,
|
||||
\ <line2>,
|
||||
\ <f-args>)
|
||||
@ -889,7 +890,7 @@ function! youcompleteme#LogsComplete( arglead, cmdline, cursorpos )
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:CompleterCommand( count, line1, line2, ... )
|
||||
function! s:CompleterCommand( mods, count, line1, line2, ... )
|
||||
" CompleterCommand will call the OnUserCommand function of a completer. If
|
||||
" the first arguments is of the form "ft=..." it can be used to specify the
|
||||
" completer to use (for example "ft=cpp"). Else the native filetype completer
|
||||
@ -910,6 +911,7 @@ function! s:CompleterCommand( count, line1, line2, ... )
|
||||
exec s:python_command "ycm_state.SendCommandRequest(" .
|
||||
\ "vim.eval( 'l:arguments' )," .
|
||||
\ "vim.eval( 'l:completer' )," .
|
||||
\ "vim.eval( 'a:mods' )," .
|
||||
\ "vimsupport.GetBoolValue( 'a:count != -1' )," .
|
||||
\ "vimsupport.GetIntValue( 'a:line1' )," .
|
||||
\ "vimsupport.GetIntValue( 'a:line2' ) )"
|
||||
|
@ -3133,11 +3133,27 @@ Default: '1'
|
||||
The *g:ycm_goto_buffer_command* option
|
||||
|
||||
Defines where 'GoTo*' commands result should be opened. Can take one of the
|
||||
following values: "[ 'same-buffer', 'horizontal-split', 'vertical-split', 'new-
|
||||
tab', 'new-or-existing-tab' ]" If this option is set to the "'same-buffer'" but
|
||||
current buffer can not be switched (when buffer is modified and 'nohidden'
|
||||
option is set), then result will be opened in horizontal split.
|
||||
following values: "[ 'same-buffer', 'split', 'split-or-existing-window' ]" If
|
||||
this option is set to the "'same-buffer'" but current buffer can not be
|
||||
switched (when buffer is modified and 'nohidden' option is set), then result
|
||||
will be opened in a split. When the option is set to "'split-or-existing-
|
||||
window'", if the result is already open in a window of the current tab page (or
|
||||
any tab pages with the ':tab' modifier; see below), it will jump to that
|
||||
window. Otherwise, the result will be opened in a split as if the option was
|
||||
set to "'split'".
|
||||
|
||||
To customize the way a new window is split, prefix the 'GoTo*' command with one
|
||||
of the following modifiers: ':aboveleft', ':belowright', ':botright',
|
||||
':leftabove', ':rightbelow', ':topleft', and ':vertical'. For instance, to
|
||||
split vertically to the right of the current window, run the command:
|
||||
>
|
||||
:rightbelow vertical YcmCompleter GoTo
|
||||
<
|
||||
To open in a new tab page, use the ':tab' modifier with the "'split'" or
|
||||
"'split-or-existing-window'" options e.g.:
|
||||
>
|
||||
:tab YcmCompleter GoTo
|
||||
<
|
||||
Default: "'same-buffer'"
|
||||
>
|
||||
let g:ycm_goto_buffer_command = 'same-buffer'
|
||||
|
@ -60,7 +60,7 @@ class CommandRequest( BaseRequest ):
|
||||
return self._response
|
||||
|
||||
|
||||
def RunPostCommandActionsIfNeeded( self ):
|
||||
def RunPostCommandActionsIfNeeded( self, modifiers ):
|
||||
if not self.Done() or self._response is None:
|
||||
return
|
||||
|
||||
@ -82,10 +82,10 @@ class CommandRequest( BaseRequest ):
|
||||
# The only other type of response we understand is GoTo, and that is the
|
||||
# only one that we can't detect just by inspecting the response (it should
|
||||
# either be a single location or a list)
|
||||
return self._HandleGotoResponse()
|
||||
return self._HandleGotoResponse( modifiers )
|
||||
|
||||
|
||||
def _HandleGotoResponse( self ):
|
||||
def _HandleGotoResponse( self, modifiers ):
|
||||
if isinstance( self._response, list ):
|
||||
vimsupport.SetQuickFixList(
|
||||
[ _BuildQfListItem( x ) for x in self._response ] )
|
||||
@ -93,7 +93,8 @@ class CommandRequest( BaseRequest ):
|
||||
else:
|
||||
vimsupport.JumpToLocation( self._response[ 'filepath' ],
|
||||
self._response[ 'line_num' ],
|
||||
self._response[ 'column_num' ] )
|
||||
self._response[ 'column_num' ],
|
||||
modifiers )
|
||||
|
||||
|
||||
def _HandleFixitResponse( self ):
|
||||
@ -131,11 +132,11 @@ class CommandRequest( BaseRequest ):
|
||||
vimsupport.WriteToPreviewWindow( self._response[ 'detailed_info' ] )
|
||||
|
||||
|
||||
def SendCommandRequest( arguments, completer, extra_data = None ):
|
||||
def SendCommandRequest( arguments, completer, modifiers, extra_data = None ):
|
||||
request = CommandRequest( arguments, completer, extra_data )
|
||||
# This is a blocking call.
|
||||
request.Start()
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( modifiers )
|
||||
return request.Response()
|
||||
|
||||
|
||||
|
@ -100,7 +100,7 @@ class GoToResponse_QuickFix_test( object ):
|
||||
variable_exists ):
|
||||
self._request._response = completer_response
|
||||
|
||||
self._request.RunPostCommandActionsIfNeeded()
|
||||
self._request.RunPostCommandActionsIfNeeded( 'aboveleft' )
|
||||
|
||||
vim_eval.assert_has_exact_calls( [
|
||||
call( 'setqflist( {0} )'.format( json.dumps( expected_qf_list ) ) )
|
||||
@ -120,7 +120,7 @@ class Response_Detection_test( object ):
|
||||
with patch( 'vim.command' ) as vim_command:
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = response
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'belowright' )
|
||||
vim_command.assert_called_with( "echo '{0}'".format( response ) )
|
||||
|
||||
tests = [
|
||||
@ -144,7 +144,7 @@ class Response_Detection_test( object ):
|
||||
request._response = {
|
||||
'fixits': []
|
||||
}
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'botright' )
|
||||
|
||||
post_vim_message.assert_called_with(
|
||||
'No fixits found for current line', warning = False )
|
||||
@ -163,7 +163,7 @@ class Response_Detection_test( object ):
|
||||
return_value = selection ):
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = response
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'leftabove' )
|
||||
|
||||
replace_chunks.assert_called_with( chunks, silent = silent )
|
||||
post_vim_message.assert_not_called()
|
||||
@ -222,7 +222,7 @@ class Response_Detection_test( object ):
|
||||
with patch( 'ycm.vimsupport.PostVimMessage' ) as post_vim_message:
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = { 'message': message }
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'rightbelow' )
|
||||
post_vim_message.assert_called_with( message, warning = False )
|
||||
|
||||
tests = [
|
||||
@ -243,7 +243,7 @@ class Response_Detection_test( object ):
|
||||
with patch( 'ycm.vimsupport.WriteToPreviewWindow' ) as write_to_preview:
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = { 'detailed_info': info }
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'topleft' )
|
||||
write_to_preview.assert_called_with( info )
|
||||
|
||||
tests = [
|
||||
@ -263,11 +263,12 @@ class Response_Detection_test( object ):
|
||||
with patch( 'ycm.vimsupport.JumpToLocation' ) as jump_to_location:
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = response
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'rightbelow' )
|
||||
jump_to_location.assert_called_with(
|
||||
response[ 'filepath' ],
|
||||
response[ 'line_num' ],
|
||||
response[ 'column_num' ] )
|
||||
response[ 'column_num' ],
|
||||
'rightbelow' )
|
||||
|
||||
def GoToListTest( command, response ):
|
||||
# Note: the detail of these called are tested by
|
||||
@ -277,7 +278,7 @@ class Response_Detection_test( object ):
|
||||
with patch( 'ycm.vimsupport.OpenQuickFixList' ) as open_qf_list:
|
||||
request = CommandRequest( [ command ] )
|
||||
request._response = response
|
||||
request.RunPostCommandActionsIfNeeded()
|
||||
request.RunPostCommandActionsIfNeeded( 'tab' )
|
||||
ok_( set_qf_list.called )
|
||||
ok_( open_qf_list.called )
|
||||
|
||||
|
@ -36,13 +36,14 @@ def SendCommandRequest_ExtraConfVimData_Works_test( ycm ):
|
||||
current_buffer = VimBuffer( 'buffer' )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', False, 1, 1 )
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', 'aboveleft', False, 1, 1 )
|
||||
assert_that(
|
||||
# Positional arguments passed to SendCommandRequest.
|
||||
send_request.call_args[ 0 ],
|
||||
contains(
|
||||
contains( 'GoTo' ),
|
||||
'python',
|
||||
'aboveleft',
|
||||
has_entries( {
|
||||
'options': has_entries( {
|
||||
'tab_size': 2,
|
||||
@ -61,13 +62,14 @@ def SendCommandRequest_ExtraConfData_UndefinedValue_test( ycm ):
|
||||
current_buffer = VimBuffer( 'buffer' )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', False, 1, 1 )
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', 'belowright', False, 1, 1 )
|
||||
assert_that(
|
||||
# Positional arguments passed to SendCommandRequest.
|
||||
send_request.call_args[ 0 ],
|
||||
contains(
|
||||
contains( 'GoTo' ),
|
||||
'python',
|
||||
'belowright',
|
||||
has_entries( {
|
||||
'options': has_entries( {
|
||||
'tab_size': 2,
|
||||
@ -84,10 +86,11 @@ def SendCommandRequest_BuildRange_NoVisualMarks_test( ycm, *args ):
|
||||
'second line' ] )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', True, 1, 2 )
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', '', True, 1, 2 )
|
||||
send_request.assert_called_once_with(
|
||||
[ 'GoTo' ],
|
||||
'python',
|
||||
'',
|
||||
{
|
||||
'options': {
|
||||
'tab_size': 2,
|
||||
@ -116,10 +119,11 @@ def SendCommandRequest_BuildRange_VisualMarks_test( ycm, *args ):
|
||||
visual_end = [ 2, 8 ] )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', True, 1, 2 )
|
||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python', 'tab', True, 1, 2 )
|
||||
send_request.assert_called_once_with(
|
||||
[ 'GoTo' ],
|
||||
'python',
|
||||
'tab',
|
||||
{
|
||||
'options': {
|
||||
'tab_size': 2,
|
||||
|
@ -1619,7 +1619,10 @@ def JumpToLocation_SameFile_SameBuffer_NoSwapFile_test( vim_command ):
|
||||
# bytes on Python 2 but unicode on Python 3.
|
||||
current_buffer = VimBuffer( 'uni¢𐍈d€' )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim:
|
||||
vimsupport.JumpToLocation( os.path.realpath( u'uni¢𐍈d€' ), 2, 5 )
|
||||
vimsupport.JumpToLocation( os.path.realpath( u'uni¢𐍈d€' ),
|
||||
2,
|
||||
5,
|
||||
'aboveleft' )
|
||||
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
@ -1636,12 +1639,12 @@ def JumpToLocation_DifferentFile_SameBuffer_Unmodified_test( vim_command ):
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim:
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'belowright' )
|
||||
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps edit {0}'.format( target_name ) ),
|
||||
call( u'keepjumps belowright edit {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
@ -1656,12 +1659,12 @@ def JumpToLocation_DifferentFile_SameBuffer_Modified_CannotHide_test(
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim:
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'botright' )
|
||||
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps split {0}'.format( target_name ) ),
|
||||
call( u'keepjumps botright split {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
@ -1676,12 +1679,12 @@ def JumpToLocation_DifferentFile_SameBuffer_Modified_CanHide_test(
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim:
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'leftabove' )
|
||||
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps edit {0}'.format( target_name ) ),
|
||||
call( u'keepjumps leftabove edit {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
@ -1697,7 +1700,7 @@ def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Unexpected_test(
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
assert_that(
|
||||
calling( vimsupport.JumpToLocation ).with_args(
|
||||
os.path.realpath( u'different_uni¢𐍈d€' ), 2, 5 ),
|
||||
os.path.realpath( u'different_uni¢𐍈d€' ), 2, 5, 'rightbelow' ),
|
||||
raises( VimError, 'Unknown code' )
|
||||
)
|
||||
|
||||
@ -1712,11 +1715,11 @@ def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Quit_test( vim_command ):
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'topleft' )
|
||||
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps edit {0}'.format( target_name ) )
|
||||
call( u'keepjumps topleft edit {0}'.format( target_name ) )
|
||||
] )
|
||||
|
||||
|
||||
@ -1730,11 +1733,106 @@ def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Abort_test( vim_command ):
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'vertical' )
|
||||
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps edit {0}'.format( target_name ) )
|
||||
call( u'keepjumps vertical edit {0}'.format( target_name ) )
|
||||
] )
|
||||
|
||||
|
||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||
{ 'goto_buffer_command': 'split-or-existing-window' } )
|
||||
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||
def JumpToLocation_DifferentFile_Split_CurrentTab_NotAlreadyOpened_test(
|
||||
vim_command ):
|
||||
|
||||
current_buffer = VimBuffer( 'uni¢𐍈d€' )
|
||||
current_window = MagicMock( buffer = current_buffer )
|
||||
current_tab = MagicMock( windows = [ current_window ] )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim:
|
||||
vim.current.tabpage = current_tab
|
||||
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'aboveleft' )
|
||||
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps aboveleft split {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
|
||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||
{ 'goto_buffer_command': 'split-or-existing-window' } )
|
||||
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||
def JumpToLocation_DifferentFile_Split_CurrentTab_AlreadyOpened_test(
|
||||
vim_command ):
|
||||
|
||||
current_buffer = VimBuffer( 'uni¢𐍈d€' )
|
||||
different_buffer = VimBuffer( 'different_uni¢𐍈d€' )
|
||||
current_window = MagicMock( buffer = current_buffer )
|
||||
different_window = MagicMock( buffer = different_buffer )
|
||||
current_tab = MagicMock( windows = [ current_window, different_window ] )
|
||||
with MockVimBuffers( [ current_buffer, different_buffer ],
|
||||
[ current_buffer ] ) as vim:
|
||||
vim.current.tabpage = current_tab
|
||||
|
||||
vimsupport.JumpToLocation( os.path.realpath( u'different_uni¢𐍈d€' ),
|
||||
2, 5, 'belowright' )
|
||||
|
||||
assert_that( vim.current.tabpage, equal_to( current_tab ) )
|
||||
assert_that( vim.current.window, equal_to( different_window ) )
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
|
||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||
{ 'goto_buffer_command': 'split-or-existing-window' } )
|
||||
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||
def JumpToLocation_DifferentFile_Split_AllTabs_NotAlreadyOpened_test(
|
||||
vim_command ):
|
||||
|
||||
current_buffer = VimBuffer( 'uni¢𐍈d€' )
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'tab' )
|
||||
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps tab split {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
|
||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||
{ 'goto_buffer_command': 'split-or-existing-window' } )
|
||||
@patch( 'vim.command', new_callable = ExtendedMock )
|
||||
def JumpToLocation_DifferentFile_Split_AllTabs_AlreadyOpened_test(
|
||||
vim_command ):
|
||||
|
||||
current_buffer = VimBuffer( 'uni¢𐍈d€' )
|
||||
different_buffer = VimBuffer( 'different_uni¢𐍈d€' )
|
||||
current_window = MagicMock( buffer = current_buffer )
|
||||
different_window = MagicMock( buffer = different_buffer )
|
||||
current_tab = MagicMock( windows = [ current_window, different_window ] )
|
||||
with patch( 'vim.tabpages', [ current_tab ] ):
|
||||
with MockVimBuffers( [ current_buffer, different_buffer ],
|
||||
[ current_buffer ] ) as vim:
|
||||
vimsupport.JumpToLocation( os.path.realpath( u'different_uni¢𐍈d€' ),
|
||||
2, 5, 'tab' )
|
||||
|
||||
assert_that( vim.current.tabpage, equal_to( current_tab ) )
|
||||
assert_that( vim.current.window, equal_to( different_window ) )
|
||||
assert_that( vim.current.window.cursor, equal_to( ( 2, 4 ) ) )
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
|
||||
@ -1748,11 +1846,11 @@ def JumpToLocation_DifferentFile_NewOrExistingTab_NotAlreadyOpened_test(
|
||||
with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
|
||||
target_name = os.path.realpath( u'different_uni¢𐍈d€' )
|
||||
|
||||
vimsupport.JumpToLocation( target_name, 2, 5 )
|
||||
vimsupport.JumpToLocation( target_name, 2, 5, 'aboveleft vertical' )
|
||||
|
||||
vim_command.assert_has_exact_calls( [
|
||||
call( 'normal! m\'' ),
|
||||
call( u'keepjumps tabedit {0}'.format( target_name ) ),
|
||||
call( u'keepjumps aboveleft vertical tabedit {0}'.format( target_name ) ),
|
||||
call( 'normal! zz' )
|
||||
] )
|
||||
|
||||
@ -1772,7 +1870,7 @@ def JumpToLocation_DifferentFile_NewOrExistingTab_AlreadyOpened_test(
|
||||
with MockVimBuffers( [ current_buffer, different_buffer ],
|
||||
[ current_buffer ] ) as vim:
|
||||
vimsupport.JumpToLocation( os.path.realpath( u'different_uni¢𐍈d€' ),
|
||||
2, 5 )
|
||||
2, 5, 'belowright tab' )
|
||||
|
||||
assert_that( vim.current.tabpage, equal_to( current_tab ) )
|
||||
assert_that( vim.current.window, equal_to( different_window ) )
|
||||
|
@ -34,6 +34,9 @@ from ycmd.utils import ( ByteOffsetToCodepointOffset, GetCurrentDirectory,
|
||||
from ycmd import user_options_store
|
||||
|
||||
BUFFER_COMMAND_MAP = { 'same-buffer' : 'edit',
|
||||
'split' : 'split',
|
||||
# These commands are obsolete. :vertical or :tab should
|
||||
# be used with the 'split' command instead.
|
||||
'horizontal-split' : 'split',
|
||||
'vertical-split' : 'vsplit',
|
||||
'new-tab' : 'tabedit' }
|
||||
@ -439,12 +442,9 @@ def EscapeFilepathForVimCommand( filepath ):
|
||||
|
||||
|
||||
# Both |line| and |column| need to be 1-based
|
||||
def TryJumpLocationInOpenedTab( filename, line, column ):
|
||||
filepath = os.path.realpath( filename )
|
||||
|
||||
for tab in vim.tabpages:
|
||||
def TryJumpLocationInTab( tab, filename, line, column ):
|
||||
for win in tab.windows:
|
||||
if GetBufferFilepath( win.buffer ) == filepath:
|
||||
if GetBufferFilepath( win.buffer ) == filename:
|
||||
vim.current.tabpage = tab
|
||||
vim.current.window = win
|
||||
vim.current.window.cursor = ( line, column - 1 )
|
||||
@ -452,6 +452,15 @@ def TryJumpLocationInOpenedTab( filename, line, column ):
|
||||
# Center the screen on the jumped-to location
|
||||
vim.command( 'normal! zz' )
|
||||
return True
|
||||
# 'filename' is not opened in this tab page
|
||||
return False
|
||||
|
||||
|
||||
# Both |line| and |column| need to be 1-based
|
||||
def TryJumpLocationInTabs( filename, line, column ):
|
||||
for tab in vim.tabpages:
|
||||
if TryJumpLocationInTab( tab, filename, line, column ):
|
||||
return True
|
||||
# 'filename' is not opened in any tab pages
|
||||
return False
|
||||
|
||||
@ -464,8 +473,30 @@ def GetVimCommand( user_command, default = 'edit' ):
|
||||
return vim_command
|
||||
|
||||
|
||||
def JumpToFile( filename, command, modifiers ):
|
||||
vim_command = GetVimCommand( command )
|
||||
try:
|
||||
escaped_filename = EscapeFilepathForVimCommand( filename )
|
||||
vim.command( 'keepjumps {} {} {}'.format( modifiers,
|
||||
vim_command,
|
||||
escaped_filename ) )
|
||||
# When the file we are trying to jump to has a swap file
|
||||
# Vim opens swap-exists-choices dialog and throws vim.error with E325 error,
|
||||
# or KeyboardInterrupt after user selects one of the options.
|
||||
except vim.error as e:
|
||||
if 'E325' not in str( e ):
|
||||
raise
|
||||
# Do nothing if the target file is still not opened (user chose (Q)uit).
|
||||
if filename != GetCurrentBufferFilepath():
|
||||
return False
|
||||
# Thrown when user chooses (A)bort in .swp message box.
|
||||
except KeyboardInterrupt:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Both |line| and |column| need to be 1-based
|
||||
def JumpToLocation( filename, line, column ):
|
||||
def JumpToLocation( filename, line, column, modifiers ):
|
||||
# Add an entry to the jumplist
|
||||
vim.command( "normal! m'" )
|
||||
|
||||
@ -478,27 +509,24 @@ def JumpToLocation( filename, line, column ):
|
||||
# jumplist.
|
||||
user_command = user_options_store.Value( 'goto_buffer_command' )
|
||||
|
||||
if user_command == 'split-or-existing-window':
|
||||
if 'tab' in modifiers:
|
||||
if TryJumpLocationInTabs( filename, line, column ):
|
||||
return
|
||||
elif TryJumpLocationInTab( vim.current.tabpage, filename, line, column ):
|
||||
return
|
||||
user_command = 'split'
|
||||
|
||||
# This command is kept for backward compatibility. :tab should be used with
|
||||
# the 'split-or-existing-window' command instead.
|
||||
if user_command == 'new-or-existing-tab':
|
||||
if TryJumpLocationInOpenedTab( filename, line, column ):
|
||||
if TryJumpLocationInTabs( filename, line, column ):
|
||||
return
|
||||
user_command = 'new-tab'
|
||||
|
||||
vim_command = GetVimCommand( user_command )
|
||||
try:
|
||||
escaped_filename = EscapeFilepathForVimCommand( filename )
|
||||
vim.command( 'keepjumps {0} {1}'.format( vim_command, escaped_filename ) )
|
||||
# When the file we are trying to jump to has a swap file
|
||||
# Vim opens swap-exists-choices dialog and throws vim.error with E325 error,
|
||||
# or KeyboardInterrupt after user selects one of the options.
|
||||
except vim.error as e:
|
||||
if 'E325' not in str( e ):
|
||||
raise
|
||||
# Do nothing if the target file is still not opened (user chose (Q)uit)
|
||||
if filename != GetCurrentBufferFilepath():
|
||||
return
|
||||
# Thrown when user chooses (A)bort in .swp message box
|
||||
except KeyboardInterrupt:
|
||||
if not JumpToFile( filename, user_command, modifiers ):
|
||||
return
|
||||
|
||||
vim.current.window.cursor = ( line, column - 1 )
|
||||
|
||||
# Center the screen on the jumped-to location
|
||||
|
@ -322,6 +322,7 @@ class YouCompleteMe( object ):
|
||||
def SendCommandRequest( self,
|
||||
arguments,
|
||||
completer,
|
||||
modifiers,
|
||||
has_range,
|
||||
start_line,
|
||||
end_line ):
|
||||
@ -334,7 +335,7 @@ class YouCompleteMe( object ):
|
||||
if has_range:
|
||||
extra_data.update( vimsupport.BuildRange( start_line, end_line ) )
|
||||
self._AddExtraConfDataIfNeeded( extra_data )
|
||||
return SendCommandRequest( arguments, completer, extra_data )
|
||||
return SendCommandRequest( arguments, completer, modifiers, extra_data )
|
||||
|
||||
|
||||
def GetDefinedSubcommands( self ):
|
||||
|
Loading…
Reference in New Issue
Block a user