fix(lsp): start incremental sync range at previous newline character (#17610)

This change forces the start of an incremental sync range to begin always on an existing line.
This commit is contained in:
Michael Lingelbach 2022-03-05 09:17:56 -08:00 committed by GitHub
parent 228ea78622
commit a5e475fcc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 11 deletions

View File

@ -131,13 +131,22 @@ end
---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8)
---@returns table<int, int> line_idx, byte_idx, and char_idx of first change position ---@returns table<int, int> line_idx, byte_idx, and char_idx of first change position
local function compute_start_range(prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding) local function compute_start_range(prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding)
local char_idx
local byte_idx
-- If firstline == lastline, no existing text is changed. All edit operations -- If firstline == lastline, no existing text is changed. All edit operations
-- occur on a new line pointed to by lastline. This occurs during insertion of -- occur on a new line pointed to by lastline. This occurs during insertion of
-- new lines(O), the new newline is inserted at the line indicated by -- new lines(O), the new newline is inserted at the line indicated by
-- new_lastline. -- new_lastline.
if firstline == lastline then
local line = prev_lines[firstline - 1]
byte_idx = #line + 1
char_idx = compute_line_length(line, offset_encoding) + 1
return { line_idx = firstline - 1, byte_idx = byte_idx, char_idx = char_idx }
end
-- If firstline == new_lastline, the first change occurred on a line that was deleted. -- If firstline == new_lastline, the first change occurred on a line that was deleted.
-- In this case, the first byte change is also at the first byte of firstline -- In this case, the first byte change is also at the first byte of firstline
if firstline == new_lastline or firstline == lastline then if firstline == new_lastline then
return { line_idx = firstline, byte_idx = 1, char_idx = 1 } return { line_idx = firstline, byte_idx = 1, char_idx = 1 }
end end
@ -158,8 +167,6 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline,
end end
-- Convert byte to codepoint if applicable -- Convert byte to codepoint if applicable
local char_idx
local byte_idx
if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1)then if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1)then
byte_idx = start_byte_idx byte_idx = start_byte_idx
char_idx = 1 char_idx = 1

View File

@ -207,16 +207,16 @@ describe('incremental synchronization', function()
{ {
range = { range = {
['start'] = { ['start'] = {
character = 0, character = 11,
line = 1 line = 0,
}, },
['end'] = { ['end'] = {
character = 0, character = 0,
line = 1 line = 1
} }
}, },
rangeLength = 0, rangeLength = 1,
text = 'hello world\n' text = '\nhello world\n'
} }
} }
test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n') test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n')
@ -226,20 +226,39 @@ describe('incremental synchronization', function()
{ {
range = { range = {
['start'] = { ['start'] = {
character = 0, character = 11,
line = 1 line = 0
}, },
['end'] = { ['end'] = {
character = 0, character = 0,
line = 1 line = 1
} }
}, },
rangeLength = 0, rangeLength = 1,
text = '\n' text = '\n\n'
} }
} }
test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n') test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
end) end)
it('adding a line to an empty buffer', function()
local expected_text_changes = {
{
range = {
['start'] = {
character = 0,
line = 0
},
['end'] = {
character = 0,
line = 1
}
},
rangeLength = 1,
text = '\n\n'
}
}
test_edit({""}, {"o"}, expected_text_changes, 'utf-16', '\n')
end)
end) end)
describe('multi line edit', function() describe('multi line edit', function()
it('deletion and insertion', function() it('deletion and insertion', function()