mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #12343 from ndreas/fix/lsp-multibyte-indexing
Fix LSP multibyte indexing
This commit is contained in:
commit
96568d5b07
@ -95,17 +95,23 @@ local edit_sort_key = sort_by_key(function(e)
|
|||||||
return {e.A[1], e.A[2], e.i}
|
return {e.A[1], e.A[2], e.i}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local function get_line_byte_from_line_character(bufnr, lnum, cnum)
|
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
|
||||||
-- Skip check when the byte and character position is the same
|
-- Returns a zero-indexed column, since set_lines() does the conversion to
|
||||||
if cnum > 0 then
|
-- 1-indexed
|
||||||
local lines = api.nvim_buf_get_lines(bufnr, lnum, lnum+1, false)
|
local function get_line_byte_from_position(bufnr, position)
|
||||||
|
-- LSP's line and characters are 0-indexed
|
||||||
|
-- Vim's line and columns are 1-indexed
|
||||||
|
local col = position.character
|
||||||
|
-- When on the first character, we can ignore the difference between byte and
|
||||||
|
-- character
|
||||||
|
if col > 0 then
|
||||||
|
local line = position.line
|
||||||
|
local lines = api.nvim_buf_get_lines(bufnr, line, line + 1, false)
|
||||||
if #lines > 0 then
|
if #lines > 0 then
|
||||||
return vim.str_byteindex(lines[1], cnum)
|
return vim.str_byteindex(lines[1], col)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return col
|
||||||
return cnum
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.apply_text_edits(text_edits, bufnr)
|
function M.apply_text_edits(text_edits, bufnr)
|
||||||
@ -118,15 +124,9 @@ function M.apply_text_edits(text_edits, bufnr)
|
|||||||
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
|
-- adjust start and end column for UTF-16 encoding of non-ASCII characters
|
||||||
local start_row = e.range.start.line
|
local start_row = e.range.start.line
|
||||||
local start_col = get_line_byte_from_line_character(
|
local start_col = get_line_byte_from_position(bufnr, e.range.start)
|
||||||
bufnr,
|
|
||||||
start_row,
|
|
||||||
e.range.start.character)
|
|
||||||
local end_row = e.range["end"].line
|
local end_row = e.range["end"].line
|
||||||
local end_col = get_line_byte_from_line_character(
|
local end_col = get_line_byte_from_position(bufnr, e.range['end'])
|
||||||
bufnr,
|
|
||||||
end_row,
|
|
||||||
e.range["end"].character)
|
|
||||||
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.
|
||||||
@ -543,9 +543,7 @@ function M.jump_to_location(location)
|
|||||||
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
|
||||||
local row = range.start.line
|
local row = range.start.line
|
||||||
local col = range.start.character
|
local col = get_line_byte_from_position(0, range.start)
|
||||||
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
|
|
||||||
col = vim.str_byteindex(line, col)
|
|
||||||
api.nvim_win_set_cursor(0, {row + 1, col})
|
api.nvim_win_set_cursor(0, {row + 1, col})
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -1317,4 +1317,65 @@ describe('LSP', function()
|
|||||||
eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)"))
|
eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)"))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('lsp.util.jump_to_location', function()
|
||||||
|
local target_bufnr
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
target_bufnr = exec_lua [[
|
||||||
|
local bufnr = vim.uri_to_bufnr("file://fake/uri")
|
||||||
|
local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
|
||||||
|
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
|
||||||
|
return bufnr
|
||||||
|
]]
|
||||||
|
end)
|
||||||
|
|
||||||
|
local location = function(start_line, start_char, end_line, end_char)
|
||||||
|
return {
|
||||||
|
uri = "file://fake/uri",
|
||||||
|
range = {
|
||||||
|
start = { line = start_line, character = start_char },
|
||||||
|
["end"] = { line = end_line, character = end_char },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local jump = function(msg)
|
||||||
|
eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
|
||||||
|
eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
|
||||||
|
return {
|
||||||
|
line = exec_lua[[return vim.fn.line('.')]],
|
||||||
|
col = exec_lua[[return vim.fn.col('.')]],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it('jumps to a Location', function()
|
||||||
|
local pos = jump(location(0, 9, 0, 9))
|
||||||
|
eq(1, pos.line)
|
||||||
|
eq(10, pos.col)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('jumps to a LocationLink', function()
|
||||||
|
local pos = jump({
|
||||||
|
targetUri = "file://fake/uri",
|
||||||
|
targetSelectionRange = {
|
||||||
|
start = { line = 0, character = 4 },
|
||||||
|
["end"] = { line = 0, character = 4 },
|
||||||
|
},
|
||||||
|
targetRange = {
|
||||||
|
start = { line = 1, character = 5 },
|
||||||
|
["end"] = { line = 1, character = 5 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
eq(1, pos.line)
|
||||||
|
eq(5, pos.col)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('jumps to the correct multibyte column', function()
|
||||||
|
local pos = jump(location(1, 2, 1, 2))
|
||||||
|
eq(2, pos.line)
|
||||||
|
eq(4, pos.col)
|
||||||
|
eq('å', exec_lua[[return vim.fn.expand('<cword>')]])
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user