neovim icon indicating copy to clipboard operation
neovim copied to clipboard

Supports LSP method `workspace/diagnostic`

Open brianhuster opened this issue 6 months ago • 4 comments

Problem

Nvim already has support for textDocument/diagnostic, but with it, developer would only see issues in the files they had open. Changes in one file could introduce errors in other, unopened files, but the developer could remain unaware until those other files were opened.

I think quickfix feature was created partly to target this problem, but it would be great to enhance it with LSP workspace diagnostics

Workspace diagnostics are also useful for LLM, since many AI agents now support editing multiple files. I think it can also be used in a well-formatted "digest" including the project tree

Expected behavior

  • Specification
  • Users should be able to see workspace diagnostics either via the file explorer or in quickfix list
  • There should also be a function that returns workspace diagnostics as a Lua table so I can easily add it to LLM context

What do you think @MariaSolOs

brianhuster avatar May 29 '25 18:05 brianhuster

Sounds like a reasonable request to me. Tagging @lewis6991 @gpanders @mfussenegger and @justinmk for the bikeshedding discussion.

MariaSolOs avatar May 30 '25 05:05 MariaSolOs

Support for this would be great for C# developers who are using the Roslyn LSP. Some relevant discussion here: https://github.com/seblyng/roslyn.nvim/issues/32

cphorton avatar May 30 '25 07:05 cphorton

  • Users should be able to see workspace diagnostics either via the file explorer or in quickfix list
  • There should also be a function that returns workspace diagnostics as a Lua table so I can easily add it to LLM context

Those SGTM, though the file-explorer part should be ignored until we have a non-netrw answer for that.

justinmk avatar May 30 '25 15:05 justinmk

Summarizing some of the discussion I had on Matrix with @lewis6991 and @clason about the implementation details of this:

  • We would need a new vim.lsp.workspace_diagnostics() function that returns all workspace diagnostics as the current architecture of vim.diagnostic is mostly "push" and we would like to keep vim.diagnostic.get() sync.
  • vim.lsp.workspace_diagnostics() would call vim.diagnostic.get() and vim.diagnostic.set() to handle the results following the spec ("diagnostics for a higher document version should win over those from a lower document version" and "diagnostics from a document pull should win over diagnostics from a workspace pull").

I'm happy to work on this, but before I start coding I would appreciate the input of @gpanders and @mfussenegger here too :)

MariaSolOs avatar May 31 '25 22:05 MariaSolOs

need a new vim.lsp.workspace_diagnostics()

nit: all of our current workspace-related functions are in vim.lsp.buf. The new one should go there too (or in vim.lsp.diagnostic ?), though it probably makes sense to introduce vim.lsp.workspace and relocate stuff there.

justinmk avatar Jun 01 '25 15:06 justinmk

If anything I'd prefer to move all the vim.lsp.buf functions into vim.lsp.

Workspace diagnostics also isn't related to any buffer so can't go there anyway.

It shouldn't go in vim.diagnostic as it just doesn't belong there. Vim.diagnostic does not make LSP requests

lewis6991 avatar Jun 01 '25 15:06 lewis6991

To quote from the docs:

The vim.lsp.buf_… functions perform operations for LSP clients attached to the current buffer.

So it's not about "buffer functions" but about all client functions for the current buffer, which makes it an appropriate place for requesting workspace diagnostics. (Of course, this becomes iffy with multiple clients per buffer...)

It's for sure not the most fortunate name for that module. Maybe we can find a better one to shove all client functions (buffer or workspace) under (keeping buf around as a compat shim)? (lsp.client or lsp.request come to mind)

clason avatar Jun 01 '25 15:06 clason

It shouldn't go in vim.diagnostic as it just doesn't belong there. Vim.diagnostic does not make LSP requests

This feels like an implementation detail though. From a public API standpoint, it does feel strange to have a diagnostic function outside vim.diagnostic.

MariaSolOs avatar Jun 01 '25 16:06 MariaSolOs

It’s not an implementation detail. In the old days, diagnostics and LSP were intertwined. It was messy and there was no clean way to add diagnostics from non-LSP sources. Dedicated plugins existed solely to shim non-LSP diagnostics into LSP.

vim.diagnostic was created with the clear intent of separating generic diagnostics (which can come from anywhere, including but not limited to LSP) from LSP diagnostics. If we start adding LSP-isms back into vim.diagnostic then we are just moving backward to the point where we didn’t have a clear abstraction boundary between separate ideas.

It’s fine to have diagnostics functions under vim.lsp that are specific to LSP diagnostics. We already have a whole file dedicated to that.

gpanders avatar Jun 01 '25 16:06 gpanders

This feels like an implementation detail though. From a public API standpoint, it does feel strange to have a diagnostic function outside vim.diagnostic.

It is not. It is a specific design detail of the interface. We discussed this at length and how to address it. At the moment vim.diagnostic just stores diagnostics that are pushed to it via vim.diagnostic.set() which can then be retrieved via vim.diagnostic.get(). There is no public or even private API for vim.diagnostic to pull diagnostics.

lewis6991 avatar Jun 01 '25 16:06 lewis6991

Fair enough. Thank you @gpanders and @lewis6991 for explaining. I apologize if I'm being slow in understanding the design decisions here, but as someone who lacks some of the historical context I was confused by the desire to keep vim.diagnostic LSP-independent, but thanks to @gpanders I finally get it.

MariaSolOs avatar Jun 01 '25 16:06 MariaSolOs

To quote from the docs:

The vim.lsp.buf_… functions perform operations for LSP clients attached to the current buffer.

So it's not about "buffer functions" but about all client functions for the current buffer, which makes it an appropriate place for requesting workspace diagnostics. (Of course, this becomes iffy with multiple clients per buffer...)

It's for sure not the most fortunate name for that module. Maybe we can find a better one to shove all client functions (buffer or workspace) under (keeping buf around as a compat shim)? (lsp.client or lsp.request come to mind)

After looking at what's already in vim.lsp.buf, I agree, we can just add a new function there for now. We can bikeshed a new home/namespace later.

lewis6991 avatar Jun 01 '25 16:06 lewis6991

After looking at what's already in vim.lsp.buf, I agree, we can just add a new function there for now. We can bikeshed a new home/namespace later.

Why not just add the new function in vim.lsp.diagnostic?

MariaSolOs avatar Jun 01 '25 16:06 MariaSolOs

Because that module is deprecated. (It's part of the old, bad, design we have replaced.)

clason avatar Jun 01 '25 16:06 clason

After looking at what's already in vim.lsp.buf, I agree, we can just add a new function there for now. We can bikeshed a new home/namespace later.

Why not just add the new function in vim.lsp.diagnostic?

Just like the quick fix entries structure, the vim.diagnostic structure can be used anywhere across the whole project. We don't need to add (or replace) a dedicated module for anything that uses vim.Diagnostic.

lewis6991 avatar Jun 01 '25 16:06 lewis6991

Okay then. I’ll add the new function to (the poorly named) vim.lsp.buf.

MariaSolOs avatar Jun 01 '25 17:06 MariaSolOs

I've been playing around with workspace diagnostics (using the Roslyn LSP mentioned earlier in this thread) and have a question about this: when would we pull workspace diagnostics? Would this implementation include that? When testing with VS Code, it seems like it always has the most recent workspace diagnostics. I'm not sure how this implementation works or how to implement it. Would it get called on project open and when edits are made? Pulling workspace diagnostics can sometimes take a while. I know some LSPs implement PartialResultParams. What would happen if I make a change to a file that means there would be updated diagnostics for a document I already got results for, but the workspace pull isn't finished yet? Would we have to wait for it to finish before calling it again?

ZieMcd avatar Jun 01 '25 20:06 ZieMcd

Because that module is deprecated. (It's part of the old, bad, design we have replaced.)

Afaik not all of it. See :help lsp-diagnostic. These functions aren't deprecated, and afaik there is no plan to change that?

mfussenegger avatar Jun 01 '25 20:06 mfussenegger

Silly me, thinking :h vim.lsp.diagnostic would give me the right help tag.

(Still, the remaining functions are really low-level and not on the same level as a major LSP request.)

clason avatar Jun 01 '25 20:06 clason

@brianhuster Or anyone else following this thread: Do you have a (preferably easy to set up) language server that supports workspace diagnostics that I can use to test https://github.com/neovim/neovim/pull/34262?

MariaSolOs avatar Jun 07 '25 03:06 MariaSolOs

I think basedpyright (an LS for Python) supports workspace diagnostic. The config could look like this (assuming you also use nvim-lspconfig)

---@type vim.lsp.Config
vim.lsp.config.basedpyright = {
    settings = {
        basedpyright = {
            analysis = {
                diagnosticMode = 'workspace'
            }
        }
    }
}
vim.lsp.enable 'basedpyright'

brianhuster avatar Jun 07 '25 10:06 brianhuster

I think basedpyright (an LS for Python) supports workspace diagnostic. The config could look like this (assuming you also use nvim-lspconfig)

---@type vim.lsp.Config vim.lsp.config.basedpyright = { settings = { basedpyright = { analysis = { diagnosticMode = 'workspace' } } } } vim.lsp.enable 'basedpyright'

Hmm it doesn't seem like it supports the workspace/diagnostic request: https://github.com/DetachHead/basedpyright/blob/0618b0988d6733f758bef6c0812780efd7e77bbe/packages/pyright-internal/src/languageServerBase.ts#L723

MariaSolOs avatar Jun 07 '25 15:06 MariaSolOs

Microsoft's roslyn lsp does support workspace/diagnostic though it is pretty annoying to install. Also the server capabilities DiagnosticOptions.workspaceDiagnostics = false. Not sure if I have to change something in client capabilities. But you should get a response when sending the workspace/diagnostic or at least I do.

ZieMcd avatar Jun 07 '25 17:06 ZieMcd

Hello there, i really want this in neovim, read through it here https://neovim.io/doc/user/lsp.html#vim.lsp.buf.workspace_diagnostics() and loved it, but i couldn't find anywhere that says in what version it is being planned to come... Is there such a place in the docs or here in the github?

thanks btw for the merge, this will help me out a lot <3

Thiago-Assis-T avatar Nov 12 '25 15:11 Thiago-Assis-T

Features will land in the next minor release after the merge, in this case 0.12.

clason avatar Nov 12 '25 16:11 clason