Skip to content

Commit dff8130

Browse files
refactor(lsp): integrated out of bound clipping of edits for row/column issues
1 parent 9b73de0 commit dff8130

File tree

1 file changed

+38
-45
lines changed

1 file changed

+38
-45
lines changed

runtime/lua/vim/lsp/util.lua

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -459,59 +459,52 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
459459
text = split(text_edit.newText, '\n', true),
460460
}
461461

462-
-- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here.
463462
local max = api.nvim_buf_line_count(bufnr)
464-
if max <= e.start_row or max <= e.end_row then
465-
local len = #(get_line(bufnr, max - 1) or '')
466-
if max <= e.start_row then
467-
e.start_row = max - 1
468-
e.start_col = len
469-
table.insert(e.text, 1, '')
470-
end
463+
-- If the whole edit is after the lines in the buffer we can simply add the new text to the end
464+
-- of the buffer.
465+
if max <= e.start_row then
466+
api.nvim_buf_set_lines(bufnr, max, max, false, e.text)
467+
else
468+
local last_line_len = #(get_line(bufnr, math.min(e.end_row, max - 1)) or '')
469+
-- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't
470+
-- accept it so we should fix it here.
471471
if max <= e.end_row then
472472
e.end_row = max - 1
473-
e.end_col = len
473+
e.end_col = last_line_len
474+
has_eol_text_edit = true
475+
else
476+
-- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
477+
-- replacement text ends with a newline We can likely assume that the replacement is assumed
478+
-- to be meant to replace the newline with another newline and we need to make sure this
479+
-- doens't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
480+
-- in the file some servers (clangd on windows) will include that character in the line
481+
-- while nvim_buf_set_lines doesn't count it as part of the line.
482+
if
483+
e.end_col > last_line_len
484+
and #text_edit.newText > 0
485+
and string.sub(text_edit.newText, -1) == '\n'
486+
then
487+
table.remove(e.text, #e.text)
488+
end
474489
end
475-
has_eol_text_edit = true
476-
end
490+
-- Make sure we don't go out of bounds for e.end_col
491+
e.end_col = math.min(last_line_len, e.end_col)
477492

478-
-- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
479-
-- replacement text ends with a newline We can likely assume that the replacement is assumed to
480-
-- be meant to replace the newline with another newline and we need to make sure this doens't
481-
-- add an extra empty line. E.g. when the last line to be replaced contains a '\r' in the file
482-
-- some servers (clangd on windows) will include that character in the line while
483-
-- nvim_buf_set_lines doesn't count it as part of the line.
484-
local last_line = get_line(bufnr, e.end_row)
485-
if
486-
e.end_col > #last_line
487-
and #text_edit.newText > 0
488-
and string.sub(text_edit.newText, -1) == '\n'
489-
then
490-
table.remove(e.text, #e.text)
491-
end
492-
-- Make sure we don't go out of bounds for e.end_col
493-
e.end_col = math.min(#last_line, e.end_col)
494-
495-
-- If the replacement is over full lines it is recommended to use nvim_buf_set_lines
496-
-- see. https://neovim.io/doc/user/api.html#nvim_buf_set_test()
497-
if e.end_col == #last_line and e.start_col == 0 then
498-
api.nvim_buf_set_lines(bufnr, e.start_row, e.end_row + 1, false, e.text)
499-
else
500493
api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
501-
end
502494

503-
-- Fix cursor position.
504-
local row_count = (e.end_row - e.start_row) + 1
505-
if e.end_row < cursor.row then
506-
cursor.row = cursor.row + (#e.text - row_count)
507-
is_cursor_fixed = true
508-
elseif e.end_row == cursor.row and e.end_col <= cursor.col then
509-
cursor.row = cursor.row + (#e.text - row_count)
510-
cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
511-
if #e.text == 1 then
512-
cursor.col = cursor.col + e.start_col
495+
-- Fix cursor position.
496+
local row_count = (e.end_row - e.start_row) + 1
497+
if e.end_row < cursor.row then
498+
cursor.row = cursor.row + (#e.text - row_count)
499+
is_cursor_fixed = true
500+
elseif e.end_row == cursor.row and e.end_col <= cursor.col then
501+
cursor.row = cursor.row + (#e.text - row_count)
502+
cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
503+
if #e.text == 1 then
504+
cursor.col = cursor.col + e.start_col
505+
end
506+
is_cursor_fixed = true
513507
end
514-
is_cursor_fixed = true
515508
end
516509
end
517510

0 commit comments

Comments
 (0)