commit 68e316e3f9107f2bd9be934f089cf8203f9c4c3d
parent 7bd4dfd209e9877c9878ce63e59a84492f00251b
Author: Riley Bruins <ribru17@hotmail.com>
Date: Thu, 10 Jul 2025 11:24:17 -0700
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.
Diffstat:
5 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
@@ -1903,7 +1903,8 @@ Lua module: vim.lsp.diagnostic *lsp-diagnostic*
This module provides functionality for requesting LSP diagnostics for a
document/workspace and populating them using |vim.Diagnostic|s.
`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()*
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
@@ -204,6 +204,9 @@ LSP
• LSP `DiagnosticRelatedInformation` is now shown in
|vim.diagnostic.open_float()|. It is read from the LSP diagnostic object
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
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
@@ -2341,6 +2341,8 @@ function M.open_float(opts, ...)
end
end
+ ---@type table<integer, lsp.Location>
+ local related_info_locations = {}
for i, diagnostic in ipairs(diagnostics) do
if type(prefix_opt) == 'function' then
--- @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
-- range, plus description.
for _, info in ipairs(related_info) do
- -- TODO: Somehow allow users to open the location when their cursor is over it?
- local file_name = vim.fs.basename(vim.uri_to_fname(info.location.uri))
+ local location = info.location
+ local file_name = vim.fs.basename(vim.uri_to_fname(location.uri))
local info_suffix = ': ' .. info.message
+ related_info_locations[#lines + 1] = info.location
lines[#lines + 1] = string.format(
'%s%s:%s:%s%s',
default_pre,
file_name,
- info.location.range.start.line,
- info.location.range.start.character,
+ location.range.start.line,
+ location.range.start.character,
info_suffix
)
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)
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
local add_highlight = api.nvim_buf_add_highlight
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
@@ -1,6 +1,7 @@
---@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
----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 protocol = lsp.protocol
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
@@ -3383,6 +3383,92 @@ describe('vim.diagnostic', function()
)
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()
eq(
{ '1. Syntax error' },