diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 0f4e5b572b..e500be46c2 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -131,13 +131,22 @@ end ---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ---@returns table 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 char_idx + local byte_idx -- 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 -- new lines(O), the new newline is inserted at the line indicated by -- 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. -- 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 } end @@ -158,8 +167,6 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, end -- 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 byte_idx = start_byte_idx char_idx = 1 diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 4e3eddb960..da54f3c649 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -207,16 +207,16 @@ describe('incremental synchronization', function() { range = { ['start'] = { - character = 0, - line = 1 + character = 11, + line = 0, }, ['end'] = { character = 0, line = 1 } }, - rangeLength = 0, - text = 'hello world\n' + rangeLength = 1, + text = '\nhello world\n' } } test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n') @@ -226,20 +226,39 @@ describe('incremental synchronization', function() { range = { ['start'] = { - character = 0, - line = 1 + character = 11, + line = 0 }, ['end'] = { character = 0, line = 1 } }, - rangeLength = 0, - text = '\n' + rangeLength = 1, + text = '\n\n' } } test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n') 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) describe('multi line edit', function() it('deletion and insertion', function()