mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
lsp: Make apply_text_edits non-ASCII safe (#12223)
* Make apply_text_edits non-ASCII safe Use `vim.str_byteindex` to correct starting and ending positions for text edits if the line contains non-ASCII characters. Fixes #12221 * text_edit may be applied to other buffers * make sure the buffer is loaded * add comments * add test for non-ASCII edits
This commit is contained in:
parent
9a67b030d9
commit
281e44f7bb
@ -96,16 +96,28 @@ end)
|
|||||||
|
|
||||||
function M.apply_text_edits(text_edits, bufnr)
|
function M.apply_text_edits(text_edits, bufnr)
|
||||||
if not next(text_edits) then return end
|
if not next(text_edits) then return end
|
||||||
|
if not api.nvim_buf_is_loaded(bufnr) then
|
||||||
|
vim.fn.bufload(bufnr)
|
||||||
|
end
|
||||||
local start_line, finish_line = math.huge, -1
|
local start_line, finish_line = math.huge, -1
|
||||||
local cleaned = {}
|
local cleaned = {}
|
||||||
for i, e in ipairs(text_edits) do
|
for i, e in ipairs(text_edits) do
|
||||||
|
-- adjust start and end column for UTF-16 encoding of non-ASCII characters
|
||||||
|
local start_row = e.range.start.line
|
||||||
|
local start_col = e.range.start.character
|
||||||
|
local start_bline = api.nvim_buf_get_lines(bufnr, start_row, start_row+1, true)[1]
|
||||||
|
start_col = vim.str_byteindex(start_bline, start_col)
|
||||||
|
local end_row = e.range["end"].line
|
||||||
|
local end_col = e.range["end"].character
|
||||||
|
local end_bline = api.nvim_buf_get_lines(bufnr, end_row, end_row+1, true)[1]
|
||||||
|
end_col = vim.str_byteindex(end_bline, end_col)
|
||||||
start_line = math.min(e.range.start.line, start_line)
|
start_line = math.min(e.range.start.line, start_line)
|
||||||
finish_line = math.max(e.range["end"].line, finish_line)
|
finish_line = math.max(e.range["end"].line, finish_line)
|
||||||
-- TODO(ashkan) sanity check ranges for overlap.
|
-- TODO(ashkan) sanity check ranges for overlap.
|
||||||
table.insert(cleaned, {
|
table.insert(cleaned, {
|
||||||
i = i;
|
i = i;
|
||||||
A = {e.range.start.line; e.range.start.character};
|
A = {start_row; start_col};
|
||||||
B = {e.range["end"].line; e.range["end"].character};
|
B = {end_row; end_col};
|
||||||
lines = vim.split(e.newText, '\n', true);
|
lines = vim.split(e.newText, '\n', true);
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@ -113,9 +125,6 @@ function M.apply_text_edits(text_edits, bufnr)
|
|||||||
-- Reverse sort the orders so we can apply them without interfering with
|
-- Reverse sort the orders so we can apply them without interfering with
|
||||||
-- eachother. Also add i as a sort key to mimic a stable sort.
|
-- eachother. Also add i as a sort key to mimic a stable sort.
|
||||||
table.sort(cleaned, edit_sort_key)
|
table.sort(cleaned, edit_sort_key)
|
||||||
if not api.nvim_buf_is_loaded(bufnr) then
|
|
||||||
vim.fn.bufload(bufnr)
|
|
||||||
end
|
|
||||||
local lines = api.nvim_buf_get_lines(bufnr, start_line, finish_line + 1, false)
|
local lines = api.nvim_buf_get_lines(bufnr, start_line, finish_line + 1, false)
|
||||||
local fix_eol = api.nvim_buf_get_option(bufnr, 'fixeol')
|
local fix_eol = api.nvim_buf_get_option(bufnr, 'fixeol')
|
||||||
local set_eol = fix_eol and api.nvim_buf_line_count(bufnr) <= finish_line + 1
|
local set_eol = fix_eol and api.nvim_buf_line_count(bufnr) <= finish_line + 1
|
||||||
@ -443,7 +452,7 @@ function M.jump_to_location(location)
|
|||||||
local items = {{tagname=vim.fn.expand('<cword>'), from=from}}
|
local items = {{tagname=vim.fn.expand('<cword>'), from=from}}
|
||||||
vim.fn.settagstack(vim.fn.win_getid(), {items=items}, 't')
|
vim.fn.settagstack(vim.fn.win_getid(), {items=items}, 't')
|
||||||
|
|
||||||
--- Jump to new location
|
--- Jump to new location (adjusting for UTF-16 encoding of characters)
|
||||||
api.nvim_set_current_buf(bufnr)
|
api.nvim_set_current_buf(bufnr)
|
||||||
api.nvim_buf_set_option(0, 'buflisted', true)
|
api.nvim_buf_set_option(0, 'buflisted', true)
|
||||||
local range = location.range or location.targetSelectionRange
|
local range = location.range or location.targetSelectionRange
|
||||||
|
@ -779,7 +779,7 @@ describe('LSP', function()
|
|||||||
Fourth line of text
|
Fourth line of text
|
||||||
å å ɧ 汉语 ↥ 🤦 🦄]]))
|
å å ɧ 汉语 ↥ 🤦 🦄]]))
|
||||||
end)
|
end)
|
||||||
it('applies apply simple edits', function()
|
it('applies simple edits', function()
|
||||||
local edits = {
|
local edits = {
|
||||||
make_edit(0, 0, 0, 0, {"123"});
|
make_edit(0, 0, 0, 0, {"123"});
|
||||||
make_edit(1, 0, 1, 1, {"2"});
|
make_edit(1, 0, 1, 1, {"2"});
|
||||||
@ -818,10 +818,9 @@ describe('LSP', function()
|
|||||||
'å å ɧ 汉语 ↥ 🤦 🦄';
|
'å å ɧ 汉语 ↥ 🤦 🦄';
|
||||||
}, buf_lines(1))
|
}, buf_lines(1))
|
||||||
end)
|
end)
|
||||||
pending('applies non-ASCII characters edits', function()
|
it('applies non-ASCII characters edits', function()
|
||||||
-- FIXME: We don't handle non-ASCII characters well in UTF-16
|
|
||||||
local edits = {
|
local edits = {
|
||||||
make_edit(4, 0, 4, 14, {"a a h"});
|
make_edit(4, 3, 4, 4, {"ä"});
|
||||||
}
|
}
|
||||||
exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
|
exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
|
||||||
eq({
|
eq({
|
||||||
@ -829,7 +828,7 @@ describe('LSP', function()
|
|||||||
'Second line of text';
|
'Second line of text';
|
||||||
'Third line of text';
|
'Third line of text';
|
||||||
'Fourth line of text';
|
'Fourth line of text';
|
||||||
'a a h';
|
'å ä ɧ 汉语 ↥ 🤦 🦄';
|
||||||
}, buf_lines(1))
|
}, buf_lines(1))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user