mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 03:48:18 +00:00
fix(lsp): handle out-of-bounds character positions #30288
Problem: str_byteindex_enc could return an error if the index was longer than the lline length. This was handled in each of the calls to it individually Solution: * Fix the call at the source level so that if the index is higher than the line length, line length is returned as per LSP specification * Remove pcalls on str_byteindex_enc calls. No longer needed now that str_byteindex_enc has a bounds check.
This commit is contained in:
@@ -147,6 +147,12 @@ end
|
||||
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
|
||||
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
|
||||
function M._str_byteindex_enc(line, index, encoding)
|
||||
local len = vim.fn.strlen(line)
|
||||
if index > len then
|
||||
-- LSP spec: if character > line length, default to the line length.
|
||||
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
||||
return len
|
||||
end
|
||||
if not encoding then
|
||||
encoding = 'utf-16'
|
||||
end
|
||||
@@ -166,7 +172,6 @@ function M._str_byteindex_enc(line, index, encoding)
|
||||
end
|
||||
|
||||
local _str_utfindex_enc = M._str_utfindex_enc
|
||||
local _str_byteindex_enc = M._str_byteindex_enc
|
||||
|
||||
--- Replaces text in a range with new text.
|
||||
---
|
||||
@@ -334,12 +339,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
|
||||
-- character
|
||||
if col > 0 then
|
||||
local line = get_line(bufnr, position.line) or ''
|
||||
local ok, result
|
||||
ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
|
||||
if ok then
|
||||
return result
|
||||
end
|
||||
return math.min(#line, col)
|
||||
return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
|
||||
end
|
||||
return col
|
||||
end
|
||||
@@ -436,14 +436,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
|
||||
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
|
||||
-- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length 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
|
||||
-- doesn'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
|
||||
e.end_col >= last_line_len
|
||||
and text_edit.range['end'].character > e.end_col
|
||||
and #text_edit.newText > 0
|
||||
and string.sub(text_edit.newText, -1) == '\n'
|
||||
then
|
||||
@@ -1795,17 +1796,9 @@ function M.locations_to_items(locations, offset_encoding)
|
||||
local row = pos.line
|
||||
local end_row = end_pos.line
|
||||
local line = lines[row] or ''
|
||||
local line_len = vim.fn.strcharlen(line)
|
||||
local end_line = lines[end_row] or ''
|
||||
local end_line_len = vim.fn.strcharlen(end_line)
|
||||
-- LSP spec: if character > line length, default to the line length.
|
||||
-- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
|
||||
local col = pos.character <= line_len
|
||||
and M._str_byteindex_enc(line, pos.character, offset_encoding)
|
||||
or line_len
|
||||
local end_col = end_pos.character <= end_line_len
|
||||
and M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
||||
or end_line_len
|
||||
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
|
||||
local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
|
||||
|
||||
table.insert(items, {
|
||||
filename = filename,
|
||||
|
Reference in New Issue
Block a user