diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 700a3ea1c2..dd7c2494d4 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -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, diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 5edd224ae9..0d9ed9bd2c 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -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()