lsp: Implement support for the textDocument/diagnostic command (#19230)

Closes [#13107](https://github.com/zed-industries/zed/issues/13107)

Enabled pull diagnostics by default, for the language servers that
declare support in the corresponding capabilities.

```
"diagnostics": {
    "lsp_pull_diagnostics_debounce_ms": null
}
```
settings can be used to disable the pulling.

Release Notes:

- Added support for the LSP `textDocument/diagnostic` command.

# Brief

This is draft PR that implements the LSP `textDocument/diagnostic`
command. The goal is to receive your feedback and establish further
steps towards fully implementing this command. I tried to re-use
existing method and structures to ensure:

1. The existing functionality works as before
2. There is no interference between the diagnostics sent by a server and
the diagnostics requested by a client.

The current implementation is done via a new LSP command
`GetDocumentDiagnostics` that is sent when a buffer is saved and when a
buffer is edited. There is a new method called `pull_diagnostic` that is
called for such events. It has debounce to ensure we don't spam a server
with commands every time the buffer is edited. Probably, we don't need
the debounce when the buffer is saved.

All in all, the goal is basically to get your feedback and ensure I am
on the right track. Thanks!


## References

1.
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_pullDiagnostics

## In action

You can clone any Ruby repo since the `ruby-lsp` supports the pull
diagnostics only.

Steps to reproduce:

1. Clone this repo https://github.com/vitallium/stimulus-lsp-error-zed
2. Install Ruby (via `asdf` or `mise).
4. Install Ruby gems via `bundle install`
5. Install Ruby LSP with `gem install ruby-lsp`
6. Check out this PR and build Zed
7. Open any file and start editing to see diagnostics in realtime.



https://github.com/user-attachments/assets/0ef6ec41-e4fa-4539-8f2c-6be0d8be4129

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
Vitaly Slobodin 2025-06-05 21:42:52 +02:00 committed by GitHub
parent 04cd3fcd23
commit 7aa70a4858
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 1408 additions and 124 deletions

View file

@ -251,6 +251,14 @@ message Diagnostic {
Anchor start = 1;
Anchor end = 2;
optional string source = 3;
enum SourceKind {
Pulled = 0;
Pushed = 1;
Other = 2;
}
SourceKind source_kind = 16;
Severity severity = 4;
string message = 5;
optional string code = 6;

View file

@ -678,6 +678,7 @@ message MultiLspQuery {
GetCodeActions get_code_actions = 6;
GetSignatureHelp get_signature_help = 7;
GetCodeLens get_code_lens = 8;
GetDocumentDiagnostics get_document_diagnostics = 9;
}
}
@ -703,6 +704,7 @@ message LspResponse {
GetCodeActionsResponse get_code_actions_response = 2;
GetSignatureHelpResponse get_signature_help_response = 3;
GetCodeLensResponse get_code_lens_response = 4;
GetDocumentDiagnosticsResponse get_document_diagnostics_response = 5;
}
}
@ -749,3 +751,59 @@ message LspExtClearFlycheck {
uint64 buffer_id = 2;
uint64 language_server_id = 3;
}
message LspDiagnosticRelatedInformation {
optional string location_url = 1;
PointUtf16 location_range_start = 2;
PointUtf16 location_range_end = 3;
string message = 4;
}
enum LspDiagnosticTag {
None = 0;
Unnecessary = 1;
Deprecated = 2;
}
message LspDiagnostic {
PointUtf16 start = 1;
PointUtf16 end = 2;
Severity severity = 3;
optional string code = 4;
optional string code_description = 5;
optional string source = 6;
string message = 7;
repeated LspDiagnosticRelatedInformation related_information = 8;
repeated LspDiagnosticTag tags = 9;
optional string data = 10;
enum Severity {
None = 0;
Error = 1;
Warning = 2;
Information = 3;
Hint = 4;
}
}
message GetDocumentDiagnostics {
uint64 project_id = 1;
uint64 buffer_id = 2;
repeated VectorClockEntry version = 3;
}
message GetDocumentDiagnosticsResponse {
repeated PulledDiagnostics pulled_diagnostics = 1;
}
message PulledDiagnostics {
uint64 server_id = 1;
string uri = 2;
optional string result_id = 3;
bool changed = 4;
repeated LspDiagnostic diagnostics = 5;
}
message RefreshDocumentsDiagnostics {
uint64 project_id = 1;
}

View file

@ -387,7 +387,12 @@ message Envelope {
LspExtRunFlycheck lsp_ext_run_flycheck = 346;
LspExtClearFlycheck lsp_ext_clear_flycheck = 347;
LogToDebugConsole log_to_debug_console = 348; // current max
LogToDebugConsole log_to_debug_console = 348;
GetDocumentDiagnostics get_document_diagnostics = 350;
GetDocumentDiagnosticsResponse get_document_diagnostics_response = 351;
RefreshDocumentsDiagnostics refresh_documents_diagnostics = 352; // current max
}
reserved 87 to 88;

View file

@ -307,6 +307,9 @@ messages!(
(RunDebugLocators, Background),
(DebugRequest, Background),
(LogToDebugConsole, Background),
(GetDocumentDiagnostics, Background),
(GetDocumentDiagnosticsResponse, Background),
(RefreshDocumentsDiagnostics, Background)
);
request_messages!(
@ -469,6 +472,8 @@ request_messages!(
(ToggleBreakpoint, Ack),
(GetDebugAdapterBinary, DebugAdapterBinary),
(RunDebugLocators, DebugRequest),
(GetDocumentDiagnostics, GetDocumentDiagnosticsResponse),
(RefreshDocumentsDiagnostics, Ack)
);
entity_messages!(
@ -595,6 +600,8 @@ entity_messages!(
RunDebugLocators,
GetDebugAdapterBinary,
LogToDebugConsole,
GetDocumentDiagnostics,
RefreshDocumentsDiagnostics
);
entity_messages!(