Skip to content

Commit

Permalink
Merge pull request #4146 from puremourning/fix-loclist-tabs
Browse files Browse the repository at this point in the history
Fix traceback in neovim when changin tabs; use WindowID rather than w…
  • Loading branch information
puremourning committed Apr 19, 2023
2 parents 0d387ad + f451807 commit 78ba06e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 121 deletions.
51 changes: 38 additions & 13 deletions python/ycm/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,35 @@ def pop( self, index ):
return self._buffers.pop( index )


class VimTabpages:
def __init__( self, *args ):
"""|buffers| is a list of VimBuffer objects."""
self._tabpages = []
self._tabpages.extend( args )


def __getitem__( self, number ):
"""Emulates vim.buffers[ number ]"""
for tabpage in self._tabpages:
if number == tabpage.number:
return tabpage
raise KeyError( number )


def __iter__( self ):
"""Emulates for loop on vim.buffers"""
return iter( self._tabpages )


class VimWindow:
"""An object that looks like a vim.window object:
- |number|: number of the window;
- |buffer_object|: a VimBuffer object representing the buffer inside the
window;
- |cursor|: a tuple corresponding to the cursor position."""

def __init__( self, number, buffer_object, cursor = None ):
def __init__( self, tabpage, number, buffer_object, cursor = None ):
self.tabpage = tabpage
self.number = number
self.buffer = buffer_object
self.cursor = cursor
Expand All @@ -510,31 +531,33 @@ def __repr__( self ):
f'cursor = { self.cursor } )' )


class VimWindows:
class VimTabpage:
"""An object that looks like a vim.windows object."""

def __init__( self, buffers, cursor ):
def __init__( self, number, buffers, cursor ):
"""|buffers| is a list of VimBuffer objects corresponding to the window
layout. The first element of that list is assumed to be the current window.
|cursor| is the cursor position of that window."""
windows = []
windows.append( VimWindow( 1, buffers[ 0 ], cursor ) )
self.number = number
self.windows = []
self.windows.append( VimWindow( self, 1, buffers[ 0 ], cursor ) )
for window_number in range( 1, len( buffers ) ):
windows.append( VimWindow( window_number + 1, buffers[ window_number ] ) )
self._windows = windows
self.windows.append( VimWindow( self,
window_number + 1,
buffers[ window_number ] ) )


def __getitem__( self, number ):
"""Emulates vim.windows[ number ]"""
try:
return self._windows[ number ]
return self.windows[ number ]
except IndexError:
raise IndexError( 'no such window' )


def __iter__( self ):
"""Emulates for loop on vim.windows"""
return iter( self._windows )
return iter( self.windows )


class VimCurrent:
Expand All @@ -544,6 +567,7 @@ class VimCurrent:
def __init__( self, current_window ):
self.buffer = current_window.buffer
self.window = current_window
self.tabpage = current_window.tabpage
self.line = self.buffer.contents[ current_window.cursor[ 0 ] - 1 ]


Expand Down Expand Up @@ -639,10 +663,11 @@ def MockVimBuffers( buffers, window_buffers, cursor_position = ( 1, 1 ) ):
'which corresponds to the current window.' )

with patch( 'vim.buffers', VimBuffers( buffers ) ):
with patch( 'vim.windows', VimWindows( window_buffers,
cursor_position ) ) as windows:
with patch( 'vim.current', VimCurrent( windows[ 0 ] ) ):
yield VIM_MOCK
with patch( 'vim.tabpages', VimTabpages(
VimTabpage( 1, window_buffers, cursor_position ) ) ) as tabpages:
with patch( 'vim.windows', tabpages[ 1 ] ) as windows:
with patch( 'vim.current', VimCurrent( windows[ 0 ] ) ):
yield VIM_MOCK


def MockVimModule():
Expand Down
44 changes: 24 additions & 20 deletions python/ycm/tests/vimsupport_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ def _BuildLocations( start_line, start_column, end_line, end_column ):


class VimsupportTest( TestCase ):
@patch( 'ycm.vimsupport.WinIDForWindow', side_effect = range( 1001, 1010 ) )
@patch( 'vim.eval', new_callable = ExtendedMock )
def test_SetLocationListsForBuffer_Current( self, vim_eval ):
def test_SetLocationListsForBuffer_Current( self, vim_eval, *args ):
diagnostics = [ {
'bufnr': 3,
'filename': 'some_filename',
Expand All @@ -84,10 +85,10 @@ def test_SetLocationListsForBuffer_Current( self, vim_eval ):
vimsupport.SetLocationListsForBuffer( 3, diagnostics )

vim_eval.assert_has_exact_calls( [
call( 'setloclist( 1, [], " ", { "title": "ycm_loc", '
call( 'setloclist( 1001, [], " ", { "title": "ycm_loc", '
'"items": [{"bufnr": 3, "filename": "some_filename", "lnum": 5, '
'"col": 22, "type": "E", "valid": 1}] } )' ),
call( 'getloclist( 1, { "nr": "$", "id": 0 } ).id' ),
call( 'getloclist( 1001, { "nr": "$", "id": 0 } ).id' ),
] )


Expand Down Expand Up @@ -127,8 +128,9 @@ def test_SetLocationListsForBuffer_NotVisible( self, vim_eval ):
vim_eval.assert_not_called()


@patch( 'ycm.vimsupport.WinIDForWindow', side_effect = range( 1001, 1010 ) )
@patch( 'vim.eval', new_callable = ExtendedMock, side_effect = [ -1, 1 ] )
def test_SetLocationListsForBuffer_MultipleWindows( self, vim_eval ):
def test_SetLocationListsForBuffer_MultipleWindows( self, vim_eval, *args ):
diagnostics = [ {
'bufnr': 3,
'filename': 'some_filename',
Expand All @@ -144,14 +146,15 @@ def test_SetLocationListsForBuffer_MultipleWindows( self, vim_eval ):
vimsupport.SetLocationListsForBuffer( 1, diagnostics )

vim_eval.assert_has_exact_calls( [
call( 'setloclist( 2, [], " ", { "title": "ycm_loc", "items": '
call( 'setloclist( 1001, [], " ", { "title": "ycm_loc", "items": '
f'{ json.dumps( diagnostics ) } }} )' ),
call( 'getloclist( 2, { "nr": "$", "id": 0 } ).id' ),
call( 'getloclist( 1001, { "nr": "$", "id": 0 } ).id' ),
] )


@patch( 'ycm.vimsupport.WinIDForWindow', side_effect = range( 1001, 1010 ) )
@patch( 'vim.eval', new_callable = ExtendedMock )
def test_SetLocationList( self, vim_eval ):
def test_SetLocationList( self, vim_eval, *args ):
diagnostics = [ {
'bufnr': 3,
'filename': 'some_filename',
Expand All @@ -165,15 +168,16 @@ def test_SetLocationList( self, vim_eval ):
vimsupport.SetLocationList( diagnostics )

vim_eval.assert_has_exact_calls( [
call( 'setloclist( 0, [], " ", { "title": "ycm_loc", "items": [{"bufnr": '
'3, "filename": "some_filename", "lnum": '
call( 'setloclist( 1001, [], " ", { "title": "ycm_loc", "items": '
'[{"bufnr": 3, "filename": "some_filename", "lnum": '
'5, "col": 22, "type": "E", "valid": 1}] } )' ),
call( 'getloclist( 0, { "nr": "$", "id": 0 } ).id' ),
call( 'getloclist( 1001, { "nr": "$", "id": 0 } ).id' ),
] )


@patch( 'ycm.vimsupport.WinIDForWindow', side_effect = range( 1001, 1010 ) )
@patch( 'vim.eval', new_callable = ExtendedMock )
def test_SetLocationList_NotCurrent( self, vim_eval ):
def test_SetLocationList_NotCurrent( self, vim_eval, *args ):
diagnostics = [ {
'bufnr': 3,
'filename': 'some_filename',
Expand All @@ -192,10 +196,10 @@ def test_SetLocationList_NotCurrent( self, vim_eval ):
# This version does not check the current
# buffer and just sets the current win
vim_eval.assert_has_exact_calls( [
call( 'setloclist( 0, [], " ", { "title": "ycm_loc", "items": [{"bufnr": '
'3, "filename": "some_filename", "lnum": 5, "col": 22, '
call( 'setloclist( 1001, [], " ", { "title": "ycm_loc", "items": '
'[{"bufnr": 3, "filename": "some_filename", "lnum": 5, "col": 22, '
'"type": "E", "valid": 1}] } )' ),
call( 'getloclist( 0, { "nr": "$", "id": 0 } ).id' ),
call( 'getloclist( 1001, { "nr": "$", "id": 0 } ).id' ),
] )


Expand Down Expand Up @@ -2052,9 +2056,9 @@ def test_JumpToLocation_DifferentFile_Split_AllTabs_AlreadyOpened(
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:
with MockVimBuffers( [ current_buffer, different_buffer ],
[ current_buffer ] ) as vim:
with patch( 'vim.tabpages', [ current_tab ] ):
vimsupport.JumpToLocation( os.path.realpath( 'different_uni¢𐍈d€' ),
2,
5,
Expand Down Expand Up @@ -2102,9 +2106,9 @@ def test_JumpToLocation_DifferentFile_NewOrExistingTab_AlreadyOpened(
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:
with MockVimBuffers( [ current_buffer, different_buffer ],
[ current_buffer ] ) as vim:
with patch( 'vim.tabpages', [ current_tab ] ):
vimsupport.JumpToLocation( os.path.realpath( 'different_uni¢𐍈d€' ),
2,
5,
Expand Down
Loading

0 comments on commit 78ba06e

Please sign in to comment.