mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
feat(diagnostic): jump to related info location from open_float
#34837
This commit allows users to jump to the location specified in a diagnostic's `relatedInformation`, using `gf` from within the `open_float` window. The cursor need only be on line that displays the related info.
This commit is contained in:
@ -1903,7 +1903,8 @@ Lua module: vim.lsp.diagnostic *lsp-diagnostic*
|
|||||||
This module provides functionality for requesting LSP diagnostics for a
|
This module provides functionality for requesting LSP diagnostics for a
|
||||||
document/workspace and populating them using |vim.Diagnostic|s.
|
document/workspace and populating them using |vim.Diagnostic|s.
|
||||||
`DiagnosticRelatedInformation` is supported: it is included in the window
|
`DiagnosticRelatedInformation` is supported: it is included in the window
|
||||||
shown by |vim.diagnostic.open_float()|.
|
shown by |vim.diagnostic.open_float()|. When the cursor is on a line with
|
||||||
|
related information, |gf| jumps to the problem location.
|
||||||
|
|
||||||
|
|
||||||
from({diagnostics}) *vim.lsp.diagnostic.from()*
|
from({diagnostics}) *vim.lsp.diagnostic.from()*
|
||||||
|
@ -204,6 +204,9 @@ LSP
|
|||||||
• LSP `DiagnosticRelatedInformation` is now shown in
|
• LSP `DiagnosticRelatedInformation` is now shown in
|
||||||
|vim.diagnostic.open_float()|. It is read from the LSP diagnostic object
|
|vim.diagnostic.open_float()|. It is read from the LSP diagnostic object
|
||||||
stored in the `user_data` field.
|
stored in the `user_data` field.
|
||||||
|
• When inside the float created by |vim.diagnostic.open_float()| and the
|
||||||
|
cursor is on a line with `DiagnosticRelatedInformation`, |gf| can be used to
|
||||||
|
jump to the problematic location.
|
||||||
|
|
||||||
LUA
|
LUA
|
||||||
|
|
||||||
|
@ -2341,6 +2341,8 @@ function M.open_float(opts, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type table<integer, lsp.Location>
|
||||||
|
local related_info_locations = {}
|
||||||
for i, diagnostic in ipairs(diagnostics) do
|
for i, diagnostic in ipairs(diagnostics) do
|
||||||
if type(prefix_opt) == 'function' then
|
if type(prefix_opt) == 'function' then
|
||||||
--- @cast prefix_opt fun(...): string?, string?
|
--- @cast prefix_opt fun(...): string?, string?
|
||||||
@ -2378,15 +2380,16 @@ function M.open_float(opts, ...)
|
|||||||
-- Below the diagnostic, show its LSP related information (if any) in the form of file name and
|
-- Below the diagnostic, show its LSP related information (if any) in the form of file name and
|
||||||
-- range, plus description.
|
-- range, plus description.
|
||||||
for _, info in ipairs(related_info) do
|
for _, info in ipairs(related_info) do
|
||||||
-- TODO: Somehow allow users to open the location when their cursor is over it?
|
local location = info.location
|
||||||
local file_name = vim.fs.basename(vim.uri_to_fname(info.location.uri))
|
local file_name = vim.fs.basename(vim.uri_to_fname(location.uri))
|
||||||
local info_suffix = ': ' .. info.message
|
local info_suffix = ': ' .. info.message
|
||||||
|
related_info_locations[#lines + 1] = info.location
|
||||||
lines[#lines + 1] = string.format(
|
lines[#lines + 1] = string.format(
|
||||||
'%s%s:%s:%s%s',
|
'%s%s:%s:%s%s',
|
||||||
default_pre,
|
default_pre,
|
||||||
file_name,
|
file_name,
|
||||||
info.location.range.start.line,
|
location.range.start.line,
|
||||||
info.location.range.start.character,
|
location.range.start.character,
|
||||||
info_suffix
|
info_suffix
|
||||||
)
|
)
|
||||||
highlights[#highlights + 1] = {
|
highlights[#highlights + 1] = {
|
||||||
@ -2412,6 +2415,19 @@ function M.open_float(opts, ...)
|
|||||||
local float_bufnr, winnr = vim.lsp.util.open_floating_preview(lines, 'plaintext', opts)
|
local float_bufnr, winnr = vim.lsp.util.open_floating_preview(lines, 'plaintext', opts)
|
||||||
vim.bo[float_bufnr].path = vim.bo[bufnr].path
|
vim.bo[float_bufnr].path = vim.bo[bufnr].path
|
||||||
|
|
||||||
|
-- TODO: Handle this generally (like vim.ui.open()), rather than overriding gf.
|
||||||
|
vim.keymap.set('n', 'gf', function()
|
||||||
|
local cursor_row = api.nvim_win_get_cursor(0)[1]
|
||||||
|
local location = related_info_locations[cursor_row]
|
||||||
|
if location then
|
||||||
|
-- Split the window before calling `show_document` so the window doesn't disappear.
|
||||||
|
vim.cmd.split()
|
||||||
|
vim.lsp.util.show_document(location, 'utf-16', { focus = true })
|
||||||
|
else
|
||||||
|
vim.cmd.normal({ 'gf', bang = true })
|
||||||
|
end
|
||||||
|
end, { buffer = float_bufnr, remap = false })
|
||||||
|
|
||||||
--- @diagnostic disable-next-line: deprecated
|
--- @diagnostic disable-next-line: deprecated
|
||||||
local add_highlight = api.nvim_buf_add_highlight
|
local add_highlight = api.nvim_buf_add_highlight
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
---@brief This module provides functionality for requesting LSP diagnostics for a document/workspace
|
---@brief This module provides functionality for requesting LSP diagnostics for a document/workspace
|
||||||
---and populating them using |vim.Diagnostic|s. `DiagnosticRelatedInformation` is supported: it is
|
---and populating them using |vim.Diagnostic|s. `DiagnosticRelatedInformation` is supported: it is
|
||||||
---included in the window shown by |vim.diagnostic.open_float()|.
|
---included in the window shown by |vim.diagnostic.open_float()|. When the cursor is on a line with
|
||||||
|
---related information, |gf| jumps to the problem location.
|
||||||
|
|
||||||
local lsp = vim.lsp
|
local lsp = vim.lsp
|
||||||
local protocol = lsp.protocol
|
local protocol = lsp.protocol
|
||||||
|
@ -3383,6 +3383,92 @@ describe('vim.diagnostic', function()
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can add LSP related information to a diagnostic', function()
|
||||||
|
local related_info_uri = 'file:///fake/uri'
|
||||||
|
|
||||||
|
-- Populate the related info buffer.
|
||||||
|
exec_lua(function()
|
||||||
|
local fake_bufnr = vim.uri_to_bufnr(related_info_uri)
|
||||||
|
vim.fn.bufload(fake_bufnr)
|
||||||
|
vim.api.nvim_buf_set_lines(fake_bufnr, 0, 1, false, {
|
||||||
|
'O, the Pelican,',
|
||||||
|
'so smoothly doth he crest.',
|
||||||
|
'a wind god!',
|
||||||
|
})
|
||||||
|
vim.api.nvim_win_set_buf(0, fake_bufnr)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Displays related info.
|
||||||
|
eq(
|
||||||
|
{
|
||||||
|
'1. Some warning',
|
||||||
|
' uri:1:0: Some extra info',
|
||||||
|
' uri:2:3: Some more extra info',
|
||||||
|
},
|
||||||
|
exec_lua(function()
|
||||||
|
---@type vim.Diagnostic
|
||||||
|
local diagnostic = _G.make_warning('Some warning', 1, 1, 1, 3)
|
||||||
|
diagnostic.user_data = {
|
||||||
|
-- Related information comes from LSP user_data
|
||||||
|
lsp = {
|
||||||
|
relatedInformation = {
|
||||||
|
{
|
||||||
|
message = 'Some extra info',
|
||||||
|
location = {
|
||||||
|
uri = related_info_uri,
|
||||||
|
range = {
|
||||||
|
start = {
|
||||||
|
line = 1,
|
||||||
|
character = 0,
|
||||||
|
},
|
||||||
|
['end'] = {
|
||||||
|
line = 1,
|
||||||
|
character = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message = 'Some more extra info',
|
||||||
|
location = {
|
||||||
|
uri = related_info_uri,
|
||||||
|
range = {
|
||||||
|
start = {
|
||||||
|
line = 2,
|
||||||
|
character = 3,
|
||||||
|
},
|
||||||
|
['end'] = {
|
||||||
|
line = 4,
|
||||||
|
character = 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
|
||||||
|
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic })
|
||||||
|
local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' })
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
|
||||||
|
-- Put the cursor on a line with related info
|
||||||
|
vim.api.nvim_tabpage_set_win(0, winnr)
|
||||||
|
vim.api.nvim_win_set_cursor(0, { 2, 0 })
|
||||||
|
return lines
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Jumps to related info.
|
||||||
|
eq(
|
||||||
|
'so smoothly doth he crest.',
|
||||||
|
exec_lua(function()
|
||||||
|
vim.cmd.norm('gf')
|
||||||
|
vim.wait(20, function() end)
|
||||||
|
return vim.api.nvim_get_current_line()
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
it('works with the old signature', function()
|
it('works with the old signature', function()
|
||||||
eq(
|
eq(
|
||||||
{ '1. Syntax error' },
|
{ '1. Syntax error' },
|
||||||
|
Reference in New Issue
Block a user