aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/util.lua
diff options
context:
space:
mode:
authorofwinterpassed <johannes@librem.one>2022-09-20 22:14:58 +0200
committerGitHub <noreply@github.com>2022-09-20 22:14:58 +0200
commitec94014cd1d09884b12cb19021d5a1eff52cb76d (patch)
tree1fae13b19e9f3c1c67eeadc27252073bddb23f95 /runtime/lua/vim/lsp/util.lua
parent62db91f06cd6effab59e84289889b2a5d75f3e4b (diff)
downloadrneovim-ec94014cd1d09884b12cb19021d5a1eff52cb76d.tar.gz
rneovim-ec94014cd1d09884b12cb19021d5a1eff52cb76d.tar.bz2
rneovim-ec94014cd1d09884b12cb19021d5a1eff52cb76d.zip
fix(lsp): out of bounds error in lsp.util.apply_text_edits (#20137)
Co-authored-by: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com>
Diffstat (limited to 'runtime/lua/vim/lsp/util.lua')
-rw-r--r--runtime/lua/vim/lsp/util.lua65
1 files changed, 41 insertions, 24 deletions
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 283099bbcf..1909dbd4d1 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -459,35 +459,52 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
text = split(text_edit.newText, '\n', true),
}
- -- 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.
local max = api.nvim_buf_line_count(bufnr)
- if max <= e.start_row or max <= e.end_row then
- local len = #(get_line(bufnr, max - 1) or '')
- if max <= e.start_row then
- e.start_row = max - 1
- e.start_col = len
- table.insert(e.text, 1, '')
- end
+ -- If the whole edit is after the lines in the buffer we can simply add the new text to the end
+ -- of the buffer.
+ if max <= e.start_row then
+ api.nvim_buf_set_lines(bufnr, max, max, false, e.text)
+ else
+ local last_line_len = #(get_line(bufnr, math.min(e.end_row, max - 1)) or '')
+ -- 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.
if max <= e.end_row then
e.end_row = max - 1
- e.end_col = len
+ e.end_col = last_line_len
+ has_eol_text_edit = true
+ else
+ -- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
+ -- replacement text ends with a newline We can likely assume that the replacement is assumed
+ -- to be meant to replace the newline with another newline and we need to make sure this
+ -- doens't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
+ -- in the file some servers (clangd on windows) will include that character in the line
+ -- while nvim_buf_set_text doesn't count it as part of the line.
+ if
+ e.end_col > last_line_len
+ and #text_edit.newText > 0
+ and string.sub(text_edit.newText, -1) == '\n'
+ then
+ table.remove(e.text, #e.text)
+ end
end
- has_eol_text_edit = true
- end
- api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
-
- -- Fix cursor position.
- local row_count = (e.end_row - e.start_row) + 1
- if e.end_row < cursor.row then
- cursor.row = cursor.row + (#e.text - row_count)
- is_cursor_fixed = true
- elseif e.end_row == cursor.row and e.end_col <= cursor.col then
- cursor.row = cursor.row + (#e.text - row_count)
- cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
- if #e.text == 1 then
- cursor.col = cursor.col + e.start_col
+ -- Make sure we don't go out of bounds for e.end_col
+ e.end_col = math.min(last_line_len, e.end_col)
+
+ api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
+
+ -- Fix cursor position.
+ local row_count = (e.end_row - e.start_row) + 1
+ if e.end_row < cursor.row then
+ cursor.row = cursor.row + (#e.text - row_count)
+ is_cursor_fixed = true
+ elseif e.end_row == cursor.row and e.end_col <= cursor.col then
+ cursor.row = cursor.row + (#e.text - row_count)
+ cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
+ if #e.text == 1 then
+ cursor.col = cursor.col + e.start_col
+ end
+ is_cursor_fixed = true
end
- is_cursor_fixed = true
end
end