fix(lsp): improper diagnostic end_col computation

**Problem:** For multiline diagnostics, the end column was improperly
calculated by checking the byte index of the character position on the
*start* line.

**Solution:** Calculate the byte index for end_col using the *end* line.
This commit is contained in:
Riley Bruins
2025-05-02 08:25:24 -07:00
committed by Christian Clason
parent adbd33027f
commit 5d1fd4aca5
2 changed files with 36 additions and 2 deletions

View File

@ -100,12 +100,16 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
message = diagnostic.message.value
end
local line = buf_lines and buf_lines[start.line + 1] or ''
local end_line = line
if _end.line > start.line then
end_line = buf_lines and buf_lines[_end.line + 1] or ''
end
--- @type vim.Diagnostic
return {
lnum = start.line,
col = vim.str_byteindex(line, position_encoding, start.character, false),
end_lnum = _end.line,
end_col = vim.str_byteindex(line, position_encoding, _end.character, false),
end_col = vim.str_byteindex(end_line, position_encoding, _end.character, false),
severity = severity_lsp_to_vim(diagnostic.severity),
message = message,
source = diagnostic.source,

View File

@ -108,7 +108,7 @@ describe('vim.lsp.diagnostic', function()
exec_lua(function()
diagnostic_bufnr = vim.uri_to_bufnr(fake_uri)
local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
local lines = { '1st line', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
vim.fn.bufload(diagnostic_bufnr)
vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
@ -285,6 +285,36 @@ describe('vim.lsp.diagnostic', function()
eq('Pull Diagnostic', diags[1].message)
end)
it('handles multiline diagnostic ranges #33782', function()
local diags = exec_lua(function()
vim.lsp.diagnostic.on_diagnostic(nil, {
kind = 'full',
items = {
_G.make_error('Pull Diagnostic', 0, 6, 1, 10),
},
}, {
params = {
textDocument = { uri = fake_uri },
},
uri = fake_uri,
client_id = client_id,
bufnr = diagnostic_bufnr,
}, {})
return vim.diagnostic.get(diagnostic_bufnr)
end)
local lines = exec_lua(function()
return vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, false)
end)
-- This test case must be run over a multiline diagnostic in which the start line is shorter
-- than the end line, and the end_col exceeds the start line's length.
eq(#lines[1], 8)
eq(#lines[2], 16)
eq(1, #diags)
eq(6, diags[1].col)
eq(10, diags[1].end_col)
end)
it('severity defaults to error if missing', function()
---@type vim.Diagnostic[]
local diagnostics = exec_lua(function()