Improve support for multiple registrations of textDocument/diagnostic (#43703)

Closes https://github.com/zed-industries/zed/issues/41935

The registration ID responsible for generating each diagnostic is now
tracked. This allows us to replace only the diagnostics from the same
registration ID when a pull diagnostics report is applied.

Additionally, various deficiencies in our support for pull diagnostics
have been fixed:
- Document pulls are issued for all open buffers, not just the edited
one. A shorter debounce is used for the edited buffer. Workspace
diagnostics are also now ignored for open buffers.
- Tracking of `lastResultId` is improved.
- Stored pull diagnostics are discarded when the corresponding buffer is
closed.

Release Notes:

- Improved compatibility with language servers that use the "pull
diagnostics" feature of Language Server Protocol.

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
John Tur
2025-12-03 20:47:43 +02:00
committed by GitHub
co-authored by Kirill Bulatov Kirill Bulatov
parent 493cfadb42
commit a51e975b81
13 changed files with 524 additions and 263 deletions
+3
View File
@@ -237,6 +237,8 @@ struct SelectionSet {
pub struct Diagnostic {
/// The name of the service that produced this diagnostic.
pub source: Option<String>,
/// The ID provided by the dynamic registration that produced this diagnostic.
pub registration_id: Option<SharedString>,
/// A machine-readable code that identifies this diagnostic.
pub code: Option<NumberOrString>,
pub code_description: Option<lsp::Uri>,
@@ -5390,6 +5392,7 @@ impl Default for Diagnostic {
is_unnecessary: false,
underline: true,
data: None,
registration_id: None,
}
}
}
+7
View File
@@ -3,6 +3,7 @@
use crate::{CursorShape, Diagnostic, DiagnosticSourceKind, diagnostic_set::DiagnosticEntry};
use anyhow::{Context as _, Result};
use clock::ReplicaId;
use gpui::SharedString;
use lsp::{DiagnosticSeverity, LanguageServerId};
use rpc::proto;
use serde_json::Value;
@@ -239,6 +240,11 @@ pub fn serialize_diagnostics<'a>(
is_disk_based: entry.diagnostic.is_disk_based,
is_unnecessary: entry.diagnostic.is_unnecessary,
data: entry.diagnostic.data.as_ref().map(|data| data.to_string()),
registration_id: entry
.diagnostic
.registration_id
.as_ref()
.map(ToString::to_string),
})
.collect()
}
@@ -457,6 +463,7 @@ pub fn deserialize_diagnostics(
is_disk_based: diagnostic.is_disk_based,
is_unnecessary: diagnostic.is_unnecessary,
underline: diagnostic.underline,
registration_id: diagnostic.registration_id.map(SharedString::from),
source_kind: match proto::diagnostic::SourceKind::from_i32(
diagnostic.source_kind,
)? {