From 131063e08fef32ee34732ba1530676bdf408d924 Mon Sep 17 00:00:00 2001 From: Andreas Johansson Date: Tue, 19 May 2020 08:49:13 +0200 Subject: Refactor fetching the line byte Takes the entire LSP position instead of line/col --- runtime/lua/vim/lsp/util.lua | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 534c90f1fd..8a536f72f4 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -94,17 +94,23 @@ local edit_sort_key = sort_by_key(function(e) return {e.A[1], e.A[2], e.i} end) -local function get_line_byte_from_line_character(bufnr, lnum, cnum) - -- Skip check when the byte and character position is the same - if cnum > 0 then - local lines = api.nvim_buf_get_lines(bufnr, lnum, lnum+1, false) - +--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position +-- Returns a zero-indexed column, since set_lines() does the conversion to +-- 1-indexed +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 - return vim.str_byteindex(lines[1], cnum) + return vim.str_byteindex(lines[1], col) end end - - return cnum + return col end function M.apply_text_edits(text_edits, bufnr) @@ -117,15 +123,9 @@ function M.apply_text_edits(text_edits, bufnr) 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 = get_line_byte_from_line_character( - bufnr, - start_row, - e.range.start.character) + local start_col = get_line_byte_from_position(bufnr, e.range.start) local end_row = e.range["end"].line - local end_col = get_line_byte_from_line_character( - bufnr, - end_row, - e.range["end"].character) + local end_col = get_line_byte_from_position(bufnr, e.range['end']) start_line = math.min(e.range.start.line, start_line) finish_line = math.max(e.range["end"].line, finish_line) -- TODO(ashkan) sanity check ranges for overlap. -- cgit From 0aca34e0a98ab47a8ae907031b25f687760a9264 Mon Sep 17 00:00:00 2001 From: Andreas Johansson Date: Tue, 19 May 2020 08:50:31 +0200 Subject: Use get_line_byte_from_position in jump_to_location --- runtime/lua/vim/lsp/util.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 8a536f72f4..1b099fb3f4 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -474,9 +474,7 @@ function M.jump_to_location(location) api.nvim_buf_set_option(0, 'buflisted', true) local range = location.range or location.targetSelectionRange local row = range.start.line - local col = range.start.character - local line = api.nvim_buf_get_lines(0, row, row+1, true)[1] - col = vim.str_byteindex(line, col) + local col = get_line_byte_from_position(0, range.start) api.nvim_win_set_cursor(0, {row + 1, col}) return true end -- cgit From 67eb3bfbc38b8d46dfb458698f1dc5f952229d4a Mon Sep 17 00:00:00 2001 From: Andreas Johansson Date: Tue, 19 May 2020 08:51:10 +0200 Subject: Add tests for jump_to_location --- test/functional/plugin/lsp_spec.lua | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f41a5323a8..5fe44d1bf2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1290,4 +1290,65 @@ describe('LSP', function() eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)")) 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('')]]) + end) + end) end) -- cgit