Fix cursor position when replacing chunk

Vim doesn't move the cursor accordingly when its position is on the last line
of the replaced area after its ending column because the whole line is
replaced. The cursor must be manually moved in that case.
This commit is contained in:
micbou 2018-04-04 15:03:32 +02:00
parent e018777b38
commit d215342f2f
No known key found for this signature in database
GPG Key ID: C7E8FD1F3BDA1E05
2 changed files with 70 additions and 2 deletions

View File

@ -190,6 +190,7 @@ def AssertBuffersAreEqualAsBytes( result_buffer, expected_buffer ):
eq_( ToBytes( result_line ), ToBytes( expected_line ) )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Repl_1_test():
# Replace with longer range
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -212,6 +213,7 @@ def ReplaceChunk_SingleLine_Repl_1_test():
result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Repl_2_test():
# Replace with shorter range
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -221,6 +223,7 @@ def ReplaceChunk_SingleLine_Repl_2_test():
AssertBuffersAreEqualAsBytes( [ 'This is a test' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Repl_3_test():
# Replace with equal range
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -230,6 +233,7 @@ def ReplaceChunk_SingleLine_Repl_3_test():
AssertBuffersAreEqualAsBytes( [ 'This be a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Add_1_test():
# Insert at start
result_buffer = VimBuffer( 'buffer', contents = [ 'is a string' ] )
@ -239,6 +243,7 @@ def ReplaceChunk_SingleLine_Add_1_test():
AssertBuffersAreEqualAsBytes( [ 'This is a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Add_2_test():
# Insert at end
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a ' ] )
@ -248,6 +253,7 @@ def ReplaceChunk_SingleLine_Add_2_test():
AssertBuffersAreEqualAsBytes( [ 'This is a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Add_3_test():
# Insert in the middle
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -257,6 +263,7 @@ def ReplaceChunk_SingleLine_Add_3_test():
AssertBuffersAreEqualAsBytes( [ 'This is not a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Del_1_test():
# Delete from start
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -266,6 +273,7 @@ def ReplaceChunk_SingleLine_Del_1_test():
AssertBuffersAreEqualAsBytes( [ 'is a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Del_2_test():
# Delete from end
result_buffer = VimBuffer( 'buffer', contents = [ 'This is a string' ] )
@ -275,6 +283,7 @@ def ReplaceChunk_SingleLine_Del_2_test():
AssertBuffersAreEqualAsBytes( [ 'This is a' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Del_3_test():
# Delete from middle
result_buffer = VimBuffer( 'buffer', contents = [ 'This is not a string' ] )
@ -284,6 +293,7 @@ def ReplaceChunk_SingleLine_Del_3_test():
AssertBuffersAreEqualAsBytes( [ 'This is a string' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Unicode_ReplaceUnicodeChars_test():
# Replace Unicode characters.
result_buffer = VimBuffer(
@ -295,6 +305,7 @@ def ReplaceChunk_SingleLine_Unicode_ReplaceUnicodeChars_test():
result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Unicode_ReplaceAfterUnicode_test():
# Replace ASCII characters after Unicode characters in the line.
result_buffer = VimBuffer(
@ -306,6 +317,7 @@ def ReplaceChunk_SingleLine_Unicode_ReplaceAfterUnicode_test():
result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleLine_Unicode_Grown_test():
# Replace ASCII characters after Unicode characters in the line.
result_buffer = VimBuffer( 'buffer', contents = [ 'a' ] )
@ -315,6 +327,7 @@ def ReplaceChunk_SingleLine_Unicode_Grown_test():
AssertBuffersAreEqualAsBytes( [ 'å' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_RemoveSingleLine_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -326,6 +339,7 @@ def ReplaceChunk_RemoveSingleLine_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleToMultipleLines_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -347,6 +361,7 @@ def ReplaceChunk_SingleToMultipleLines_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleToMultipleLines2_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -361,6 +376,7 @@ def ReplaceChunk_SingleToMultipleLines2_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleToMultipleLines3_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -375,6 +391,7 @@ def ReplaceChunk_SingleToMultipleLines3_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleToMultipleLinesReplace_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -389,6 +406,7 @@ def ReplaceChunk_SingleToMultipleLinesReplace_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SingleToMultipleLinesReplace_2_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -411,6 +429,7 @@ def ReplaceChunk_SingleToMultipleLinesReplace_2_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_MultipleLinesToSingleLine_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -441,6 +460,7 @@ def ReplaceChunk_MultipleLinesToSingleLine_test():
'ddaa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_MultipleLinesToSameMultipleLines_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -455,6 +475,7 @@ def ReplaceChunk_MultipleLinesToSameMultipleLines_test():
'aDe' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_MultipleLinesToMoreMultipleLines_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -470,6 +491,7 @@ def ReplaceChunk_MultipleLinesToMoreMultipleLines_test():
'aDe' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_MultipleLinesToLessMultipleLines_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -483,6 +505,7 @@ def ReplaceChunk_MultipleLinesToLessMultipleLines_test():
'aDe' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_MultipleLinesToEvenLessMultipleLines_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -495,6 +518,7 @@ def ReplaceChunk_MultipleLinesToEvenLessMultipleLines_test():
'bFDe' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_SpanBufferEdge_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -507,6 +531,7 @@ def ReplaceChunk_SpanBufferEdge_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_DeleteTextInLine_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -518,6 +543,7 @@ def ReplaceChunk_DeleteTextInLine_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_AddTextInLine_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -530,6 +556,7 @@ def ReplaceChunk_AddTextInLine_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_ReplaceTextInLine_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'aAa',
'aBa',
@ -542,6 +569,7 @@ def ReplaceChunk_ReplaceTextInLine_test():
'aCa' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_NewlineChunk_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'first line',
'second line' ] )
@ -552,16 +580,30 @@ def ReplaceChunk_NewlineChunk_test():
'second line' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunk_BeyondEndOfFile_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'first line',
'second line' ] )
start, end = _BuildLocations( 1, 11, 3, 1 )
vimsupport.ReplaceChunk( start, end, '\n', result_buffer )
AssertBuffersAreEqualAsBytes( [ 'first line' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 3 ) )
def ReplaceChunk_CursorPosition_test():
result_buffer = VimBuffer( 'buffer', contents = [ 'bar' ] )
start, end = _BuildLocations( 1, 1, 1, 1 )
vimsupport.ReplaceChunk( start,
end,
'xyz\nfoo',
result_buffer )
AssertBuffersAreEqualAsBytes( [ 'xyz', 'foobar' ], result_buffer )
# Cursor line is 0-based.
assert_that( vimsupport.CurrentLineAndColumn(), contains( 1, 6 ) )
def _BuildLocations( start_line, start_column, end_line, end_column ):
return {
'line_num' : start_line,
@ -572,6 +614,7 @@ def _BuildLocations( start_line, start_column, end_line, end_column ):
}
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_SortedChunks_test():
chunks = [
_BuildChunk( 1, 4, 1, 4, '(' ),
@ -584,6 +627,7 @@ def ReplaceChunksInBuffer_SortedChunks_test():
AssertBuffersAreEqualAsBytes( [ 'CT<(10 >> 2)> ct' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_UnsortedChunks_test():
chunks = [
_BuildChunk( 1, 11, 1, 11, ')' ),
@ -596,6 +640,7 @@ def ReplaceChunksInBuffer_UnsortedChunks_test():
AssertBuffersAreEqualAsBytes( [ 'CT<(10 >> 2)> ct' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_LineOverlappingChunks_test():
chunks = [
_BuildChunk( 1, 11, 2, 1, '\n ' ),
@ -615,6 +660,7 @@ def ReplaceChunksInBuffer_LineOverlappingChunks_test():
' fourth line' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_OutdentChunks_test():
chunks = [
_BuildChunk( 1, 1, 1, 5, ' ' ),
@ -632,6 +678,7 @@ def ReplaceChunksInBuffer_OutdentChunks_test():
' third line' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_OneLineIndentingChunks_test():
chunks = [
_BuildChunk( 1, 8, 2, 1, '\n ' ),
@ -651,6 +698,7 @@ def ReplaceChunksInBuffer_OneLineIndentingChunks_test():
'}' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
def ReplaceChunksInBuffer_SameLocation_test():
chunks = [
_BuildChunk( 1, 1, 1, 1, 'this ' ),
@ -664,6 +712,7 @@ def ReplaceChunksInBuffer_SameLocation_test():
AssertBuffersAreEqualAsBytes( [ 'this is pure folly' ], result_buffer )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.VariableExists', return_value = False )
@patch( 'ycm.vimsupport.SetFittingHeightForCurrentWindow' )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
@ -745,6 +794,7 @@ def ReplaceChunks_SingleFile_Open_test( vim_command,
] )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.VariableExists', return_value = False )
@patch( 'ycm.vimsupport.SetFittingHeightForCurrentWindow' )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
@ -852,6 +902,7 @@ def ReplaceChunks_SingleFile_NotOpen_test( vim_command,
] )
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.VariableExists', return_value = False )
@patch( 'ycm.vimsupport.SetFittingHeightForCurrentWindow' )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
@ -949,6 +1000,7 @@ def ReplaceChunks_SingleFile_NotOpen_Silent_test(
post_vim_message.assert_not_called()
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
side_effect = [ -1, -1, 1 ],
new_callable = ExtendedMock )
@ -1028,6 +1080,7 @@ def ReplaceChunks_User_Declines_To_Open_File_test(
post_vim_message.assert_not_called()
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename',
side_effect = [ -1, -1, 1 ],
new_callable = ExtendedMock )
@ -1105,6 +1158,7 @@ def ReplaceChunks_User_Aborts_Opening_File_test(
post_vim_message.assert_not_called()
@patch( 'vim.current.window.cursor', ( 1, 1 ) )
@patch( 'ycm.vimsupport.VariableExists', return_value = False )
@patch( 'ycm.vimsupport.SetFittingHeightForCurrentWindow' )
@patch( 'ycm.vimsupport.GetBufferNumberForFilename', side_effect = [
@ -1576,6 +1630,7 @@ def InsertNamespace_insert_test( vim_current, *args ):
'',
' int taco = Math' ]
vim_current.buffer = VimBuffer( '', contents = contents )
vim_current.window.cursor = ( 1, 1 )
vimsupport.InsertNamespace( 'System' )
@ -1598,6 +1653,7 @@ def InsertNamespace_append_test( vim_current, *args ):
' int taco;',
' List salad = new List' ]
vim_current.buffer = VimBuffer( '', contents = contents )
vim_current.window.cursor = ( 1, 1 )
vimsupport.InsertNamespace( 'System.Collections' )

View File

@ -947,13 +947,25 @@ def ReplaceChunk( start, end, replacement_text, vim_buffer ):
# NOTE: Vim buffers are a list of byte objects on Python 2 but unicode
# objects on Python 3.
start_existing_text = ToBytes( vim_buffer[ start_line ] )[ : start_column ]
end_existing_text = ToBytes( vim_buffer[ end_line ] )[ end_column : ]
end_line_text = ToBytes( vim_buffer[ end_line ] )
end_existing_text = end_line_text[ end_column : ]
replacement_lines[ 0 ] = start_existing_text + replacement_lines[ 0 ]
replacement_lines[ -1 ] = replacement_lines[ -1 ] + end_existing_text
cursor_line, cursor_column = CurrentLineAndColumn()
vim_buffer[ start_line : end_line + 1 ] = replacement_lines[ : ]
# When the cursor position is on the last line in the replaced area, and ends
# up somewhere after the end of the new text, we need to reset the cursor
# position. This is because Vim doesn't know where to put it, and guesses
# badly. We put it at the end of the new text.
if cursor_line == end_line and cursor_column >= end_column:
cursor_line = start_line + len( replacement_lines ) - 1
cursor_column += len( replacement_lines[ - 1 ] ) - len( end_line_text )
SetCurrentLineAndColumn( cursor_line, cursor_column )
return {
'bufnr': vim_buffer.number,
'filename': vim_buffer.name,